diff --git a/files/ansible-playbooks/update-indoor.yml b/files/ansible-playbooks/update-indoor-old.yml similarity index 100% rename from files/ansible-playbooks/update-indoor.yml rename to files/ansible-playbooks/update-indoor-old.yml diff --git a/files/ansible-playbooks/update-indoor-scheduler.yml b/files/ansible-playbooks/update-indoor-scheduler.yml new file mode 100644 index 0000000..6d22d22 --- /dev/null +++ b/files/ansible-playbooks/update-indoor-scheduler.yml @@ -0,0 +1,66 @@ +# update-indoor-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-indoor6-stable.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 | Abort if nb_ip not available" + fail: + msg: "Wrapper preflight did not produce nb_ip. FAIL line: {{ nb_ip_err | default('') }}" + when: not nb_ip_ok + + - name: "Wrapper | Update ansible_host to nb_ip" + set_fact: + ansible_host: "{{ nb_ip }}" + changed_when: false + + - name: "Wrapper | Reset connection after ansible_host change" + meta: reset_connection + + +- import_playbook: update-indoor6-stable.yml + vars: + is_run_by: "scheduler" diff --git a/files/ansible-playbooks/update-indoor6-stable.yml b/files/ansible-playbooks/update-indoor6-stable.yml index d6bc73d..7d113c1 100644 --- a/files/ansible-playbooks/update-indoor6-stable.yml +++ b/files/ansible-playbooks/update-indoor6-stable.yml @@ -7,6 +7,9 @@ # Busybox-safe PATH prefix for all remote raw calls on DEV1 pathprefix: "PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH; " + # Invocation context (default: manual; scheduler wrapper sets is_run_by=scheduler) + is_run_by_effective: "{{ is_run_by | default('manual') }}" + # DEV1 credentials (stable, like rebootin222) dev1_user: "root" dev1_pass: "wavewave" @@ -81,6 +84,7 @@ - "image_sha256={{ image_sha256 | default('UNSET') }}" - "afterupgrade_routing_key={{ afterupgrade_routing_key | default('UNSET') }}" - "inventory_hostname={{ inventory_hostname }}" + - "is_run_by={{ is_run_by_effective }}" # ====== NEW: pick up force-upgrade flag from CLI and TEMP override ====== - name: Read force-upgrade flag from CLI (supports -e force-upgrade=yes) @@ -940,6 +944,40 @@ - "reboot_seconds={{ _reboot_seconds | default(0) }}" - "reboot_minutes={{ _reboot_minutes | default(0) }}" + - name: Scheduler mode compute action_restart_timestamp + when: is_run_by_effective == 'scheduler' + delegate_to: localhost + ansible.builtin.set_fact: + action_restart_now_ts: "{{ lookup('pipe', 'date +%s') | int }}" + action_restart_timestamp: "{{ (lookup('pipe', 'date +%s') | int) + (_reboot_seconds | int) }}" + changed_when: false + + - name: Scheduler mode publish action_restart_timestamp custom field to control queue + when: is_run_by_effective == 'scheduler' + 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_restart_timestamp', + 'task_result': (action_restart_timestamp | string) + } | to_json }}" + payload_encoding: "string" + changed_when: false + - name: Build human-readable reboot phrase delegate_to: localhost ansible.builtin.set_fact: @@ -1587,6 +1625,7 @@ correlation_id: "{{ au_correlation_id }}" original_emitted_at: "{{ au_original_emitted_at }}" schema_version: 1 + is_run_by: "{{ is_run_by_effective }}" when: au_delay_sec is defined delegate_to: localhost diff --git a/files/ansible-playbooks/update-reboot-scheduler.yml b/files/ansible-playbooks/update-reboot-scheduler.yml index f15d2e1..0ee54b9 100644 --- a/files/ansible-playbooks/update-reboot-scheduler.yml +++ b/files/ansible-playbooks/update-reboot-scheduler.yml @@ -3,7 +3,7 @@ # 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-rebootin224.yml -# Phase 4: Run afterupgrade_check.yml + - hosts: all gather_facts: no