@@ -3,6 +3,7 @@ package instance
33import (
44 "context"
55 "fmt"
6+ "reflect"
67
78 "github.com/k8s-proxmox/cluster-api-provider-proxmox/cloud/scheduler/framework"
89 "github.com/k8s-proxmox/proxmox-go/api"
@@ -13,6 +14,7 @@ import (
1314
1415const (
1516 bootDvice = "scsi0"
17+
1618)
1719
1820// reconciles QEMU instance
@@ -96,9 +98,39 @@ func (s *Service) createQEMU(ctx context.Context) (*proxmox.VirtualMachine, erro
9698 return nil , err
9799 }
98100
101+ // Resize disks immediately after creation
102+ if err := s .resizeExtraDisks (ctx , vm ); err != nil {
103+ log .Error (err , "Failed to resize extra disks" )
104+ }
105+
99106 return vm , nil
100107}
101108
109+ func (s * Service ) resizeExtraDisks (ctx context.Context , vm * proxmox.VirtualMachine ) error {
110+ log := log .FromContext (ctx )
111+ log .Info ("Resizing additional disks for VM" , "vmid" , vm .VM .VMID )
112+
113+ extraDisks := s .scope .GetHardware ().ExtraDisks
114+ if len (extraDisks ) == 0 {
115+ return nil // No extra disks, nothing to do
116+ }
117+
118+ for i , disk := range extraDisks {
119+ diskName := fmt .Sprintf ("scsi%d" , i + 1 ) // scsi1, scsi2, scsi3...
120+ log .Info ("Resizing disk" , "vmid" , vm .VM .VMID , "disk" , diskName , "size" , disk .Size )
121+
122+ // Use `ResizeVolume` to resize the disk
123+ err := vm .ResizeVolume (ctx , diskName , disk .Size )
124+ if err != nil {
125+ log .Error (err , "Failed to resize disk" , "disk" , diskName )
126+ return err
127+ }
128+ }
129+
130+ log .Info ("Successfully resized all extra disks" , "vmid" , vm .VM .VMID )
131+ return nil
132+ }
133+
102134func (s * Service ) generateVMOptions () api.VirtualMachineCreateOptions {
103135 vmName := s .scope .Name ()
104136 snippetStorageName := s .scope .GetClusterStorage ().Name
@@ -108,8 +140,29 @@ func (s *Service) generateVMOptions() api.VirtualMachineCreateOptions {
108140 options := s .scope .GetOptions ()
109141 cicustom := fmt .Sprintf ("user=%s:%s" , snippetStorageName , userSnippetPath (vmName ))
110142 ide2 := fmt .Sprintf ("file=%s:cloudinit,media=cdrom" , imageStorageName )
111- scsi0 := fmt .Sprintf ("%s:0,import-from=%s" , imageStorageName , rawImageFilePath (s .scope .GetImage ()))
112143 net0 := hardware .NetworkDevice .String ()
144+ // Assign primary SCSI disk
145+ scsiDisks := api.Scsi {}
146+ scsiDisks .Scsi0 = fmt .Sprintf ("%s:0,import-from=%s" , imageStorageName , rawImageFilePath (s .scope .GetImage ()))
147+ // Assign additional disks manually
148+ extraDisks := s .scope .GetHardware ().ExtraDisks
149+ if len (extraDisks ) > 5 {
150+ log .FromContext (context .TODO ()).Error (fmt .Errorf ("too many extra disks" ), "Only 6 extra disks are supported, ignoring extra disks" )
151+ extraDisks = extraDisks [:5 ] // Trim to max 5 extra disks
152+ }
153+
154+ // Assign extra disks
155+ scsiStruct := reflect .ValueOf (& scsiDisks ).Elem ()
156+ for i , disk := range extraDisks {
157+ fieldName := fmt .Sprintf ("Scsi%d" , i + 1 ) // Scsi1, Scsi2, ...
158+ field := scsiStruct .FieldByName (fieldName )
159+ if field .IsValid () && field .CanSet () {
160+ field .SetString (fmt .Sprintf ("%s:%d,format=%s,size=%s" , disk .Storage , i + 1 , disk .Format , disk .Size ))
161+ // field.SetString(fmt.Sprintf("%s:%d,size=%s", disk.Storage, i+1, disk.Size))
162+ } else {
163+ log .FromContext (context .TODO ()).Error (fmt .Errorf ("invalid SCSI field" ), "Failed to set extra disk" , "field" , fieldName )
164+ }
165+ }
113166
114167 vmoptions := api.VirtualMachineCreateOptions {
115168 ACPI : boolToInt8 (options .ACPI ),
@@ -140,7 +193,7 @@ func (s *Service) generateVMOptions() api.VirtualMachineCreateOptions {
140193 OSType : api .OSType (options .OSType ),
141194 Protection : boolToInt8 (options .Protection ),
142195 Reboot : int (boolToInt8 (options .Reboot )),
143- Scsi : api. Scsi { Scsi0 : scsi0 } ,
196+ Scsi : scsiDisks ,
144197 ScsiHw : api .VirtioScsiPci ,
145198 SearchDomain : network .SearchDomain ,
146199 Serial : api.Serial {Serial0 : "socket" },
@@ -168,10 +221,33 @@ func boolToInt8(b bool) int8 {
168221func (s * Service ) injectVMOption (vmOption * api.VirtualMachineCreateOptions , storage string ) * api.VirtualMachineCreateOptions {
169222 // storage is finalized after node scheduling so we need to inject storage name here
170223 ide2 := fmt .Sprintf ("file=%s:cloudinit,media=cdrom" , storage )
171- scsi0 := fmt .Sprintf ("%s:0,import-from=%s" , storage , rawImageFilePath (s .scope .GetImage ()))
172- vmOption .Scsi .Scsi0 = scsi0
173224 vmOption .Ide .Ide2 = ide2
174225 vmOption .Storage = storage
226+ // Assign primary root disk
227+ vmOption .Scsi .Scsi0 = fmt .Sprintf ("%s:0,import-from=%s" , storage , rawImageFilePath (s .scope .GetImage ()))
228+
229+ // Assign Extra Disks (Scsi1, Scsi2, ... up to Scsi5)
230+ extraDisks := s .scope .GetHardware ().ExtraDisks
231+ if len (extraDisks ) > 5 {
232+ log .FromContext (context .TODO ()).Error (fmt .Errorf ("too many extra disks" ), "Only 5 extra disks are supported, ignoring excess" )
233+ extraDisks = extraDisks [:5 ] // Limit to 5 extra disks
234+ }
175235
236+ // Set each disk explicitly
237+ if len (extraDisks ) > 0 {
238+ vmOption .Scsi .Scsi1 = fmt .Sprintf ("%s:1,size=%s" , extraDisks [0 ].Storage , extraDisks [0 ].Size )
239+ }
240+ if len (extraDisks ) > 1 {
241+ vmOption .Scsi .Scsi2 = fmt .Sprintf ("%s:2,size=%s" , extraDisks [1 ].Storage , extraDisks [1 ].Size )
242+ }
243+ if len (extraDisks ) > 2 {
244+ vmOption .Scsi .Scsi3 = fmt .Sprintf ("%s:3,size=%s" , extraDisks [2 ].Storage , extraDisks [2 ].Size )
245+ }
246+ if len (extraDisks ) > 3 {
247+ vmOption .Scsi .Scsi4 = fmt .Sprintf ("%s:4,size=%s" , extraDisks [3 ].Storage , extraDisks [3 ].Size )
248+ }
249+ if len (extraDisks ) > 4 {
250+ vmOption .Scsi .Scsi5 = fmt .Sprintf ("%s:5,size=%s" , extraDisks [4 ].Storage , extraDisks [4 ].Size )
251+ }
176252 return vmOption
177253}
0 commit comments