Skip to content

Commit 75f164b

Browse files
committed
Encrypt disks on copy for fast deploy direct
This patch updates Fast Deploy's direct mode to encrypt disks as part of the copy operation instead of after the fact.
1 parent 5acdb66 commit 75f164b

File tree

4 files changed

+146
-42
lines changed

4 files changed

+146
-42
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module github.com/vmware-tanzu/vm-operator
22

33
go 1.24.4
44

5+
replace github.com/vmware/govmomi => github.com/akutz/govmomi v0.28.1-0.20250923171507-b1ee1fbc4bff
6+
57
replace (
68
github.com/vmware-tanzu/vm-operator/api => ./api
79
github.com/vmware-tanzu/vm-operator/external/appplatform => ./external/appplatform

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/akutz/govmomi v0.28.1-0.20250923171507-b1ee1fbc4bff h1:r0GHglFjeqYlYr67oDnJdEAm8/s57BB5kgKVAUc6c/g=
2+
github.com/akutz/govmomi v0.28.1-0.20250923171507-b1ee1fbc4bff/go.mod h1:MKEZBs5aGMM+J33dt2rWXP7ayDyCMKi4hO4DkH694pw=
13
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
24
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
35
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
@@ -120,8 +122,6 @@ github.com/vmware-tanzu/net-operator-api v0.0.0-20250826165015-90a4bb21727b h1:4
120122
github.com/vmware-tanzu/net-operator-api v0.0.0-20250826165015-90a4bb21727b/go.mod h1:w6QJGm3crIA16ZIz1FVQXD2NVeJhOgGXxW05RbVTSTo=
121123
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20250813103855-288a237381b5 h1:OUPe+BjC/XWqHRWYHDCtTa/lZpEz6U8YmZcZi1Rp5BU=
122124
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20250813103855-288a237381b5/go.mod h1:Q4JzNkNMvjo7pXtlB5/R3oME4Nhah7fAObWgghVmtxk=
123-
github.com/vmware/govmomi v0.53.0-alpha.0.0.20250911174024-a3b63a98bfb9 h1:iUUFRkImk2noxtlV+GvGEZLMdr44qkVaW2PfrKV8jpc=
124-
github.com/vmware/govmomi v0.53.0-alpha.0.0.20250911174024-a3b63a98bfb9/go.mod h1:MKEZBs5aGMM+J33dt2rWXP7ayDyCMKi4hO4DkH694pw=
125125
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
126126
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
127127
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

pkg/providers/vsphere/vmlifecycle/create_fastdeploy.go

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func fastDeploy(
6666
}
6767
logger.Info("Got destination file paths", "dstFilePaths", dstFilePaths)
6868

69-
// Collect the disks and remove the storage profile from them.
69+
// Collect the disks.
7070
var (
7171
disks []*vimtypes.VirtualDisk
7272
diskSpecs []*vimtypes.VirtualDeviceConfigSpec
@@ -248,7 +248,8 @@ func fastDeploy(
248248
diskSpecs,
249249
dstDiskFormat,
250250
dstDiskPaths,
251-
srcDiskPaths)
251+
srcDiskPaths,
252+
createArgs.IsEncryptedStorageProfile)
252253
}
253254

