@@ -12,6 +12,7 @@ import (
1212 "github.com/onkernel/hypeman/lib/network"
1313 "github.com/onkernel/hypeman/lib/system"
1414 "github.com/onkernel/hypeman/lib/vmm"
15+ "github.com/onkernel/hypeman/lib/volumes"
1516 "gvisor.dev/gvisor/pkg/cleanup"
1617)
1718
@@ -179,6 +180,41 @@ func (m *manager) createInstance(
179180 })
180181 }
181182
183+ // 10.5. Validate and attach volumes
184+ if len (req .Volumes ) > 0 {
185+ log .DebugContext (ctx , "validating volumes" , "id" , id , "count" , len (req .Volumes ))
186+ for _ , volAttach := range req .Volumes {
187+ // Check volume exists and is not attached
188+ vol , err := m .volumeManager .GetVolume (ctx , volAttach .VolumeID )
189+ if err != nil {
190+ log .ErrorContext (ctx , "volume not found" , "id" , id , "volume_id" , volAttach .VolumeID , "error" , err )
191+ return nil , fmt .Errorf ("volume %s: %w" , volAttach .VolumeID , err )
192+ }
193+ if vol .AttachedTo != nil {
194+ log .ErrorContext (ctx , "volume already attached" , "id" , id , "volume_id" , volAttach .VolumeID , "attached_to" , * vol .AttachedTo )
195+ return nil , fmt .Errorf ("volume %s is already attached to instance %s" , volAttach .VolumeID , * vol .AttachedTo )
196+ }
197+
198+ // Mark volume as attached
199+ if err := m .volumeManager .AttachVolume (ctx , volAttach .VolumeID , volumes.AttachVolumeRequest {
200+ InstanceID : id ,
201+ MountPath : volAttach .MountPath ,
202+ Readonly : volAttach .Readonly ,
203+ }); err != nil {
204+ log .ErrorContext (ctx , "failed to attach volume" , "id" , id , "volume_id" , volAttach .VolumeID , "error" , err )
205+ return nil , fmt .Errorf ("attach volume %s: %w" , volAttach .VolumeID , err )
206+ }
207+
208+ // Add volume cleanup to stack
209+ volumeID := volAttach .VolumeID // capture for closure
210+ cu .Add (func () {
211+ m .volumeManager .DetachVolume (ctx , volumeID )
212+ })
213+ }
214+ // Store volume attachments in metadata
215+ stored .Volumes = req .Volumes
216+ }
217+
182218 // 11. Create config disk (needs Instance for buildVMConfig)
183219 inst := & Instance {StoredMetadata : * stored }
184220 log .DebugContext (ctx , "creating config disk" , "id" , id )
@@ -388,6 +424,15 @@ func (m *manager) buildVMConfig(inst *Instance, imageInfo *images.Image, netConf
388424 },
389425 }
390426
427+ // Add attached volumes as additional disks
428+ for _ , volAttach := range inst .Volumes {
429+ volumePath := m .volumeManager .GetVolumePath (volAttach .VolumeID )
430+ disks = append (disks , vmm.DiskConfig {
431+ Path : & volumePath ,
432+ Readonly : ptr (volAttach .Readonly ),
433+ })
434+ }
435+
391436 // Serial console configuration
392437 serial := vmm.ConsoleConfig {
393438 Mode : vmm .ConsoleConfigMode ("File" ),
0 commit comments