diff --git a/api/v1alpha3/conversion.go b/api/v1alpha3/conversion.go index d4444a2098..e1c14381cb 100644 --- a/api/v1alpha3/conversion.go +++ b/api/v1alpha3/conversion.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha3 import ( + corev1 "k8s.io/api/core/v1" conversion "k8s.io/apimachinery/pkg/conversion" ctrlconversion "sigs.k8s.io/controller-runtime/pkg/conversion" @@ -113,20 +114,37 @@ func Convert_v1alpha3_OpenStackClusterSpec_To_v1alpha4_OpenStackClusterSpec(in * return autoConvert_v1alpha3_OpenStackClusterSpec_To_v1alpha4_OpenStackClusterSpec(in, out, s) } +// Convert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec has to be added by us because we have to +// convert the Type of CloudsSecret from SecretReference to string. +func Convert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec(in *v1alpha4.OpenStackClusterSpec, out *OpenStackClusterSpec, s conversion.Scope) error { + if in.IdentityRef != nil { + out.CloudsSecret = &corev1.SecretReference{ + Name: in.IdentityRef.Name, + } + } + return autoConvert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec(in, out, s) +} + // Convert_v1alpha3_OpenStackMachineSpec_To_v1alpha4_OpenStackMachineSpec is an autogenerated conversion function. // v1alpha4 drops the field .UserDataSecret which is why we reuqire to define the function here. func Convert_v1alpha3_OpenStackMachineSpec_To_v1alpha4_OpenStackMachineSpec(in *OpenStackMachineSpec, out *v1alpha4.OpenStackMachineSpec, s conversion.Scope) error { + if in.CloudsSecret != nil { + out.IdentityRef = &v1alpha4.OpenStackIdentityReference{ + Name: in.CloudsSecret.Name, + } + } return autoConvert_v1alpha3_OpenStackMachineSpec_To_v1alpha4_OpenStackMachineSpec(in, out, s) } -// Convert_v1alpha3_OpenStackClusterSpec_To_v1alpha4_OpenStackClusterSpec has to be added by us for the new portOpts +// Convert_v1alpha4_Network_To_v1alpha3_Network has to be added by us for the new portOpts // parameter in v1alpha4. There is no intention to support this parameter in v1alpha3, so the field is just dropped. func Convert_v1alpha4_Network_To_v1alpha3_Network(in *v1alpha4.Network, out *Network, s conversion.Scope) error { return autoConvert_v1alpha4_Network_To_v1alpha3_Network(in, out, s) } -// Convert_v1alpha3_OpenStackClusterSpec_To_v1alpha4_OpenStackClusterSpec has to be added by us for the new ports +// Convert_v1alpha4_OpenStackMachineSpec_To_v1alpha3_OpenStackMachineSpec has to be added by us for the new ports // parameter in v1alpha4. There is no intention to support this parameter in v1alpha3, so the field is just dropped. +// Further, we want to convert the Type of CloudsSecret from SecretReference to string. func Convert_v1alpha4_OpenStackMachineSpec_To_v1alpha3_OpenStackMachineSpec(in *v1alpha4.OpenStackMachineSpec, out *OpenStackMachineSpec, s conversion.Scope) error { return autoConvert_v1alpha4_OpenStackMachineSpec_To_v1alpha3_OpenStackMachineSpec(in, out, s) } diff --git a/api/v1alpha3/openstackcluster_types.go b/api/v1alpha3/openstackcluster_types.go index c153c4ef05..023e30c2a1 100644 --- a/api/v1alpha3/openstackcluster_types.go +++ b/api/v1alpha3/openstackcluster_types.go @@ -33,6 +33,7 @@ type OpenStackClusterSpec struct { // The name of the secret containing the openstack credentials // +optional + // +k8s:conversion-gen=false CloudsSecret *corev1.SecretReference `json:"cloudsSecret"` // The name of the cloud to use from the clouds secret diff --git a/api/v1alpha3/openstackmachine_types.go b/api/v1alpha3/openstackmachine_types.go index 103a554537..cabe2885b8 100644 --- a/api/v1alpha3/openstackmachine_types.go +++ b/api/v1alpha3/openstackmachine_types.go @@ -38,6 +38,7 @@ type OpenStackMachineSpec struct { // The name of the secret containing the openstack credentials // +optional + // +k8s:conversion-gen=false CloudsSecret *corev1.SecretReference `json:"cloudsSecret"` // The name of the cloud to use from the clouds secret diff --git a/api/v1alpha3/zz_generated.conversion.go b/api/v1alpha3/zz_generated.conversion.go index d2c14027fe..8161ca8a68 100644 --- a/api/v1alpha3/zz_generated.conversion.go +++ b/api/v1alpha3/zz_generated.conversion.go @@ -124,11 +124,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1alpha4.OpenStackClusterSpec)(nil), (*OpenStackClusterSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec(a.(*v1alpha4.OpenStackClusterSpec), b.(*OpenStackClusterSpec), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*OpenStackClusterStatus)(nil), (*v1alpha4.OpenStackClusterStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_OpenStackClusterStatus_To_v1alpha4_OpenStackClusterStatus(a.(*OpenStackClusterStatus), b.(*v1alpha4.OpenStackClusterStatus), scope) }); err != nil { @@ -329,6 +324,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1alpha4.OpenStackClusterSpec)(nil), (*OpenStackClusterSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec(a.(*v1alpha4.OpenStackClusterSpec), b.(*OpenStackClusterSpec), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1alpha4.OpenStackClusterStatus)(nil), (*OpenStackClusterStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha4_OpenStackClusterStatus_To_v1alpha3_OpenStackClusterStatus(a.(*v1alpha4.OpenStackClusterStatus), b.(*OpenStackClusterStatus), scope) }); err != nil { @@ -675,7 +675,7 @@ func Convert_v1alpha4_OpenStackClusterList_To_v1alpha3_OpenStackClusterList(in * } func autoConvert_v1alpha3_OpenStackClusterSpec_To_v1alpha4_OpenStackClusterSpec(in *OpenStackClusterSpec, out *v1alpha4.OpenStackClusterSpec, s conversion.Scope) error { - out.CloudsSecret = (*v1.SecretReference)(unsafe.Pointer(in.CloudsSecret)) + // INFO: in.CloudsSecret opted out of conversion generation out.CloudName = in.CloudName out.NodeCIDR = in.NodeCIDR if err := Convert_v1alpha3_Filter_To_v1alpha4_Filter(&in.Network, &out.Network, s); err != nil { @@ -712,7 +712,6 @@ func autoConvert_v1alpha3_OpenStackClusterSpec_To_v1alpha4_OpenStackClusterSpec( } func autoConvert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec(in *v1alpha4.OpenStackClusterSpec, out *OpenStackClusterSpec, s conversion.Scope) error { - out.CloudsSecret = (*v1.SecretReference)(unsafe.Pointer(in.CloudsSecret)) out.CloudName = in.CloudName out.NodeCIDR = in.NodeCIDR if err := Convert_v1alpha4_Filter_To_v1alpha3_Filter(&in.Network, &out.Network, s); err != nil { @@ -744,14 +743,10 @@ func autoConvert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec( } else { out.Bastion = nil } + // INFO: in.IdentityRef opted out of conversion generation return nil } -// Convert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec is an autogenerated conversion function. -func Convert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec(in *v1alpha4.OpenStackClusterSpec, out *OpenStackClusterSpec, s conversion.Scope) error { - return autoConvert_v1alpha4_OpenStackClusterSpec_To_v1alpha3_OpenStackClusterSpec(in, out, s) -} - func autoConvert_v1alpha3_OpenStackClusterStatus_To_v1alpha4_OpenStackClusterStatus(in *OpenStackClusterStatus, out *v1alpha4.OpenStackClusterStatus, s conversion.Scope) error { out.Ready = in.Ready if in.Network != nil { @@ -908,7 +903,7 @@ func Convert_v1alpha4_OpenStackMachineList_To_v1alpha3_OpenStackMachineList(in * func autoConvert_v1alpha3_OpenStackMachineSpec_To_v1alpha4_OpenStackMachineSpec(in *OpenStackMachineSpec, out *v1alpha4.OpenStackMachineSpec, s conversion.Scope) error { out.ProviderID = (*string)(unsafe.Pointer(in.ProviderID)) out.InstanceID = (*string)(unsafe.Pointer(in.InstanceID)) - out.CloudsSecret = (*v1.SecretReference)(unsafe.Pointer(in.CloudsSecret)) + // INFO: in.CloudsSecret opted out of conversion generation out.CloudName = in.CloudName out.Flavor = in.Flavor out.Image = in.Image @@ -930,7 +925,6 @@ func autoConvert_v1alpha3_OpenStackMachineSpec_To_v1alpha4_OpenStackMachineSpec( func autoConvert_v1alpha4_OpenStackMachineSpec_To_v1alpha3_OpenStackMachineSpec(in *v1alpha4.OpenStackMachineSpec, out *OpenStackMachineSpec, s conversion.Scope) error { out.ProviderID = (*string)(unsafe.Pointer(in.ProviderID)) out.InstanceID = (*string)(unsafe.Pointer(in.InstanceID)) - out.CloudsSecret = (*v1.SecretReference)(unsafe.Pointer(in.CloudsSecret)) out.CloudName = in.CloudName out.Flavor = in.Flavor out.Image = in.Image @@ -946,6 +940,7 @@ func autoConvert_v1alpha4_OpenStackMachineSpec_To_v1alpha3_OpenStackMachineSpec( out.ConfigDrive = (*bool)(unsafe.Pointer(in.ConfigDrive)) out.RootVolume = (*RootVolume)(unsafe.Pointer(in.RootVolume)) out.ServerGroupID = in.ServerGroupID + // INFO: in.IdentityRef opted out of conversion generation return nil } diff --git a/api/v1alpha4/identity_types.go b/api/v1alpha4/identity_types.go new file mode 100644 index 0000000000..0b73bfe238 --- /dev/null +++ b/api/v1alpha4/identity_types.go @@ -0,0 +1,33 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha4 + +const defaultIdentityRefKind = "Secret" + +// OpenStackIdentityReference is a reference to an infrastructure +// provider identity to be used to provision cluster resources. +type OpenStackIdentityReference struct { + // Kind of the identity. Must be supported by the infrastructure + // provider and may be either cluster or namespace-scoped. + // +kubebuilder:validation:MinLength=1 + Kind string `json:"kind"` + + // Name of the infrastructure identity to be used. + // Must be either a cluster-scoped resource, or namespaced-scoped + // resource the same namespace as the resource(s) being provisioned. + Name string `json:"name"` +} diff --git a/api/v1alpha4/openstackcluster_types.go b/api/v1alpha4/openstackcluster_types.go index 702958e8f1..7a813db76f 100644 --- a/api/v1alpha4/openstackcluster_types.go +++ b/api/v1alpha4/openstackcluster_types.go @@ -17,7 +17,6 @@ limitations under the License. package v1alpha4 import ( - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" capierrors "sigs.k8s.io/cluster-api/errors" @@ -31,11 +30,6 @@ const ( // OpenStackClusterSpec defines the desired state of OpenStackCluster. type OpenStackClusterSpec struct { - - // The name of the secret containing the openstack credentials - // +optional - CloudsSecret *corev1.SecretReference `json:"cloudsSecret"` - // The name of the cloud to use from the clouds secret // +optional CloudName string `json:"cloudName"` @@ -106,6 +100,11 @@ type OpenStackClusterSpec struct { // Bastion is the OpenStack instance to login the nodes //+optional Bastion *Bastion `json:"bastion,omitempty"` + + // IdentityRef is a reference to a identity to be used when reconciling this cluster + // +optional + // +k8s:conversion-gen=false + IdentityRef *OpenStackIdentityReference `json:"identityRef,omitempty"` } // OpenStackClusterStatus defines the observed state of OpenStackCluster. diff --git a/api/v1alpha4/openstackcluster_webhook.go b/api/v1alpha4/openstackcluster_webhook.go index b9e58c1895..6c7a346951 100644 --- a/api/v1alpha4/openstackcluster_webhook.go +++ b/api/v1alpha4/openstackcluster_webhook.go @@ -17,9 +17,12 @@ limitations under the License. package v1alpha4 import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" "sigs.k8s.io/controller-runtime/pkg/builder" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/webhook" ) // log is for logging in this package. @@ -30,3 +33,45 @@ func (r *OpenStackCluster) SetupWebhookWithManager(mgr manager.Manager) error { For(r). Complete() } + +// +kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1alpha4-openstackcluster,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=openstackcluster,versions=v1alpha4,name=validation.openstackcluster.infrastructure.x-k8s.io,sideEffects=None,admissionReviewVersions=v1beta1 +// +kubebuilder:webhook:verbs=create;update,path=/mutate-infrastructure-cluster-x-k8s-io-v1alpha4-openstackcluster,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=openstackcluster,versions=v1alpha4,name=default.openstackcluster.infrastructure.x-k8s.io,sideEffects=None,admissionReviewVersions=v1beta1 + +var ( + _ webhook.Defaulter = &OpenStackCluster{} + _ webhook.Validator = &OpenStackCluster{} +) + +// Default satisfies the defaulting webhook interface. +func (r *OpenStackCluster) Default() { + if r.Spec.IdentityRef != nil && r.Spec.IdentityRef.Kind == "" { + r.Spec.IdentityRef.Kind = defaultIdentityRefKind + } +} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type. +func (r *OpenStackCluster) ValidateCreate() error { + var allErrs field.ErrorList + + if r.Spec.IdentityRef != nil && r.Spec.IdentityRef.Kind != defaultIdentityRefKind { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "identityRef", "kind"), "must be a Secret")) + } + + return aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs) +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type. +func (r *OpenStackCluster) ValidateUpdate(old runtime.Object) error { + var allErrs field.ErrorList + + if r.Spec.IdentityRef != nil && r.Spec.IdentityRef.Kind != defaultIdentityRefKind { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "identityRef", "kind"), "must be a Secret")) + } + + return aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs) +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type. +func (r *OpenStackCluster) ValidateDelete() error { + return nil +} diff --git a/api/v1alpha4/openstackmachine_types.go b/api/v1alpha4/openstackmachine_types.go index 997178cca8..89c16f5877 100644 --- a/api/v1alpha4/openstackmachine_types.go +++ b/api/v1alpha4/openstackmachine_types.go @@ -36,10 +36,6 @@ type OpenStackMachineSpec struct { // InstanceID is the OpenStack instance ID for this machine. InstanceID *string `json:"instanceID,omitempty"` - // The name of the secret containing the openstack credentials - // +optional - CloudsSecret *corev1.SecretReference `json:"cloudsSecret"` - // The name of the cloud to use from the clouds secret // +optional CloudName string `json:"cloudName"` @@ -90,6 +86,11 @@ type OpenStackMachineSpec struct { // The server group to assign the machine to ServerGroupID string `json:"serverGroupID,omitempty"` + + // IdentityRef is a reference to a identity to be used when reconciling this cluster + // +optional + // +k8s:conversion-gen=false + IdentityRef *OpenStackIdentityReference `json:"identityRef,omitempty"` } // OpenStackMachineStatus defines the observed state of OpenStackMachine. diff --git a/api/v1alpha4/openstackmachine_webhook.go b/api/v1alpha4/openstackmachine_webhook.go index d1e8f6459d..40f1789b88 100644 --- a/api/v1alpha4/openstackmachine_webhook.go +++ b/api/v1alpha4/openstackmachine_webhook.go @@ -39,13 +39,28 @@ func (r *OpenStackMachine) SetupWebhookWithManager(mgr manager.Manager) error { } // +kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1alpha4-openstackmachine,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=openstackmachines,versions=v1alpha4,name=validation.openstackmachine.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1beta1 +// +kubebuilder:webhook:verbs=create;update,path=/mutate-infrastructure-cluster-x-k8s-io-v1alpha4-openstackmachine,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=openstackmachines,versions=v1alpha4,name=default.openstackmachine.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1beta1 -var _ webhook.Validator = &OpenStackMachine{} +var ( + _ webhook.Defaulter = &OpenStackMachine{} + _ webhook.Validator = &OpenStackMachine{} +) + +// Default satisfies the defaulting webhook interface. +func (r *OpenStackMachine) Default() { + if r.Spec.IdentityRef != nil && r.Spec.IdentityRef.Kind == "" { + r.Spec.IdentityRef.Kind = defaultIdentityRefKind + } +} // ValidateCreate implements webhook.Validator so a webhook will be registered for the type. func (r *OpenStackMachine) ValidateCreate() error { var allErrs field.ErrorList + if r.Spec.IdentityRef != nil && r.Spec.IdentityRef.Kind != defaultIdentityRefKind { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "identityRef", "kind"), "must be a Secret")) + } + return aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs) } @@ -66,6 +81,10 @@ func (r *OpenStackMachine) ValidateUpdate(old runtime.Object) error { var allErrs field.ErrorList + if r.Spec.IdentityRef != nil && r.Spec.IdentityRef.Kind != defaultIdentityRefKind { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "identityRef", "kind"), "must be a Secret")) + } + newOpenStackMachineSpec := newOpenStackMachine["spec"].(map[string]interface{}) oldOpenStackMachineSpec := oldOpenStackMachine["spec"].(map[string]interface{}) diff --git a/api/v1alpha4/openstackmachinetemplate_webhook.go b/api/v1alpha4/openstackmachinetemplate_webhook.go index 2cf41e21c1..06df4c7304 100644 --- a/api/v1alpha4/openstackmachinetemplate_webhook.go +++ b/api/v1alpha4/openstackmachinetemplate_webhook.go @@ -61,11 +61,7 @@ func (r *OpenStackMachineTemplate) ValidateUpdate(old runtime.Object) error { ) } - if len(allErrs) != 0 { - return aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs) - } - - return nil + return aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs) } // ValidateDelete implements webhook.Validator so a webhook will be registered for the type. diff --git a/api/v1alpha4/zz_generated.deepcopy.go b/api/v1alpha4/zz_generated.deepcopy.go index fb16be9b3d..0818c40f27 100644 --- a/api/v1alpha4/zz_generated.deepcopy.go +++ b/api/v1alpha4/zz_generated.deepcopy.go @@ -311,11 +311,6 @@ func (in *OpenStackClusterList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackClusterSpec) DeepCopyInto(out *OpenStackClusterSpec) { *out = *in - if in.CloudsSecret != nil { - in, out := &in.CloudsSecret, &out.CloudsSecret - *out = new(v1.SecretReference) - **out = **in - } in.Network.DeepCopyInto(&out.Network) in.Subnet.DeepCopyInto(&out.Subnet) if in.DNSNameservers != nil { @@ -351,6 +346,11 @@ func (in *OpenStackClusterSpec) DeepCopyInto(out *OpenStackClusterSpec) { *out = new(Bastion) (*in).DeepCopyInto(*out) } + if in.IdentityRef != nil { + in, out := &in.IdentityRef, &out.IdentityRef + *out = new(OpenStackIdentityReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackClusterSpec. @@ -425,6 +425,21 @@ func (in *OpenStackClusterStatus) DeepCopy() *OpenStackClusterStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenStackIdentityReference) DeepCopyInto(out *OpenStackIdentityReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackIdentityReference. +func (in *OpenStackIdentityReference) DeepCopy() *OpenStackIdentityReference { + if in == nil { + return nil + } + out := new(OpenStackIdentityReference) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackMachine) DeepCopyInto(out *OpenStackMachine) { *out = *in @@ -497,11 +512,6 @@ func (in *OpenStackMachineSpec) DeepCopyInto(out *OpenStackMachineSpec) { *out = new(string) **out = **in } - if in.CloudsSecret != nil { - in, out := &in.CloudsSecret, &out.CloudsSecret - *out = new(v1.SecretReference) - **out = **in - } if in.Networks != nil { in, out := &in.Networks, &out.Networks *out = make([]NetworkParam, len(*in)) @@ -543,6 +553,11 @@ func (in *OpenStackMachineSpec) DeepCopyInto(out *OpenStackMachineSpec) { *out = new(RootVolume) **out = **in } + if in.IdentityRef != nil { + in, out := &in.IdentityRef, &out.IdentityRef + *out = new(OpenStackIdentityReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackMachineSpec. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml index 5b424168f2..87974db0b2 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml @@ -1101,19 +1101,6 @@ spec: description: The name of the cloud to use from the clouds secret type: string - cloudsSecret: - description: The name of the secret containing the openstack - credentials - properties: - name: - description: Name is unique within a namespace to reference - a secret resource. - type: string - namespace: - description: Namespace defines the space within which - the secret name must be unique. - type: string - type: object configDrive: description: Config Drive support type: boolean @@ -1126,6 +1113,26 @@ spec: machine, only used for master. The floatingIP should have been created and haven't been associated. type: string + identityRef: + description: IdentityRef is a reference to a identity to be + used when reconciling this cluster + properties: + kind: + description: Kind of the identity. Must be supported by + the infrastructure provider and may be either cluster + or namespace-scoped. + minLength: 1 + type: string + name: + description: Name of the infrastructure identity to be + used. Must be either a cluster-scoped resource, or namespaced-scoped + resource the same namespace as the resource(s) being + provisioned. + type: string + required: + - kind + - name + type: object image: description: The name of the image to use for your server instance. If the RootVolume is specified, this will be ignored @@ -1399,18 +1406,6 @@ spec: cloudName: description: The name of the cloud to use from the clouds secret type: string - cloudsSecret: - description: The name of the secret containing the openstack credentials - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object controlPlaneAvailabilityZones: description: ControlPlaneAvailabilityZones is the az to deploy control plane to @@ -1516,6 +1511,24 @@ spec: - subnet type: object type: array + identityRef: + description: IdentityRef is a reference to a identity to be used when + reconciling this cluster + properties: + kind: + description: Kind of the identity. Must be supported by the infrastructure + provider and may be either cluster or namespace-scoped. + minLength: 1 + type: string + name: + description: Name of the infrastructure identity to be used. Must + be either a cluster-scoped resource, or namespaced-scoped resource + the same namespace as the resource(s) being provisioned. + type: string + required: + - kind + - name + type: object managedAPIServerLoadBalancer: description: 'ManagedAPIServerLoadBalancer defines whether a LoadBalancer for the APIServer should be created. If set to true the following diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml index aad8edbe28..6ba599bbbf 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml @@ -399,18 +399,6 @@ spec: cloudName: description: The name of the cloud to use from the clouds secret type: string - cloudsSecret: - description: The name of the secret containing the openstack credentials - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object configDrive: description: Config Drive support type: boolean @@ -422,6 +410,24 @@ spec: only used for master. The floatingIP should have been created and haven't been associated. type: string + identityRef: + description: IdentityRef is a reference to a identity to be used when + reconciling this cluster + properties: + kind: + description: Kind of the identity. Must be supported by the infrastructure + provider and may be either cluster or namespace-scoped. + minLength: 1 + type: string + name: + description: Name of the infrastructure identity to be used. Must + be either a cluster-scoped resource, or namespaced-scoped resource + the same namespace as the resource(s) being provisioned. + type: string + required: + - kind + - name + type: object image: description: The name of the image to use for your server instance. If the RootVolume is specified, this will be ignored and use rootVolume diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml index a30fb801d3..4a2410792a 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml @@ -340,19 +340,6 @@ spec: description: The name of the cloud to use from the clouds secret type: string - cloudsSecret: - description: The name of the secret containing the openstack - credentials - properties: - name: - description: Name is unique within a namespace to reference - a secret resource. - type: string - namespace: - description: Namespace defines the space within which - the secret name must be unique. - type: string - type: object configDrive: description: Config Drive support type: boolean @@ -365,6 +352,26 @@ spec: machine, only used for master. The floatingIP should have been created and haven't been associated. type: string + identityRef: + description: IdentityRef is a reference to a identity to be + used when reconciling this cluster + properties: + kind: + description: Kind of the identity. Must be supported by + the infrastructure provider and may be either cluster + or namespace-scoped. + minLength: 1 + type: string + name: + description: Name of the infrastructure identity to be + used. Must be either a cluster-scoped resource, or namespaced-scoped + resource the same namespace as the resource(s) being + provisioned. + type: string + required: + - kind + - name + type: object image: description: The name of the image to use for your server instance. If the RootVolume is specified, this will be ignored diff --git a/config/default/webhookcainjection_patch.yaml b/config/default/webhookcainjection_patch.yaml index 6360f315b6..0bde6bfc6a 100644 --- a/config/default/webhookcainjection_patch.yaml +++ b/config/default/webhookcainjection_patch.yaml @@ -1,12 +1,9 @@ -# This patch add annotation to admission webhook config and -# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. -# uncomment the following lines to enable mutating webhook -#apiVersion: admissionregistration.k8s.io/v1 -#kind: MutatingWebhookConfiguration -#metadata: -# name: mutating-webhook-configuration -# annotations: -# cert-manager.k8s.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: mutating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index 99ca898b28..502ed2cce7 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -1,4 +1,54 @@ +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + creationTimestamp: null + name: mutating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-infrastructure-cluster-x-k8s-io-v1alpha4-openstackcluster + failurePolicy: Fail + matchPolicy: Equivalent + name: default.openstackcluster.infrastructure.x-k8s.io + rules: + - apiGroups: + - infrastructure.cluster.x-k8s.io + apiVersions: + - v1alpha4 + operations: + - CREATE + - UPDATE + resources: + - openstackcluster + sideEffects: None +- admissionReviewVersions: + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-infrastructure-cluster-x-k8s-io-v1alpha4-openstackmachine + failurePolicy: Fail + matchPolicy: Equivalent + name: default.openstackmachine.infrastructure.cluster.x-k8s.io + rules: + - apiGroups: + - infrastructure.cluster.x-k8s.io + apiVersions: + - v1alpha4 + operations: + - CREATE + - UPDATE + resources: + - openstackmachines + sideEffects: None + --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration @@ -6,6 +56,27 @@ metadata: creationTimestamp: null name: validating-webhook-configuration webhooks: +- admissionReviewVersions: + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-infrastructure-cluster-x-k8s-io-v1alpha4-openstackcluster + failurePolicy: Fail + matchPolicy: Equivalent + name: validation.openstackcluster.infrastructure.x-k8s.io + rules: + - apiGroups: + - infrastructure.cluster.x-k8s.io + apiVersions: + - v1alpha4 + operations: + - CREATE + - UPDATE + resources: + - openstackcluster + sideEffects: None - admissionReviewVersions: - v1beta1 clientConfig: diff --git a/pkg/cloud/services/provider/provider.go b/pkg/cloud/services/provider/provider.go index beacf6b779..cbfb6f5fbf 100644 --- a/pkg/cloud/services/provider/provider.go +++ b/pkg/cloud/services/provider/provider.go @@ -46,13 +46,9 @@ func NewClientFromMachine(ctx context.Context, ctrlClient client.Client, openSta var cloud clientconfig.Cloud var caCert []byte - if openStackMachine.Spec.CloudsSecret != nil && openStackMachine.Spec.CloudsSecret.Name != "" { - namespace := openStackMachine.Spec.CloudsSecret.Namespace - if namespace == "" { - namespace = openStackMachine.Namespace - } + if openStackMachine.Spec.IdentityRef != nil { var err error - cloud, caCert, err = getCloudFromSecret(ctx, ctrlClient, namespace, openStackMachine.Spec.CloudsSecret.Name, openStackMachine.Spec.CloudName) + cloud, caCert, err = getCloudFromSecret(ctx, ctrlClient, openStackMachine.Namespace, openStackMachine.Spec.IdentityRef.Name, openStackMachine.Spec.CloudName) if err != nil { return nil, nil, err } @@ -64,13 +60,9 @@ func NewClientFromCluster(ctx context.Context, ctrlClient client.Client, openSta var cloud clientconfig.Cloud var caCert []byte - if openStackCluster.Spec.CloudsSecret != nil && openStackCluster.Spec.CloudsSecret.Name != "" { - namespace := openStackCluster.Spec.CloudsSecret.Namespace - if namespace == "" { - namespace = openStackCluster.Namespace - } + if openStackCluster.Spec.IdentityRef != nil { var err error - cloud, caCert, err = getCloudFromSecret(ctx, ctrlClient, namespace, openStackCluster.Spec.CloudsSecret.Name, openStackCluster.Spec.CloudName) + cloud, caCert, err = getCloudFromSecret(ctx, ctrlClient, openStackCluster.Namespace, openStackCluster.Spec.IdentityRef.Name, openStackCluster.Spec.CloudName) if err != nil { return nil, nil, err } diff --git a/templates/cluster-template-external-cloud-provider.yaml b/templates/cluster-template-external-cloud-provider.yaml index 90deb94aaa..b92d7867eb 100644 --- a/templates/cluster-template-external-cloud-provider.yaml +++ b/templates/cluster-template-external-cloud-provider.yaml @@ -23,8 +23,9 @@ metadata: name: ${CLUSTER_NAME} spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret managedAPIServerLoadBalancer: true managedSecurityGroups: true nodeCidr: 10.6.0.0/24 @@ -74,8 +75,9 @@ spec: image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret --- apiVersion: cluster.x-k8s.io/v1alpha4 kind: MachineDeployment @@ -109,8 +111,9 @@ spec: template: spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} diff --git a/templates/cluster-template-without-lb.yaml b/templates/cluster-template-without-lb.yaml index dc0ef7573d..4db7afd991 100644 --- a/templates/cluster-template-without-lb.yaml +++ b/templates/cluster-template-without-lb.yaml @@ -23,8 +23,9 @@ metadata: name: ${CLUSTER_NAME} spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret managedSecurityGroups: true nodeCidr: 10.6.0.0/24 dnsNameservers: @@ -102,8 +103,9 @@ spec: image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret --- apiVersion: cluster.x-k8s.io/v1alpha4 kind: MachineDeployment @@ -137,8 +139,9 @@ spec: template: spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} diff --git a/templates/cluster-template.yaml b/templates/cluster-template.yaml index 9707098e3a..bf13434bd1 100644 --- a/templates/cluster-template.yaml +++ b/templates/cluster-template.yaml @@ -23,8 +23,9 @@ metadata: name: ${CLUSTER_NAME} spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret managedAPIServerLoadBalancer: true managedSecurityGroups: true nodeCidr: 10.6.0.0/24 @@ -103,8 +104,9 @@ spec: image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret --- apiVersion: cluster.x-k8s.io/v1alpha4 kind: MachineDeployment @@ -138,8 +140,9 @@ spec: template: spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} diff --git a/test/e2e/data/infrastructure-openstack/cluster-template-external-cloud-provider.yaml b/test/e2e/data/infrastructure-openstack/cluster-template-external-cloud-provider.yaml index b61c72ccad..0f2ad19686 100644 --- a/test/e2e/data/infrastructure-openstack/cluster-template-external-cloud-provider.yaml +++ b/test/e2e/data/infrastructure-openstack/cluster-template-external-cloud-provider.yaml @@ -26,8 +26,9 @@ metadata: name: ${CLUSTER_NAME} spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret managedAPIServerLoadBalancer: true managedSecurityGroups: true nodeCidr: 10.6.0.0/24 @@ -94,8 +95,9 @@ spec: image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret --- apiVersion: cluster.x-k8s.io/v1alpha4 kind: MachineDeployment @@ -129,8 +131,9 @@ spec: template: spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} diff --git a/test/e2e/data/infrastructure-openstack/cluster-template-without-lb.yaml b/test/e2e/data/infrastructure-openstack/cluster-template-without-lb.yaml index c4fd5de23e..b4d3eb5b96 100644 --- a/test/e2e/data/infrastructure-openstack/cluster-template-without-lb.yaml +++ b/test/e2e/data/infrastructure-openstack/cluster-template-without-lb.yaml @@ -25,8 +25,9 @@ metadata: name: ${CLUSTER_NAME} spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret managedSecurityGroups: true nodeCidr: 10.6.0.0/24 dnsNameservers: @@ -110,8 +111,9 @@ spec: image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret --- apiVersion: cluster.x-k8s.io/v1alpha4 kind: MachineDeployment @@ -145,9 +147,10 @@ spec: template: spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: - name: ${CLUSTER_NAME}-cloud-config flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} + identityRef: + name: ${CLUSTER_NAME}-cloud-config + kind: Secret image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} --- diff --git a/test/e2e/data/infrastructure-openstack/cluster-template.yaml b/test/e2e/data/infrastructure-openstack/cluster-template.yaml index 508a20c917..ea46c74582 100644 --- a/test/e2e/data/infrastructure-openstack/cluster-template.yaml +++ b/test/e2e/data/infrastructure-openstack/cluster-template.yaml @@ -25,8 +25,9 @@ metadata: name: ${CLUSTER_NAME} spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret managedAPIServerLoadBalancer: true managedSecurityGroups: true nodeCidr: 10.6.0.0/24 @@ -111,8 +112,9 @@ spec: image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret --- apiVersion: cluster.x-k8s.io/v1alpha4 kind: MachineDeployment @@ -146,8 +148,9 @@ spec: template: spec: cloudName: ${OPENSTACK_CLOUD} - cloudsSecret: + identityRef: name: ${CLUSTER_NAME}-cloud-config + kind: Secret flavor: ${OPENSTACK_NODE_MACHINE_FLAVOR} image: ${OPENSTACK_IMAGE_NAME} sshKeyName: ${OPENSTACK_SSH_KEY_NAME} diff --git a/test/e2e/suites/e2e/e2e_test.go b/test/e2e/suites/e2e/e2e_test.go index 152d84ab84..309ce443af 100644 --- a/test/e2e/suites/e2e/e2e_test.go +++ b/test/e2e/suites/e2e/e2e_test.go @@ -327,7 +327,8 @@ func makeOpenStackMachineTemplate(namespace, clusterName, name string, subnetID Image: e2eCtx.E2EConfig.GetVariable(shared.OpenStackImageName), SSHKeyName: shared.DefaultSSHKeyPairName, CloudName: e2eCtx.E2EConfig.GetVariable(shared.OpenStackCloud), - CloudsSecret: &corev1.SecretReference{ + IdentityRef: &infrav1.OpenStackIdentityReference{ + Kind: "Secret", Name: fmt.Sprintf("%s-cloud-config", clusterName), }, Subnet: subnetID, @@ -350,7 +351,8 @@ func makeOpenStackMachineTemplateWithPortOptions(namespace, clusterName, name st Image: e2eCtx.E2EConfig.GetVariable(shared.OpenStackImageName), SSHKeyName: shared.DefaultSSHKeyPairName, CloudName: e2eCtx.E2EConfig.GetVariable(shared.OpenStackCloud), - CloudsSecret: &corev1.SecretReference{ + IdentityRef: &infrav1.OpenStackIdentityReference{ + Kind: "Secret", Name: fmt.Sprintf("%s-cloud-config", clusterName), }, Ports: *portOpts,