From 89c282465e0a62776c75121ce1e3cc80a81b00b9 Mon Sep 17 00:00:00 2001 From: pavel Date: Tue, 4 Nov 2025 16:09:23 +0200 Subject: [PATCH] 16:09 --- files/ansible-playbooks/sot-updater.yml | 99 +++++++++++++++++++++---- 1 file changed, 86 insertions(+), 13 deletions(-) diff --git a/files/ansible-playbooks/sot-updater.yml b/files/ansible-playbooks/sot-updater.yml index a7b1289..e8df62f 100644 --- a/files/ansible-playbooks/sot-updater.yml +++ b/files/ansible-playbooks/sot-updater.yml @@ -38,12 +38,6 @@ control_queue: "{{ lookup('env','CONTROLQUEUE') | default('queue_controls', true) }}" pre_tasks: - - - name: "NB preflight | Pause 3s for cloud to settle" - delegate_to: localhost - ansible.builtin.pause: - seconds: 1 - - name: "NB preflight | Verify script exists" delegate_to: localhost ansible.builtin.stat: @@ -51,21 +45,18 @@ register: nb_script - name: "NB preflight | Abort softly if script missing (path typo?)" + when: not nb_script.stat.exists delegate_to: localhost ansible.builtin.debug: msg: - "NB preflight skipped: /opt/containers/ansible-worker/app/nb_onedevice_update.py not found." - "Tip: adjust chdir/path or script name." - when: not nb_script.stat.exists - name: "NB preflight | Run nb_onedevice_update.py for {{ inventory_hostname }} (chatty)" when: nb_script.stat.exists delegate_to: localhost environment: - PYTHONUNBUFFERED: "1" # flush prints immediately - # Add any env your script needs here, e.g.: - # NB_URL: "{{ lookup('env','NB_URL') | default('', true) }}" - # NB_TOKEN: "{{ lookup('env','NB_TOKEN') | default('', true) }}" + PYTHONUNBUFFERED: "1" args: chdir: "/opt/containers/ansible-worker/app" executable: /bin/bash @@ -73,8 +64,8 @@ set -o pipefail python3 -u nb_onedevice_update.py "{{ inventory_hostname }}" --chatty 2>&1 register: nb_preflight - changed_when: false # informational - failed_when: false # soft-fail, keep going + changed_when: false + failed_when: false - name: "NB preflight | Show results" when: nb_script.stat.exists @@ -88,7 +79,89 @@ - "{{ (nb_preflight.stderr_lines | default([''])) }}" - "raw stdout (joined): {{ nb_preflight.stdout | default('') | trim }}" + # --- Parse the OK line for reuse (device/ip/fw/etc.) --- + - name: "NB preflight | Parse OK line" + when: nb_script.stat.exists + delegate_to: localhost + vars: + nb_ok_line: >- + {{ (nb_preflight.stdout | default('') | regex_findall('^OK\\s+.*$', multiline=True)) | last | default('') }} + nb_groups: >- + {{ (nb_ok_line | regex_findall('^OK\\s+(\\S+)\\s+ip=([^\\s]+)\\s+fw=([^\\s]+)\\s+node=([^\\s]+)\\s+sector=([^\\s]+)\\s+small=([^\\s]+)')) | first | default([]) }} + set_fact: + nb_ok: "{{ (nb_preflight.rc | default(1)) == 0 and (nb_groups | length) == 6 }}" + nb_dev: "{{ nb_groups[0] | default('') }}" + nb_ip: "{{ nb_groups[1] | default('') }}" + nb_fw: "{{ nb_groups[2] | default('') }}" + nb_node: "{{ nb_groups[3] | default('') }}" + nb_sector: "{{ nb_groups[4] | default('') }}" + nb_small: "{{ nb_groups[5] | default('') }}" + nb_ok_line: "{{ nb_ok_line }}" + + # --- Heuristic for "cloud IP different from NetBox before update" --- + # We detect this via the script's chatty line: "IP: moving from iface=... -> ..." + - name: "NB preflight | Detect whether IP changed (cloud vs prior NetBox)" + when: nb_script.stat.exists + delegate_to: localhost + set_fact: + nb_ip_changed: "{{ (nb_preflight.stdout | default('')) is search('^IP:\\s+moving\\s+[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\s+from\\s+iface=', multiline=True) }}" + + - name: "NB preflight | Verdict" + when: nb_script.stat.exists + delegate_to: localhost + ansible.builtin.debug: + msg: + - "NB preflight verdict: {{ 'IP CHANGED (will requeue)' if nb_ip_changed else 'IP SAME (continue)' }}" + - "OK line: {{ nb_ok_line | default('') }}" + - "Parsed nb_ip={{ nb_ip | default('') }}" + + # --- If IP changed → publish a 3s delayed 'sot-updater' task and stop this host --- + - name: "NB preflight | Publish delayed requeue (3s) and stop" + when: + - nb_script.stat.exists + - nb_ip_changed | default(false) + delegate_to: localhost + uri: + url: "http://localhost:15672/api/exchanges/app/deviceconfig.delayed/publish" + method: POST + user: "admin" + password: "change_me" + force_basic_auth: true + status_code: 200 + headers: + content-type: "application/json" + body_format: json + body: + properties: + content_type: "application/json" + headers: + x-delay: 3000 + routing_key: "deviceconfig" + payload: "{{ {'inscope_device': (ansible_hostname | default(inventory_hostname)), 'task_name': 'sot-updater'} | to_json }}" + payload_encoding: "string" + register: rmq_requeue + changed_when: false + failed_when: false + + - name: "NB preflight | Log requeue publish response" + when: + - nb_script.stat.exists + - nb_ip_changed | default(false) + delegate_to: localhost + ansible.builtin.debug: + var: rmq_requeue.json + + - name: "NB preflight | Stop further tasks for this host" + when: + - nb_script.stat.exists + - nb_ip_changed | default(false) + meta: end_host + + # --- If IP did not change → optional 1s pause, then continue normally --- - name: "NB preflight | Pause 1s" + when: + - nb_script.stat.exists + - not (nb_ip_changed | default(false)) delegate_to: localhost ansible.builtin.pause: seconds: 1