Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ require (
github.com/vmware-tanzu/image-registry-operator-api v0.0.0-20250624211456-dfc90459c658
github.com/vmware-tanzu/net-operator-api v0.0.0-20250826165015-90a4bb21727b
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20250813103855-288a237381b5
github.com/vmware/govmomi v0.53.0-alpha.0.0.20250911174024-a3b63a98bfb9
github.com/vmware/govmomi v0.53.0-alpha.0.0.20250923175025-e586c7832696
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/net v0.42.0 // indirect
// * https://github.com/vmware-tanzu/vm-operator/security/dependabot/24
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ github.com/vmware-tanzu/net-operator-api v0.0.0-20250826165015-90a4bb21727b h1:4
github.com/vmware-tanzu/net-operator-api v0.0.0-20250826165015-90a4bb21727b/go.mod h1:w6QJGm3crIA16ZIz1FVQXD2NVeJhOgGXxW05RbVTSTo=
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20250813103855-288a237381b5 h1:OUPe+BjC/XWqHRWYHDCtTa/lZpEz6U8YmZcZi1Rp5BU=
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20250813103855-288a237381b5/go.mod h1:Q4JzNkNMvjo7pXtlB5/R3oME4Nhah7fAObWgghVmtxk=
github.com/vmware/govmomi v0.53.0-alpha.0.0.20250911174024-a3b63a98bfb9 h1:iUUFRkImk2noxtlV+GvGEZLMdr44qkVaW2PfrKV8jpc=
github.com/vmware/govmomi v0.53.0-alpha.0.0.20250911174024-a3b63a98bfb9/go.mod h1:MKEZBs5aGMM+J33dt2rWXP7ayDyCMKi4hO4DkH694pw=
github.com/vmware/govmomi v0.53.0-alpha.0.0.20250923175025-e586c7832696 h1:ik1abQdgfaDKsNBndP3e30JLPCkVJ3MRe4F4+5i4zvU=
github.com/vmware/govmomi v0.53.0-alpha.0.0.20250923175025-e586c7832696/go.mod h1:MKEZBs5aGMM+J33dt2rWXP7ayDyCMKi4hO4DkH694pw=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
93 changes: 53 additions & 40 deletions pkg/providers/vsphere/vmlifecycle/create_fastdeploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func fastDeploy(
}
logger.Info("Got destination file paths", "dstFilePaths", dstFilePaths)

// Collect the disks and remove the storage profile from them.
// Collect the disks.
var (
disks []*vimtypes.VirtualDisk
diskSpecs []*vimtypes.VirtualDeviceConfigSpec
Expand Down Expand Up @@ -248,7 +248,8 @@ func fastDeploy(
diskSpecs,
dstDiskFormat,
dstDiskPaths,
srcDiskPaths)
srcDiskPaths,
createArgs.IsEncryptedStorageProfile)
}

