Commit Graph

7 Commits

Author SHA1 Message Date
5865198240 Wire up arm64 without claiming it works
Proxmox VE 9.2 made arm64 official — same code base, repositories and release
lifecycle as x86-64 — and the pve-no-subscription repository carries proxmox-ve,
pve-manager, proxmox-default-kernel and pve-qemu-kvm for it. The build was still
hard-wired to amd64 in four places, which is now fixed:

  * firmware is chosen from the target architecture (AAVMF for arm64, OVMF for
    amd64) and padded to 64 MiB as QEMU's arm64 virt machine requires. Upstream
    packer-maas keys this on the host architecture, which only works when host
    and target match.
  * host_is_arm is derived from uname rather than hard-coded false, so KVM is
    used exactly when host and target architectures agree
  * the release body builds its MAAS upload command from MAAS_ARCH, PVE_VERSION
    and IMAGE_NAME instead of repeating amd64
  * install-deps.sh installs qemu-system-arm and AAVMF under WITH_ARM64=1,
    off by default since they are useless on an amd64-only builder

verify-image.sh asserted no kernel matching *-amd64, which would have passed
silently on an arm64 image carrying a Debian arm64 kernel. It now rejects any
/boot/vmlinuz-* not ending in -pve, which holds for both architectures. Checking
that with synthetic file lists caught a first attempt that returned "pass" for an
image containing both a PVE and a Debian kernel, so the expression is now a single
pipeline verified against GNU grep on the build host — the macOS grep this was
first tried on disagrees, and only the Linux behaviour matters here.

No arm64 image has been built and none deployed. The README gains an arm64
section saying so plainly, listing the two real obstacles — TCG emulation on an
x86_64 builder, and having no arm64 hardware to deploy to — and the entry stays
under "Not verified".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 23:16:21 +02:00
4719d30359 Rebuild on kernel changes and on age, not just on pve-manager
The build condition only compared pve-manager, which left two gaps. Kernel
security fixes ship in proxmox-default-kernel and do not bump pve-manager, so the
updates that matter most would not have triggered a rebuild. Debian base security
updates bump neither, so an image could have sat unchanged indefinitely while its
openssl and glibc went stale.

scripts/ci/decide-build.sh now rebuilds when pve-manager changes, when
proxmox-default-kernel changes, or when the newest release passes MAX_AGE_DAYS
(30). It compares against image-info.txt from the last release rather than
inferring from tag names, so the comparison reflects what is actually inside the
published image, and it can be run by hand to see the decision without triggering
anything.

The daily schedule stays. Measured from the trixie repository, Proxmox publishes
about weekly — 56 pve-manager and 28 proxmox-kernel versions since 9.0 — so daily
checking costs about 30 seconds on the days nothing changed and cuts worst-case
staleness from a week to a day. Tags carry the date now (pve-<version>-<date>)
because an age-triggered rebuild can repeat a version.

The README gains a "Prebuilt images" section linking the releases page, with the
checksum and MAAS upload commands, and a "Release automation" section explaining
the trigger table and stating plainly that the host-mode runner gives root on the
build machine to anything that can dispatch a workflow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 22:59:10 +02:00
8b2e1275af Do not delete the workspace from inside it
The checkout step ran rm -rf on $GITHUB_WORKSPACE while the shell's working
directory was that same path. git then failed with 'Unable to read current
working directory', and every later step died with 'fork/exec /usr/bin/bash: no
such file or directory' for the same reason.

Both the checkout and the cleanup step now cd to / first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pve-9.2.11
2026-09-04 22:36:47 +02:00
e964933af1 Add a Gitea Actions pipeline that publishes the image as a release
Builds the image on a self-hosted runner and publishes it, with the checksum and
a corresponding-source offer, as a Gitea release.

The schedule is daily but the build is conditional. Proxmox does not ship daily,
so an unconditional daily build would produce roughly 45 GB a month of
near-identical artifacts; instead the job compares the newest pve-manager in the
configured repository against the last published release and stops early when
they match. A manual trigger with `force` rebuilds anyway. Releases are tagged
after the version they contain (`pve-9.2.11`) rather than the date, so the tag
says something useful, and older ones are pruned to keep three.

The logic lives in scripts/ci/ rather than inline in the workflow. Shell inside a
YAML block scalar cannot carry an indented heredoc terminator, and the release
body needs several; scripts also mean the pieces can be run and tested by hand.
A `print-var` target exposes single Makefile variables to them.

Two constraints shaped this:

  * The runner is registered in host mode, so steps run directly on the build
    machine as root. The build needs /dev/kvm, qemu-nbd, FUSE and root, which a
    container would have to be given anyway. The consequence — anything able to
    dispatch a workflow gets root on that machine — is stated in the workflow
    header rather than left implicit.
  * Checkout is a plain git clone. actions/checkout is a JavaScript action and
    the host-mode runner has no Node.js runtime.

The artifact is named maas-image-pve-<version>-amd64.tar.gz, not
proxmox-ve-*.tar.gz, and the release body says the build is unofficial and
unaffiliated. Proxmox permits redistribution under the AGPLv3 but asks that the
trademark not be used in product names.

