diff --git a/mikrotikbackup_clean.yml b/mikrotikbackup_clean.yml index 9cdd015..c5781fd 100644 --- a/mikrotikbackup_clean.yml +++ b/mikrotikbackup_clean.yml @@ -1,7 +1,7 @@ --- - name: Backup and/or Upgrade MikroTik hosts: mikrotik_routers - gather_facts: no + gather_facts: false serial: 10 vars: @@ -10,30 +10,30 @@ checkmk_service_description: "MikroTik Backup/Upgrade" tasks: - # ---------------------------- # Always: identity + timestamp # ---------------------------- - name: Get router identity community.routeros.command: - commands: /system identity print + commands: + - /system identity print register: identity_raw tags: always - name: Parse router name - set_fact: - router_name: "{{ identity_raw.stdout[0].split(': ')[1] | trim }}" + ansible.builtin.set_fact: + router_name: "{{ identity_raw.stdout[0].split(': ', 1)[1] | trim }}" tags: always - name: Get timestamp - command: date +%Y-%m-%d_%H-%M-%S + ansible.builtin.command: date +%Y-%m-%d_%H-%M-%S register: date_out delegate_to: localhost changed_when: false tags: always - name: Set timestamp fact - set_fact: + ansible.builtin.set_fact: ts: "{{ date_out.stdout }}" tags: always @@ -41,7 +41,7 @@ # Backup # ---------------------------- - name: Ensure local backup directory exists - file: + ansible.builtin.file: path: "{{ backup_dir }}" state: directory mode: "0755" @@ -50,12 +50,13 @@ - name: Export router config community.routeros.command: - commands: /export terse show-sensitive + commands: + - /export terse show-sensitive register: export_cfg tags: backup - name: Save export locally - copy: + ansible.builtin.copy: content: "{{ export_cfg.stdout[0] }}" dest: "{{ backup_dir }}/{{ router_name }}-{{ ts }}.rsc" mode: "0600" @@ -63,67 +64,60 @@ tags: backup - name: Mark backup success - set_fact: + ansible.builtin.set_fact: backup_ok: true backup_file: "{{ backup_dir }}/{{ router_name }}-{{ ts }}.rsc" tags: backup # ---------------------------- - # Upgrade (robust MikroTik flow) + # Upgrade # ---------------------------- - name: Trigger update check community.routeros.command: - commands: /system package update check-for-updates once + commands: + - /system package update check-for-updates once + register: update_trigger tags: upgrade - name: Poll update status until ready community.routeros.command: - commands: /system package update print as-value + commands: + - /system package update print as-value register: update_info retries: 10 delay: 3 until: > update_info.stdout is defined and - update_info.stdout[0] is defined and - update_info.stdout[0]['status'] is defined and - update_info.stdout[0]['status'] != 'finding out latest version...' + update_info.stdout | length > 0 and + update_info.stdout[0] is mapping and + update_info.stdout[0].get('status', '') != '' and + 'finding out latest version' not in (update_info.stdout[0].get('status', '') | lower) tags: upgrade - # Optional debug (can remove later) - - name: DEBUG update info - debug: + - name: Debug update info + ansible.builtin.debug: var: update_info.stdout[0] tags: upgrade - # ---------------------------- - # Parse versions - # ---------------------------- - name: Parse versions - set_fact: - installed_version: "{{ update_info.stdout[0]['installed-version'] | default('unknown') }}" - latest_version: "{{ update_info.stdout[0]['latest-version'] | default('unknown') }}" - update_status: "{{ update_info.stdout[0]['status'] | default('unknown') }}" + ansible.builtin.set_fact: + installed_version: "{{ update_info.stdout[0].get('installed-version', 'unknown') }}" + latest_version: "{{ update_info.stdout[0].get('latest-version', 'unknown') }}" + update_status: "{{ update_info.stdout[0].get('status', 'unknown') }}" + update_channel: "{{ update_info.stdout[0].get('channel', 'unknown') }}" tags: upgrade - # ---------------------------- - # Detect issues - # ---------------------------- - name: Detect update failure - set_fact: - update_failed: "{{ 'error' in update_status or 'failed' in update_status }}" + ansible.builtin.set_fact: + update_failed: >- + {{ + 'error' in (update_status | lower) or + 'failed' in (update_status | lower) + }} tags: upgrade - - name: Warn if update check failed - debug: - msg: "WARNING: Update check failed on {{ router_name }} (status={{ update_status }})" - when: update_failed - tags: upgrade - - # ---------------------------- - # Decide upgrade - # ---------------------------- - name: Set upgrade-needed fact - set_fact: + ansible.builtin.set_fact: upgrade_needed: >- {{ not update_failed and @@ -134,28 +128,40 @@ tags: upgrade - name: Show decision - debug: - msg: "Router={{ router_name }} installed={{ installed_version }} latest={{ latest_version }} status={{ update_status }} upgrade_needed={{ upgrade_needed }}" + ansible.builtin.debug: + msg: >- + Router={{ router_name }} + channel={{ update_channel }} + installed={{ installed_version }} + latest={{ latest_version }} + status={{ update_status }} + upgrade_needed={{ upgrade_needed }} + tags: upgrade + + - name: Warn if update check failed + ansible.builtin.debug: + msg: "WARNING: Update check failed on {{ router_name }} (status={{ update_status }})" + when: update_failed tags: upgrade - name: Skip upgrade if already latest - debug: + ansible.builtin.debug: msg: "Router {{ router_name }} is already up to date ({{ installed_version }})" - when: not upgrade_needed + when: + - not update_failed + - not upgrade_needed tags: upgrade - # ---------------------------- - # Perform upgrade - # ---------------------------- - name: Trigger package install community.routeros.command: - commands: /system package update install + commands: + - /system package update install register: upgrade_result when: upgrade_needed tags: upgrade - name: Wait for router to come back - wait_for_connection: + ansible.builtin.wait_for_connection: delay: 180 timeout: 600 sleep: 10 @@ -166,19 +172,25 @@ - name: Confirm upgraded version community.routeros.command: - commands: /system resource print + commands: + - /system resource print register: post_upgrade_info when: upgrade_needed tags: upgrade - name: Parse post-upgrade version - set_fact: - post_upgrade_version: "{{ post_upgrade_info.stdout[0] | regex_search('version: ([^\\s]+)', '\\1') | default('unknown', true) }}" + ansible.builtin.set_fact: + post_upgrade_version: >- + {{ + post_upgrade_info.stdout[0] + | regex_search('version: ([^\\s]+)', '\\1') + | default('unknown', true) + }} when: upgrade_needed tags: upgrade - name: Show post-upgrade version - debug: + ansible.builtin.debug: msg: "Router {{ router_name }} upgraded to {{ post_upgrade_version }}" when: upgrade_needed tags: upgrade @@ -186,32 +198,32 @@ # ---------------------------- # Build Checkmk result # ---------------------------- - - name: Result when no upgrade - set_fact: + - name: Build Checkmk result when no upgrade was needed + ansible.builtin.set_fact: cmk_state: "{{ 2 if update_failed else 0 }}" cmk_output: >- - {{ 'CRIT' if update_failed else 'OK' }} - - router={{ router_name }} + {{ 'CRIT' if update_failed else 'OK' }} - router={{ router_name }} backup=ok + channel={{ update_channel }} installed={{ installed_version }} latest={{ latest_version }} - status={{ update_status }} + status="{{ update_status }}" upgrade_needed=no backup_file={{ backup_file | default('n/a') }} backup_ts={{ ts }} when: not upgrade_needed tags: always - - name: Result when upgrade happened - set_fact: + - name: Build Checkmk result when upgrade succeeded + ansible.builtin.set_fact: cmk_state: "{{ 0 if post_upgrade_version == latest_version else 2 }}" cmk_output: >- - {{ 'OK' if post_upgrade_version == latest_version else 'CRIT' }} - - router={{ router_name }} + {{ 'OK' if post_upgrade_version == latest_version else 'CRIT' }} - router={{ router_name }} backup=ok + channel={{ update_channel }} installed_before={{ installed_version }} latest={{ latest_version }} - status={{ update_status }} + status="{{ update_status }}" upgrade_needed=yes upgraded_to={{ post_upgrade_version }} backup_file={{ backup_file | default('n/a') }} @@ -224,7 +236,7 @@ # ---------------------------- - name: Send result to Checkmk delegate_to: localhost - uri: + ansible.builtin.uri: url: "{{ checkmk_url }}" method: POST headers: @@ -238,12 +250,15 @@ state: "{{ cmk_state | int }}" output: "{{ cmk_output }}" return_content: true - status_code: [200, 201, 204] + status_code: + - 200 + - 201 + - 204 register: checkmk_result failed_when: false tags: always - name: Show Checkmk response - debug: + ansible.builtin.debug: var: checkmk_result tags: always \ No newline at end of file