diff --git a/api/v1beta1/azuremanagedmachinepool_webhook.go b/api/v1beta1/azuremanagedmachinepool_webhook.go index 86be164f2aa4..decb98786781 100644 --- a/api/v1beta1/azuremanagedmachinepool_webhook.go +++ b/api/v1beta1/azuremanagedmachinepool_webhook.go @@ -23,11 +23,13 @@ import ( "regexp" "strconv" "strings" + "unicode" "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" kerrors "k8s.io/apimachinery/pkg/util/errors" + utilrand "k8s.io/apimachinery/pkg/util/rand" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/utils/ptr" "sigs.k8s.io/cluster-api-provider-azure/feature" @@ -72,9 +74,9 @@ func (mw *azureManagedMachinePoolWebhook) Default(ctx context.Context, obj runti m.Labels[LabelAgentPoolMode] = m.Spec.Mode if m.Spec.Name == nil || *m.Spec.Name == "" { - m.Spec.Name = &m.Name + aksNodePoolName := generateAKSNodePoolName(m.Name) + m.Spec.Name = &aksNodePoolName } - if m.Spec.OSType == nil { m.Spec.OSType = ptr.To(DefaultOSType) } @@ -82,6 +84,24 @@ func (mw *azureManagedMachinePoolWebhook) Default(ctx context.Context, obj runti return nil } +// Generates a valid unique nodepool name following limitations of Azure. +func generateAKSNodePoolName(name string) string { + name = strings.ToLower(name) + name = strings.Map(func(r rune) rune { + if unicode.IsNumber(r) || unicode.IsLetter(r) { + return r + } + return -1 + }, name) + name = strings.TrimLeftFunc(name, unicode.IsNumber) + if len(name) > 6 { + name = name[:6] + } else if name == "" { + name = "pool" + } + return fmt.Sprintf("%s%s", name, utilrand.String(6)) +} + //+kubebuilder:webhook:verbs=create;update;delete,path=/validate-infrastructure-cluster-x-k8s-io-v1beta1-azuremanagedmachinepool,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=azuremanagedmachinepools,versions=v1beta1,name=validation.azuremanagedmachinepools.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1 // ValidateCreate implements webhook.Validator so a webhook will be registered for the type. @@ -371,6 +391,35 @@ func (m *AzureManagedMachinePool) validateName() error { "Windows agent pool name can not be longer than 6 characters.") } + // Length check for linux following restrictions of AKS. + if (m.Spec.OSType == nil || *m.Spec.OSType == LinuxOS) && + (m.Spec.Name != nil && len(*m.Spec.Name) > 12) { + return field.Invalid( + field.NewPath("Spec", "Name"), + m.Spec.Name, + "Linux agent pool name can not be longer than 12 characters.") + } + + // Common Checks for both Windows & Linux following restrictions of AKS. + if m.Spec.Name != nil { + for _, char := range *m.Spec.Name { + if !unicode.IsLower(char) && !unicode.IsNumber(char) { + return field.Invalid( + field.NewPath("Spec", "Name"), + m.Spec.Name, + "Agent pool name may only contain lowercase alphanumeric characters.") + } + } + + nodePoolName := *m.Spec.Name + if !unicode.IsLower(rune(nodePoolName[0])) { + return field.Invalid( + field.NewPath("Spec", "Name"), + m.Spec.Name, + "Linux agent pool name must begin with a lowercase letter.") + } + } + return nil }