diff --git a/playbooks/pve-nag-patch.yaml b/playbooks/pve-nag-patch.yaml new file mode 100644 index 0000000..d76023f --- /dev/null +++ b/playbooks/pve-nag-patch.yaml @@ -0,0 +1,29 @@ +# Remove the Proxmox "No valid subscription" popup on a PVE host and keep it removed across updates. +# scripts/elway infra-ops@ --playbook playbooks/pve-nag-patch.yaml +# Source + rationale: services/pve-nag-patch/. UI-only (one static JS file); no service restart. +steps: + - name: patch script + sudo: true + upload: + src: services/pve-nag-patch/pve-nag-patch + dest: /usr/local/sbin/pve-nag-patch + mode: "0755" + - name: apt hook (re-apply after every dpkg run) + sudo: true + upload: + src: services/pve-nag-patch/86pve-nag-patch + dest: /etc/apt/apt.conf.d/86pve-nag-patch + mode: "0644" + - name: apply now + sudo: true + shell: /usr/local/sbin/pve-nag-patch + when: "! grep -q pve-nag-patch /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" + +verify: + - name: the file on disk carries the patch + sudo: true + shell: grep -q 'false /\* pve-nag-patch \*/' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js + changed_when: "false" + - name: pveproxy serves the patched file + shell: curl -sk https://127.0.0.1:8006/proxmoxlib.js | grep -q 'pve-nag-patch' + changed_when: "false" diff --git a/services/pve-nag-patch/86pve-nag-patch b/services/pve-nag-patch/86pve-nag-patch new file mode 100644 index 0000000..d35a86e --- /dev/null +++ b/services/pve-nag-patch/86pve-nag-patch @@ -0,0 +1,3 @@ +// Re-apply the subscription-popup patch after every dpkg run (a proxmox-widget-toolkit update restores the +// original proxmoxlib.js). Source: eshpfi services/pve-nag-patch/. The script always exits 0. +DPkg::Post-Invoke { "if [ -x /usr/local/sbin/pve-nag-patch ]; then /usr/local/sbin/pve-nag-patch; fi"; }; diff --git a/services/pve-nag-patch/README.md b/services/pve-nag-patch/README.md new file mode 100644 index 0000000..7e87385 --- /dev/null +++ b/services/pve-nag-patch/README.md @@ -0,0 +1,43 @@ +# pve-nag-patch: no "No valid subscription" popup on our Proxmox hosts + +Prime, 2026-10-03: "every host". UI-only. One static file (`proxmox-widget-toolkit`'s `proxmoxlib.js`) gets +one edit, so no service restarts and no change to how Proxmox runs. Hard-refresh the browser once. + +**What it changes.** In `Proxmox.Utils.checked_command`, the status test that guards the popup becomes `false`. +The else-branch then runs the guarded command directly, so login, apt "Refresh" and the rest work with no popup. +The common `void(Ext.Msg.show…` trick would swallow those commands. The regex is anchored on the popup itself: +the status test must be followed immediately by `) { Ext.Msg.show({ title: gettext('No valid subscription')`. +The subscription panel's own status test stays untouched. + +**Why anchored:** before rollout, I ran the patch offline against a copy of each host's live file. An +unanchored first version would have patched the wrong line, the subscription panel, on **nh3-pve and +pfi-pve**. Their older toolkits (4.3.11, 4.3.6) wrap the test across two lines (`res⏎ .data.status…`). + +**Kept across updates:** `/etc/apt/apt.conf.d/86pve-nag-patch` re-runs `/usr/local/sbin/pve-nag-patch` after +every dpkg run. Proven on nh3-pve-2 with `apt-get install --reinstall proxmox-widget-toolkit`: the original +came back and the hook re-patched it. The script is idempotent and always exits 0, so it can never fail an apt +run. It also leaves alone a file that another de-nag tool already handled. + +| Host | Toolkit | State (2026-10-03 1326) | +|---|---|---| +| nh3-pve-2 | 5.2.10 | patched + hook (hook proven by reinstall) | +| nh3-pve | 4.3.11 | patched + hook | +| pfi-pve | 4.3.6 | patched + hook | +| esh-pve | 4.3.17 | patched + hook | +| esh-nas-pve | 4.3.17 | **already de-nagged before this**: pve-nag-buster (`86pve-nags`) + the community `no-nag-script`; file shows `res.false`. Left alone | +| esh-pve-2 | n/a | unplugged; run the playbook when it is back | +| sfsrv-ana | n/a | SureFire client hypervisor: NOT touched (coordinate first) | +| pbs-ana / pbs-nh3 | n/a | PBS has the same popup, but infra-ops has no sudo there. Not done | + +**Checks run:** +- each served file passes `node --check`; +- our marker is present; +- the popup's status test is gone; +- positive control: the same grep finds the live test in every unpatched original; +- `node --check` caught a deliberately broken copy. + +```bash +scripts/elway infra-ops@ --playbook playbooks/pve-nag-patch.yaml # install / re-apply +``` +**Undo:** remove `/etc/apt/apt.conf.d/86pve-nag-patch` and `/usr/local/sbin/pve-nag-patch`, then +`apt-get install --reinstall proxmox-widget-toolkit`. diff --git a/services/pve-nag-patch/pve-nag-patch b/services/pve-nag-patch/pve-nag-patch new file mode 100755 index 0000000..294581a --- /dev/null +++ b/services/pve-nag-patch/pve-nag-patch @@ -0,0 +1,33 @@ +#!/bin/sh +# pve-nag-patch: stop the Proxmox web UI's "No valid subscription" popup (Prime, 2026-10-03: every host). +# +# The popup lives in proxmox-widget-toolkit's proxmoxlib.js, in Proxmox.Utils.checked_command: when the +# subscription status is not 'active' it shows Ext.Msg.show(...) and runs the guarded command only after OK. +# This replaces that one status test with `false`, so the else-branch runs the command directly. The popup +# is skipped, and buttons guarded by checked_command (login, apt Refresh, ...) still work. The common +# "void(Ext.Msg.show" trick swallows the command instead. The second status test in the file (the +# subscription panel's state) is deliberately left alone. +# +# Idempotent; safe to run any time. The apt hook /etc/apt/apt.conf.d/86pve-nag-patch re-runs it after every +# dpkg run, because each proxmox-widget-toolkit update restores the original file. +# Undo: apt-get install --reinstall proxmox-widget-toolkit, after removing the hook. +# Always exits 0 so it can never fail an apt transaction. +[ -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ] || exit 0 +grep -q 'pve-nag-patch' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && exit 0 +# Already de-nagged by another tool (pve-nag-buster / the community `res.false` or NoMoreNagging seds): leave it. +grep -q -E "res\.false|NoMoreNagging|void\(\{ //Ext\.Msg\.show" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && exit 0 +if ! grep -q 'No valid subscription' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; then + logger -t pve-nag-patch "popup not found: proxmoxlib.js layout changed, NOT patched" + exit 0 +fi +# Anchored on the popup itself: the status test must be IMMEDIATELY followed by `) { Ext.Msg.show({ title: +# gettext('No valid subscription')`, so nothing else in the file can match. Older toolkits (4.3.6/4.3.11) wrap +# the test across lines (`res\n .data.status...`), hence the \s*. Found in the 2026-10-03 rollout's offline test, +# where an unanchored first version would have patched the subscription PANEL on nh3-pve and pfi-pve. +perl -0pi -e 's/res\s*\.data\.status\.toLowerCase\(\)\s*!==\s*.active.(\s*\)\s*\{\s*Ext\.Msg\.show\(\{\s*title:\s*gettext\(.No valid subscription.\))/false \/* pve-nag-patch *\/$1/' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js +if grep -q 'pve-nag-patch' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; then + logger -t pve-nag-patch "patched proxmoxlib.js" +else + logger -t pve-nag-patch "status test before the popup not found: NOT patched" +fi +exit 0