Skip to content

feat(metalman): support rack manager virtual media installs - #910

Merged
Jordan Olshevski (jveski) merged 37 commits into
mainfrom
metalman-extended
Oct 15, 2026
Merged

Jordan Olshevski (jveski) merged 37 commits into
mainfrom
metalman-extended

Conversation

@jveski

@jveski Jordan Olshevski (jveski) commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Metalman can now manage rack managers that expose one Redfish service per slot under a URL path prefix, using a bootloader served as virtual media - no DHCP needed.

Also adds an Azure linux host image in order to support machines with MANA NICs.

Metalman can now drive rack managers that expose one Redfish service per
slot under a URL path prefix, such as https://manager/7. The client finds
these endpoints on its own, so the Machine API stays vendor neutral.

A new VirtualMedia boot protocol installs a machine without DHCP boot
options. Metalman builds a small per-operation UEFI ISO with a static
network GRUB config, stages it on the rack manager over TFTP, mounts it,
and boots it. The installer then fetches the kernel, initrd, and disk image
over HTTP. A durable state machine with a finalizer handles boot retries,
cleanup, and a reboot barrier so the host never boots the media twice.

Also adds Azure Linux 3.0 machine images (with an NVIDIA variant), runs the
installer on the Azure Linux kernel so MANA NICs work, and fixes issues
found while installing a real arm64 GPU host.

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

Unresolved callback races, frozen-state recovery gaps, and cleanup coupling can prevent installations from completing.

5 open findings
What changed in this PR

Adds rack-manager VirtualMedia installation to Metalman, alongside Azure Linux host images and arm64 GPU compatibility fixes.

Changes:

  • Adds slot-prefixed Redfish access, operation-owned boot media, cleanup, and reboot coordination.
  • Integrates ISO serving and static-network boot without DHCP boot hints.
  • Adds Azure Linux images and improves installer and NVIDIA support.
