Skip to content

🌱 Add Namingstrategy to InfraCluster #11898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions api/v1beta1/clusterclass_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ type ClusterClassSpec struct {
// +optional
Infrastructure LocalObjectTemplate `json:"infrastructure,omitempty"`

// infrastructureNamingStrategy allows changing the naming pattern used when creating the infrastructure object.
// +optional
InfrastructureNamingStrategy *InfrastructureNamingStrategy `json:"infrastructureNamingStrategy,omitempty"`

// controlPlane is a reference to a local struct that holds the details
// for provisioning the Control Plane for the Cluster.
// +optional
Expand Down Expand Up @@ -207,6 +211,19 @@ type ControlPlaneClassNamingStrategy struct {
Template *string `json:"template,omitempty"`
}

// InfrastructureNamingStrategy defines the naming strategy for infrastructure objects.
type InfrastructureNamingStrategy struct {
// template defines the template to use for generating the name of the Infrastructure object.
// If not defined, it will fallback to `{{ .cluster.name }}-{{ .random }}`.
// If the templated string exceeds 63 characters, it will be trimmed to 58 characters and will
// get concatenated with a random suffix of length 5.
// The templating mechanism provides the following arguments:
// * `.cluster.name`: The name of the cluster object.
// * `.random`: A random alphanumeric string, without vowels, of length 5.
// +optional
Template *string `json:"template,omitempty"`
}

