Weiter zum Inhalt
  • Home
  • Aktuell
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Hell
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dunkel
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. Proxmox-Updater (Host/LXC/VM) auch ioBroker,piHole,etc

NEWS

  • Der neue Monatsrückblick für September 2026 ist online!
    BluefoxB
    Bluefox
    9
    1
    514

  • Neu im Blog: Was die neue Website alles kann
    BluefoxB
    Bluefox
    7
    1
    319

  • Node.js 24 ist jetzt offiziell empfohlen!
    apollon77A
    apollon77
    9
    1
    634

Proxmox-Updater (Host/LXC/VM) auch ioBroker,piHole,etc

Geplant Angeheftet Gesperrt Verschoben Skripten / Logik
137 Beiträge 16 Kommentatoren 22.0k Aufrufe 23 Beobachtet
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • MartinPM
    MartinPM
    MartinP
    schrieb am zuletzt editiert von
    #82

    Ich finde ein händisch Updaten eigentlich ganz praktisch. Ich arbeite mich von weniger wichtigen zu wichtigen Instanzen auf meinem Proxmox-PVE vor, wenn da beim Update von "debian-test" etwas klemmt, kann man erstmal untersuchen, was es ist.

    Ich finde das irgendwann eingeführte "mit nächsten LXC/VM weitermachen bei Fehler" etwas bedenklich. Ggfs macht das bequeme Script dann alle Container/VMs der Reihe nach kaputt wenn es ein systematisches Problem im Repository gibt...

    Intel(R) Celeron(R) CPU N3000 @1.04GHz 8G RAM 480G SSD * Virtualization : unprivileged lxc container on Proxmox * 6 GByte RAM für den iobroker Container * Remote-Access über Wireguard meiner Fritzbox

    Bass-TB 1 Antwort Letzte Antwort
    0
    • Bass-TB Bass-T

      @Negalein sagte:

      @Bass-T sagte:

      das Log des betreffenden Ultimate-Updater-Jobs

      hoffe das ist das richtige

      ultimate-updater.log

      Kann ich den laufenden Job irgendwie abbrechen?
      Oder Maschine rebooten und hoffen dass er wieder bootet?

      Danke für die Rückmeldung und die Logs. 👍

      Bitte den Host erstmal nicht rebooten und apt/dpkg auch nicht blind beenden.

      Ich habe den Hänger inzwischen genauer nachvollzogen.

      Der Ultimate-Updater-Job selbst ist nicht kaputt. Das Host-Update wartet auf eine interaktive Paketfrage zu /etc/ssh/sshd_config.

      Genauer gesagt wartet apt-get dist-upgrade während des openssh-server-Updates auf eine Maintainer-/Conffile-Entscheidung.

      Damit haben wir allerdings eine echte Lücke im aktuellen Jobmodell gefunden:

      Der Updatejob läuft bewusst serverseitig weiter, damit ein geschlossenes Browserfenster oder eine getrennte SSH-Verbindung kein laufendes apt/dpkg abschießt. Das funktioniert auch.

      Wenn der Paketmanager aber eine Benutzereingabe benötigt, gibt es momentan noch keinen Rückkanal von WebUI/CLI zum laufenden Job. Der Job sieht dann einfach weiterhin wie running aus und wartet auf die Eingabe.

      Das wird auf develop entsprechend weiter bearbeitet. Der normale Updatebetrieb soll dabei interaktiv bleiben – gerade bei Konfigurationsfragen möchte ich solche Entscheidungen nicht einfach automatisch treffen lassen. Für unbeaufsichtigte/scheduled Updates gibt es separat den Headless-/Non-Interactive-Betrieb.

      Für deinen aktuell laufenden Job bitte einmal auf dem betroffenen Proxmox-Host ausführen:

      ps aux | grep -E 'apt|apt-get|dpkg'
      

      und:

      ps -ef --forest | grep -A20 -B5 -E 'apt|apt-get|dpkg'
      

      Wenn dort noch apt-get dist-upgrade, apt oder dpkg läuft, bitte nicht killen.

      Zusätzlich bitte noch:

      dpkg --audit
      

      und:

      systemctl list-units --type=service | grep ultimate-updater
      

      Poste mir die Ausgaben bitte hier. Dann können wir den aktuell laufenden Zustand gezielt und möglichst sicher auflösen.

      Die gleichzeitig in deinen Logs sichtbaren pveproxy-/pve-ssl.key-Fehler sind übrigens ein separates Proxmox-Problem. Sie erklären den konkreten Hänger beim Update nicht.


      Den anderen von dir gemeldeten Fehler bei der Welcome-Screen-Installation konnte ich ebenfalls nachvollziehen und habe ihn bereits auf develop behoben. 👍

      Ursache war, dass die Hauptinstallation bei verschachtelten Release-Archiven bereits den korrekt ermittelten Pfad verwendet hat, die anschließende Welcome-Screen-Installation aber noch auf den alten festen Temp-Pfad zugegriffen hat.

      Fix auf develop:

      0bcb3dfe8d2ebef61f6400626934af4a06e9fae8

      Der Welcome-Screen wird jetzt ebenfalls aus dem tatsächlich ermittelten Payload-Verzeichnis installiert.

      Danke fürs Testen und insbesondere für die Logs – dadurch konnten wir beide Punkte ziemlich eindeutig eingrenzen. 🙂

      NegaleinN
      NegaleinN
      Negalein
      schrieb am zuletzt editiert von
      #83

      @Bass-T

      ps aux | grep -E 'apt|apt-get|dpkg'

      root@proxmox2:~# ps aux | grep -E 'apt|apt-get|dpkg'
      root      436538  0.0  0.0   6528  2376 pts/0    S+   10:47   0:00 grep -E apt|apt-get|dpkg
      root     1448924  0.0  0.0   6652  3632 ?        S    Sep06   0:01 lxc-attach -n 108 --keep-env -- bash -c apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
      100000   1449016  0.1  0.9  90888 71624 ?        S    Sep06   1:49 apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
      100000   1455020  0.0  0.0  10612  5012 ?        Ss+  Sep06   0:00 /usr/bin/dpkg --force-confdef --force-confold --status-fd 24 --configure --pending
      100000   1457403  0.0  0.2  22936 17592 ?        S+   Sep06   0:00 /usr/bin/perl /usr/share/debconf/frontend /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
      100000   1457519  0.0  0.0   2680  1880 ?        S+   Sep06   0:00 /bin/sh /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
      

      ps -ef --forest | grep -A20 -B5 -E 'apt|apt-get|dpkg'

      root@proxmox2:~# ps -ef --forest | grep -A20 -B5 -E 'apt|apt-get|dpkg'
      root         930       1  0 Aug25 ?        00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
      root      414595     930  0 10:42 ?        00:00:00  \_ sshd-session: root [priv]
      root      414633  414595  0 10:42 ?        00:00:00  |   \_ sshd-session: root@pts/0
      root      414636  414633  0 10:42 pts/0    00:00:00  |       \_ -bash
      root      440215  414636  0 10:48 pts/0    00:00:00  |           \_ ps -ef --forest
      root      440216  414636  0 10:48 pts/0    00:00:00  |           \_ grep -A20 -B5 -E apt|apt-get|dpkg
      root      414600     930  0 10:42 ?        00:00:00  \_ sshd-session: root [priv]
      root      414635  414600  0 10:42 ?        00:00:00      \_ sshd-session: root@notty
      root      414637  414635  0 10:42 ?        00:00:00          \_ /usr/lib/openssh/sftp-server
      root         941       1  0 Aug25 tty1     00:00:00 /sbin/agetty -o -- \u --noreset --noclear - linux
      root        1075       1  0 Aug25 ?        00:00:03 /usr/sbin/cron -f
      root        1076       1  0 Aug25 ?        00:03:26 /usr/libexec/proxmox/proxmox-firewall start
      root        1097       1  0 Aug25 ?        01:46:56 pve-firewall
      root        1104       1  2 Aug25 ?        06:17:25 pvestatd
      root        1128       1  0 Aug25 ?        00:00:34 pvedaemon
      root     3834705    1128  0 05:37 ?        00:00:33  \_ pvedaemon worker
      root     3854893    1128  0 06:37 ?        00:00:31  \_ pvedaemon worker
      root        4479    1128  0 08:59 ?        00:00:11  \_ pvedaemon worker
      www-data    1141       1  0 Aug25 ?        00:01:05 pveproxy
      www-data  161013    1141  0 09:38 ?        00:00:04  \_ pveproxy worker
      www-data  173411    1141  0 09:42 ?        00:00:04  \_ pveproxy worker
      www-data  197959    1141  0 09:48 ?        00:00:03  \_ pveproxy worker
      www-data    1152       1  0 Aug25 ?        00:00:40 spiceproxy
      www-data 3433683    1152  0 00:04 ?        00:00:02  \_ spiceproxy worker
      root        1178       1  0 Aug25 ?        00:02:32 /usr/bin/lxc-start -F -n 108
      100000      1248    1178  0 Aug25 ?        00:04:47  \_ /usr/lib/systemd/systemd --system --deserialize=34
      --
      root     1392096       1  0 Sep06 ?        00:02:44 /usr/bin/python3 /etc/ultimate-updater/web-ui/server.py --bind 0.0.0.0 --port 8765
      root     1408660       1  0 Sep06 ?        00:00:00 /bin/bash /etc/ultimate-updater/job-runner.sh run-global ultimate-updater-update-all-systems-20260906-153017-380501623-1408489 /etc/ultimate-updater/global-update.sh
      root     1408698 1408660  0 Sep06 ?        00:00:00  \_ /bin/bash /etc/ultimate-updater/global-update.sh
      root     1408709 1408698  0 Sep06 ?        00:00:00      \_ /bin/bash /etc/ultimate-updater/update.sh
      root     1408811 1408709  0 Sep06 ?        00:00:00          \_ tee /var/log/ultimate-updater.log
      root     1448924 1408709  0 Sep06 ?        00:00:01          \_ lxc-attach -n 108 --keep-env -- bash -c apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
      100000   1449016 1448924  0 Sep06 ?        00:01:49              \_ apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
      100000   1455020 1449016  0 Sep06 ?        00:00:00                  \_ /usr/bin/dpkg --force-confdef --force-confold --status-fd 24 --configure --pending
      100000   1457403 1455020  0 Sep06 ?        00:00:00                      \_ /usr/bin/perl /usr/share/debconf/frontend /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
      100000   1457519 1457403  0 Sep06 ?        00:00:00                          \_ /bin/sh /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
      100000   1457533 1457519  0 Sep06 ?        00:00:00                          |   \_ /bin/sh /usr/bin/ucf --three-way --debconf-ok --sum-file /usr/share/openssh/sshd_config.md5sum /tmp/tmp.wUhDAEjyQn /etc/ssh/sshd_config
      100000   1457635 1457403  0 Sep06 ?        00:00:00                          \_ whiptail --backtitle Package configuration --title Configuring openssh-server --output-fd 11 --nocancel --default-item keep the local version currently installed --menu A new version (/tmp/tmp.wUhDAEjyQn) of configuration file  /etc/ssh/sshd_config is available, but the version installed currently  has been locally modified.  What do you want to do about modified configuration file sshd_config? 19 76 7 -- install the package maintainer's version  keep the local version currently installed  show the differences between the versions  show a side-by-side difference between the versions  show a 3-way difference between available versions  do a 3-way merge between available versions  start a new shell to examine the situation
      _chrony  1429618       1  0 Sep06 ?        00:00:00 /usr/sbin/chronyd -n -F 1
      _chrony  1429623 1429618  0 Sep06 ?        00:00:00  \_ /usr/sbin/chronyd -n -F 1
      root     1431494       1  0 Sep06 ?        00:00:00 /usr/sbin/zed -F
      root     1432298       1  0 Sep06 ?        00:01:39 /usr/bin/pmxcfs
      root     1433736       1  0 Sep06 ?        00:00:00 /usr/sbin/qmeventd /var/run/qmeventd.sock
      root     1441793       1  0 Sep06 ?        00:00:00 /usr/sbin/rsyslogd -n -iNONE
      root     1441927       1  0 Sep06 ?        00:00:00 /usr/lib/postfix/sbin/master -w
      postfix  1441929 1441927  0 Sep06 ?        00:00:00  \_ qmgr -l -t unix -u
      postfix   299199 1441927  0 10:13 ?        00:00:00  \_ pickup -l -t unix -u -c
      root     1442345       1  0 Sep06 ?        00:00:16 pve-ha-lrm
      root     1442740       1  0 Sep06 ?        00:00:10 pve-ha-crm
      root     3433677       1  0 00:04 ?        00:00:10 /usr/sbin/pvefw-logger
      root      414602       1  0 10:42 ?        00:00:00 /usr/lib/systemd/systemd --user
      root      414604  414602  0 10:42 ?        00:00:00  \_ (sd-pam)
      

      dpkg --audit

      root@proxmox2:~# dpkg --audit
      root@proxmox2:~#
      

      systemctl list-units --type=service | grep ultimate-updater

      root@proxmox2:~# systemctl list-units --type=service | grep ultimate-updater
      ● ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service loaded activating start   start Ultimate Updater update for all systems
        ultimate-updater-web.service                                                  loaded active     running       Ultimate Updater web UI
      

      ° Node.js & System Update ---> sudo apt update, iob stop, sudo apt full-upgrade
      ° Node.js Fixer ---> iob nodejs-update
      ° Fixer ---> iob fix

      Bass-TB 1 Antwort Letzte Antwort
      0
      • MartinPM MartinP

        Ich finde ein händisch Updaten eigentlich ganz praktisch. Ich arbeite mich von weniger wichtigen zu wichtigen Instanzen auf meinem Proxmox-PVE vor, wenn da beim Update von "debian-test" etwas klemmt, kann man erstmal untersuchen, was es ist.

        Ich finde das irgendwann eingeführte "mit nächsten LXC/VM weitermachen bei Fehler" etwas bedenklich. Ggfs macht das bequeme Script dann alle Container/VMs der Reihe nach kaputt wenn es ein systematisches Problem im Repository gibt...

        Bass-TB
        Bass-TB
        Bass-T
        schrieb am zuletzt editiert von
        #84

        @MartinP sagte:

        Ich finde ein händisch Updaten eigentlich ganz praktisch. Ich arbeite mich von weniger wichtigen zu wichtigen Instanzen auf meinem Proxmox-PVE vor, wenn da beim Update von "debian-test" etwas klemmt, kann man erstmal untersuchen, was es ist.

        Ich finde das irgendwann eingeführte "mit nächsten LXC/VM weitermachen bei Fehler" etwas bedenklich. Ggfs macht das bequeme Script dann alle Container/VMs der Reihe nach kaputt wenn es ein systematisches Problem im Repository gibt...

        Vielen Dank erstmal für dein input. Und ich muss dir recht geben. Unter bestimmten kriterien und bei kritischen Systemen bin ich voll bei dir.
        Daher gibt es unter Settings die Option "continue after errors".
        Nach belieben einfach deaktivieren ;)
        c84a2d1b-f257-4764-96c4-899c6f3acb60-image.jpeg

        Proxmox Cluster

        • NUC7i5 ioBroker Server (Proxmox)
        • HP Elitedesk 800 G4 SSF (Proxmox)
        • HP Elitedesk 800 G2 DM (Proxmox)
          mein Proxmox-Updater für euch

        KNX / Broadlink / Tasmota ESPs / Zigbee
        Vis: 15" Touchmonitor mit Raspi4 / 10" Tablet (Dauerstrom umbau) / Sonoff NSPanel (alle)

        1 Antwort Letzte Antwort
        0
        • NegaleinN Negalein

          @Bass-T

          ps aux | grep -E 'apt|apt-get|dpkg'

          root@proxmox2:~# ps aux | grep -E 'apt|apt-get|dpkg'
          root      436538  0.0  0.0   6528  2376 pts/0    S+   10:47   0:00 grep -E apt|apt-get|dpkg
          root     1448924  0.0  0.0   6652  3632 ?        S    Sep06   0:01 lxc-attach -n 108 --keep-env -- bash -c apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
          100000   1449016  0.1  0.9  90888 71624 ?        S    Sep06   1:49 apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
          100000   1455020  0.0  0.0  10612  5012 ?        Ss+  Sep06   0:00 /usr/bin/dpkg --force-confdef --force-confold --status-fd 24 --configure --pending
          100000   1457403  0.0  0.2  22936 17592 ?        S+   Sep06   0:00 /usr/bin/perl /usr/share/debconf/frontend /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
          100000   1457519  0.0  0.0   2680  1880 ?        S+   Sep06   0:00 /bin/sh /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
          

          ps -ef --forest | grep -A20 -B5 -E 'apt|apt-get|dpkg'

          root@proxmox2:~# ps -ef --forest | grep -A20 -B5 -E 'apt|apt-get|dpkg'
          root         930       1  0 Aug25 ?        00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
          root      414595     930  0 10:42 ?        00:00:00  \_ sshd-session: root [priv]
          root      414633  414595  0 10:42 ?        00:00:00  |   \_ sshd-session: root@pts/0
          root      414636  414633  0 10:42 pts/0    00:00:00  |       \_ -bash
          root      440215  414636  0 10:48 pts/0    00:00:00  |           \_ ps -ef --forest
          root      440216  414636  0 10:48 pts/0    00:00:00  |           \_ grep -A20 -B5 -E apt|apt-get|dpkg
          root      414600     930  0 10:42 ?        00:00:00  \_ sshd-session: root [priv]
          root      414635  414600  0 10:42 ?        00:00:00      \_ sshd-session: root@notty
          root      414637  414635  0 10:42 ?        00:00:00          \_ /usr/lib/openssh/sftp-server
          root         941       1  0 Aug25 tty1     00:00:00 /sbin/agetty -o -- \u --noreset --noclear - linux
          root        1075       1  0 Aug25 ?        00:00:03 /usr/sbin/cron -f
          root        1076       1  0 Aug25 ?        00:03:26 /usr/libexec/proxmox/proxmox-firewall start
          root        1097       1  0 Aug25 ?        01:46:56 pve-firewall
          root        1104       1  2 Aug25 ?        06:17:25 pvestatd
          root        1128       1  0 Aug25 ?        00:00:34 pvedaemon
          root     3834705    1128  0 05:37 ?        00:00:33  \_ pvedaemon worker
          root     3854893    1128  0 06:37 ?        00:00:31  \_ pvedaemon worker
          root        4479    1128  0 08:59 ?        00:00:11  \_ pvedaemon worker
          www-data    1141       1  0 Aug25 ?        00:01:05 pveproxy
          www-data  161013    1141  0 09:38 ?        00:00:04  \_ pveproxy worker
          www-data  173411    1141  0 09:42 ?        00:00:04  \_ pveproxy worker
          www-data  197959    1141  0 09:48 ?        00:00:03  \_ pveproxy worker
          www-data    1152       1  0 Aug25 ?        00:00:40 spiceproxy
          www-data 3433683    1152  0 00:04 ?        00:00:02  \_ spiceproxy worker
          root        1178       1  0 Aug25 ?        00:02:32 /usr/bin/lxc-start -F -n 108
          100000      1248    1178  0 Aug25 ?        00:04:47  \_ /usr/lib/systemd/systemd --system --deserialize=34
          --
          root     1392096       1  0 Sep06 ?        00:02:44 /usr/bin/python3 /etc/ultimate-updater/web-ui/server.py --bind 0.0.0.0 --port 8765
          root     1408660       1  0 Sep06 ?        00:00:00 /bin/bash /etc/ultimate-updater/job-runner.sh run-global ultimate-updater-update-all-systems-20260906-153017-380501623-1408489 /etc/ultimate-updater/global-update.sh
          root     1408698 1408660  0 Sep06 ?        00:00:00  \_ /bin/bash /etc/ultimate-updater/global-update.sh
          root     1408709 1408698  0 Sep06 ?        00:00:00      \_ /bin/bash /etc/ultimate-updater/update.sh
          root     1408811 1408709  0 Sep06 ?        00:00:00          \_ tee /var/log/ultimate-updater.log
          root     1448924 1408709  0 Sep06 ?        00:00:01          \_ lxc-attach -n 108 --keep-env -- bash -c apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
          100000   1449016 1448924  0 Sep06 ?        00:01:49              \_ apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
          100000   1455020 1449016  0 Sep06 ?        00:00:00                  \_ /usr/bin/dpkg --force-confdef --force-confold --status-fd 24 --configure --pending
          100000   1457403 1455020  0 Sep06 ?        00:00:00                      \_ /usr/bin/perl /usr/share/debconf/frontend /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
          100000   1457519 1457403  0 Sep06 ?        00:00:00                          \_ /bin/sh /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
          100000   1457533 1457519  0 Sep06 ?        00:00:00                          |   \_ /bin/sh /usr/bin/ucf --three-way --debconf-ok --sum-file /usr/share/openssh/sshd_config.md5sum /tmp/tmp.wUhDAEjyQn /etc/ssh/sshd_config
          100000   1457635 1457403  0 Sep06 ?        00:00:00                          \_ whiptail --backtitle Package configuration --title Configuring openssh-server --output-fd 11 --nocancel --default-item keep the local version currently installed --menu A new version (/tmp/tmp.wUhDAEjyQn) of configuration file  /etc/ssh/sshd_config is available, but the version installed currently  has been locally modified.  What do you want to do about modified configuration file sshd_config? 19 76 7 -- install the package maintainer's version  keep the local version currently installed  show the differences between the versions  show a side-by-side difference between the versions  show a 3-way difference between available versions  do a 3-way merge between available versions  start a new shell to examine the situation
          _chrony  1429618       1  0 Sep06 ?        00:00:00 /usr/sbin/chronyd -n -F 1
          _chrony  1429623 1429618  0 Sep06 ?        00:00:00  \_ /usr/sbin/chronyd -n -F 1
          root     1431494       1  0 Sep06 ?        00:00:00 /usr/sbin/zed -F
          root     1432298       1  0 Sep06 ?        00:01:39 /usr/bin/pmxcfs
          root     1433736       1  0 Sep06 ?        00:00:00 /usr/sbin/qmeventd /var/run/qmeventd.sock
          root     1441793       1  0 Sep06 ?        00:00:00 /usr/sbin/rsyslogd -n -iNONE
          root     1441927       1  0 Sep06 ?        00:00:00 /usr/lib/postfix/sbin/master -w
          postfix  1441929 1441927  0 Sep06 ?        00:00:00  \_ qmgr -l -t unix -u
          postfix   299199 1441927  0 10:13 ?        00:00:00  \_ pickup -l -t unix -u -c
          root     1442345       1  0 Sep06 ?        00:00:16 pve-ha-lrm
          root     1442740       1  0 Sep06 ?        00:00:10 pve-ha-crm
          root     3433677       1  0 00:04 ?        00:00:10 /usr/sbin/pvefw-logger
          root      414602       1  0 10:42 ?        00:00:00 /usr/lib/systemd/systemd --user
          root      414604  414602  0 10:42 ?        00:00:00  \_ (sd-pam)
          

          dpkg --audit

          root@proxmox2:~# dpkg --audit
          root@proxmox2:~#
          

          systemctl list-units --type=service | grep ultimate-updater

          root@proxmox2:~# systemctl list-units --type=service | grep ultimate-updater
          ● ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service loaded activating start   start Ultimate Updater update for all systems
            ultimate-updater-web.service                                                  loaded active     running       Ultimate Updater web UI
          
          Bass-TB
          Bass-TB
          Bass-T
          schrieb am zuletzt editiert von
          #85

          @Negalein danke, damit ist jetzt ziemlich eindeutig zu sehen, wo der Job hängt. 👍

          Der Proxmox-Host selbst hängt nicht in apt/dpkg.

          Der Updatejob befindet sich aktuell in LXC 108 und wartet dort auf eine interaktive Frage von openssh-server:

          apt-get
          └─ dpkg
             └─ openssh-server.postinst
                └─ ucf
                   └─ whiptail
          

          Konkret wartet dieser Dialog auf eine Entscheidung zu:

          /etc/ssh/sshd_config
          

          Die Auswahl ist momentan sogar bereits auf

          keep the local version currently installed
          

          voreingestellt.

          Das bestätigt genau die inzwischen gefundene Lücke:
          Der Ultimate-Updater-Job läuft korrekt serverseitig weiter, kann die interaktive whiptail-Abfrage derzeit aber noch nicht zurück an die WebUI/CLI geben.

          Bitte weiterhin nicht rebooten und auch nicht die komplette Ultimate-Updater-Service-Unit abschießen.

          Dein dpkg --audit war übrigens auf dem Proxmox-Host. Relevant ist jetzt CT 108.

          Bitte zunächst einmal prüfen:

          pct exec 108 -- dpkg --audit
          

          und:

          pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
          

          Wenn dort weiterhin der whiptail-Prozess wartet, würde ich diesen einzelnen Dialog kontrolliert beenden und nicht apt oder dpkg selbst killen.

          Auf deinem bisherigen Prozessbaum wäre das PID 1457635, bitte die aktuelle PID vorher nochmals prüfen:

          pgrep -a whiptail
          

          Dann nur diesen Prozess mit TERM beenden:

          kill -TERM <WHIPTAIL-PID>
          

          Danach bitte kurz warten und kontrollieren:

          ps aux | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
          

          Sobald die laufende apt/dpkg-Kette beendet ist, direkt interaktiv in den Container:

          pct enter 108
          

          Dort:

          dpkg --audit
          

          und anschließend:

          dpkg --configure -a
          

          Jetzt läuft die Paketkonfiguration in einem echten Terminal und die Frage zu sshd_config sollte sichtbar und beantwortbar sein.

          In deinem Fall würde ich bei einer bewusst angepassten SSH-Konfiguration in der Regel:

          keep the local version currently installed
          

          wählen.

          Danach nochmals:

          dpkg --audit
          

          Wenn das ohne Ausgabe zurückkommt, ist der dpkg-Zustand wieder sauber.

          Bitte poste danach noch kurz die Ausgabe bzw. ob dpkg --configure -a sauber durchgelaufen ist.

          Der Fall ist für die Weiterentwicklung übrigens sehr hilfreich: Wir haben inzwischen auf dem Testcluster bereits erfolgreich nachgewiesen, dass sich genau solche Paketdialoge über einen persistenten PTY-/Reconnect-Kanal lösen lassen. Das wird jetzt sauber in den Ultimate Updater integriert.

          Proxmox Cluster

          • NUC7i5 ioBroker Server (Proxmox)
          • HP Elitedesk 800 G4 SSF (Proxmox)
          • HP Elitedesk 800 G2 DM (Proxmox)
            mein Proxmox-Updater für euch

          KNX / Broadlink / Tasmota ESPs / Zigbee
          Vis: 15" Touchmonitor mit Raspi4 / 10" Tablet (Dauerstrom umbau) / Sonoff NSPanel (alle)

          NegaleinN 2 Antworten Letzte Antwort
          0
          • Bass-TB Bass-T

            @Negalein danke, damit ist jetzt ziemlich eindeutig zu sehen, wo der Job hängt. 👍

            Der Proxmox-Host selbst hängt nicht in apt/dpkg.

            Der Updatejob befindet sich aktuell in LXC 108 und wartet dort auf eine interaktive Frage von openssh-server:

            apt-get
            └─ dpkg
               └─ openssh-server.postinst
                  └─ ucf
                     └─ whiptail
            

            Konkret wartet dieser Dialog auf eine Entscheidung zu:

            /etc/ssh/sshd_config
            

            Die Auswahl ist momentan sogar bereits auf

            keep the local version currently installed
            

            voreingestellt.

            Das bestätigt genau die inzwischen gefundene Lücke:
            Der Ultimate-Updater-Job läuft korrekt serverseitig weiter, kann die interaktive whiptail-Abfrage derzeit aber noch nicht zurück an die WebUI/CLI geben.

            Bitte weiterhin nicht rebooten und auch nicht die komplette Ultimate-Updater-Service-Unit abschießen.

            Dein dpkg --audit war übrigens auf dem Proxmox-Host. Relevant ist jetzt CT 108.

            Bitte zunächst einmal prüfen:

            pct exec 108 -- dpkg --audit
            

            und:

            pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
            

            Wenn dort weiterhin der whiptail-Prozess wartet, würde ich diesen einzelnen Dialog kontrolliert beenden und nicht apt oder dpkg selbst killen.

            Auf deinem bisherigen Prozessbaum wäre das PID 1457635, bitte die aktuelle PID vorher nochmals prüfen:

            pgrep -a whiptail
            

            Dann nur diesen Prozess mit TERM beenden:

            kill -TERM <WHIPTAIL-PID>
            

            Danach bitte kurz warten und kontrollieren:

            ps aux | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
            

            Sobald die laufende apt/dpkg-Kette beendet ist, direkt interaktiv in den Container:

            pct enter 108
            

            Dort:

            dpkg --audit
            

            und anschließend:

            dpkg --configure -a
            

            Jetzt läuft die Paketkonfiguration in einem echten Terminal und die Frage zu sshd_config sollte sichtbar und beantwortbar sein.

            In deinem Fall würde ich bei einer bewusst angepassten SSH-Konfiguration in der Regel:

            keep the local version currently installed
            

            wählen.

            Danach nochmals:

            dpkg --audit
            

            Wenn das ohne Ausgabe zurückkommt, ist der dpkg-Zustand wieder sauber.

            Bitte poste danach noch kurz die Ausgabe bzw. ob dpkg --configure -a sauber durchgelaufen ist.

            Der Fall ist für die Weiterentwicklung übrigens sehr hilfreich: Wir haben inzwischen auf dem Testcluster bereits erfolgreich nachgewiesen, dass sich genau solche Paketdialoge über einen persistenten PTY-/Reconnect-Kanal lösen lassen. Das wird jetzt sauber in den Ultimate Updater integriert.

            NegaleinN
            NegaleinN
            Negalein
            schrieb am zuletzt editiert von
            #86

            @Bass-T

            pct exec 108 -- dpkg --audit

            root@proxmox2:~# pct exec 108 -- dpkg --audit
            Another process has locked the database for writing, and might currently be
            modifying it, some of the following problems might just be due to that.
            
            The following packages have been unpacked but not yet configured.
            They must be configured using dpkg --configure or the configure
            menu option in dselect for them to work:
             bind9-dnsutils       Clients provided with BIND 9
             python3.13-dev       Header files and a static library for Python (v3.13)
             ssh                  secure shell client and server (metapackage)
            
            The following packages are only half configured, probably due to problems
            configuring them the first time.  The configuration should be retried using
            dpkg --configure <package> or the configure menu option in dselect:
             openssh-server       secure shell (SSH) server, for secure access from remote
            
            The following packages have been triggered, but the trigger processing
            has not yet been done.  Trigger processing can be requested using
            dselect or dpkg --configure --pending (or dpkg --triggers-only):
             dbus                 simple interprocess messaging system (system message bus)
             debianutils          Miscellaneous utilities specific to Debian
             libc-bin             GNU C Library: Binaries
             mailcap              Debian's mailcap system, and support programs
             man-db               tools for reading manual pages
             postfix              High-performance mail transport agent
             procps               /proc file system utilities
             shared-mime-info     FreeDesktop.org shared MIME database and spec
            

            pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'

            root@proxmox2:~# pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
            root      157822       0  0 Sep06 ?        00:01:52 apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
            root      160812  157822  0 Sep06 pts/3    00:00:00 /usr/bin/dpkg --force-confdef --force-confold --status-fd 24 --configure --pending
            root      161796  160812  0 Sep06 pts/3    00:00:00 /usr/bin/perl /usr/share/debconf/frontend /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
            root      161809  161796  0 Sep06 pts/3    00:00:00 /bin/sh /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
            root      161814  161809  0 Sep06 pts/3    00:00:00 /bin/sh /usr/bin/ucf --three-way --debconf-ok --sum-file /usr/share/openssh/sshd_config.md5sum /tmp/tmp.wUhDAEjyQn /etc/ssh/sshd_config
            root      161852  161796  0 Sep06 pts/3    00:00:00 whiptail --backtitle Package configuration --title Configuring openssh-server --output-fd 11 --nocancel --default-item keep the local version currently installed --menu A new version (/tmp/tmp.wUhDAEjyQn) of configuration file  /etc/ssh/sshd_config is available, but the version installed currently  has been locally modified.  What do you want to do about modified configuration file sshd_config? 19 76 7 -- install the package maintainer's version  keep the local version currently installed  show the differences between the versions  show a side-by-side difference between the versions  show a 3-way difference between available versions  do a 3-way merge between available versions  start a new shell to examine the situation
            

            pgrep -a whiptail

            root@proxmox2:~# pgrep -a whiptail
            1457635 whiptail --backtitle Package configuration --title Configuring openssh-server --output-fd 11 --nocancel --default-item keep the local version currently installed --menu A new version (/tmp/tmp.wUhDAEjyQn) of configuration file  /etc/ssh/sshd_config is available, but the version installed currently  has been locally modified.  What do you want to do about modified configuration file sshd_config? 19 76 7 -- install the package maintainer's version  keep the local version currently installed  show the differences between the versions  show a side-by-side difference between the versions  show a 3-way difference between available versions  do a 3-way merge between available versions  start a new shell to examine the situation
            

            kill -TERM 1457635

            root@proxmox2:~# kill -TERM 1457635
            root@proxmox2:~#
            

            ps aux | grep -E 'apt|apt-get|dpkg|ucf|whiptail'

            root@proxmox2:~# ps aux | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
            100000    570046  0.3  0.1  17788 14536 ?        S    11:20   0:00 bash -c #!/usr/bin/env bash _CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main" _cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func" source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func") # Copyright (c) 2021-2026 tteck # Author: tteck (tteckster) # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://www.home-assistant.io/  APP="Home Assistant" var_tags="${var_tags:-automation;smarthome;docker}" var_cpu="${var_cpu:-2}" var_ram="${var_ram:-2048}" var_disk="${var_disk:-16}" var_os="${var_os:-debian}" var_version="${var_version:-13}" var_arm64="${var_arm64:-yes}" var_unprivileged="${var_unprivileged:-1}"  header_info "$APP" variables color catch_errors  function update_script() {   header_info   check_container_storage   check_container_resources   if [[ ! -d /var/lib/docker/volumes/hass_config/_data ]]; then     msg_error "No ${APP} Installation Found!"     exit   fi   UPD=$(msg_menu "Home Assistant Update Options" \     "1" "Update ALL Containers" \     "2" "Remove ALL Unused Images" \     "3" "Install HACS" \     "4" "Install FileBrowser")    if [ "$UPD" == "1" ]; then     msg_info "Updating All Containers"     CONTAINER_LIST="${1:-$(docker ps -q)}"     for container in ${CONTAINER_LIST}; do       CONTAINER_IMAGE="$(docker inspect --format "{{.Config.Image}}" --type container "${container}")"       RUNNING_IMAGE="$(docker inspect --format "{{.Image}}" --type container "${container}")"       docker pull "${CONTAINER_IMAGE}"       LATEST_IMAGE="$(docker inspect --format "{{.Id}}" --type image "${CONTAINER_IMAGE}")"       if [[ "${RUNNING_IMAGE}" != "${LATEST_IMAGE}" ]]; then         pip install -U runlike         echo "Updating ${container} image ${CONTAINER_IMAGE}"         DOCKER_COMMAND="$(runlike --use-volume-id "${container}")"         docker rm --force "${container}"         eval "${DOCKER_COMMAND}"       fi     done     msg_ok "Updated All Containers"     exit   fi   if [ "$UPD" == "2" ]; then     msg_info "Removing ALL Unused Images"     docker image prune -af     msg_ok "Removed ALL Unused Images"     exit   fi   if [ "$UPD" == "3" ]; then     msg_info "Installing Home Assistant Community Store (HACS)"     $STD apt update     cd /var/lib/docker/volumes/hass_config/_data     $STD bash <(curl -fsSL https://get.hacs.xyz)     msg_ok "Installed Home Assistant Community Store (HACS)"     echo -e "\n Reboot Home Assistant and clear browser cache then Add HACS integration.\n"     exit   fi   if [ "$UPD" == "4" ]; then     msg_info "Installing FileBrowser"     RELEASE=$(curl -fsSL https://api.github.com/repos/filebrowser/filebrowser/releases/latest | grep -o '"tag_name": ".*"' | sed 's/"//g' | sed 's/tag_name: //g')     $STD curl -fsSL https://github.com/filebrowser/filebrowser/releases/download/v2.23.0/linux-$(arch_resolve)-filebrowser.tar.gz | tar -xzv -C /usr/local/bin     $STD filebrowser config init -a '0.0.0.0'     $STD filebrowser config set -a '0.0.0.0'     $STD filebrowser users add admin community-scripts.org --perm.admin     msg_ok "Installed FileBrowser"      msg_info "Creating Service"     service_path="/etc/systemd/system/filebrowser.service"     echo "[Unit] Description=Filebrowser After=network-online.target [Service] User=root WorkingDirectory=/root/ ExecStart=/usr/local/bin/filebrowser -r / [Install] WantedBy=default.target" >$service_path      $STD systemctl enable --now filebrowser     msg_ok "Created Service"      msg_ok "Completed successfully!\n"     echo -e "FileBrowser should be reachable by going to the following URL.          ${BL}http://$LOCAL_IP:8080${CL}   admin|community-scripts.org\n"     exit   fi }  start build_container description  msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" echo -e "${INFO}${YW}Access it using the following URL:${CL}" echo -e "${GATEWAY}${BGN}HA: http://${IP}:8123${CL}" echo -e "${GATEWAY}${BGN}Portainer: https://${IP}:9443${CL}"
            root      574939  0.0  0.0   6660  2352 pts/0    S+   11:21   0:00 grep -E apt|apt-get|dpkg|ucf|whiptail
            

            jetzt hier weiter?

            Sobald die laufende apt/dpkg-Kette beendet ist, direkt interaktiv in den Container:

            Copy to Clipboard

            pct enter 108

            Dort:

            Copy to Clipboard

            dpkg --audit

            und anschließend:

            Copy to Clipboard

            dpkg --configure -a

            ° Node.js & System Update ---> sudo apt update, iob stop, sudo apt full-upgrade
            ° Node.js Fixer ---> iob nodejs-update
            ° Fixer ---> iob fix

            Bass-TB 1 Antwort Letzte Antwort
            0
            • NegaleinN Negalein

              @Bass-T

              pct exec 108 -- dpkg --audit

              root@proxmox2:~# pct exec 108 -- dpkg --audit
              Another process has locked the database for writing, and might currently be
              modifying it, some of the following problems might just be due to that.
              
              The following packages have been unpacked but not yet configured.
              They must be configured using dpkg --configure or the configure
              menu option in dselect for them to work:
               bind9-dnsutils       Clients provided with BIND 9
               python3.13-dev       Header files and a static library for Python (v3.13)
               ssh                  secure shell client and server (metapackage)
              
              The following packages are only half configured, probably due to problems
              configuring them the first time.  The configuration should be retried using
              dpkg --configure <package> or the configure menu option in dselect:
               openssh-server       secure shell (SSH) server, for secure access from remote
              
              The following packages have been triggered, but the trigger processing
              has not yet been done.  Trigger processing can be requested using
              dselect or dpkg --configure --pending (or dpkg --triggers-only):
               dbus                 simple interprocess messaging system (system message bus)
               debianutils          Miscellaneous utilities specific to Debian
               libc-bin             GNU C Library: Binaries
               mailcap              Debian's mailcap system, and support programs
               man-db               tools for reading manual pages
               postfix              High-performance mail transport agent
               procps               /proc file system utilities
               shared-mime-info     FreeDesktop.org shared MIME database and spec
              

              pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'

              root@proxmox2:~# pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
              root      157822       0  0 Sep06 ?        00:01:52 apt-get -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold dist-upgrade -y
              root      160812  157822  0 Sep06 pts/3    00:00:00 /usr/bin/dpkg --force-confdef --force-confold --status-fd 24 --configure --pending
              root      161796  160812  0 Sep06 pts/3    00:00:00 /usr/bin/perl /usr/share/debconf/frontend /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
              root      161809  161796  0 Sep06 pts/3    00:00:00 /bin/sh /var/lib/dpkg/info/openssh-server.postinst configure 1:10.0p1-7
              root      161814  161809  0 Sep06 pts/3    00:00:00 /bin/sh /usr/bin/ucf --three-way --debconf-ok --sum-file /usr/share/openssh/sshd_config.md5sum /tmp/tmp.wUhDAEjyQn /etc/ssh/sshd_config
              root      161852  161796  0 Sep06 pts/3    00:00:00 whiptail --backtitle Package configuration --title Configuring openssh-server --output-fd 11 --nocancel --default-item keep the local version currently installed --menu A new version (/tmp/tmp.wUhDAEjyQn) of configuration file  /etc/ssh/sshd_config is available, but the version installed currently  has been locally modified.  What do you want to do about modified configuration file sshd_config? 19 76 7 -- install the package maintainer's version  keep the local version currently installed  show the differences between the versions  show a side-by-side difference between the versions  show a 3-way difference between available versions  do a 3-way merge between available versions  start a new shell to examine the situation
              

              pgrep -a whiptail

              root@proxmox2:~# pgrep -a whiptail
              1457635 whiptail --backtitle Package configuration --title Configuring openssh-server --output-fd 11 --nocancel --default-item keep the local version currently installed --menu A new version (/tmp/tmp.wUhDAEjyQn) of configuration file  /etc/ssh/sshd_config is available, but the version installed currently  has been locally modified.  What do you want to do about modified configuration file sshd_config? 19 76 7 -- install the package maintainer's version  keep the local version currently installed  show the differences between the versions  show a side-by-side difference between the versions  show a 3-way difference between available versions  do a 3-way merge between available versions  start a new shell to examine the situation
              

              kill -TERM 1457635

              root@proxmox2:~# kill -TERM 1457635
              root@proxmox2:~#
              

              ps aux | grep -E 'apt|apt-get|dpkg|ucf|whiptail'

              root@proxmox2:~# ps aux | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
              100000    570046  0.3  0.1  17788 14536 ?        S    11:20   0:00 bash -c #!/usr/bin/env bash _CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main" _cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func" source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func") # Copyright (c) 2021-2026 tteck # Author: tteck (tteckster) # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://www.home-assistant.io/  APP="Home Assistant" var_tags="${var_tags:-automation;smarthome;docker}" var_cpu="${var_cpu:-2}" var_ram="${var_ram:-2048}" var_disk="${var_disk:-16}" var_os="${var_os:-debian}" var_version="${var_version:-13}" var_arm64="${var_arm64:-yes}" var_unprivileged="${var_unprivileged:-1}"  header_info "$APP" variables color catch_errors  function update_script() {   header_info   check_container_storage   check_container_resources   if [[ ! -d /var/lib/docker/volumes/hass_config/_data ]]; then     msg_error "No ${APP} Installation Found!"     exit   fi   UPD=$(msg_menu "Home Assistant Update Options" \     "1" "Update ALL Containers" \     "2" "Remove ALL Unused Images" \     "3" "Install HACS" \     "4" "Install FileBrowser")    if [ "$UPD" == "1" ]; then     msg_info "Updating All Containers"     CONTAINER_LIST="${1:-$(docker ps -q)}"     for container in ${CONTAINER_LIST}; do       CONTAINER_IMAGE="$(docker inspect --format "{{.Config.Image}}" --type container "${container}")"       RUNNING_IMAGE="$(docker inspect --format "{{.Image}}" --type container "${container}")"       docker pull "${CONTAINER_IMAGE}"       LATEST_IMAGE="$(docker inspect --format "{{.Id}}" --type image "${CONTAINER_IMAGE}")"       if [[ "${RUNNING_IMAGE}" != "${LATEST_IMAGE}" ]]; then         pip install -U runlike         echo "Updating ${container} image ${CONTAINER_IMAGE}"         DOCKER_COMMAND="$(runlike --use-volume-id "${container}")"         docker rm --force "${container}"         eval "${DOCKER_COMMAND}"       fi     done     msg_ok "Updated All Containers"     exit   fi   if [ "$UPD" == "2" ]; then     msg_info "Removing ALL Unused Images"     docker image prune -af     msg_ok "Removed ALL Unused Images"     exit   fi   if [ "$UPD" == "3" ]; then     msg_info "Installing Home Assistant Community Store (HACS)"     $STD apt update     cd /var/lib/docker/volumes/hass_config/_data     $STD bash <(curl -fsSL https://get.hacs.xyz)     msg_ok "Installed Home Assistant Community Store (HACS)"     echo -e "\n Reboot Home Assistant and clear browser cache then Add HACS integration.\n"     exit   fi   if [ "$UPD" == "4" ]; then     msg_info "Installing FileBrowser"     RELEASE=$(curl -fsSL https://api.github.com/repos/filebrowser/filebrowser/releases/latest | grep -o '"tag_name": ".*"' | sed 's/"//g' | sed 's/tag_name: //g')     $STD curl -fsSL https://github.com/filebrowser/filebrowser/releases/download/v2.23.0/linux-$(arch_resolve)-filebrowser.tar.gz | tar -xzv -C /usr/local/bin     $STD filebrowser config init -a '0.0.0.0'     $STD filebrowser config set -a '0.0.0.0'     $STD filebrowser users add admin community-scripts.org --perm.admin     msg_ok "Installed FileBrowser"      msg_info "Creating Service"     service_path="/etc/systemd/system/filebrowser.service"     echo "[Unit] Description=Filebrowser After=network-online.target [Service] User=root WorkingDirectory=/root/ ExecStart=/usr/local/bin/filebrowser -r / [Install] WantedBy=default.target" >$service_path      $STD systemctl enable --now filebrowser     msg_ok "Created Service"      msg_ok "Completed successfully!\n"     echo -e "FileBrowser should be reachable by going to the following URL.          ${BL}http://$LOCAL_IP:8080${CL}   admin|community-scripts.org\n"     exit   fi }  start build_container description  msg_ok "Completed successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" echo -e "${INFO}${YW}Access it using the following URL:${CL}" echo -e "${GATEWAY}${BGN}HA: http://${IP}:8123${CL}" echo -e "${GATEWAY}${BGN}Portainer: https://${IP}:9443${CL}"
              root      574939  0.0  0.0   6660  2352 pts/0    S+   11:21   0:00 grep -E apt|apt-get|dpkg|ucf|whiptail
              

              jetzt hier weiter?

              Sobald die laufende apt/dpkg-Kette beendet ist, direkt interaktiv in den Container:

              Copy to Clipboard

              pct enter 108

              Dort:

              Copy to Clipboard

              dpkg --audit

              und anschließend:

              Copy to Clipboard

              dpkg --configure -a

              Bass-TB
              Bass-TB
              Bass-T
              schrieb am zuletzt editiert von
              #87

              @Negalein ja, grundsätzlich wäre dpkg --configure -a der nächste Reparaturschritt – aber bitte noch einen Moment warten und nicht direkt ausführen. 👍

              Das Beenden von whiptail hat funktioniert:
              Die vorher festhängende Kette

              apt-get
              → dpkg
              → openssh-server.postinst
              → ucf
              → whiptail
              

              ist jetzt nicht mehr in der Prozessliste.

              Allerdings sieht man inzwischen einen neuen Community-Scripts-Prozess. Das heißt sehr wahrscheinlich, dass der globale Ultimate-Updater-Job nach dem abgebrochenen Paketdialog bereits weitergelaufen ist.

              Bevor wir jetzt manuell dpkg --configure -a in CT 108 starten, müssen wir deshalb kurz sicherstellen, dass dort nicht erneut bzw. parallel etwas arbeitet.

              Bitte einmal:

              pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
              

              und:

              pct exec 108 -- dpkg --audit
              

              Zusätzlich bitte den aktuellen Ultimate-Updater-Status:

              ultimate-updater status
              

              und den aktuellen Stand des laufenden Jobs:

              systemctl status ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service --no-pager
              

              sowie die letzten Zeilen:

              journalctl -u ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service -n 80 --no-pager
              

              Wenn in CT 108 kein apt/dpkg mehr läuft, können wir anschließend dort sauber interaktiv fortsetzen mit:

              pct enter 108
              

              und dann:

              dpkg --configure -a
              

              Bei der Frage zu /etc/ssh/sshd_config würde ich bei einer bewusst angepassten SSH-Konfiguration weiterhin

              keep the local version currently installed
              

              wählen.

              Aber erst die obigen Ausgaben – ich möchte vermeiden, dass wir jetzt einen zweiten dpkg starten, während der Ultimate Updater noch irgendwo im selben Container arbeitet.

              Proxmox Cluster

              • NUC7i5 ioBroker Server (Proxmox)
              • HP Elitedesk 800 G4 SSF (Proxmox)
              • HP Elitedesk 800 G2 DM (Proxmox)
                mein Proxmox-Updater für euch

              KNX / Broadlink / Tasmota ESPs / Zigbee
              Vis: 15" Touchmonitor mit Raspi4 / 10" Tablet (Dauerstrom umbau) / Sonoff NSPanel (alle)

              NegaleinN 1 Antwort Letzte Antwort
              0
              • Bass-TB Bass-T

                @Negalein danke, damit ist jetzt ziemlich eindeutig zu sehen, wo der Job hängt. 👍

                Der Proxmox-Host selbst hängt nicht in apt/dpkg.

                Der Updatejob befindet sich aktuell in LXC 108 und wartet dort auf eine interaktive Frage von openssh-server:

                apt-get
                └─ dpkg
                   └─ openssh-server.postinst
                      └─ ucf
                         └─ whiptail
                

                Konkret wartet dieser Dialog auf eine Entscheidung zu:

                /etc/ssh/sshd_config
                

                Die Auswahl ist momentan sogar bereits auf

                keep the local version currently installed
                

                voreingestellt.

                Das bestätigt genau die inzwischen gefundene Lücke:
                Der Ultimate-Updater-Job läuft korrekt serverseitig weiter, kann die interaktive whiptail-Abfrage derzeit aber noch nicht zurück an die WebUI/CLI geben.

                Bitte weiterhin nicht rebooten und auch nicht die komplette Ultimate-Updater-Service-Unit abschießen.

                Dein dpkg --audit war übrigens auf dem Proxmox-Host. Relevant ist jetzt CT 108.

                Bitte zunächst einmal prüfen:

                pct exec 108 -- dpkg --audit
                

                und:

                pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
                

                Wenn dort weiterhin der whiptail-Prozess wartet, würde ich diesen einzelnen Dialog kontrolliert beenden und nicht apt oder dpkg selbst killen.

                Auf deinem bisherigen Prozessbaum wäre das PID 1457635, bitte die aktuelle PID vorher nochmals prüfen:

                pgrep -a whiptail
                

                Dann nur diesen Prozess mit TERM beenden:

                kill -TERM <WHIPTAIL-PID>
                

                Danach bitte kurz warten und kontrollieren:

                ps aux | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
                

                Sobald die laufende apt/dpkg-Kette beendet ist, direkt interaktiv in den Container:

                pct enter 108
                

                Dort:

                dpkg --audit
                

                und anschließend:

                dpkg --configure -a
                

                Jetzt läuft die Paketkonfiguration in einem echten Terminal und die Frage zu sshd_config sollte sichtbar und beantwortbar sein.

                In deinem Fall würde ich bei einer bewusst angepassten SSH-Konfiguration in der Regel:

                keep the local version currently installed
                

                wählen.

                Danach nochmals:

                dpkg --audit
                

                Wenn das ohne Ausgabe zurückkommt, ist der dpkg-Zustand wieder sauber.

                Bitte poste danach noch kurz die Ausgabe bzw. ob dpkg --configure -a sauber durchgelaufen ist.

                Der Fall ist für die Weiterentwicklung übrigens sehr hilfreich: Wir haben inzwischen auf dem Testcluster bereits erfolgreich nachgewiesen, dass sich genau solche Paketdialoge über einen persistenten PTY-/Reconnect-Kanal lösen lassen. Das wird jetzt sauber in den Ultimate Updater integriert.

                NegaleinN
                NegaleinN
                Negalein
                schrieb am zuletzt editiert von
                #88

                @Bass-T sagte:

                In deinem Fall würde ich bei einer bewusst angepassten SSH-Konfiguration in der Regel:

                hmmm, wüsste nicht, dass ich da jemals was angepasst hätte

                keep the local version currently installed

                im Config vom Updater?

                ° Node.js & System Update ---> sudo apt update, iob stop, sudo apt full-upgrade
                ° Node.js Fixer ---> iob nodejs-update
                ° Fixer ---> iob fix

                1 Antwort Letzte Antwort
                0
                • Bass-TB Bass-T

                  @Negalein ja, grundsätzlich wäre dpkg --configure -a der nächste Reparaturschritt – aber bitte noch einen Moment warten und nicht direkt ausführen. 👍

                  Das Beenden von whiptail hat funktioniert:
                  Die vorher festhängende Kette

                  apt-get
                  → dpkg
                  → openssh-server.postinst
                  → ucf
                  → whiptail
                  

                  ist jetzt nicht mehr in der Prozessliste.

                  Allerdings sieht man inzwischen einen neuen Community-Scripts-Prozess. Das heißt sehr wahrscheinlich, dass der globale Ultimate-Updater-Job nach dem abgebrochenen Paketdialog bereits weitergelaufen ist.

                  Bevor wir jetzt manuell dpkg --configure -a in CT 108 starten, müssen wir deshalb kurz sicherstellen, dass dort nicht erneut bzw. parallel etwas arbeitet.

                  Bitte einmal:

                  pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
                  

                  und:

                  pct exec 108 -- dpkg --audit
                  

                  Zusätzlich bitte den aktuellen Ultimate-Updater-Status:

                  ultimate-updater status
                  

                  und den aktuellen Stand des laufenden Jobs:

                  systemctl status ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service --no-pager
                  

                  sowie die letzten Zeilen:

                  journalctl -u ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service -n 80 --no-pager
                  

                  Wenn in CT 108 kein apt/dpkg mehr läuft, können wir anschließend dort sauber interaktiv fortsetzen mit:

                  pct enter 108
                  

                  und dann:

                  dpkg --configure -a
                  

                  Bei der Frage zu /etc/ssh/sshd_config würde ich bei einer bewusst angepassten SSH-Konfiguration weiterhin

                  keep the local version currently installed
                  

                  wählen.

                  Aber erst die obigen Ausgaben – ich möchte vermeiden, dass wir jetzt einen zweiten dpkg starten, während der Ultimate Updater noch irgendwo im selben Container arbeitet.

                  NegaleinN
                  NegaleinN
                  Negalein
                  schrieb am zuletzt editiert von
                  #89

                  @Bass-T

                  pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'

                  root@proxmox2:~# pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
                  root@proxmox2:~#
                  

                  pct exec 108 -- dpkg --audit

                  root@proxmox2:~# pct exec 108 -- dpkg --audit
                  root@proxmox2:~#
                  

                  ultimate-updater status

                  root@proxmox2:~# ultimate-updater status
                  Status schema 1
                  Generated: 2026-09-07T09:23:33Z
                  Target / friendly name   Reachable Updates Status         Last check
                  ----------------------   --------- ------- ------         ----------
                  proxmox2                 yes       130     updates_ava... 2026-09-06T15:29:41Z
                  108 · spoolman           yes       106     updates_ava... 2026-09-06T15:29:41Z
                  109 · homeassistant      yes       73      updates_ava... 2026-09-06T15:29:41Z
                  110 · agentdvr           yes       96      updates_ava... 2026-09-06T15:29:41Z
                  
                  Jobs
                  Type     Target / friendly name         State          Exit
                  JOB      all-systems                    completed      0
                  CHECK    all-systems                    completed      0
                  UPDATE   all-systems                    completed      0
                  JOB      selfupdate                     completed      0
                  

                  systemctl status ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service --no-pager

                  root@proxmox2:~# systemctl status ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service --no-pager
                  Unit ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service could not be found.
                  

                  journalctl -u ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service -n 80 --no-pager

                  Sep 07 11:30:52 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:03 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:03 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:14 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:14 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:25 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:25 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:33 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:36 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:36 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:47 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:47 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:58 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:31:58 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:32:09 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:32:09 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:32:20 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  Sep 07 11:32:20 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                  root@proxmox
                  

                  ° Node.js & System Update ---> sudo apt update, iob stop, sudo apt full-upgrade
                  ° Node.js Fixer ---> iob nodejs-update
                  ° Fixer ---> iob fix

                  Bass-TB 1 Antwort Letzte Antwort
                  0
                  • NegaleinN Negalein

                    @Bass-T

                    pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'

                    root@proxmox2:~# pct exec 108 -- ps -ef | grep -E 'apt|apt-get|dpkg|ucf|whiptail'
                    root@proxmox2:~#
                    

                    pct exec 108 -- dpkg --audit

                    root@proxmox2:~# pct exec 108 -- dpkg --audit
                    root@proxmox2:~#
                    

                    ultimate-updater status

                    root@proxmox2:~# ultimate-updater status
                    Status schema 1
                    Generated: 2026-09-07T09:23:33Z
                    Target / friendly name   Reachable Updates Status         Last check
                    ----------------------   --------- ------- ------         ----------
                    proxmox2                 yes       130     updates_ava... 2026-09-06T15:29:41Z
                    108 · spoolman           yes       106     updates_ava... 2026-09-06T15:29:41Z
                    109 · homeassistant      yes       73      updates_ava... 2026-09-06T15:29:41Z
                    110 · agentdvr           yes       96      updates_ava... 2026-09-06T15:29:41Z
                    
                    Jobs
                    Type     Target / friendly name         State          Exit
                    JOB      all-systems                    completed      0
                    CHECK    all-systems                    completed      0
                    UPDATE   all-systems                    completed      0
                    JOB      selfupdate                     completed      0
                    

                    systemctl status ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service --no-pager

                    root@proxmox2:~# systemctl status ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service --no-pager
                    Unit ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service could not be found.
                    

                    journalctl -u ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service -n 80 --no-pager

                    Sep 07 11:30:52 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:03 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:03 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:14 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:14 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:25 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:25 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:33 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:36 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:36 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:47 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:47 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:58 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:31:58 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:32:09 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:32:09 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:32:20 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    Sep 07 11:32:20 proxmox2 systemd[1]: ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: Failed to open /run/systemd/transient/ultimate-updater-update-all-systems-20260906-153017-380501623-1408489.service: No such file or directory
                    root@proxmox
                    
                    Bass-TB
                    Bass-TB
                    Bass-T
                    schrieb am zuletzt editiert von
                    #90

                    @Negalein perfekt – jetzt sieht alles wieder sauber aus. 👍

                    Du musst nicht mehr mit pct enter 108 und dpkg --configure -a weitermachen.

                    Die wichtigen Punkte sind:

                    pct exec 108 -- ps ...
                    

                    liefert keinen laufenden apt-/dpkg-/ucf-/whiptail-Prozess mehr.

                    Und:

                    pct exec 108 -- dpkg --audit
                    

                    liefert ebenfalls keine Ausgabe.

                    Damit ist der Paketstatus in CT 108 wieder sauber. ✅

                    Auch der Ultimate Updater selbst hat den Lauf inzwischen beendet:

                    JOB      all-systems   completed   0
                    CHECK    all-systems   completed   0
                    UPDATE   all-systems   completed   0
                    

                    Der Job ist also nicht mehr aktiv und hat Exitcode 0.

                    Dass

                    Unit ultimate-updater-update-all-systems-....service could not be found
                    

                    kommt, ist an dieser Stelle ebenfalls normal:

                    Ultimate Updater verwendet dafür eine transiente systemd-Unit. Sobald der Job beendet und aufgeräumt wurde, existiert diese Unit unter /run/systemd/transient/ nicht mehr.

                    Die nachfolgenden Meldungen im Journal

                    Failed to open /run/systemd/transient/...
                    

                    entstehen nur dadurch, dass nachträglich nach dieser bereits entfernten Unit gefragt wurde. Das ist jetzt kein weiterer Fehler des Updates.

                    Was jetzt noch sinnvoll ist

                    Die Updatezahlen in

                    ultimate-updater status
                    

                    stammen noch vom vorherigen Check:

                    Last check: 2026-09-06T15:29:41Z
                    

                    Deshalb würde ich jetzt einfach nochmal einen normalen Check aller Systeme über die WebUI starten.

                    Noch kein weiteres Update, nur Check.

                    Dann sollten die Updatezahlen und Statuswerte wieder auf dem aktuellen Stand sein.


                    Der Fall war übrigens sehr hilfreich. 🙂

                    Damit ist jetzt eindeutig bestätigt, dass der lange Lauf durch den interaktiven openssh-server-/sshd_config-Dialog in LXC 108 verursacht wurde und nicht durch einen Defekt der Jobverwaltung.

                    Genau diese Lücke – interaktive Paketabfragen bei serverseitig weiterlaufenden Jobs – wird gerade auf develop bearbeitet.

                    Auf dem Testcluster konnte bereits erfolgreich nachgewiesen werden, dass ein solcher dpkg-/whiptail-Prompt auch nach Disconnect über einen persistenten PTY-Kanal wieder verbunden und beantwortet werden kann.

                    Danke fürs Durchhalten und für die ganzen Ausgaben. 👍

                    Proxmox Cluster

                    • NUC7i5 ioBroker Server (Proxmox)
                    • HP Elitedesk 800 G4 SSF (Proxmox)
                    • HP Elitedesk 800 G2 DM (Proxmox)
                      mein Proxmox-Updater für euch

                    KNX / Broadlink / Tasmota ESPs / Zigbee
                    Vis: 15" Touchmonitor mit Raspi4 / 10" Tablet (Dauerstrom umbau) / Sonoff NSPanel (alle)

                    NegaleinN 1 Antwort Letzte Antwort
                    0
                    • Bass-TB Bass-T

                      @Negalein perfekt – jetzt sieht alles wieder sauber aus. 👍

                      Du musst nicht mehr mit pct enter 108 und dpkg --configure -a weitermachen.

                      Die wichtigen Punkte sind:

                      pct exec 108 -- ps ...
                      

                      liefert keinen laufenden apt-/dpkg-/ucf-/whiptail-Prozess mehr.

                      Und:

                      pct exec 108 -- dpkg --audit
                      

                      liefert ebenfalls keine Ausgabe.

                      Damit ist der Paketstatus in CT 108 wieder sauber. ✅

                      Auch der Ultimate Updater selbst hat den Lauf inzwischen beendet:

                      JOB      all-systems   completed   0
                      CHECK    all-systems   completed   0
                      UPDATE   all-systems   completed   0
                      

                      Der Job ist also nicht mehr aktiv und hat Exitcode 0.

                      Dass

                      Unit ultimate-updater-update-all-systems-....service could not be found
                      

                      kommt, ist an dieser Stelle ebenfalls normal:

                      Ultimate Updater verwendet dafür eine transiente systemd-Unit. Sobald der Job beendet und aufgeräumt wurde, existiert diese Unit unter /run/systemd/transient/ nicht mehr.

                      Die nachfolgenden Meldungen im Journal

                      Failed to open /run/systemd/transient/...
                      

                      entstehen nur dadurch, dass nachträglich nach dieser bereits entfernten Unit gefragt wurde. Das ist jetzt kein weiterer Fehler des Updates.

                      Was jetzt noch sinnvoll ist

                      Die Updatezahlen in

                      ultimate-updater status
                      

                      stammen noch vom vorherigen Check:

                      Last check: 2026-09-06T15:29:41Z
                      

                      Deshalb würde ich jetzt einfach nochmal einen normalen Check aller Systeme über die WebUI starten.

                      Noch kein weiteres Update, nur Check.

                      Dann sollten die Updatezahlen und Statuswerte wieder auf dem aktuellen Stand sein.


                      Der Fall war übrigens sehr hilfreich. 🙂

                      Damit ist jetzt eindeutig bestätigt, dass der lange Lauf durch den interaktiven openssh-server-/sshd_config-Dialog in LXC 108 verursacht wurde und nicht durch einen Defekt der Jobverwaltung.

                      Genau diese Lücke – interaktive Paketabfragen bei serverseitig weiterlaufenden Jobs – wird gerade auf develop bearbeitet.

                      Auf dem Testcluster konnte bereits erfolgreich nachgewiesen werden, dass ein solcher dpkg-/whiptail-Prompt auch nach Disconnect über einen persistenten PTY-Kanal wieder verbunden und beantwortet werden kann.

                      Danke fürs Durchhalten und für die ganzen Ausgaben. 👍

                      NegaleinN
                      NegaleinN
                      Negalein
                      schrieb am zuletzt editiert von
                      #91

                      @Bass-T

                      Noch kein weiteres Update, nur Check.

                      4843d37d-981e-4a74-a257-ef7df037c2fb-image.jpeg

                      Danke fürs Durchhalten und für die ganzen Ausgaben. 👍

                      gerne! nur gemeinsam kommt man ans Ziel :)

                      den Host kann ich jetzt rebooten?

                      84b2eba0-946f-465d-9d50-7432adc499cc-image.jpeg

                      ° Node.js & System Update ---> sudo apt update, iob stop, sudo apt full-upgrade
                      ° Node.js Fixer ---> iob nodejs-update
                      ° Fixer ---> iob fix

                      Bass-TB 1 Antwort Letzte Antwort
                      0
                      • NegaleinN Negalein

                        @Bass-T

                        Noch kein weiteres Update, nur Check.

                        4843d37d-981e-4a74-a257-ef7df037c2fb-image.jpeg

                        Danke fürs Durchhalten und für die ganzen Ausgaben. 👍

                        gerne! nur gemeinsam kommt man ans Ziel :)

                        den Host kann ich jetzt rebooten?

                        84b2eba0-946f-465d-9d50-7432adc499cc-image.jpeg

                        Bass-TB
                        Bass-TB
                        Bass-T
                        schrieb am zuletzt editiert von
                        #92

                        @Negalein jetzt spricht aus Sicht des Ultimate Updaters nichts mehr gegen einen Reboot. 👍

                        Der problematische Paketlauf ist beendet:

                        • kein apt/dpkg mehr aktiv
                        • dpkg --audit sauber
                        • Ultimate-Updater-Job completed 0
                        • abschließender Check ebenfalls erfolgreich

                        Damit besteht keine Gefahr mehr, dass du durch den Reboot einen laufenden Paketmanager abschießt.

                        Die pveproxy-/pve-ssl.key-Meldungen sind ein separates Proxmox-Thema. Bevor du rebootest, würde ich deshalb nur noch kurz prüfen:

                        systemctl --failed
                        

                        und:

                        systemctl is-active pveproxy pvedaemon pvestatd
                        

                        Falls der Host Teil eines Clusters ist zusätzlich:

                        pvecm status
                        

                        Wenn da nichts Kritisches auffällt, kannst du den Host rebooten.

                        Vielen Dank nochmal - gefällt mir deine Einstellung 😎

                        Proxmox Cluster

                        • NUC7i5 ioBroker Server (Proxmox)
                        • HP Elitedesk 800 G4 SSF (Proxmox)
                        • HP Elitedesk 800 G2 DM (Proxmox)
                          mein Proxmox-Updater für euch

                        KNX / Broadlink / Tasmota ESPs / Zigbee
                        Vis: 15" Touchmonitor mit Raspi4 / 10" Tablet (Dauerstrom umbau) / Sonoff NSPanel (alle)

                        NegaleinN 1 Antwort Letzte Antwort
                        0
                        • Bass-TB Bass-T

                          @Negalein jetzt spricht aus Sicht des Ultimate Updaters nichts mehr gegen einen Reboot. 👍

                          Der problematische Paketlauf ist beendet:

                          • kein apt/dpkg mehr aktiv
                          • dpkg --audit sauber
                          • Ultimate-Updater-Job completed 0
                          • abschließender Check ebenfalls erfolgreich

                          Damit besteht keine Gefahr mehr, dass du durch den Reboot einen laufenden Paketmanager abschießt.

                          Die pveproxy-/pve-ssl.key-Meldungen sind ein separates Proxmox-Thema. Bevor du rebootest, würde ich deshalb nur noch kurz prüfen:

                          systemctl --failed
                          

                          und:

                          systemctl is-active pveproxy pvedaemon pvestatd
                          

                          Falls der Host Teil eines Clusters ist zusätzlich:

                          pvecm status
                          

                          Wenn da nichts Kritisches auffällt, kannst du den Host rebooten.

                          Vielen Dank nochmal - gefällt mir deine Einstellung 😎

                          NegaleinN
                          NegaleinN
                          Negalein
                          schrieb am zuletzt editiert von
                          #93

                          @Bass-T

                          systemctl --failed

                          root@proxmox2:~# systemctl --failed
                            UNIT LOAD ACTIVE SUB DESCRIPTION
                          
                          0 loaded units listed.
                          

                          systemctl is-active pveproxy pvedaemon pvestatd

                          root@proxmox2:~# systemctl is-active pveproxy pvedaemon pvestatd
                          active
                          active
                          active
                          

                          schaut alles gut aus.
                          Dann reboote ich mal.

                          ° Node.js & System Update ---> sudo apt update, iob stop, sudo apt full-upgrade
                          ° Node.js Fixer ---> iob nodejs-update
                          ° Fixer ---> iob fix

                          1 Antwort Letzte Antwort
                          0
                          • T
                            T
                            TT-Tom
                            schrieb am zuletzt editiert von
                            #94

                            @bass-t

                            das gleiche Problem habe ich auch mit meinem MySql-Server gehabt. Dort wurde auch bei
                            dist-upgrade ein Auswahlfenster geöffnet. Habe das Ganze dann genau abgeschlossen, wie du es hier beschrieben hast. Habe den LXC erstmal ausgeklammert.

                            Gruß Tom

                            Wenn meine Hilfe erfolgreich war, benutze bitte das Voting unten rechts im Beitrag

                            Public Transport
                            https://github.com/tt-tom17/ioBroker.public-transport
                            https://github.com/tt-tom17/ioBroker.public-transport/wiki

                            NSPanel Adapter Wiki
                            https://github.com/ticaki/ioBroker.nspanel-lovelace-ui/wiki

                            Bass-TB 1 Antwort Letzte Antwort
                            0
                            • T TT-Tom

                              @bass-t

                              das gleiche Problem habe ich auch mit meinem MySql-Server gehabt. Dort wurde auch bei
                              dist-upgrade ein Auswahlfenster geöffnet. Habe das Ganze dann genau abgeschlossen, wie du es hier beschrieben hast. Habe den LXC erstmal ausgeklammert.

                              Bass-TB
                              Bass-TB
                              Bass-T
                              schrieb am zuletzt editiert von
                              #95

                              @TT-Tom ja, genau derselbe Grund.

                              Das Problem ist inzwischen eindeutig identifiziert und der technische Fix ist auf develop bereits weitgehend umgesetzt.

                              Interaktive Paketdialoge laufen jetzt über einen persistenten PTY-Kanal, sodass sich der Benutzer nach einem Disconnect wieder an den laufenden Job hängen und die Abfrage beantworten kann.

                              Der CLI-Teil funktioniert bereits:

                              ultimate-updater job attach <JOB_ID>

                              Damit wurden auf dem Testcluster echte dpkg-/whiptail-Prompts inklusive Disconnect/Reconnect erfolgreich getestet.

                              Was aktuell noch fehlt, ist die direkte Eingabe über die WebUI. Das ist der nächste Schritt.

                              Für v5.1.2 bleibt dein Workaround daher momentan sinnvoll:
                              den betroffenen LXC entweder vorübergehend ausklammern oder bei einem interaktiven Prompt wie beschrieben manuell sauber zu Ende konfigurieren.

                              Der vollständige Fix wird dann mit einem kommenden Release aus develop übernommen.

                              Proxmox Cluster

                              • NUC7i5 ioBroker Server (Proxmox)
                              • HP Elitedesk 800 G4 SSF (Proxmox)
                              • HP Elitedesk 800 G2 DM (Proxmox)
                                mein Proxmox-Updater für euch

                              KNX / Broadlink / Tasmota ESPs / Zigbee
                              Vis: 15" Touchmonitor mit Raspi4 / 10" Tablet (Dauerstrom umbau) / Sonoff NSPanel (alle)

                              1 Antwort Letzte Antwort
                              1
                              • NegaleinN
                                NegaleinN
                                Negalein
                                schrieb am zuletzt editiert von
                                #96

                                @bass-t

                                wie verhält es sich, wenn der Host noch auf 7.4-20 ist?

                                Vorher selber auf 9.x updaten?
                                Oder schafft das der Updater?

                                ° Node.js & System Update ---> sudo apt update, iob stop, sudo apt full-upgrade
                                ° Node.js Fixer ---> iob nodejs-update
                                ° Fixer ---> iob fix

                                1 Antwort Letzte Antwort
                                0
                                • Bass-TB
                                  Bass-TB
                                  Bass-T
                                  schrieb am zuletzt editiert von Bass-T
                                  #97

                                  @negalein es könnte funktionieren, ich habe es aber nie produktiv gestestet.
                                  Lediglich von 8 auf 9. Dass hatte funktioniert.

                                  Persöhnlich würde ich einen sprung von 2 Maintain Versionen glaub nicht automatisiert laufen lassen - persönliche einschätzung.

                                  Natürlich zum Updaten innerhalb der Version - sollte kein Thema sein und wunderprächtig funktionieren

                                  Ich muss mich revidieren. Ein Versionssprung macht mein Updater NICHT - sry

                                  Proxmox Cluster

                                  • NUC7i5 ioBroker Server (Proxmox)
                                  • HP Elitedesk 800 G4 SSF (Proxmox)
                                  • HP Elitedesk 800 G2 DM (Proxmox)
                                    mein Proxmox-Updater für euch

                                  KNX / Broadlink / Tasmota ESPs / Zigbee
                                  Vis: 15" Touchmonitor mit Raspi4 / 10" Tablet (Dauerstrom umbau) / Sonoff NSPanel (alle)

                                  1 Antwort Letzte Antwort
                                  0
                                  • David G.D
                                    David G.D
                                    David G.
                                    schrieb am zuletzt editiert von
                                    #98

                                    Hey,

                                    ich hatte @Nagelein ja gefragt wo die Daten aus seiner mal her sind - leider automatisch aus dem Script.

                                    Ich habe mit gestern mit Claude ein Script geschrieben, was mir alles in den iobroker holt.

                                    Status & Datenpunkte

                                    • Kompletter Status aller Targets (Host, VMs, CTs) als Datenpunkte, automatisch je
                                      Ziel angelegt (inkl. Betriebssystem, erreichbar/offline, Anzahl offener Updates,
                                      Security- vs. normale Updates, Reboot-noetig-Flag, letzter Check/Update, u.v.m.)
                                    • Health-Zusammenfassung auf einen Blick: Summe offener Security-/Normal-Updates,
                                      Liste der Targets mit offenen Updates, nicht erreichbare Targets, Targets mit
                                      ausstehendem Reboot
                                    • Job-Historie (laufende & vergangene Check-/Update-Jobs je Target) inkl.
                                      automatischem Nachladen der Logzeilen bei fehlgeschlagenen/abgebrochenen Jobs
                                    • Live-Indikator "laeuft gerade ein Job" mit adaptivem Poll-Takt (schnell waehrend
                                      etwas laeuft, langsam wenn nichts ansteht - erkennt auch kurze Jobs von nur
                                      wenigen Sekunden zuverlaessig)
                                    • Automatisches Aufraeumen: nicht mehr existierende Targets verschwinden auch aus
                                      ioBroker wieder

                                    Aktionen per Knopfdruck (aus ioBroker/VIS)

                                    • Update einzeln je Host/VM/CT
                                    • Update Sammel-Button: alle VMs/CTs auf einmal (Host bewusst ausgenommen)
                                    • Update Sammel-Button: nur Targets mit Security-relevanten Updates
                                    • Check einzeln je Host/VM/CT (nur Status aktualisieren, kein Update)
                                    • Check Sammel-Button: alle sofort auf einmal (schnell, kurzzeitig hoehere Last)
                                    • Schutz gegen Doppelausloesung: neue Aktion wird blockiert, solange bereits ein
                                      Job laeuft

                                    Automatisierung

                                    • Stuendlicher voller Status-Refresh
                                    • Naechtlicher gestaffelter Check aller Targets: geht nacheinander mit mehreren
                                      Minuten Abstand durch (statt alle gleichzeitig) - schont Host und Netzwerk
                                    • Alle Zeiten/Intervalle zentral als Variablen im Skriptkopf einstellbar

                                    Sicherheit

                                    • Zugangsdaten nur lokal im Skript, Session-Cookie + CSRF-Token werden bei jedem
                                      Login frisch geholt und nicht dauerhaft gespeichert
                                    // ioBroker JavaScript-Adapter Script
                                    // Liest den Status aller Proxmox-Hosts/VMs/CTs aus der "Ultimate Updater"-Web-API
                                    // (https://github.com/BassT23/Proxmox) und legt fuer jedes Target alle verfuegbaren
                                    // Felder als Datenpunkte an. Zusaetzlich Buttons zum Aktualisieren - einzeln pro
                                    // VM/CT, einzeln fuer den Host, und ein Sammel-Button fuer alle VMs/CTs (ohne Host).
                                    // Aktualisiert sich automatisch stuendlich.
                                    //
                                    // WICHTIG: Benutzername/Passwort direkt hier im Script-Editor eintragen - NICHT in
                                    // einem Chat/einer KI-Anfrage teilen. Die Web-API nutzt Session-Cookie + CSRF-Token,
                                    // beides wird bei jedem Login frisch geholt und nicht dauerhaft gespeichert.
                                    
                                    const UU_BASE = "https://192.168.99.58:8765";
                                    const UU_USERNAME = "root";
                                    const UU_PASSWORD = "xxxxxxxx"; 
                                    
                                    const ROOT = "0_userdata.0.proxmoxUpdater";
                                    
                                    // ---- Alle Zeit-/Intervall-Einstellungen zentral an einem Ort ----
                                    const REFRESH_CRON = "0 * * * *"; // voller Status-Refresh (alle Targets, Cleanup, Zusammenfassung, ...)
                                    const POLL_INTERVAL_BUSY_MS = 2000; // Job-Status-Poll-Takt, solange ein Check/Update-Job laeuft
                                    const POLL_INTERVAL_IDLE_MS = 30000; // Job-Status-Poll-Takt, wenn nichts laeuft
                                    const STAGGERED_CHECK_CRON = "0 4 * * *"; // Start des naechtlichen gestaffelten Checks aller Targets
                                    const STAGGERED_CHECK_DELAY_MINUTES = 3; // Abstand zwischen den einzelnen Targets beim gestaffelten Check
                                    const STAGGERED_CHECK_DELAY_MS = STAGGERED_CHECK_DELAY_MINUTES * 60 * 1000;
                                    
                                    function sanitize(s) {
                                        return String(s).replace(/[^a-zA-Z0-9_]/g, "_");
                                    }
                                    
                                    // Reiner Name reicht nicht als Ordner-Key - mehrere Targets koennen denselben Namen
                                    // tragen (z.B. mehrere CTs heissen "AgentDVR"), dann wuerden sie sich sonst beim
                                    // Anlegen der Datenpunkte gegenseitig ueberschreiben. Die ID ist dagegen garantiert
                                    // eindeutig, wird also immer mit angehaengt; der Name bleibt trotzdem lesbar im Key
                                    // und zusaetzlich als common.name des Channels sichtbar.
                                    function targetKey(t) {
                                        return `${sanitize(t.name || t.id)}_${sanitize(t.id)}`;
                                    }
                                    
                                    function createChannelP(id, name) {
                                        return setObjectAsync(id, { type: "channel", common: { name }, native: {} });
                                    }
                                    
                                    // read-only per Default (reine Anzeigewerte); Buttons ueberschreiben write:true selbst.
                                    function createStateP(id, common, val) {
                                        return createStateAsync(id, val, { read: true, write: false, ...common });
                                    }
                                    
                                    // httpGetAsync/httpPostAsync liefern per Default responseType "text", nicht "json"
                                    // (siehe getHttpRequestConfig in ioBroker.javascript) - ohne explizites responseType:"json"
                                    // kommt ein roher String zurueck und z.B. "status.targets" ist dann still undefined statt
                                    // eines Fehlers. Zusaetzlich JSON.parse-Fallback, falls trotzdem ein String zurueckkommt.
                                    function parseJson(data) {
                                        return typeof data === "string" ? JSON.parse(data) : data;
                                    }
                                    
                                    async function uuLogin() {
                                        const res = await httpPostAsync(
                                            `${UU_BASE}/api/login`,
                                            { username: UU_USERNAME, password: UU_PASSWORD },
                                            { validateCertificate: false, timeout: 15000, responseType: "json" },
                                        );
                                        if (res.statusCode !== 200) {
                                            throw new Error(`Login fehlgeschlagen: HTTP ${res.statusCode}`);
                                        }
                                        const setCookie = res.headers["set-cookie"];
                                        const cookie = Array.isArray(setCookie)
                                            ? setCookie.map(c => c.split(";")[0]).join("; ")
                                            : String(setCookie || "").split(";")[0];
                                        const data = parseJson(res.data);
                                        return { cookie, csrf: data && data.csrf };
                                    }
                                    
                                    async function uuGet(path, session) {
                                        const res = await httpGetAsync(`${UU_BASE}${path}`, {
                                            headers: { Cookie: session.cookie },
                                            validateCertificate: false,
                                            timeout: 15000,
                                            responseType: "json",
                                        });
                                        if (res.statusCode !== 200) {
                                            throw new Error(`${path} -> HTTP ${res.statusCode}`);
                                        }
                                        return parseJson(res.data);
                                    }
                                    
                                    async function uuPost(path, session, body) {
                                        const res = await httpPostAsync(`${UU_BASE}${path}`, body || {}, {
                                            headers: { Cookie: session.cookie, "X-CSRF-Token": session.csrf },
                                            validateCertificate: false,
                                            timeout: 15000,
                                            responseType: "json",
                                        });
                                        if (res.statusCode !== 200) {
                                            throw new Error(`${path} -> HTTP ${res.statusCode}`);
                                        }
                                        return parseJson(res.data);
                                    }
                                    
                                    async function uuLogout(session) {
                                        try {
                                            await uuPost("/api/logout", session, {});
                                        } catch (e) {
                                            // egal - Session laeuft sonst einfach serverseitig aus
                                        }
                                    }
                                    
                                    // Server-seitige Definition von "beschaeftigt" (server.py: state in {running, pending, starting}) -
                                    // nicht nur "running", damit ein gerade erst gestarteter Job nicht uebersehen wird.
                                    const BUSY_STATES = ["running", "pending", "starting"];
                                    
                                    // Bei diesen Endzustaenden lohnt es sich, das Log nachzuladen (bei "completed" nicht
                                    // noetig - da ist eh alles gut gegangen).
                                    const FAILURE_STATES = ["failed", "interrupted"];
                                    
                                    async function isAnyJobRunning(session) {
                                        const jobsResp = await uuGet("/api/jobs", session);
                                        const jobs = jobsResp.jobs || [];
                                        return jobs.some(j => BUSY_STATES.includes(j.state));
                                    }
                                    
                                    // Legt rekursiv alle Felder eines Targets (auch verschachtelte wie "updates") als
                                    // Datenpunkte an. Arrays werden als JSON-String gespeichert.
                                    async function flattenAndSet(prefix, obj) {
                                        for (const [key, val] of Object.entries(obj)) {
                                            const id = `${prefix}.${sanitize(key)}`;
                                            if (val !== null && typeof val === "object" && !Array.isArray(val)) {
                                                await createChannelP(id, key);
                                                await flattenAndSet(id, val);
                                            } else if (Array.isArray(val)) {
                                                await createStateP(id, { name: key, type: "string", role: "json" }, JSON.stringify(val));
                                            } else {
                                                const type = typeof val === "boolean" ? "boolean" : typeof val === "number" ? "number" : "string";
                                                const safeVal = val === undefined || val === null ? (type === "string" ? "" : null) : val;
                                                await createStateP(id, { name: key, type, role: "value" }, safeVal);
                                            }
                                        }
                                    }
                                    
                                    // Entfernt Target-Ordner, die beim letzten Refresh noch da waren, aber jetzt nicht mehr
                                    // von der API geliefert werden (VM/CT geloescht, oder - einmalig - Umstellung von
                                    // ID- auf Name-basierte Ordner). Vergleicht ueber das ".id"-Feld jedes Ordners.
                                    async function cleanupStaleTargets(currentTargets) {
                                        const currentPrefixes = new Set(currentTargets.map(targetKey));
                                        const existingPrefixes = new Set();
                                        $(`${ROOT}.targets.*.id`).each(id => {
                                            const prefix = id.replace(`${ROOT}.targets.`, "").replace(/\.id$/, "");
                                            if (!prefix.includes(".")) {
                                                existingPrefixes.add(prefix);
                                            }
                                        });
                                        for (const prefix of existingPrefixes) {
                                            if (!currentPrefixes.has(prefix)) {
                                                const fullId = `${ROOT}.targets.${prefix}`;
                                                await deleteObjectAsync(fullId, true);
                                                log(`[proxmoxUpdater] Nicht mehr gelieferter Target-Ordner entfernt: ${fullId}`);
                                            }
                                        }
                                    }
                                    
                                    // Leichtgewichtiger Check (nur /api/jobs, kein voller Status) - dafuer viel oefter
                                    // aufgerufen als der schwere refreshStatus(), damit "laeuft gerade was" auch bei
                                    // kurzen Update-Jobs (oft nur Sekunden bis wenige Minuten) nicht zwischen zwei
                                    // stuendlichen Refreshs verpasst wird. session wird wiederverwendet, falls schon
                                    // eine besteht (z.B. direkt nach einem Button-Klick), sonst wird selbst eingeloggt.
                                    async function refreshJobStatus(session) {
                                        const jobsResp = await uuGet("/api/jobs", session);
                                        const jobs = jobsResp.jobs || [];
                                        const jobRunning = jobs.some(j => BUSY_STATES.includes(j.state));
                                        await createStateP(`${ROOT}.jobRunning`, { name: "Läuft gerade ein Check/Update-Job?", type: "boolean", role: "indicator.working" }, jobRunning);
                                    
                                        // Job-Historie: letzte Checks/Updates pro Target (unit, target, state, exit_code, Zeiten ...)
                                        await createChannelP(`${ROOT}.jobs`, "Job-Historie");
                                        await createStateP(`${ROOT}.jobs.count`, { name: "Anzahl Jobs (laufend + Historie)", type: "number", role: "value" }, jobs.length);
                                        for (const j of jobs) {
                                            const jobPrefix = `${ROOT}.jobs.${sanitize(j.unit)}`;
                                            await createChannelP(jobPrefix, `${j.target || j.unit} (${j.state})`);
                                            await flattenAndSet(jobPrefix, j);
                                            if (FAILURE_STATES.includes(j.state)) {
                                                await fetchJobLogIfMissing(jobPrefix, j.unit, session);
                                            }
                                        }
                                        return jobRunning;
                                    }
                                    
                                    // Holt die letzten Logzeilen eines fehlgeschlagenen/abgebrochenen Jobs nach
                                    // (GET /api/jobs/<unit>/log - liefert die letzten 200 Zeilen aus journalctl).
                                    // Nur einmal pro Job noetig, daher Ueberspringen falls schon vorhanden.
                                    async function fetchJobLogIfMissing(jobPrefix, unit, session) {
                                        const logId = `${jobPrefix}.log`;
                                        const existing = await getStateAsync(logId);
                                        if (existing && existing.val) {
                                            return;
                                        }
                                        try {
                                            const logResp = await uuGet(`/api/jobs/${encodeURIComponent(unit)}/log`, session);
                                            await createStateP(logId, { name: "Log (letzte Zeilen bei Fehlschlag)", type: "string", role: "text" }, String(logResp.log || ""));
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Log fuer Job ${unit} konnte nicht geholt werden: ${e.message}`, "warn");
                                        }
                                    }
                                    
                                    // Selbstjustierender Poll-Takt, wie ihn auch die Original-Web-GUI von Ultimate
                                    // Updater selbst verwendet (server.py: loadJobs() pollt alle 2s solange ein Job
                                    // "running" ist, sonst alle 10s - wir nehmen 2s/30s, damit unser normaler Takt
                                    // erhalten bleibt): solange ein Job laeuft, alle 2s pruefen, damit auch kurze
                                    // Jobs von nur 10-15s sicher erfasst werden; sonst normaler 30s-Rhythmus.
                                    // pollTimer wird bei jedem Tick neu gesetzt (nie parallel mehrere Timer aktiv).
                                    let pollTimer = null;
                                    
                                    async function pollJobStatusOnce() {
                                        let session;
                                        let jobRunning = false;
                                        try {
                                            session = await uuLogin();
                                            jobRunning = await refreshJobStatus(session);
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Job-Status-Check fehlgeschlagen: ${e.message}`, "error");
                                        } finally {
                                            if (session) {
                                                await uuLogout(session);
                                            }
                                        }
                                        pollTimer = setTimeout(
                                            () => { pollJobStatusOnce().catch(e => log(`[proxmoxUpdater] Job-Status-Poll fehlgeschlagen: ${e.message}`, "error")); },
                                            jobRunning ? POLL_INTERVAL_BUSY_MS : POLL_INTERVAL_IDLE_MS,
                                        );
                                    }
                                    
                                    // Fuer den sofortigen Check direkt nach einem Button-Klick: laufenden Timer verwerfen
                                    // und sofort neu pruefen (nicht awaiten - der Button-Handler soll nicht darauf warten).
                                    function kickJobStatusPoll() {
                                        clearTimeout(pollTimer);
                                        pollJobStatusOnce().catch(e => log(`[proxmoxUpdater] Job-Status-Poll fehlgeschlagen: ${e.message}`, "error"));
                                    }
                                    
                                    async function refreshStatus() {
                                        let session;
                                        try {
                                            session = await uuLogin();
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Login fehlgeschlagen: ${e.message}`, "error");
                                            return;
                                        }
                                    
                                        try {
                                            const status = await uuGet("/api/status", session);
                                            const targets = status.targets || [];
                                    
                                            await createChannelP(ROOT, "Proxmox Ultimate Updater");
                                            await createStateP(`${ROOT}.lastRefresh`, { name: "Letzte Aktualisierung", type: "number", role: "value.time" }, Date.now());
                                            await createStateP(`${ROOT}.schemaVersion`, { name: "Schema-Version", type: "string", role: "text" }, String(status.schema_version || ""));
                                            await createStateP(`${ROOT}.generatedAt`, { name: "Generiert am (Server)", type: "string", role: "text" }, String(status.generated_at || ""));
                                            await createStateP(`${ROOT}.targetCount`, { name: "Anzahl Targets", type: "number", role: "value" }, targets.length);
                                    
                                            await refreshJobStatus(session);
                                    
                                            // Zusammenfassung ueber alle Targets - erspart das Durchklicken aller Ordner,
                                            // um zu sehen ob/wo/wie viel gerade ansteht.
                                            const targetsWithUpdates = targets.filter(t => (t.security_updates || 0) > 0 || (t.normal_updates || 0) > 0);
                                            const targetsUnreachable = targets.filter(t => t.reachable === false);
                                            const targetsRebootRequired = targets.filter(t => t.reboot_required === true);
                                            await createChannelP(`${ROOT}.summary`, "Zusammenfassung");
                                            await createStateP(`${ROOT}.summary.securityUpdatesTotal`, { name: "Offene Security-Updates (Summe ueber alle Targets)", type: "number", role: "value" }, targets.reduce((sum, t) => sum + (t.security_updates || 0), 0));
                                            await createStateP(`${ROOT}.summary.normalUpdatesTotal`, { name: "Offene normale Updates (Summe ueber alle Targets)", type: "number", role: "value" }, targets.reduce((sum, t) => sum + (t.normal_updates || 0), 0));
                                            await createStateP(`${ROOT}.summary.targetsWithUpdatesCount`, { name: "Anzahl Targets mit offenen Updates", type: "number", role: "value" }, targetsWithUpdates.length);
                                            await createStateP(`${ROOT}.summary.targetsWithUpdatesList`, { name: "Targets mit offenen Updates", type: "string", role: "json" }, JSON.stringify(targetsWithUpdates.map(t => t.name || t.id)));
                                            await createStateP(`${ROOT}.summary.unreachableCount`, { name: "Anzahl nicht erreichbarer Targets (gestoppte VMs/CTs zaehlen nicht mit)", type: "number", role: "value" }, targetsUnreachable.length);
                                            await createStateP(`${ROOT}.summary.unreachableList`, { name: "Nicht erreichbare Targets", type: "string", role: "json" }, JSON.stringify(targetsUnreachable.map(t => t.name || t.id)));
                                            await createStateP(`${ROOT}.summary.rebootRequiredCount`, { name: "Anzahl Targets mit ausstehendem Reboot", type: "number", role: "value" }, targetsRebootRequired.length);
                                            await createStateP(`${ROOT}.summary.rebootRequiredList`, { name: "Targets mit ausstehendem Reboot", type: "string", role: "json" }, JSON.stringify(targetsRebootRequired.map(t => t.name || t.id)));
                                    
                                            // Sammel-Buttons
                                            await createStateAsync(`${ROOT}.updateAllVmsCtsNow`, false, {
                                                name: "Alle VMs/CTs aktualisieren (ohne Host)",
                                                type: "boolean",
                                                role: "button",
                                                read: true,
                                                write: true,
                                            });
                                            await createStateAsync(`${ROOT}.updateSecurityOnlyNow`, false, {
                                                name: "Nur Security-Updates aktualisieren (VMs/CTs, ohne Host)",
                                                type: "boolean",
                                                role: "button",
                                                read: true,
                                                write: true,
                                            });
                                            await createStateAsync(`${ROOT}.checkAllNow`, false, {
                                                name: "Alle pruefen, inkl. Host (nur Status, kein Update)",
                                                type: "boolean",
                                                role: "button",
                                                read: true,
                                                write: true,
                                            });
                                    
                                            await createChannelP(`${ROOT}.targets`, "Targets");
                                            await cleanupStaleTargets(targets);
                                    
                                            for (const t of targets) {
                                                const isHost = t.type === "host";
                                                const prefix = `${ROOT}.targets.${targetKey(t)}`;
                                                await createChannelP(prefix, `${t.name || t.id} (${t.type})`);
                                                await flattenAndSet(prefix, t);
                                    
                                                await createStateAsync(`${prefix}.updateNow`, false, {
                                                    name: isHost ? "Diesen Host aktualisieren" : "Dieses VM/CT aktualisieren",
                                                    type: "boolean",
                                                    role: "button",
                                                    read: true,
                                                    write: true,
                                                });
                                                await createStateAsync(`${prefix}.checkNow`, false, {
                                                    name: isHost ? "Diesen Host pruefen (kein Update)" : "Dieses VM/CT pruefen (kein Update)",
                                                    type: "boolean",
                                                    role: "button",
                                                    read: true,
                                                    write: true,
                                                });
                                            }
                                    
                                            log(`[proxmoxUpdater] Status aktualisiert: ${targets.length} Targets`);
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Status-Abruf fehlgeschlagen: ${e.message}`, "error");
                                        } finally {
                                            await uuLogout(session);
                                        }
                                    }
                                    
                                    // ---- Einzel-Update-Button je Target ----
                                    on({ id: new RegExp("^0_userdata\\.0\\.proxmoxUpdater\\.targets\\.[^.]+\\.updateNow$"), change: "ne" }, async obj => {
                                        if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                            return;
                                        }
                                        setState(obj.id, false, true);
                                    
                                        const prefix = obj.id.replace(/\.updateNow$/, "");
                                        const typeState = await getStateAsync(`${prefix}.type`);
                                        const isHost = typeState && typeState.val === "host";
                                    
                                        let session;
                                        try {
                                            session = await uuLogin();
                                            if (await isAnyJobRunning(session)) {
                                                log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Aktion nicht ausgelöst.", "warn");
                                                return;
                                            }
                                            if (isHost) {
                                                const nodeState = await getStateAsync(`${prefix}.node`);
                                                const node = nodeState && nodeState.val;
                                                const res = await uuPost(`/api/update-node/${encodeURIComponent(node)}`, session, {});
                                                log(`[proxmoxUpdater] Host-Update gestartet (${node}): ${res.message || "OK"}`);
                                            } else {
                                                const idState = await getStateAsync(`${prefix}.id`);
                                                const id = idState && idState.val;
                                                const res = await uuPost(`/api/update/${encodeURIComponent(id)}`, session, {});
                                                log(`[proxmoxUpdater] Update gestartet (${id}): ${res.message || "OK"}`);
                                            }
                                            // sofort neu pruefen und danach automatisch in den schnellen 2s-Takt wechseln,
                                            // solange der Job laeuft - siehe kickJobStatusPoll()/pollJobStatusOnce()
                                            kickJobStatusPoll();
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Update fehlgeschlagen: ${e.message}`, "error");
                                        } finally {
                                            if (session) {
                                                await uuLogout(session);
                                            }
                                        }
                                    });
                                    
                                    // ---- Sammel-Button: alle VMs/CTs (ohne Host) ----
                                    on({ id: `${ROOT}.updateAllVmsCtsNow`, change: "ne" }, async obj => {
                                        if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                            return;
                                        }
                                        setState(obj.id, false, true);
                                    
                                        let session;
                                        try {
                                            session = await uuLogin();
                                            if (await isAnyJobRunning(session)) {
                                                log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Sammel-Update nicht ausgelöst.", "warn");
                                                return;
                                            }
                                            const status = await uuGet("/api/status", session);
                                            const targets = (status.targets || []).filter(t => t.type !== "host");
                                            log(`[proxmoxUpdater] Starte Update fuer ${targets.length} VMs/CTs (Host ausgenommen)`);
                                            for (const t of targets) {
                                                try {
                                                    await uuPost(`/api/update/${encodeURIComponent(t.id)}`, session, {});
                                                } catch (e) {
                                                    log(`[proxmoxUpdater] Update fuer ${t.id} fehlgeschlagen: ${e.message}`, "warn");
                                                }
                                            }
                                            // sofort neu pruefen und danach automatisch in den schnellen 2s-Takt wechseln,
                                            // solange der Job laeuft - siehe kickJobStatusPoll()/pollJobStatusOnce()
                                            kickJobStatusPoll();
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Sammel-Update fehlgeschlagen: ${e.message}`, "error");
                                        } finally {
                                            if (session) {
                                                await uuLogout(session);
                                            }
                                        }
                                    });
                                    
                                    // ---- Einzel-Check-Button je Target (nur pruefen, kein Update) ----
                                    on({ id: new RegExp("^0_userdata\\.0\\.proxmoxUpdater\\.targets\\.[^.]+\\.checkNow$"), change: "ne" }, async obj => {
                                        if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                            return;
                                        }
                                        setState(obj.id, false, true);
                                    
                                        const prefix = obj.id.replace(/\.checkNow$/, "");
                                        const typeState = await getStateAsync(`${prefix}.type`);
                                        const isHost = typeState && typeState.val === "host";
                                    
                                        let session;
                                        try {
                                            session = await uuLogin();
                                            if (await isAnyJobRunning(session)) {
                                                log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Check nicht ausgelöst.", "warn");
                                                return;
                                            }
                                            if (isHost) {
                                                const nodeState = await getStateAsync(`${prefix}.node`);
                                                const node = nodeState && nodeState.val;
                                                const res = await uuPost(`/api/check-node/${encodeURIComponent(node)}`, session, {});
                                                log(`[proxmoxUpdater] Host-Check gestartet (${node}): ${res.message || "OK"}`);
                                            } else {
                                                const idState = await getStateAsync(`${prefix}.id`);
                                                const id = idState && idState.val;
                                                const res = await uuPost(`/api/check/${encodeURIComponent(id)}`, session, {});
                                                log(`[proxmoxUpdater] Check gestartet (${id}): ${res.message || "OK"}`);
                                            }
                                            kickJobStatusPoll();
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Check fehlgeschlagen: ${e.message}`, "error");
                                        } finally {
                                            if (session) {
                                                await uuLogout(session);
                                            }
                                        }
                                    });
                                    
                                    // ---- Sammel-Button: alle pruefen, inkl. Host (read-only, daher unbedenklich) ----
                                    on({ id: `${ROOT}.checkAllNow`, change: "ne" }, async obj => {
                                        if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                            return;
                                        }
                                        setState(obj.id, false, true);
                                    
                                        let session;
                                        try {
                                            session = await uuLogin();
                                            if (await isAnyJobRunning(session)) {
                                                log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Sammel-Check nicht ausgelöst.", "warn");
                                                return;
                                            }
                                            const res = await uuPost("/api/check-all", session, {});
                                            log(`[proxmoxUpdater] Sammel-Check gestartet: ${res.message || "OK"}`);
                                            kickJobStatusPoll();
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Sammel-Check fehlgeschlagen: ${e.message}`, "error");
                                        } finally {
                                            if (session) {
                                                await uuLogout(session);
                                            }
                                        }
                                    });
                                    
                                    // ---- Sammel-Button: nur Targets mit Security-Updates aktualisieren (ohne Host) ----
                                    on({ id: `${ROOT}.updateSecurityOnlyNow`, change: "ne" }, async obj => {
                                        if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                            return;
                                        }
                                        setState(obj.id, false, true);
                                    
                                        let session;
                                        try {
                                            session = await uuLogin();
                                            if (await isAnyJobRunning(session)) {
                                                log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Security-Update nicht ausgelöst.", "warn");
                                                return;
                                            }
                                            const status = await uuGet("/api/status", session);
                                            const targets = (status.targets || []).filter(t => t.type !== "host" && (t.security_updates || 0) > 0);
                                            log(`[proxmoxUpdater] Starte Security-Update fuer ${targets.length} VMs/CTs`);
                                            for (const t of targets) {
                                                try {
                                                    await uuPost(`/api/update/${encodeURIComponent(t.id)}`, session, {});
                                                } catch (e) {
                                                    log(`[proxmoxUpdater] Security-Update fuer ${t.id} fehlgeschlagen: ${e.message}`, "warn");
                                                }
                                            }
                                            kickJobStatusPoll();
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Security-Update fehlgeschlagen: ${e.message}`, "error");
                                        } finally {
                                            if (session) {
                                                await uuLogout(session);
                                            }
                                        }
                                    });
                                    
                                    function delay(ms) {
                                        return new Promise(resolve => setTimeout(resolve, ms));
                                    }
                                    
                                    // Gestaffelter Check aller Targets nacheinander (statt alle gleichzeitig wie
                                    // checkAllNow) - schont Host/Netzwerk, dauert dafuer entsprechend laenger
                                    // (28 Targets * STAGGERED_CHECK_DELAY_MINUTES ≈ 1,5h). Fuer den schnellen,
                                    // manuellen "jetzt sofort alle" mit kurzer hoher Last gibt es weiterhin den
                                    // checkAllNow-Datenpunkt/Button.
                                    async function staggeredCheckAll() {
                                        let targets;
                                        try {
                                            const session = await uuLogin();
                                            try {
                                                const status = await uuGet("/api/status", session);
                                                targets = status.targets || [];
                                            } finally {
                                                await uuLogout(session);
                                            }
                                        } catch (e) {
                                            log(`[proxmoxUpdater] Gestaffelter Check: Target-Liste konnte nicht geholt werden: ${e.message}`, "error");
                                            return;
                                        }
                                    
                                        log(`[proxmoxUpdater] Gestaffelter Check gestartet (${targets.length} Targets, ${STAGGERED_CHECK_DELAY_MINUTES} min Abstand)`);
                                        for (let i = 0; i < targets.length; i++) {
                                            const t = targets[i];
                                            const label = t.name || t.id;
                                            let session;
                                            try {
                                                session = await uuLogin();
                                                if (await isAnyJobRunning(session)) {
                                                    log(`[proxmoxUpdater] Gestaffelter Check: ${label} übersprungen - es läuft bereits ein anderer Job.`, "warn");
                                                } else if (t.type === "host") {
                                                    await uuPost(`/api/check-node/${encodeURIComponent(t.node)}`, session, {});
                                                    log(`[proxmoxUpdater] Gestaffelter Check ${i + 1}/${targets.length}: Host ${label} gestartet`);
                                                } else {
                                                    await uuPost(`/api/check/${encodeURIComponent(t.id)}`, session, {});
                                                    log(`[proxmoxUpdater] Gestaffelter Check ${i + 1}/${targets.length}: ${label} gestartet`);
                                                }
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Gestaffelter Check: ${label} fehlgeschlagen: ${e.message}`, "warn");
                                            } finally {
                                                if (session) {
                                                    await uuLogout(session);
                                                }
                                            }
                                            kickJobStatusPoll();
                                            if (i < targets.length - 1) {
                                                await delay(STAGGERED_CHECK_DELAY_MS);
                                            }
                                        }
                                        log(`[proxmoxUpdater] Gestaffelter Check abgeschlossen (${targets.length} Targets)`);
                                    }
                                    
                                    refreshStatus().catch(e => log(`[proxmoxUpdater] Abbruch: ${e.message}`, "error"));
                                    
                                    // stuendlich der volle, schwere Refresh (alle Targets, Cleanup, ...)
                                    schedule(REFRESH_CRON, refreshStatus);
                                    
                                    // naechtlich der gestaffelte Check aller Targets (siehe staggeredCheckAll())
                                    schedule(STAGGERED_CHECK_CRON, () => {
                                        staggeredCheckAll().catch(e => log(`[proxmoxUpdater] Gestaffelter Check abgebrochen: ${e.message}`, "error"));
                                    });
                                    
                                    // leichter Job-Status-Check startet selbstjustierend (busy/idle-Takt s.o.) -
                                    // schedule() kann keine Sub-Minuten-Intervalle, daher die eigene setTimeout-Kette
                                    // in pollJobStatusOnce()/kickJobStatusPoll() weiter oben.
                                    pollTimer = setTimeout(() => {
                                        pollJobStatusOnce().catch(e => log(`[proxmoxUpdater] Job-Status-Poll fehlgeschlagen: ${e.message}`, "error"));
                                    }, POLL_INTERVAL_IDLE_MS);
                                    
                                    

                                    Zeigt eure Lovelace-Visualisierung klick
                                    (Auch ideal um sich Anregungen zu holen)

                                    Meine Tabellen für eure Visualisierung klick

                                    NegaleinN 1 Antwort Letzte Antwort
                                    1
                                    • Bass-TB
                                      Bass-TB
                                      Bass-T
                                      schrieb am zuletzt editiert von
                                      #99

                                      @david-g. Schick, damit ist der Updater ja praktisch voll in die Visu integrierbar – top. 👌🏻

                                      Wenn ich mal wieder dafür Zeit finde, muss ich bei mir auch wieder ran.
                                      Umzug ist voll doof für Visu bauen. 😀

                                      Proxmox Cluster

                                      • NUC7i5 ioBroker Server (Proxmox)
                                      • HP Elitedesk 800 G4 SSF (Proxmox)
                                      • HP Elitedesk 800 G2 DM (Proxmox)
                                        mein Proxmox-Updater für euch

                                      KNX / Broadlink / Tasmota ESPs / Zigbee
                                      Vis: 15" Touchmonitor mit Raspi4 / 10" Tablet (Dauerstrom umbau) / Sonoff NSPanel (alle)

                                      1 Antwort Letzte Antwort
                                      0
                                      • David G.D David G.

                                        Hey,

                                        ich hatte @Nagelein ja gefragt wo die Daten aus seiner mal her sind - leider automatisch aus dem Script.

                                        Ich habe mit gestern mit Claude ein Script geschrieben, was mir alles in den iobroker holt.

                                        Status & Datenpunkte

                                        • Kompletter Status aller Targets (Host, VMs, CTs) als Datenpunkte, automatisch je
                                          Ziel angelegt (inkl. Betriebssystem, erreichbar/offline, Anzahl offener Updates,
                                          Security- vs. normale Updates, Reboot-noetig-Flag, letzter Check/Update, u.v.m.)
                                        • Health-Zusammenfassung auf einen Blick: Summe offener Security-/Normal-Updates,
                                          Liste der Targets mit offenen Updates, nicht erreichbare Targets, Targets mit
                                          ausstehendem Reboot
                                        • Job-Historie (laufende & vergangene Check-/Update-Jobs je Target) inkl.
                                          automatischem Nachladen der Logzeilen bei fehlgeschlagenen/abgebrochenen Jobs
                                        • Live-Indikator "laeuft gerade ein Job" mit adaptivem Poll-Takt (schnell waehrend
                                          etwas laeuft, langsam wenn nichts ansteht - erkennt auch kurze Jobs von nur
                                          wenigen Sekunden zuverlaessig)
                                        • Automatisches Aufraeumen: nicht mehr existierende Targets verschwinden auch aus
                                          ioBroker wieder

                                        Aktionen per Knopfdruck (aus ioBroker/VIS)

                                        • Update einzeln je Host/VM/CT
                                        • Update Sammel-Button: alle VMs/CTs auf einmal (Host bewusst ausgenommen)
                                        • Update Sammel-Button: nur Targets mit Security-relevanten Updates
                                        • Check einzeln je Host/VM/CT (nur Status aktualisieren, kein Update)
                                        • Check Sammel-Button: alle sofort auf einmal (schnell, kurzzeitig hoehere Last)
                                        • Schutz gegen Doppelausloesung: neue Aktion wird blockiert, solange bereits ein
                                          Job laeuft

                                        Automatisierung

                                        • Stuendlicher voller Status-Refresh
                                        • Naechtlicher gestaffelter Check aller Targets: geht nacheinander mit mehreren
                                          Minuten Abstand durch (statt alle gleichzeitig) - schont Host und Netzwerk
                                        • Alle Zeiten/Intervalle zentral als Variablen im Skriptkopf einstellbar

                                        Sicherheit

                                        • Zugangsdaten nur lokal im Skript, Session-Cookie + CSRF-Token werden bei jedem
                                          Login frisch geholt und nicht dauerhaft gespeichert
                                        // ioBroker JavaScript-Adapter Script
                                        // Liest den Status aller Proxmox-Hosts/VMs/CTs aus der "Ultimate Updater"-Web-API
                                        // (https://github.com/BassT23/Proxmox) und legt fuer jedes Target alle verfuegbaren
                                        // Felder als Datenpunkte an. Zusaetzlich Buttons zum Aktualisieren - einzeln pro
                                        // VM/CT, einzeln fuer den Host, und ein Sammel-Button fuer alle VMs/CTs (ohne Host).
                                        // Aktualisiert sich automatisch stuendlich.
                                        //
                                        // WICHTIG: Benutzername/Passwort direkt hier im Script-Editor eintragen - NICHT in
                                        // einem Chat/einer KI-Anfrage teilen. Die Web-API nutzt Session-Cookie + CSRF-Token,
                                        // beides wird bei jedem Login frisch geholt und nicht dauerhaft gespeichert.
                                        
                                        const UU_BASE = "https://192.168.99.58:8765";
                                        const UU_USERNAME = "root";
                                        const UU_PASSWORD = "xxxxxxxx"; 
                                        
                                        const ROOT = "0_userdata.0.proxmoxUpdater";
                                        
                                        // ---- Alle Zeit-/Intervall-Einstellungen zentral an einem Ort ----
                                        const REFRESH_CRON = "0 * * * *"; // voller Status-Refresh (alle Targets, Cleanup, Zusammenfassung, ...)
                                        const POLL_INTERVAL_BUSY_MS = 2000; // Job-Status-Poll-Takt, solange ein Check/Update-Job laeuft
                                        const POLL_INTERVAL_IDLE_MS = 30000; // Job-Status-Poll-Takt, wenn nichts laeuft
                                        const STAGGERED_CHECK_CRON = "0 4 * * *"; // Start des naechtlichen gestaffelten Checks aller Targets
                                        const STAGGERED_CHECK_DELAY_MINUTES = 3; // Abstand zwischen den einzelnen Targets beim gestaffelten Check
                                        const STAGGERED_CHECK_DELAY_MS = STAGGERED_CHECK_DELAY_MINUTES * 60 * 1000;
                                        
                                        function sanitize(s) {
                                            return String(s).replace(/[^a-zA-Z0-9_]/g, "_");
                                        }
                                        
                                        // Reiner Name reicht nicht als Ordner-Key - mehrere Targets koennen denselben Namen
                                        // tragen (z.B. mehrere CTs heissen "AgentDVR"), dann wuerden sie sich sonst beim
                                        // Anlegen der Datenpunkte gegenseitig ueberschreiben. Die ID ist dagegen garantiert
                                        // eindeutig, wird also immer mit angehaengt; der Name bleibt trotzdem lesbar im Key
                                        // und zusaetzlich als common.name des Channels sichtbar.
                                        function targetKey(t) {
                                            return `${sanitize(t.name || t.id)}_${sanitize(t.id)}`;
                                        }
                                        
                                        function createChannelP(id, name) {
                                            return setObjectAsync(id, { type: "channel", common: { name }, native: {} });
                                        }
                                        
                                        // read-only per Default (reine Anzeigewerte); Buttons ueberschreiben write:true selbst.
                                        function createStateP(id, common, val) {
                                            return createStateAsync(id, val, { read: true, write: false, ...common });
                                        }
                                        
                                        // httpGetAsync/httpPostAsync liefern per Default responseType "text", nicht "json"
                                        // (siehe getHttpRequestConfig in ioBroker.javascript) - ohne explizites responseType:"json"
                                        // kommt ein roher String zurueck und z.B. "status.targets" ist dann still undefined statt
                                        // eines Fehlers. Zusaetzlich JSON.parse-Fallback, falls trotzdem ein String zurueckkommt.
                                        function parseJson(data) {
                                            return typeof data === "string" ? JSON.parse(data) : data;
                                        }
                                        
                                        async function uuLogin() {
                                            const res = await httpPostAsync(
                                                `${UU_BASE}/api/login`,
                                                { username: UU_USERNAME, password: UU_PASSWORD },
                                                { validateCertificate: false, timeout: 15000, responseType: "json" },
                                            );
                                            if (res.statusCode !== 200) {
                                                throw new Error(`Login fehlgeschlagen: HTTP ${res.statusCode}`);
                                            }
                                            const setCookie = res.headers["set-cookie"];
                                            const cookie = Array.isArray(setCookie)
                                                ? setCookie.map(c => c.split(";")[0]).join("; ")
                                                : String(setCookie || "").split(";")[0];
                                            const data = parseJson(res.data);
                                            return { cookie, csrf: data && data.csrf };
                                        }
                                        
                                        async function uuGet(path, session) {
                                            const res = await httpGetAsync(`${UU_BASE}${path}`, {
                                                headers: { Cookie: session.cookie },
                                                validateCertificate: false,
                                                timeout: 15000,
                                                responseType: "json",
                                            });
                                            if (res.statusCode !== 200) {
                                                throw new Error(`${path} -> HTTP ${res.statusCode}`);
                                            }
                                            return parseJson(res.data);
                                        }
                                        
                                        async function uuPost(path, session, body) {
                                            const res = await httpPostAsync(`${UU_BASE}${path}`, body || {}, {
                                                headers: { Cookie: session.cookie, "X-CSRF-Token": session.csrf },
                                                validateCertificate: false,
                                                timeout: 15000,
                                                responseType: "json",
                                            });
                                            if (res.statusCode !== 200) {
                                                throw new Error(`${path} -> HTTP ${res.statusCode}`);
                                            }
                                            return parseJson(res.data);
                                        }
                                        
                                        async function uuLogout(session) {
                                            try {
                                                await uuPost("/api/logout", session, {});
                                            } catch (e) {
                                                // egal - Session laeuft sonst einfach serverseitig aus
                                            }
                                        }
                                        
                                        // Server-seitige Definition von "beschaeftigt" (server.py: state in {running, pending, starting}) -
                                        // nicht nur "running", damit ein gerade erst gestarteter Job nicht uebersehen wird.
                                        const BUSY_STATES = ["running", "pending", "starting"];
                                        
                                        // Bei diesen Endzustaenden lohnt es sich, das Log nachzuladen (bei "completed" nicht
                                        // noetig - da ist eh alles gut gegangen).
                                        const FAILURE_STATES = ["failed", "interrupted"];
                                        
                                        async function isAnyJobRunning(session) {
                                            const jobsResp = await uuGet("/api/jobs", session);
                                            const jobs = jobsResp.jobs || [];
                                            return jobs.some(j => BUSY_STATES.includes(j.state));
                                        }
                                        
                                        // Legt rekursiv alle Felder eines Targets (auch verschachtelte wie "updates") als
                                        // Datenpunkte an. Arrays werden als JSON-String gespeichert.
                                        async function flattenAndSet(prefix, obj) {
                                            for (const [key, val] of Object.entries(obj)) {
                                                const id = `${prefix}.${sanitize(key)}`;
                                                if (val !== null && typeof val === "object" && !Array.isArray(val)) {
                                                    await createChannelP(id, key);
                                                    await flattenAndSet(id, val);
                                                } else if (Array.isArray(val)) {
                                                    await createStateP(id, { name: key, type: "string", role: "json" }, JSON.stringify(val));
                                                } else {
                                                    const type = typeof val === "boolean" ? "boolean" : typeof val === "number" ? "number" : "string";
                                                    const safeVal = val === undefined || val === null ? (type === "string" ? "" : null) : val;
                                                    await createStateP(id, { name: key, type, role: "value" }, safeVal);
                                                }
                                            }
                                        }
                                        
                                        // Entfernt Target-Ordner, die beim letzten Refresh noch da waren, aber jetzt nicht mehr
                                        // von der API geliefert werden (VM/CT geloescht, oder - einmalig - Umstellung von
                                        // ID- auf Name-basierte Ordner). Vergleicht ueber das ".id"-Feld jedes Ordners.
                                        async function cleanupStaleTargets(currentTargets) {
                                            const currentPrefixes = new Set(currentTargets.map(targetKey));
                                            const existingPrefixes = new Set();
                                            $(`${ROOT}.targets.*.id`).each(id => {
                                                const prefix = id.replace(`${ROOT}.targets.`, "").replace(/\.id$/, "");
                                                if (!prefix.includes(".")) {
                                                    existingPrefixes.add(prefix);
                                                }
                                            });
                                            for (const prefix of existingPrefixes) {
                                                if (!currentPrefixes.has(prefix)) {
                                                    const fullId = `${ROOT}.targets.${prefix}`;
                                                    await deleteObjectAsync(fullId, true);
                                                    log(`[proxmoxUpdater] Nicht mehr gelieferter Target-Ordner entfernt: ${fullId}`);
                                                }
                                            }
                                        }
                                        
                                        // Leichtgewichtiger Check (nur /api/jobs, kein voller Status) - dafuer viel oefter
                                        // aufgerufen als der schwere refreshStatus(), damit "laeuft gerade was" auch bei
                                        // kurzen Update-Jobs (oft nur Sekunden bis wenige Minuten) nicht zwischen zwei
                                        // stuendlichen Refreshs verpasst wird. session wird wiederverwendet, falls schon
                                        // eine besteht (z.B. direkt nach einem Button-Klick), sonst wird selbst eingeloggt.
                                        async function refreshJobStatus(session) {
                                            const jobsResp = await uuGet("/api/jobs", session);
                                            const jobs = jobsResp.jobs || [];
                                            const jobRunning = jobs.some(j => BUSY_STATES.includes(j.state));
                                            await createStateP(`${ROOT}.jobRunning`, { name: "Läuft gerade ein Check/Update-Job?", type: "boolean", role: "indicator.working" }, jobRunning);
                                        
                                            // Job-Historie: letzte Checks/Updates pro Target (unit, target, state, exit_code, Zeiten ...)
                                            await createChannelP(`${ROOT}.jobs`, "Job-Historie");
                                            await createStateP(`${ROOT}.jobs.count`, { name: "Anzahl Jobs (laufend + Historie)", type: "number", role: "value" }, jobs.length);
                                            for (const j of jobs) {
                                                const jobPrefix = `${ROOT}.jobs.${sanitize(j.unit)}`;
                                                await createChannelP(jobPrefix, `${j.target || j.unit} (${j.state})`);
                                                await flattenAndSet(jobPrefix, j);
                                                if (FAILURE_STATES.includes(j.state)) {
                                                    await fetchJobLogIfMissing(jobPrefix, j.unit, session);
                                                }
                                            }
                                            return jobRunning;
                                        }
                                        
                                        // Holt die letzten Logzeilen eines fehlgeschlagenen/abgebrochenen Jobs nach
                                        // (GET /api/jobs/<unit>/log - liefert die letzten 200 Zeilen aus journalctl).
                                        // Nur einmal pro Job noetig, daher Ueberspringen falls schon vorhanden.
                                        async function fetchJobLogIfMissing(jobPrefix, unit, session) {
                                            const logId = `${jobPrefix}.log`;
                                            const existing = await getStateAsync(logId);
                                            if (existing && existing.val) {
                                                return;
                                            }
                                            try {
                                                const logResp = await uuGet(`/api/jobs/${encodeURIComponent(unit)}/log`, session);
                                                await createStateP(logId, { name: "Log (letzte Zeilen bei Fehlschlag)", type: "string", role: "text" }, String(logResp.log || ""));
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Log fuer Job ${unit} konnte nicht geholt werden: ${e.message}`, "warn");
                                            }
                                        }
                                        
                                        // Selbstjustierender Poll-Takt, wie ihn auch die Original-Web-GUI von Ultimate
                                        // Updater selbst verwendet (server.py: loadJobs() pollt alle 2s solange ein Job
                                        // "running" ist, sonst alle 10s - wir nehmen 2s/30s, damit unser normaler Takt
                                        // erhalten bleibt): solange ein Job laeuft, alle 2s pruefen, damit auch kurze
                                        // Jobs von nur 10-15s sicher erfasst werden; sonst normaler 30s-Rhythmus.
                                        // pollTimer wird bei jedem Tick neu gesetzt (nie parallel mehrere Timer aktiv).
                                        let pollTimer = null;
                                        
                                        async function pollJobStatusOnce() {
                                            let session;
                                            let jobRunning = false;
                                            try {
                                                session = await uuLogin();
                                                jobRunning = await refreshJobStatus(session);
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Job-Status-Check fehlgeschlagen: ${e.message}`, "error");
                                            } finally {
                                                if (session) {
                                                    await uuLogout(session);
                                                }
                                            }
                                            pollTimer = setTimeout(
                                                () => { pollJobStatusOnce().catch(e => log(`[proxmoxUpdater] Job-Status-Poll fehlgeschlagen: ${e.message}`, "error")); },
                                                jobRunning ? POLL_INTERVAL_BUSY_MS : POLL_INTERVAL_IDLE_MS,
                                            );
                                        }
                                        
                                        // Fuer den sofortigen Check direkt nach einem Button-Klick: laufenden Timer verwerfen
                                        // und sofort neu pruefen (nicht awaiten - der Button-Handler soll nicht darauf warten).
                                        function kickJobStatusPoll() {
                                            clearTimeout(pollTimer);
                                            pollJobStatusOnce().catch(e => log(`[proxmoxUpdater] Job-Status-Poll fehlgeschlagen: ${e.message}`, "error"));
                                        }
                                        
                                        async function refreshStatus() {
                                            let session;
                                            try {
                                                session = await uuLogin();
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Login fehlgeschlagen: ${e.message}`, "error");
                                                return;
                                            }
                                        
                                            try {
                                                const status = await uuGet("/api/status", session);
                                                const targets = status.targets || [];
                                        
                                                await createChannelP(ROOT, "Proxmox Ultimate Updater");
                                                await createStateP(`${ROOT}.lastRefresh`, { name: "Letzte Aktualisierung", type: "number", role: "value.time" }, Date.now());
                                                await createStateP(`${ROOT}.schemaVersion`, { name: "Schema-Version", type: "string", role: "text" }, String(status.schema_version || ""));
                                                await createStateP(`${ROOT}.generatedAt`, { name: "Generiert am (Server)", type: "string", role: "text" }, String(status.generated_at || ""));
                                                await createStateP(`${ROOT}.targetCount`, { name: "Anzahl Targets", type: "number", role: "value" }, targets.length);
                                        
                                                await refreshJobStatus(session);
                                        
                                                // Zusammenfassung ueber alle Targets - erspart das Durchklicken aller Ordner,
                                                // um zu sehen ob/wo/wie viel gerade ansteht.
                                                const targetsWithUpdates = targets.filter(t => (t.security_updates || 0) > 0 || (t.normal_updates || 0) > 0);
                                                const targetsUnreachable = targets.filter(t => t.reachable === false);
                                                const targetsRebootRequired = targets.filter(t => t.reboot_required === true);
                                                await createChannelP(`${ROOT}.summary`, "Zusammenfassung");
                                                await createStateP(`${ROOT}.summary.securityUpdatesTotal`, { name: "Offene Security-Updates (Summe ueber alle Targets)", type: "number", role: "value" }, targets.reduce((sum, t) => sum + (t.security_updates || 0), 0));
                                                await createStateP(`${ROOT}.summary.normalUpdatesTotal`, { name: "Offene normale Updates (Summe ueber alle Targets)", type: "number", role: "value" }, targets.reduce((sum, t) => sum + (t.normal_updates || 0), 0));
                                                await createStateP(`${ROOT}.summary.targetsWithUpdatesCount`, { name: "Anzahl Targets mit offenen Updates", type: "number", role: "value" }, targetsWithUpdates.length);
                                                await createStateP(`${ROOT}.summary.targetsWithUpdatesList`, { name: "Targets mit offenen Updates", type: "string", role: "json" }, JSON.stringify(targetsWithUpdates.map(t => t.name || t.id)));
                                                await createStateP(`${ROOT}.summary.unreachableCount`, { name: "Anzahl nicht erreichbarer Targets (gestoppte VMs/CTs zaehlen nicht mit)", type: "number", role: "value" }, targetsUnreachable.length);
                                                await createStateP(`${ROOT}.summary.unreachableList`, { name: "Nicht erreichbare Targets", type: "string", role: "json" }, JSON.stringify(targetsUnreachable.map(t => t.name || t.id)));
                                                await createStateP(`${ROOT}.summary.rebootRequiredCount`, { name: "Anzahl Targets mit ausstehendem Reboot", type: "number", role: "value" }, targetsRebootRequired.length);
                                                await createStateP(`${ROOT}.summary.rebootRequiredList`, { name: "Targets mit ausstehendem Reboot", type: "string", role: "json" }, JSON.stringify(targetsRebootRequired.map(t => t.name || t.id)));
                                        
                                                // Sammel-Buttons
                                                await createStateAsync(`${ROOT}.updateAllVmsCtsNow`, false, {
                                                    name: "Alle VMs/CTs aktualisieren (ohne Host)",
                                                    type: "boolean",
                                                    role: "button",
                                                    read: true,
                                                    write: true,
                                                });
                                                await createStateAsync(`${ROOT}.updateSecurityOnlyNow`, false, {
                                                    name: "Nur Security-Updates aktualisieren (VMs/CTs, ohne Host)",
                                                    type: "boolean",
                                                    role: "button",
                                                    read: true,
                                                    write: true,
                                                });
                                                await createStateAsync(`${ROOT}.checkAllNow`, false, {
                                                    name: "Alle pruefen, inkl. Host (nur Status, kein Update)",
                                                    type: "boolean",
                                                    role: "button",
                                                    read: true,
                                                    write: true,
                                                });
                                        
                                                await createChannelP(`${ROOT}.targets`, "Targets");
                                                await cleanupStaleTargets(targets);
                                        
                                                for (const t of targets) {
                                                    const isHost = t.type === "host";
                                                    const prefix = `${ROOT}.targets.${targetKey(t)}`;
                                                    await createChannelP(prefix, `${t.name || t.id} (${t.type})`);
                                                    await flattenAndSet(prefix, t);
                                        
                                                    await createStateAsync(`${prefix}.updateNow`, false, {
                                                        name: isHost ? "Diesen Host aktualisieren" : "Dieses VM/CT aktualisieren",
                                                        type: "boolean",
                                                        role: "button",
                                                        read: true,
                                                        write: true,
                                                    });
                                                    await createStateAsync(`${prefix}.checkNow`, false, {
                                                        name: isHost ? "Diesen Host pruefen (kein Update)" : "Dieses VM/CT pruefen (kein Update)",
                                                        type: "boolean",
                                                        role: "button",
                                                        read: true,
                                                        write: true,
                                                    });
                                                }
                                        
                                                log(`[proxmoxUpdater] Status aktualisiert: ${targets.length} Targets`);
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Status-Abruf fehlgeschlagen: ${e.message}`, "error");
                                            } finally {
                                                await uuLogout(session);
                                            }
                                        }
                                        
                                        // ---- Einzel-Update-Button je Target ----
                                        on({ id: new RegExp("^0_userdata\\.0\\.proxmoxUpdater\\.targets\\.[^.]+\\.updateNow$"), change: "ne" }, async obj => {
                                            if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                                return;
                                            }
                                            setState(obj.id, false, true);
                                        
                                            const prefix = obj.id.replace(/\.updateNow$/, "");
                                            const typeState = await getStateAsync(`${prefix}.type`);
                                            const isHost = typeState && typeState.val === "host";
                                        
                                            let session;
                                            try {
                                                session = await uuLogin();
                                                if (await isAnyJobRunning(session)) {
                                                    log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Aktion nicht ausgelöst.", "warn");
                                                    return;
                                                }
                                                if (isHost) {
                                                    const nodeState = await getStateAsync(`${prefix}.node`);
                                                    const node = nodeState && nodeState.val;
                                                    const res = await uuPost(`/api/update-node/${encodeURIComponent(node)}`, session, {});
                                                    log(`[proxmoxUpdater] Host-Update gestartet (${node}): ${res.message || "OK"}`);
                                                } else {
                                                    const idState = await getStateAsync(`${prefix}.id`);
                                                    const id = idState && idState.val;
                                                    const res = await uuPost(`/api/update/${encodeURIComponent(id)}`, session, {});
                                                    log(`[proxmoxUpdater] Update gestartet (${id}): ${res.message || "OK"}`);
                                                }
                                                // sofort neu pruefen und danach automatisch in den schnellen 2s-Takt wechseln,
                                                // solange der Job laeuft - siehe kickJobStatusPoll()/pollJobStatusOnce()
                                                kickJobStatusPoll();
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Update fehlgeschlagen: ${e.message}`, "error");
                                            } finally {
                                                if (session) {
                                                    await uuLogout(session);
                                                }
                                            }
                                        });
                                        
                                        // ---- Sammel-Button: alle VMs/CTs (ohne Host) ----
                                        on({ id: `${ROOT}.updateAllVmsCtsNow`, change: "ne" }, async obj => {
                                            if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                                return;
                                            }
                                            setState(obj.id, false, true);
                                        
                                            let session;
                                            try {
                                                session = await uuLogin();
                                                if (await isAnyJobRunning(session)) {
                                                    log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Sammel-Update nicht ausgelöst.", "warn");
                                                    return;
                                                }
                                                const status = await uuGet("/api/status", session);
                                                const targets = (status.targets || []).filter(t => t.type !== "host");
                                                log(`[proxmoxUpdater] Starte Update fuer ${targets.length} VMs/CTs (Host ausgenommen)`);
                                                for (const t of targets) {
                                                    try {
                                                        await uuPost(`/api/update/${encodeURIComponent(t.id)}`, session, {});
                                                    } catch (e) {
                                                        log(`[proxmoxUpdater] Update fuer ${t.id} fehlgeschlagen: ${e.message}`, "warn");
                                                    }
                                                }
                                                // sofort neu pruefen und danach automatisch in den schnellen 2s-Takt wechseln,
                                                // solange der Job laeuft - siehe kickJobStatusPoll()/pollJobStatusOnce()
                                                kickJobStatusPoll();
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Sammel-Update fehlgeschlagen: ${e.message}`, "error");
                                            } finally {
                                                if (session) {
                                                    await uuLogout(session);
                                                }
                                            }
                                        });
                                        
                                        // ---- Einzel-Check-Button je Target (nur pruefen, kein Update) ----
                                        on({ id: new RegExp("^0_userdata\\.0\\.proxmoxUpdater\\.targets\\.[^.]+\\.checkNow$"), change: "ne" }, async obj => {
                                            if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                                return;
                                            }
                                            setState(obj.id, false, true);
                                        
                                            const prefix = obj.id.replace(/\.checkNow$/, "");
                                            const typeState = await getStateAsync(`${prefix}.type`);
                                            const isHost = typeState && typeState.val === "host";
                                        
                                            let session;
                                            try {
                                                session = await uuLogin();
                                                if (await isAnyJobRunning(session)) {
                                                    log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Check nicht ausgelöst.", "warn");
                                                    return;
                                                }
                                                if (isHost) {
                                                    const nodeState = await getStateAsync(`${prefix}.node`);
                                                    const node = nodeState && nodeState.val;
                                                    const res = await uuPost(`/api/check-node/${encodeURIComponent(node)}`, session, {});
                                                    log(`[proxmoxUpdater] Host-Check gestartet (${node}): ${res.message || "OK"}`);
                                                } else {
                                                    const idState = await getStateAsync(`${prefix}.id`);
                                                    const id = idState && idState.val;
                                                    const res = await uuPost(`/api/check/${encodeURIComponent(id)}`, session, {});
                                                    log(`[proxmoxUpdater] Check gestartet (${id}): ${res.message || "OK"}`);
                                                }
                                                kickJobStatusPoll();
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Check fehlgeschlagen: ${e.message}`, "error");
                                            } finally {
                                                if (session) {
                                                    await uuLogout(session);
                                                }
                                            }
                                        });
                                        
                                        // ---- Sammel-Button: alle pruefen, inkl. Host (read-only, daher unbedenklich) ----
                                        on({ id: `${ROOT}.checkAllNow`, change: "ne" }, async obj => {
                                            if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                                return;
                                            }
                                            setState(obj.id, false, true);
                                        
                                            let session;
                                            try {
                                                session = await uuLogin();
                                                if (await isAnyJobRunning(session)) {
                                                    log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Sammel-Check nicht ausgelöst.", "warn");
                                                    return;
                                                }
                                                const res = await uuPost("/api/check-all", session, {});
                                                log(`[proxmoxUpdater] Sammel-Check gestartet: ${res.message || "OK"}`);
                                                kickJobStatusPoll();
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Sammel-Check fehlgeschlagen: ${e.message}`, "error");
                                            } finally {
                                                if (session) {
                                                    await uuLogout(session);
                                                }
                                            }
                                        });
                                        
                                        // ---- Sammel-Button: nur Targets mit Security-Updates aktualisieren (ohne Host) ----
                                        on({ id: `${ROOT}.updateSecurityOnlyNow`, change: "ne" }, async obj => {
                                            if (!obj.state || obj.state.val !== true || obj.state.ack) {
                                                return;
                                            }
                                            setState(obj.id, false, true);
                                        
                                            let session;
                                            try {
                                                session = await uuLogin();
                                                if (await isAnyJobRunning(session)) {
                                                    log("[proxmoxUpdater] Läuft bereits ein Check/Update-Job - Security-Update nicht ausgelöst.", "warn");
                                                    return;
                                                }
                                                const status = await uuGet("/api/status", session);
                                                const targets = (status.targets || []).filter(t => t.type !== "host" && (t.security_updates || 0) > 0);
                                                log(`[proxmoxUpdater] Starte Security-Update fuer ${targets.length} VMs/CTs`);
                                                for (const t of targets) {
                                                    try {
                                                        await uuPost(`/api/update/${encodeURIComponent(t.id)}`, session, {});
                                                    } catch (e) {
                                                        log(`[proxmoxUpdater] Security-Update fuer ${t.id} fehlgeschlagen: ${e.message}`, "warn");
                                                    }
                                                }
                                                kickJobStatusPoll();
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Security-Update fehlgeschlagen: ${e.message}`, "error");
                                            } finally {
                                                if (session) {
                                                    await uuLogout(session);
                                                }
                                            }
                                        });
                                        
                                        function delay(ms) {
                                            return new Promise(resolve => setTimeout(resolve, ms));
                                        }
                                        
                                        // Gestaffelter Check aller Targets nacheinander (statt alle gleichzeitig wie
                                        // checkAllNow) - schont Host/Netzwerk, dauert dafuer entsprechend laenger
                                        // (28 Targets * STAGGERED_CHECK_DELAY_MINUTES ≈ 1,5h). Fuer den schnellen,
                                        // manuellen "jetzt sofort alle" mit kurzer hoher Last gibt es weiterhin den
                                        // checkAllNow-Datenpunkt/Button.
                                        async function staggeredCheckAll() {
                                            let targets;
                                            try {
                                                const session = await uuLogin();
                                                try {
                                                    const status = await uuGet("/api/status", session);
                                                    targets = status.targets || [];
                                                } finally {
                                                    await uuLogout(session);
                                                }
                                            } catch (e) {
                                                log(`[proxmoxUpdater] Gestaffelter Check: Target-Liste konnte nicht geholt werden: ${e.message}`, "error");
                                                return;
                                            }
                                        
                                            log(`[proxmoxUpdater] Gestaffelter Check gestartet (${targets.length} Targets, ${STAGGERED_CHECK_DELAY_MINUTES} min Abstand)`);
                                            for (let i = 0; i < targets.length; i++) {
                                                const t = targets[i];
                                                const label = t.name || t.id;
                                                let session;
                                                try {
                                                    session = await uuLogin();
                                                    if (await isAnyJobRunning(session)) {
                                                        log(`[proxmoxUpdater] Gestaffelter Check: ${label} übersprungen - es läuft bereits ein anderer Job.`, "warn");
                                                    } else if (t.type === "host") {
                                                        await uuPost(`/api/check-node/${encodeURIComponent(t.node)}`, session, {});
                                                        log(`[proxmoxUpdater] Gestaffelter Check ${i + 1}/${targets.length}: Host ${label} gestartet`);
                                                    } else {
                                                        await uuPost(`/api/check/${encodeURIComponent(t.id)}`, session, {});
                                                        log(`[proxmoxUpdater] Gestaffelter Check ${i + 1}/${targets.length}: ${label} gestartet`);
                                                    }
                                                } catch (e) {
                                                    log(`[proxmoxUpdater] Gestaffelter Check: ${label} fehlgeschlagen: ${e.message}`, "warn");
                                                } finally {
                                                    if (session) {
                                                        await uuLogout(session);
                                                    }
                                                }
                                                kickJobStatusPoll();
                                                if (i < targets.length - 1) {
                                                    await delay(STAGGERED_CHECK_DELAY_MS);
                                                }
                                            }
                                            log(`[proxmoxUpdater] Gestaffelter Check abgeschlossen (${targets.length} Targets)`);
                                        }
                                        
                                        refreshStatus().catch(e => log(`[proxmoxUpdater] Abbruch: ${e.message}`, "error"));
                                        
                                        // stuendlich der volle, schwere Refresh (alle Targets, Cleanup, ...)
                                        schedule(REFRESH_CRON, refreshStatus);
                                        
                                        // naechtlich der gestaffelte Check aller Targets (siehe staggeredCheckAll())
                                        schedule(STAGGERED_CHECK_CRON, () => {
                                            staggeredCheckAll().catch(e => log(`[proxmoxUpdater] Gestaffelter Check abgebrochen: ${e.message}`, "error"));
                                        });
                                        
                                        // leichter Job-Status-Check startet selbstjustierend (busy/idle-Takt s.o.) -
                                        // schedule() kann keine Sub-Minuten-Intervalle, daher die eigene setTimeout-Kette
                                        // in pollJobStatusOnce()/kickJobStatusPoll() weiter oben.
                                        pollTimer = setTimeout(() => {
                                            pollJobStatusOnce().catch(e => log(`[proxmoxUpdater] Job-Status-Poll fehlgeschlagen: ${e.message}`, "error"));
                                        }, POLL_INTERVAL_IDLE_MS);
                                        
                                        
                                        NegaleinN
                                        NegaleinN
                                        Negalein
                                        schrieb am zuletzt editiert von
                                        #100

                                        @David-G. sagte:

                                        Ich habe mit gestern mit Claude ein Script geschrieben, was mir alles in den iobroker holt.

                                        Hi David!

                                        Ist das Script in Kombination mit dem Proxmox-Updater, oder läuft es auch ohne installiertem Proxmox-Updater?

                                        Hast du dir dafür schon eine VIS gebastelt? ;)

                                        ° Node.js & System Update ---> sudo apt update, iob stop, sudo apt full-upgrade
                                        ° Node.js Fixer ---> iob nodejs-update
                                        ° Fixer ---> iob fix

                                        David G.D 1 Antwort Letzte Antwort
                                        0
                                        • NegaleinN Negalein

                                          @David-G. sagte:

                                          Ich habe mit gestern mit Claude ein Script geschrieben, was mir alles in den iobroker holt.

                                          Hi David!

                                          Ist das Script in Kombination mit dem Proxmox-Updater, oder läuft es auch ohne installiertem Proxmox-Updater?

                                          Hast du dir dafür schon eine VIS gebastelt? ;)

                                          David G.D
                                          David G.D
                                          David G.
                                          schrieb am zuletzt editiert von
                                          #101

                                          @Negalein

                                          Baut auf dem Update auf.
                                          Nutzt die Endpunkte der gui vom Updater.

                                          Nein, noch nicht.

                                          Zeigt eure Lovelace-Visualisierung klick
                                          (Auch ideal um sich Anregungen zu holen)

                                          Meine Tabellen für eure Visualisierung klick

                                          1 Antwort Letzte Antwort
                                          2

                                          Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.

                                          Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.

                                          Mit deinem Input könnte dieser Beitrag noch besser werden 💗

                                          Registrieren Anmelden
                                          Antworten
                                          • In einem neuen Thema antworten
                                          Anmelden zum Antworten
                                          • Älteste zuerst
                                          • Neuste zuerst
                                          • Meiste Stimmen


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          320

                                          Online

                                          33.1k

                                          Benutzer

                                          84.0k

                                          Themen

                                          1.4m

                                          Beiträge
                                          Community
                                          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                                          ioBroker Community 2014-2026
                                          logo
                                          • Anmelden

                                          • Du hast noch kein Konto? Registrieren

                                          • Anmelden oder registrieren, um zu suchen
                                          • Erster Beitrag
                                            Letzter Beitrag
                                          0
                                          • Home
                                          • Aktuell
                                          • Ungelesen 0
                                          • Kategorien
                                          • Unreplied
                                          • Beliebt
                                          • GitHub
                                          • Docu
                                          • Hilfe