Skip to content

Commit 38f6b67

Browse files
authored
✨ Add ability to configure data disk provision type during clone (#3332)
* Updated proposal to include provisioning types * Added data disk provisioning types * Added data disk provisioning types e2e
1 parent ed30520 commit 38f6b67

File tree

9 files changed

+215
-21
lines changed

9 files changed

+215
-21
lines changed

apis/v1beta1/types.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,30 @@ type VSphereDisk struct {
220220
// SizeGiB is the size of the disk in GiB.
221221
// +kubebuilder:validation:Required
222222
SizeGiB int32 `json:"sizeGiB"`
223+
// ProvisioningMode specifies the provisioning type to be used by this vSphere data disk.
224+
// If not set, the setting will be provided by the default storage policy.
225+
// +optional
226+
ProvisioningMode ProvisioningMode `json:"provisioningMode,omitempty"`
223227
}
224228

229+
// ProvisioningMode represents the various provisioning types available to a VMs disk.
230+
// +kubebuilder:validation:Enum=Thin;Thick;EagerlyZeroed
231+
type ProvisioningMode string
232+
233+
var (
234+
// ThinProvisioningMode creates the disk using thin provisioning. This means a sparse (allocate on demand)
235+
// format with additional space optimizations.
236+
ThinProvisioningMode ProvisioningMode = "Thin"
237+
238+
// ThickProvisioningMode creates the disk with all space allocated.
239+
ThickProvisioningMode ProvisioningMode = "Thick"
240+
241+
// EagerlyZeroedProvisioningMode creates the disk using eager zero provisioning. An eager zeroed thick disk
242+
// has all space allocated and wiped clean of any previous contents on the physical media at
243+
// creation time. Such disks may take longer time during creation compared to other disk formats.
244+
EagerlyZeroedProvisioningMode ProvisioningMode = "EagerlyZeroed"
245+
)
246+
225247
// VSphereMachineTemplateResource describes the data needed to create a VSphereMachine from a template.
226248
type VSphereMachineTemplateResource struct {
227249

config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachines.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,15 @@ spec:
986986
Name is used to identify the disk definition. Name is required and needs to be unique so that it can be used to
987987
clearly identify purpose of the disk.
988988
type: string
989+
provisioningMode:
990+
description: |-
991+
ProvisioningMode specifies the provisioning type to be used by this vSphere data disk.
992+
If not set, the setting will be provided by the default storage policy.
993+
enum:
994+
- Thin
995+
- Thick
996+
- EagerlyZeroed
997+
type: string
989998
sizeGiB:
990999
description: SizeGiB is the size of the disk in GiB.
9911000
format: int32

config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,15 @@ spec:
856856
Name is used to identify the disk definition. Name is required and needs to be unique so that it can be used to
857857
clearly identify purpose of the disk.
858858
type: string
859+
provisioningMode:
860+
description: |-
861+
ProvisioningMode specifies the provisioning type to be used by this vSphere data disk.
862+
If not set, the setting will be provided by the default storage policy.
863+
enum:
864+
- Thin
865+
- Thick
866+
- EagerlyZeroed
867+
type: string
859868
sizeGiB:
860869
description: SizeGiB is the size of the disk in GiB.
861870
format: int32

config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspherevms.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,15 @@ spec:
10761076
Name is used to identify the disk definition. Name is required and needs to be unique so that it can be used to
10771077
clearly identify purpose of the disk.
10781078
type: string
1079+
provisioningMode:
1080+
description: |-
1081+
ProvisioningMode specifies the provisioning type to be used by this vSphere data disk.
1082+
If not set, the setting will be provided by the default storage policy.
1083+
enum:
1084+
- Thin
1085+
- Thick
1086+
- EagerlyZeroed
1087+
type: string
10791088
sizeGiB:
10801089
description: SizeGiB is the size of the disk in GiB.
10811090
format: int32

docs/proposal/20241003-data-disk-support.md

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ title: CAPV Additional Data Disks When Creating New Machines
66
authors:
77
- "@vr4manta"
88
reviewers:
9-
- TBD
9+
- "@chrischdi"
10+
- "@neolit123"
1011
creation-date: 2024-10-03
1112
last-updated: 2024-10-03
1213
status: implementable
@@ -113,9 +114,33 @@ type VSphereDisk struct {
113114
// SizeGiB is the size of the disk (in GiB).
114115
// +kubebuilder:validation:Required
115116
SizeGiB int32 `json:"sizeGiB"`
117+
// ProvisioningMode specifies the provisioning type to be used by this vSphere data disk.
118+
// If not set, the setting will be provided by the default storage policy.
119+
// +optional
120+
ProvisioningMode ProvisioningMode `json:"provisioningMode,omitempty"`
116121
}
117122
```
118123

124+
Provisioning type currently will be represented by the following configuration options:
125+
126+
```go
127+
type ProvisioningType string
128+
129+
var (
130+
// ThinProvisioningMode creates the disk using thin provisioning. This means a sparse (allocate on demand)
131+
// format with additional space optimizations.
132+
ThinProvisioningMode ProvisioningMode = "Thin"
133+
134+
// ThickProvisioningMode creates the disk with all space allocated.
135+
ThickProvisioningMode ProvisioningMode = "Thick"
136+
137+
// EagerlyZeroedProvisioningMode creates the disk using eager zero provisioning. An eager zeroed thick disk
138+
// has all space allocated and wiped clean of any previous contents on the physical media at
139+
// creation time. Such disks may take longer time during creation compared to other disk formats.
140+
EagerlyZeroedProvisioningMode ProvisioningMode = "EagerlyZeroed"
141+
)
142+
```
143+
119144
The above type has been added to the machine spec section
120145

121146
```go
@@ -148,8 +173,10 @@ spec:
148173
dataDisks:
149174
- name: images
150175
sizeGiB: 50
176+
provisioningType: Thin
151177
- name: swap
152178
sizeGiB: 90
179+
provisioningType: Thick
153180
cloneMode: linkedClone
154181
datacenter: cidatacenter
155182
datastore: /cidatacenter/datastore/vsanDatastore
@@ -175,8 +202,10 @@ spec:
175202
dataDisks:
176203
- name: images
177204
sizeGiB: 50
205+
provisioningType: Thin
178206
- name: swap
179207
sizeGiB: 90
208+
provisioningType: Thick
180209
datacenter: cidatacenter
181210
datastore: /cidatacenter/datastore/vsanDatastore
182211
diskGiB: 128
@@ -193,7 +222,7 @@ spec:
193222

194223
```
195224

196-
In the above examples, two data disks will be created during the clone process and placed after the OS disk. The example shows a 50 GiB with name `images` and a 90 GiB disk with name `swap` being configured and added.
225+
In the above examples, two data disks will be created during the clone process and placed after the OS disk. The example shows a 50 GiB with name `images` that will be thin provisioned and a 90 GiB disk with name `swap` that will be thick provisioned being configured and added.
197226

198227
For each `dataDisks` definition, the clone procedure will attempt to generate a device VirtualDeviceConfigSpec that will be used to create the new disk device. Each disk will be attached in the order in which they are defined in the template. All disks defined in the vSphere OVA template will come first with the new disks being attached after.
199228

pkg/services/govmomi/vcenter/clone.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -433,18 +433,34 @@ func createDataDisks(ctx context.Context, dataDiskDefs []infrav1.VSphereDisk, de
433433
for i, dataDisk := range dataDiskDefs {
434434
log.V(2).Info("Adding disk", "name", dataDisk.Name, "spec", dataDisk)
435435

436+
backing := &types.VirtualDiskFlatVer2BackingInfo{
437+
DiskMode: string(types.VirtualDiskModePersistent),
438+
VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
439+
FileName: "",
440+
},
441+
}
442+
443+
// Set provisioning type for the new data disk.
444+
// Currently, if ThinProvisioned is not set, GOVC will set default to false. We may want to change this behavior
445+
// to match what template image OS disk has configured to make them match if not set.
446+
switch dataDisk.ProvisioningMode {
447+
case infrav1.ThinProvisioningMode:
448+
backing.ThinProvisioned = types.NewBool(true)
449+
case infrav1.ThickProvisioningMode:
450+
backing.ThinProvisioned = types.NewBool(false)
451+
case infrav1.EagerlyZeroedProvisioningMode:
452+
backing.ThinProvisioned = types.NewBool(false)
453+
backing.EagerlyScrub = types.NewBool(true)
454+
default:
455+
log.V(2).Info("No provisioning type detected. Leaving configuration empty.")
456+
}
457+
436458
dev := &types.VirtualDisk{
437459
VirtualDevice: types.VirtualDevice{
438460
// Key needs to be unique and cannot match another new disk being added. So we'll use the index as an
439461
// input to NewKey. NewKey() will always return same value since our new devices are not part of devices yet.
440-
Key: devices.NewKey() - int32(i),
441-
Backing: &types.VirtualDiskFlatVer2BackingInfo{
442-
DiskMode: string(types.VirtualDiskModePersistent),
443-
ThinProvisioned: types.NewBool(true),
444-
VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
445-
FileName: "",
446-
},
447-
},
462+
Key: devices.NewKey() - int32(i),
463+
Backing: backing,
448464
ControllerKey: controller.GetVirtualController().Key,
449465
},
450466
CapacityInKB: int64(dataDisk.SizeGiB) * 1024 * 1024,

pkg/services/govmomi/vcenter/clone_test.go

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"testing"
2424

25+
"github.com/onsi/gomega"
2526
"github.com/vmware/govmomi/object"
2627
"github.com/vmware/govmomi/simulator"
2728
_ "github.com/vmware/govmomi/vapi/simulator" // run init func to register the tagging API endpoints.
@@ -184,51 +185,81 @@ func TestCreateDataDisks(t *testing.T) {
184185
name: "Add data disk with 1 ova disk",
185186
devices: deviceList,
186187
controller: controller,
187-
dataDisks: createDataDiskDefinitions(1),
188+
dataDisks: createDataDiskDefinitions(1, nil),
188189
expectedUnitNumber: []int{1},
189190
},
190191
{
191192
name: "Add data disk with 2 ova disk",
192193
devices: createAdditionalDisks(deviceList, controller, 1),
193194
controller: controller,
194-
dataDisks: createDataDiskDefinitions(1),
195+
dataDisks: createDataDiskDefinitions(1, nil),
195196
expectedUnitNumber: []int{2},
196197
},
197198
{
198199
name: "Add multiple data disk with 1 ova disk",
199200
devices: deviceList,
200201
controller: controller,
201-
dataDisks: createDataDiskDefinitions(2),
202+
dataDisks: createDataDiskDefinitions(2, nil),
202203
expectedUnitNumber: []int{1, 2},
203204
},
204205
{
205206
name: "Add too many data disks with 1 ova disk",
206207
devices: deviceList,
207208
controller: controller,
208-
dataDisks: createDataDiskDefinitions(30),
209+
dataDisks: createDataDiskDefinitions(30, nil),
209210
err: "all unit numbers are already in-use",
210211
},
211212
{
212213
name: "Add data disk with no ova disk",
213214
devices: nil,
214215
controller: nil,
215-
dataDisks: createDataDiskDefinitions(1),
216+
dataDisks: createDataDiskDefinitions(1, nil),
216217
err: "Invalid disk count: 0",
217218
},
218219
{
219220
name: "Add too many data disks with 1 ova disk",
220221
devices: deviceList,
221222
controller: controller,
222-
dataDisks: createDataDiskDefinitions(40),
223+
dataDisks: createDataDiskDefinitions(40, nil),
223224
err: "all unit numbers are already in-use",
224225
},
226+
{
227+
name: "Create data disk with Thin provisioning",
228+
devices: deviceList,
229+
controller: controller,
230+
dataDisks: createDataDiskDefinitions(1, &infrav1.ThinProvisioningMode),
231+
expectedUnitNumber: []int{1},
232+
},
233+
{
234+
name: "Create data disk with Thick provisioning",
235+
devices: deviceList,
236+
controller: controller,
237+
dataDisks: createDataDiskDefinitions(1, &infrav1.ThickProvisioningMode),
238+
expectedUnitNumber: []int{1},
239+
},
240+
{
241+
name: "Create data disk with EagerZeroed provisioning",
242+
devices: deviceList,
243+
controller: controller,
244+
dataDisks: createDataDiskDefinitions(1, &infrav1.EagerlyZeroedProvisioningMode),
245+
expectedUnitNumber: []int{1},
246+
},
247+
{
248+
name: "Create data disk without provisioning type set",
249+
devices: deviceList,
250+
controller: controller,
251+
dataDisks: createDataDiskDefinitions(1, nil),
252+
expectedUnitNumber: []int{1},
253+
},
225254
}
226255

227256
for _, test := range testCases {
228257
tc := test
229258
t.Run(tc.name, func(t *testing.T) {
230259
var funcError error
231260

261+
g := gomega.NewWithT(t)
262+
232263
// Create the data disks
233264
newDisks, funcError := createDataDisks(ctx.TODO(), tc.dataDisks, tc.devices)
234265
if (tc.err != "" && funcError == nil) || (tc.err == "" && funcError != nil) || (funcError != nil && tc.err != funcError.Error()) {
@@ -255,6 +286,24 @@ func TestCreateDataDisks(t *testing.T) {
255286
if tc.err == "" && unitNumber != int32(tc.expectedUnitNumber[index]) {
256287
t.Fatalf("Expected to get unitNumber '%d' error from assignUnitNumber, got: '%d'", tc.expectedUnitNumber[index], unitNumber)
257288
}
289+
290+
// Check to see if the provision type matches.
291+
backingInfo := disk.GetVirtualDeviceConfigSpec().Device.GetVirtualDevice().Backing.(*types.VirtualDiskFlatVer2BackingInfo)
292+
switch tc.dataDisks[index].ProvisioningMode {
293+
case infrav1.ThinProvisioningMode:
294+
g.Expect(backingInfo.ThinProvisioned).To(gomega.Equal(types.NewBool(true)))
295+
g.Expect(backingInfo.EagerlyScrub).To(gomega.BeNil())
296+
case infrav1.ThickProvisioningMode:
297+
g.Expect(backingInfo.ThinProvisioned).To(gomega.Equal(types.NewBool(false)))
298+
g.Expect(backingInfo.EagerlyScrub).To(gomega.BeNil())
299+
case infrav1.EagerlyZeroedProvisioningMode:
300+
g.Expect(backingInfo.ThinProvisioned).To(gomega.Equal(types.NewBool(false)))
301+
g.Expect(backingInfo.EagerlyScrub).To(gomega.Equal(types.NewBool(true)))
302+
default:
303+
// Currently, if not set, GOVC will set default to false. We may want to change this behavior to match what template image OS disk is to make them match if not set.
304+
g.Expect(backingInfo.ThinProvisioned).To(gomega.BeNil())
305+
g.Expect(backingInfo.EagerlyScrub).To(gomega.BeNil())
306+
}
258307
}
259308
}
260309
})
@@ -296,14 +345,17 @@ func createVirtualDisk(key int32, controller types.BaseVirtualController, diskSi
296345
return dev
297346
}
298347

299-
func createDataDiskDefinitions(numOfDataDisks int) []infrav1.VSphereDisk {
348+
func createDataDiskDefinitions(numOfDataDisks int, provisionType *infrav1.ProvisioningMode) []infrav1.VSphereDisk {
300349
disks := []infrav1.VSphereDisk{}
301350

302351
for i := 0; i < numOfDataDisks; i++ {
303352
disk := infrav1.VSphereDisk{
304353
Name: fmt.Sprintf("disk_%d", i),
305354
SizeGiB: 10 * int32(i),
306355
}
356+
if provisionType != nil {
357+
disk.ProvisioningMode = *provisionType
358+
}
307359
disks = append(disks, disk)
308360
}
309361
return disks

test/e2e/data/infrastructure-vsphere-govmomi/main/multi-disk/data-disks-patch.yaml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ spec:
88
spec:
99
dataDisks:
1010
- name: "disk_1"
11-
sizeGiB: 10
11+
sizeGiB: 1
12+
provisioningType: "Thin"
1213
- name: "disk_2"
13-
sizeGiB: 20
14+
sizeGiB: 2
15+
provisioningType: "Thick"
1416
---
1517
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
1618
kind: VSphereMachineTemplate
@@ -22,4 +24,13 @@ spec:
2224
spec:
2325
dataDisks:
2426
- name: "disk_1"
25-
sizeGiB: 20
27+
sizeGiB: 1
28+
provisioningType: "Thin"
29+
- name: "disk_2"
30+
sizeGiB: 2
31+
provisioningType: "Thick"
32+
- name: "disk_3"
33+
sizeGiB: 3
34+
provisioningType: "EagerlyZeroed"
35+
- name: "disk_4"
36+
sizeGiB: 4

0 commit comments

Comments
 (0)