From db9d2d7490da22262ddc0e89125bf772e2588716 Mon Sep 17 00:00:00 2001 From: Jan Jansen Date: Wed, 3 May 2023 15:08:03 +0200 Subject: [PATCH] :sparkles: allow other identity in vmmachine Signed-off-by: Jan Jansen --- apis/v1alpha3/zz_generated.conversion.go | 1 + apis/v1alpha4/zz_generated.conversion.go | 1 + apis/v1beta1/types.go | 5 ++ apis/v1beta1/zz_generated.deepcopy.go | 5 ++ ...ture.cluster.x-k8s.io_vspheremachines.yaml | 19 ++++++++ ...ster.x-k8s.io_vspheremachinetemplates.yaml | 20 ++++++++ ...structure.cluster.x-k8s.io_vspherevms.yaml | 19 ++++++++ controllers/vspherevm_controller.go | 47 +++++++++++++------ pkg/identity/identity.go | 17 ++++--- pkg/identity/identity_test.go | 6 +-- 10 files changed, 116 insertions(+), 24 deletions(-) diff --git a/apis/v1alpha3/zz_generated.conversion.go b/apis/v1alpha3/zz_generated.conversion.go index 5983bdc72c..50c7deffed 100644 --- a/apis/v1alpha3/zz_generated.conversion.go +++ b/apis/v1alpha3/zz_generated.conversion.go @@ -1689,5 +1689,6 @@ func autoConvert_v1beta1_VirtualMachineCloneSpec_To_v1alpha3_VirtualMachineClone // WARNING: in.PciDevices requires manual conversion: does not exist in peer-type // WARNING: in.OS requires manual conversion: does not exist in peer-type // WARNING: in.HardwareVersion requires manual conversion: does not exist in peer-type + // WARNING: in.IdentityRef requires manual conversion: does not exist in peer-type return nil } diff --git a/apis/v1alpha4/zz_generated.conversion.go b/apis/v1alpha4/zz_generated.conversion.go index 253fa6ff0d..8ed7eb5bbb 100644 --- a/apis/v1alpha4/zz_generated.conversion.go +++ b/apis/v1alpha4/zz_generated.conversion.go @@ -1847,5 +1847,6 @@ func autoConvert_v1beta1_VirtualMachineCloneSpec_To_v1alpha4_VirtualMachineClone // WARNING: in.PciDevices requires manual conversion: does not exist in peer-type // WARNING: in.OS requires manual conversion: does not exist in peer-type // WARNING: in.HardwareVersion requires manual conversion: does not exist in peer-type + // WARNING: in.IdentityRef requires manual conversion: does not exist in peer-type return nil } diff --git a/apis/v1beta1/types.go b/apis/v1beta1/types.go index 40b543b1c4..304d1b0e20 100644 --- a/apis/v1beta1/types.go +++ b/apis/v1beta1/types.go @@ -176,6 +176,11 @@ type VirtualMachineCloneSpec struct { // Check the compatibility with the ESXi version before setting the value. // +optional HardwareVersion string `json:"hardwareVersion,omitempty"` + + // IdentityRef is a reference to either a Secret or VSphereClusterIdentity that contains + // the identity to use when reconciling the virtual machine. + // +optional + IdentityRef *VSphereIdentityReference `json:"identityRef,omitempty"` } // VSphereMachineTemplateResource describes the data needed to create a VSphereMachine from a template diff --git a/apis/v1beta1/zz_generated.deepcopy.go b/apis/v1beta1/zz_generated.deepcopy.go index 15533fcaec..443d15799e 100644 --- a/apis/v1beta1/zz_generated.deepcopy.go +++ b/apis/v1beta1/zz_generated.deepcopy.go @@ -1306,6 +1306,11 @@ func (in *VirtualMachineCloneSpec) DeepCopyInto(out *VirtualMachineCloneSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.IdentityRef != nil { + in, out := &in.IdentityRef, &out.IdentityRef + *out = new(VSphereIdentityReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineCloneSpec. diff --git a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachines.yaml b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachines.yaml index bbfff217c0..f655b96b89 100644 --- a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachines.yaml +++ b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachines.yaml @@ -903,6 +903,25 @@ spec: from which the virtual machine is cloned. Check the compatibility with the ESXi version before setting the value. type: string + identityRef: + description: IdentityRef is a reference to either a Secret or VSphereClusterIdentity + that contains the identity to use when reconciling the virtual machine. + properties: + kind: + description: Kind of the identity. Can either be VSphereClusterIdentity + or Secret + enum: + - VSphereClusterIdentity + - Secret + type: string + name: + description: Name of the identity. + minLength: 1 + type: string + required: + - kind + - name + type: object memoryMiB: description: MemoryMiB is the size of a virtual machine's memory, in MiB. Defaults to the eponymous property value in the template diff --git a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml index 697563c52e..f35a045e18 100644 --- a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml +++ b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml @@ -789,6 +789,26 @@ spec: Check the compatibility with the ESXi version before setting the value. type: string + identityRef: + description: IdentityRef is a reference to either a Secret + or VSphereClusterIdentity that contains the identity to + use when reconciling the virtual machine. + properties: + kind: + description: Kind of the identity. Can either be VSphereClusterIdentity + or Secret + enum: + - VSphereClusterIdentity + - Secret + type: string + name: + description: Name of the identity. + minLength: 1 + type: string + required: + - kind + - name + type: object memoryMiB: description: MemoryMiB is the size of a virtual machine's memory, in MiB. Defaults to the eponymous property value diff --git a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspherevms.yaml b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspherevms.yaml index 6324b355e8..6539f0693c 100644 --- a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspherevms.yaml +++ b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspherevms.yaml @@ -950,6 +950,25 @@ spec: from which the virtual machine is cloned. Check the compatibility with the ESXi version before setting the value. type: string + identityRef: + description: IdentityRef is a reference to either a Secret or VSphereClusterIdentity + that contains the identity to use when reconciling the virtual machine. + properties: + kind: + description: Kind of the identity. Can either be VSphereClusterIdentity + or Secret + enum: + - VSphereClusterIdentity + - Secret + type: string + name: + description: Name of the identity. + minLength: 1 + type: string + required: + - kind + - name + type: object memoryMiB: description: MemoryMiB is the size of a virtual machine's memory, in MiB. Defaults to the eponymous property value in the template diff --git a/controllers/vspherevm_controller.go b/controllers/vspherevm_controller.go index cd36fbf1c9..3a0864d1f8 100644 --- a/controllers/vspherevm_controller.go +++ b/controllers/vspherevm_controller.go @@ -529,28 +529,24 @@ func (r vmReconciler) retrieveVcenterSession(ctx goctx.Context, vsphereVM *infra params := session.NewParams(). WithServer(vsphereVM.Spec.Server). WithDatacenter(vsphereVM.Spec.Datacenter). - WithUserInfo(r.ControllerContext.Username, r.ControllerContext.Password). WithThumbprint(vsphereVM.Spec.Thumbprint). WithFeatures(session.Feature{ KeepAliveDuration: r.KeepAliveDuration, }) - cluster, err := clusterutilv1.GetClusterFromMetadata(r.ControllerContext, r.Client, vsphereVM.ObjectMeta) + + vsphereCluster, err := r.retrieveCluster(vsphereVM) if err != nil { - r.Logger.Info("VsphereVM is missing cluster label or cluster does not exist") - return session.GetOrCreate(r.Context, - params) + return nil, err } - key := ctrlclient.ObjectKey{ - Namespace: cluster.Namespace, - Name: cluster.Spec.InfrastructureRef.Name, - } - vsphereCluster := &infrav1.VSphereCluster{} - err = r.Client.Get(r, key, vsphereCluster) - if err != nil { - r.Logger.Info("VSphereCluster couldn't be retrieved") - return session.GetOrCreate(r.Context, - params) + if vsphereVM.Spec.IdentityRef != nil { + creds, err := identity.GetCredentialsWithExternalIdentity(ctx, r.Client, vsphereCluster, vsphereVM.Spec.IdentityRef, r.Namespace) + if err != nil { + return nil, err + } + + params = params.WithUserInfo(creds.Username, creds.Password) + return session.GetOrCreate(ctx, params) } if vsphereCluster.Spec.IdentityRef != nil { @@ -563,11 +559,32 @@ func (r vmReconciler) retrieveVcenterSession(ctx goctx.Context, vsphereVM *infra params) } + params = params.WithUserInfo(r.ControllerContext.Username, r.ControllerContext.Password) // Fallback to using credentials provided to the manager return session.GetOrCreate(r.Context, params) } +func (r vmReconciler) retrieveCluster(vsphereVM *infrav1.VSphereVM) (*infrav1.VSphereCluster, error) { + cluster, err := clusterutilv1.GetClusterFromMetadata(r.ControllerContext, r.Client, vsphereVM.ObjectMeta) + if err != nil { + r.Logger.Info("VsphereVM is missing cluster label or cluster does not exist") + return nil, err + } + + key := ctrlclient.ObjectKey{ + Namespace: cluster.Namespace, + Name: cluster.Spec.InfrastructureRef.Name, + } + vsphereCluster := &infrav1.VSphereCluster{} + err = r.Client.Get(r, key, vsphereCluster) + if err != nil { + r.Logger.Info("VSphereCluster couldn't be retrieved") + return nil, err + } + return vsphereCluster, nil +} + func (r vmReconciler) fetchClusterModuleInfo(clusterModInput fetchClusterModuleInput) (*string, error) { var ( owner ctrlclient.Object diff --git a/pkg/identity/identity.go b/pkg/identity/identity.go index 420cb4676c..bea7db8d75 100644 --- a/pkg/identity/identity.go +++ b/pkg/identity/identity.go @@ -40,12 +40,11 @@ type Credentials struct { Password string } -func GetCredentials(ctx context.Context, c client.Client, cluster *infrav1.VSphereCluster, controllerNamespace string) (*Credentials, error) { - if err := validateInputs(c, cluster); err != nil { +func GetCredentialsWithExternalIdentity(ctx context.Context, c client.Client, cluster *infrav1.VSphereCluster, ref *infrav1.VSphereIdentityReference, controllerNamespace string) (*Credentials, error) { + if err := validateInputs(c, cluster, ref); err != nil { return nil, err } - ref := cluster.Spec.IdentityRef secret := &apiv1.Secret{} var secretKey client.ObjectKey @@ -108,15 +107,21 @@ func GetCredentials(ctx context.Context, c client.Client, cluster *infrav1.VSphe return credentials, nil } -func validateInputs(c client.Client, cluster *infrav1.VSphereCluster) error { +func GetCredentials(ctx context.Context, c client.Client, cluster *infrav1.VSphereCluster, controllerNamespace string) (*Credentials, error) { + if err := validateInputs(c, cluster, cluster.Spec.IdentityRef); err != nil { + return nil, err + } + return GetCredentialsWithExternalIdentity(ctx, c, cluster, cluster.Spec.IdentityRef, controllerNamespace) +} + +func validateInputs(c client.Client, cluster *infrav1.VSphereCluster, identityRef *infrav1.VSphereIdentityReference) error { if c == nil { return errors.New("kubernetes client is required") } if cluster == nil { return errors.New("vsphere cluster is required") } - ref := cluster.Spec.IdentityRef - if ref == nil { + if identityRef == nil { return errors.New("IdentityRef is required") } return nil diff --git a/pkg/identity/identity_test.go b/pkg/identity/identity_test.go index f9f74c6fdd..cb8e5c2cd4 100644 --- a/pkg/identity/identity_test.go +++ b/pkg/identity/identity_test.go @@ -236,19 +236,19 @@ var _ = Describe("validateInputs", func() { Context("If the client is missing", func() { It("should error if client is missing", func() { - Expect(validateInputs(nil, cluster)).NotTo(Succeed()) + Expect(validateInputs(nil, cluster, nil)).NotTo(Succeed()) }) }) Context("If the cluster is missing", func() { It("should error if cluster is missing", func() { - Expect(validateInputs(k8sclient, nil)).NotTo(Succeed()) + Expect(validateInputs(k8sclient, nil, nil)).NotTo(Succeed()) }) }) Context("If the identityRef is missing on cluster", func() { It("should error if identityRef is missing on cluster", func() { - Expect(validateInputs(k8sclient, cluster)).NotTo(Succeed()) + Expect(validateInputs(k8sclient, cluster, nil)).NotTo(Succeed()) }) }) })