Skip to content

Commit

Permalink
Addressed comments on compatibility attrs
Browse files Browse the repository at this point in the history
* amends to descs and fix typos
* correctly parse providers
* changed providers anno separator
* enforce CAPI version check
  in providertemplates
* amends to the API regarding
  CAPI version compatibility
  • Loading branch information
zerospiel authored and Kshatrix committed Oct 15, 2024
1 parent 571dc77 commit 545f2ba
Show file tree
Hide file tree
Showing 26 changed files with 654 additions and 338 deletions.
21 changes: 12 additions & 9 deletions api/v1alpha1/clustertemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,20 @@ const (
// ClusterTemplateSpec defines the desired state of ClusterTemplate
type ClusterTemplateSpec struct {
Helm HelmSpec `json:"helm"`
// Compatible K8S version of the cluster set in the SemVer format.
KubertenesVersion string `json:"k8sVersion,omitempty"`
// Providers represent required CAPI providers with constrainted compatibility versions set. Should be set if not present in the Helm chart metadata.
// Kubernetes exact version in the SemVer format provided by this ClusterTemplate.
KubernetesVersion string `json:"k8sVersion,omitempty"`
// 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.
Providers ProvidersTupled `json:"providers,omitempty"`
}

// ClusterTemplateStatus defines the observed state of ClusterTemplate
type ClusterTemplateStatus struct {
// Compatible K8S version of the cluster set in the SemVer format.
KubertenesVersion string `json:"k8sVersion,omitempty"`
// Providers represent exposed CAPI providers with constrainted compatibility versions set.
// Kubernetes exact version in the SemVer format provided by this ClusterTemplate.
KubernetesVersion string `json:"k8sVersion,omitempty"`
// Providers represent required CAPI providers with constrained compatibility versions set
// if the latter has been given.
Providers ProvidersTupled `json:"providers,omitempty"`

TemplateStatusCommon `json:",inline"`
Expand All @@ -67,8 +70,8 @@ func (t *ClusterTemplate) FillStatusWithProviders(annotations map[string]string)
}

kversion := annotations[ChartAnnotationKubernetesVersion]
if t.Spec.KubertenesVersion != "" {
kversion = t.Spec.KubertenesVersion
if t.Spec.KubernetesVersion != "" {
kversion = t.Spec.KubernetesVersion
}
if kversion == "" {
return nil
Expand All @@ -78,7 +81,7 @@ func (t *ClusterTemplate) FillStatusWithProviders(annotations map[string]string)
return fmt.Errorf("failed to parse kubernetes version %s: %w", kversion, err)
}

t.Status.KubertenesVersion = kversion
t.Status.KubernetesVersion = kversion

return nil
}
Expand Down
16 changes: 10 additions & 6 deletions api/v1alpha1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,26 @@ type (
}

// Holds different types of CAPI providers with either
// an exact or constrainted version in the SemVer format. The requirement
// 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 constrainted version in the SemVer format.
// 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 constrainted version in the SemVer format.
// 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 constrainted version in the SemVer format.
// 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"`
}

