Skip to content

metalman: declarative bond and VLAN host networking for VirtualMedia installs - #1109

Open
Jordan Olshevski (jveski) wants to merge 31 commits into
mainfrom
metalman-bond-vlan
Open

Jordan Olshevski (jveski) wants to merge 31 commits into
mainfrom
metalman-bond-vlan

Conversation

@jveski

Copy link
Copy Markdown
Contributor

Adds an optional network block to Machine netboot specs so Metalman can provision hosts whose only uplink is an LACP bond, with tagged VLANs, static routes, and DNS. When it is set, VirtualMedia boots a local installer from the ISO instead of fetching GRUB config over a single NIC. The installer brings up the bond and VLANs, then fetches its install instructions from a new /bootmedia//install endpoint, which uses the same operation and source-IP checks as the existing media callbacks. The same config is written to the installed host as netplan or systemd-networkd files. Machines without network keep the existing single-NIC flow.

The bond-member and VLAN-link rules on HostNetworkSpec exceeded the API
server CEL cost budget in the MachineOperation CRD, where PXESpec is
embedded in the unbounded status.targets list, so the CRD was rejected.
Declare them on MachineSpec (spec.pxe) and HostSpec (spec.host.netboot)
instead, and bound interface names with maxLength 15.
Evaluate the Machine and MachineOperation CRDs with the apiextensions
schema validator, CEL validator, and structural defaulting, covering the
reference bond/VLAN topology and each rejection rule.
…etplan

When the frozen netboot spec declares a host network, build an ISO that
carries the installer and media.cpio and boots it locally, serve KEY=VALUE
install instructions at /bootmedia/<id>/install with the grub.cfg
authorization, and render the declared netplan into NoCloud network-config.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Validation permits VLAN MTUs above the effective parent MTU and address ordering that selects a non-lease provisioning source, causing installation to fail before instruction retrieval or receive a 404 from /install.

2 open issues
1 file not reviewed
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file
What changed in this PR

Adds declarative host networking to Metalman’s VirtualMedia provisioning flow, enabling installation over bond and VLAN uplinks without requiring firmware-level networking. Machines without a network block retain the existing single-NIC flow.

Changes:

  • Adds network API types, validation, generated schemas, and configuration examples.
  • Packages local installer media and provides an operation-authorized /install endpoint.
  • Renders runtime and persistent network configuration, with tests for validation, rendering, archives, and installer behavior.
File Description
internal/​metalman/​netboot/​oci_cache.go Adds local-installer capability metadata.
internal/​metalman/​netboot/​netboot.go Exposes declared networking to templates.
internal/​metalman/​netboot/​media.go Builds local installer ISOs with network configuration.
internal/​metalman/​netboot/​media_network_test.go Tests local media and install endpoint behavior.
internal/​metalman/​netboot/​media_http.go Serves authorized local install instructions.
internal/​metalman/​hostnetwork/​validate.go Validates topology and provisioning lease consistency.
internal/​metalman/​hostnetwork/​validate_test.go Tests topology validation and edge cases.
internal/​metalman/​hostnetwork/​runtime.go Renders installer network directives.
internal/​metalman/​hostnetwork/​runtime_test.go Tests runtime directives and defaults.
internal/​metalman/​hostnetwork/​render.go Generates netplan, networkd, and media configuration.
internal/​metalman/​hostnetwork/​render_test.go Tests persistent configuration and archive contents.
internal/​metalman/​hostnetwork/​cpio.go Implements deterministic network configuration archives.
internal/​metalman/​hostnetwork/​cpio_test.go Tests archive structure, validation, and extraction.
images/​netboot/​init_test.go Tests installer networking and persistence functions.
images/​netboot/​Containerfile Includes networking tools, modules, and capability metadata.
images/​netboot/​assets/​network-config.tmpl Selects declared networking over single-NIC configuration.
docs/​content/​reference/​machina-crd.md Documents network fields and image requirements.
docs/​content/​guides/​pxe.md Explains bond and VLAN provisioning.
designs/​metalman-host-network.md Describes networking contracts and boot flow.
deploy/​machina/​examples/​metalman-bond-vlan.yaml Provides a bond and VLAN Machine example.
deploy/​machina/​crd/​unbounded-cloud.io_machines.yaml Adds generated Machine network schema and rules.
deploy/​machina/​crd/​unbounded-cloud.io_machineoperations.yaml Adds networking to operation snapshot schemas.
api/​machina/​v1alpha3/​zz_generated.deepcopy.go Adds generated copying for network types.
api/​machina/​v1alpha3/​machine_types.go Defines network types and validation markers.
api/​machina/​v1alpha3/​host_network_crd_test.go Tests schema validation, defaults, and snapshots.

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

A transient MachineOperation list failure still returns a permanent 404 instead of a retryable 503, aborting valid local boots, and the failing-List path lacks test coverage.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Return 503 for transient callback owner lookup failures

internal/​metalman/​netboot/​media_http.go:388

A transient MachineOperation list failure returns 404 from ServeHTTP's initial callbackOwner lookup (media_http.go:367-374), before this install handler can run. The installer treats 404 as permanent, so a temporary API outage aborts an otherwise valid local boot instead of retrying. Return 503 for errMediaLookup in that initial branch too, and add a failing-List case alongside the existing failing-Get test.

2 resolved since last review
1 file not reviewed
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

A critical VLAN name-matching bug lets valid configurations pass topology validation but causes the installer to reject distinct names as duplicates and stop before fetching install instructions.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

High severity Use fixed-string matching for declared network names

internal/​metalman/​hostnetwork/​runtime.go:51

Declaring VLAN e0-64 (ID 64) before e0.64 (ID 65) on the same ethernet passes topology validation, but the installer rejects the second name as a duplicate and stops before fetching install instructions. net_declared in images/netboot/assets/init:230 uses grep -qx, which treats the dot as a wildcard matching the hyphen. Change that lookup to grep -Fqx and add a regression case for these distinct names.

1 file not reviewed
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed to evaluate reserved interface names causing installer failures and large media payloads potentially exhausting controller memory.

No open issues 🎉

1 file not reviewed
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The change spans signed-GRUB boot and persistent networking on amd64/arm64 UEFI, while mocked tests leave bootability and bond/VLAN connectivity unverified without representative VM or hardware validation.

No open issues 🎉

1 file not reviewed
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

Review effort: Balanced

When UEFI firmware boots the bootstrap ISO as a CD-ROM, Ubuntu GRUB roots
itself at (cd0)/grub on the ISO9660 file system rather than the FAT EFI
image, so it found no config and stopped at the grub> prompt. Copy the same
config to the GRUB prefix paths in the ISO9660 tree as well. Found by
booting the local installer ISO in QEMU with OVMF.
The declared bond/VLAN network is authoritative and never runs DHCP, so
dhcpLeases[0].holdLease would be silently ignored. Reject it in CEL and in
hostnetwork.Validate, and document the rule.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The cross-layer boot and networking changes need representative amd64/arm64 runtime validation, since mocked tests do not establish local-media boot, real LACP/VLAN activation, or post-install connectivity.

No open issues 🎉

1 file not reviewed
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The firmware/GRUB boot and bond/VLAN networking changes require representative end-to-end boot and first-reboot validation beyond the existing rendering, packaging, and mocked-command tests.

No open issues 🎉

1 file not reviewed
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

Review effort: Balanced

@jveski
Jordan Olshevski (jveski) marked this pull request as ready for review November 10, 2026 23:30
@jveski
Jordan Olshevski (jveski) requested a review from a team November 10, 2026 23:30

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants