From 0c1c5033e08aca666debb22192f56e3a8172617d Mon Sep 17 00:00:00 2001 From: David Schroeder Date: Tue, 22 Sep 2026 22:05:38 -0500 Subject: [PATCH] update fix --- README.md | 4 +++- defaults.inc | 2 +- inc/orphan-disks.py | 1 + proxmenu-scripts.sh | 15 +++++++++++--- tests/test-menu-update.py | 42 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 5 deletions(-) mode change 100644 => 100755 inc/orphan-disks.py create mode 100644 tests/test-menu-update.py diff --git a/README.md b/README.md index 0c60c3b..3a52929 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,9 @@ update every online cluster node over Proxmox's root SSH trust, then update the initiating node. Each node independently performs the same clean-worktree, branch, and fast-forward safety checks. Offline, unreachable, dirty, ahead, or diverged nodes are never overwritten and are reported as failures. Standalone -hosts retain the local-only update behavior. +hosts retain the local-only update behavior. The menu reloads the locally installed +code and version after an update attempt, including when another node fails. +Failures remain visible until you press Enter to continue. Legacy installations automatically update from the published `main` branch. On their first launch after receiving this version, control is handed to the diff --git a/defaults.inc b/defaults.inc index 3774bd8..647205a 100755 --- a/defaults.inc +++ b/defaults.inc @@ -3,7 +3,7 @@ action="${1:-}" FOLDER='/opt/idssys/ta-proxmenu' -VERS='2026.9.22-2' +VERS='2026.9.22-3' noupdate=' ' diff --git a/inc/orphan-disks.py b/inc/orphan-disks.py old mode 100644 new mode 100755 index bfc35e7..9a5537b --- a/inc/orphan-disks.py +++ b/inc/orphan-disks.py @@ -112,6 +112,7 @@ def scan(root=Path('/etc/pve/nodes'), get=api): refs, errors, before = references(root, nodes, guests) warnings.extend(errors) shared_done = set() + echo for node in sorted(nodes, key=lambda item: item['node']): name = node['node'] if node.get('status') != 'online': diff --git a/proxmenu-scripts.sh b/proxmenu-scripts.sh index 39e01f8..3266587 100755 --- a/proxmenu-scripts.sh +++ b/proxmenu-scripts.sh @@ -2678,6 +2678,16 @@ BRANCH_MANAGEMENT_MENU() { done } +TAPM_INSTALL_MENU_UPDATE() { + if ! /opt/idssys/ta-proxmenu/run.sh update; then + printf '\nUpdate reported failures; review the node results above. TAPM will reload the locally installed version.\n' + ENTER2CONTINUE + fi + # A remote failure can coexist with a successful local update. Reload the + # full menu, including functions and defaults, regardless of cluster status. + exec /opt/idssys/ta-proxmenu/run.sh +} + UTILITIES_MENU() { local -a labels local -a values=("install_update" "check_update" "branches" "about") @@ -2727,9 +2737,8 @@ UTILITIES_MENU() { echo -en "\n${idsCL[LightCyan]}Install the update for the current branch (y/N)?${idsCL[Default]} " read -r -n 1 choice echo - if [[ "$choice" =~ ^[Yy]$ ]] && - /opt/idssys/ta-proxmenu/run.sh update; then - exec /opt/idssys/ta-proxmenu/run.sh + if [[ "$choice" =~ ^[Yy]$ ]]; then + TAPM_INSTALL_MENU_UPDATE fi ENTER2CONTINUE ;; diff --git a/tests/test-menu-update.py b/tests/test-menu-update.py new file mode 100644 index 0000000..6b65c24 --- /dev/null +++ b/tests/test-menu-update.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +"""Exercise menu reloads after successful and partially failed updates.""" +from pathlib import Path +import os +import subprocess +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parents[1] + + +class MenuUpdateTests(unittest.TestCase): + def test_reload_after_success_or_failure(self): + source = (ROOT / 'proxmenu-scripts.sh').read_text() + function = source.split('TAPM_INSTALL_MENU_UPDATE() {', 1)[1].split('\n}\n', 1)[0] + for status in (0, 1): + with self.subTest(update_status=status), tempfile.TemporaryDirectory() as directory: + launcher = Path(directory) / 'run.sh' + log = Path(directory) / 'calls' + launcher.write_text('''#!/bin/bash +if [[ "${1:-}" == update ]]; then + echo update >> "$TEST_LOG" + exit "$TEST_STATUS" +fi +echo reload >> "$TEST_LOG" +''') + launcher.chmod(0o700) + script = 'ENTER2CONTINUE() { echo pause >> "$TEST_LOG"; }\n' + script += 'TAPM_INSTALL_MENU_UPDATE() {' + function.replace( + '/opt/idssys/ta-proxmenu/run.sh', '"' + str(launcher) + '"') + '\n}\n' + script += 'TAPM_INSTALL_MENU_UPDATE\necho stale-menu >> "$TEST_LOG"\n' + result = subprocess.run(['bash', '-c', script], capture_output=True, text=True, + env=dict(os.environ, TEST_LOG=str(log), TEST_STATUS=str(status))) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(log.read_text().splitlines(), + ['update', 'reload'] if status == 0 else ['update', 'pause', 'reload']) + if status: + self.assertIn('reported failures', result.stdout) + + +if __name__ == '__main__': + unittest.main()