Feat/arch aarch64#354
Open
lausser wants to merge 12 commits into
Open
Conversation
…ons API Pulls Telmate/proxmox-api-go forward from the Oct 2024 pin (b149708f) to the merged tip at f4e48ca. The upstream library has restructured most client methods to take context.Context, typed VM identifiers (GuestID/GuestName), reshaped QemuNetworkInterfaces/QemuPciDevices, and moved EFI/RNG/Tags handling to pointer-wrapped struct types. Every call site and adjacent test mock is adjusted accordingly; behavior is preserved. One observable difference: the post-create SetVmConfig fix-up that re-asserted EFIDisk on proxmox-clone builds is gone. The new Create path handles the EFI disk reliably, and the explicit retry is redundant. api-go's own go.mod declares go 1.26.2; `go mod tidy` cascades that floor into this module. Plugin CI will need to lift its Go matrix accordingly.
…lues Adds a new `arch` HCL field on the proxmox-iso and proxmox-clone builders that selects the QEMU CPU architecture for the created VM template. Accepted values: `""` (host default), `"x86_64"`, `"aarch64"`. Invalid values are rejected at validate time before any API call is made. This commit lands the field, the validation whitelist, and propagation into the api-go CreateOptions on the initial POST. Companion validation (bios/efi_config/vga/serials requirements when arch=aarch64) and arch-aware defaults follow in the next two commits.
When arch=aarch64 is set, five companion settings must be configured
correctly for the build to reach a working PVE template. Each rule fires
at validate time, before any API call, naming the offending field by its
HCL name:
- FR-004: arch=aarch64 + bios=seabios → error. aarch64 requires UEFI.
- FR-009: arch=aarch64 + empty efi_config → error.
- FR-010: arch=aarch64 + non-serial vga.type → error. QMP send-key for
boot_command keystrokes only reaches the guest through a serial console.
- FR-011: arch=aarch64 + serial vga.type + empty serials → error.
- FR-012: arch=aarch64 + boot_iso.type="ide" → error. The QEMU virt
machine type has no IDE bus.
Rules 2–5 live in builder/proxmox/common/config.go and run immediately
after the EFI normalization block (FR-009 reads the post-normalize
EFIStoragePool, so the position is load-bearing). Rule 6 lives in
builder/proxmox/iso/config.go because BootISO is on iso.Config.
Verbatim error strings are stable surface — see
specs/002-aarch64-proxmox-iso/contracts/feature-surface.md.
When arch=aarch64 and the corresponding companion field is unset, the
plugin substitutes an aarch64-appropriate default. Explicit user values
are always honored.
- FR-006: boot_iso.type defaults to "scsi" (not "ide" — the QEMU virt
machine type has no IDE bus). Index is intentionally left unset; SCSI
auto-assignment finds a free slot at runtime.
- FR-006: additional_iso_files[*].type defaults to "scsi" for the same
reason.
- FR-015: cpu_type defaults to "cortex-a57". PVE rejects "kvm64" (the
plugin's x86 default) on the virt machine type with "CPU model 'kvm64'
does not exist for configured vCPU architecture 'aarch64'".
- FR-013: qemu_additional_args auto-injects "-device qemu-xhci -device
usb-kbd" so boot_command keystrokes reach the guest. The virt machine
type ships without a keyboard; QMP send-key is a silent no-op without
one. Detection is strict empty-string equality — supplying any value
fully disables the auto-inject. Device order is load-bearing.
Adds a Building aarch64 (ARM64) templates section to docs/builders/iso.mdx that documents the prerequisites, the four hard companion fields the plugin enforces when arch=aarch64, the arch-aware defaults it substitutes, the qemu_additional_args opt-out gotcha, and a worked HCL2 example that produces a Debian 13 ARM64 template on PVE 9.
Contributor
Author
Pinning Telmate/proxmox-api-go@f4e48ca in a5e4e73 cascades go 1.26.2 into our go.mod via go mod tidy (api-go's own go.mod floor). The CI matrix reads .go-version for golangci-lint and the generate check; the old 1.21.13 value causes a type-export format mismatch that breaks both jobs. Bump to match.
Rerun make generate after adding the "Building aarch64 (ARM64) templates" section to docs/builders/iso.mdx. Picks up the new arch field docs in the compiled .web-docs/ tree.
golangci-lint v1.60.1 (the previous pinned version) bundles a Go typechecker that cannot read export data produced by Go 1.26, causing all typecheck-dependent linters to fail with "unsupported version: 2". v2.x is the first release line with full Go 1.26 support; v1.x is no longer maintained. - go-validate.yml: bump golangci-lint-action v5 → v9.2.0, lint version v1.60.1 → v2.12.2 - .golangci.yml: migrate to v2 config format (version: "2", linters.default: none replaces disable-all, output.formats as array, remove linters.fast and run.skip-dirs-use-default which v2 dropped)
The previous v2 migration kept output sub-settings and linters-settings that are not valid top-level keys in v2, causing exit code 3 (config parse failure). Strip to the essential sections: linters, issues, run.
9b90186 to
68c1536
Compare
In v2 the exclusion settings moved out of the top-level issues section: issues.exclude-rules → linters.exclusions.rules issues.exclude-files → linters.exclusions.paths The old keys cause a jsonschema validation error and prevent the linter from starting at all.
…oimports is a formatter In v2, gosimple was merged into staticcheck and goimports was reclassified as a formatter. Update the config accordingly: - remove gosimple from linters.enable (now covered by staticcheck) - move goimports to formatters.enable with its own exclusions block - update the gosimple S-code exclusion rule to use staticcheck
Four corrections to the iso.mdx aarch64 worked example: - boot_command: replace ISOLINUX boot: prompt sequence with the verified GRUB EFI edit-mode sequence (e, arrow navigation, F10). Debian arm64 netinst uses GRUB EFI, not ISOLINUX; the previous sequence was silently swallowed by the GRUB menu and the build would hang until ssh_timeout. Verified empirically against Debian 13.4.0 arm64 netinst on PVE 9.1.11. - boot_wait: 5s → 10s to give GRUB EFI time to render before keystrokes land. - pre_enrolled_keys: true → false; Secure Boot key enrollment breaks unsigned or self-signed bootloaders in template builds. - boot_iso: remove redundant iso_storage_pool (only meaningful with iso_url). Regenerate .web-docs/ to match.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
Add first-class aarch64 / ARM64 template support to the
proxmox-isoandproxmox-clonebuilders via a newarchHCL field. Witharch = "aarch64"and four companion fields, the plugin produces a working ARM64 template on Proxmox VE 9.1.9+ end-to-end.There are no manual post-create fix-ups, no
qemu_additional_argsescape hatches, noadditional_configmap.Inspiration came from this blog post: https://kwellkorn.de/2025/03/25/virtualisierung-von-arm-architektur-unter-proxmox/
What the
archfield does:archis a create-only PVE setting; a post-create PUT silently fails and leaves the VM unbootable, so it must be in the initial VM-create payload.The field accepts
""(host default),"x86_64", and"aarch64". The first two values are no-ops on existing builds.Validation added for
arch = "aarch64":bios = "ovmf"(AAVMF firmware; SeaBIOS is x86-only)efi_configblock (UEFI boot disk)vga.typeto be one ofserial0–serial3(no VGA output on virt machine)serialswhen a serial VGA type is setArch-aware defaults (only when field is unset):
boot_iso.type→"scsi"(aarch64 virt machine has no IDE controller)additional_iso_files[*].type→"scsi"(same reason)cpu_type→"cortex-a57"(PVE rejects x86 cpu models for aarch64)machine→"virt"(the correct QEMU machine type for ARM64)arch = "x86_64"andarch = ""produce identical behavior to before this PR; this change is strictly additive.Infrastructure commit (
a5e4e73):pinning
github.com/Telmate/proxmox-api-go@f4e48ca(Telmate/proxmox-api-go#555, merged 2026-05-13) required absorbing 18 months of api-go API drift (context.Contextplumbing, typedGuestID/GuestName,QemuNetworkInterfaces/QemuPciDevicesrestructure, pointer-wrapped EFI/RNG/Tags).This commit is behavior-preserving for existing builds.
Two forced side-effects of the api-go bump reviewers should know about:
go.mod).step_start_vm.gois removed. The new api-goCreatepath handles it correctly, making the retry redundant.Empirical validation (bum-proxmox1 / PVE 9.1.11, 2026-05-15):
cpu_type = cortex-a57): (14m 28s on AMD Ryzen 9 Pro 8945HS); guestlscpuconfirms Cortex-A57cpu_type = cortex-a72): (14m 24s; PVE hardware tab and guestlacpuconfirm correct CPU)Resolved Issues
No open issue to close.
Rollback Plan
If a change needs to be reverted, we will roll out an update to the code within 7 days.
Changes to Security Controls
No changes to security controls. The new
archfield affects only VM hardware configuration at create time; it does not touch access controls, encryption, or logging.