Operate Shared VyOS Image Build Pipeline (HyOps)¶
Build one canonical VyOS record and publish the state contract consumed by both the Proxmox and Hetzner seed paths.
Module:
core/shared/vyos-image-build
Purpose¶
This is the default product path for VyOS image production.
Use it when you want HybridOps to:
- build or validate one canonical record
- publish it to object storage
- publish a reusable HyOps state contract for downstream seed modules
Use Operate Shared VyOS Image Artifact Contract (HyOps)
only when the record already exists and you only need to register it into state.
Related¶
Related reading¶
- Network routing contract
- Provision Hetzner VyOS Edge (HyOps Blueprint)
- Deploy Edge Control Plane (HyOps Blueprint)
- Operate Shared VyOS Image Registration Contract (HyOps)
Default product path¶
- Apply
core/shared/vyos-image-build. - Consume its
record_state_reffrom: core/onprem/vyos-template-seedcore/hetzner/vyos-image-seed- Let:
platform/onprem/vyos-edgeorg/hetzner/vyos-edge-foundationconsume the resulting template/image state.
This keeps the platform DRY:
- build once
- publish once
- seed many
Authoritative implementation note:
- the canonical VyOS cloud-init helper is
tools/build/vyos/assets/cc_vyos.py - packaged build and seed paths must consume that helper instead of carrying their own divergent copies
Recommended record shape¶
Recommended published outputs:
- Proxmox/default record: versioned public
qcow2 - Hetzner import record: versioned public
raw.xz
Why:
- Proxmox template seeding is cleanest from a
qcow2 - Hetzner image import is cleanest from a directly reachable
raw.xz
The qcow2 auto-wrap path for Hetzner still exists, but it is now a compatibility path only. Use it only when the execution host:
- has
qemu-img - is publicly reachable for temporary record serving
- is intentionally acting as the wrapper/import host
If you want predictable Hetzner imports, publish raw.xz explicitly.
Typical validation¶
hyops validate --env dev --skip-preflight \
--module core/shared/vyos-image-build \
--inputs modules/core/shared/vyos-image-build/examples/inputs.gcs-state.yml
Typical apply¶
hyops apply --env dev \
--module core/shared/vyos-image-build \
--inputs modules/core/shared/vyos-image-build/examples/inputs.gcs-state.yml
Verified steady-state example¶
Validated on Saturday, March 7, 2026:
- shared build state:
core/shared/vyos-image-build#vyos_default_build - record version:
2026.03.03-0027-rolling-r2 - shared qcow2 URL:
https://storage.googleapis.com/hyops-dev-vyos-records-a1/network/vyos/vyos-1.5-2026.03.03-0027-rolling-r2.qcow2- Hetzner import URL:
https://storage.googleapis.com/hyops-dev-vyos-records-a1/network/vyos/vyos-1.5-2026.03.03-0027-rolling.raw.xz
Verification commands:
jq '.status,.outputs' \
"$HOME/.hybridops/envs/dev/state/modules/core__shared__vyos-image-build/instances/vyos_default_build.json"
jq '.status,.outputs' \
"$HOME/.hybridops/envs/dev/state/modules/core__hetzner__vyos-image-seed/latest.json"
jq '.status,.outputs' \
"$HOME/.hybridops/envs/dev/state/modules/core__onprem__vyos-template-seed/latest.json"
Downstream consumption¶
Proxmox template seed:
record_state_ref: "core/shared/vyos-image-build#vyos_default_build"
record_key: "vyos-1.5"
Hetzner image seed:
- default: consume
record_state_refwhen it already resolves a suitable Hetzner import source - recommended override: set a direct public
image_source_urlto the publishedraw.xz
Important behavior:
record_state_refis authoritative for downstream seed inputs- stale rerun values such as
record_url,record_sha256,record_version,image_source_url, andseed_commandmust not override the upstream record contract image_state_refis authoritative fororg/hetzner/vyos-edge-foundation
Builder posture¶
- preferred ISO build method remains
vyos-vm-images - packaged Packer fallback remains available for controlled/debug use
- KVM-backed builders are the supported path for ISO/Packer builds
tcgis debug-only and must not be treated as the production build path
Fresh-user prerequisites¶
- Provision one object repository, for example:
org/gcp/object-repo#vyos_records- Supply upload credentials outside Terraform state, for example:
HYOPS_VYOS_GCS_SA_JSONHYOPS_VYOS_GCS_SA_JSON_FILE- Apply the build module once.
- Consume the published state contract from the Proxmox and Hetzner seed modules.
Cleanup after failed build attempts¶
After the good image is verified, clean up obsolete records deliberately.
Safe cleanup targets:
- superseded Hetzner snapshots that are no longer referenced by current state
- temporary local staging such as
/tmp/hyops-hetzner-seed - failed builder scratch disks or wrapper outputs
- stale Proxmox smoke records from failed pre-fix runs:
smoke-*test VMs/var/lib/vz/snippets/hyops-vyos-smoke-*/var/tmp/hyops-vyos-smoke-mnt-*
Before deleting anything, confirm the active state points at the current image/template:
jq '.outputs.image_ref,.outputs.image_description' \
"$HOME/.hybridops/envs/dev/state/modules/core__hetzner__vyos-image-seed/latest.json"
jq '.outputs.template_vm_id,.outputs.template_name' \
"$HOME/.hybridops/envs/dev/state/modules/core__onprem__vyos-template-seed/latest.json"
Notes¶
- prefer a pinned, mirrored record URL over upstream
latest - do not publish mutable URLs into the shared contract
gs://...is not directly usable by Hetzner rescue; publish/consume the equivalent publichttps://storage.googleapis.com/...URL- keep the shared build module as the default story; treat manual record registration as the exception