1205
This commit is contained in:
@@ -2,26 +2,41 @@
|
|||||||
# sot-updater.yml — Read Dev1 & Dev2 firmware and publish to controls → netbox-reporter
|
# sot-updater.yml — Read Dev1 & Dev2 firmware and publish to controls → netbox-reporter
|
||||||
# Run: nbplay sot-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 (full base, AIRPINGs, soft-fail telemetry)
|
||||||
hosts: all
|
hosts: all
|
||||||
gather_facts: no
|
gather_facts: no
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
# Busybox-safe PATH prefix for raw calls on DEV1
|
# Busybox-safe PATH prefix for *all* raw calls on DEV1
|
||||||
pathprefix: "PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH; "
|
pathprefix: "PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH; "
|
||||||
|
|
||||||
# DEV1 credentials for tunnel
|
# DEV1 credentials (controller-side)
|
||||||
dev1_user: "root"
|
dev1_user: "root"
|
||||||
dev1_pass: "wavewave"
|
dev1_pass: "wavewave"
|
||||||
|
ssh_timeout: 30
|
||||||
|
|
||||||
# Tunnel target DEV2 behind DEV1
|
# 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_passfiles: [ "basicpass", "basicpass2" ]
|
||||||
dev1_iface: "br-wan"
|
|
||||||
|
|
||||||
# Rabbit journaling defaults
|
# DEV1 side addressing to reach DEV2
|
||||||
|
dev2_side_ip: "192.168.1.11/24" # IP we add/remove on DEV1
|
||||||
|
dev1_iface: "br-wan" # DEV1 interface where IP is added
|
||||||
|
arping_iface: "eth0" # iface used for ARP refreshes (as per update-indoor)
|
||||||
|
dev2_side_ip_addr: "{{ dev2_side_ip.split('/')[0] }}"
|
||||||
|
|
||||||
|
# Controller SSH common opts
|
||||||
|
ssh_opts_common: >-
|
||||||
|
-o PreferredAuthentications=password
|
||||||
|
-o PubkeyAuthentication=no
|
||||||
|
-o StrictHostKeyChecking=no
|
||||||
|
-o UserKnownHostsFile=/dev/null
|
||||||
|
-o NumberOfPasswordPrompts=1
|
||||||
|
-o ConnectTimeout=30
|
||||||
|
|
||||||
|
# Rabbit (controls)
|
||||||
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) }}"
|
||||||
@@ -32,65 +47,26 @@
|
|||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
# ───────────────────────── Progress: start ─────────────────────────
|
# ───────────────────────── Progress: start ─────────────────────────
|
||||||
- name: "⚙️ Start | Device processing begins (Dev1 phase)"
|
- name: "⚙️ Start | Dev1 banner → tunnel/auth → Dev2 firmux (telemetry mode)"
|
||||||
debug:
|
debug:
|
||||||
msg:
|
msg:
|
||||||
- "Device: {{ inventory_hostname }}"
|
- "Device: {{ inventory_hostname }}"
|
||||||
- "Phase: Dev1 (read banner & publish fw_version)"
|
- "Mode: report-only (soft-fail; publish journals on failures)"
|
||||||
|
|
||||||
# ───────────────────────── DEV1 ─────────────────────────
|
# ---------------------------- Temp IP on DEV1 ----------------------------
|
||||||
- name: Dev1 | Read first /etc/banner line containing 'rev'
|
- name: Add temporary IP on DEV1 (tolerate 'File exists'; soft-fail)
|
||||||
ansible.builtin.raw: "{{ pathprefix }} cat /etc/banner | grep -i rev | head -n1"
|
ansible.builtin.raw: >
|
||||||
register: dev1_banner
|
{{ pathprefix }}
|
||||||
changed_when: false
|
ip a add {{ dev2_side_ip }} dev {{ dev1_iface }}
|
||||||
|
register: add_ip
|
||||||
|
changed_when: add_ip.rc == 0
|
||||||
|
failed_when: false
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Dev1 | Debug banner output
|
- name: Soft-report if temp IP add failed (not just 'File exists')
|
||||||
debug:
|
when: add_ip.rc is defined and add_ip.rc != 0 and
|
||||||
msg:
|
('File exists' not in (add_ip.stdout | default(''))) and
|
||||||
- "Dev1 banner raw: {{ (dev1_banner.stdout | default('') | trim) | regex_replace('\\n',' ') }}"
|
('File exists' not in (add_ip.stderr | default('')))
|
||||||
|
|
||||||
- name: Dev1 | Strip trailing timestamp after pipe
|
|
||||||
delegate_to: localhost
|
|
||||||
set_fact:
|
|
||||||
dev1_fw_base: "{{ (dev1_banner.stdout | default('') | trim) | regex_replace('\\s*\\|.*$', '') }}"
|
|
||||||
|
|
||||||
- name: Dev1 | Convert '... rev NNNN' → '...-rNNNN'
|
|
||||||
delegate_to: localhost
|
|
||||||
set_fact:
|
|
||||||
dev1_fw_clean: "{{ dev1_fw_base | regex_replace('\\s*[Rr][Ee][Vv]\\.??\\s*([0-9]+)\\s*$', '-r\\1') }}"
|
|
||||||
|
|
||||||
- name: Dev1 | Debug normalized fw string to be published
|
|
||||||
delegate_to: localhost
|
|
||||||
debug:
|
|
||||||
msg:
|
|
||||||
- "Dev1 fw_version (clean): {{ dev1_fw_clean }}"
|
|
||||||
|
|
||||||
# Build payload preview for Dev1 (so the next debug is defined)
|
|
||||||
- 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)
|
|
||||||
when: dev1_payload_preview is defined
|
|
||||||
delegate_to: localhost
|
|
||||||
debug:
|
|
||||||
var: dev1_payload_preview
|
|
||||||
|
|
||||||
- name: Publish → controls | custom_field_set fw_version (Dev1)
|
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.uri:
|
ansible.builtin.uri:
|
||||||
url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ rmq_exchange | urlencode }}/publish"
|
url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ rmq_exchange | urlencode }}/publish"
|
||||||
@@ -106,58 +82,31 @@
|
|||||||
routing_key: "{{ control_queue }}"
|
routing_key: "{{ control_queue }}"
|
||||||
payload: "{{ {
|
payload: "{{ {
|
||||||
'inscope_device': (ansible_hostname | default(inventory_hostname)),
|
'inscope_device': (ansible_hostname | default(inventory_hostname)),
|
||||||
'task_name': 'custom_field_set',
|
'task_name': 'journal_entry',
|
||||||
'task_add1': 'fw_version',
|
'task_result': 'temp_ip_add_failed',
|
||||||
'task_result': dev1_fw_clean
|
'task_add1': 'rc=' ~ (add_ip.rc | string),
|
||||||
|
'task_add2': (add_ip.stderr | default(add_ip.stdout) | trim)[:512]
|
||||||
} | to_json }}"
|
} | to_json }}"
|
||||||
payload_encoding: "string"
|
payload_encoding: "string"
|
||||||
register: dev1_publish_resp
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Dev1 | Debug publish API response
|
- name: Debug temp IP add
|
||||||
delegate_to: localhost
|
|
||||||
debug:
|
debug:
|
||||||
msg:
|
msg:
|
||||||
- "Dev1 publish response: {{ dev1_publish_resp.json | default(dev1_publish_resp) }}"
|
- "rc={{ add_ip.rc | default('') }}"
|
||||||
|
|
||||||
- name: "✅ Progress | Completed Dev1, moving to tunnel & Dev2 phase"
|
|
||||||
debug:
|
|
||||||
msg:
|
|
||||||
- "Device: {{ inventory_hostname }}"
|
|
||||||
- "Phase switch: Dev1 done → Dev2 (tunnel, auth, read indoor_fwver)"
|
|
||||||
|
|
||||||
- name: Dev2 | ARP ping the target (from Dev1) to confirm who is at {{ dev2_host }}
|
|
||||||
ansible.builtin.raw: >
|
|
||||||
{{ pathprefix }}
|
|
||||||
arping -c 1 -w 2 -I {{ dev1_iface }} {{ dev2_host }} 2>&1 || true
|
|
||||||
register: dev2_arping
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Debug | arping summary (MAC & replies)
|
|
||||||
debug:
|
|
||||||
msg:
|
|
||||||
- "arping rc={{ dev2_arping.rc }}"
|
|
||||||
- "arping stdout={{ (dev2_arping.stdout | default('')) | trim }}"
|
|
||||||
- "arping stderr={{ (dev2_arping.stderr | default('')) | trim }}"
|
|
||||||
|
|
||||||
# ───────────────────────── TUNNEL PREP ─────────────────────────
|
|
||||||
- name: Add temporary IP on DEV1 (tolerate 'File exists')
|
|
||||||
ansible.builtin.raw: >
|
|
||||||
{{ pathprefix }}
|
|
||||||
ip a add {{ dev2_side_ip }} dev {{ dev1_iface }}
|
|
||||||
register: add_ip
|
|
||||||
changed_when: add_ip.rc == 0
|
|
||||||
failed_when: add_ip.rc != 0
|
|
||||||
and ('File exists' not in (add_ip.stdout | 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 }}"
|
- "stdout={{ (add_ip.stdout | default('')) | trim }}"
|
||||||
- "stderr={{ (add_ip.stderr | default('')) | trim }}"
|
- "stderr={{ (add_ip.stderr | default('')) | trim }}"
|
||||||
|
|
||||||
|
# ---------------------------- AIRPING #1 (early refresh) ----------------------------
|
||||||
|
- name: Refresh ARP #1 on DEV1 LAN (unsolicited)
|
||||||
|
ansible.builtin.raw: >
|
||||||
|
{{ pathprefix }}
|
||||||
|
arping -U -I {{ arping_iface }} {{ dev2_side_ip_addr }} -c 3
|
||||||
|
register: arping1
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
# ---------------------------- Local tunnel prep ----------------------------
|
||||||
- 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: |
|
||||||
@@ -181,120 +130,180 @@
|
|||||||
register: pick_port
|
register: pick_port
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: Debug | chosen local tunnel port
|
- name: Record chosen local port & ControlMaster path (or note failure)
|
||||||
delegate_to: localhost
|
|
||||||
debug:
|
|
||||||
msg:
|
|
||||||
- "Chosen local port: {{ pick_port.stdout | trim }}"
|
|
||||||
|
|
||||||
- name: Stop if no free local port was found
|
|
||||||
ansible.builtin.meta: end_host
|
|
||||||
when: (pick_port.stdout | trim | length) == 0
|
|
||||||
|
|
||||||
- name: Record chosen local port
|
|
||||||
delegate_to: localhost
|
|
||||||
set_fact:
|
|
||||||
_local_port: "{{ pick_port.stdout | trim }}"
|
|
||||||
|
|
||||||
- name: Create ControlMaster socket dir (mktemp)
|
|
||||||
delegate_to: localhost
|
|
||||||
set_fact:
|
|
||||||
_ctrl_dir: "{{ lookup('pipe', 'mktemp -d') }}"
|
|
||||||
|
|
||||||
- name: Compose ControlMaster socket path
|
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
set_fact:
|
set_fact:
|
||||||
|
_local_port: "{{ (pick_port.stdout | default('') | trim) }}"
|
||||||
|
_ctrl_dir: "{{ lookup('ansible.builtin.pipe', 'mktemp -d') }}"
|
||||||
_ctrl_sock: "{{ _ctrl_dir }}/ssh_tunnel_ctl"
|
_ctrl_sock: "{{ _ctrl_dir }}/ssh_tunnel_ctl"
|
||||||
|
|
||||||
- name: Debug | ControlMaster paths
|
- name: Journal if no free local port was found (continue anyway)
|
||||||
|
when: _local_port | length == 0
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
debug:
|
ansible.builtin.uri:
|
||||||
msg:
|
url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ rmq_exchange | urlencode }}/publish"
|
||||||
- "_ctrl_dir={{ _ctrl_dir }}"
|
method: POST
|
||||||
- "_ctrl_sock={{ _ctrl_sock }}"
|
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': 'journal_entry',
|
||||||
|
'task_result': 'tunnel_port_pick_failed'
|
||||||
|
} | to_json }}"
|
||||||
|
payload_encoding: "string"
|
||||||
|
|
||||||
- name: Dev2 | ARP ping the target (from Dev1) to confirm who is at {{ dev2_host }}
|
# ---------------------------- AIRPING #2 (before tunnel) ----------------------------
|
||||||
|
- name: Refresh ARP #2 on DEV1 LAN (pre-tunnel)
|
||||||
|
when: _local_port | length > 0
|
||||||
ansible.builtin.raw: >
|
ansible.builtin.raw: >
|
||||||
{{ pathprefix }}
|
{{ pathprefix }}
|
||||||
arping -c 1 -w 2 -I {{ dev1_iface }} {{ dev2_host }} 2>&1 || true
|
arping -U -I {{ arping_iface }} {{ dev2_side_ip_addr }} -c 3
|
||||||
register: dev2_arping
|
register: arping2
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Debug | arping summary (MAC & replies)
|
# ---------------------------- Start tunnel via DEV1 ----------------------------
|
||||||
debug:
|
|
||||||
msg:
|
|
||||||
- "arping rc={{ dev2_arping.rc }}"
|
|
||||||
- "arping stdout={{ (dev2_arping.stdout | default('')) | trim }}"
|
|
||||||
- "arping stderr={{ (dev2_arping.stderr | default('')) | trim }}"
|
|
||||||
|
|
||||||
- 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
|
||||||
|
when: _local_port | length > 0
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.shell: |
|
||||||
set -e
|
set -e
|
||||||
USER="{{ dev1_user }}"
|
USER="{{ dev1_user }}"
|
||||||
HOST="{{ ansible_host | default(inventory_hostname) }}"
|
HOST="{{ ansible_host | default(inventory_hostname) }}"
|
||||||
sshpass -p '{{ dev1_pass }}' ssh -f -N \
|
sshpass -p '{{ dev1_pass }}' ssh -f -N {{ ssh_opts_common }} \
|
||||||
-o PreferredAuthentications=password -o PubkeyAuthentication=no \
|
|
||||||
-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
|
||||||
-o NumberOfPasswordPrompts=1 -o ConnectTimeout=30 \
|
|
||||||
-M -S "{{ _ctrl_sock }}" \
|
-M -S "{{ _ctrl_sock }}" \
|
||||||
-L "127.0.0.1:{{ _local_port }}:{{ dev2_host }}:{{ dev2_port }}" \
|
-L "127.0.0.1:{{ _local_port }}:{{ dev2_host }}:{{ dev2_port }}" \
|
||||||
"${USER}@${HOST}"
|
"${USER}@${HOST}"
|
||||||
args: { executable: /bin/bash }
|
args: { executable: /bin/bash }
|
||||||
register: start_tunnel
|
register: start_tunnel
|
||||||
changed_when: true
|
changed_when: true
|
||||||
|
failed_when: false
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Debug | tunnel start status
|
- name: Probe TCP reachability to DEV2 through the tunnel (nc)
|
||||||
delegate_to: localhost
|
when: _local_port | length > 0
|
||||||
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
|
|
||||||
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 }}"
|
||||||
register: nc_probe
|
register: nc_probe
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Debug | tunnel probe result
|
- name: Set tunnel_ok fact
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
debug:
|
set_fact:
|
||||||
msg:
|
tunnel_ok: "{{ (_local_port | length > 0) and (nc_probe.rc is defined) and (nc_probe.rc == 0) }}"
|
||||||
- "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: Journal if tunnel probe failed
|
||||||
ansible.builtin.meta: end_host
|
when: not tunnel_ok
|
||||||
when: nc_probe.rc != 0
|
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': 'journal_entry',
|
||||||
|
'task_result': 'tunnel_probe_failed',
|
||||||
|
'task_add1': 'port=' ~ (_local_port | default('n/a'))
|
||||||
|
} | to_json }}"
|
||||||
|
payload_encoding: "string"
|
||||||
|
|
||||||
- name: "✅ Progress | Tunnel OK, proceeding to Dev2 auth and reads"
|
# ───────────────────────── DEV1: banner → fw_version ─────────────────────────
|
||||||
debug:
|
- name: Dev1 | Probe banner via SSH from controller (classic extraction)
|
||||||
msg:
|
delegate_to: localhost
|
||||||
- "Device: {{ inventory_hostname }}"
|
ansible.builtin.shell: |
|
||||||
- "Phase: Dev2 (auth selection, firmux/banner read)"
|
set -e
|
||||||
|
USER="{{ dev1_user }}"
|
||||||
|
HOST="{{ ansible_host | default(inventory_hostname) }}"
|
||||||
|
sshpass -p '{{ dev1_pass }}' \
|
||||||
|
ssh -o StrictHostKeyChecking=no -o PubkeyAuthentication=no -o ConnectTimeout={{ ssh_timeout }} \
|
||||||
|
"${USER}@${HOST}" \
|
||||||
|
"PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH; cat /etc/banner | grep -i rev | head -n1"
|
||||||
|
register: dev1_banner
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Dev2 | ARP ping the target (from Dev1) to confirm who is at {{ dev2_host }}
|
- name: Dev1 | Normalize banner → X.X.X-rYYYY
|
||||||
ansible.builtin.raw: >
|
delegate_to: localhost
|
||||||
{{ pathprefix }}
|
set_fact:
|
||||||
arping -c 1 -w 2 -I {{ dev1_iface }} {{ dev2_host }} 2>&1 || true
|
dev1_fw_clean: >-
|
||||||
register: dev2_arping
|
{{
|
||||||
|
(
|
||||||
|
(dev1_banner.stdout | default('') | trim )
|
||||||
|
| regex_replace('\\s*\\|.*$', '') # drop ' | timestamp'
|
||||||
|
| regex_replace('(?i)\\s*rev\\.?\\s*([0-9]+)\\s*$', '-r\\1')
|
||||||
|
| regex_search('[0-9]+\\.[0-9]+\\.[0-9]+-r[0-9]+')
|
||||||
|
) | default('', true)
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: Journal if DEV1 normalization failed (no core)
|
||||||
|
when: (dev1_fw_clean | default('') | length) == 0
|
||||||
|
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': 'journal_entry',
|
||||||
|
'task_result': 'dev1_banner_parse_failed',
|
||||||
|
'task_add1': (dev1_banner.stdout | default('NO_STDOUT') | trim)[:256]
|
||||||
|
} | to_json }}"
|
||||||
|
payload_encoding: "string"
|
||||||
|
|
||||||
|
- name: Publish → controls | custom_field_set fw_version (Dev1)
|
||||||
|
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': 'fw_version',
|
||||||
|
'task_result': (dev1_fw_clean if (dev1_fw_clean | length) > 0 else 'unavailable')
|
||||||
|
} | to_json }}"
|
||||||
|
payload_encoding: "string"
|
||||||
|
register: dev1_publish_resp
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: Debug | arping summary (MAC & replies)
|
# ───────────────────────── DEV2 auth pick ─────────────────────────
|
||||||
debug:
|
|
||||||
msg:
|
|
||||||
- "arping rc={{ dev2_arping.rc }}"
|
|
||||||
- "arping stdout={{ (dev2_arping.stdout | default('')) | trim }}"
|
|
||||||
- "arping stderr={{ (dev2_arping.stderr | default('')) | trim }}"
|
|
||||||
|
|
||||||
# ───────────────────────── DEV2 AUTH PICK (as per update-indoor) ─────────────────────────
|
|
||||||
- name: Try DEV2 login with 'basicpass' (root)
|
- name: Try DEV2 login with 'basicpass' (root)
|
||||||
|
when: tunnel_ok | default(false)
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.shell: |
|
||||||
set -e
|
set -e
|
||||||
@@ -307,22 +316,17 @@
|
|||||||
-p "$PORT" root@127.0.0.1 echo OK >/dev/null 2>&1
|
-p "$PORT" root@127.0.0.1 echo OK >/dev/null 2>&1
|
||||||
register: dev2_try_basicpass
|
register: dev2_try_basicpass
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_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: tunnel_ok | default(false) and dev2_try_basicpass.rc == 0
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
dev2_passfile_used: "basicpass"
|
dev2_passfile_used: "basicpass"
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Try DEV2 login with 'basicpass2' (only if first failed)
|
- name: Try DEV2 login with 'basicpass2' (only if first failed)
|
||||||
when: dev2_passfile_used is not defined
|
when: tunnel_ok | default(false) and dev2_passfile_used is not defined
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.shell: |
|
||||||
set -e
|
set -e
|
||||||
@@ -335,49 +339,57 @@
|
|||||||
-p "$PORT" root@127.0.0.1 echo OK >/dev/null 2>&1
|
-p "$PORT" root@127.0.0.1 echo OK >/dev/null 2>&1
|
||||||
register: dev2_try_basicpass2
|
register: dev2_try_basicpass2
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_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: tunnel_ok | default(false) and (dev2_passfile_used is not defined) and (dev2_try_basicpass2.rc | default(1)) == 0
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
dev2_passfile_used: "basicpass2"
|
dev2_passfile_used: "basicpass2"
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Mark DEV2 auth as NONE if both attempts failed
|
- name: Mark DEV2 auth as NONE if both attempts failed
|
||||||
when: dev2_passfile_used is not defined
|
when: tunnel_ok | default(false) and (dev2_passfile_used is not defined)
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
dev2_passfile_used: "NONE"
|
dev2_passfile_used: "NONE"
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Debug | selected passfile
|
- name: Journal if DEV2 auth failed
|
||||||
|
when: tunnel_ok | default(false) and (dev2_passfile_used == 'NONE')
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
debug:
|
ansible.builtin.uri:
|
||||||
msg: "DEV2 passfile used: {{ dev2_passfile_used }}"
|
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': 'journal_entry',
|
||||||
|
'task_result': 'dev2_auth_failed'
|
||||||
|
} | to_json }}"
|
||||||
|
payload_encoding: "string"
|
||||||
|
|
||||||
- name: Dev2 | ARP ping the target (from Dev1) to confirm who is at {{ dev2_host }}
|
# ---------------------------- AIRPING #3 (post-tunnel stabilizer) ----------------------------
|
||||||
|
- name: Refresh ARP #3 on DEV1 LAN (post-tunnel)
|
||||||
|
when: tunnel_ok | default(false)
|
||||||
ansible.builtin.raw: >
|
ansible.builtin.raw: >
|
||||||
{{ pathprefix }}
|
{{ pathprefix }}
|
||||||
arping -c 1 -w 2 -I {{ dev1_iface }} {{ dev2_host }} 2>&1 || true
|
arping -U -I {{ arping_iface }} {{ dev2_side_ip_addr }} -c 3
|
||||||
register: dev2_arping
|
register: arping3
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Debug | arping summary (MAC & replies)
|
# ───────────────────────── DEV2: firmux → indoor_fwver ─────────────────────────
|
||||||
debug:
|
- name: Dev2 | Read /usr/lib/release/firmux (if authenticated)
|
||||||
msg:
|
when: tunnel_ok | default(false) and dev2_passfile_used is defined and dev2_passfile_used != 'NONE'
|
||||||
- "arping rc={{ dev2_arping.rc }}"
|
|
||||||
- "arping stdout={{ (dev2_arping.stdout | default('')) | trim }}"
|
|
||||||
- "arping stderr={{ (dev2_arping.stderr | default('')) | trim }}"
|
|
||||||
|
|
||||||
# ───────────────────────── DEV2 READS ─────────────────────────
|
|
||||||
- name: Dev2 | Read /usr/lib/release/firmux (if present)
|
|
||||||
when: dev2_passfile_used != "NONE"
|
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.shell: |
|
||||||
set -e
|
set -e
|
||||||
@@ -392,90 +404,54 @@
|
|||||||
args: { executable: /bin/bash }
|
args: { executable: /bin/bash }
|
||||||
register: dev2_firmux
|
register: dev2_firmux
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
### added by pavel
|
- name: Dev2 | Choose firmux line (prefer containing 'rev NNNN')
|
||||||
- name: Debug output firmux variable
|
when: tunnel_ok | default(false)
|
||||||
delegate_to: localhost
|
|
||||||
debug:
|
|
||||||
msg: "firmux caught: {{ dev2_firmux.stdout }}"
|
|
||||||
|
|
||||||
# Dev2: firmux-only selection (prefer a line that has "rev NNNN")
|
|
||||||
- name: Dev2 | Prepare firmux lines list
|
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
set_fact:
|
set_fact:
|
||||||
_firmux_lines: "{{ (dev2_firmux.stdout | default('') | regex_replace('\r','')) | split('\n') | map('trim') | list }}"
|
_firmux_lines: "{{ (dev2_firmux.stdout | default('') | regex_replace('\r','')) | split('\n') | map('trim') | list }}"
|
||||||
|
dev2_line: >-
|
||||||
- name: Dev2 | Select line from firmux (prefer '... rev NNNN')
|
|
||||||
delegate_to: localhost
|
|
||||||
set_fact:
|
|
||||||
indoor_fw_raw: >-
|
|
||||||
{{
|
{{
|
||||||
(
|
(_firmux_lines | select('match','(?i).*\\brev\\s*\\d+.*') | list | first)
|
||||||
_firmux_lines
|
| default((_firmux_lines | select('truthy') | list | first) | default(''))
|
||||||
| select('match', '(?i).*\\brev\\s*\\d+.*')
|
|
||||||
| list
|
|
||||||
)[0]
|
|
||||||
if (
|
|
||||||
_firmux_lines
|
|
||||||
| select('match', '(?i).*\\brev\\s*\\d+.*')
|
|
||||||
| list
|
|
||||||
| length
|
|
||||||
) > 0
|
|
||||||
else
|
|
||||||
((_firmux_lines | select('truthy') | list )[0] | default(''))
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
- name: Dev2 | Debug chosen line from firmux
|
- name: Dev2 | Normalize to EXACT 'X.X.X rev YYYY' (lowercase 'rev', single space)
|
||||||
delegate_to: localhost
|
when: tunnel_ok | default(false)
|
||||||
debug:
|
|
||||||
msg: "Chosen indoor_fw_raw='{{ indoor_fw_raw }}'"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Final value for NetBox: keep exactly what firmux says (no '-r' conversion)
|
|
||||||
- name: Dev2 | Final indoor fw string (no transformation)
|
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
set_fact:
|
set_fact:
|
||||||
indoor_fw_norm: "{{ indoor_fw_raw | trim }}"
|
dev2_line_clean: "{{ (dev2_line | default('') | trim) | regex_replace('\\s*\\|.*$', '') }}"
|
||||||
|
dev2_ver: "{{ dev2_line_clean | regex_search('[0-9]+\\.[0-9]+\\.[0-9]+') | default('') }}"
|
||||||
|
dev2_rev_token: "{{ dev2_line_clean | regex_search('(?i)\\brev\\.?\\s*[0-9]+') | default('') }}"
|
||||||
|
dev2_rev_num: "{{ dev2_rev_token | regex_replace('(?i).*\\brev\\.?\\s*', '') }}"
|
||||||
|
indoor_fw_norm: "{{ (dev2_ver ~ ' rev ' ~ dev2_rev_num) if (dev2_ver|length>0 and dev2_rev_num|length>0) else '' }}"
|
||||||
|
|
||||||
# Build payload preview (exact string) — single, corrected task
|
- name: Journal if DEV2 normalization failed (no version or rev)
|
||||||
- name: Dev2 | Build payload preview string
|
when: tunnel_ok | default(false) and (indoor_fw_norm | default('') | length) == 0
|
||||||
when:
|
|
||||||
- dev2_passfile_used is defined
|
|
||||||
- dev2_passfile_used != "NONE"
|
|
||||||
- indoor_fw_norm is defined
|
|
||||||
- (indoor_fw_norm | length) > 0
|
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
set_fact:
|
ansible.builtin.uri:
|
||||||
dev2_payload_preview: >-
|
url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ rmq_exchange | urlencode }}/publish"
|
||||||
{{
|
method: POST
|
||||||
{
|
user: "{{ rmq_user }}"
|
||||||
"properties": {"content_type": "application/json"},
|
password: "{{ rmq_pass }}"
|
||||||
"routing_key": control_queue,
|
force_basic_auth: true
|
||||||
"payload": ({
|
status_code: 200
|
||||||
"inscope_device": (ansible_hostname | default(inventory_hostname)),
|
headers: { content-type: "application/json" }
|
||||||
"task_name": "custom_field_set",
|
body_format: json
|
||||||
"task_add1": "indoor_fwver",
|
body:
|
||||||
"task_result": indoor_fw_norm
|
properties: { content_type: "application/json" }
|
||||||
} | to_json),
|
routing_key: "{{ control_queue }}"
|
||||||
"payload_encoding": "string"
|
payload: "{{ {
|
||||||
} | to_json
|
'inscope_device': (ansible_hostname | default(inventory_hostname)),
|
||||||
}}
|
'task_name': 'journal_entry',
|
||||||
|
'task_result': 'dev2_firmux_parse_failed',
|
||||||
- name: Dev2 | Debug EXACT publish body (payload preview)
|
'task_add1': (dev2_firmux.stdout | default('NO_STDOUT') | trim)[:256]
|
||||||
when:
|
} | to_json }}"
|
||||||
- dev2_passfile_used != "NONE"
|
payload_encoding: "string"
|
||||||
- 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:
|
|
||||||
- dev2_passfile_used != "NONE"
|
|
||||||
- indoor_fw_norm is defined
|
|
||||||
- (indoor_fw_norm | length) > 0
|
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.uri:
|
ansible.builtin.uri:
|
||||||
url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ rmq_exchange | urlencode }}/publish"
|
url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ rmq_exchange | urlencode }}/publish"
|
||||||
@@ -493,29 +469,35 @@
|
|||||||
'inscope_device': (ansible_hostname | default(inventory_hostname)),
|
'inscope_device': (ansible_hostname | default(inventory_hostname)),
|
||||||
'task_name': 'custom_field_set',
|
'task_name': 'custom_field_set',
|
||||||
'task_add1': 'indoor_fwver',
|
'task_add1': 'indoor_fwver',
|
||||||
'task_result': indoor_fw_norm
|
'task_result': (
|
||||||
|
indoor_fw_norm if (tunnel_ok | default(false)) and (indoor_fw_norm | default('') | length) > 0
|
||||||
|
else ('unreachable' if not (tunnel_ok | default(false)) else 'unavailable')
|
||||||
|
)
|
||||||
} | to_json }}"
|
} | to_json }}"
|
||||||
payload_encoding: "string"
|
payload_encoding: "string"
|
||||||
register: dev2_publish_resp
|
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)"
|
- name: "✅ Progress | Cleanup start (close tunnel & remove temp IP)"
|
||||||
debug:
|
debug:
|
||||||
msg:
|
msg: "Closing ControlMaster and removing temporary IP"
|
||||||
- "Cleanup phase: closing ControlMaster & removing temp IP"
|
|
||||||
|
# ---------------------------- AIRPING #4 (pre-cleanup) ----------------------------
|
||||||
|
- name: Refresh ARP #4 on DEV1 LAN (pre-cleanup)
|
||||||
|
ansible.builtin.raw: >
|
||||||
|
{{ pathprefix }}
|
||||||
|
arping -U -I {{ arping_iface }} {{ dev2_side_ip_addr }} -c 3
|
||||||
|
register: arping4
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
- 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"
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Remove tunnel control dir (best-effort)
|
- name: Remove tunnel control dir (best-effort)
|
||||||
@@ -525,25 +507,43 @@
|
|||||||
state: absent
|
state: absent
|
||||||
ignore_errors: true
|
ignore_errors: true
|
||||||
|
|
||||||
- name: Remove temporary IP on DEV1 (tolerate 'Cannot assign requested address')
|
- name: Remove temporary IP on DEV1 (tolerate 'Cannot assign requested address'; soft-fail)
|
||||||
ansible.builtin.raw: >
|
ansible.builtin.raw: >
|
||||||
{{ pathprefix }}
|
{{ pathprefix }}
|
||||||
ip a del {{ dev2_side_ip }} dev {{ dev1_iface }}
|
ip a del {{ dev2_side_ip }} dev {{ dev1_iface }}
|
||||||
register: del_ip
|
register: del_ip
|
||||||
changed_when: del_ip.rc == 0
|
changed_when: del_ip.rc == 0
|
||||||
failed_when: del_ip.rc != 0
|
failed_when: false
|
||||||
and ('Cannot assign requested address' not in (del_ip.stdout | default('')))
|
ignore_errors: true
|
||||||
and ('Cannot assign requested address' not in (del_ip.stderr | default('')))
|
|
||||||
|
|
||||||
- name: Debug | temp IP del result
|
- name: Journal if temp IP delete failed (not just 'Cannot assign requested address')
|
||||||
debug:
|
when: del_ip.rc is defined and del_ip.rc != 0 and
|
||||||
msg:
|
('Cannot assign requested address' not in (del_ip.stdout | default(''))) and
|
||||||
- "Del IP rc={{ del_ip.rc }}"
|
('Cannot assign requested address' not in (del_ip.stderr | default('')))
|
||||||
- "stdout={{ (del_ip.stdout | default('')) | trim }}"
|
delegate_to: localhost
|
||||||
- "stderr={{ (del_ip.stderr | default('')) | trim }}"
|
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': 'journal_entry',
|
||||||
|
'task_result': 'temp_ip_del_failed',
|
||||||
|
'task_add1': 'rc=' ~ (del_ip.rc | string),
|
||||||
|
'task_add2': (del_ip.stderr | default(del_ip.stdout) | trim)[:512]
|
||||||
|
} | to_json }}"
|
||||||
|
payload_encoding: "string"
|
||||||
|
|
||||||
- name: "✅ Progress | Completed device processing"
|
- name: "✅ Completed | Device processed (Dev1+Dev2)."
|
||||||
debug:
|
debug:
|
||||||
msg:
|
msg:
|
||||||
- "Device: {{ inventory_hostname }}"
|
- "Device: {{ inventory_hostname }}"
|
||||||
- "Status: DONE (Dev1+Dev2 processed)"
|
- "Status: DONE (report-only)"
|
||||||
|
|||||||
Reference in New Issue
Block a user