File Description
pkg/​agent/​phases/​nodestart/​nvidia.go Prepares NVIDIA library search paths.
pkg/​agent/​phases/​nodestart/​nvidia_test.go Tests library directory configuration.
pkg/​agent/​phases/​host/​preflight_nvidia.go Handles uppercase arm64 linker tags.
pkg/​agent/​phases/​host/​preflight_nvidia_test.go Tests architecture filtering.
internal/​operator/​rbac_test.go Checks media finalizer permissions.
internal/​metalman/​redfish/​virtualmedia.go Implements rack media operations.
internal/​metalman/​redfish/​virtualmedia_test.go Tests media requests and failures.
internal/​metalman/​redfish/​session.go Checks vendor completion responses.
internal/​metalman/​redfish/​rackmanager.go Adds rack detection and power recovery.
internal/​metalman/​redfish/​completion.go Parses vendor completion codes.
internal/​metalman/​redfish/​completion_test.go Tests completion response handling.
internal/​metalman/​redfish/​client.go Routes rack-specific Redfish operations.
internal/​metalman/​netboot/​tftp.go Serves operation-owned ISOs.
internal/​metalman/​netboot/​reconciler.go Tags temporary OCI layouts consistently.
internal/​metalman/​netboot/​reconciler_layout_test.go Tests tag and digest unpacking.
internal/​metalman/​netboot/​oci_cache.go Adds media compatibility metadata.
internal/​metalman/​netboot/​netboot.go Adds media template inputs.
internal/​metalman/​netboot/​netboot_test.go Tests routes and template changes.
internal/​metalman/​netboot/​media.go Builds and authorizes bootstrap ISOs.
internal/​metalman/​netboot/​media_http.go Serves scoped configuration and callbacks.
internal/​metalman/​netboot/​http.go Integrates frozen-media artifact routing.
internal/​metalman/​machineops/​virtualmedia.go Implements media lifecycle and cleanup.
internal/​metalman/​machineops/​status_queue.go Routes per-target media status.
internal/​metalman/​machineops/​controller.go Coordinates media operations and readiness.
internal/​metalman/​machineops/​controller_test.go Tests readiness and retry behavior.
internal/​metalman/​dhcp/​dhcp.go Suppresses VirtualMedia boot hints.
internal/​metalman/​dhcp/​dhcp_test.go Tests DHCP hint suppression.
internal/​metalman/​commands/​serve_pxe.go Wires media services and advertised address.
internal/​metalman/​commands/​serve_pxe_test.go Tests media address configuration.
internal/​metalman/​bootmedia/​types.go Defines provider and client contracts.
internal/​metalman/​bootmedia/​types_test.go Tests primer filenames.
images/​netboot/​Containerfile Uses Azure Linux kernel and media artifacts.
images/​netboot/​assets/​vendor-data.tmpl Collects failed-unit diagnostics.
images/​netboot/​assets/​init Adds stable disk IDs and reboot barrier.
images/​netboot/​assets/​grub.cfg.tmpl Adds media boot parameters.
images/​metalman/​Containerfile Installs ISO construction tools.
images/​host-azurelinux3/​Containerfile Builds Azure Linux host images.
images/​host-azurelinux3/​assets/​rootfs.sh Configures Azure Linux root filesystems.
images/​host-azurelinux3/​assets/​disk.sh Assembles bootable disk images.
images/​host-azurelinux3-nvidia/​Containerfile Builds NVIDIA-enabled host images.
deploy/​machina/​crd/​unbounded-cloud.io_machines.yaml Adds VirtualMedia schema validation.
deploy/​machina/​crd/​unbounded-cloud.io_machineoperations.yaml Adds media lifecycle status schema.
deploy/​machina/​06-metalman-rbac.yaml.tmpl Grants finalizer management permissions.
api/​machina/​v1alpha3/​zz_generated.deepcopy.go Copies media status fields.
api/​machina/​v1alpha3/​machineoperation_types.go Defines durable media status.
api/​machina/​v1alpha3/​machine_types.go Defines VirtualMedia boot protocol.
api/​machina/​v1alpha3/​machine_types_test.go Tests protocol defaults and status serialization.
Files not reviewed (1)
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/metalman/machineops/virtualmedia.go Outdated
Comment thread internal/metalman/machineops/virtualmedia.go
Comment thread internal/metalman/netboot/http.go
Comment thread internal/metalman/commands/serve_pxe.go Outdated
Comment thread internal/metalman/netboot/media.go

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.

Comment thread internal/metalman/machineops/virtualmedia.go Outdated
Comment thread internal/metalman/netboot/http.go
Comment thread internal/metalman/netboot/media.go Outdated
Comment thread internal/metalman/netboot/media_http.go Outdated
Comment thread internal/metalman/netboot/http.go
Recheck site ownership and outstanding media on each finalizer update. Keep incomplete acquisition protected and verify the persisted finalizer before media effects.

Cover cross-site cleanup, restart recovery, stale status, and conflicting updates.
Reject live-IP and forwarded-IP fallback for retained media leases and VirtualMedia Machines. Keep media reports on the authorized owner path and preserve PXE and HTTP forwarding behavior.
End callback authorization when media retention is abandoned. Keep callbacks available for failed targets before abandonment, and test rejected requests leave status unchanged.
Pass the serve-pxe site to the media provider and filter frozen media claims and live successors by site. Treat an empty site as an exact match, not a wildcard.

Cover cross-site lease collisions, callback rejection, and same-site access with regression tests.
Return 503 with Retry-After when saving a media cloud-init condition fails, while preserving the error log and legacy report behavior. Cover failed patches, successful persistence, and events without condition updates.

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

Authorization bypasses, cross-site interference, and image-readiness gaps can expose provisioning data or interrupt installations.

3 open findings
7 resolved since last review
Files not reviewed (1)
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file
Previously missed (2)

In code that hasn't changed since last review

Medium severity Preparation succeeds without cached frozen disk image

internal/​metalman/​netboot/​media.go:319

