This commit is contained in:
2026-02-12 09:01:15 +02:00
parent 9a0888cec9
commit 0b79d9dbfc
2 changed files with 177 additions and 5 deletions

View File

@@ -3,8 +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
# NOTE: update-rebootin224.yml is responsible for scheduling afterupgrade_check via RabbitMQ (delayed).
# Do NOT import/run afterupgrade_check.yml here.
# Phase 4: Run afterupgrade_check.yml
- hosts: all
gather_facts: no
@@ -42,9 +41,7 @@
_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('')) }}"
# NOTE: regex_search with a replacement can yield a list on some Ansible/Jinja versions;
# keep it as a plain string match for ansible_host.
_ip_raw: "{{ _ok_line | regex_search('([0-9]{1,3}(?:\\.[0-9]{1,3}){3})') | default('') }}"
_ip_raw: "{{ _ok_line | regex_search('([0-9]{1,3}(?:\\.[0-9]{1,3}){3})','\\1') | default('') }}"
set_fact:
nb_ip: "{{ _ip_raw }}"
nb_ip_ok: "{{ (_ip_raw | length) > 0 }}"
@@ -66,3 +63,5 @@
- import_playbook: update-rebootin224.yml
vars:
is_run_by: "scheduler"

View File

@@ -13,6 +13,9 @@
rmq_exchange: "{{ lookup('env','RMQ_EXCHANGE') | default('controls', true) }}"
control_queue: "{{ lookup('env','CONTROLQUEUE') | default('queue_controls', true) }}"
# Invocation context (default: manual; scheduler wrapper sets is_run_by=scheduler)
is_run_by_effective: "{{ is_run_by | default('manual') }}"
# NEW: Post-upgrade check scheduling (via holding queue -> DLX)
# The holding queue is bound to exchange 'deviceconfig.holding' with routing key 'deviceconfig'.
# Messages published here carry a per-message TTL (AMQP 'expiration' property, in ms).
@@ -139,9 +142,75 @@
(not (rmq_tag_failed_pre_resp.json.routed | default(false) | bool))
delegate_to: localhost
- name: Scheduler | Publish action_state failed (hostname preflight)
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_state',
'task_result': 'failed'
} | to_json }}"
payload_encoding: "string"
changed_when: false
delegate_to: localhost
when: is_run_by_effective == 'scheduler'
- name: Scheduler | Debug action_state failed published (hostname preflight)
ansible.builtin.debug:
msg: "scheduler-run detected; published action_state=failed (hostname preflight)"
when: is_run_by_effective == 'scheduler'
- name: Stop play after hostname preflight failure
ansible.builtin.meta: end_play
- name: Scheduler context | Debug is_run_by
ansible.builtin.debug:
msg: "is_run_by={{ is_run_by_effective }}"
- name: Scheduler | Publish action_state inprogress (scheduler-run)
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_state',
'task_result': 'inprogress'
} | to_json }}"
payload_encoding: "string"
changed_when: false
delegate_to: localhost
when: is_run_by_effective == 'scheduler'
- name: Scheduler | Debug action_state inprogress published
ansible.builtin.debug:
msg: "scheduler-run detected; published action_state=inprogress"
when: is_run_by_effective == 'scheduler'
# --- Tag device as update-in-progress at start ---
- name: Build control queue payload for update-in-progress tag
ansible.builtin.set_fact:
@@ -724,6 +793,79 @@
when: afterupgrade_payload is defined
delegate_to: localhost
- name: Scheduler | Publish action_state waiting (success)
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_state',
'task_result': 'waiting'
} | to_json }}"
payload_encoding: "string"
changed_when: false
delegate_to: localhost
when: is_run_by_effective == 'scheduler'
- name: Scheduler | Compute action_restart_timestamp (unix seconds) when reboot scheduled
ansible.builtin.set_fact:
action_restart_timestamp: "{{ (lookup('pipe','date -u +%s') | int) + (reboot_seconds | int) }}"
changed_when: false
delegate_to: localhost
when:
- is_run_by_effective == 'scheduler'
- reboot_seconds is defined
- (reboot_seconds | int) > 0
- name: Scheduler | Debug computed action_restart_timestamp
ansible.builtin.debug:
msg: "action_restart_timestamp={{ action_restart_timestamp }} (reboot_seconds={{ reboot_seconds | int }})"
when:
- is_run_by_effective == 'scheduler'
- action_restart_timestamp is defined
delegate_to: localhost
- name: Scheduler | Publish action_restart_timestamp custom field
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
delegate_to: localhost
when:
- is_run_by_effective == 'scheduler'
- action_restart_timestamp is defined
rescue:
- name: Build failure task name and detail
ansible.builtin.set_fact:
@@ -807,3 +949,34 @@
(rmq_tag_failed_resp.json is not defined) or
(not (rmq_tag_failed_resp.json.routed | default(false) | bool))
delegate_to: localhost
- name: Scheduler | Publish action_state failed (update failure)
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_state',
'task_result': 'failed'
} | to_json }}"
payload_encoding: "string"
changed_when: false
delegate_to: localhost
when: is_run_by_effective == 'scheduler'
- name: Scheduler | Debug action_state failed published (update failure)
ansible.builtin.debug:
msg: "scheduler-run detected; published action_state=failed (update failure)"
when: is_run_by_effective == 'scheduler'