// WorkersClass is a collection of deployment classes.
type WorkersClass struct {
// machineDeployments is a list of machine deployment classes that can be used to create
Expand Down
25 changes: 25 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

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

29 changes: 28 additions & 1 deletion api/v1beta1/zz_generated.openapi.go

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

15 changes: 15 additions & 0 deletions config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml

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

7 changes: 6 additions & 1 deletion exp/topology/desiredstate/desired_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,16 @@ func computeInfrastructureCluster(_ context.Context, s *scope.Scope) (*unstructu
cluster := s.Current.Cluster
currentRef := cluster.Spec.InfrastructureRef

nameTemplate := "{{ .cluster.name }}-{{ .random }}"
if s.Blueprint.ClusterClass.Spec.InfrastructureNamingStrategy != nil && s.Blueprint.ClusterClass.Spec.InfrastructureNamingStrategy.Template != nil {
nameTemplate = *s.Blueprint.ClusterClass.Spec.InfrastructureNamingStrategy.Template
}

infrastructureCluster, err := templateToObject(templateToInput{
template: template,
templateClonedFromRef: templateClonedFromRef,
cluster: cluster,
nameGenerator: topologynames.SimpleNameGenerator(fmt.Sprintf("%s-", cluster.Name)),
nameGenerator: topologynames.InfraClusterNameGenerator(nameTemplate, cluster.Name),
currentObjectRef: currentRef,
// Note: It is not possible to add an ownerRef to Cluster at this stage, otherwise the provisioning
// of the infrastructure cluster starts no matter of the object being actually referenced by the Cluster itself.
Expand Down
1 change: 1 addition & 0 deletions internal/apis/core/v1alpha4/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ func (src *ClusterClass) ConvertTo(dstRaw conversion.Hub) error {
dst.Spec.ControlPlane.MachineHealthCheck = restored.Spec.ControlPlane.MachineHealthCheck
dst.Spec.ControlPlane.ReadinessGates = restored.Spec.ControlPlane.ReadinessGates
dst.Spec.ControlPlane.NamingStrategy = restored.Spec.ControlPlane.NamingStrategy
dst.Spec.InfrastructureNamingStrategy = restored.Spec.InfrastructureNamingStrategy
dst.Spec.ControlPlane.NodeDrainTimeout = restored.Spec.ControlPlane.NodeDrainTimeout
dst.Spec.ControlPlane.NodeVolumeDetachTimeout = restored.Spec.ControlPlane.NodeVolumeDetachTimeout
dst.Spec.ControlPlane.NodeDeletionTimeout = restored.Spec.ControlPlane.NodeDeletionTimeout
Expand Down
1 change: 1 addition & 0 deletions internal/apis/core/v1alpha4/zz_generated.conversion.go

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

6 changes: 6 additions & 0 deletions internal/topology/names/names.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ func MachineSetMachineNameGenerator(templateString, clusterName, machineSetName
})
}

// InfraClusterNameGenerator returns a generator for creating a infrastructure cluster name.
func InfraClusterNameGenerator(templateString, clusterName string) NameGenerator {
return newTemplateGenerator(templateString, clusterName,
map[string]interface{}{})
}

// templateGenerator parses the template string as text/template and executes it using
// the passed data to generate a name.
type templateGenerator struct {
Expand Down
17 changes: 17 additions & 0 deletions internal/webhooks/clusterclass.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,23 @@ func validateMachineHealthCheckClasses(clusterClass *clusterv1.ClusterClass) fie
func validateNamingStrategies(clusterClass *clusterv1.ClusterClass) field.ErrorList {
var allErrs field.ErrorList

if clusterClass.Spec.InfrastructureNamingStrategy != nil && clusterClass.Spec.InfrastructureNamingStrategy.Template != nil {
name, err := topologynames.InfraClusterNameGenerator(*clusterClass.Spec.InfrastructureNamingStrategy.Template, "cluster").GenerateName()
templateFldPath := field.NewPath("spec", "infrastructureNamingStrategy", "template")
if err != nil {
allErrs = append(allErrs,
field.Invalid(
templateFldPath,
*clusterClass.Spec.InfrastructureNamingStrategy.Template,
fmt.Sprintf("invalid InfraCluster name template: %v", err),
))
} else {
for _, err := range validation.IsDNS1123Subdomain(name) {
allErrs = append(allErrs, field.Invalid(templateFldPath, *clusterClass.Spec.InfrastructureNamingStrategy.Template, err))
}
}
}

if clusterClass.Spec.ControlPlane.NamingStrategy != nil && clusterClass.Spec.ControlPlane.NamingStrategy.Template != nil {
name, err := topologynames.ControlPlaneNameGenerator(*clusterClass.Spec.ControlPlane.NamingStrategy.Template, "cluster").GenerateName()
templateFldPath := field.NewPath("spec", "controlPlane", "namingStrategy", "template")
Expand Down
31 changes: 31 additions & 0 deletions internal/webhooks/clusterclass_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1644,6 +1644,7 @@ func TestClusterClassValidation(t *testing.T) {
in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(
builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
WithInfraClusterStrategy(&clusterv1.InfrastructureNamingStrategy{Template: ptr.To("{{ .cluster.name }}-infra-{{ .random }}")}).
WithControlPlaneTemplate(
builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
Build()).
Expand All @@ -1670,6 +1671,36 @@ func TestClusterClassValidation(t *testing.T) {
Build(),
expectErr: false,
},
{
name: "should return error for invalid InfraCluster InfrastructuresNamingStrategy.template",
in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(
builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
WithInfraClusterStrategy(&clusterv1.InfrastructureNamingStrategy{Template: ptr.To("template-infra-{{ .invalidkey }}")}).
WithControlPlaneTemplate(
builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
Build()).
WithControlPlaneInfrastructureMachineTemplate(
builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
Build()).
Build(),
expectErr: true,
},
{
name: "should return error for invalid InfraCluster InfrastructuresNamingStrategy.template when the generated name does not conform to RFC 1123",
in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(
builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
WithInfraClusterStrategy(&clusterv1.InfrastructureNamingStrategy{Template: ptr.To("template-infra-{{ .cluster.name }}-")}).
WithControlPlaneTemplate(
builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
Build()).
WithControlPlaneInfrastructureMachineTemplate(
builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
Build()).
Build(),
expectErr: true,
},
{
name: "should return error for invalid ControlPlane namingStrategy.template",
in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ spec:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerClusterTemplate
name: quick-start-cluster
infrastructureNamingStrategy:
template: "{{ .cluster.name }}-infra-{{ .random }}"
workers:
machineDeployments:
- class: default-worker
Expand Down
10 changes: 10 additions & 0 deletions util/test/builder/builders.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ type ClusterClassBuilder struct {
controlPlaneNodeVolumeDetachTimeout *metav1.Duration
controlPlaneNodeDeletionTimeout *metav1.Duration
controlPlaneNamingStrategy *clusterv1.ControlPlaneClassNamingStrategy
infraClusterNamingStrategy *clusterv1.InfrastructureNamingStrategy
machineDeploymentClasses []clusterv1.MachineDeploymentClass
machinePoolClasses []clusterv1.MachinePoolClass
variables []clusterv1.ClusterClassVariable
Expand Down Expand Up @@ -426,6 +427,12 @@ func (c *ClusterClassBuilder) WithControlPlaneNamingStrategy(n *clusterv1.Contro
return c
}

// WithInfraClusterStrategy sets the NamingStrategy for the infra cluster to the ClusterClassBuilder.
func (c *ClusterClassBuilder) WithInfraClusterStrategy(n *clusterv1.InfrastructureNamingStrategy) *ClusterClassBuilder {
c.infraClusterNamingStrategy = n
return c
}

// WithVariables adds the Variables to the ClusterClassBuilder.
func (c *ClusterClassBuilder) WithVariables(vars ...clusterv1.ClusterClassVariable) *ClusterClassBuilder {
c.variables = vars
Expand Down Expand Up @@ -524,6 +531,9 @@ func (c *ClusterClassBuilder) Build() *clusterv1.ClusterClass {
if c.controlPlaneNamingStrategy != nil {
obj.Spec.ControlPlane.NamingStrategy = c.controlPlaneNamingStrategy
}
if c.infraClusterNamingStrategy != nil {
obj.Spec.InfrastructureNamingStrategy = c.infraClusterNamingStrategy
}

obj.Spec.Workers.MachineDeployments = c.machineDeploymentClasses
obj.Spec.Workers.MachinePools = c.machinePoolClasses
Expand Down
5 changes: 5 additions & 0 deletions util/test/builder/zz_generated.deepcopy.go

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