SOURCES.md is generated per release: the image is an unmodified installation of
Debian and Proxmox packages, so it points at those archives for the
corresponding source, and records that the firmware licence texts ship inside the
image at /usr/share/doc/pve-firmware/licenses/ and must not be stripped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 22:35:30 +02:00
77bf86a1b8 Separate what was actually verified from what was only written
The previous "Verified status" section listed the test environment and a
one-line result, which let readers assume far more coverage than the testing
justified. Options that had never run once were presented alongside ones that
were exercised repeatedly.

Every configuration option in the reference tables that was not exercised is now
marked "Untested" inline — 25 of them, including every PVE_NET_* value other than
the tested defaults, PVE_CLUSTER_LINK0/LINK1, fingerprint discovery, the join
retry path, and every PVE_THINPOOL_* value beyond auto with the defaults.

"Verified status" is now two lists. The first gives, per area, the observation
that supports the claim rather than the claim alone: which command was run, what
it printed, which file was found where. The second is everything that was never
exercised, with no implication that it is broken.

Three claims elsewhere were overstated and are corrected:

  * the ~700 MB saving from a local APT cache is an estimate from package sizes;
    that path has never been run
  * MAAS 3.2+ is the documented minimum, but only 3.7.2 with snap packaging was
    tested; the deb packaging's preseed path is untested
  * the build timings are measured, but the contribution of each individual
    optimisation is not

Both cases in "Moving to a new Proxmox release" are also marked: the minor-version
path is verified only as a mechanism (no package versions are pinned), never as an
actual version step, and the claim about upstream breaking on an unknown Debian
release is read from upstream's source rather than observed.

Verified while writing this: the iSCSI initiator names really do differ between
the two nodes, PVE_CLUSTER_WIPE_SECRETS really does scrub both password fields
after a join, and "make preseed" and "make install-preseed" work as targets on the
MAAS region controller rather than only as the commands they wrap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 22:03:19 +02:00
40b5d50ec9 License under AGPL-3.0-or-later and publish documentation via GitHub Pages
Parts of this repository are derived from canonical/packer-maas, which Canonical
distributes under the AGPLv3, so its copyleft carries over and a permissive or
plain-GPL licence is not available:

  * maas/curtin_userdata_custom.in is adapted from upstream's
    debian/curtin_userdata_custom_amd64, with several late_commands copied
    verbatim (the PXE-disable call, the target bind mount, the cloud.cfg rewrite
    and the zz-update-grub fix)
  * overlay/curtin/curtin-hooks follows upstream's debian/scripts/curtin-hooks:
    same imports, same load_command_environment -> load_command_config ->
    builtin_curthooks -> cleanup structure, near-identical cleanup(). The
    kernel-disabling and interface-pinning functions are original.

The upstream template itself is not vendored; it is cloned at build time and
pinned by PM_REF.

Adds the full AGPL-3.0 text as LICENSE and SPDX-License-Identifier headers to
every source file, placed after the shebang or the #cloud-config marker so both
keep working. deploy-cluster.sh's --help filters the new header lines out of the
usage text it extracts from its own comment block.

GitHub Pages serves index.md, which includes README.md, so the site cannot drift
from the repository documentation. Nothing but build/ is excluded, which keeps
the README's relative links to LICENSE, scripts/ and maas/examples/ resolving on
the published site.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 21:57:03 +02:00
3d4841f31c Initial commit: MAAS-deployable Proxmox VE images with cluster automation
Builds a Proxmox VE image that MAAS can deploy to bare metal, plus first-boot
automation that configures the node and joins it to a Proxmox cluster with no
manual steps.

The image starts from the official Debian cloud image and installs proxmox-ve
on top of it, rather than capturing a raw disk from the Proxmox ISO. That keeps
MAAS in control of partitioning, networking, SSH keys and cloud-init, and makes
moving between Proxmox releases a variable change instead of a rewrite.

Contents:

  * Makefile driving the whole flow: build, verify, preseed, upload
  * customize-proxmox.sh, run inside the Packer build VM, which layers Proxmox
    onto the Debian cloud image and resets the pmxcfs node identity so one image
    can produce many nodes
  * pve-maas-init, a first-boot state machine covering /etc/hosts, node-unique
    identifiers, the root password, vmbr0 conversion, cluster create/join and
    the local-lvm thin pool; each stage is resumable across reboots
  * curtin-hooks, which stops curtin installing a kernel over APT and pins
    interface names by MAC so they match what MAAS recorded at commissioning
  * a MAAS curtin preseed template and cloud-init examples
  * deploy-cluster.sh, which builds a whole cluster through the MAAS API
  * verify-image.sh, 22 static checks on the produced tarball

Cluster identity lives entirely in deploy-time cloud-init user-data, so a single
image and preseed can build any number of independent clusters.

Verified end to end against MAAS 3.7.2: proxmox-ve 9.2.0 / pve-manager 9.2.11 /
kernel 7.0.14-15-pve, deployed to two machines that formed a quorate cluster with
local-lvm on both, with no manual intervention.

The README documents four failure modes found along the way that all fail
silently: curtin rejecting "kernel: null", pvenetcommit overwriting the network
configuration at boot, interface renaming leaving the link down, and a systemd
ordering cycle that made systemd delete the service's start job.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 21:50:17 +02:00