Skip to content

Commit

Permalink
Align provider names with the CAPI labels
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
zerospiel committed Oct 18, 2024
1 parent a4c12b1 commit 91f2165
Show file tree
Hide file tree
Showing 27 changed files with 269 additions and 572 deletions.
14 changes: 2 additions & 12 deletions api/v1alpha1/clustertemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
66 changes: 39 additions & 27 deletions api/v1alpha1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package v1alpha1

import (
"context"
"strings"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -36,30 +37,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 {
Expand Down Expand Up @@ -145,6 +137,20 @@ func ExtractServiceTemplateName(rawObj client.Object) []string {
return templates
}

const (
// TODO (zerospiel): temporary global
bprefix, cpprefix, iprefix = "bootstrap-", "control-plane-", "infrastructure-"
)

// Names strips all the provider-type prefixes, returning only names of the providers.
func (c Providers) Names() []string {
nn := make([]string, len(c))
for i, v := range c {
nn[i] = strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(v, bprefix), cpprefix), iprefix)
}
return nn
}

func (c ProvidersTupled) BootstrapProvidersNames() []string {
return c.names(bootstrapProvidersType)
}
Expand All @@ -158,22 +164,28 @@ func (c ProvidersTupled) InfrastructureProvidersNames() []string {
}

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
f := func(p string) []string {
res := make([]string, 0, len(c))
for _, v := range c {
if strings.HasPrefix(v.Name, p) {
res = append(res, v.Name[len(p):])
}
}
return res
}

switch typ {
case bootstrapProvidersType:
return f(c.BootstrapProviders)
return f(bprefix)
case controlPlaneProvidersType:
return f(c.ControlPlaneProviders)
return f(cpprefix)
case infrastructureProvidersType:
return f(c.InfrastructureProviders)
return f(iprefix)
default:
return []string{}
nn := make([]string, len(c))
for i, v := range c {
nn[i] = strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(v.Name, bprefix), cpprefix), iprefix)
}
return nn
}
}
14 changes: 2 additions & 12 deletions api/v1alpha1/providertemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
35 changes: 7 additions & 28 deletions api/v1alpha1/servicetemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
40 changes: 14 additions & 26 deletions api/v1alpha1/templates_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -85,22 +82,26 @@ const (
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)
Expand All @@ -127,16 +128,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{}, ""
}
}
Loading

0 comments on commit 91f2165

Please sign in to comment.