diff --git a/mikrotikbackup.yml b/mikrotikbackup.yml deleted file mode 100644 index 7e66667..0000000 --- a/mikrotikbackup.yml +++ /dev/null @@ -1,127 +0,0 @@ -# mikrotikbackup.yml - - -- name: Backup MikroTik configuration - hosts: mikrotiks - gather_facts: false - - vars: - # This path is located on the Semaphore runner - backup_dir: /opt/mikrotik_backups - - tasks: - - name: Ensure local backup directory exists - ansible.builtin.file: - path: "{{ backup_dir }}" - state: directory - 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 - - - name: Get router identity - community.routeros.command: - commands: - - /system identity print - register: identity_result - changed_when: false - - - name: Extract router identity line - ansible.builtin.set_fact: - router_identity_line: >- - {{ - ( - identity_result.stdout_lines[0] - | select('match', '^\s*name\s*:') - | list - | first - ) - | default('', true) - }} - - - name: Validate router identity output - ansible.builtin.assert: - that: - - router_identity_line | length > 0 - fail_msg: >- - Could not parse RouterOS identity on - {{ inventory_hostname }}. - quiet: true - - - name: Build safe router name - ansible.builtin.set_fact: - 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 - ansible.builtin.assert: - that: - - 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: - commands: - - /export terse show-sensitive - register: export_result - changed_when: false - no_log: true - - - name: Validate exported configuration - ansible.builtin.assert: - that: - - 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: - content: "{{ export_result.stdout[0] | trim }}\n" - dest: "{{ backup_file }}" - mode: "0600" - 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 }} \ No newline at end of file diff --git a/mikrotikbackup_clean.yml b/mikrotikbackup_clean.yml new file mode 100644 index 0000000..af7d53f --- /dev/null +++ b/mikrotikbackup_clean.yml @@ -0,0 +1,149 @@ +# mikrotikbackup_clean.yml + + +- name: Backup and/or Upgrade MikroTik + hosts: mikrotik_routers + gather_facts: no + + vars: + backup_dir: /opt/mikrotik_backups/ + + tasks: + + # ---------------------------- + # Always: identity + timestamp + # ---------------------------- + - name: Get router identity + community.routeros.command: + commands: /system identity print + register: identity_raw + tags: always + + - name: Parse router name + set_fact: + router_name: "{{ identity_raw.stdout[0].split(': ')[1] | trim }}" + tags: always + + - name: Get timestamp + ansible.builtin.command: date +%Y-%m-%d_%H-%M-%S + register: date_out + delegate_to: localhost + tags: always + + - name: Set timestamp fact + set_fact: + ts: "{{ date_out.stdout }}" + tags: always + + # ---------------------------- + # Backup (tag: backup) + # ---------------------------- + - name: Ensure local backup directory exists + ansible.builtin.file: + path: "{{ backup_dir }}" + state: directory + mode: "0755" + delegate_to: localhost + tags: [backup, never] + + - name: Export router config + community.routeros.command: + commands: /export terse show-sensitive + register: export_cfg + tags: [backup, never] + + - name: Save export locally + ansible.builtin.copy: + content: "{{ export_cfg.stdout[0] }}" + dest: "{{ backup_dir }}/{{ router_name }}-{{ ts }}.rsc" + delegate_to: localhost + tags: [backup, never] + + # ---------------------------- + # Upgrade (tag: upgrade) + # ---------------------------- + - name: Check current and latest available package versions + community.routeros.command: + commands: /system package update check-for-updates + register: update_check + tags: [upgrade, never] + + - name: Normalize update output + set_fact: + _update_text: "{{ update_check.stdout[0] | replace('\r', '') }}" + tags: [upgrade, never] + + # ⬇️ Add this to see exactly what RouterOS returns before parsing + - name: Debug raw update output + ansible.builtin.debug: + msg: "{{ _update_text }}" + tags: [upgrade, never] + + - name: Parse installed and latest versions + set_fact: + installed_version: >- + {{ + (_update_text | regex_findall('(?:installed|current)-version:[ ]*([0-9A-Za-z.]+)'))[0] + if (_update_text | regex_findall('(?:installed|current)-version:[ ]*([0-9A-Za-z.]+)')) + else 'unknown' + }} + latest_version: >- + {{ + (_update_text | regex_findall('(?:latest|newest)-version:[ ]*([0-9A-Za-z.]+)'))[0] + if (_update_text | regex_findall('(?:latest|newest)-version:[ ]*([0-9A-Za-z.]+)')) + else 'unknown' + }} + tags: [upgrade, never] + + - name: Fail if versions could not be parsed + ansible.builtin.fail: + msg: > + Could not parse versions from update output. + Raw text was: {{ _update_text }} + when: installed_version == 'unknown' or latest_version == 'unknown' + tags: [upgrade, never] + + - name: Debug parsed versions + ansible.builtin.debug: + msg: + - "Installed: {{ installed_version }}" + - "Latest: {{ latest_version }}" + tags: [upgrade, never] + + - name: Skip upgrade if already on latest + ansible.builtin.debug: + msg: "Router {{ router_name }} is already on latest version {{ installed_version }}. Skipping upgrade." + when: installed_version == latest_version + tags: [upgrade, never] + + - name: Trigger package download and install + community.routeros.command: + commands: /system package update install + register: upgrade_result + when: installed_version != latest_version + tags: [upgrade, never] + + - name: Wait for router to come back online after reboot + community.routeros.command: + commands: /system resource print + register: reboot_wait + until: reboot_wait is not failed + retries: 30 + delay: 15 + when: + - installed_version != latest_version + - upgrade_result is not failed + tags: [upgrade, never] + + - name: Confirm upgraded version + community.routeros.command: + commands: /system resource print + register: post_upgrade_info + when: installed_version != latest_version + tags: [upgrade, never] + + - name: Show post-upgrade RouterOS version + ansible.builtin.debug: + msg: "{{ post_upgrade_info.stdout[0] | regex_search('version: .+') }}" + when: installed_version != latest_version + tags: [upgrade, never]