// Represents name of the provider with either an exact or constrainted version in the SemVer format.
// Represents name of the provider with either an exact or constrained version in the SemVer format.
ProviderTuple struct {
// Name of the provider.
Name string `json:"name,omitempty"`
// Compatibility restriction in the SemVer format (exact or constrainted version)
// Compatibility restriction in the SemVer format (exact or constrained version).
// Optional to be defined.
VersionOrConstraint string `json:"versionOrConstraint,omitempty"`
}
)
Expand Down
7 changes: 2 additions & 5 deletions api/v1alpha1/managedcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,9 @@ type ManagedClusterSpec struct {

// ManagedClusterStatus defines the observed state of ManagedCluster
type ManagedClusterStatus struct {
// Currently compatible K8S version of the cluster. Being set only if
// Currently compatible exact Kubernetes version of the cluster. Being set only if
// provided by the corresponding ClusterTemplate.
KubertenesVersion string `json:"k8sVersion,omitempty"`
// Providers represent exposed CAPI providers with constrainted compatibility versions set.
// Propagated from the corresponding ClusterTemplate.
Providers ProvidersTupled `json:"providers,omitempty"`
KubernetesVersion string `json:"k8sVersion,omitempty"`
// Conditions contains details for the current state of the ManagedCluster
Conditions []metav1.Condition `json:"conditions,omitempty"`
// ObservedGeneration is the last observed generation.
Expand Down
70 changes: 51 additions & 19 deletions api/v1alpha1/providertemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,39 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ChartAnnotationCAPIVersion is an annotation containing the CAPI exact version in the SemVer format associated with a ProviderTemplate.
const ChartAnnotationCAPIVersion = "hmc.mirantis.com/capi-version"
const (
// ChartAnnotationCAPIVersion is an annotation containing the CAPI exact version in the SemVer format associated with a ProviderTemplate.
ChartAnnotationCAPIVersion = "hmc.mirantis.com/capi-version"
// ChartAnnotationCAPIVersionConstraint is an annotation containing the CAPI version constraint in the SemVer format associated with a ProviderTemplate.
ChartAnnotationCAPIVersionConstraint = "hmc.mirantis.com/capi-version-constraint"
)

// +kubebuilder:validation:XValidation:rule="!(has(self.capiVersion) && has(self.capiVersionConstraint))", message="Either capiVersion or capiVersionConstraint may be set, but not both"

// ProviderTemplateSpec defines the desired state of ProviderTemplate
type ProviderTemplateSpec struct {
Helm HelmSpec `json:"helm"`
// Compatible CAPI provider version set in the SemVer format.
Helm HelmSpec `json:"helm,omitempty"`
// CAPI exact version in the SemVer format.
// Applicable only for the cluster-api ProviderTemplate itself.
CAPIVersion string `json:"capiVersion,omitempty"`
// Represents required CAPI providers with exact compatibility versions set. Should be set if not present in the Helm chart metadata.
// CAPI version constraint in the SemVer format indicating compatibility with the core CAPI.
// Not applicable for the cluster-api ProviderTemplate.
CAPIVersionConstraint string `json:"capiVersionConstraint,omitempty"`
// 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.
Providers ProvidersTupled `json:"providers,omitempty"`
}

// ProviderTemplateStatus defines the observed state of ProviderTemplate
type ProviderTemplateStatus struct {
// Compatible CAPI provider version in the SemVer format.
// CAPI exact version in the SemVer format.
// Applicable only for the capi Template itself.
CAPIVersion string `json:"capiVersion,omitempty"`
// Providers represent exposed CAPI providers with exact compatibility versions set.
// CAPI version constraint in the SemVer format indicating compatibility with the core CAPI.
CAPIVersionConstraint string `json:"capiVersionConstraint,omitempty"`
// Providers represent exposed CAPI providers with exact compatibility versions set
// if the latter has been given.
Providers ProvidersTupled `json:"providers,omitempty"`

TemplateStatusCommon `json:",inline"`
Expand All @@ -62,19 +78,35 @@ func (t *ProviderTemplate) FillStatusWithProviders(annotations map[string]string
return fmt.Errorf("failed to parse ProviderTemplate infrastructure providers: %v", err)
}

capiVersion := annotations[ChartAnnotationCAPIVersion]
if t.Spec.CAPIVersion != "" {
capiVersion = t.Spec.CAPIVersion
if t.Name == CoreCAPIName {
capiVersion := annotations[ChartAnnotationCAPIVersion]
if t.Spec.CAPIVersion != "" {
capiVersion = t.Spec.CAPIVersion
}
if capiVersion == "" {
return nil
}

if _, err := semver.NewVersion(capiVersion); err != nil {
return fmt.Errorf("failed to parse CAPI version %s: %w", capiVersion, err)
}

t.Status.CAPIVersion = capiVersion
} else {
capiConstraint := annotations[ChartAnnotationCAPIVersionConstraint]
if t.Spec.CAPIVersionConstraint != "" {
capiConstraint = t.Spec.CAPIVersionConstraint
}
if capiConstraint == "" {
return nil
}

if _, err := semver.NewConstraint(capiConstraint); err != nil {
return fmt.Errorf("failed to parse CAPI version constraint %s: %w", capiConstraint, err)
}

t.Status.CAPIVersionConstraint = capiConstraint
}
if capiVersion == "" {
return nil
}

if _, err := semver.NewVersion(capiVersion); err != nil {
return fmt.Errorf("failed to parse CAPI version %s: %w", capiVersion, err)
}

t.Status.CAPIVersion = capiVersion

return nil
}
Expand Down
26 changes: 12 additions & 14 deletions api/v1alpha1/servicetemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,25 @@ import (
const (
// Denotes the servicetemplate resource Kind.
ServiceTemplateKind = "ServiceTemplate"
// ChartAnnotationKubernetesConstraint is an annotation containing the Kubernetes constrainted version in the SemVer format associated with a ServiceTemplate.
// ChartAnnotationKubernetesConstraint is an annotation containing the Kubernetes constrained version in the SemVer format associated with a ServiceTemplate.
ChartAnnotationKubernetesConstraint = "hmc.mirantis.com/k8s-version-constraint"
)

// ServiceTemplateSpec defines the desired state of ServiceTemplate
type ServiceTemplateSpec struct {
Helm HelmSpec `json:"helm"`
// Constraint describing compatible K8S versions of the cluster set in the SemVer format.
KubertenesConstraint string `json:"k8sConstraint,omitempty"`
// Represents required CAPI providers. Should be set if not present in the Helm chart metadata.
KubernetesConstraint string `json:"k8sConstraint,omitempty"`
// Providers represent requested CAPI providers.
// Should be set if not present in the Helm chart metadata.
Providers Providers `json:"providers,omitempty"`
}

// ServiceTemplateStatus defines the observed state of ServiceTemplate
type ServiceTemplateStatus struct {
// Constraint describing compatible K8S versions of the cluster set in the SemVer format.
KubertenesConstraint string `json:"k8sConstraint,omitempty"`
// Represents exposed CAPI providers.
KubernetesConstraint string `json:"k8sConstraint,omitempty"`
// Providers represent requested CAPI providers.
Providers Providers `json:"providers,omitempty"`

TemplateStatusCommon `json:",inline"`
Expand All @@ -65,17 +66,14 @@ func (t *ServiceTemplate) FillStatusWithProviders(annotations map[string]string)
pspec, anno = t.Spec.Providers.InfrastructureProviders, ChartAnnotationInfraProviders
}

if len(pspec) > 0 {
return pspec
}

providers := annotations[anno]
if len(providers) == 0 {
return []string{}
return pspec
}

splitted := strings.Split(providers, ",")
splitted := strings.Split(providers, multiProviderSeparator)
result := make([]string, 0, len(splitted))
result = append(result, pspec...)
for _, v := range splitted {
if c := strings.TrimSpace(v); c != "" {
result = append(result, c)
Expand All @@ -90,8 +88,8 @@ func (t *ServiceTemplate) FillStatusWithProviders(annotations map[string]string)
t.Status.Providers.InfrastructureProviders = parseProviders(infrastructureProvidersType)

kconstraint := annotations[ChartAnnotationKubernetesConstraint]
if t.Spec.KubertenesConstraint != "" {
kconstraint = t.Spec.KubertenesConstraint
if t.Spec.KubernetesConstraint != "" {
kconstraint = t.Spec.KubernetesConstraint
}
if kconstraint == "" {
return nil
Expand All @@ -101,7 +99,7 @@ func (t *ServiceTemplate) FillStatusWithProviders(annotations map[string]string)
return fmt.Errorf("failed to parse kubernetes constraint %s: %w", kconstraint, err)
}

t.Status.KubertenesConstraint = kconstraint
t.Status.KubernetesConstraint = kconstraint

return nil
}
Expand Down
13 changes: 7 additions & 6 deletions api/v1alpha1/templates_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,23 @@ const (
infrastructureProvidersType
)

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)
if len(pspec) > 0 {
return pspec, nil
}

providers := annotations[anno]
if len(providers) == 0 {
return []ProviderTuple{}, nil
return pspec, nil
}

var (
splitted = strings.Split(providers, ",")
pstatus = make([]ProviderTuple, 0, len(splitted))
splitted = strings.Split(providers, multiProviderSeparator)
pstatus = make([]ProviderTuple, 0, len(splitted)+len(pspec))
merr error
)
pstatus = append(pstatus, pspec...)

for _, v := range splitted {
v = strings.TrimSpace(v)
nVerOrC := strings.SplitN(v, " ", 2)
Expand Down
1 change: 0 additions & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions internal/controller/managedcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,7 @@ func (r *ManagedClusterReconciler) Update(ctx context.Context, managedCluster *h
return ctrl.Result{}, errors.New(errMsg)
}
// template is ok, propagate data from it
managedCluster.Status.KubertenesVersion = template.Status.KubertenesVersion
managedCluster.Status.Providers = template.Status.Providers
managedCluster.Status.KubernetesVersion = template.Status.KubernetesVersion

apimeta.SetStatusCondition(managedCluster.GetConditions(), metav1.Condition{
Type: hmc.TemplateReadyCondition,
Expand Down
8 changes: 4 additions & 4 deletions internal/controller/release_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ type ReleaseReconciler struct {

Config *rest.Config

CreateManagement bool
CreateRelease bool
CreateTemplates bool

HMCTemplatesChartName string
SystemNamespace string

DefaultRegistryConfig helm.DefaultRegistryConfig

CreateManagement bool
CreateRelease bool
CreateTemplates bool
}

func (r *ReleaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
Expand Down
6 changes: 3 additions & 3 deletions internal/controller/template_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ const (
// TemplateReconciler reconciles a *Template object
type TemplateReconciler struct {
client.Client
SystemNamespace string

DefaultRegistryConfig helm.DefaultRegistryConfig

downloadHelmChartFunc func(context.Context, *sourcev1.Artifact) (*chart.Chart, error)

SystemNamespace string
DefaultRegistryConfig helm.DefaultRegistryConfig
}

type ClusterTemplateReconciler struct {
Expand Down
2 changes: 1 addition & 1 deletion internal/helm/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ type ReconcileHelmReleaseOpts struct {
OwnerReference *metav1.OwnerReference
ChartRef *hcv2.CrossNamespaceSourceReference
ReconcileInterval *time.Duration
DependsOn []meta.NamespacedObjectReference
TargetNamespace string
DependsOn []meta.NamespacedObjectReference
CreateNamespace bool
}

Expand Down
Loading

0 comments on commit 545f2ba

Please sign in to comment.