From dfc3bc053ab550a8a82ae14da7d80b37fcbbaf07 Mon Sep 17 00:00:00 2001 From: zerospiel Date: Fri, 18 Oct 2024 13:52:18 +0200 Subject: [PATCH] Align provider names with the CAPI labels * removed nested struct with infra/bstrp/cp providers * removed the corresponding chart annotations * align all providers into a single struct depending on a single annotation with regarding prefixes * migrated provider/cluster templates on the new annotation Closes #497 --- api/v1alpha1/clustertemplate_types.go | 14 +- api/v1alpha1/common.go | 65 ++------ api/v1alpha1/providertemplate_types.go | 14 +- api/v1alpha1/servicetemplate_types.go | 35 +---- api/v1alpha1/templates_common.go | 48 ++---- api/v1alpha1/zz_generated.deepcopy.go | 88 ++++++----- .../controller/managedcluster_controller.go | 111 +++++++------- .../managedcluster_controller_test.go | 16 +- internal/controller/management_controller.go | 8 +- internal/controller/template_controller.go | 16 +- .../controller/template_controller_test.go | 44 +++--- internal/telemetry/event.go | 6 +- internal/telemetry/tracker.go | 5 +- internal/webhook/managedcluster_webhook.go | 37 +++-- .../webhook/managedcluster_webhook_test.go | 50 +++---- internal/webhook/management_webhook_test.go | 2 +- templates/cluster/aws-eks/Chart.yaml | 4 +- templates/cluster/aws-hosted-cp/Chart.yaml | 4 +- .../cluster/aws-standalone-cp/Chart.yaml | 4 +- templates/cluster/azure-hosted-cp/Chart.yaml | 4 +- .../cluster/azure-standalone-cp/Chart.yaml | 4 +- .../cluster/vsphere-hosted-cp/Chart.yaml | 4 +- .../cluster/vsphere-standalone-cp/Chart.yaml | 4 +- .../cluster-api-provider-aws/Chart.yaml | 4 +- .../cluster-api-provider-azure/Chart.yaml | 2 +- .../cluster-api-provider-vsphere/Chart.yaml | 2 +- .../hmc.mirantis.com_clustertemplates.yaml | 140 ++++-------------- .../crds/hmc.mirantis.com_managements.yaml | 70 ++------- .../hmc.mirantis.com_providertemplates.yaml | 140 ++++-------------- .../hmc.mirantis.com_servicetemplates.yaml | 46 +----- templates/provider/k0smotron/Chart.yaml | 4 +- 31 files changed, 315 insertions(+), 680 deletions(-) diff --git a/api/v1alpha1/clustertemplate_types.go b/api/v1alpha1/clustertemplate_types.go index 024cc2d77..e8b211ba8 100644 --- a/api/v1alpha1/clustertemplate_types.go +++ b/api/v1alpha1/clustertemplate_types.go @@ -54,19 +54,9 @@ type ClusterTemplateStatus struct { // either from the spec or from the given annotations. func (t *ClusterTemplate) FillStatusWithProviders(annotations map[string]string) error { var err error - t.Status.Providers.BootstrapProviders, err = parseProviders(t, bootstrapProvidersType, annotations, semver.NewConstraint) + t.Status.Providers, err = parseProviders(t, annotations, semver.NewConstraint) if err != nil { - return fmt.Errorf("failed to parse ClusterTemplate bootstrap providers: %v", err) - } - - t.Status.Providers.ControlPlaneProviders, err = parseProviders(t, controlPlaneProvidersType, annotations, semver.NewConstraint) - if err != nil { - return fmt.Errorf("failed to parse ClusterTemplate controlPlane providers: %v", err) - } - - t.Status.Providers.InfrastructureProviders, err = parseProviders(t, infrastructureProvidersType, annotations, semver.NewConstraint) - if err != nil { - return fmt.Errorf("failed to parse ClusterTemplate infrastructure providers: %v", err) + return fmt.Errorf("failed to parse ClusterTemplate providers: %v", err) } kversion := annotations[ChartAnnotationKubernetesVersion] diff --git a/api/v1alpha1/common.go b/api/v1alpha1/common.go index c4f326b45..fdba2d2f6 100644 --- a/api/v1alpha1/common.go +++ b/api/v1alpha1/common.go @@ -36,30 +36,21 @@ const ( ) type ( + // TODO (zerospiel): unite with the versioned as part of the [Contracts support]. + // + // [Contracts support]: https://github.com/Mirantis/hmc/issues/496 + // Providers hold different types of CAPI providers. - Providers struct { - // InfrastructureProviders is the list of CAPI infrastructure providers - InfrastructureProviders []string `json:"infrastructure,omitempty"` - // BootstrapProviders is the list of CAPI bootstrap providers - BootstrapProviders []string `json:"bootstrap,omitempty"` - // ControlPlaneProviders is the list of CAPI control plane providers - ControlPlaneProviders []string `json:"controlPlane,omitempty"` - } + Providers []string // Holds different types of CAPI providers with either // an exact or constrained version in the SemVer format. The requirement // is determined by a consumer of this type. - ProvidersTupled struct { - // List of CAPI infrastructure providers with either an exact or constrained version in the SemVer format. - // Compatibility attributes are optional to be defined. - InfrastructureProviders []ProviderTuple `json:"infrastructure,omitempty"` - // List of CAPI bootstrap providers with either an exact or constrained version in the SemVer format. - // Compatibility attributes are optional to be defined. - BootstrapProviders []ProviderTuple `json:"bootstrap,omitempty"` - // List of CAPI control plane providers with either an exact or constrained version in the SemVer format. - // Compatibility attributes are optional to be defined. - ControlPlaneProviders []ProviderTuple `json:"controlPlane,omitempty"` - } + + // Holds different types of CAPI providers with either + // an exact or constrained version in the SemVer format. The requirement + // is determined by a consumer of this type. + ProvidersTupled []ProviderTuple // Represents name of the provider with either an exact or constrained version in the SemVer format. ProviderTuple struct { @@ -145,35 +136,11 @@ func ExtractServiceTemplateName(rawObj client.Object) []string { return templates } -func (c ProvidersTupled) BootstrapProvidersNames() []string { - return c.names(bootstrapProvidersType) -} - -func (c ProvidersTupled) ControlPlaneProvidersNames() []string { - return c.names(controlPlaneProvidersType) -} - -func (c ProvidersTupled) InfrastructureProvidersNames() []string { - return c.names(infrastructureProvidersType) -} - -func (c ProvidersTupled) names(typ providersType) []string { - f := func(nn []ProviderTuple) []string { - res := make([]string, len(nn)) - for i, v := range nn { - res[i] = v.Name - } - return res - } - - switch typ { - case bootstrapProvidersType: - return f(c.BootstrapProviders) - case controlPlaneProvidersType: - return f(c.ControlPlaneProviders) - case infrastructureProvidersType: - return f(c.InfrastructureProviders) - default: - return []string{} +// Names flattens the underlaying slice to provider names slice and returns it. +func (c ProvidersTupled) Names() []string { + nn := make([]string, len(c)) + for i, v := range c { + nn[i] = v.Name } + return nn } diff --git a/api/v1alpha1/providertemplate_types.go b/api/v1alpha1/providertemplate_types.go index b71f020cd..ca7ebd6cf 100644 --- a/api/v1alpha1/providertemplate_types.go +++ b/api/v1alpha1/providertemplate_types.go @@ -63,19 +63,9 @@ type ProviderTemplateStatus struct { // either from the spec or from the given annotations. func (t *ProviderTemplate) FillStatusWithProviders(annotations map[string]string) error { var err error - t.Status.Providers.BootstrapProviders, err = parseProviders(t, bootstrapProvidersType, annotations, semver.NewVersion) + t.Status.Providers, err = parseProviders(t, annotations, semver.NewVersion) if err != nil { - return fmt.Errorf("failed to parse ProviderTemplate bootstrap providers: %v", err) - } - - t.Status.Providers.ControlPlaneProviders, err = parseProviders(t, controlPlaneProvidersType, annotations, semver.NewVersion) - if err != nil { - return fmt.Errorf("failed to parse ProviderTemplate controlPlane providers: %v", err) - } - - t.Status.Providers.InfrastructureProviders, err = parseProviders(t, infrastructureProvidersType, annotations, semver.NewVersion) - if err != nil { - return fmt.Errorf("failed to parse ProviderTemplate infrastructure providers: %v", err) + return fmt.Errorf("failed to parse ProviderTemplate providers: %v", err) } if t.Name == CoreCAPIName { diff --git a/api/v1alpha1/servicetemplate_types.go b/api/v1alpha1/servicetemplate_types.go index 540c33eb6..70aaf781d 100644 --- a/api/v1alpha1/servicetemplate_types.go +++ b/api/v1alpha1/servicetemplate_types.go @@ -52,41 +52,20 @@ type ServiceTemplateStatus struct { // FillStatusWithProviders sets the status of the template with providers // either from the spec or from the given annotations. func (t *ServiceTemplate) FillStatusWithProviders(annotations map[string]string) error { - parseProviders := func(typ providersType) []string { - var ( - pspec []string - anno string - ) - switch typ { - case bootstrapProvidersType: - pspec, anno = t.Spec.Providers.BootstrapProviders, ChartAnnotationBootstrapProviders - case controlPlaneProvidersType: - pspec, anno = t.Spec.Providers.ControlPlaneProviders, ChartAnnotationControlPlaneProviders - case infrastructureProvidersType: - pspec, anno = t.Spec.Providers.InfrastructureProviders, ChartAnnotationInfraProviders - } - - providers := annotations[anno] - if len(providers) == 0 { - return pspec - } - + providers := annotations[ChartAnnotationProviderName] + if len(providers) == 0 { + t.Status.Providers = t.Spec.Providers + } else { splitted := strings.Split(providers, multiProviderSeparator) - result := make([]string, 0, len(splitted)) - result = append(result, pspec...) + t.Status.Providers = make([]string, 0, len(splitted)) + t.Status.Providers = append(t.Status.Providers, t.Spec.Providers...) for _, v := range splitted { if c := strings.TrimSpace(v); c != "" { - result = append(result, c) + t.Status.Providers = append(t.Status.Providers, c) } } - - return result } - t.Status.Providers.BootstrapProviders = parseProviders(bootstrapProvidersType) - t.Status.Providers.ControlPlaneProviders = parseProviders(controlPlaneProvidersType) - t.Status.Providers.InfrastructureProviders = parseProviders(infrastructureProvidersType) - kconstraint := annotations[ChartAnnotationKubernetesConstraint] if t.Spec.KubernetesConstraint != "" { kconstraint = t.Spec.KubernetesConstraint diff --git a/api/v1alpha1/templates_common.go b/api/v1alpha1/templates_common.go index 3f1abaf92..688b28e86 100644 --- a/api/v1alpha1/templates_common.go +++ b/api/v1alpha1/templates_common.go @@ -24,12 +24,9 @@ import ( ) const ( - // ChartAnnotationInfraProviders is an annotation containing the CAPI infrastructure providers associated with Template. - ChartAnnotationInfraProviders = "hmc.mirantis.com/infrastructure-providers" - // ChartAnnotationBootstrapProviders is an annotation containing the CAPI bootstrap providers associated with Template. - ChartAnnotationBootstrapProviders = "hmc.mirantis.com/bootstrap-providers" - // ChartAnnotationControlPlaneProviders is an annotation containing the CAPI control plane providers associated with Template. - ChartAnnotationControlPlaneProviders = "hmc.mirantis.com/control-plane-providers" + // ChartAnnotationProviderName is the annotation set on components in a Template. + // This annotations allows to identify all the components belonging to a provider. + ChartAnnotationProviderName = "cluster.x-k8s.io/provider" ) // +kubebuilder:validation:XValidation:rule="(has(self.chartName) && !has(self.chartRef)) || (!has(self.chartName) && has(self.chartRef))", message="either chartName or chartRef must be set" @@ -77,30 +74,26 @@ type TemplateValidationStatus struct { Valid bool `json:"valid"` } -type providersType int - -const ( - bootstrapProvidersType providersType = iota - controlPlaneProvidersType - infrastructureProvidersType -) - +// TODO (zerospiel): change to comma as part of the [Contracts support]. +// +// [Contracts support]: https://github.com/Mirantis/hmc/issues/496 const multiProviderSeparator = ";" -func parseProviders[T any](providersGetter interface{ GetSpecProviders() ProvidersTupled }, typ providersType, annotations map[string]string, validationFn func(string) (T, error)) ([]ProviderTuple, error) { - pspec, anno := getProvidersSpecAnno(providersGetter, typ) - - providers := annotations[anno] +// TODO (zerospiel): move to the template-ctrl? +func parseProviders[T any](providersGetter interface{ GetSpecProviders() ProvidersTupled }, annotations map[string]string, validationFn func(string) (T, error)) ([]ProviderTuple, error) { + providers := annotations[ChartAnnotationProviderName] if len(providers) == 0 { - return pspec, nil + return providersGetter.GetSpecProviders(), nil } var ( + ps = providersGetter.GetSpecProviders() + splitted = strings.Split(providers, multiProviderSeparator) - pstatus = make([]ProviderTuple, 0, len(splitted)+len(pspec)) + pstatus = make([]ProviderTuple, 0, len(splitted)+len(ps)) merr error ) - pstatus = append(pstatus, pspec...) + pstatus = append(pstatus, ps...) for _, v := range splitted { v = strings.TrimSpace(v) @@ -127,16 +120,3 @@ func parseProviders[T any](providersGetter interface{ GetSpecProviders() Provide return pstatus, merr } - -func getProvidersSpecAnno(providersGetter interface{ GetSpecProviders() ProvidersTupled }, typ providersType) (spec []ProviderTuple, annotation string) { - switch typ { - case bootstrapProvidersType: - return providersGetter.GetSpecProviders().BootstrapProviders, ChartAnnotationBootstrapProviders - case controlPlaneProvidersType: - return providersGetter.GetSpecProviders().ControlPlaneProviders, ChartAnnotationControlPlaneProviders - case infrastructureProvidersType: - return providersGetter.GetSpecProviders().InfrastructureProviders, ChartAnnotationInfraProviders - default: - return []ProviderTuple{}, "" - } -} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index e14ce1474..706a72b05 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -188,7 +188,11 @@ func (in *ClusterTemplateList) DeepCopyObject() runtime.Object { func (in *ClusterTemplateSpec) DeepCopyInto(out *ClusterTemplateSpec) { *out = *in in.Helm.DeepCopyInto(&out.Helm) - in.Providers.DeepCopyInto(&out.Providers) + if in.Providers != nil { + in, out := &in.Providers, &out.Providers + *out = make(ProvidersTupled, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTemplateSpec. @@ -204,7 +208,11 @@ func (in *ClusterTemplateSpec) DeepCopy() *ClusterTemplateSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterTemplateStatus) DeepCopyInto(out *ClusterTemplateStatus) { *out = *in - in.Providers.DeepCopyInto(&out.Providers) + if in.Providers != nil { + in, out := &in.Providers, &out.Providers + *out = make(ProvidersTupled, len(*in)) + copy(*out, *in) + } in.TemplateStatusCommon.DeepCopyInto(&out.TemplateStatusCommon) } @@ -603,7 +611,11 @@ func (in *ManagementStatus) DeepCopyInto(out *ManagementStatus) { (*out)[key] = val } } - in.AvailableProviders.DeepCopyInto(&out.AvailableProviders) + if in.AvailableProviders != nil { + in, out := &in.AvailableProviders, &out.AvailableProviders + *out = make(ProvidersTupled, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementStatus. @@ -808,7 +820,11 @@ func (in *ProviderTemplateList) DeepCopyObject() runtime.Object { func (in *ProviderTemplateSpec) DeepCopyInto(out *ProviderTemplateSpec) { *out = *in in.Helm.DeepCopyInto(&out.Helm) - in.Providers.DeepCopyInto(&out.Providers) + if in.Providers != nil { + in, out := &in.Providers, &out.Providers + *out = make(ProvidersTupled, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderTemplateSpec. @@ -824,7 +840,11 @@ func (in *ProviderTemplateSpec) DeepCopy() *ProviderTemplateSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProviderTemplateStatus) DeepCopyInto(out *ProviderTemplateStatus) { *out = *in - in.Providers.DeepCopyInto(&out.Providers) + if in.Providers != nil { + in, out := &in.Providers, &out.Providers + *out = make(ProvidersTupled, len(*in)) + copy(*out, *in) + } in.TemplateStatusCommon.DeepCopyInto(&out.TemplateStatusCommon) } @@ -854,63 +874,41 @@ func (in *ProviderTuple) DeepCopy() *ProviderTuple { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Providers) DeepCopyInto(out *Providers) { - *out = *in - if in.InfrastructureProviders != nil { - in, out := &in.InfrastructureProviders, &out.InfrastructureProviders - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.BootstrapProviders != nil { - in, out := &in.BootstrapProviders, &out.BootstrapProviders - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.ControlPlaneProviders != nil { - in, out := &in.ControlPlaneProviders, &out.ControlPlaneProviders - *out = make([]string, len(*in)) +func (in Providers) DeepCopyInto(out *Providers) { + { + in := &in + *out = make(Providers, len(*in)) copy(*out, *in) } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Providers. -func (in *Providers) DeepCopy() *Providers { +func (in Providers) DeepCopy() Providers { if in == nil { return nil } out := new(Providers) in.DeepCopyInto(out) - return out + return *out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProvidersTupled) DeepCopyInto(out *ProvidersTupled) { - *out = *in - if in.InfrastructureProviders != nil { - in, out := &in.InfrastructureProviders, &out.InfrastructureProviders - *out = make([]ProviderTuple, len(*in)) - copy(*out, *in) - } - if in.BootstrapProviders != nil { - in, out := &in.BootstrapProviders, &out.BootstrapProviders - *out = make([]ProviderTuple, len(*in)) - copy(*out, *in) - } - if in.ControlPlaneProviders != nil { - in, out := &in.ControlPlaneProviders, &out.ControlPlaneProviders - *out = make([]ProviderTuple, len(*in)) +func (in ProvidersTupled) DeepCopyInto(out *ProvidersTupled) { + { + in := &in + *out = make(ProvidersTupled, len(*in)) copy(*out, *in) } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvidersTupled. -func (in *ProvidersTupled) DeepCopy() *ProvidersTupled { +func (in ProvidersTupled) DeepCopy() ProvidersTupled { if in == nil { return nil } out := new(ProvidersTupled) in.DeepCopyInto(out) - return out + return *out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -1157,7 +1155,11 @@ func (in *ServiceTemplateList) DeepCopyObject() runtime.Object { func (in *ServiceTemplateSpec) DeepCopyInto(out *ServiceTemplateSpec) { *out = *in in.Helm.DeepCopyInto(&out.Helm) - in.Providers.DeepCopyInto(&out.Providers) + if in.Providers != nil { + in, out := &in.Providers, &out.Providers + *out = make(Providers, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceTemplateSpec. @@ -1173,7 +1175,11 @@ func (in *ServiceTemplateSpec) DeepCopy() *ServiceTemplateSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceTemplateStatus) DeepCopyInto(out *ServiceTemplateStatus) { *out = *in - in.Providers.DeepCopyInto(&out.Providers) + if in.Providers != nil { + in, out := &in.Providers, &out.Providers + *out = make(Providers, len(*in)) + copy(*out, *in) + } in.TemplateStatusCommon.DeepCopyInto(&out.TemplateStatusCommon) } diff --git a/internal/controller/managedcluster_controller.go b/internal/controller/managedcluster_controller.go index aff940e42..89e2801c9 100644 --- a/internal/controller/managedcluster_controller.go +++ b/internal/controller/managedcluster_controller.go @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "fmt" + "strings" texttemplate "text/template" "time" @@ -69,26 +70,6 @@ type ManagedClusterReconciler struct { SystemNamespace string } -var ( - gvkAWSCluster = schema.GroupVersionKind{ - Group: "infrastructure.cluster.x-k8s.io", - Version: "v1beta2", - Kind: "awscluster", - } - - gvkAzureCluster = schema.GroupVersionKind{ - Group: "infrastructure.cluster.x-k8s.io", - Version: "v1beta1", - Kind: "azurecluster", - } - - gvkMachine = schema.GroupVersionKind{ - Group: "cluster.x-k8s.io", - Version: "v1beta1", - Kind: "machine", - } -) - // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. func (r *ManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { @@ -373,9 +354,9 @@ func (r *ManagedClusterReconciler) Update(ctx context.Context, managedCluster *h return ctrl.Result{RequeueAfter: DefaultRequeueInterval}, nil } - result, err := r.reconcileCredentialPropagation(ctx, managedCluster) - if err != nil { - return result, err + if err := r.reconcileCredentialPropagation(ctx, managedCluster); err != nil { + l.Error(err, "failed to reconcile credentials propagation") + return ctrl.Result{}, err } return r.updateServices(ctx, managedCluster) @@ -537,17 +518,30 @@ func (r *ManagedClusterReconciler) Delete(ctx context.Context, managedCluster *h } func (r *ManagedClusterReconciler) releaseCluster(ctx context.Context, namespace, name, templateName string) error { - providers, err := r.getProviders(ctx, namespace, templateName) + providers, err := r.getInfraProvidersNames(ctx, namespace, templateName) if err != nil { return err } - for _, provider := range providers.BootstrapProviders { - if provider.Name == "eks" { - // no need to do anything for EKS clusters - return nil + var ( + gvkAWSCluster = schema.GroupVersionKind{ + Group: "infrastructure.cluster.x-k8s.io", + Version: "v1beta2", + Kind: "AWSCluster", + } + + gvkAzureCluster = schema.GroupVersionKind{ + Group: "infrastructure.cluster.x-k8s.io", + Version: "v1beta1", + Kind: "AzureCluster", } - } + + gvkMachine = schema.GroupVersionKind{ + Group: "cluster.x-k8s.io", + Version: "v1beta1", + Kind: "Machine", + } + ) providerGVKs := map[string]schema.GroupVersionKind{ "aws": gvkAWSCluster, @@ -555,14 +549,18 @@ func (r *ManagedClusterReconciler) releaseCluster(ctx context.Context, namespace } // Associate the provider with it's GVK - for _, provider := range providers.InfrastructureProviders { - gvk, ok := providerGVKs[provider.Name] + for _, provider := range providers { + gvk, ok := providerGVKs[provider] if !ok { continue } cluster, err := r.getCluster(ctx, namespace, name, gvk) if err != nil { + if provider == "aws" && apierrors.IsNotFound(err) { + return nil + } + return err } @@ -579,15 +577,22 @@ func (r *ManagedClusterReconciler) releaseCluster(ctx context.Context, namespace return nil } -func (r *ManagedClusterReconciler) getProviders(ctx context.Context, templateNamespace, templateName string) (hmc.ProvidersTupled, error) { +func (r *ManagedClusterReconciler) getInfraProvidersNames(ctx context.Context, templateNamespace, templateName string) ([]string, error) { template := &hmc.ClusterTemplate{} templateRef := client.ObjectKey{Name: templateName, Namespace: templateNamespace} if err := r.Get(ctx, templateRef, template); err != nil { ctrl.LoggerFrom(ctx).Error(err, "Failed to get ClusterTemplate", "template namespace", templateNamespace, "template name", templateName) - return hmc.ProvidersTupled{}, err + return nil, err + } + + ips := make([]string, 0, len(template.Status.Providers)) + for _, v := range template.Status.Providers { + if strings.HasPrefix(v.Name, "infrastructure-") { + ips = append(ips, v.Name) + } } - return template.Status.Providers, nil + return ips[:len(ips):len(ips)], nil } func (r *ManagedClusterReconciler) getCluster(ctx context.Context, namespace, name string, gvk schema.GroupVersionKind) (*metav1.PartialObjectMetadata, error) { @@ -634,14 +639,13 @@ func (r *ManagedClusterReconciler) objectsAvailable(ctx context.Context, namespa return len(itemsList.Items) != 0, nil } -func (r *ManagedClusterReconciler) reconcileCredentialPropagation(ctx context.Context, managedCluster *hmc.ManagedCluster) (ctrl.Result, error) { +func (r *ManagedClusterReconciler) reconcileCredentialPropagation(ctx context.Context, managedCluster *hmc.ManagedCluster) error { l := ctrl.LoggerFrom(ctx) l.Info("Reconciling CCM credentials propagation") - providers, err := r.getProviders(ctx, managedCluster.Namespace, managedCluster.Spec.Template) + providers, err := r.getInfraProvidersNames(ctx, managedCluster.Namespace, managedCluster.Spec.Template) if err != nil { - return ctrl.Result{}, - fmt.Errorf("failed to get cluster providers for cluster %s/%s: %s", managedCluster.Namespace, managedCluster.Name, err) + return fmt.Errorf("failed to get cluster providers for cluster %s/%s: %s", managedCluster.Namespace, managedCluster.Name, err) } kubeconfSecret := &corev1.Secret{} @@ -649,19 +653,16 @@ func (r *ManagedClusterReconciler) reconcileCredentialPropagation(ctx context.Co Name: fmt.Sprintf("%s-kubeconfig", managedCluster.Name), Namespace: managedCluster.Namespace, }, kubeconfSecret); err != nil { - return ctrl.Result{}, - fmt.Errorf("failed to get kubeconfig secret for cluster %s/%s: %s", managedCluster.Namespace, managedCluster.Name, err) + return fmt.Errorf("failed to get kubeconfig secret for cluster %s/%s: %s", managedCluster.Namespace, managedCluster.Name, err) } - for _, provider := range providers.InfrastructureProviders { - switch provider.Name { + for _, provider := range providers { + switch provider { case "aws": l.Info("Skipping creds propagation for AWS") - continue case "azure": l.Info("Azure creds propagation start") - err := r.propagateAzureSecrets(ctx, managedCluster, kubeconfSecret) - if err != nil { + if err := r.propagateAzureSecrets(ctx, managedCluster, kubeconfSecret); err != nil { errMsg := fmt.Sprintf("failed to create Azure CCM credentials: %s", err) apimeta.SetStatusCondition(managedCluster.GetConditions(), metav1.Condition{ Type: hmc.CredentialsPropagatedCondition, @@ -669,19 +670,19 @@ func (r *ManagedClusterReconciler) reconcileCredentialPropagation(ctx context.Co Reason: hmc.FailedReason, Message: errMsg, }) - return ctrl.Result{}, errors.New(errMsg) + + return errors.New(errMsg) } + apimeta.SetStatusCondition(managedCluster.GetConditions(), metav1.Condition{ Type: hmc.CredentialsPropagatedCondition, Status: metav1.ConditionTrue, Reason: hmc.SucceededReason, Message: "Azure CCM credentials created", }) - continue case "vsphere": l.Info("vSphere creds propagation start") - err := r.propagateVSphereSecrets(ctx, managedCluster, kubeconfSecret) - if err != nil { + if err := r.propagateVSphereSecrets(ctx, managedCluster, kubeconfSecret); err != nil { errMsg := fmt.Sprintf("failed to create vSphere CCM credentials: %s", err) apimeta.SetStatusCondition(managedCluster.GetConditions(), metav1.Condition{ Type: hmc.CredentialsPropagatedCondition, @@ -689,28 +690,28 @@ func (r *ManagedClusterReconciler) reconcileCredentialPropagation(ctx context.Co Reason: hmc.FailedReason, Message: errMsg, }) - return ctrl.Result{}, errors.New(errMsg) + return errors.New(errMsg) } + apimeta.SetStatusCondition(managedCluster.GetConditions(), metav1.Condition{ Type: hmc.CredentialsPropagatedCondition, Status: metav1.ConditionTrue, Reason: hmc.SucceededReason, Message: "vSphere CCM credentials created", }) - continue default: - errMsg := fmt.Sprintf("unsupported infrastructure provider %s", provider) apimeta.SetStatusCondition(managedCluster.GetConditions(), metav1.Condition{ Type: hmc.CredentialsPropagatedCondition, Status: metav1.ConditionFalse, Reason: hmc.FailedReason, - Message: errMsg, + Message: fmt.Sprintf("unsupported infrastructure provider %s", provider), }) - continue } } + l.Info("CCM credentials reconcile finished") - return ctrl.Result{}, nil + + return nil } func (r *ManagedClusterReconciler) propagateAzureSecrets(ctx context.Context, managedCluster *hmc.ManagedCluster, kubeconfSecret *corev1.Secret) error { diff --git a/internal/controller/managedcluster_controller_test.go b/internal/controller/managedcluster_controller_test.go index a7070fa7e..029b544a9 100644 --- a/internal/controller/managedcluster_controller_test.go +++ b/internal/controller/managedcluster_controller_test.go @@ -94,13 +94,7 @@ var _ = Describe("ManagedCluster Controller", func() { Raw: []byte(`{"foo":"bar"}`), }, }, - Providers: hmc.ProvidersTupled{ - InfrastructureProviders: []hmc.ProviderTuple{ - { - Name: "aws", - }, - }, - }, + Providers: hmc.ProvidersTupled{{Name: "infrastructure-aws"}}, } Expect(k8sClient.Status().Update(ctx, template)).To(Succeed()) } @@ -116,13 +110,7 @@ var _ = Describe("ManagedCluster Controller", func() { } Expect(k8sClient.Create(ctx, management)).To(Succeed()) management.Status = hmc.ManagementStatus{ - AvailableProviders: hmc.ProvidersTupled{ - InfrastructureProviders: []hmc.ProviderTuple{ - { - Name: "aws", - }, - }, - }, + AvailableProviders: hmc.ProvidersTupled{{Name: "infrastructure-aws"}}, } Expect(k8sClient.Status().Update(ctx, management)).To(Succeed()) } diff --git a/internal/controller/management_controller.go b/internal/controller/management_controller.go index 41a1f6723..537dc1e43 100644 --- a/internal/controller/management_controller.go +++ b/internal/controller/management_controller.go @@ -19,6 +19,8 @@ import ( "encoding/json" "errors" "fmt" + "slices" + "strings" fluxv2 "github.com/fluxcd/helm-controller/api/v2" "github.com/fluxcd/pkg/apis/meta" @@ -425,9 +427,9 @@ func updateComponentsStatus( } if err == "" { - providers.InfrastructureProviders = append(providers.InfrastructureProviders, templateProviders.InfrastructureProviders...) - providers.BootstrapProviders = append(providers.BootstrapProviders, templateProviders.BootstrapProviders...) - providers.ControlPlaneProviders = append(providers.ControlPlaneProviders, templateProviders.ControlPlaneProviders...) + *providers = append(*providers, templateProviders...) + slices.SortFunc(*providers, func(a, b hmc.ProviderTuple) int { return strings.Compare(a.Name, b.Name) }) + *providers = slices.Compact(*providers) } } diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index 6611a1901..9e0c403a9 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -344,13 +344,7 @@ func (r *ClusterTemplateReconciler) validateCompatibilityAttrs(ctx context.Conte ctrl.LoggerFrom(ctx).V(1).Info("providers to check", "exposed", exposedProviders, "required", requiredProviders) var merr error - missing, wrong, parsing := collectMissingProvidersWithWrongVersions("bootstrap", exposedProviders.BootstrapProviders, requiredProviders.BootstrapProviders) - merr = errors.Join(merr, missing, wrong, parsing) - - missing, wrong, parsing = collectMissingProvidersWithWrongVersions("control plane", exposedProviders.ControlPlaneProviders, requiredProviders.ControlPlaneProviders) - merr = errors.Join(merr, missing, wrong, parsing) - - missing, wrong, parsing = collectMissingProvidersWithWrongVersions("infrastructure", exposedProviders.InfrastructureProviders, requiredProviders.InfrastructureProviders) + missing, wrong, parsing := collectMissingProvidersWithWrongVersions(exposedProviders, requiredProviders) merr = errors.Join(merr, missing, wrong, parsing) if merr != nil { @@ -363,7 +357,7 @@ func (r *ClusterTemplateReconciler) validateCompatibilityAttrs(ctx context.Conte // collectMissingProvidersWithWrongVersions returns collected errors for missing providers, providers with // wrong versions that do not satisfy the corresponding constraints, and parsing errors respectevly. -func collectMissingProvidersWithWrongVersions(typ string, exposed, required []hmc.ProviderTuple) (missingErr, nonSatisfyingErr, parsingErr error) { +func collectMissingProvidersWithWrongVersions(exposed, required []hmc.ProviderTuple) (missingErr, nonSatisfyingErr, parsingErr error) { exposedSet := make(map[string]hmc.ProviderTuple, len(exposed)) for _, v := range exposed { exposedSet[v.Name] = v @@ -403,16 +397,16 @@ func collectMissingProvidersWithWrongVersions(typ string, exposed, required []hm if len(missing) > 0 { slices.Sort(missing) - missingErr = fmt.Errorf("one or more required %s providers are not deployed yet: %v", typ, missing) + missingErr = fmt.Errorf("one or more required providers are not deployed yet: %v", missing) } if len(nonSatisfying) > 0 { slices.Sort(nonSatisfying) - nonSatisfyingErr = fmt.Errorf("one or more required %s providers does not satisfy constraints: %v", typ, nonSatisfying) + nonSatisfyingErr = fmt.Errorf("one or more required providers does not satisfy constraints: %v", nonSatisfying) } if parsingErr != nil { - parsingErr = fmt.Errorf("one or more errors parsing %s providers' versions and constraints : %v", typ, parsingErr) + parsingErr = fmt.Errorf("one or more errors parsing providers' versions and constraints : %v", parsingErr) } return missingErr, nonSatisfyingErr, parsingErr diff --git a/internal/controller/template_controller_test.go b/internal/controller/template_controller_test.go index 3fec09bbc..fe6cf6d4a 100644 --- a/internal/controller/template_controller_test.go +++ b/internal/controller/template_controller_test.go @@ -217,12 +217,10 @@ var _ = Describe("Template Controller", func() { }, Spec: hmcmirantiscomv1alpha1.ClusterTemplateSpec{ Helm: helmSpec, - Providers: hmcmirantiscomv1alpha1.ProvidersTupled{ - BootstrapProviders: []hmcmirantiscomv1alpha1.ProviderTuple{ - { - Name: someProviderName, - VersionOrConstraint: someProviderVersionConstraint, // constraint - }, + Providers: []hmcmirantiscomv1alpha1.ProviderTuple{ + { + Name: someProviderName, + VersionOrConstraint: someProviderVersionConstraint, // constraint }, }, }, @@ -235,12 +233,12 @@ var _ = Describe("Template Controller", func() { return err } - if l := len(clusterTemplate.Spec.Providers.BootstrapProviders); l != 1 { - return fmt.Errorf("expected .spec.providers.bootstrapProviders length to be exactly 1, got %d", l) + if l := len(clusterTemplate.Spec.Providers); l != 1 { + return fmt.Errorf("expected .spec.providers length to be exactly 1, got %d", l) } - if v := clusterTemplate.Spec.Providers.BootstrapProviders[0]; v.Name != someProviderName || v.VersionOrConstraint != someProviderVersionConstraint { - return fmt.Errorf("expected .spec.providers.bootstrapProviders[0] to be %s:%s, got %s:%s", someProviderName, someProviderVersionConstraint, v.Name, v.VersionOrConstraint) + if v := clusterTemplate.Spec.Providers[0]; v.Name != someProviderName || v.VersionOrConstraint != someProviderVersionConstraint { + return fmt.Errorf("expected .spec.providers[0] to be %s:%s, got %s:%s", someProviderName, someProviderVersionConstraint, v.Name, v.VersionOrConstraint) } return nil @@ -255,12 +253,10 @@ var _ = Describe("Template Controller", func() { } Expect(k8sClient.Create(ctx, mgmt)).To(Succeed()) mgmt.Status = hmcmirantiscomv1alpha1.ManagementStatus{ - AvailableProviders: hmcmirantiscomv1alpha1.ProvidersTupled{ - BootstrapProviders: []hmcmirantiscomv1alpha1.ProviderTuple{ - { - Name: someProviderName, - VersionOrConstraint: someProviderVersion, // version - }, + AvailableProviders: []hmcmirantiscomv1alpha1.ProviderTuple{ + { + Name: someProviderName, + VersionOrConstraint: someProviderVersion, // version }, }, } @@ -272,16 +268,12 @@ var _ = Describe("Template Controller", func() { return err } - if l := len(mgmt.Status.AvailableProviders.BootstrapProviders); l != 1 { - return fmt.Errorf("expected .status.availableProviders.bootstrapProviders length to be exactly 1, got %d", l) - } - - if l := len(mgmt.Status.AvailableProviders.BootstrapProviders); l != 1 { - return fmt.Errorf("expected .status.availableProviders.bootstrapProviders length to be exactly 1, got %d", l) + if l := len(mgmt.Status.AvailableProviders); l != 1 { + return fmt.Errorf("expected .status.availableProviders length to be exactly 1, got %d", l) } - if v := mgmt.Status.AvailableProviders.BootstrapProviders[0]; v.Name != someProviderName || v.VersionOrConstraint != someProviderVersion { - return fmt.Errorf("expected .status.availableProviders.bootstrapProviders[0] to be %s:%s, got %s:%s", someProviderName, someProviderVersionConstraint, v.Name, v.VersionOrConstraint) + if v := mgmt.Status.AvailableProviders[0]; v.Name != someProviderName || v.VersionOrConstraint != someProviderVersion { + return fmt.Errorf("expected .status.availableProviders[0] to be %s:%s, got %s:%s", someProviderName, someProviderVersionConstraint, v.Name, v.VersionOrConstraint) } return nil @@ -301,8 +293,8 @@ var _ = Describe("Template Controller", func() { By("Having the valid cluster template status") Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(clusterTemplate), clusterTemplate)).To(Succeed()) Expect(clusterTemplate.Status.Valid && clusterTemplate.Status.ValidationError == "").To(BeTrue()) - Expect(clusterTemplate.Status.Providers.BootstrapProviders).To(HaveLen(1)) - Expect(clusterTemplate.Status.Providers.BootstrapProviders[0]).To(Equal(hmcmirantiscomv1alpha1.ProviderTuple{Name: someProviderName, VersionOrConstraint: someProviderVersionConstraint})) + Expect(clusterTemplate.Status.Providers).To(HaveLen(1)) + Expect(clusterTemplate.Status.Providers[0]).To(Equal(hmcmirantiscomv1alpha1.ProviderTuple{Name: someProviderName, VersionOrConstraint: someProviderVersionConstraint})) By("Removing the created objects") Expect(k8sClient.Delete(ctx, mgmt)).To(Succeed()) diff --git a/internal/telemetry/event.go b/internal/telemetry/event.go index 176470905..81dd10971 100644 --- a/internal/telemetry/event.go +++ b/internal/telemetry/event.go @@ -35,16 +35,14 @@ func TrackManagedClusterCreate(id, managedClusterID, template string, dryRun boo return TrackEvent(managedClusterCreateEvent, id, props) } -func TrackManagedClusterHeartbeat(id, managedClusterID, clusterID, template, templateHelmChartVersion, infrastructureProvider, bootstrapProvider, controlPlaneProvider string) error { +func TrackManagedClusterHeartbeat(id, managedClusterID, clusterID, template, templateHelmChartVersion string, providers []string) error { props := map[string]any{ "hmcVersion": build.Version, "managedClusterID": managedClusterID, "clusterID": clusterID, "template": template, "templateHelmChartVersion": templateHelmChartVersion, - "infrastructureProvider": infrastructureProvider, - "bootstrapProvider": bootstrapProvider, - "controlPlaneProvider": controlPlaneProvider, + "providers": providers, } return TrackEvent(managedClusterHeartbeatEvent, id, props) } diff --git a/internal/telemetry/tracker.go b/internal/telemetry/tracker.go index 83d9b858e..8621dd23a 100644 --- a/internal/telemetry/tracker.go +++ b/internal/telemetry/tracker.go @@ -18,7 +18,6 @@ import ( "context" "errors" "fmt" - "strings" "time" "sigs.k8s.io/controller-runtime/pkg/client" @@ -93,9 +92,7 @@ func (t *Tracker) trackManagedClusterHeartbeat(ctx context.Context) error { clusterID, managedCluster.Spec.Template, template.Spec.Helm.ChartVersion, - strings.Join(template.Status.Providers.InfrastructureProvidersNames(), ","), - strings.Join(template.Status.Providers.BootstrapProvidersNames(), ","), - strings.Join(template.Status.Providers.ControlPlaneProvidersNames(), ","), + template.Status.Providers.Names(), ) if err != nil { errs = errors.Join(errs, fmt.Errorf("failed to track the heartbeat of the managedcluster %s/%s", managedCluster.Namespace, managedCluster.Name)) diff --git a/internal/webhook/managedcluster_webhook.go b/internal/webhook/managedcluster_webhook.go index 18b66b0eb..6884f7416 100644 --- a/internal/webhook/managedcluster_webhook.go +++ b/internal/webhook/managedcluster_webhook.go @@ -17,6 +17,7 @@ package webhook import ( "context" "fmt" + "strings" "github.com/Masterminds/semver/v3" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -212,9 +213,19 @@ func isTemplateValid(template *hmcv1alpha1.ClusterTemplate) error { } func (v *ManagedClusterValidator) validateCredential(ctx context.Context, managedCluster *hmcv1alpha1.ManagedCluster, template *hmcv1alpha1.ClusterTemplate) error { - infraProviders := template.Status.Providers.InfrastructureProviders + if len(template.Status.Providers) == 0 { + return fmt.Errorf("template %q has no providers defined", template.Name) + } + + hasInfra := false + for _, v := range template.Status.Providers { + if strings.HasPrefix(v.Name, "infrastructure-") { + hasInfra = true + break + } + } - if len(infraProviders) == 0 { + if !hasInfra { return fmt.Errorf("template %q has no infrastructure providers defined", template.Name) } @@ -232,31 +243,33 @@ func (v *ManagedClusterValidator) validateCredential(ctx context.Context, manage func isCredMatchTemplate(cred *hmcv1alpha1.Credential, template *hmcv1alpha1.ClusterTemplate) error { idtyKind := cred.Spec.IdentityRef.Kind - infraProviders := template.Status.Providers.InfrastructureProviders - errMsg := func(idtyKind string, provider string) error { + errMsg := func(provider string) error { return fmt.Errorf("wrong kind of the ClusterIdentity %q for provider %q", idtyKind, provider) } - for _, provider := range infraProviders { + for _, provider := range template.Status.Providers { switch provider.Name { - case "aws": + case "infrastructure-aws": if idtyKind != "AWSClusterStaticIdentity" && idtyKind != "AWSClusterRoleIdentity" && idtyKind != "AWSClusterControllerIdentity" { - return errMsg(idtyKind, provider.Name) + return errMsg(provider.Name) } - case "azure": + case "infrastructure-azure": if idtyKind != "AzureClusterIdentity" { - return errMsg(idtyKind, provider.Name) + return errMsg(provider.Name) } - case "vsphere": + case "infrastructure-vsphere": if idtyKind != "VSphereClusterIdentity" { - return errMsg(idtyKind, provider.Name) + return errMsg(provider.Name) } default: - return fmt.Errorf("unsupported infrastructure provider %s", provider.Name) + if strings.HasPrefix(provider.Name, "infrastructure-") { + return fmt.Errorf("unsupported infrastructure provider %s", provider.Name) + } } } + return nil } diff --git a/internal/webhook/managedcluster_webhook_test.go b/internal/webhook/managedcluster_webhook_test.go index 4bd961898..ad8261de6 100644 --- a/internal/webhook/managedcluster_webhook_test.go +++ b/internal/webhook/managedcluster_webhook_test.go @@ -43,9 +43,9 @@ var ( mgmt = management.NewManagement( management.WithAvailableProviders(v1alpha1.ProvidersTupled{ - InfrastructureProviders: []v1alpha1.ProviderTuple{{Name: "aws"}}, - BootstrapProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, - ControlPlaneProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, + {Name: "infrastructure-aws"}, + {Name: "control-plane-k0s"}, + {Name: "bootstrap-k0s"}, }), ) @@ -128,9 +128,9 @@ func TestManagedClusterValidateCreate(t *testing.T) { template.NewClusterTemplate( template.WithName(testTemplateName), template.WithProvidersStatus(v1alpha1.ProvidersTupled{ - InfrastructureProviders: []v1alpha1.ProviderTuple{{Name: "aws"}}, - BootstrapProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, - ControlPlaneProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, + {Name: "infrastructure-aws"}, + {Name: "control-plane-k0s"}, + {Name: "bootstrap-k0s"}, }), template.WithValidationStatus(v1alpha1.TemplateValidationStatus{Valid: true}), ), @@ -145,9 +145,9 @@ func TestManagedClusterValidateCreate(t *testing.T) { existingObjects: []runtime.Object{ cred, management.NewManagement(management.WithAvailableProviders(v1alpha1.ProvidersTupled{ - InfrastructureProviders: []v1alpha1.ProviderTuple{{Name: "aws", VersionOrConstraint: "v1.0.0"}}, - BootstrapProviders: []v1alpha1.ProviderTuple{{Name: "k0s", VersionOrConstraint: "v1.0.0"}}, - ControlPlaneProviders: []v1alpha1.ProviderTuple{{Name: "k0s", VersionOrConstraint: "v1.0.0"}}, + {Name: "infrastructure-aws", VersionOrConstraint: "v1.0.0"}, + {Name: "control-plane-k0s", VersionOrConstraint: "v1.0.0"}, + {Name: "bootstrap-k0s", VersionOrConstraint: "v1.0.0"}, })), template.NewClusterTemplate( template.WithName(testTemplateName), @@ -171,9 +171,9 @@ func TestManagedClusterValidateCreate(t *testing.T) { template.NewClusterTemplate( template.WithName(testTemplateName), template.WithProvidersStatus(v1alpha1.ProvidersTupled{ - InfrastructureProviders: []v1alpha1.ProviderTuple{{Name: "aws"}}, - BootstrapProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, - ControlPlaneProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, + {Name: "infrastructure-aws"}, + {Name: "control-plane-k0s"}, + {Name: "bootstrap-k0s"}, }), template.WithValidationStatus(v1alpha1.TemplateValidationStatus{Valid: true}), ), @@ -200,9 +200,9 @@ func TestManagedClusterValidateCreate(t *testing.T) { template.NewClusterTemplate( template.WithName(testTemplateName), template.WithProvidersStatus(v1alpha1.ProvidersTupled{ - InfrastructureProviders: []v1alpha1.ProviderTuple{{Name: "aws"}}, - BootstrapProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, - ControlPlaneProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, + {Name: "infrastructure-aws"}, + {Name: "control-plane-k0s"}, + {Name: "bootstrap-k0s"}, }), template.WithValidationStatus(v1alpha1.TemplateValidationStatus{Valid: true}), ), @@ -219,22 +219,22 @@ func TestManagedClusterValidateCreate(t *testing.T) { cred, management.NewManagement( management.WithAvailableProviders(v1alpha1.ProvidersTupled{ - InfrastructureProviders: []v1alpha1.ProviderTuple{{Name: "azure"}}, - BootstrapProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, - ControlPlaneProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, + {Name: "infrastructure-azure"}, + {Name: "control-plane-k0s"}, + {Name: "bootstrap-k0s"}, }), ), template.NewClusterTemplate( template.WithName(testTemplateName), template.WithProvidersStatus(v1alpha1.ProvidersTupled{ - InfrastructureProviders: []v1alpha1.ProviderTuple{{Name: "azure"}}, - BootstrapProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, - ControlPlaneProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, + {Name: "infrastructure-azure"}, + {Name: "control-plane-k0s"}, + {Name: "bootstrap-k0s"}, }), template.WithValidationStatus(v1alpha1.TemplateValidationStatus{Valid: true}), ), }, - err: "the ManagedCluster is invalid: wrong kind of the ClusterIdentity \"AWSClusterStaticIdentity\" for provider \"azure\"", + err: "the ManagedCluster is invalid: wrong kind of the ClusterIdentity \"AWSClusterStaticIdentity\" for provider \"infrastructure-azure\"", }, } for _, tt := range tests { @@ -311,9 +311,9 @@ func TestManagedClusterValidateUpdate(t *testing.T) { ValidationError: "validation error example", }), template.WithProvidersStatus(v1alpha1.ProvidersTupled{ - InfrastructureProviders: []v1alpha1.ProviderTuple{{Name: "aws"}}, - BootstrapProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, - ControlPlaneProviders: []v1alpha1.ProviderTuple{{Name: "k0s"}}, + {Name: "infrastructure-aws"}, + {Name: "control-plane-k0s"}, + {Name: "bootstrap-k0s"}, }), ), }, diff --git a/internal/webhook/management_webhook_test.go b/internal/webhook/management_webhook_test.go index 13bb2942d..a3d311475 100644 --- a/internal/webhook/management_webhook_test.go +++ b/internal/webhook/management_webhook_test.go @@ -46,7 +46,7 @@ func TestManagementValidateUpdate(t *testing.T) { ) providerAwsDefaultTpl := v1alpha1.Provider{ - Name: "aws", + Name: "infrastructure-aws", Component: v1alpha1.Component{ Template: template.DefaultName, }, diff --git a/templates/cluster/aws-eks/Chart.yaml b/templates/cluster/aws-eks/Chart.yaml index 56513523a..683662771 100644 --- a/templates/cluster/aws-eks/Chart.yaml +++ b/templates/cluster/aws-eks/Chart.yaml @@ -8,6 +8,4 @@ type: application # Versions are expected to follow Semantic Versioning (https://semver.org/) version: 0.0.1 annotations: - hmc.mirantis.com/infrastructure-providers: aws - hmc.mirantis.com/controlplane-providers: eks - hmc.mirantis.com/bootstrap-providers: eks + cluster.x-k8s.io/provider: infrastructure-aws diff --git a/templates/cluster/aws-hosted-cp/Chart.yaml b/templates/cluster/aws-hosted-cp/Chart.yaml index 64f6d8f68..10c1fc142 100644 --- a/templates/cluster/aws-hosted-cp/Chart.yaml +++ b/templates/cluster/aws-hosted-cp/Chart.yaml @@ -14,6 +14,4 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "v1.31.1+k0s.1" annotations: - hmc.mirantis.com/infrastructure-providers: aws - hmc.mirantis.com/control-plane-providers: k0smotron - hmc.mirantis.com/bootstrap-providers: k0s + cluster.x-k8s.io/provider: infrastructure-aws; control-plane-k0smotron; bootstrap-k0s diff --git a/templates/cluster/aws-standalone-cp/Chart.yaml b/templates/cluster/aws-standalone-cp/Chart.yaml index 01f0fcada..93edbe18e 100644 --- a/templates/cluster/aws-standalone-cp/Chart.yaml +++ b/templates/cluster/aws-standalone-cp/Chart.yaml @@ -13,6 +13,4 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "v1.31.1+k0s.1" annotations: - hmc.mirantis.com/infrastructure-providers: aws - hmc.mirantis.com/control-plane-providers: k0s - hmc.mirantis.com/bootstrap-providers: k0s + cluster.x-k8s.io/provider: infrastructure-aws; control-plane-k0s; bootstrap-k0s diff --git a/templates/cluster/azure-hosted-cp/Chart.yaml b/templates/cluster/azure-hosted-cp/Chart.yaml index 1a614b992..889326c70 100644 --- a/templates/cluster/azure-hosted-cp/Chart.yaml +++ b/templates/cluster/azure-hosted-cp/Chart.yaml @@ -14,6 +14,4 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "v1.31.1+k0s.1" annotations: - hmc.mirantis.com/infrastructure-providers: azure - hmc.mirantis.com/control-plane-providers: k0s - hmc.mirantis.com/bootstrap-providers: k0s + cluster.x-k8s.io/provider: infrastructure-azure; control-plane-k0s; bootstrap-k0s diff --git a/templates/cluster/azure-standalone-cp/Chart.yaml b/templates/cluster/azure-standalone-cp/Chart.yaml index 16c716767..5f01758d3 100644 --- a/templates/cluster/azure-standalone-cp/Chart.yaml +++ b/templates/cluster/azure-standalone-cp/Chart.yaml @@ -13,6 +13,4 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "1.31.1+k0s.1" annotations: - hmc.mirantis.com/infrastructure-providers: azure - hmc.mirantis.com/control-plane-providers: k0s - hmc.mirantis.com/bootstrap-providers: k0s + cluster.x-k8s.io/provider: infrastructure-azure; control-plane-k0s; bootstrap-k0s diff --git a/templates/cluster/vsphere-hosted-cp/Chart.yaml b/templates/cluster/vsphere-hosted-cp/Chart.yaml index 63c943e5e..e33bb4d3c 100644 --- a/templates/cluster/vsphere-hosted-cp/Chart.yaml +++ b/templates/cluster/vsphere-hosted-cp/Chart.yaml @@ -14,7 +14,5 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "v1.31.1+k0s.1" annotations: + cluster.x-k8s.io/provider: infrastructure-vsphere; control-plane-k0s; bootstrap-k0s hmc.mirantis.com/type: deployment - hmc.mirantis.com/infrastructure-providers: vsphere - hmc.mirantis.com/control-plane-providers: k0s - hmc.mirantis.com/bootstrap-providers: k0s diff --git a/templates/cluster/vsphere-standalone-cp/Chart.yaml b/templates/cluster/vsphere-standalone-cp/Chart.yaml index c96eadd20..49b29322f 100644 --- a/templates/cluster/vsphere-standalone-cp/Chart.yaml +++ b/templates/cluster/vsphere-standalone-cp/Chart.yaml @@ -13,7 +13,5 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "v1.31.1+k0s.1" annotations: + cluster.x-k8s.io/provider: infrastructure-vsphere; control-plane-k0s; bootstrap-k0s hmc.mirantis.com/type: deployment - hmc.mirantis.com/infrastructure-providers: vsphere - hmc.mirantis.com/control-plane-providers: k0s - hmc.mirantis.com/bootstrap-providers: k0s diff --git a/templates/provider/cluster-api-provider-aws/Chart.yaml b/templates/provider/cluster-api-provider-aws/Chart.yaml index b3b3ab54f..86821d729 100644 --- a/templates/provider/cluster-api-provider-aws/Chart.yaml +++ b/templates/provider/cluster-api-provider-aws/Chart.yaml @@ -20,6 +20,4 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "2.6.1" annotations: - hmc.mirantis.com/infrastructure-providers: aws - hmc.mirantis.com/controlplane-providers: eks - hmc.mirantis.com/bootstrap-providers: eks + cluster.x-k8s.io/provider: infrastructure-aws diff --git a/templates/provider/cluster-api-provider-azure/Chart.yaml b/templates/provider/cluster-api-provider-azure/Chart.yaml index 172b7eee3..02feff0d7 100644 --- a/templates/provider/cluster-api-provider-azure/Chart.yaml +++ b/templates/provider/cluster-api-provider-azure/Chart.yaml @@ -20,4 +20,4 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "1.17.0" annotations: - hmc.mirantis.com/infrastructure-providers: azure + cluster.x-k8s.io/provider: infrastructure-azure diff --git a/templates/provider/cluster-api-provider-vsphere/Chart.yaml b/templates/provider/cluster-api-provider-vsphere/Chart.yaml index 4a4db32ab..ce9008714 100644 --- a/templates/provider/cluster-api-provider-vsphere/Chart.yaml +++ b/templates/provider/cluster-api-provider-vsphere/Chart.yaml @@ -20,4 +20,4 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "1.11.1" annotations: - hmc.mirantis.com/infrastructure-providers: vsphere + cluster.x-k8s.io/provider: infrastructure-vsphere diff --git a/templates/provider/hmc/templates/crds/hmc.mirantis.com_clustertemplates.yaml b/templates/provider/hmc/templates/crds/hmc.mirantis.com_clustertemplates.yaml index 51fc2e84e..bd386db7d 100644 --- a/templates/provider/hmc/templates/crds/hmc.mirantis.com_clustertemplates.yaml +++ b/templates/provider/hmc/templates/crds/hmc.mirantis.com_clustertemplates.yaml @@ -112,62 +112,20 @@ spec: Providers represent required CAPI providers with constrained compatibility versions set. Should be set if not present in the Helm chart metadata. Compatibility attributes are optional to be defined. - properties: - bootstrap: - description: |- - List of CAPI bootstrap providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - controlPlane: - description: |- - List of CAPI control plane providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - infrastructure: - description: |- - List of CAPI infrastructure providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - type: object + items: + description: Represents name of the provider with either an exact + or constrained version in the SemVer format. + properties: + name: + description: Name of the provider. + type: string + versionOrConstraint: + description: |- + Compatibility restriction in the SemVer format (exact or constrained version). + Optional to be defined. + type: string + type: object + type: array required: - helm type: object @@ -227,62 +185,20 @@ spec: description: |- Providers represent required CAPI providers with constrained compatibility versions set if the latter has been given. - properties: - bootstrap: - description: |- - List of CAPI bootstrap providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - controlPlane: - description: |- - List of CAPI control plane providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - infrastructure: - description: |- - List of CAPI infrastructure providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - type: object + items: + description: Represents name of the provider with either an exact + or constrained version in the SemVer format. + properties: + name: + description: Name of the provider. + type: string + versionOrConstraint: + description: |- + Compatibility restriction in the SemVer format (exact or constrained version). + Optional to be defined. + type: string + type: object + type: array valid: description: Valid indicates whether the template passed validation or not. diff --git a/templates/provider/hmc/templates/crds/hmc.mirantis.com_managements.yaml b/templates/provider/hmc/templates/crds/hmc.mirantis.com_managements.yaml index 8ffcde13e..d69574975 100644 --- a/templates/provider/hmc/templates/crds/hmc.mirantis.com_managements.yaml +++ b/templates/provider/hmc/templates/crds/hmc.mirantis.com_managements.yaml @@ -115,62 +115,20 @@ spec: description: |- AvailableProviders holds all CAPI providers available along with their exact compatibility versions if specified in ProviderTemplates on the Management cluster. - properties: - bootstrap: - description: |- - List of CAPI bootstrap providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - controlPlane: - description: |- - List of CAPI control plane providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - infrastructure: - description: |- - List of CAPI infrastructure providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - type: object + items: + description: Represents name of the provider with either an exact + or constrained version in the SemVer format. + properties: + name: + description: Name of the provider. + type: string + versionOrConstraint: + description: |- + Compatibility restriction in the SemVer format (exact or constrained version). + Optional to be defined. + type: string + type: object + type: array components: additionalProperties: description: ComponentStatus is the status of Management component diff --git a/templates/provider/hmc/templates/crds/hmc.mirantis.com_providertemplates.yaml b/templates/provider/hmc/templates/crds/hmc.mirantis.com_providertemplates.yaml index 39ddece49..1e584155f 100644 --- a/templates/provider/hmc/templates/crds/hmc.mirantis.com_providertemplates.yaml +++ b/templates/provider/hmc/templates/crds/hmc.mirantis.com_providertemplates.yaml @@ -118,62 +118,20 @@ spec: Providers represent exposed CAPI providers with exact compatibility versions set. Should be set if not present in the Helm chart metadata. Compatibility attributes are optional to be defined. - properties: - bootstrap: - description: |- - List of CAPI bootstrap providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - controlPlane: - description: |- - List of CAPI control plane providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - infrastructure: - description: |- - List of CAPI infrastructure providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - type: object + items: + description: Represents name of the provider with either an exact + or constrained version in the SemVer format. + properties: + name: + description: Name of the provider. + type: string + versionOrConstraint: + description: |- + Compatibility restriction in the SemVer format (exact or constrained version). + Optional to be defined. + type: string + type: object + type: array type: object x-kubernetes-validations: - message: Spec is immutable @@ -239,62 +197,20 @@ spec: description: |- Providers represent exposed CAPI providers with exact compatibility versions set if the latter has been given. - properties: - bootstrap: - description: |- - List of CAPI bootstrap providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - controlPlane: - description: |- - List of CAPI control plane providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - infrastructure: - description: |- - List of CAPI infrastructure providers with either an exact or constrained version in the SemVer format. - Compatibility attributes are optional to be defined. - items: - description: Represents name of the provider with either an - exact or constrained version in the SemVer format. - properties: - name: - description: Name of the provider. - type: string - versionOrConstraint: - description: |- - Compatibility restriction in the SemVer format (exact or constrained version). - Optional to be defined. - type: string - type: object - type: array - type: object + items: + description: Represents name of the provider with either an exact + or constrained version in the SemVer format. + properties: + name: + description: Name of the provider. + type: string + versionOrConstraint: + description: |- + Compatibility restriction in the SemVer format (exact or constrained version). + Optional to be defined. + type: string + type: object + type: array valid: description: Valid indicates whether the template passed validation or not. diff --git a/templates/provider/hmc/templates/crds/hmc.mirantis.com_servicetemplates.yaml b/templates/provider/hmc/templates/crds/hmc.mirantis.com_servicetemplates.yaml index 967e71ac7..84c17f57f 100644 --- a/templates/provider/hmc/templates/crds/hmc.mirantis.com_servicetemplates.yaml +++ b/templates/provider/hmc/templates/crds/hmc.mirantis.com_servicetemplates.yaml @@ -111,26 +111,9 @@ spec: description: |- Providers represent requested CAPI providers. Should be set if not present in the Helm chart metadata. - properties: - bootstrap: - description: BootstrapProviders is the list of CAPI bootstrap - providers - items: - type: string - type: array - controlPlane: - description: ControlPlaneProviders is the list of CAPI control - plane providers - items: - type: string - type: array - infrastructure: - description: InfrastructureProviders is the list of CAPI infrastructure - providers - items: - type: string - type: array - type: object + items: + type: string + type: array required: - helm type: object @@ -188,26 +171,9 @@ spec: type: integer providers: description: Providers represent requested CAPI providers. - properties: - bootstrap: - description: BootstrapProviders is the list of CAPI bootstrap - providers - items: - type: string - type: array - controlPlane: - description: ControlPlaneProviders is the list of CAPI control - plane providers - items: - type: string - type: array - infrastructure: - description: InfrastructureProviders is the list of CAPI infrastructure - providers - items: - type: string - type: array - type: object + items: + type: string + type: array valid: description: Valid indicates whether the template passed validation or not. diff --git a/templates/provider/k0smotron/Chart.yaml b/templates/provider/k0smotron/Chart.yaml index 47ce14d17..9e1e376c2 100644 --- a/templates/provider/k0smotron/Chart.yaml +++ b/templates/provider/k0smotron/Chart.yaml @@ -20,6 +20,4 @@ version: 0.0.2 # It is recommended to use it with quotes. appVersion: "1.0.4" annotations: - hmc.mirantis.com/infrastructure-providers: k0smotron - hmc.mirantis.com/bootstrap-providers: k0s - hmc.mirantis.com/control-plane-providers: k0s; k0smotron + cluster.x-k8s.io/provider: infrastructure-k0smotron; bootstrap-k0s; control-plane-k0s; control-plane-k0smotron