254255
func fastDeployLinked(
@@ -330,45 +331,65 @@ func fastDeployDirect(
330331
diskSpecs []*vimtypes.VirtualDeviceConfigSpec,
331332
diskFormat vimtypes.DatastoreSectorFormat,
332333
dstDiskPaths,
333-
srcDiskPaths []string) (*vimtypes.ManagedObjectReference, error) {
334+
srcDiskPaths []string,
335+
isEncryptedStorageProfile bool) (*vimtypes.ManagedObjectReference, error) {
334336

335337
logger := pkglog.FromContextOrDefault(ctx).WithName("fastDeployDirect")
336338

337-
// Copy each disk into the VM directory.
338-
if err := fastDeployDirectCopyDisks(
339-
ctx,
340-
logger,
341-
datacenter,
342-
configSpec,
343-
srcDiskPaths,
344-
dstDiskPaths,
345-
diskFormat); err != nil {
346-
347-
return nil, err
348-
}
349-
350-
_, isVMEncrypted := configSpec.Crypto.(*vimtypes.CryptoSpecEncrypt)
351-
339+
diskCopySpecs := make([]vimtypes.FileBackedVirtualDiskSpec, len(dstDiskPaths))
352340
for i := range diskSpecs {
353341
ds := diskSpecs[i]
354342

355343
// Set the file operation to an empty string since the disk already
356344
// exists.
357345
ds.FileOperation = ""
358346

359-
if isVMEncrypted {
360-
// If the VM is to be encrypted, then the disks need to be updated
361-
// so they are not marked as encrypted upon VM creation. This is
362-
// because it is not possible to change the encryption state of VM
363-
// disks when they are being attached. Instead the disks must be
364-
// encrypted after they are attached to the VM.
365-
ds.Profile = nil
366-
if ds.Backing != nil {
367-
ds.Backing.Crypto = nil
347+
profile := ds.Profile
348+
if len(profile) == 0 {
349+
profile = configSpec.VmProfile
350+
}
351+
352+
diskCopySpecs[i] = vimtypes.FileBackedVirtualDiskSpec{
353+
VirtualDiskSpec: vimtypes.VirtualDiskSpec{
354+
AdapterType: string(vimtypes.VirtualDiskAdapterTypeLsiLogic),
355+
DiskType: string(vimtypes.VirtualDiskTypeThin),
356+
},
357+
SectorFormat: string(diskFormat),
358+
Profile: profile,
359+
}
360+
361+
// Copy the disks using the same crypto key as the VM if the storage
362+
// class is encrypted.
363+
if isEncryptedStorageProfile && configSpec.Crypto != nil {
364+
if ds.Backing == nil {
365+
ds.Backing = &vimtypes.VirtualDeviceConfigSpecBackingSpec{}
366+
}
367+
crypto := ds.Backing.Crypto
368+
if crypto == nil {
369+
crypto = configSpec.Crypto
368370
}
371+
diskCopySpecs[i].Crypto = crypto
372+
373+
// Please note, the disk is added to the VM with its crypto spec
374+
// set to nil since it is an existing disk. The disk is already
375+
// encrypted as part of the copy operation.
376+
ds.Profile = profile
377+
ds.Backing.Crypto = nil
369378
}
370379
}
371380

381+
// Copy each disk into the VM directory.
382+
if err := fastDeployDirectCopyDisks(
383+
ctx,
384+
logger,
385+
datacenter,
386+
srcDiskPaths,
387+
dstDiskPaths,
388+
diskCopySpecs); err != nil {
389+
390+
return nil, err
391+
}
392+
372393
return fastDeployCreateVM(ctx, logger, folder, pool, host, configSpec)
373394
}
374395

@@ -410,43 +431,35 @@ func fastDeployDirectCopyDisks(
410431
ctx context.Context,
411432
logger logr.Logger,
412433
datacenter *object.Datacenter,
413-
configSpec vimtypes.VirtualMachineConfigSpec,
414434
srcDiskPaths,
415435
dstDiskPaths []string,
416-
diskFormat vimtypes.DatastoreSectorFormat) error {
436+
dstDiskSpecs []vimtypes.FileBackedVirtualDiskSpec) error {
417437

418438
var (
419439
wg sync.WaitGroup
420440
copyDiskTasks = make([]*object.Task, len(srcDiskPaths))
421441
copyDiskErrs = make(chan error, len(srcDiskPaths))
422-
copyDiskSpec = vimtypes.FileBackedVirtualDiskSpec{
423-
VirtualDiskSpec: vimtypes.VirtualDiskSpec{
424-
AdapterType: string(vimtypes.VirtualDiskAdapterTypeLsiLogic),
425-
DiskType: string(vimtypes.VirtualDiskTypeThin),
426-
},
427-
SectorFormat: string(diskFormat),
428-
Profile: configSpec.VmProfile,
429-
}
430-
diskManager = object.NewVirtualDiskManager(datacenter.Client())
442+
diskManager = object.NewVirtualDiskManager(datacenter.Client())
431443
)
432444

433445
for i := range srcDiskPaths {
434446
s := srcDiskPaths[i]
435447
d := dstDiskPaths[i]
448+
c := dstDiskSpecs[i]
436449

437450
logger.Info(
438451
"Copying disk",
439452
"dstDiskPath", d,
440453
"srcDiskPath", s,
441-
"copyDiskSpec", copyDiskSpec)
454+
"dstDiskSpec", c)
442455

443456
t, err := diskManager.CopyVirtualDisk(
444457
ctx,
445458
s,
446459
datacenter,
447460
d,
448461
datacenter,
449-
&copyDiskSpec,
462+
&c,
450463
false)
451464
if err != nil {
452465
logger.Error(err, "failed to copy disk, cancelling other tasks")

pkg/providers/vsphere/vmprovider_vm_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,95 @@ func vmTests() {
18811881
v3, _ := ec.GetString(pkgconst.VMProvKeepDisksExtraConfigKey)
18821882
Expect(v3).To(Equal(path.Base(ctx.ContentLibraryItemDiskPath)))
18831883
})
1884+
1885+
When("direct mode is used", func() {
1886+
JustBeforeEach(func() {
1887+
if vm.Annotations == nil {
1888+
vm.Annotations = map[string]string{}
1889+
}
1890+
vm.Annotations[pkgconst.FastDeployAnnotationKey] = pkgconst.FastDeployModeDirect
1891+
})
1892+
It("should succeed", func() {
1893+
vcVM, err := createOrUpdateAndGetVcVM(ctx, vmProvider, vm)
1894+
Expect(err).ToNot(HaveOccurred())
1895+
1896+
var moVM mo.VirtualMachine
1897+
Expect(vcVM.Properties(
1898+
ctx,
1899+
vcVM.Reference(),
1900+
[]string{"config.extraConfig"},
1901+
&moVM)).To(Succeed())
1902+
ec := object.OptionValueList(moVM.Config.ExtraConfig)
1903+
v1, _ := ec.GetString("hello")
1904+
Expect(v1).To(Equal("world"))
1905+
v2, _ := ec.GetString("fu")
1906+
Expect(v2).To(Equal("bar"))
1907+
_, ok := ec.GetString(pkgconst.VMProvKeepDisksExtraConfigKey)
1908+
Expect(ok).To(BeFalse())
1909+
})
1910+
1911+
When("disks are encrypted", func() {
1912+
BeforeEach(func() {
1913+
pkgcfg.SetContext(parentCtx, func(config *pkgcfg.Config) {
1914+
config.Features.BringYourOwnEncryptionKey = true
1915+
})
1916+
parentCtx = vmconfig.WithContext(parentCtx)
1917+
parentCtx = vmconfig.Register(parentCtx, crypto.New())
1918+
})
1919+
JustBeforeEach(func() {
1920+
m := vimcrypto.NewManagerKmip(ctx.VCClient.Client)
1921+
Expect(m.MarkDefault(ctx, ctx.NativeKeyProviderID)).To(Succeed())
1922+
1923+
var storageClass storagev1.StorageClass
1924+
Expect(ctx.Client.Get(
1925+
ctx,
1926+
client.ObjectKey{Name: ctx.EncryptedStorageClassName},
1927+
&storageClass)).To(Succeed())
1928+
Expect(kubeutil.MarkEncryptedStorageClass(
1929+
ctx,
1930+
ctx.Client,
1931+
storageClass,
1932+
true)).To(Succeed())
1933+
1934+
vm.Spec.StorageClass = ctx.EncryptedStorageClassName
1935+
})
1936+
It("should succeed", func() {
1937+
vcVM, err := createOrUpdateAndGetVcVM(ctx, vmProvider, vm)
1938+
Expect(err).ToNot(HaveOccurred())
1939+
1940+
var moVM mo.VirtualMachine
1941+
Expect(vcVM.Properties(
1942+
ctx,
1943+
vcVM.Reference(),
1944+
[]string{"config"},
1945+
&moVM)).To(Succeed())
1946+
ec := object.OptionValueList(moVM.Config.ExtraConfig)
1947+
v1, _ := ec.GetString("hello")
1948+
Expect(v1).To(Equal("world"))
1949+
v2, _ := ec.GetString("fu")
1950+
Expect(v2).To(Equal("bar"))
1951+
_, ok := ec.GetString(pkgconst.VMProvKeepDisksExtraConfigKey)
1952+
Expect(ok).To(BeFalse())
1953+
1954+
for _, bd := range moVM.Config.Hardware.Device {
1955+
if d, ok := bd.(*vimtypes.VirtualDisk); ok {
1956+
var keyID *vimtypes.CryptoKeyId
1957+
switch tBack := d.Backing.(type) {
1958+
case *vimtypes.VirtualDiskFlatVer2BackingInfo:
1959+
keyID = tBack.KeyId
1960+
case *vimtypes.VirtualDiskSeSparseBackingInfo:
1961+
keyID = tBack.KeyId
1962+
case *vimtypes.VirtualDiskSparseVer2BackingInfo:
1963+
keyID = tBack.KeyId
1964+
}
1965+
Expect(keyID).ToNot(BeNil())
1966+
Expect(keyID.ProviderId).ToNot(BeNil())
1967+
Expect(keyID.ProviderId.Id).To(Equal(ctx.NativeKeyProviderID))
1968+
}
1969+
}
1970+
})
1971+
})
1972+
})
18841973
})
18851974
})
18861975

0 commit comments

Comments
 (0)