Preparation validates the netboot image but never checks that the frozen disk image is cached. If its pull is failing, preparation still succeeds and the controller can power-cycle the host into an installer that cannot download its image. Once download retries expire, the installer drops into a shell (images/netboot/assets/init:333-335); LoaderStartedAt prevents a boot retry (machineops/virtualmedia.go:401). Resolve the frozen disk.img.gz before preparation succeeds, returning ErrNotYetDownloaded while its image is pending. Update the preparation fixtures to cache the disk image too.

Medium severity ISO release prematurely removes frozen image authorization

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

ISO release does not end first-boot authorization: firstBootOwner still accepts terminal targets with ImageWritten and RebootRequestedAt until the final cloud-init report (media_http.go:47-53). This predicate nevertheless stops the OCI reconciler from restoring their frozen image mappings (reconciler.go:117). After a restart, if the Machine's netboot reference has changed, authorized cloud-init template requests cannot resolve the frozen image (oci_cache.go:193-195). Retain those image references until first-boot authorization ends, and cover this restart case.

🧠 Review effort: Balanced

Comment thread internal/metalman/netboot/http.go
Comment thread internal/metalman/netboot/media_http.go Outdated
Remove trailing slashes and normalize decoded paths before routing so authorization and cache lookup use the same path. Keep boot media capability aliases rejected. Add alias tests for artifacts, first-boot data, reports, and kernel range requests.
Ignore foreign-site media before matching a Machine name or lease. Share exact site matching across media lookups and image reconciliation.

Cover direct and forwarded PXE/HTTP datasource and report requests, including name and lease collisions, empty sites, and same-site rejection.

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

Unresolved disk-selection, scheduling, recovery, and image-retention issues can cause data loss or block provisioning.

3 open findings
2 resolved since last review
Files not reviewed (1)
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file
Previously missed (2)

In code that hasn't changed since last review

Medium severity Released ISO artifacts lose frozen image mappings after restart

internal/​metalman/​netboot/​reconciler.go:119

Releasing ISO artifacts does not end first-boot authorization. A failed target with ImageWritten and RebootRequestedAt remains authorized until its final cloud-init report or abandonment (media_http.go:47-53), but this filter stops restoring its frozen image mappings. After a Metalman restart, if the Machine's netboot image has changed, neither watch restores the old mapping. Authorized cloud-init requests then fail even when the frozen files remain on disk, since NewOCICache starts with empty mappings (oci_cache.go:49-54). Keep the frozen netboot image reconciled for the full first-boot authorization lifetime and add a released/failed-target restart test.

Medium severity Blade PowerOn does not complete pending ResetOn recovery

internal/​metalman/​redfish/​rackmanager.go:229

A successful blade PowerOn read leaves a pending ResetOn recovery incomplete. Slot power-on itself boots the host, and the virtual-media controller advances to Installing on this read without retrying ResetOn (machineops/virtualmedia.go:525-531). Consequently, pendingCompleted stays false and later outages on the same client cannot trigger recovery because rackMutateLocked requires pending == recoveryNone. Mark the pending ResetOn recovery complete when the blade confirms PowerOn, while preserving the grace window.

🧠 Review effort: Balanced

Comment thread images/netboot/assets/init Outdated
Comment thread internal/metalman/machineops/controller.go Outdated
…ease path

The noble release alias no longer serves 24.04.4 files. Use the path for that point release so the download keeps working after newer point releases.
Read the namespace ID from sysfs, falling back to the device name, and create namespace-qualified model/serial aliases. Reserve the legacy alias for namespace 1 so later namespaces cannot redirect installer writes; retain WWID aliases.
Compare retained media ownership in both directions before creation time and name to prevent cyclic conflict waits. Use the same ordering to select blockers, and cover media priority, tie-breaking, and install timeout progress after a Redfish URL change.
Share the first-boot lifetime predicate with OCI reconciliation so released targets retain frozen netboot templates until a final report or abandonment. Restore only the netboot image after artifact release and cover restart recovery, ended claims, and site isolation.
The Ubuntu shim and GRUB reject the Azure Linux kernel with Secure Boot
enabled. The amd64 Ubuntu generic kernel already has the MANA driver, so
only arm64 needs the Azure Linux kernel.

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

