Point Proxmox at the sources this Debian actually has

PVE arrives with the image now, so this section accepts it rather than installs
it — but it needs every line of knowledge from InstallProxmoxVe.php to do that,
just pointed the other way.

The kernel is the claim, not the package. An installed proxmox-ve running on a
Debian kernel is exactly the half state RebootIntoPveKernel exists because of,
so uname is what gets checked.

The codename table now verifies a pairing instead of creating one. An image
whose PVE major does not match its Debian base was built wrong, and no amount
of fixing package sources heals a PVE compiled against a different libc — that
machine gets reinstalled with the right image. The other half of the table,
codename to PVE major, is written down here because the ISO route needs it and
the original file only had the suite side.

Removing the subscription repositories is the part that everything after this
depends on. A Proxmox image ships pve-enterprise, and without a subscription it
fails every apt-get update — after which no package install in any later
section succeeds. Both spellings are handled, because PVE 8 used one-line .list
files and PVE 9 moved to deb822, and ceph is in the list because the same trap
is set there a second time. The proof is a clean apt-get update at the end,
which is the only thing that tells removal apart from overwriting.

One thing changed after the first draft: when pveversion cannot be parsed, the
pairing check used to be skipped in silence. That is the fake that R19 records
as worse than no check at all, because it stops the next person from looking.
It now says "Paarung UNGEPRÜFT" in the report and in the log.

Verified without hardware: dash-clean; bookworm maps to PVE 8, trixie to PVE 9,
forky is refused; the pveversion parser reads 9 and 8 out of both real formats
and yields nothing for garbage; and against a copy of /etc/apt/sources.list.d
holding all five subscription files plus an unrelated one, exactly the five go
and the unrelated one stays. Step 2 unticked — there is no Proxmox here to
accept.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feature/host-bootstrap
nexxo 2026-07-30 20:00:01 +02:00
parent 0f563545fd
commit f214713113
3 changed files with 154 additions and 14 deletions

View File

