From c7586c38e7c16938e31880584349771c9d995df7 Mon Sep 17 00:00:00 2001 From: pavel Date: Thu, 23 Oct 2025 19:28:27 +0300 Subject: [PATCH] 1928 --- files/ansible-playbooks/update-indoor.yml | 97 +++++++---------------- 1 file changed, 29 insertions(+), 68 deletions(-) diff --git a/files/ansible-playbooks/update-indoor.yml b/files/ansible-playbooks/update-indoor.yml index e43da8b..eb1b393 100644 --- a/files/ansible-playbooks/update-indoor.yml +++ b/files/ansible-playbooks/update-indoor.yml @@ -1,5 +1,5 @@ --- -# update-secondline.yml +# update-indoor.yml (conservative, minimal fixes) - name: Second-line indoor upgrade via DEV1 → tunnel → DEV2 (non-invasive control path) hosts: all gather_facts: no @@ -50,7 +50,6 @@ control_queue: "{{ lookup('env','CONTROLQUEUE') | default('queue_controls', true) }}" afterupgrade_routing_key: "{{ lookup('env','AFTERUP_ROUTING_KEY') | default('deviceconfig', true) }}" - pre_tasks: # ------------------------------- Hostname sanity DEV1 ------------------------------- - name: Read DEV1 hostname (busybox-safe) @@ -158,13 +157,31 @@ echo "$p"; return 0 fi fi - done + end return 1 } pick register: pick_port changed_when: false + # (moved up) Stop immediately if no free local port was found + - name: Stop if no free local port was found + ansible.builtin.meta: end_host + when: (pick_port.stdout | trim | length) == 0 + + # (moved up) Set chosen port and control socket path + - name: Record chosen local port and create control dir for SSH ControlMaster + delegate_to: localhost + ansible.builtin.set_fact: + _local_port: "{{ pick_port.stdout | trim }}" + _ctrl_dir: "{{ lookup('ansible.builtin.pipe', 'mktemp -d') }}" + + - name: Build path for SSH ControlMaster socket + delegate_to: localhost + ansible.builtin.set_fact: + _ctrl_sock: "{{ _ctrl_dir }}/ssh_tunnel_ctl" + + # (moved down) Now it’s safe to reference _local_port/_ctrl_sock - name: Debug picked local port (controller) delegate_to: localhost ansible.builtin.debug: @@ -191,30 +208,6 @@ msg: - "listeners_before:\n{{ (port_listeners_before.stdout | default('')) | 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 and create control dir for SSH ControlMaster - delegate_to: localhost - ansible.builtin.set_fact: - _local_port: "{{ pick_port.stdout | trim }}" - _ctrl_dir: "{{ lookup('ansible.builtin.pipe', 'mktemp -d') }}" - - - name: Build path for SSH ControlMaster socket - delegate_to: localhost - ansible.builtin.set_fact: - _ctrl_sock: "{{ _ctrl_dir }}/ssh_tunnel_ctl" - - - name: Debug tunnel parameters (controller side) - delegate_to: localhost - ansible.builtin.debug: - msg: - - "local_port={{ _local_port }}" - - "ctrl_dir={{ _ctrl_dir }}" - - "ctrl_sock={{ _ctrl_sock }}" - - name: Refresh ARP on DEV1’s LAN (send unsolicited ARP from temporary IP) ansible.builtin.raw: arping -U -I eth0 192.168.1.11 -c 3 @@ -251,8 +244,8 @@ { ss -ltnp 2>/dev/null || true; } | awk -v p=":${P}$" '$0 ~ p {print}' echo "== lsof LISTEN on :${P} ==" { lsof -nP -iTCP:"${P}" -sTCP:LISTEN 2>/dev/null || true; } - echo "== grep ControlMaster PID ==" - pgrep -fa "ssh.*-S {{ _ctrl_sock | regex_escape }}" || true + echo "== ps/grep ControlMaster by ControlPath ==" + ps -ef | grep -F " -S {{ _ctrl_sock }}" | grep -v grep || true register: port_listeners_after changed_when: false failed_when: false @@ -263,7 +256,6 @@ msg: - "{{ (port_listeners_after.stdout | default('')) | trim }}" - - name: Wait a moment for tunnel to settle delegate_to: localhost ansible.builtin.wait_for: @@ -286,7 +278,6 @@ - "tunnel_check.rc={{ tun_check.rc }}" - "tunnel_check.out={{ (tun_check.stdout | default('')) | trim }}" - # ADD THIS RIGHT AFTER THE EXISTING DEBUG: - name: Debug ControlMaster check (full rc/stdout/stderr) delegate_to: localhost ansible.builtin.debug: @@ -332,33 +323,7 @@ - "{{ (dev2_ls.stdout | default('')) | trim }}" - "{{ (dev2_ls.stderr | default('')) | trim }}" - - - name: Probe SSH banner through tunnel without auth (quick) - delegate_to: localhost - ansible.builtin.shell: | - set -e - PORT="{{ _local_port }}" - # No password, no interactive auth; prints preauth/banners then exits - ssh -p "$PORT" \ - -o PreferredAuthentications=none \ - -o PubkeyAuthentication=no \ - -o KbdInteractiveAuthentication=no \ - -o PasswordAuthentication=no \ - -o NumberOfPasswordPrompts=0 \ - -o ConnectTimeout=5 \ - -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ - -vvv root@127.0.0.1 true 2>&1 || true - register: tunnel_banner_probe - changed_when: false - failed_when: false - - - name: Debug SSH preauth probe output (first 40 lines) - delegate_to: localhost - ansible.builtin.debug: - msg: "{{ (tunnel_banner_probe.stdout | default('')) | regex_replace('^(?:.*\\n){,40}\\K[\\s\\S]*','[...truncated...]') }}" - - - # ---------------------------- Pick DEV2 password for root ---------------------------- + # ---------------------------- Single banner probe (kept) ---------------------------- - name: Probe SSH banner through tunnel (pre-auth, quick) delegate_to: localhost ansible.builtin.shell: | @@ -380,9 +345,9 @@ - name: Debug SSH preauth probe (first 40 lines) delegate_to: localhost ansible.builtin.debug: - msg: "{{ (tunnel_banner_probe.stdout | default('')) | regex_replace('^(?:.*\\n){,40}\\K[\\s\\S]*','[...truncated...]') }}" - + msg: "{{ (tunnel_banner_probe.stdout | default('') | split('\n'))[:40] | join('\n') }}" + # ---------------------------- Pick DEV2 password for root ---------------------------- - name: Try DEV2 login with 'basicpass' (root) delegate_to: localhost ansible.builtin.shell: | @@ -407,8 +372,8 @@ { ss -ltnp 2>/dev/null || true; } | awk -v p=":${P}$" '$0 ~ p {print}' echo "== lsof LISTEN on :${P} ==" { lsof -nP -iTCP:"${P}" -sTCP:LISTEN 2>/dev/null || true; } - echo "== pgrep ControlMaster by socket ==" - pgrep -fa "ssh.*-S {{ _ctrl_sock | regex_escape }}" || true + echo "== ps/grep ControlMaster by ControlPath ==" + ps -ef | grep -F " -S {{ _ctrl_sock }}" | grep -v grep || true register: listeners_after_basicpass changed_when: false failed_when: false @@ -422,7 +387,6 @@ - "ctrl_sock={{ _ctrl_sock }}" - "listeners:\n{{ (listeners_after_basicpass.stdout | default('')) | trim }}" - - name: Select 'basicpass' if previous login succeeded when: dev2_try_basicpass.rc == 0 delegate_to: localhost @@ -455,8 +419,8 @@ { ss -ltnp 2>/dev/null || true; } | awk -v p=":${P}$" '$0 ~ p {print}' echo "== lsof LISTEN on :${P} ==" { lsof -nP -iTCP:"${P}" -sTCP:LISTEN 2>/dev/null || true; } - echo "== pgrep ControlMaster by socket ==" - pgrep -fa "ssh.*-S {{ _ctrl_sock | regex_escape }}" || true + echo "== ps/grep ControlMaster by ControlPath ==" + ps -ef | grep -F " -S {{ _ctrl_sock }}" | grep -v grep || true register: listeners_after_basicpass2 changed_when: false failed_when: false @@ -471,7 +435,6 @@ - "listeners:\n{{ (listeners_after_basicpass2.stdout | default('')) | trim }}" when: dev2_try_basicpass2 is defined - - name: Select 'basicpass2' if second login succeeded when: dev2_passfile_used is not defined and dev2_try_basicpass2.rc == 0 delegate_to: localhost @@ -1148,8 +1111,6 @@ register: dev2_marker_write changed_when: true ignore_errors: true - - # ---------------------------- Reboot scheduling (normalized) ---------------------------- - name: Schedule DEV2 reboot after computed delay (seconds)