* feat(gpu): add NVIDIA MIG multi-instance GPU support
Partitions MIG-capable GPUs (A100, A30, H100) into isolated slices exposed
as mdev devices instead of whole-GPU VFIO passthrough. VMs attach via
-device vfio-pci,sysfsdev=<mdev-path> using the GPUAttachment discriminated
union (PCIAddress for whole-GPU, MdevPath for MIG).
Key changes:
- gpu: new MIGProfile/MIGInstance types, IsMIGCapable model map, mig.go ops
(EnableMIGMode, DisableMIGMode, CreateInstances, ListInstances,
DestroyAllInstances, enrichMdevPaths)
- gpu.Manager: Claim() returns (*GPUDevice, *MIGInstance, error); AddMIGInstances,
ReclaimByMdev for restart recovery; MarkMIGFailed per-slice
- daemon: buildGPUPool helper partitions devices into whole-GPU vs MIG pools;
MIGProfile config field selects profile per node or per GPU override
- vm.VM: GPUAttachments []gpu.GPUAttachment replaces GPUPCIAddresses []string
- admin CLI: spx admin gpu mig status/enable/disable subcommands with
admin.SetMIGProfile for spinifex.toml writes
- docs: COMMANDS.md updated with three new MIG management command rows
* test(gpu): unit tests for MIG parsers and pool manager
Cover all pure parsing functions (parseMIGMemory, isCapacityExhaustedError,
extractProfileFields/GIFields, parseMIGProfiles, parseMIGInstances,
parseCreatedGIID/CIID) with realistic nvidia-smi fixture output.
Manager MIG tests cover AddMIGInstances, Claim/Release on mdev-backed entries,
MarkMIGFailed, ReclaimByMdev, and interaction with whole-GPU MarkFailed — all
using fake mdev directories in t.TempDir() so no GPU hardware is required.
* feat(gpu): dynamic MIG profile-per-request with on-demand GI/CI lifecycle
Replaces static config-driven MIG pre-carving with a dynamic model where
the MIG profile is specified per RunInstances call via mig.<profile>
instance type names (e.g. mig.1g.10gb) that mirror nvidia-smi nomenclature
directly.
- Manager.Claim(instanceID, profileName): fast path claims a pre-carved
slice; slow path dequeues a free MIG GPU, releases the lock, calls
nvidia-smi mig -cgi/-cci to carve all slices, then reclaims the lock to
commit and return the first slice
- Manager.Release: last release on a dynamically-carved GPU calls
DestroyAllInstances and returns the GPU to freeMIGGPUs, allowing a
different profile on the next claim
- AddMIGGPU(dev): registers a fresh MIG GPU for dynamic allocation;
AddMIGInstances (restart recovery) keeps its no-destroy semantics
- GenerateMIGTypes: produces mig.<profile> InstanceTypeInfo entries from
gpu.ListProfiles at daemon startup; IsMIGType/MIGProfileFromType let
callers inspect these names
- buildGPUPool: calls ListInstances for recovery, AddMIGGPU for fresh
GPUs, ListProfiles to collect MIG profile specs for type generation;
removes setupMIGInstances and migProfileForDevice
- GPUClaimer.Claim gains profileName param; daemonGPUClaimer, service_impl
call sites, and fakeGPUClaimer all updated
* fix(gpu): correct mdev parent detection and make --profile optional for mig enable
enrichMdevPaths was using os.Readlink on "parent_bus_0" (a non-existent
sysfs attribute) and then on ".." (a directory, not a symlink) — both
would fail on real NVIDIA hardware, breaking CreateInstances and
ListInstances on daemon restart recovery. Fix: read the mdev UUID's own
symlink target, which always encodes the parent GPU's PCI address in its
path (e.g. .../0000:01:00.0/<uuid>).
Make basePath injectable in enrichMdevPaths so the fix is covered by a
new set of unit tests using temp-dir symlinks (TestEnrichMdevPaths_*).
Remove the MarkFlagRequired("profile") from "spx admin gpu mig enable":
Phase 2 is fully dynamic — the daemon carves slices on demand at
RunInstances time. Without --profile, the command just enables MIG mode
and destroys any pre-carved slices so the daemon starts with a free GPU.
With --profile, behaviour is unchanged (pre-carve a static pool).
* chore: writeups for smci and arcee
* test: add coverage for MIG exec, manager slow-path, instancetypes and admin
- Add mig_exec_test.go with fake nvidia-smi harness covering Enable/Disable MIGMode,
IsMIGModeEnabled, DestroyAllInstances, ListProfiles, CreateInstances, ListInstances
- Extend manager_mig_test.go with slow-path Claim/Release tests using fake nvidia-smi
- Add generate_test.go coverage for IsMIGType, MIGProfileFromType, GenerateMIGTypes
- Add admin_test.go coverage for SetMIGProfile (create, update, idempotent, error paths)
- Make mdevBasePath a var to allow sysfs injection in tests
- Add json tags to GPUAttachment fields to satisfy musttag linter
Diff coverage: 75.6% (threshold: 60%).
* fixed gpu passthrough doc
* Revert "fixed gpu passthrough doc"
This reverts commit 1e20f5ab13.
* feat: Added RTX 6000 GPU MIG support and fixed docs
* feat: expose GPU/MIG inventory in GetNodes and GetVMs admin API
Add Manager.Snapshot() for lock-safe pool inspection. Extend
NodeStatusResponse with GPUs []GPUInfo (per-physical-GPU inventory
with per-slice detail for MIG) and VMInfo with GPU *VMGPUInfo
(model, VRAM, profile, mdev path for the attached GPU). Populate
both in handleNodeStatus and handleNodeVMs via buildGPUInventory,
buildPoolLookup, and resolveVMGPU helpers.
* feat: surface GPU info on EC2 instance detail page (mulga-new-03)
Admin users see a GPU card (model, VRAM, attachment type, MIG profile/mdev
path or PCI address) populated from the GetVMs admin API. Adds formatVRAMMiB
helper and VMGPUInfo/GPUInfo/GPUSliceInfo types to the frontend.
* feat: GPU columns + inventory card on Nodes page (mulga-new-04)
Adds GPU column to VMsTable (model/VRAM or MIG profile) and ResourceTable
(alloc/total GPUs). Section 4 GPU Inventory card shows per-node GPU state with
per-slice MIG drill-down. Also adds total_gpus/alloc_gpus to NodeInfo type.
* feat: grouped GPU-aware instance type picker in Run Instances (mulga-new-05)
Splits the flat instance type dropdown into Standard and GPU-Accelerated groups.
GPU items show total VRAM alongside the type name. Selecting a GPU type surfaces
an info line with GPU name and VRAM.
* testing image builder scripts
* fixed nvidia build script
* more descriptive errors for image build script
* more fixes
* more fixes
* fix: surface PCI address in whole-GPU VMGPUInfo and rebuild frontend dist
Add PCIAddress to VMGPUInfo, populate it in resolveVMGPU for whole-GPU
passthrough, and fix the instance detail page which was incorrectly
showing instance type in the PCI address field. Rebuilt frontend dist
to include GPU UI changes (inventory card, resource columns, GPU-aware
instance type picker).
* fix: improve kernel version detection in nvidia image build script
Fall back to /lib/modules when /boot/vmlinuz-* is absent, and add
diagnostic output to help debug kernel detection failures.
* fixing nvidia image build script
* fix ami name issue
* correct kernel versions
* another fix
* image build works, added docker and nvidia toolkit for QoL
* fix: add gpg
* fixing amd image builder
* add universe
* another fix
* nvm
* fix docker user group issues
* make rocm land where it is supposed to
* fix docker groups
* feat: add Ubuntu 26.04 GPU AMI catalog entries and fix build script parted detection
Add ubuntu-26.04-nvidia-gpu-x86_64 and ubuntu-26.04-amd-gpu-x86_64 to AvailableImages,
hosted on iso.mulgadc.com/system-ami/ with SHA256 checksums. Fix build-system-image.sh
to detect parted in /usr/sbin when not on PATH. Suppress gosec false positives in DHCP
manager (cancel stored in leaseLoop) and promisc ioctl (standard syscall uintptr pattern).
* Updated passthrough doc regarding GPU images
* fix: remove orphaned nolint directives (golangci-lint v2.12.2 no longer flags G115/G118)
* chore: remove stale spinifex@192.168.3.107 directory
Scripts were accidentally committed with a node hostname as the path
prefix during initial testing. Correct copies live in scripts/images/.
title, description, category, tags, sections, resources
| title | description | category | tags | sections | resources | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| GPU Passthrough | Configure VFIO GPU passthrough on a Spinifex node to expose NVIDIA or AMD GPUs to EC2 instances. | Compute |
|
|
|
Overview
Spinifex supports VFIO-based GPU passthrough, binding NVIDIA and AMD GPUs directly to guest VMs via the vfio-pci kernel driver. Once configured, the node exposes GPU-enabled EC2 instance types and the GPU is allocated exclusively to individual instances.
At startup, Spinifex always probes for GPU hardware and surfaces the result in the node banner and in spx top nodes — regardless of whether passthrough is enabled. This lets operators verify hardware before activating the feature.
The passthrough state is reflected in the login banner:
Note: GPU passthrough is supported on x86_64 hosts only.
Prerequisites
- IOMMU must be supported and enabled in the host BIOS/UEFI (
Intel VT-dorAMD-Vi). - An NVIDIA or AMD GPU must be physically installed.
- The Spinifex node must be running on bare metal (not inside a VM).
Instructions
Host Setup
Run the one-time host configuration as root. This command is idempotent — safe to re-run after a reboot.
sudo spx admin gpu setup
What it does:
- Detects installed GPUs and their PCI IDs.
- Enables IOMMU in GRUB (
intel_iommu=on iommu=ptoramd_iommu=on iommu=pt). - Writes the vfio udev rule (
/etc/udev/rules.d/99-spinifex-vfio.rules). - Blacklists
nouveau(NVIDIA) andamdgpu(AMD) so the host kernel does not claim the device. - Configures
vfio-pciearly binding in/etc/modprobe.d/vfio-pci.conf. - Adds vfio modules to initramfs.
If any change requires a reboot, the command prints instructions and exits:
Setup complete — reboot required.
sudo reboot
Then run: sudo spx admin gpu enable
Enable Passthrough
After setup and reboot, enable GPU passthrough:
sudo spx admin gpu enable
The command writes the configuration, signals the daemon (SIGHUP), and waits up to 30 seconds for the daemon to confirm the new state. On success it prints the current GPU status.
Status and Monitoring
Per-node status:
spx admin gpu status
# or for a specific node in the cluster:
spx admin gpu status --node <node-name>
Output includes hardware detected, IOMMU state, vfio-pci binding, passthrough enabled/disabled, GPU pool allocation (allocated/total), and the GPU-capable EC2 instance types available on that node.
Cluster view:
spx top nodes includes a GPU (used/total) column:
| Value | Meaning |
|---|---|
1/2 |
Passthrough active — 1 of 2 GPUs allocated |
0/1* |
Node has a GPU but passthrough is not enabled |
- |
No GPU hardware detected |
spx top nodes
GPU Instance Types
GPU instance types are derived from detected hardware. To list available GPU instance types on the current node:
aws ec2 describe-instance-types \
--filters Name=instance-type,Values=g*
Launching GPU Instances
Spinifex ships two pre-built GPU guest images. Import the one that matches your host hardware before launching:
spx admin images import --name ubuntu-26.04-nvidia-gpu-x86_64 # NVIDIA hosts
spx admin images import --name ubuntu-26.04-amd-gpu-x86_64 # AMD hosts
These images are built on Ubuntu 26.04 and serve as a base for GPU workloads. Both include Docker CE, Python 3, and common utilities (git, curl, htop, tmux, ffmpeg).
NVIDIA (ubuntu-26.04-nvidia-gpu-x86_64): NVIDIA server driver with DKMS pre-built against the image kernel, nvidia-smi, nvidia-container-toolkit wired into Docker (--gpus all works on first boot). CUDA toolkit and cuDNN are not included — use an NGC container or install inside the instance.
AMD (ubuntu-26.04-amd-gpu-x86_64): linux-firmware (amdgpu firmware blobs), ROCm 7.2 CLI tools (rocm-smi, rocminfo, amd-smi). Full ROCm compute libraries (rocblas, etc.) are not included — install inside the instance as needed.
Launch a GPU instance:
aws ec2 run-instances \
--image-id $GPU_AMI \
--instance-type $INSTANCE_TYPE \
--key-name spinifex-key
To verify the GPU is visible from inside the instance, SSH in and run:
# NVIDIA
nvidia-smi
# AMD
rocm-smi
Disable Passthrough
Passthrough cannot be disabled while GPU instances are running. Terminate all GPU instances first, then:
sudo spx admin gpu disable
The command signals the daemon and waits for confirmation. The GPU is released back to the host kernel on the next reboot (the vfio-pci binding persists until setup is re-run without the blacklists).
Troubleshooting
IOMMU not active after reboot
Verify IOMMU is enabled in BIOS/UEFI (Intel VT-d or AMD-Vi). Then check GRUB picked up the parameters:
cat /proc/cmdline | grep iommu
ls /sys/kernel/iommu_groups/
If /sys/kernel/iommu_groups/ is empty, IOMMU is not active. Re-run sudo spx admin gpu setup after enabling it in firmware.
GPU bound to native driver instead of vfio-pci
lspci -k | grep -A3 -i "vga\|3d\|display"
If the driver is amdgpu or nvidia rather than vfio-pci, the blacklist or early binding did not take effect. Re-run setup and reboot:
sudo spx admin gpu setup
sudo reboot
spx admin gpu enable fails with "prerequisites not met"
Run setup first to configure the host, then retry enable:
sudo spx admin gpu setup
sudo spx admin gpu enable
Daemon does not confirm within 30 seconds
Check the daemon log for errors:
journalctl -u spinifex-daemon -n 50