feat: enhance MikroTik backup playbook with improved structure and validation

This commit is contained in:
martin.fencl
2026-07-29 15:15:47 +02:00
parent 36962b1f37
commit 8910bb1040
+106 -38
View File
@@ -1,59 +1,127 @@
- name: Backup MikroTik config (text export only) # mikrotikbackup.yml
- name: Backup MikroTik configuration
hosts: mikrotiks hosts: mikrotiks
gather_facts: no gather_facts: false
vars: vars:
backup_dir: /opt/mikrotik_backups/ # This path is located on the Semaphore runner
backup_dir: /opt/mikrotik_backups
tasks: tasks:
# ----------------------------
# Ensure local backup directory
# ----------------------------
- name: Ensure local backup directory exists - name: Ensure local backup directory exists
ansible.builtin.file: ansible.builtin.file:
path: "{{ backup_dir }}" path: "{{ backup_dir }}"
state: directory state: directory
mode: "0755" mode: "0700"
delegate_to: localhost
run_once: true
- name: Generate backup timestamp
ansible.builtin.command:
argv:
- date
- --utc
- "+%Y-%m-%d_%H-%M-%S"
register: backup_timestamp
changed_when: false
delegate_to: localhost delegate_to: localhost
# ----------------------------
# Get router identity
# ----------------------------
- name: Get router identity - name: Get router identity
community.routeros.command: community.routeros.command:
commands: /system identity print commands:
register: identity_raw - /system identity print
register: identity_result
changed_when: false
- name: Parse router name - name: Extract router identity line
set_fact: ansible.builtin.set_fact:
router_name: "{{ identity_raw.stdout[0].split(': ')[1] | trim }}" router_identity_line: >-
{{
(
identity_result.stdout_lines[0]
| select('match', '^\s*name\s*:')
| list
| first
)
| default('', true)
}}
# ---------------------------- - name: Validate router identity output
# Timestamp ansible.builtin.assert:
# ---------------------------- that:
- name: Get timestamp - router_identity_line | length > 0
ansible.builtin.command: date +%Y-%m-%d_%H-%M-%S fail_msg: >-
register: date_out Could not parse RouterOS identity on
delegate_to: localhost {{ inventory_hostname }}.
quiet: true
- name: Set timestamp fact - name: Build safe router name
set_fact: ansible.builtin.set_fact:
ts: "{{ date_out.stdout }}" router_name: >-
{{
router_identity_line
| regex_replace('^\s*name\s*:\s*', '')
| trim
| regex_replace('[^A-Za-z0-9._-]+', '_')
| regex_replace('^_+|_+$', '')
}}
# ---------------------------- - name: Validate safe router name
# Export config (stable for diff) ansible.builtin.assert:
# ---------------------------- that:
- name: Export router config - router_name | length > 0
fail_msg: >-
Router identity on {{ inventory_hostname }}
cannot be converted to a safe filename.
quiet: true
- name: Set local backup filename
ansible.builtin.set_fact:
backup_file: >-
{{
backup_dir
~ '/'
~ router_name
~ '-'
~ backup_timestamp.stdout
~ '.rsc'
}}
- name: Export RouterOS configuration
community.routeros.command: community.routeros.command:
commands: /export terse show-sensitive commands:
register: export_cfg - /export terse show-sensitive
register: export_result
changed_when: false
no_log: true
# ---------------------------- - name: Validate exported configuration
# Save export locally ansible.builtin.assert:
# ---------------------------- that:
- name: Save export locally - export_result.stdout is defined
- export_result.stdout | length > 0
- export_result.stdout[0] | default('') | trim | length > 0
fail_msg: >-
RouterOS returned an empty configuration export
for {{ inventory_hostname }}.
quiet: true
no_log: true
- name: Save RouterOS configuration locally
ansible.builtin.copy: ansible.builtin.copy:
content: "{{ export_cfg.stdout[0] }}" content: "{{ export_result.stdout[0] | trim }}\n"
dest: "{{ backup_dir }}/{{ router_name }}-{{ ts }}.rsc" dest: "{{ backup_file }}"
mode: "0600"
delegate_to: localhost delegate_to: localhost
no_log: true
diff: false
- name: Show backup result
ansible.builtin.debug:
msg: >-
MikroTik backup completed:
host={{ inventory_hostname }}
identity={{ router_name }}
file={{ backup_file }}