# update-outdoorbackup-scheduler.yml # Single nbplay invocation: # Phase 1: Cloud -> NetBox sync (via sot-updater-iponly.yml in wrapper mode) # Phase 2: Refresh ansible_host from nb_ip, reset_connection # Phase 3: Run update-outdoorbackup224.yml - hosts: all gather_facts: no vars: rmq_host: "{{ lookup('env','RMQ_HOST') | default('10.210.12.2', true) }}" rmq_port: "{{ lookup('env','RMQ_PORT') | default('15672', true) }}" rmq_user: "{{ lookup('env','RMQ_USER') | default('admin', true) }}" rmq_pass: "{{ lookup('env','RMQ_PASS') | default('change_me', true) }}" rmq_vhost: "{{ lookup('env','RMQ_VHOST') | default('app', true) }}" rmq_exchange: "{{ lookup('env','RMQ_EXCHANGE') | default('controls', true) }}" control_queue: "{{ lookup('env','CONTROLQUEUE') | default('queue_controls', true) }}" tasks: [] - import_playbook: sot-updater-iponly.yml vars: sot_wrapper_mode: true - name: Phase 2 | Refresh in-memory target IP after iponly hosts: all gather_facts: no vars: rmq_host: "{{ lookup('env','RMQ_HOST') | default('10.210.12.2', true) }}" rmq_port: "{{ lookup('env','RMQ_PORT') | default('15672', true) }}" rmq_user: "{{ lookup('env','RMQ_USER') | default('admin', true) }}" rmq_pass: "{{ lookup('env','RMQ_PASS') | default('change_me', true) }}" rmq_vhost: "{{ lookup('env','RMQ_VHOST') | default('app', true) }}" rmq_exchange: "{{ lookup('env','RMQ_EXCHANGE') | default('controls', true) }}" control_queue: "{{ lookup('env','CONTROLQUEUE') | default('queue_controls', true) }}" tasks: - name: "Wrapper | Extract nb_ip from nb_onedevice_update.py stdout" vars: _lines: "{{ (nb_preflight.stdout_lines | default([])) | map('regex_replace','\r','') | map('trim') | list }}" _ok_line: "{{ (_lines | select('match','^OK\\s+') | list | last | default('')) }}" _fail_line: "{{ (_lines | select('match','^FAIL\\s+') | list | last | default('')) }}" _ip_raw: "{{ _ok_line | regex_search('([0-9]{1,3}(?:\\.[0-9]{1,3}){3})') | default('') }}" set_fact: nb_ip: "{{ _ip_raw }}" nb_ip_ok: "{{ (_ip_raw | length) > 0 }}" nb_ip_err: "{{ _fail_line }}" changed_when: false - name: "Wrapper | Continue with inventory IP if nb_ip not available" debug: msg: "Wrapper preflight did not produce nb_ip, keeping current inventory ansible_host. FAIL line: {{ nb_ip_err | default('') }}" when: not nb_ip_ok changed_when: false - name: "Wrapper | Debug before ansible_host override" debug: msg: - "inventory_hostname={{ inventory_hostname }}" - "ansible_host(before)={{ ansible_host | default('UNSET') }}" - "ansible_port={{ ansible_port | default('22') }}" - "nb_ip={{ nb_ip | default('UNSET') }}" changed_when: false - name: "Wrapper | Update ansible_host to nb_ip" set_fact: ansible_host: "{{ nb_ip }}" when: nb_ip_ok changed_when: false - name: "Wrapper | Debug after ansible_host override" debug: msg: - "inventory_hostname={{ inventory_hostname }}" - "ansible_host(after)={{ ansible_host | default('UNSET') }}" - "ansible_port={{ ansible_port | default('22') }}" changed_when: false - name: "Wrapper | Reset connection after ansible_host change" meta: reset_connection when: nb_ip_ok - name: "Wrapper | Debug after reset_connection" debug: msg: - "inventory_hostname={{ inventory_hostname }}" - "ansible_host(post_reset)={{ ansible_host | default('UNSET') }}" - "ansible_port={{ ansible_port | default('22') }}" changed_when: false - name: "Wrapper | Pause 2s before next playbook" pause: seconds: 2 changed_when: false - import_playbook: update-outdoorbackup225.yml vars: is_run_by: "scheduler" - name: Phase 4 | Scheduled success only | Chain sot-updater-scheduler hosts: all gather_facts: no vars: rmq_host: "{{ lookup('env','RMQ_HOST') | default('10.210.12.2', true) }}" rmq_port: "{{ lookup('env','RMQ_PORT') | default('15672', true) }}" rmq_user: "{{ lookup('env','RMQ_USER') | default('admin', true) }}" rmq_pass: "{{ lookup('env','RMQ_PASS') | default('change_me', true) }}" rmq_vhost: "{{ lookup('env','RMQ_VHOST') | default('app', true) }}" rmq_exchange: "{{ lookup('env','RMQ_EXCHANGE') | default('controls', true) }}" control_queue: "{{ lookup('env','CONTROLQUEUE') | default('queue_controls', true) }}" tasks: - name: Scheduled success | Set action_next to sot-updater-scheduler when: - hostvars[inventory_hostname].journal_success_payload is defined delegate_to: localhost ansible.builtin.uri: url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ rmq_exchange | urlencode }}/publish" method: POST user: "{{ rmq_user }}" password: "{{ rmq_pass }}" force_basic_auth: true status_code: 200 headers: content-type: "application/json" body_format: json body: properties: content_type: "application/json" routing_key: "{{ control_queue }}" payload: "{{ { 'inscope_device': (ansible_hostname | default(inventory_hostname)), 'task_name': 'custom_field_set', 'task_add1': 'action_next', 'task_result': 'sot-updater-scheduler' } | to_json }}" payload_encoding: "string" changed_when: false - name: Scheduled success | Publish sot-updater-scheduler work message when: - hostvars[inventory_hostname].journal_success_payload is defined delegate_to: localhost ansible.builtin.uri: url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ 'deviceconfig' | urlencode }}/publish" method: POST user: "{{ rmq_user }}" password: "{{ rmq_pass }}" force_basic_auth: true status_code: 200 headers: content-type: "application/json" body_format: json body: properties: content_type: "application/json" routing_key: "deviceconfig" payload: "{{ { 'inscope_device': (ansible_hostname | default(inventory_hostname)), 'task_name': 'sot-updater-scheduler' } | to_json }}" payload_encoding: "string" changed_when: false