@@ -3,6 +3,7 @@ package instance
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "reflect"
6
7
7
8
"github.com/k8s-proxmox/cluster-api-provider-proxmox/cloud/scheduler/framework"
8
9
"github.com/k8s-proxmox/proxmox-go/api"
@@ -13,6 +14,7 @@ import (
13
14
14
15
const (
15
16
bootDvice = "scsi0"
17
+
16
18
)
17
19
18
20
// reconciles QEMU instance
@@ -96,9 +98,39 @@ func (s *Service) createQEMU(ctx context.Context) (*proxmox.VirtualMachine, erro
96
98
return nil , err
97
99
}
98
100
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
+
99
106
return vm , nil
100
107
}
101
108
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
+
102
134
func (s * Service ) generateVMOptions () api.VirtualMachineCreateOptions {
103
135
vmName := s .scope .Name ()
104
136
snippetStorageName := s .scope .GetClusterStorage ().Name
@@ -108,8 +140,29 @@ func (s *Service) generateVMOptions() api.VirtualMachineCreateOptions {
108
140
options := s .scope .GetOptions ()
109
141
cicustom := fmt .Sprintf ("user=%s:%s" , snippetStorageName , userSnippetPath (vmName ))
110
142
ide2 := fmt .Sprintf ("file=%s:cloudinit,media=cdrom" , imageStorageName )
111
- scsi0 := fmt .Sprintf ("%s:0,import-from=%s" , imageStorageName , rawImageFilePath (s .scope .GetImage ()))
112
143
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
+ }
113
166
114
167
vmoptions := api.VirtualMachineCreateOptions {
115
168
ACPI : boolToInt8 (options .ACPI ),
@@ -140,7 +193,7 @@ func (s *Service) generateVMOptions() api.VirtualMachineCreateOptions {
140
193
OSType : api .OSType (options .OSType ),
141
194
Protection : boolToInt8 (options .Protection ),
142
195
Reboot : int (boolToInt8 (options .Reboot )),
143
- Scsi : api. Scsi { Scsi0 : scsi0 } ,
196
+ Scsi : scsiDisks ,
144
197
ScsiHw : api .VirtioScsiPci ,
145
198
SearchDomain : network .SearchDomain ,
146
199
Serial : api.Serial {Serial0 : "socket" },
@@ -168,10 +221,33 @@ func boolToInt8(b bool) int8 {
168
221
func (s * Service ) injectVMOption (vmOption * api.VirtualMachineCreateOptions , storage string ) * api.VirtualMachineCreateOptions {
169
222
// storage is finalized after node scheduling so we need to inject storage name here
170
223
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
173
224
vmOption .Ide .Ide2 = ide2
174
225
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
+ }
175
235
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
+ }
176
252
return vmOption
177
253
}
0 commit comments