From 6fd2c4111398f050aeec0f62690984cf57215613 Mon Sep 17 00:00:00 2001 From: Zhongcheng Lao Date: Fri, 7 Nov 2025 17:49:41 +0800 Subject: [PATCH 1/2] Add supports to Crypto Spec in VMOp VirtualMachine and PVC --- apis/vmware/v1beta1/types.go | 62 +++++++++++ apis/vmware/v1beta1/vspheremachine_types.go | 13 +++ apis/vmware/v1beta1/zz_generated.deepcopy.go | 35 ++++++ ...ture.cluster.x-k8s.io_vspheremachines.yaml | 73 +++++++++++++ ...ster.x-k8s.io_vspheremachinetemplates.yaml | 73 +++++++++++++ .../vmware/vspherecluster_reconciler_test.go | 3 +- go.mod | 2 +- go.sum | 4 +- pkg/services/network/netop_provider.go | 2 +- pkg/services/network/nsxt_provider.go | 2 +- pkg/services/network/nsxt_vpc_provider.go | 6 +- .../vmoperator/control_plane_endpoint.go | 2 +- pkg/services/vmoperator/vmopmachine.go | 34 +++++- pkg/services/vmoperator/vmopmachine_test.go | 100 +++++++++++++++++- pkg/util/testutil.go | 7 +- test/framework/vmoperator/vmoperator.go | 2 +- test/go.mod | 4 +- test/go.sum | 4 +- 18 files changed, 407 insertions(+), 21 deletions(-) diff --git a/apis/vmware/v1beta1/types.go b/apis/vmware/v1beta1/types.go index 0936d111f9..ea3b12bc12 100644 --- a/apis/vmware/v1beta1/types.go +++ b/apis/vmware/v1beta1/types.go @@ -76,3 +76,65 @@ const ( // state within the configured timeout (default 5m). VirtualMachinePowerOpModeTrySoft VirtualMachinePowerOpMode = "trySoft" ) + +// VirtualMachineCryptoSpec defines the desired state of a VirtualMachine's +// encryption state. +type VirtualMachineCryptoSpec struct { + // encryptionClassName describes the name of the EncryptionClass resource + // used to encrypt this VM. + // + // Please note, this field is not required to encrypt the VM. If the + // underlying platform has a default key provider, the VM may still be fully + // or partially encrypted depending on the specified storage and VM classes. + // + // If there is a default key provider and an encryption storage class is + // selected, the files in the VM's home directory and non-PVC virtual disks + // will be encrypted + // + // If there is a default key provider and a VM Class with a virtual, trusted + // platform module (vTPM) is selected, the files in the VM's home directory, + // minus any virtual disks, will be encrypted. + // + // If the underlying vSphere platform does not have a default key provider, + // then this field is required when specifying an encryption storage class + // and/or a VM Class with a vTPM. + // + // If this field is set, spec.storageClass must use an encryption-enabled + // storage class. + // +optional + // +kubebuilder:validation:MaxLength=253 + EncryptionClassName *string `json:"encryptionClassName,omitempty"` + + // useDefaultKeyProvider describes the desired behavior for when an explicit + // EncryptionClass is not provided. + // + // When an explicit encryptionClass is not provided and this value is true: + // + // - Deploying a VirtualMachine with an encryption storage policy or vTPM + // will be encrypted using the default key provider. + // + // - If a VirtualMachine is not encrypted, uses an encryption storage + // policy or has a virtual, trusted platform module (vTPM), there is a + // default key provider, the VM will be encrypted using the default key + // provider. + // + // - If a VirtualMachine is encrypted with a provider other than the default + // key provider, the VM will be rekeyed using the default key provider. + // + // When an explicit EncryptionClass is not provided and this value is false: + // + // - Deploying a VirtualMachine with an encryption storage policy or vTPM + // will fail. + // + // - If a VirtualMachine is encrypted with a provider other than the default + // key provider, the VM will be not be rekeyed. + // + // Please note, this could result in a VirtualMachine that cannot be + // powered on since it is encrypted using a provider or key that may have + // been removed. Without the key, the VM cannot be decrypted and thus + // cannot be powered on. + // + // Defaults to true if omitted. + // +optional + UseDefaultKeyProvider *bool `json:"useDefaultKeyProvider,omitempty"` +} diff --git a/apis/vmware/v1beta1/vspheremachine_types.go b/apis/vmware/v1beta1/vspheremachine_types.go index 6014d7f115..0bbf4d46ad 100644 --- a/apis/vmware/v1beta1/vspheremachine_types.go +++ b/apis/vmware/v1beta1/vspheremachine_types.go @@ -35,6 +35,15 @@ type VSphereMachineVolume struct { // StorageClass defaults to VSphereMachineSpec.StorageClass // +optional StorageClass string `json:"storageClass,omitempty"` + // encryptionClassName describes the name of the EncryptionClass resource + // used to encrypt this volume. Defaults to VSphereMachineSpec.Crypto.EncryptionClassName. + // + // Please note, this field is not required to encrypt the volume. If the + // underlying platform has a default key provider, the volume may still be fully + // or partially encrypted depending on the specified storage. + // +optional + // +kubebuilder:validation:MaxLength=253 + EncryptionClassName *string `json:"encryptionClassName,omitempty"` } // VSphereMachineSpec defines the desired state of VSphereMachine. @@ -63,6 +72,10 @@ type VSphereMachineSpec struct { // +optional StorageClass string `json:"storageClass,omitempty"` + // crypto describes the desired encryption state of the VirtualMachine. + // +optional + Crypto *VirtualMachineCryptoSpec `json:"crypto,omitempty"` + // Volumes is the set of PVCs to be created and attached to the VSphereMachine // +optional Volumes []VSphereMachineVolume `json:"volumes,omitempty"` diff --git a/apis/vmware/v1beta1/zz_generated.deepcopy.go b/apis/vmware/v1beta1/zz_generated.deepcopy.go index e0963532f0..bd5c758acb 100644 --- a/apis/vmware/v1beta1/zz_generated.deepcopy.go +++ b/apis/vmware/v1beta1/zz_generated.deepcopy.go @@ -735,6 +735,11 @@ func (in *VSphereMachineSpec) DeepCopyInto(out *VSphereMachineSpec) { *out = new(string) **out = **in } + if in.Crypto != nil { + in, out := &in.Crypto, &out.Crypto + *out = new(VirtualMachineCryptoSpec) + (*in).DeepCopyInto(*out) + } if in.Volumes != nil { in, out := &in.Volumes, &out.Volumes *out = make([]VSphereMachineVolume, len(*in)) @@ -953,6 +958,11 @@ func (in *VSphereMachineVolume) DeepCopyInto(out *VSphereMachineVolume) { (*out)[key] = val.DeepCopy() } } + if in.EncryptionClassName != nil { + in, out := &in.EncryptionClassName, &out.EncryptionClassName + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VSphereMachineVolume. @@ -965,6 +975,31 @@ func (in *VSphereMachineVolume) DeepCopy() *VSphereMachineVolume { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineCryptoSpec) DeepCopyInto(out *VirtualMachineCryptoSpec) { + *out = *in + if in.EncryptionClassName != nil { + in, out := &in.EncryptionClassName, &out.EncryptionClassName + *out = new(string) + **out = **in + } + if in.UseDefaultKeyProvider != nil { + in, out := &in.UseDefaultKeyProvider, &out.UseDefaultKeyProvider + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineCryptoSpec. +func (in *VirtualMachineCryptoSpec) DeepCopy() *VirtualMachineCryptoSpec { + if in == nil { + return nil + } + out := new(VirtualMachineCryptoSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VirtualMachineNamingStrategy) DeepCopyInto(out *VirtualMachineNamingStrategy) { *out = *in diff --git a/config/supervisor/crd/bases/vmware.infrastructure.cluster.x-k8s.io_vspheremachines.yaml b/config/supervisor/crd/bases/vmware.infrastructure.cluster.x-k8s.io_vspheremachines.yaml index dec6dc8025..c74db56feb 100644 --- a/config/supervisor/crd/bases/vmware.infrastructure.cluster.x-k8s.io_vspheremachines.yaml +++ b/config/supervisor/crd/bases/vmware.infrastructure.cluster.x-k8s.io_vspheremachines.yaml @@ -59,6 +59,69 @@ spec: ClassName is the name of the class used when specifying the underlying virtual machine type: string + crypto: + description: crypto describes the desired encryption state of the + VirtualMachine. + properties: + encryptionClassName: + description: |- + encryptionClassName describes the name of the EncryptionClass resource + used to encrypt this VM. + + Please note, this field is not required to encrypt the VM. If the + underlying platform has a default key provider, the VM may still be fully + or partially encrypted depending on the specified storage and VM classes. + + If there is a default key provider and an encryption storage class is + selected, the files in the VM's home directory and non-PVC virtual disks + will be encrypted + + If there is a default key provider and a VM Class with a virtual, trusted + platform module (vTPM) is selected, the files in the VM's home directory, + minus any virtual disks, will be encrypted. + + If the underlying vSphere platform does not have a default key provider, + then this field is required when specifying an encryption storage class + and/or a VM Class with a vTPM. + + If this field is set, spec.storageClass must use an encryption-enabled + storage class. + maxLength: 253 + type: string + useDefaultKeyProvider: + description: |- + useDefaultKeyProvider describes the desired behavior for when an explicit + EncryptionClass is not provided. + + When an explicit encryptionClass is not provided and this value is true: + + - Deploying a VirtualMachine with an encryption storage policy or vTPM + will be encrypted using the default key provider. + + - If a VirtualMachine is not encrypted, uses an encryption storage + policy or has a virtual, trusted platform module (vTPM), there is a + default key provider, the VM will be encrypted using the default key + provider. + + - If a VirtualMachine is encrypted with a provider other than the default + key provider, the VM will be rekeyed using the default key provider. + + When an explicit EncryptionClass is not provided and this value is false: + + - Deploying a VirtualMachine with an encryption storage policy or vTPM + will fail. + + - If a VirtualMachine is encrypted with a provider other than the default + key provider, the VM will be not be rekeyed. + + Please note, this could result in a VirtualMachine that cannot be + powered on since it is encrypted using a provider or key that may have + been removed. Without the key, the VM cannot be decrypted and thus + cannot be powered on. + + Defaults to true if omitted. + type: boolean + type: object failureDomain: description: |- FailureDomain is the failure domain the machine will be created in. @@ -344,6 +407,16 @@ spec: x-kubernetes-int-or-string: true description: Capacity is the PVC capacity type: object + encryptionClassName: + description: |- + encryptionClassName describes the name of the EncryptionClass resource + used to encrypt this volume. Defaults to VSphereMachineSpec.Crypto.EncryptionClassName. + + Please note, this field is not required to encrypt the volume. If the + underlying platform has a default key provider, the volume may still be fully + or partially encrypted depending on the specified storage. + maxLength: 253 + type: string name: description: 'Name is suffix used to name this PVC as: VSphereMachine.Name + "-" + Name' diff --git a/config/supervisor/crd/bases/vmware.infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml b/config/supervisor/crd/bases/vmware.infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml index 2bec192082..f04de462ae 100644 --- a/config/supervisor/crd/bases/vmware.infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml +++ b/config/supervisor/crd/bases/vmware.infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml @@ -55,6 +55,69 @@ spec: ClassName is the name of the class used when specifying the underlying virtual machine type: string + crypto: + description: crypto describes the desired encryption state + of the VirtualMachine. + properties: + encryptionClassName: + description: |- + encryptionClassName describes the name of the EncryptionClass resource + used to encrypt this VM. + + Please note, this field is not required to encrypt the VM. If the + underlying platform has a default key provider, the VM may still be fully + or partially encrypted depending on the specified storage and VM classes. + + If there is a default key provider and an encryption storage class is + selected, the files in the VM's home directory and non-PVC virtual disks + will be encrypted + + If there is a default key provider and a VM Class with a virtual, trusted + platform module (vTPM) is selected, the files in the VM's home directory, + minus any virtual disks, will be encrypted. + + If the underlying vSphere platform does not have a default key provider, + then this field is required when specifying an encryption storage class + and/or a VM Class with a vTPM. + + If this field is set, spec.storageClass must use an encryption-enabled + storage class. + maxLength: 253 + type: string + useDefaultKeyProvider: + description: |- + useDefaultKeyProvider describes the desired behavior for when an explicit + EncryptionClass is not provided. + + When an explicit encryptionClass is not provided and this value is true: + + - Deploying a VirtualMachine with an encryption storage policy or vTPM + will be encrypted using the default key provider. + + - If a VirtualMachine is not encrypted, uses an encryption storage + policy or has a virtual, trusted platform module (vTPM), there is a + default key provider, the VM will be encrypted using the default key + provider. + + - If a VirtualMachine is encrypted with a provider other than the default + key provider, the VM will be rekeyed using the default key provider. + + When an explicit EncryptionClass is not provided and this value is false: + + - Deploying a VirtualMachine with an encryption storage policy or vTPM + will fail. + + - If a VirtualMachine is encrypted with a provider other than the default + key provider, the VM will be not be rekeyed. + + Please note, this could result in a VirtualMachine that cannot be + powered on since it is encrypted using a provider or key that may have + been removed. Without the key, the VM cannot be decrypted and thus + cannot be powered on. + + Defaults to true if omitted. + type: boolean + type: object failureDomain: description: |- FailureDomain is the failure domain the machine will be created in. @@ -341,6 +404,16 @@ spec: x-kubernetes-int-or-string: true description: Capacity is the PVC capacity type: object + encryptionClassName: + description: |- + encryptionClassName describes the name of the EncryptionClass resource + used to encrypt this volume. Defaults to VSphereMachineSpec.Crypto.EncryptionClassName. + + Please note, this field is not required to encrypt the volume. If the + underlying platform has a default key provider, the volume may still be fully + or partially encrypted depending on the specified storage. + maxLength: 253 + type: string name: description: 'Name is suffix used to name this PVC as: VSphereMachine.Name + "-" + Name' diff --git a/controllers/vmware/vspherecluster_reconciler_test.go b/controllers/vmware/vspherecluster_reconciler_test.go index f22390fd45..2eb021c19b 100644 --- a/controllers/vmware/vspherecluster_reconciler_test.go +++ b/controllers/vmware/vspherecluster_reconciler_test.go @@ -53,6 +53,7 @@ var _ = Describe("Cluster Controller Tests", func() { className = "test-className" imageName = "test-imageName" storageClass = "test-storageClass" + encryptionClass = "test-encryptionClass" testIP = "127.0.0.1" ) var ( @@ -69,7 +70,7 @@ var _ = Describe("Cluster Controller Tests", func() { cluster = util.CreateCluster(clusterName) vsphereCluster = util.CreateVSphereCluster(clusterName) clusterCtx, controllerManagerContext = util.CreateClusterContext(cluster, vsphereCluster) - vsphereMachine = util.CreateVSphereMachine(machineName, clusterName, className, imageName, storageClass, controlPlaneLabelTrue) + vsphereMachine = util.CreateVSphereMachine(machineName, clusterName, className, imageName, storageClass, encryptionClass, controlPlaneLabelTrue) reconciler = &ClusterReconciler{ Client: controllerManagerContext.Client, diff --git a/go.mod b/go.mod index f4d718c081..26eb138cf7 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ replace sigs.k8s.io/cluster-api => sigs.k8s.io/cluster-api v1.12.0-beta.1 replace github.com/vmware-tanzu/vm-operator/pkg/constants/testlabels => github.com/vmware-tanzu/vm-operator/pkg/constants/testlabels v0.0.0-20240404200847-de75746a9505 // The version of vm-operator should be kept in sync with the manifests at: config/deployments/integration-tests -replace github.com/vmware-tanzu/vm-operator/api => github.com/vmware-tanzu/vm-operator/api v1.8.6 +replace github.com/vmware-tanzu/vm-operator/api => github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719 require ( github.com/vmware-tanzu/net-operator-api v0.0.0-20240326163340-1f32d6bf7f9d diff --git a/go.sum b/go.sum index 46d428f500..5085885d15 100644 --- a/go.sum +++ b/go.sum @@ -241,8 +241,8 @@ github.com/vmware-tanzu/net-operator-api v0.0.0-20240326163340-1f32d6bf7f9d h1:c github.com/vmware-tanzu/net-operator-api v0.0.0-20240326163340-1f32d6bf7f9d/go.mod h1:JbFOh22iDsT5BowJe0GgpMI5e2/S7cWaJlv9LdURVQM= github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20241112044858-9da8637c1b0d h1:z9lrzKVtNlujduv9BilzPxuge/LE2F0N1ms3TP4JZvw= github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20241112044858-9da8637c1b0d/go.mod h1:Q4JzNkNMvjo7pXtlB5/R3oME4Nhah7fAObWgghVmtxk= -github.com/vmware-tanzu/vm-operator/api v1.8.6 h1:NIndORjcnSmIlQsCMIewpIwg/ocRVDh2lYjOroTVLrU= -github.com/vmware-tanzu/vm-operator/api v1.8.6/go.mod h1:HHA2SNI9B5Yqtyp5t+Gt9WTWBi/fIkM6+MukDDSf11A= +github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719 h1:nb/5ytRj7E/5eo9UzLfaR29JytMtbGpqMVs3hjaRwZ0= +github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719/go.mod h1:nWTPpxfe4gHuuYuFcrs86+NMxfkqPk3a3IlvI8TCWak= github.com/vmware-tanzu/vm-operator/external/ncp v0.0.0-20240404200847-de75746a9505 h1:y4wXx1FUFqqSgJ/xUOEM1DLS2Uu0KaeLADWpzpioGTU= github.com/vmware-tanzu/vm-operator/external/ncp v0.0.0-20240404200847-de75746a9505/go.mod h1:5rqRJ9zGR+KnKbkGx373WgN8xJpvAj99kHnfoDYRO5I= github.com/vmware/govmomi v0.52.0 h1:JyxQ1IQdllrY7PJbv2am9mRsv3p9xWlIQ66bv+XnyLw= diff --git a/pkg/services/network/netop_provider.go b/pkg/services/network/netop_provider.go index fa1c1860fa..e13de3bd4d 100644 --- a/pkg/services/network/netop_provider.go +++ b/pkg/services/network/netop_provider.go @@ -136,7 +136,7 @@ func (np *netopNetworkProvider) ConfigureVirtualMachine(ctx context.Context, clu // Set the VM primary interface vm.Spec.Network.Interfaces = append(vm.Spec.Network.Interfaces, vmoprv1.VirtualMachineNetworkInterfaceSpec{ Name: PrimaryInterfaceName, - Network: vmoprv1common.PartialObjectRef{ + Network: &vmoprv1common.PartialObjectRef{ TypeMeta: metav1.TypeMeta{ Kind: NetworkGVKNetOperator.Kind, APIVersion: NetworkGVKNetOperator.GroupVersion().String(), diff --git a/pkg/services/network/nsxt_provider.go b/pkg/services/network/nsxt_provider.go index 96a0450bb7..90885cb568 100644 --- a/pkg/services/network/nsxt_provider.go +++ b/pkg/services/network/nsxt_provider.go @@ -223,7 +223,7 @@ func (np *nsxtNetworkProvider) ConfigureVirtualMachine(_ context.Context, cluste } vm.Spec.Network.Interfaces = append(vm.Spec.Network.Interfaces, vmoprv1.VirtualMachineNetworkInterfaceSpec{ Name: fmt.Sprintf("eth%d", len(vm.Spec.Network.Interfaces)), - Network: vmoprv1common.PartialObjectRef{ + Network: &vmoprv1common.PartialObjectRef{ TypeMeta: metav1.TypeMeta{ Kind: NetworkGVKNSXT.Kind, APIVersion: NetworkGVKNSXT.GroupVersion().String(), diff --git a/pkg/services/network/nsxt_vpc_provider.go b/pkg/services/network/nsxt_vpc_provider.go index 0c3533a37c..9b2c8defa0 100644 --- a/pkg/services/network/nsxt_vpc_provider.go +++ b/pkg/services/network/nsxt_vpc_provider.go @@ -224,7 +224,7 @@ func (vp *nsxtVPCNetworkProvider) ConfigureVirtualMachine(_ context.Context, clu networkName := clusterCtx.VSphereCluster.Name vm.Spec.Network.Interfaces = append(vm.Spec.Network.Interfaces, vmoprv1.VirtualMachineNetworkInterfaceSpec{ Name: PrimaryInterfaceName, - Network: vmoprv1common.PartialObjectRef{ + Network: &vmoprv1common.PartialObjectRef{ TypeMeta: metav1.TypeMeta{ Kind: NetworkGVKNSXTVPCSubnetSet.Kind, APIVersion: NetworkGVKNSXTVPCSubnetSet.GroupVersion().String(), @@ -243,7 +243,7 @@ func (vp *nsxtVPCNetworkProvider) ConfigureVirtualMachine(_ context.Context, clu } vmInterface := vmoprv1.VirtualMachineNetworkInterfaceSpec{ Name: PrimaryInterfaceName, - Network: vmoprv1common.PartialObjectRef{ + Network: &vmoprv1common.PartialObjectRef{ TypeMeta: metav1.TypeMeta{ Kind: primary.Network.Kind, APIVersion: primary.Network.APIVersion, @@ -281,7 +281,7 @@ func setVMSecondaryInterfaces(machine *vmwarev1.VSphereMachine, vm *vmoprv1.Virt } vmInterface := vmoprv1.VirtualMachineNetworkInterfaceSpec{ Name: secondaryInterface.Name, - Network: vmoprv1common.PartialObjectRef{ + Network: &vmoprv1common.PartialObjectRef{ TypeMeta: metav1.TypeMeta{ Kind: secondaryInterface.Network.Kind, APIVersion: secondaryInterface.Network.APIVersion, diff --git a/pkg/services/vmoperator/control_plane_endpoint.go b/pkg/services/vmoperator/control_plane_endpoint.go index e0070188e3..3b500711d7 100644 --- a/pkg/services/vmoperator/control_plane_endpoint.go +++ b/pkg/services/vmoperator/control_plane_endpoint.go @@ -189,7 +189,7 @@ func newVirtualMachineService(ctx *vmware.ClusterContext) *vmoprv1.VirtualMachin Namespace: ctx.Cluster.Namespace, }, TypeMeta: metav1.TypeMeta{ - APIVersion: vmoprv1.SchemeGroupVersion.String(), + APIVersion: vmoprv1.GroupVersion.String(), Kind: "VirtualMachineService", }, } diff --git a/pkg/services/vmoperator/vmopmachine.go b/pkg/services/vmoperator/vmopmachine.go index 840b166406..1ea62e755c 100644 --- a/pkg/services/vmoperator/vmopmachine.go +++ b/pkg/services/vmoperator/vmopmachine.go @@ -46,6 +46,10 @@ import ( infrautilv1 "sigs.k8s.io/cluster-api-provider-vsphere/pkg/util" ) +const ( + csiEncryptionClassAnnotationKey = "csi.vsphere.encryption-class" +) + // VmopMachineService reconciles VM Operator VM. type VmopMachineService struct { Client client.Client @@ -415,6 +419,16 @@ func (v *VmopMachineService) reconcileVMOperatorVM(ctx context.Context, supervis if vmOperatorVM.Spec.StorageClass == "" { vmOperatorVM.Spec.StorageClass = supervisorMachineCtx.VSphereMachine.Spec.StorageClass } + // Sets VM crypto based on VSphereMachine input + if supervisorMachineCtx.VSphereMachine.Spec.Crypto != nil { + vmOperatorVM.Spec.Crypto = &vmoprv1.VirtualMachineCryptoSpec{} + if supervisorMachineCtx.VSphereMachine.Spec.Crypto.EncryptionClassName != nil { + vmOperatorVM.Spec.Crypto.EncryptionClassName = *supervisorMachineCtx.VSphereMachine.Spec.Crypto.EncryptionClassName + } + vmOperatorVM.Spec.Crypto.UseDefaultKeyProvider = supervisorMachineCtx.VSphereMachine.Spec.Crypto.UseDefaultKeyProvider + } else { + vmOperatorVM.Spec.Crypto = nil + } vmOperatorVM.Spec.PowerState = vmoprv1.VirtualMachinePowerStateOn if supervisorMachineCtx.VSphereCluster.Status.ResourcePolicyName != "" { if vmOperatorVM.Spec.Reserved == nil { @@ -710,6 +724,13 @@ func (v *VmopMachineService) addVolumes(ctx context.Context, supervisorMachineCt if volume.StorageClass == "" { storageClassName = supervisorMachineCtx.VSphereMachine.Spec.StorageClass } + var encryptionClassName string + if volume.EncryptionClassName != nil { + encryptionClassName = *volume.EncryptionClassName + } + if encryptionClassName == "" && supervisorMachineCtx.VSphereMachine.Spec.Crypto != nil && supervisorMachineCtx.VSphereMachine.Spec.Crypto.EncryptionClassName != nil { + encryptionClassName = *supervisorMachineCtx.VSphereMachine.Spec.Crypto.EncryptionClassName + } pvc := &corev1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ @@ -733,6 +754,7 @@ func (v *VmopMachineService) addVolumes(ctx context.Context, supervisorMachineCt // have the zone annotation set. zonal := len(supervisorMachineCtx.VSphereCluster.Status.FailureDomains) > 1 + annotations := map[string]string{} if zone := supervisorMachineCtx.VSphereMachine.Spec.FailureDomain; zonal && zone != nil { topology := []map[string]string{ {kubeTopologyZoneLabelKey: *zone}, @@ -741,9 +763,15 @@ func (v *VmopMachineService) addVolumes(ctx context.Context, supervisorMachineCt if err != nil { return errors.Errorf("failed to marshal zone topology %q: %s", *zone, err) } - pvc.Annotations = map[string]string{ - "csi.vsphere.volume-requested-topology": string(b), - } + annotations["csi.vsphere.volume-requested-topology"] = string(b) + } + + if encryptionClassName != "" { + annotations[csiEncryptionClassAnnotationKey] = encryptionClassName + } + + if len(annotations) > 0 { + pvc.Annotations = annotations } if _, err := ctrlutil.CreateOrPatch(ctx, v.Client, pvc, func() error { diff --git a/pkg/services/vmoperator/vmopmachine_test.go b/pkg/services/vmoperator/vmopmachine_test.go index aa91556341..aa17bcc88c 100644 --- a/pkg/services/vmoperator/vmopmachine_test.go +++ b/pkg/services/vmoperator/vmopmachine_test.go @@ -73,6 +73,7 @@ const ( className = "test-className" imageName = "test-imageName" storageClass = "test-storageClass" + encryptionClass = "test-encryptionClass" resourcePolicyName = "test-resourcePolicy" minHardwareVersion = int32(17) vmIP = "127.0.0.1" @@ -120,7 +121,7 @@ var _ = Describe("VirtualMachine tests", func() { vsphereCluster = util.CreateVSphereCluster(clusterName) vsphereCluster.Status.ResourcePolicyName = resourcePolicyName machine = util.CreateMachine(machineName, clusterName, k8sVersion, controlPlaneLabelTrue) - vsphereMachine = util.CreateVSphereMachine(machineName, clusterName, className, imageName, storageClass, controlPlaneLabelTrue) + vsphereMachine = util.CreateVSphereMachine(machineName, clusterName, className, imageName, storageClass, encryptionClass, controlPlaneLabelTrue) clusterContext, controllerManagerContext := util.CreateClusterContext(cluster, vsphereCluster) supervisorMachineContext = util.CreateMachineContext(clusterContext, machine, vsphereMachine) supervisorMachineContext.ControllerManagerContext = controllerManagerContext @@ -152,6 +153,7 @@ var _ = Describe("VirtualMachine tests", func() { Expect(vmopVM.Spec.ImageName).To(Equal(expectedImageName)) Expect(vmopVM.Spec.ClassName).To(Equal(className)) Expect(vmopVM.Spec.StorageClass).To(Equal(storageClass)) + Expect(vmopVM.Spec.Crypto.EncryptionClassName).To(Equal(encryptionClass)) Expect(vmopVM.Spec.Reserved).ToNot(BeNil()) Expect(vmopVM.Spec.Reserved.ResourcePolicyName).To(Equal(resourcePolicyName)) Expect(vmopVM.Spec.MinHardwareVersion).To(Equal(minHardwareVersion)) @@ -655,6 +657,100 @@ var _ = Describe("VirtualMachine tests", func() { Expect(vmopVM.Spec.Volumes[i]).To(BeEquivalentTo(vmVolume)) } }) + + Specify("PVC creation and verification", func() { + expectReconcileError = false + expectVMOpVM = true + expectedImageName = imageName + expectedRequeue = true + + etcdCapacity := resource.MustParse("1Gi") + containerdCapacity := resource.MustParse("6Gi") + + vsphereMachine.Spec.Volumes = []vmwarev1.VSphereMachineVolume{ + { + Name: "etcd", + StorageClass: storageClass, + Capacity: corev1.ResourceList{ + corev1.ResourceStorage: etcdCapacity, + }, + }, + { + Name: "containerd", + EncryptionClassName: ptr.To(encryptionClass), + Capacity: corev1.ResourceList{ + corev1.ResourceStorage: containerdCapacity, + }, + }, + } + + By("VirtualMachine is created with volumes") + requeue, err = vmService.ReconcileNormal(ctx, supervisorMachineContext) + verifyOutput(supervisorMachineContext) + + By("Verifying PVCs are created") + for _, volume := range vsphereMachine.Spec.Volumes { + pvcName := volumeName(vsphereMachine, volume) + pvc := &corev1.PersistentVolumeClaim{} + pvcKey := types.NamespacedName{ + Namespace: vsphereMachine.Namespace, + Name: pvcName, + } + + err := vmService.Client.Get(ctx, pvcKey, pvc) + Expect(err).NotTo(HaveOccurred()) + + By("Verifying PVC metadata") + Expect(pvc.Name).To(Equal(pvcName)) + Expect(pvc.Namespace).To(Equal(vsphereMachine.Namespace)) + + By("Verifying PVC spec") + Expect(pvc.Spec.AccessModes).To(ContainElement(corev1.ReadWriteOnce)) + Expect(pvc.Spec.Resources.Requests).To(HaveKeyWithValue(corev1.ResourceStorage, volume.Capacity[corev1.ResourceStorage])) + Expect(pvc.Spec.StorageClassName).NotTo(BeNil()) + + // Verify storage class - should use volume-specific or fallback to machine-level + expectedStorageClass := volume.StorageClass + if expectedStorageClass == "" { + expectedStorageClass = vsphereMachine.Spec.StorageClass + } + Expect(*pvc.Spec.StorageClassName).To(Equal(expectedStorageClass)) + + By("Verifying owner reference") + Expect(pvc.OwnerReferences).To(HaveLen(1)) + ownerRef := pvc.OwnerReferences[0] + Expect(ownerRef.Kind).To(Equal("VSphereMachine")) + Expect(ownerRef.Name).To(Equal(vsphereMachine.Name)) + Expect(ownerRef.UID).To(Equal(vsphereMachine.UID)) + + By("Verifying encryption class annotation when set") + if volume.EncryptionClassName != nil && *volume.EncryptionClassName != "" { + Expect(pvc.Annotations).To(HaveKey(csiEncryptionClassAnnotationKey)) + Expect(pvc.Annotations[csiEncryptionClassAnnotationKey]).To(Equal(*volume.EncryptionClassName)) + } + } + + By("Verifying etcd PVC has volume-specific storage class") + etcdPVC := &corev1.PersistentVolumeClaim{} + etcdPVCKey := types.NamespacedName{ + Namespace: vsphereMachine.Namespace, + Name: volumeName(vsphereMachine, vsphereMachine.Spec.Volumes[0]), + } + err := vmService.Client.Get(ctx, etcdPVCKey, etcdPVC) + Expect(err).NotTo(HaveOccurred()) + Expect(*etcdPVC.Spec.StorageClassName).To(Equal(storageClass)) + + By("Verifying containerd PVC has encryption class annotation") + containerdPVC := &corev1.PersistentVolumeClaim{} + containerdPVCKey := types.NamespacedName{ + Namespace: vsphereMachine.Namespace, + Name: volumeName(vsphereMachine, vsphereMachine.Spec.Volumes[1]), + } + err = vmService.Client.Get(ctx, containerdPVCKey, containerdPVC) + Expect(err).NotTo(HaveOccurred()) + Expect(containerdPVC.Annotations).To(HaveKey(csiEncryptionClassAnnotationKey)) + Expect(containerdPVC.Annotations[csiEncryptionClassAnnotationKey]).To(Equal(encryptionClass)) + }) }) Context("Delete tests", func() { @@ -719,7 +815,7 @@ var _ = Describe("VirtualMachine tests", func() { var _ = Describe("GetMachinesInCluster", func() { initObjs := []client.Object{ - util.CreateVSphereMachine(machineName, clusterName, className, imageName, storageClass, controlPlaneLabelTrue), + util.CreateVSphereMachine(machineName, clusterName, className, imageName, storageClass, encryptionClass, controlPlaneLabelTrue), } controllerManagerContext := fake.NewControllerManagerContext(initObjs...) diff --git a/pkg/util/testutil.go b/pkg/util/testutil.go index 9d6a877e10..250d54ea26 100644 --- a/pkg/util/testutil.go +++ b/pkg/util/testutil.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/klog/v2" + "k8s.io/utils/ptr" bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2" clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -112,7 +113,7 @@ func CreateMachine(machineName, clusterName, k8sVersion string, controlPlaneLabe return machine } -func CreateVSphereMachine(machineName, clusterName, className, imageName, storageClass string, controlPlaneLabel bool) *vmwarev1.VSphereMachine { +func CreateVSphereMachine(machineName, clusterName, className, imageName, storageClass, encryptionClass string, controlPlaneLabel bool) *vmwarev1.VSphereMachine { vsphereMachine := &vmwarev1.VSphereMachine{ TypeMeta: metav1.TypeMeta{ APIVersion: vmwarev1.GroupVersion.String(), @@ -137,6 +138,10 @@ func CreateVSphereMachine(machineName, clusterName, className, imageName, storag labels[clusterv1.MachineControlPlaneLabel] = "" vsphereMachine.SetLabels(labels) } + if encryptionClass != "" { + vsphereMachine.Spec.Crypto = &vmwarev1.VirtualMachineCryptoSpec{} + vsphereMachine.Spec.Crypto.EncryptionClassName = ptr.To(encryptionClass) + } return vsphereMachine } diff --git a/test/framework/vmoperator/vmoperator.go b/test/framework/vmoperator/vmoperator.go index c80ec76545..2c1e367b01 100644 --- a/test/framework/vmoperator/vmoperator.go +++ b/test/framework/vmoperator/vmoperator.go @@ -534,7 +534,7 @@ func ReconcileDependencies(ctx context.Context, c client.Client, dependenciesCon Namespace: config.Namespace, }, Spec: vmoprv1.VirtualMachineImageSpec{ - ProviderRef: vmoprv1common.LocalObjectRef{ + ProviderRef: &vmoprv1common.LocalObjectRef{ Kind: "ContentLibraryItem", }, }, diff --git a/test/go.mod b/test/go.mod index f6b15719b3..8eca8b8cc9 100644 --- a/test/go.mod +++ b/test/go.mod @@ -11,12 +11,12 @@ replace sigs.k8s.io/cluster-api-provider-vsphere => ../ replace github.com/vmware-tanzu/vm-operator/pkg/constants/testlabels => github.com/vmware-tanzu/vm-operator/pkg/constants/testlabels v0.0.0-20240404200847-de75746a9505 // The version of vm-operator should be kept in sync with the manifests at: config/deployments/integration-testsz -replace github.com/vmware-tanzu/vm-operator/api => github.com/vmware-tanzu/vm-operator/api v1.8.6 +replace github.com/vmware-tanzu/vm-operator/api => github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719 require ( github.com/vmware-tanzu/net-operator-api v0.0.0-20240326163340-1f32d6bf7f9d // The version of vm-operator should be kept in sync with the manifests at: config/deployments/integration-tests - github.com/vmware-tanzu/vm-operator/api v1.8.6 + github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719 github.com/vmware/govmomi v0.52.0 ) diff --git a/test/go.sum b/test/go.sum index 7966a7d359..c3ec7c7673 100644 --- a/test/go.sum +++ b/test/go.sum @@ -362,8 +362,8 @@ github.com/vmware-tanzu/net-operator-api v0.0.0-20240326163340-1f32d6bf7f9d h1:c github.com/vmware-tanzu/net-operator-api v0.0.0-20240326163340-1f32d6bf7f9d/go.mod h1:JbFOh22iDsT5BowJe0GgpMI5e2/S7cWaJlv9LdURVQM= github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20241112044858-9da8637c1b0d h1:z9lrzKVtNlujduv9BilzPxuge/LE2F0N1ms3TP4JZvw= github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20241112044858-9da8637c1b0d/go.mod h1:Q4JzNkNMvjo7pXtlB5/R3oME4Nhah7fAObWgghVmtxk= -github.com/vmware-tanzu/vm-operator/api v1.8.6 h1:NIndORjcnSmIlQsCMIewpIwg/ocRVDh2lYjOroTVLrU= -github.com/vmware-tanzu/vm-operator/api v1.8.6/go.mod h1:HHA2SNI9B5Yqtyp5t+Gt9WTWBi/fIkM6+MukDDSf11A= +github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719 h1:nb/5ytRj7E/5eo9UzLfaR29JytMtbGpqMVs3hjaRwZ0= +github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719/go.mod h1:nWTPpxfe4gHuuYuFcrs86+NMxfkqPk3a3IlvI8TCWak= github.com/vmware-tanzu/vm-operator/external/ncp v0.0.0-20240404200847-de75746a9505 h1:y4wXx1FUFqqSgJ/xUOEM1DLS2Uu0KaeLADWpzpioGTU= github.com/vmware-tanzu/vm-operator/external/ncp v0.0.0-20240404200847-de75746a9505/go.mod h1:5rqRJ9zGR+KnKbkGx373WgN8xJpvAj99kHnfoDYRO5I= github.com/vmware/govmomi v0.52.0 h1:JyxQ1IQdllrY7PJbv2am9mRsv3p9xWlIQ66bv+XnyLw= From ce9801bb568ec320477c7f7bad9cd11676fe9155 Mon Sep 17 00:00:00 2001 From: Zhongcheng Lao Date: Mon, 17 Nov 2025 16:45:23 +0800 Subject: [PATCH 2/2] Add Encryption Class to the vcsim test --- test/e2e/e2e_setup_test.go | 16 +++++ test/e2e/ownerrefs_finalizers_test.go | 1 + test/framework/vmoperator/vmoperator.go | 61 ++++++++++++++++ .../v1alpha1/vmoperatordependencies_types.go | 24 ++++++- .../api/v1alpha1/zz_generated.deepcopy.go | 20 ++++++ ...cryption.vmware.com_encryptionclasses.yaml | 71 +++++++++++++++++++ ...uster.x-k8s.io_vmoperatordependencies.yaml | 17 +++++ .../vcsim/config/crd/kustomization.yaml | 1 + .../vcsim/config/rbac/role.yaml | 10 +++ .../vcsim/controllers/vcsim_controller.go | 1 + 10 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 test/infrastructure/vcsim/config/crd/bases/encryption.vmware.com_encryptionclasses.yaml diff --git a/test/e2e/e2e_setup_test.go b/test/e2e/e2e_setup_test.go index 4a00f46b3d..61ba620961 100644 --- a/test/e2e/e2e_setup_test.go +++ b/test/e2e/e2e_setup_test.go @@ -420,6 +420,22 @@ func setupNamespaceWithVMOperatorDependenciesVCenter(managementClusterProxy fram }, } + // Add EncryptionClass if configured + if e2eConfig.HasVariable("VSPHERE_ENCRYPTION_CLASS_NAME") { + encryptionClass := vcsimv1.EncryptionClass{ + Name: e2eConfig.MustGetVariable("VSPHERE_ENCRYPTION_CLASS_NAME"), + KeyProvider: e2eConfig.MustGetVariable("VSPHERE_ENCRYPTION_CLASS_KEY_PROVIDER"), + KeyID: e2eConfig.MustGetVariable("VSPHERE_ENCRYPTION_CLASS_KEY_ID"), + } + // Check if this should be the default EncryptionClass + if e2eConfig.HasVariable("VSPHERE_ENCRYPTION_CLASS_DEFAULT") { + if e2eConfig.MustGetVariable("VSPHERE_ENCRYPTION_CLASS_DEFAULT") == "true" { + encryptionClass.Default = true + } + } + dependenciesConfig.Spec.EncryptionClasses = []vcsimv1.EncryptionClass{encryptionClass} + } + items := e2eConfig.MustGetVariable("VSPHERE_CONTENT_LIBRARY_ITEMS") if items != "" { for _, i := range strings.Split(e2eConfig.MustGetVariable("VSPHERE_CONTENT_LIBRARY_ITEMS"), ",") { diff --git a/test/e2e/ownerrefs_finalizers_test.go b/test/e2e/ownerrefs_finalizers_test.go index 1b51ff5f39..bbdd6eb9d3 100644 --- a/test/e2e/ownerrefs_finalizers_test.go +++ b/test/e2e/ownerrefs_finalizers_test.go @@ -238,6 +238,7 @@ var ( "VirtualMachineClassBinding": func(_ types.NamespacedName, _ []metav1.OwnerReference) error { return nil }, "VirtualMachineClass": func(_ types.NamespacedName, _ []metav1.OwnerReference) error { return nil }, "VMOperatorDependencies": func(_ types.NamespacedName, _ []metav1.OwnerReference) error { return nil }, + "EncryptionClass": func(_ types.NamespacedName, _ []metav1.OwnerReference) error { return nil }, } } diff --git a/test/framework/vmoperator/vmoperator.go b/test/framework/vmoperator/vmoperator.go index 2c1e367b01..1bbafa1d35 100644 --- a/test/framework/vmoperator/vmoperator.go +++ b/test/framework/vmoperator/vmoperator.go @@ -38,6 +38,8 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog/v2" ctrl "sigs.k8s.io/controller-runtime" @@ -453,6 +455,65 @@ func ReconcileDependencies(ctx context.Context, c client.Client, dependenciesCon } } + // Create EncryptionClass in K8s + encryptionClassGVR := schema.GroupVersionResource{ + Group: "encryption.vmware.com", + Version: "v1alpha1", + Resource: "encryptionclasses", + } + for _, ec := range config.Spec.EncryptionClasses { + metadata := map[string]interface{}{ + "name": ec.Name, + "namespace": config.Namespace, + } + // Add default label if this is the default EncryptionClass + if ec.Default { + metadata["labels"] = map[string]interface{}{ + "encryption.vmware.com/default": "true", + } + } + + spec := map[string]interface{}{} + spec["keyProvider"] = ec.KeyProvider + spec["keyID"] = ec.KeyID + + encryptionClass := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "encryption.vmware.com/v1alpha1", + "kind": "EncryptionClass", + "metadata": metadata, + "spec": spec, + }, + } + _ = wait.PollUntilContextTimeout(ctx, 250*time.Millisecond, 5*time.Second, true, func(ctx context.Context) (bool, error) { + retryError = nil + existing := &unstructured.Unstructured{} + existing.SetGroupVersionKind(schema.GroupVersionKind{ + Group: encryptionClassGVR.Group, + Version: encryptionClassGVR.Version, + Kind: "EncryptionClass", + }) + if err := c.Get(ctx, client.ObjectKey{ + Name: ec.Name, + Namespace: config.Namespace, + }, existing); err != nil { + if !apierrors.IsNotFound(err) { + retryError = errors.Wrapf(err, "failed to get EncryptionClass %s", ec.Name) + return false, nil + } + if err := c.Create(ctx, encryptionClass); err != nil { + retryError = errors.Wrapf(err, "failed to create EncryptionClass %s", ec.Name) + return false, nil + } + log.Info("Created EncryptionClass", "EncryptionClass", klog.KRef(config.Namespace, ec.Name)) + } + return true, nil + }) + if retryError != nil { + return retryError + } + } + // Create a ContentLibrary in K8s and in vCenter, // This requires a set of objects in vCenter(or vcsim) as well as their mapping in K8s // - vCenter: a Library containing an Item diff --git a/test/infrastructure/vcsim/api/v1alpha1/vmoperatordependencies_types.go b/test/infrastructure/vcsim/api/v1alpha1/vmoperatordependencies_types.go index 87bbf929db..eb8414ef8b 100644 --- a/test/infrastructure/vcsim/api/v1alpha1/vmoperatordependencies_types.go +++ b/test/infrastructure/vcsim/api/v1alpha1/vmoperatordependencies_types.go @@ -45,6 +45,9 @@ type VMOperatorDependenciesSpec struct { // VirtualMachineClasses defines a list of VirtualMachineClasses to be bound to the namespace where this object is created. VirtualMachineClasses []VirtualMachineClass `json:"virtualMachineClasses,omitempty"` + + // EncryptionClasses defines a list of EncryptionClasses to be created in the namespace where this object is created. + EncryptionClasses []EncryptionClass `json:"encryptionClasses,omitempty"` } // VMOperatorRef provide a reference to the running instance of vm-operator. @@ -80,6 +83,14 @@ type VirtualMachineClass struct { Memory resource.Quantity `json:"memory,omitempty"` } +type EncryptionClass struct { + Name string `json:"name,omitempty"` + KeyProvider string `json:"keyProvider,omitempty"` + KeyID string `json:"keyID,omitempty"` + // Default indicates if this EncryptionClass should be marked as default + Default bool `json:"default,omitempty"` +} + type ContentLibraryItemFilesConfig struct { Name string `json:"name,omitempty"` Content []byte `json:"content,omitempty"` @@ -179,7 +190,7 @@ func (d *VMOperatorDependencies) SetVCenterFromVCenterSimulator(vCenterSimulator ) } - // Add default storage and vm class for vcsim in not otherwise specified. + // Add default storage and vm class for vcsim if not otherwise specified. if len(d.Spec.StorageClasses) == 0 { d.Spec.StorageClasses = []StorageClass{ { @@ -197,4 +208,15 @@ func (d *VMOperatorDependencies) SetVCenterFromVCenterSimulator(vCenterSimulator }, } } + // Add default encryption class for vcsim if not otherwise specified. + if len(d.Spec.EncryptionClasses) == 0 { + d.Spec.EncryptionClasses = []EncryptionClass{ + { + Name: "vcsim-default-encryption-class", + KeyProvider: "vcsim-key-provider", + KeyID: "vcsim-key-id", + Default: true, + }, + } + } } diff --git a/test/infrastructure/vcsim/api/v1alpha1/zz_generated.deepcopy.go b/test/infrastructure/vcsim/api/v1alpha1/zz_generated.deepcopy.go index 8c249cf3b6..4ea717f59d 100644 --- a/test/infrastructure/vcsim/api/v1alpha1/zz_generated.deepcopy.go +++ b/test/infrastructure/vcsim/api/v1alpha1/zz_generated.deepcopy.go @@ -227,6 +227,21 @@ func (in *ControlPlaneEndpointStatus) DeepCopy() *ControlPlaneEndpointStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EncryptionClass) DeepCopyInto(out *EncryptionClass) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EncryptionClass. +func (in *EncryptionClass) DeepCopy() *EncryptionClass { + if in == nil { + return nil + } + out := new(EncryptionClass) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EnvVar) DeepCopyInto(out *EnvVar) { *out = *in @@ -609,6 +624,11 @@ func (in *VMOperatorDependenciesSpec) DeepCopyInto(out *VMOperatorDependenciesSp (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.EncryptionClasses != nil { + in, out := &in.EncryptionClasses, &out.EncryptionClasses + *out = make([]EncryptionClass, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VMOperatorDependenciesSpec. diff --git a/test/infrastructure/vcsim/config/crd/bases/encryption.vmware.com_encryptionclasses.yaml b/test/infrastructure/vcsim/config/crd/bases/encryption.vmware.com_encryptionclasses.yaml new file mode 100644 index 0000000000..1718eb5c0c --- /dev/null +++ b/test/infrastructure/vcsim/config/crd/bases/encryption.vmware.com_encryptionclasses.yaml @@ -0,0 +1,71 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: encryptionclasses.encryption.vmware.com +spec: + group: encryption.vmware.com + names: + kind: EncryptionClass + listKind: EncryptionClassList + plural: encryptionclasses + shortNames: + - encclass + singular: encryptionclass + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.keyProvider + name: KeyProvider + type: string + - jsonPath: .spec.keyID + name: KeyID + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: EncryptionClass is the Schema for the encryptionclasses API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: EncryptionClassSpec defines the desired state of EncryptionClass. + properties: + keyID: + description: |- + KeyID describes the key used to encrypt/recrypt/decrypt resources. + When omitted, a key will be generated from the specified provider. + type: string + keyProvider: + description: |- + KeyProvider describes the key provider used to encrypt/recrypt/decrypt + resources. + type: string + required: + - keyProvider + type: object + status: + description: EncryptionClassStatus defines the observed state of EncryptionClass. + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/test/infrastructure/vcsim/config/crd/bases/vcsim.infrastructure.cluster.x-k8s.io_vmoperatordependencies.yaml b/test/infrastructure/vcsim/config/crd/bases/vcsim.infrastructure.cluster.x-k8s.io_vmoperatordependencies.yaml index 0ea1327693..6e03f84dd1 100644 --- a/test/infrastructure/vcsim/config/crd/bases/vcsim.infrastructure.cluster.x-k8s.io_vmoperatordependencies.yaml +++ b/test/infrastructure/vcsim/config/crd/bases/vcsim.infrastructure.cluster.x-k8s.io_vmoperatordependencies.yaml @@ -43,6 +43,23 @@ spec: VMOperatorDependenciesSpec defines the desired state of the VMOperatorDependencies in the namespace where this object is created. properties: + encryptionClasses: + description: EncryptionClasses defines a list of EncryptionClasses + to be created in the namespace where this object is created. + items: + properties: + default: + description: Default indicates if this EncryptionClass should + be marked as default + type: boolean + keyID: + type: string + keyProvider: + type: string + name: + type: string + type: object + type: array operatorRef: description: OperatorRef provides a reference to the running instance of vm-operator. diff --git a/test/infrastructure/vcsim/config/crd/kustomization.yaml b/test/infrastructure/vcsim/config/crd/kustomization.yaml index 0f9667c1af..24d15f43c1 100644 --- a/test/infrastructure/vcsim/config/crd/kustomization.yaml +++ b/test/infrastructure/vcsim/config/crd/kustomization.yaml @@ -11,6 +11,7 @@ resources: - bases/vcsim.infrastructure.cluster.x-k8s.io_controlplaneendpoints.yaml - bases/vcsim.infrastructure.cluster.x-k8s.io_envvars.yaml - bases/vcsim.infrastructure.cluster.x-k8s.io_vmoperatordependencies.yaml + - bases/encryption.vmware.com_encryptionclasses.yaml patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. diff --git a/test/infrastructure/vcsim/config/rbac/role.yaml b/test/infrastructure/vcsim/config/rbac/role.yaml index cad30de703..44e447ac1c 100644 --- a/test/infrastructure/vcsim/config/rbac/role.yaml +++ b/test/infrastructure/vcsim/config/rbac/role.yaml @@ -56,6 +56,16 @@ rules: - get - list - watch +- apiGroups: + - encryption.vmware.com + resources: + - encryptionclasses + verbs: + - create + - get + - list + - update + - watch - apiGroups: - infrastructure.cluster.x-k8s.io resources: diff --git a/test/infrastructure/vcsim/controllers/vcsim_controller.go b/test/infrastructure/vcsim/controllers/vcsim_controller.go index 9e6ee8bad5..1ab5633246 100644 --- a/test/infrastructure/vcsim/controllers/vcsim_controller.go +++ b/test/infrastructure/vcsim/controllers/vcsim_controller.go @@ -79,6 +79,7 @@ type VCenterSimulatorReconciler struct { // +kubebuilder:rbac:groups=vmoperator.vmware.com,resources=virtualmachineimages,verbs=get;list;watch;create // +kubebuilder:rbac:groups=vmoperator.vmware.com,resources=virtualmachineimages/status,verbs=get;update;patch // +kubebuilder:rbac:groups=storage.k8s.io,resources=storageclasses,verbs=get;list;watch;create +// +kubebuilder:rbac:groups=encryption.vmware.com,resources=encryptionclasses,verbs=get;list;watch;create;update // +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch // +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create // +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create