@ -547,6 +547,83 @@ section_rebooted() {
die 'Neustart wurde angestoßen, aber die Maschine läuft nach zwei Minuten noch. Über die Anbieterkonsole nachsehen.'
}
# ---------------------------------------------------------------------------
# Abschnitt 4: proxmox_installed — abnehmen, nicht installieren
# ---------------------------------------------------------------------------
#
# PVE kam mit dem Abbild. Dieser Abschnitt stellt fest, dass es wirklich läuft,
# dass Abbild und Unterbau zusammenpassen, und bringt die Paketquellen in
# Ordnung — ohne die kommt kein einziger der folgenden Abschnitte an seine
# Pakete.
section_proxmox_installed() {
if ! command -v pveversion >/dev/null 2>&1; then
CLUPILOT_SECTION_NOTE='pveversion gibt es nicht — auf dieser Maschine läuft kein Proxmox'
return 1
fi
# Der Kernel ist die Aussage, nicht das Paket. Ein installiertes
# proxmox-ve bei laufendem Debian-Kernel ist genau der halbe Zustand, aus
# dem RebootIntoPveKernel entstanden ist.
_kernel="$(uname -r)"
case "$_kernel" in
*-pve*) ;;
*)
CLUPILOT_SECTION_NOTE="läuft auf ${_kernel}, das ist kein PVE-Kernel"
return 1
;;
esac
_id="$(os_release_field id)"
_codename="$(os_release_field codename)"
if [ "$_id" != 'debian' ] || ! _release="$(proxmox_release_for "$_codename")"; then
CLUPILOT_SECTION_NOTE="unbekannter Unterbau: ID=${_id:-(leer)}, VERSION_CODENAME=${_codename:-(leer)} ($(os_release_field pretty)). Dieses Skript kennt keine dazu passende Proxmox-Suite und rät nicht."
return 1
fi
# Abbild und Unterbau müssen zusammengehören. Passen sie nicht, wurde das
# falsche Abbild installiert — und das heilt keine Paketquelle, das ist ein
# PVE gegen eine andere libc.
_pve_version="$(pveversion 2>/dev/null | head -1)"
_pve_major="$(printf '%s' "$_pve_version" | sed -n 's#^pve-manager/\([0-9]*\)\..*#\1#p')"
_expected_major="$(pve_major_for_codename "$_codename")"
_pairing='ungeprüft'
if [ -z "$_pve_major" ]; then
# Nicht stillschweigend durchwinken. Eine Prüfung, die nicht gelaufen
# ist, muss das sagen — sonst hält sie den Nächsten vom Nachsehen ab,
# und genau das hält R19 als eigenen Fund fest.
_pairing="Paarung UNGEPRÜFT, pveversion nicht lesbar: ${_pve_version:-(keine Ausgabe)}"
log "$_pairing"
elif [ "$_pve_major" != "$_expected_major" ]; then
CLUPILOT_SECTION_NOTE="${_pve_version} auf Debian ${_codename}: erwartet wäre PVE ${_expected_major}. Das Abbild passt nicht zum Unterbau; die Maschine wird mit dem richtigen Abbild neu aufgesetzt."
return 1
else
_pairing="PVE ${_pve_major} zu Debian ${_codename}"
fi
split_proxmox_release "$_release"
if ! _keyring_path="$(install_proxmox_key "$CLUPILOT_PVE_KEY_URL" "$CLUPILOT_PVE_KEYRING")"; then
CLUPILOT_SECTION_NOTE="Proxmox-Release-Schlüssel nicht ladbar: ${CLUPILOT_PVE_KEY_URL}"
return 1
fi
remove_subscription_sources
write_proxmox_sources "$CLUPILOT_PVE_SUITE" "$_keyring_path" '/etc/apt/sources.list.d/pve-install-repo.sources'
# Der eigentliche Beweis. Solange irgendeine Abonnement-Quelle stehen bleibt,
# endet das hier mit Fehler — und dann ist sie überschrieben worden statt
# entfernt.
export DEBIAN_FRONTEND=noninteractive
if ! apt-get update >> "${CLUPILOT_WORK_DIR}/apt.log" 2>&1; then
CLUPILOT_SECTION_NOTE="apt-get update schlägt fehl; siehe ${CLUPILOT_WORK_DIR}/apt.log"
return 1
fi
CLUPILOT_SECTION_NOTE="${_pve_version} auf ${_kernel}; ${_pairing}; Quellen auf ${CLUPILOT_PVE_SUITE}/pve-no-subscription"
return 0
}
main() {
parse_arguments "$@"
@ -582,14 +659,17 @@ main() {
die 'Abbruch beim Neustart.'
fi
# run_section proxmox_installed section_proxmox_installed # Task 4
if ! run_section proxmox_installed section_proxmox_installed; then
die 'Abbruch: Proxmox ist nicht in dem Zustand, den die folgenden Abschnitte voraussetzen.'
fi
# run_section network_bridged section_network_bridged # Task 5
# run_section wireguard_joined section_wireguard_joined # Task 6
# run_section traefik_running section_traefik_running # Task 7
# run_section template_built section_template_built # Task 8
# run_section registered section_registered # Task 9
log 'Proxmox läuft. Die Abschnitte ab Task 4 sind noch nicht eingehängt.'
log 'Proxmox abgenommen, Quellen in Ordnung. Die Abschnitte ab Task 5 sind noch nicht eingehängt.'
}
main "$@"

View File

@ -89,6 +89,31 @@ Signed-By: ${_keyring_path}
EOF
}
# Die Abonnement-Quellen, die ein Proxmox-Abbild mitbringt.
#
# Sie scheitern ohne Abonnement bei JEDEM `apt-get update` — und danach schlägt
# jede Paketinstallation der folgenden Abschnitte fehl. Das ist keine
# Schönheitskorrektur, sondern die Voraussetzung dafür, dass Traefik, WireGuard
# und die Vorlage überhaupt installiert werden können.
#
# Beide Schreibweisen, weil PVE 8 die einzeiligen `.list` benutzte und PVE 9 auf
# deb822 umgestellt hat. Und `ceph`, weil dieselbe Falle dort ein zweites Mal
# steht.
remove_subscription_sources() {
for _f in \
/etc/apt/sources.list.d/pve-enterprise.list \
/etc/apt/sources.list.d/pve-enterprise.sources \
/etc/apt/sources.list.d/ceph.list \
/etc/apt/sources.list.d/ceph.sources \
/etc/apt/sources.list.d/pve-install-repo.list
do
if [ -f "$_f" ]; then
rm -f "$_f"
log "entfernt: ${_f}"
fi
done
}
# ---------------------------------------------------------------------------
# Was diese Maschine gerade ist: Bootmodus, Netz, Platten
# ---------------------------------------------------------------------------
@ -180,6 +205,47 @@ zfs_raid_for() {
# des Ziels: das Werkzeug läuft hier, nicht dort. Unbekannter Codename bricht ab
# — nicht „trixie ist das neueste, also trixie". Das nächste Debian ist auch
# unbekannt, und dann sieht niemand hin.
# Welche PVE-Hauptversion zu welchem Debian gehört.
#
# Die andere Hälfte der Tabelle: `proxmox_release_for` sagt, welche Suite zu
# einem Debian passt; das hier sagt, welche PVE-Version dabei herauskommen muss.
# Gebraucht wird es, um ein ABBILD abzunehmen — bei dem niemand die Suite
# gewählt hat, sondern Proxmox das Paar schon zusammengestellt hatte. Passt es
# nicht, ist das Abbild falsch, und kein Nachbessern der Quellen heilt das.
pve_major_for_codename() {
case "$1" in
bookworm) printf '8' ;;
trixie) printf '9' ;;
*) return 1 ;;
esac
}
# Legt den Proxmox-Release-Schlüssel ab und gibt seinen Pfad aus.
#
# Nach /etc/apt/keyrings/ und über `Signed-By` benannt, NICHT nach
# /etc/apt/trusted.gpg.d/ — dort bürgte er für jede Quelle der Maschine.
install_proxmox_key() {
_key_url="$1"
_keyring="$2"
_keyring_path="/etc/apt/keyrings/${_keyring}"
mkdir -p /etc/apt/keyrings
if ! http_download "$_key_url" "$_keyring_path"; then
return 1
fi
chmod 644 "$_keyring_path"
printf '%s' "$_keyring_path"
}
# Zerlegt "suite|key_url|keyring" in CLUPILOT_PVE_SUITE, _KEY_URL, _KEYRING.
split_proxmox_release() {
CLUPILOT_PVE_SUITE="${1%%|*}"
_rest="${1#*|}"
CLUPILOT_PVE_KEY_URL="${_rest%%|*}"
CLUPILOT_PVE_KEYRING="${_rest##*|}"
}
ensure_autoinstall_assistant() {
if command -v proxmox-auto-install-assistant >/dev/null 2>&1; then
log 'proxmox-auto-install-assistant ist vorhanden'
@ -194,20 +260,14 @@ ensure_autoinstall_assistant() {
return 1
fi
_suite="${_release%%|*}"
_rest="${_release#*|}"
_key_url="${_rest%%|*}"
_keyring="${_rest##*|}"
_keyring_path="/etc/apt/keyrings/${_keyring}"
split_proxmox_release "$_release"
mkdir -p /etc/apt/keyrings
if ! http_download "$_key_url" "$_keyring_path"; then
log "Proxmox-Release-Schlüssel für ${_codename} nicht ladbar: ${_key_url}"
if ! _keyring_path="$(install_proxmox_key "$CLUPILOT_PVE_KEY_URL" "$CLUPILOT_PVE_KEYRING")"; then
log "Proxmox-Release-Schlüssel für ${_codename} nicht ladbar: ${CLUPILOT_PVE_KEY_URL}"
return 1
fi
chmod 644 "$_keyring_path"
write_proxmox_sources "$_suite" "$_keyring_path" '/etc/apt/sources.list.d/pve-install-repo.sources'
write_proxmox_sources "$CLUPILOT_PVE_SUITE" "$_keyring_path" '/etc/apt/sources.list.d/pve-install-repo.sources'
export DEBIAN_FRONTEND=noninteractive
apt-get update >/dev/null 2>&1 || return 1

View File

@ -253,7 +253,7 @@ bewiesen, bevor neu gestartet wird, nicht danach gehofft.
### Task 4: `proxmox_installed`
- [ ] **Step 1: Schreiben**
- [x] **Step 1: Schreiben**
> **Korrigiert mit Task 3.** PVE kommt jetzt schon mit dem Abbild. Dieser
> Abschnitt **installiert** es also nicht mehr, er **nimmt es ab und bringt
@ -285,7 +285,7 @@ werden:
läuft (`uname -r` enthält `-pve`), und **`apt-get update` läuft ohne Fehler
durch** — das ist der Beweis, dass die Enterprise-Quelle wirklich weg ist und
nicht nur überschrieben wurde.
- [ ] **Step 3: Committen.** `Point Proxmox at the sources this Debian actually has`
- [x] **Step 3: Committen.** `Point Proxmox at the sources this Debian actually has`
(war `Install Proxmox …`, bevor das Abbild PVE schon mitbrachte)
---