1001
This commit is contained in:
@@ -1,35 +1,27 @@
|
|||||||
---
|
---
|
||||||
# updater.yml — read Dev1 & Dev2 firmware versions and publish to controls → netbox-reporter
|
# sot-updater.yml — Read Dev1 & Dev2 firmware and publish to controls → netbox-reporter
|
||||||
# Run: nbplay updater.yml <device>
|
# Run: nbplay sot-updater.yml <device>
|
||||||
|
|
||||||
- name: Read fw on Dev1 + Dev2, publish NetBox custom fields
|
- name: Read fw on Dev1 + Dev2, publish NetBox custom fields
|
||||||
hosts: all
|
hosts: all
|
||||||
gather_facts: no
|
gather_facts: no
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
# Busybox-safe PATH prefix for raw calls on DEV1 (as in update-rebootin222)
|
# Busybox-safe PATH prefix for raw calls on DEV1
|
||||||
pathprefix: "PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH; "
|
pathprefix: "PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH; "
|
||||||
|
|
||||||
# DEV1 credentials (as in update-indoor)
|
# DEV1 credentials for tunnel
|
||||||
dev1_user: "root"
|
dev1_user: "root"
|
||||||
dev1_pass: "wavewave"
|
dev1_pass: "wavewave"
|
||||||
|
|
||||||
# Tunnel target DEV2 behind DEV1 (as in update-indoor)
|
# Tunnel target DEV2 behind DEV1
|
||||||
dev2_host: "192.168.1.1"
|
dev2_host: "192.168.1.1"
|
||||||
dev2_port: 22
|
dev2_port: 22
|
||||||
dev2_ssh_user: "root"
|
dev2_ssh_user: "root"
|
||||||
dev2_side_ip: "192.168.1.11/24"
|
dev2_side_ip: "192.168.1.11/24"
|
||||||
dev1_iface: "br-wan"
|
dev1_iface: "br-wan"
|
||||||
|
|
||||||
# Password files sequence (as in update-indoor: try basicpass then basicpass2)
|
# Rabbit journaling defaults
|
||||||
# NOTE: The selection below mirrors the exact “try #1 → select → try #2 → select → NONE” flow from update-indoor.
|
|
||||||
# Do not alter ordering.
|
|
||||||
# (Values are file names as used in your repo/environment.)
|
|
||||||
# We do not loop; we replicate the same task structure.
|
|
||||||
# The read of firmux uses whichever got selected.
|
|
||||||
# — Pavel’s rule: on-device commands remain immutable; we’re only orchestrating controller-side steps here.
|
|
||||||
|
|
||||||
# Rabbit journaling (mirrors update-indoor / rebootin222)
|
|
||||||
rmq_host: "{{ lookup('env','RMQ_HOST') | default('10.210.12.2', true) }}"
|
rmq_host: "{{ lookup('env','RMQ_HOST') | default('10.210.12.2', true) }}"
|
||||||
rmq_port: "{{ lookup('env','RMQ_PORT') | default('15672', true) }}"
|
rmq_port: "{{ lookup('env','RMQ_PORT') | default('15672', true) }}"
|
||||||
rmq_user: "{{ lookup('env','RMQ_USER') | default('admin', true) }}"
|
rmq_user: "{{ lookup('env','RMQ_USER') | default('admin', true) }}"
|
||||||
@@ -39,12 +31,25 @@
|
|||||||
control_queue: "{{ lookup('env','CONTROLQUEUE') | default('queue_controls', true) }}"
|
control_queue: "{{ lookup('env','CONTROLQUEUE') | default('queue_controls', true) }}"
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
# ----------------------------- DEV1: read current banner (exactly like update-rebootin222) -----------------------------
|
# ───────────────────────── Progress: start ─────────────────────────
|
||||||
|
- name: ⚙️ Start | Device processing begins (Dev1 phase)
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Device: {{ inventory_hostname }}"
|
||||||
|
- "Phase: Dev1 (read banner & publish fw_version)"
|
||||||
|
|
||||||
|
# ───────────────────────── DEV1 ─────────────────────────
|
||||||
- name: Dev1 | Read first /etc/banner line containing 'rev'
|
- name: Dev1 | Read first /etc/banner line containing 'rev'
|
||||||
ansible.builtin.raw: "{{ pathprefix }} cat /etc/banner | grep -i rev | head -n1"
|
ansible.builtin.raw: "{{ pathprefix }} cat /etc/banner | grep -i rev | head -n1"
|
||||||
register: dev1_banner
|
register: dev1_banner
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Dev1 | Debug banner output
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Dev1 banner raw: {{ (dev1_banner.stdout | default('') | trim) | regex_replace('\\n',' ') }}"
|
||||||
|
|
||||||
|
# Keep the agreed format EXACTLY "X.Y.Z rev NNNN" (no timestamp).
|
||||||
- name: Dev1 | Extract 'X.Y.Z rev NNNN' from banner (no timestamp)
|
- name: Dev1 | Extract 'X.Y.Z rev NNNN' from banner (no timestamp)
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
set_fact:
|
set_fact:
|
||||||
@@ -54,6 +59,36 @@
|
|||||||
| regex_replace('^(.+?[Rr][Ee][Vv]\\.??\\s*[0-9]+).*$', '\\1')
|
| regex_replace('^(.+?[Rr][Ee][Vv]\\.??\\s*[0-9]+).*$', '\\1')
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
- name: Dev1 | Debug normalized fw string to be published
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Dev1 fw_version (clean): {{ dev1_fw_clean }}"
|
||||||
|
|
||||||
|
# Build a preview of the EXACT payload string (for troubleshooting).
|
||||||
|
- name: Dev1 | Build payload preview string
|
||||||
|
delegate_to: localhost
|
||||||
|
set_fact:
|
||||||
|
dev1_payload_preview: >-
|
||||||
|
{{
|
||||||
|
{
|
||||||
|
"properties": {"content_type": "application/json"},
|
||||||
|
"routing_key": control_queue,
|
||||||
|
"payload": ({
|
||||||
|
"inscope_device": (ansible_hostname | default(inventory_hostname)),
|
||||||
|
"task_name": "custom_field_set",
|
||||||
|
"task_add1": "fw_version",
|
||||||
|
"task_result": dev1_fw_clean
|
||||||
|
} | to_json),
|
||||||
|
"payload_encoding": "string"
|
||||||
|
} | to_json
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: Dev1 | Debug EXACT publish body (payload preview)
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
var: dev1_payload_preview
|
||||||
|
|
||||||
- name: Publish → controls | custom_field_set fw_version (Dev1)
|
- name: Publish → controls | custom_field_set fw_version (Dev1)
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.uri:
|
ansible.builtin.uri:
|
||||||
@@ -75,9 +110,22 @@
|
|||||||
'task_result': dev1_fw_clean
|
'task_result': dev1_fw_clean
|
||||||
} | to_json }}"
|
} | to_json }}"
|
||||||
payload_encoding: "string"
|
payload_encoding: "string"
|
||||||
|
register: dev1_publish_resp
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
# ----------------------------- TUNNEL PREP (update-indoor blocks copied) -----------------------------
|
- name: Dev1 | Debug publish API response
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Dev1 publish response: {{ dev1_publish_resp.json | default(dev1_publish_resp) }}"
|
||||||
|
|
||||||
|
- name: ✅ Progress | Completed Dev1, moving to tunnel & Dev2 phase
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Device: {{ inventory_hostname }}"
|
||||||
|
- "Phase switch: Dev1 done → Dev2 (tunnel, auth, read indoor_fwver)"
|
||||||
|
|
||||||
|
# ───────────────────────── TUNNEL PREP ─────────────────────────
|
||||||
- name: Add temporary IP on DEV1 (tolerate 'File exists')
|
- name: Add temporary IP on DEV1 (tolerate 'File exists')
|
||||||
ansible.builtin.raw: >
|
ansible.builtin.raw: >
|
||||||
{{ pathprefix }}
|
{{ pathprefix }}
|
||||||
@@ -88,6 +136,13 @@
|
|||||||
and ('File exists' not in (add_ip.stdout | default('')))
|
and ('File exists' not in (add_ip.stdout | default('')))
|
||||||
and ('File exists' not in (add_ip.stderr | default('')))
|
and ('File exists' not in (add_ip.stderr | default('')))
|
||||||
|
|
||||||
|
- name: Debug | temp IP add result
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Add IP rc={{ add_ip.rc }}"
|
||||||
|
- "stdout={{ (add_ip.stdout | default('')) | trim }}"
|
||||||
|
- "stderr={{ (add_ip.stderr | default('')) | trim }}"
|
||||||
|
|
||||||
- name: Pick a free local TCP port for the tunnel (controller)
|
- name: Pick a free local TCP port for the tunnel (controller)
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.shell: |
|
||||||
@@ -111,6 +166,12 @@
|
|||||||
register: pick_port
|
register: pick_port
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Debug | chosen local tunnel port
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Chosen local port: {{ pick_port.stdout | trim }}"
|
||||||
|
|
||||||
- name: Stop if no free local port was found
|
- name: Stop if no free local port was found
|
||||||
ansible.builtin.meta: end_host
|
ansible.builtin.meta: end_host
|
||||||
when: (pick_port.stdout | trim | length) == 0
|
when: (pick_port.stdout | trim | length) == 0
|
||||||
@@ -130,6 +191,12 @@
|
|||||||
set_fact:
|
set_fact:
|
||||||
_ctrl_sock: "{{ _ctrl_dir }}/ssh_tunnel_ctl"
|
_ctrl_sock: "{{ _ctrl_dir }}/ssh_tunnel_ctl"
|
||||||
|
|
||||||
|
- name: Debug | ControlMaster paths
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "_ctrl_dir={{ _ctrl_dir }}"
|
||||||
|
- "_ctrl_sock={{ _ctrl_sock }}"
|
||||||
|
|
||||||
- name: Start SSH ControlMaster and forward 127.0.0.1:local → DEV2:22 via DEV1
|
- name: Start SSH ControlMaster and forward 127.0.0.1:local → DEV2:22 via DEV1
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
@@ -148,6 +215,14 @@
|
|||||||
register: start_tunnel
|
register: start_tunnel
|
||||||
changed_when: true
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Debug | tunnel start status
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Started ControlMaster tunnel (rc={{ start_tunnel.rc | default('n/a') }})"
|
||||||
|
- "stdout={{ (start_tunnel.stdout | default('')) | trim }}"
|
||||||
|
- "stderr={{ (start_tunnel.stderr | default('')) | trim }}"
|
||||||
|
|
||||||
- name: Probe TCP reachability to DEV2 through the tunnel
|
- name: Probe TCP reachability to DEV2 through the tunnel
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.shell: "nc -z -w5 127.0.0.1 {{ _local_port }}"
|
ansible.builtin.shell: "nc -z -w5 127.0.0.1 {{ _local_port }}"
|
||||||
@@ -155,11 +230,25 @@
|
|||||||
changed_when: false
|
changed_when: false
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Debug | tunnel probe result
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Tunnel TCP probe rc={{ nc_probe.rc }} (0=OK)"
|
||||||
|
- "stdout={{ (nc_probe.stdout | default('')) | trim }}"
|
||||||
|
- "stderr={{ (nc_probe.stderr | default('')) | trim }}"
|
||||||
|
|
||||||
- name: Stop if tunnel TCP probe failed
|
- name: Stop if tunnel TCP probe failed
|
||||||
ansible.builtin.meta: end_host
|
ansible.builtin.meta: end_host
|
||||||
when: nc_probe.rc != 0
|
when: nc_probe.rc != 0
|
||||||
|
|
||||||
# ----------------------------- DEV2 AUTH PICK (exact task sequence from update-indoor) -----------------------------
|
- name: ✅ Progress | Tunnel OK, proceeding to Dev2 auth and reads
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Device: {{ inventory_hostname }}"
|
||||||
|
- "Phase: Dev2 (auth selection, firmux/banner read)"
|
||||||
|
|
||||||
|
# ───────────────────────── DEV2 AUTH PICK (as per update-indoor) ─────────────────────────
|
||||||
- name: Try DEV2 login with 'basicpass' (root)
|
- name: Try DEV2 login with 'basicpass' (root)
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.shell: |
|
||||||
@@ -175,6 +264,11 @@
|
|||||||
changed_when: false
|
changed_when: false
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Debug | basicpass try rc
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg: "DEV2 'basicpass' try rc={{ dev2_try_basicpass.rc }} (0=OK)"
|
||||||
|
|
||||||
- name: Select 'basicpass' if previous login succeeded
|
- name: Select 'basicpass' if previous login succeeded
|
||||||
when: dev2_try_basicpass.rc == 0
|
when: dev2_try_basicpass.rc == 0
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
@@ -198,6 +292,11 @@
|
|||||||
changed_when: false
|
changed_when: false
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Debug | basicpass2 try rc
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg: "DEV2 'basicpass2' try rc={{ dev2_try_basicpass2.rc | default('n/a') }} (0=OK)"
|
||||||
|
|
||||||
- name: Select 'basicpass2' if previous login succeeded
|
- name: Select 'basicpass2' if previous login succeeded
|
||||||
when: dev2_passfile_used is not defined and dev2_try_basicpass2.rc == 0
|
when: dev2_passfile_used is not defined and dev2_try_basicpass2.rc == 0
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
@@ -212,7 +311,12 @@
|
|||||||
dev2_passfile_used: "NONE"
|
dev2_passfile_used: "NONE"
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
# ----------------------------- DEV2 firmware read (update-indoor firmux primary check) -----------------------------
|
- name: Debug | selected passfile
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg: "DEV2 passfile used: {{ dev2_passfile_used }}"
|
||||||
|
|
||||||
|
# ───────────────────────── DEV2 READS ─────────────────────────
|
||||||
- name: Dev2 | Read /usr/lib/release/firmux (if present)
|
- name: Dev2 | Read /usr/lib/release/firmux (if present)
|
||||||
when: dev2_passfile_used != "NONE"
|
when: dev2_passfile_used != "NONE"
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
@@ -259,7 +363,13 @@
|
|||||||
else (dev2_banner.stdout | default('') | trim)
|
else (dev2_banner.stdout | default('') | trim)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
- name: Dev2 | Normalize to X.Y.Z-rNNNN (convert trailing 'rev NNNN' → '-rNNNN')
|
- name: Dev2 | Debug raw indoor fw string
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Dev2 indoor_fw_raw: {{ indoor_fw_raw }}"
|
||||||
|
|
||||||
|
- name: Dev2 | Normalize to 'X.Y.Z rev NNNN' or already '-rNNNN' style
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
indoor_fw_norm: >-
|
indoor_fw_norm: >-
|
||||||
@@ -271,6 +381,43 @@
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
- name: Dev2 | Debug normalized indoor fw string
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Dev2 indoor_fw_norm: {{ indoor_fw_norm }}"
|
||||||
|
|
||||||
|
# Build payload preview (exact string).
|
||||||
|
- name: Dev2 | Build payload preview string
|
||||||
|
when:
|
||||||
|
- dev2_passfile_used != "NONE"
|
||||||
|
- indoor_fw_norm is defined
|
||||||
|
- (indoor_fw_norm | length) > 0
|
||||||
|
delegate_to: localhost
|
||||||
|
set_fact:
|
||||||
|
dev2_payload_preview: >-
|
||||||
|
{{
|
||||||
|
{
|
||||||
|
"properties": {"content_type": "application/json"},
|
||||||
|
"routing_key": control_queue,
|
||||||
|
"payload": ({
|
||||||
|
"inscope_device": (ansible_hostname | default(inventory_hostname)),
|
||||||
|
"task_name": "custom_field_set",
|
||||||
|
"task_add1": "indoor_fwver",
|
||||||
|
"task_result": indoor_fw_norm
|
||||||
|
} | to_json),
|
||||||
|
"payload_encoding": "string"
|
||||||
|
} | to_json
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: Dev2 | Debug EXACT publish body (payload preview)
|
||||||
|
when:
|
||||||
|
- dev2_passfile_used != "NONE"
|
||||||
|
- dev2_payload_preview is defined
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
var: dev2_payload_preview
|
||||||
|
|
||||||
- name: Publish → controls | custom_field_set indoor_fwver (Dev2)
|
- name: Publish → controls | custom_field_set indoor_fwver (Dev2)
|
||||||
when:
|
when:
|
||||||
- dev2_passfile_used != "NONE"
|
- dev2_passfile_used != "NONE"
|
||||||
@@ -296,9 +443,22 @@
|
|||||||
'task_result': indoor_fw_norm
|
'task_result': indoor_fw_norm
|
||||||
} | to_json }}"
|
} | to_json }}"
|
||||||
payload_encoding: "string"
|
payload_encoding: "string"
|
||||||
|
register: dev2_publish_resp
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Dev2 | Debug publish API response
|
||||||
|
when: dev2_publish_resp is defined
|
||||||
|
delegate_to: localhost
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Dev2 publish response: {{ dev2_publish_resp.json | default(dev2_publish_resp) }}"
|
||||||
|
|
||||||
post_tasks:
|
post_tasks:
|
||||||
|
- name: ✅ Progress | Finishing up (cleanup)
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Cleanup phase: closing ControlMaster & removing temp IP"
|
||||||
|
|
||||||
- name: Close SSH ControlMaster (best-effort)
|
- name: Close SSH ControlMaster (best-effort)
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.shell: "ssh -S '{{ _ctrl_sock | default('/dev/null') }}' -O exit 2>/dev/null || true"
|
ansible.builtin.shell: "ssh -S '{{ _ctrl_sock | default('/dev/null') }}' -O exit 2>/dev/null || true"
|
||||||
@@ -321,3 +481,16 @@
|
|||||||
failed_when: del_ip.rc != 0
|
failed_when: del_ip.rc != 0
|
||||||
and ('Cannot assign requested address' not in (del_ip.stdout | default('')))
|
and ('Cannot assign requested address' not in (del_ip.stdout | default('')))
|
||||||
and ('Cannot assign requested address' not in (del_ip.stderr | default('')))
|
and ('Cannot assign requested address' not in (del_ip.stderr | default('')))
|
||||||
|
|
||||||
|
- name: Debug | temp IP del result
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Del IP rc={{ del_ip.rc }}"
|
||||||
|
- "stdout={{ (del_ip.stdout | default('')) | trim }}"
|
||||||
|
- "stderr={{ (del_ip.stderr | default('')) | trim }}"
|
||||||
|
|
||||||
|
- name: ✅ Progress | Completed device processing
|
||||||
|
debug:
|
||||||
|
msg:
|
||||||
|
- "Device: {{ inventory_hostname }}"
|
||||||
|
- "Status: DONE (Dev1+Dev2 processed)"
|
||||||
|
|||||||
Reference in New Issue
Block a user