Skip to content

Commit a7af557

Browse files
authoredFeb 25, 2025··
Merge pull request #1 from mojaloop/feature/additional-disks
Additional disks
2 parents 39ad710 + 853d798 commit a7af557

File tree

8 files changed

+148
-51
lines changed

8 files changed

+148
-51
lines changed
 

‎.github/workflows/ci.yaml

-38
This file was deleted.

‎Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
# Image URL to use all building/pushing image targets
33
REGISTRY := ghcr.io
4-
PROJECT := k8s-proxmox/cluster-api-provider-proxmox
4+
PROJECT := mojaloop/cluster-api-provider-proxmox
55
RELEASE_TAG := latest
66
IMG ?= $(REGISTRY)/$(PROJECT):$(RELEASE_TAG)
77
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
@@ -331,4 +331,4 @@ $(KIND): $(LOCALBIN)
331331
@if test -x $(LOCALBIN)/kind && ! $(LOCALBIN)/kind version | grep -q $(KIND_VER); then \
332332
rm -rf $(LOCALBIN)/kind; \
333333
fi
334-
test -s $(LOCALBIN)/kind || (curl -Lo $(LOCALBIN)/kind $(KIND_DOWNLOAD_URL) && chmod +x $(LOCALBIN)/kind)
334+
test -s $(LOCALBIN)/kind || (curl -Lo $(LOCALBIN)/kind $(KIND_DOWNLOAD_URL) && chmod +x $(LOCALBIN)/kind)

‎api/v1beta1/type.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ type Image struct {
5656
ChecksumType *string `json:"checksumType,omitempty"`
5757
}
5858

59+
// ExtraDisk represents an additional virtual disk
60+
type ExtraDisk struct {
61+
Size string `json:"size,omitempty"` // e.g., "100Gi"
62+
Storage string `json:"storage,omitempty"` // e.g., "local-lvm"
63+
Type string `json:"type,omitempty"` // e.g., "scsi", "virtio"
64+
Format string `json:"format,omitempty"` //
65+
}
66+
5967
// Hardware
6068
type Hardware struct {
6169
// amount of RAM for the VM in MiB : 16 ~
@@ -94,7 +102,8 @@ type Hardware struct {
94102
// hard disk size
95103
// +kubebuilder:validation:Pattern:=\+?\d+(\.\d+)?[KMGT]?
96104
// +kubebuilder:default:="50G"
97-
Disk string `json:"disk,omitempty"`
105+
RootDisk string `json:"rootDisk,omitempty"`
106+
ExtraDisks []ExtraDisk `json:"extraDisks,omitempty"` // Add support for multiple disks
98107

99108
// network devices
100109
// to do: multiple devices

‎cloud/services/compute/instance/image.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func (s *Service) reconcileBootDevice(ctx context.Context, vm *proxmox.VirtualMa
2424

2525
// boot disk
2626
log.Info("resizing boot disk")
27-
if err := vm.ResizeVolume(ctx, bootDvice, s.scope.GetHardware().Disk); err != nil {
27+
if err := vm.ResizeVolume(ctx, bootDvice, s.scope.GetHardware().RootDisk); err != nil {
2828
return err
2929
}
3030

‎cloud/services/compute/instance/qemu.go

+80-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package instance
33
import (
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

1415
const (
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+
102134
func (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 {
168221
func (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
}

‎clusterctl.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
providers:
22
- name: proxmox
3-
url: https://github.com/k8s-proxmox/cluster-api-provider-proxmox/releases/latest/infrastructure-components.yaml
3+
url: https://github.com/mojaloop/cluster-api-provider-proxmox/releases/latest/infrastructure-components.yaml
44
type: InfrastructureProvider

‎config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxmachines.yaml

+27-2
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ spec:
226226
hardware:
227227
default:
228228
cpu: 2
229-
disk: 50G
229+
rootDisk: 50G
230230
memory: 4096
231231
networkDevice:
232232
bridge: vmbr0
@@ -256,11 +256,36 @@ spec:
256256
cpuType:
257257
description: Emulated CPU Type. Defaults to kvm64
258258
type: string
259-
disk:
259+
rootDisk:
260260
default: 50G
261261
description: hard disk size
262262
pattern: \+?\d+(\.\d+)?[KMGT]?
263263
type: string
264+
extraDisks:
265+
description: List of additional disks attached to the VM
266+
type: array
267+
items:
268+
type: object
269+
properties:
270+
size:
271+
type: string
272+
description: Size of the disk (e.g., 100G, 50G)
273+
pattern: \+?\d+(\.\d+)?[KMGT]?
274+
storage:
275+
type: string
276+
description: Storage backend to use (e.g., local-lvm, ceph, etc.)
277+
format:
278+
type: string
279+
description: Disk format (qcow2, raw, etc.)
280+
enum:
281+
- raw
282+
- qcow2
283+
slot:
284+
type: integer
285+
description: SCSI slot number for the disk
286+
required:
287+
- size
288+
- storage
264289
memory:
265290
default: 4096
266291
description: 'amount of RAM for the VM in MiB : 16 ~'

‎config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxmachinetemplates.yaml

+27-2
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ spec:
244244
hardware:
245245
default:
246246
cpu: 2
247-
disk: 50G
247+
rootDisk: 50G
248248
memory: 4096
249249
networkDevice:
250250
bridge: vmbr0
@@ -274,11 +274,36 @@ spec:
274274
cpuType:
275275
description: Emulated CPU Type. Defaults to kvm64
276276
type: string
277-
disk:
277+
rootDisk:
278278
default: 50G
279279
description: hard disk size
280280
pattern: \+?\d+(\.\d+)?[KMGT]?
281281
type: string
282+
extraDisks:
283+
description: List of additional disks attached to the VM
284+
type: array
285+
items:
286+
type: object
287+
properties:
288+
size:
289+
type: string
290+
description: Size of the disk (e.g., 100G, 50G)
291+
pattern: \+?\d+(\.\d+)?[KMGT]?
292+
storage:
293+
type: string
294+
description: Storage backend to use (e.g., local-lvm, ceph, etc.)
295+
format:
296+
type: string
297+
description: Disk format (qcow2, raw, etc.)
298+
enum:
299+
- raw
300+
- qcow2
301+
slot:
302+
type: integer
303+
description: SCSI slot number for the disk
304+
required:
305+
- size
306+
- storage
282307
memory:
283308
default: 4096
284309
description: 'amount of RAM for the VM in MiB : 16 ~'

0 commit comments

Comments
 (0)
Please sign in to comment.