func fastDeployLinked(
Expand Down Expand Up @@ -330,45 +331,65 @@ func fastDeployDirect(
diskSpecs []*vimtypes.VirtualDeviceConfigSpec,
diskFormat vimtypes.DatastoreSectorFormat,
dstDiskPaths,
srcDiskPaths []string) (*vimtypes.ManagedObjectReference, error) {
srcDiskPaths []string,
isEncryptedStorageProfile bool) (*vimtypes.ManagedObjectReference, error) {

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

// Copy each disk into the VM directory.
if err := fastDeployDirectCopyDisks(
ctx,
logger,
datacenter,
configSpec,
srcDiskPaths,
dstDiskPaths,
diskFormat); err != nil {

return nil, err
}

_, isVMEncrypted := configSpec.Crypto.(*vimtypes.CryptoSpecEncrypt)

diskCopySpecs := make([]vimtypes.FileBackedVirtualDiskSpec, len(dstDiskPaths))
for i := range diskSpecs {
ds := diskSpecs[i]

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

if isVMEncrypted {
// If the VM is to be encrypted, then the disks need to be updated
// so they are not marked as encrypted upon VM creation. This is
// because it is not possible to change the encryption state of VM
// disks when they are being attached. Instead the disks must be
// encrypted after they are attached to the VM.
ds.Profile = nil
if ds.Backing != nil {
ds.Backing.Crypto = nil
profile := ds.Profile
if len(profile) == 0 {
profile = configSpec.VmProfile
}

diskCopySpecs[i] = vimtypes.FileBackedVirtualDiskSpec{
VirtualDiskSpec: vimtypes.VirtualDiskSpec{
AdapterType: string(vimtypes.VirtualDiskAdapterTypeLsiLogic),
DiskType: string(vimtypes.VirtualDiskTypeThin),
},
SectorFormat: string(diskFormat),
Profile: profile,
}

// Copy the disks using the same crypto key as the VM if the storage
// class is encrypted.
if isEncryptedStorageProfile && configSpec.Crypto != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like configSpec.Crypto doesn't have to be not nil, if ds.Backing.Crypto is not nil?

if ds.Backing == nil {
ds.Backing = &vimtypes.VirtualDeviceConfigSpecBackingSpec{}
}
crypto := ds.Backing.Crypto
if crypto == nil {
crypto = configSpec.Crypto
}
diskCopySpecs[i].Crypto = crypto

// Please note, the disk is added to the VM with its crypto spec
// set to nil since it is an existing disk. The disk is already
// encrypted as part of the copy operation.
ds.Profile = profile
ds.Backing.Crypto = nil
}
}

// Copy each disk into the VM directory.
if err := fastDeployDirectCopyDisks(
ctx,
logger,
datacenter,
srcDiskPaths,
dstDiskPaths,
diskCopySpecs); err != nil {

return nil, err
}

return fastDeployCreateVM(ctx, logger, folder, pool, host, configSpec)
}

Expand Down Expand Up @@ -410,43 +431,35 @@ func fastDeployDirectCopyDisks(
ctx context.Context,
logger logr.Logger,
datacenter *object.Datacenter,
configSpec vimtypes.VirtualMachineConfigSpec,
srcDiskPaths,
dstDiskPaths []string,
diskFormat vimtypes.DatastoreSectorFormat) error {
dstDiskSpecs []vimtypes.FileBackedVirtualDiskSpec) error {

var (
wg sync.WaitGroup
copyDiskTasks = make([]*object.Task, len(srcDiskPaths))
copyDiskErrs = make(chan error, len(srcDiskPaths))
copyDiskSpec = vimtypes.FileBackedVirtualDiskSpec{
VirtualDiskSpec: vimtypes.VirtualDiskSpec{
AdapterType: string(vimtypes.VirtualDiskAdapterTypeLsiLogic),
DiskType: string(vimtypes.VirtualDiskTypeThin),
},
SectorFormat: string(diskFormat),
Profile: configSpec.VmProfile,
}
diskManager = object.NewVirtualDiskManager(datacenter.Client())
diskManager = object.NewVirtualDiskManager(datacenter.Client())
)

for i := range srcDiskPaths {
s := srcDiskPaths[i]
d := dstDiskPaths[i]
c := dstDiskSpecs[i]

logger.Info(
"Copying disk",
"dstDiskPath", d,
"srcDiskPath", s,
"copyDiskSpec", copyDiskSpec)
"dstDiskSpec", c)

t, err := diskManager.CopyVirtualDisk(
ctx,
s,
datacenter,
d,
datacenter,
&copyDiskSpec,
&c,
false)
if err != nil {
logger.Error(err, "failed to copy disk, cancelling other tasks")
Expand Down
89 changes: 89 additions & 0 deletions pkg/providers/vsphere/vmprovider_vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1880,6 +1880,95 @@ func vmTests() {
v3, _ := ec.GetString(pkgconst.VMProvKeepDisksExtraConfigKey)
Expect(v3).To(Equal(path.Base(ctx.ContentLibraryItemDiskPath)))
})

When("direct mode is used", func() {
JustBeforeEach(func() {
if vm.Annotations == nil {
vm.Annotations = map[string]string{}
}
vm.Annotations[pkgconst.FastDeployAnnotationKey] = pkgconst.FastDeployModeDirect
})
It("should succeed", func() {
vcVM, err := createOrUpdateAndGetVcVM(ctx, vmProvider, vm)
Expect(err).ToNot(HaveOccurred())

var moVM mo.VirtualMachine
Expect(vcVM.Properties(
ctx,
vcVM.Reference(),
[]string{"config.extraConfig"},
&moVM)).To(Succeed())
ec := object.OptionValueList(moVM.Config.ExtraConfig)
v1, _ := ec.GetString("hello")
Expect(v1).To(Equal("world"))
v2, _ := ec.GetString("fu")
Expect(v2).To(Equal("bar"))
_, ok := ec.GetString(pkgconst.VMProvKeepDisksExtraConfigKey)
Expect(ok).To(BeFalse())
})

When("disks are encrypted", func() {
BeforeEach(func() {
pkgcfg.SetContext(parentCtx, func(config *pkgcfg.Config) {
config.Features.BringYourOwnEncryptionKey = true
})
parentCtx = vmconfig.WithContext(parentCtx)
parentCtx = vmconfig.Register(parentCtx, crypto.New())
})
JustBeforeEach(func() {
m := vimcrypto.NewManagerKmip(ctx.VCClient.Client)
Expect(m.MarkDefault(ctx, ctx.NativeKeyProviderID)).To(Succeed())

var storageClass storagev1.StorageClass
Expect(ctx.Client.Get(
ctx,
client.ObjectKey{Name: ctx.EncryptedStorageClassName},
&storageClass)).To(Succeed())
Expect(kubeutil.MarkEncryptedStorageClass(
ctx,
ctx.Client,
storageClass,
true)).To(Succeed())

vm.Spec.StorageClass = ctx.EncryptedStorageClassName
})
It("should succeed", func() {
vcVM, err := createOrUpdateAndGetVcVM(ctx, vmProvider, vm)
Expect(err).ToNot(HaveOccurred())

var moVM mo.VirtualMachine
Expect(vcVM.Properties(
ctx,
vcVM.Reference(),
[]string{"config"},
&moVM)).To(Succeed())
ec := object.OptionValueList(moVM.Config.ExtraConfig)
v1, _ := ec.GetString("hello")
Expect(v1).To(Equal("world"))
v2, _ := ec.GetString("fu")
Expect(v2).To(Equal("bar"))
_, ok := ec.GetString(pkgconst.VMProvKeepDisksExtraConfigKey)
Expect(ok).To(BeFalse())

for _, bd := range moVM.Config.Hardware.Device {
if d, ok := bd.(*vimtypes.VirtualDisk); ok {
var keyID *vimtypes.CryptoKeyId
switch tBack := d.Backing.(type) {
case *vimtypes.VirtualDiskFlatVer2BackingInfo:
keyID = tBack.KeyId
case *vimtypes.VirtualDiskSeSparseBackingInfo:
keyID = tBack.KeyId
case *vimtypes.VirtualDiskSparseVer2BackingInfo:
keyID = tBack.KeyId
}
Expect(keyID).ToNot(BeNil())
Expect(keyID.ProviderId).ToNot(BeNil())
Expect(keyID.ProviderId.Id).To(Equal(ctx.NativeKeyProviderID))
}
}
})
})
})
})
})

Expand Down