Firmware-specific destructive provisioning needs human and hardware validation, and the retained legacy-serving issue remains unresolved.

2 open findings
Files not reviewed (1)
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

🧠 Review effort: Balanced

Comment thread internal/metalman/netboot/media_http.go Outdated

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

Firmware-dependent recovery and installer handoff require human validation, alongside resolution of the arm64 Secure Boot compatibility regression.

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

🧠 Review effort: Balanced

Comment thread images/netboot/Containerfile Outdated
…image

The default netboot image keeps the Ubuntu kernel on every architecture so the Ubuntu shim and GRUB can verify it with Secure Boot on. netboot-azurelinux runs the Azure Linux kernel for arm64 hosts with NICs the Ubuntu kernel does not support.

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

Firmware-specific power recovery, destructive installation handoffs, and new bootable images require human review and hardware-backed validation.

1 open finding
1 resolved since last review
Files not reviewed (1)
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

🧠 Review effort: Balanced

The image coverage test expands only matrix.component.name, so the netboot job uses the same matrix shape as the other component images.

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

Firmware-specific power recovery, media cleanup, and destructive installation paths require final human review and hardware validation.

1 open finding
Files not reviewed (1)
  • api/machina/v1alpha3/zz_generated.deepcopy.go: Generated file

🧠 Review effort: Balanced

@chokevin

Kevin Cho (chokevin) commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

The virtual-media controller looks solid. My concern is that the image and installer work feels too tied to Azure Linux, MANA, and NVIDIA.

Right now, supporting another OS, NIC, or GPU setup may require another image variant and more special cases in the shared installer scripts. Can we keep these pieces separate?

  • the generic virtual-media install flow
  • installer requirements such as architecture, drivers, and Secure Boot support
  • OS-specific disk and network setup
  • optional hardware support such as MANA, NVIDIA, Fabric Manager, or IMEX

The above was generated by the agent but in some sense I agree with the concern. What do we think about AZL vs Ubuntu and how we are going to set up the lab vs other setups that might use metalman that dont use azure nics.

@jveski

Copy link
Copy Markdown
Contributor Author

Copilot resolve the merge conflicts in this pull request

# Conflicts:
#	images/netboot/Containerfile

Co-authored-by: jveski <7576912+jveski@users.noreply.github.com>
@jveski

Copy link
Copy Markdown
Contributor Author

The virtual-media controller looks solid. My concern is that the image and installer work feels too tied to Azure Linux, MANA, and NVIDIA.

Right now, supporting another OS, NIC, or GPU setup may require another image variant and more special cases in the shared installer scripts. Can we keep these pieces separate?

  • the generic virtual-media install flow
  • installer requirements such as architecture, drivers, and Secure Boot support
  • OS-specific disk and network setup
  • optional hardware support such as MANA, NVIDIA, Fabric Manager, or IMEX

The above was generated by the agent but in some sense I agree with the concern. What do we think about AZL vs Ubuntu and how we are going to set up the lab vs other setups that might use metalman that dont use azure nics.

The netboot changes will still work on vanilla hardware - they just add support for MANA, which is easier to do by pivoting to Azure linux host images. We can build a custom Ubuntu image that includes the MANA drivers but I wanted to keep that out of scope here

Copilot AI commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Merged current main and resolved the netboot Containerfile conflict in 017431e, preserving the separate installer kernel variants and main's stable Noble download URLs. Targeted release, filesystem, and Metalman tests passed, along with both container-definition checks.

@jveski
Jordan Olshevski (jveski) added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit 4f70209 Oct 15, 2026
52 of 54 checks passed
@jveski
Jordan Olshevski (jveski) deleted the metalman-extended branch October 15, 2026 17:40
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.

4 participants