diff --git a/azure/services/agentpools/agentpools.go b/azure/services/agentpools/agentpools.go index d5eecd13583..667924616d5 100644 --- a/azure/services/agentpools/agentpools.go +++ b/azure/services/agentpools/agentpools.go @@ -74,6 +74,7 @@ func (s *Service) Reconcile(ctx context.Context) error { OrchestratorVersion: agentPoolSpec.Version, VnetSubnetID: &agentPoolSpec.VnetSubnetID, Mode: containerservice.AgentPoolMode(agentPoolSpec.Mode), + AvailabilityZones: &agentPoolSpec.AvailabilityZones, }, } @@ -118,7 +119,7 @@ func (s *Service) Reconcile(ctx context.Context) error { } // Diff and check if we require an update - diff := cmp.Diff(existingProfile, normalizedProfile) + diff := cmp.Diff(normalizedProfile, existingProfile) if diff != "" { klog.V(2).Infof("Update required (+new -old):\n%s", diff) err = s.Client.CreateOrUpdate(ctx, agentPoolSpec.ResourceGroup, agentPoolSpec.Cluster, agentPoolSpec.Name, profile) diff --git a/azure/services/managedclusters/managedclusters.go b/azure/services/managedclusters/managedclusters.go index 7c09d9350f9..71552b7210d 100644 --- a/azure/services/managedclusters/managedclusters.go +++ b/azure/services/managedclusters/managedclusters.go @@ -154,13 +154,14 @@ func (s *Service) Reconcile(ctx context.Context) error { for i := range managedClusterSpec.AgentPools { pool := managedClusterSpec.AgentPools[i] profile := containerservice.ManagedClusterAgentPoolProfile{ - Name: &pool.Name, - VMSize: &pool.SKU, - OsDiskSizeGB: &pool.OSDiskSizeGB, - Count: &pool.Replicas, - Type: containerservice.AgentPoolTypeVirtualMachineScaleSets, - VnetSubnetID: &managedClusterSpec.VnetSubnetID, - Mode: containerservice.AgentPoolModeSystem, + Name: &pool.Name, + VMSize: &pool.SKU, + OsDiskSizeGB: &pool.OSDiskSizeGB, + Count: &pool.Replicas, + Type: containerservice.AgentPoolTypeVirtualMachineScaleSets, + VnetSubnetID: &managedClusterSpec.VnetSubnetID, + Mode: containerservice.AgentPoolModeSystem, + AvailabilityZones: &pool.AvailabilityZones, } *managedCluster.AgentPoolProfiles = append(*managedCluster.AgentPoolProfiles, profile) } diff --git a/azure/types.go b/azure/types.go index 8d659eb85bf..f8e684dcd9c 100644 --- a/azure/types.go +++ b/azure/types.go @@ -400,4 +400,7 @@ type AgentPoolSpec struct { // Mode represents mode of an agent pool. Possible values include: 'System', 'User'. Mode string + + // AvailabilityZones represents the + AvailabilityZones []string } diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedmachinepools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedmachinepools.yaml index 8c9ab2c64cf..6e338f8cc02 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedmachinepools.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedmachinepools.yaml @@ -42,6 +42,12 @@ spec: description: AzureManagedMachinePoolSpec defines the desired state of AzureManagedMachinePool. properties: + availabilityZones: + description: AvailabilityZones - Availability zones for nodes. Must + use VirtualMachineScaleSets AgentPoolType. + items: + type: string + type: array mode: description: 'Mode - represents mode of an agent pool. Possible values include: System, User.' @@ -117,6 +123,12 @@ spec: description: AzureManagedMachinePoolSpec defines the desired state of AzureManagedMachinePool. properties: + availabilityZones: + description: AvailabilityZones - Availability zones for nodes. Must + use VirtualMachineScaleSets AgentPoolType. + items: + type: string + type: array mode: description: 'Mode - represents mode of an agent pool. Possible values include: System, User.' diff --git a/exp/api/v1alpha3/azuremanagedmachinepool_types.go b/exp/api/v1alpha3/azuremanagedmachinepool_types.go index cfdd986a31f..45033df7481 100644 --- a/exp/api/v1alpha3/azuremanagedmachinepool_types.go +++ b/exp/api/v1alpha3/azuremanagedmachinepool_types.go @@ -27,6 +27,9 @@ type AzureManagedMachinePoolSpec struct { // +kubebuilder:validation:Enum=System;User Mode string `json:"mode"` + // AvailabilityZones - Availability zones for nodes. Must use VirtualMachineScaleSets AgentPoolType. + AvailabilityZones []string `json:"availabilityZones,omitempty"` + // SKU is the size of the VMs in the node pool. SKU string `json:"sku"` diff --git a/exp/api/v1alpha3/zz_generated.conversion.go b/exp/api/v1alpha3/zz_generated.conversion.go index cb0d982489e..4ed59351b98 100644 --- a/exp/api/v1alpha3/zz_generated.conversion.go +++ b/exp/api/v1alpha3/zz_generated.conversion.go @@ -848,6 +848,7 @@ func Convert_v1alpha4_AzureManagedMachinePoolList_To_v1alpha3_AzureManagedMachin func autoConvert_v1alpha3_AzureManagedMachinePoolSpec_To_v1alpha4_AzureManagedMachinePoolSpec(in *AzureManagedMachinePoolSpec, out *v1alpha4.AzureManagedMachinePoolSpec, s conversion.Scope) error { out.Mode = in.Mode + out.AvailabilityZones = *(*[]string)(unsafe.Pointer(&in.AvailabilityZones)) out.SKU = in.SKU out.OSDiskSizeGB = (*int32)(unsafe.Pointer(in.OSDiskSizeGB)) out.ProviderIDList = *(*[]string)(unsafe.Pointer(&in.ProviderIDList)) @@ -861,6 +862,7 @@ func Convert_v1alpha3_AzureManagedMachinePoolSpec_To_v1alpha4_AzureManagedMachin func autoConvert_v1alpha4_AzureManagedMachinePoolSpec_To_v1alpha3_AzureManagedMachinePoolSpec(in *v1alpha4.AzureManagedMachinePoolSpec, out *AzureManagedMachinePoolSpec, s conversion.Scope) error { out.Mode = in.Mode + out.AvailabilityZones = *(*[]string)(unsafe.Pointer(&in.AvailabilityZones)) out.SKU = in.SKU out.OSDiskSizeGB = (*int32)(unsafe.Pointer(in.OSDiskSizeGB)) out.ProviderIDList = *(*[]string)(unsafe.Pointer(&in.ProviderIDList)) diff --git a/exp/api/v1alpha3/zz_generated.deepcopy.go b/exp/api/v1alpha3/zz_generated.deepcopy.go index 2df50d7a442..31ddfa7b36b 100644 --- a/exp/api/v1alpha3/zz_generated.deepcopy.go +++ b/exp/api/v1alpha3/zz_generated.deepcopy.go @@ -535,6 +535,11 @@ func (in *AzureManagedMachinePoolList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureManagedMachinePoolSpec) DeepCopyInto(out *AzureManagedMachinePoolSpec) { *out = *in + if in.AvailabilityZones != nil { + in, out := &in.AvailabilityZones, &out.AvailabilityZones + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.OSDiskSizeGB != nil { in, out := &in.OSDiskSizeGB, &out.OSDiskSizeGB *out = new(int32) diff --git a/exp/api/v1alpha4/azuremanagedmachinepool_types.go b/exp/api/v1alpha4/azuremanagedmachinepool_types.go index 68f704307f7..818c7610d04 100644 --- a/exp/api/v1alpha4/azuremanagedmachinepool_types.go +++ b/exp/api/v1alpha4/azuremanagedmachinepool_types.go @@ -42,6 +42,9 @@ type AzureManagedMachinePoolSpec struct { // +kubebuilder:validation:Enum=System;User Mode string `json:"mode"` + // AvailabilityZones - Availability zones for nodes. Must use VirtualMachineScaleSets AgentPoolType. + AvailabilityZones []string `json:"availabilityZones,omitempty"` + // SKU is the size of the VMs in the node pool. SKU string `json:"sku"` diff --git a/exp/api/v1alpha4/azuremanagedmachinepool_webhook.go b/exp/api/v1alpha4/azuremanagedmachinepool_webhook.go index d6514ce1fbd..3b6b65f788d 100644 --- a/exp/api/v1alpha4/azuremanagedmachinepool_webhook.go +++ b/exp/api/v1alpha4/azuremanagedmachinepool_webhook.go @@ -18,6 +18,7 @@ package v1alpha4 import ( "context" + "reflect" "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -86,6 +87,14 @@ func (r *AzureManagedMachinePool) ValidateUpdate(oldRaw runtime.Object, client c } } + if !reflect.DeepEqual(r.Spec.AvailabilityZones, old.Spec.AvailabilityZones) { + allErrs = append(allErrs, + field.Invalid( + field.NewPath("Spec", "AvailabilityZones"), + r.Spec.AvailabilityZones, + "field is immutable")) + } + if r.Spec.Mode != string(NodePoolModeSystem) && old.Spec.Mode == string(NodePoolModeSystem) { // validate for last system node pool if err := r.validateLastSystemNodePool(client); err != nil { diff --git a/exp/api/v1alpha4/azuremanagedmachinepool_webhook_test.go b/exp/api/v1alpha4/azuremanagedmachinepool_webhook_test.go index a05506f8106..d13ef955c6f 100644 --- a/exp/api/v1alpha4/azuremanagedmachinepool_webhook_test.go +++ b/exp/api/v1alpha4/azuremanagedmachinepool_webhook_test.go @@ -94,6 +94,45 @@ func TestAzureManagedMachinePoolUpdatingWebhook(t *testing.T) { }, wantErr: true, }, + { + name: "Cannot add AvailabilityZones after creating agentpool", + new: &AzureManagedMachinePool{ + Spec: AzureManagedMachinePoolSpec{ + Mode: "System", + SKU: "StandardD2S_V3", + OSDiskSizeGB: to.Int32Ptr(512), + }, + }, + old: &AzureManagedMachinePool{ + Spec: AzureManagedMachinePoolSpec{ + Mode: "System", + SKU: "StandardD2S_V3", + OSDiskSizeGB: to.Int32Ptr(512), + AvailabilityZones: []string{"1", "2", "3"}, + }, + }, + wantErr: true, + }, + { + name: "Cannot change AvailabilityZones of the agentpool", + new: &AzureManagedMachinePool{ + Spec: AzureManagedMachinePoolSpec{ + Mode: "System", + SKU: "StandardD2S_V3", + OSDiskSizeGB: to.Int32Ptr(512), + AvailabilityZones: []string{"1", "2"}, + }, + }, + old: &AzureManagedMachinePool{ + Spec: AzureManagedMachinePoolSpec{ + Mode: "System", + SKU: "StandardD2S_V3", + OSDiskSizeGB: to.Int32Ptr(512), + AvailabilityZones: []string{"1", "2", "3"}, + }, + }, + wantErr: true, + }, } var client client.Client for _, tc := range tests { diff --git a/exp/api/v1alpha4/zz_generated.deepcopy.go b/exp/api/v1alpha4/zz_generated.deepcopy.go index a58fa5c93a3..73d28eb2f8f 100644 --- a/exp/api/v1alpha4/zz_generated.deepcopy.go +++ b/exp/api/v1alpha4/zz_generated.deepcopy.go @@ -695,6 +695,11 @@ func (in *AzureManagedMachinePoolList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureManagedMachinePoolSpec) DeepCopyInto(out *AzureManagedMachinePoolSpec) { *out = *in + if in.AvailabilityZones != nil { + in, out := &in.AvailabilityZones, &out.AvailabilityZones + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.OSDiskSizeGB != nil { in, out := &in.OSDiskSizeGB, &out.OSDiskSizeGB *out = new(int32)