sigs.k8s.io/cluster-api-provider-azure@v1.14.3/api/v1beta1/azuremanagedcontrolplane_webhook_test.go (about)

     1  /*
     2  Copyright 2023 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package v1beta1
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	. "github.com/onsi/gomega"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/util/validation/field"
    26  	utilfeature "k8s.io/component-base/featuregate/testing"
    27  	"k8s.io/utils/ptr"
    28  	"sigs.k8s.io/cluster-api-provider-azure/feature"
    29  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    30  	capifeature "sigs.k8s.io/cluster-api/feature"
    31  )
    32  
    33  func TestDefaultingWebhook(t *testing.T) {
    34  	g := NewWithT(t)
    35  
    36  	t.Logf("Testing amcp defaulting webhook with no baseline")
    37  	amcp := &AzureManagedControlPlane{
    38  		ObjectMeta: metav1.ObjectMeta{
    39  			Name: "fooName",
    40  			Labels: map[string]string{
    41  				clusterv1.ClusterNameLabel: "fooCluster",
    42  			},
    43  		},
    44  		Spec: AzureManagedControlPlaneSpec{
    45  			AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
    46  				Location: "fooLocation",
    47  				Version:  "1.17.5",
    48  				Extensions: []AKSExtension{
    49  					{
    50  						Name: "test-extension",
    51  						Plan: &ExtensionPlan{
    52  							Product:   "test-product",
    53  							Publisher: "test-publisher",
    54  						},
    55  					},
    56  				},
    57  			},
    58  			ResourceGroupName: "fooRg",
    59  			SSHPublicKey:      ptr.To(""),
    60  		},
    61  	}
    62  	mcpw := &azureManagedControlPlaneWebhook{}
    63  	err := mcpw.Default(context.Background(), amcp)
    64  	g.Expect(err).NotTo(HaveOccurred())
    65  	g.Expect(amcp.Spec.NetworkPlugin).To(Equal(ptr.To(AzureNetworkPluginName)))
    66  	g.Expect(amcp.Spec.LoadBalancerSKU).To(Equal(ptr.To("Standard")))
    67  	g.Expect(amcp.Spec.Version).To(Equal("v1.17.5"))
    68  	g.Expect(*amcp.Spec.SSHPublicKey).NotTo(BeEmpty())
    69  	g.Expect(amcp.Spec.NodeResourceGroupName).To(Equal("MC_fooRg_fooName_fooLocation"))
    70  	g.Expect(amcp.Spec.VirtualNetwork.Name).To(Equal("fooName"))
    71  	g.Expect(amcp.Spec.VirtualNetwork.CIDRBlock).To(Equal(defaultAKSVnetCIDR))
    72  	g.Expect(amcp.Spec.VirtualNetwork.Subnet.Name).To(Equal("fooName"))
    73  	g.Expect(amcp.Spec.VirtualNetwork.Subnet.CIDRBlock).To(Equal(defaultAKSNodeSubnetCIDR))
    74  	g.Expect(amcp.Spec.SKU.Tier).To(Equal(FreeManagedControlPlaneTier))
    75  	g.Expect(amcp.Spec.Identity.Type).To(Equal(ManagedControlPlaneIdentityTypeSystemAssigned))
    76  	g.Expect(*amcp.Spec.OIDCIssuerProfile.Enabled).To(BeFalse())
    77  	g.Expect(amcp.Spec.DNSPrefix).NotTo(BeNil())
    78  	g.Expect(*amcp.Spec.DNSPrefix).To(Equal(amcp.Name))
    79  	g.Expect(amcp.Spec.Extensions[0].Plan.Name).To(Equal("fooName-test-product"))
    80  	g.Expect(amcp.Spec.EnablePreviewFeatures).NotTo(BeNil())
    81  	g.Expect(*amcp.Spec.EnablePreviewFeatures).To(BeFalse())
    82  
    83  	t.Logf("Testing amcp defaulting webhook with baseline")
    84  	netPlug := "kubenet"
    85  	netPol := "azure"
    86  	amcp.Spec.NetworkPlugin = &netPlug
    87  	amcp.Spec.NetworkPolicy = &netPol
    88  	amcp.Spec.Version = "9.99.99"
    89  	amcp.Spec.SSHPublicKey = nil
    90  	amcp.Spec.NodeResourceGroupName = "fooNodeRg"
    91  	amcp.Spec.VirtualNetwork.Name = "fooVnetName"
    92  	amcp.Spec.VirtualNetwork.Subnet.Name = "fooSubnetName"
    93  	amcp.Spec.SKU.Tier = PaidManagedControlPlaneTier
    94  	amcp.Spec.OIDCIssuerProfile = &OIDCIssuerProfile{
    95  		Enabled: ptr.To(true),
    96  	}
    97  	amcp.Spec.DNSPrefix = ptr.To("test-prefix")
    98  	amcp.Spec.FleetsMember = &FleetsMember{}
    99  	amcp.Spec.AutoUpgradeProfile = &ManagedClusterAutoUpgradeProfile{
   100  		UpgradeChannel: ptr.To(UpgradeChannelPatch),
   101  	}
   102  	amcp.Spec.SecurityProfile = &ManagedClusterSecurityProfile{
   103  		AzureKeyVaultKms: &AzureKeyVaultKms{
   104  			Enabled: true,
   105  		},
   106  		ImageCleaner: &ManagedClusterSecurityProfileImageCleaner{
   107  			Enabled:       true,
   108  			IntervalHours: ptr.To(48),
   109  		},
   110  	}
   111  	amcp.Spec.EnablePreviewFeatures = ptr.To(true)
   112  
   113  	err = mcpw.Default(context.Background(), amcp)
   114  	g.Expect(err).NotTo(HaveOccurred())
   115  	g.Expect(*amcp.Spec.NetworkPlugin).To(Equal(netPlug))
   116  	g.Expect(*amcp.Spec.NetworkPolicy).To(Equal(netPol))
   117  	g.Expect(amcp.Spec.Version).To(Equal("v9.99.99"))
   118  	g.Expect(amcp.Spec.SSHPublicKey).To(BeNil())
   119  	g.Expect(amcp.Spec.NodeResourceGroupName).To(Equal("fooNodeRg"))
   120  	g.Expect(amcp.Spec.VirtualNetwork.Name).To(Equal("fooVnetName"))
   121  	g.Expect(amcp.Spec.VirtualNetwork.Subnet.Name).To(Equal("fooSubnetName"))
   122  	g.Expect(amcp.Spec.SKU.Tier).To(Equal(StandardManagedControlPlaneTier))
   123  	g.Expect(*amcp.Spec.OIDCIssuerProfile.Enabled).To(BeTrue())
   124  	g.Expect(amcp.Spec.DNSPrefix).NotTo(BeNil())
   125  	g.Expect(*amcp.Spec.DNSPrefix).To(Equal("test-prefix"))
   126  	g.Expect(amcp.Spec.FleetsMember.Name).To(Equal("fooCluster"))
   127  	g.Expect(amcp.Spec.AutoUpgradeProfile).NotTo(BeNil())
   128  	g.Expect(amcp.Spec.AutoUpgradeProfile.UpgradeChannel).NotTo(BeNil())
   129  	g.Expect(*amcp.Spec.AutoUpgradeProfile.UpgradeChannel).To(Equal(UpgradeChannelPatch))
   130  	g.Expect(amcp.Spec.SecurityProfile).NotTo(BeNil())
   131  	g.Expect(amcp.Spec.SecurityProfile.AzureKeyVaultKms).NotTo(BeNil())
   132  	g.Expect(amcp.Spec.SecurityProfile.ImageCleaner).NotTo(BeNil())
   133  	g.Expect(amcp.Spec.SecurityProfile.ImageCleaner.IntervalHours).NotTo(BeNil())
   134  	g.Expect(*amcp.Spec.SecurityProfile.ImageCleaner.IntervalHours).To(Equal(48))
   135  	g.Expect(amcp.Spec.EnablePreviewFeatures).NotTo(BeNil())
   136  	g.Expect(*amcp.Spec.EnablePreviewFeatures).To(BeTrue())
   137  
   138  	t.Logf("Testing amcp defaulting webhook with overlay")
   139  	amcp = &AzureManagedControlPlane{
   140  		ObjectMeta: metav1.ObjectMeta{
   141  			Name: "fooName",
   142  		},
   143  		Spec: AzureManagedControlPlaneSpec{
   144  			AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   145  				Location:          "fooLocation",
   146  				Version:           "1.17.5",
   147  				NetworkPluginMode: ptr.To(NetworkPluginModeOverlay),
   148  				AutoUpgradeProfile: &ManagedClusterAutoUpgradeProfile{
   149  					UpgradeChannel: ptr.To(UpgradeChannelRapid),
   150  				},
   151  				SecurityProfile: &ManagedClusterSecurityProfile{
   152  					Defender: &ManagedClusterSecurityProfileDefender{
   153  						LogAnalyticsWorkspaceResourceID: "not empty",
   154  						SecurityMonitoring: ManagedClusterSecurityProfileDefenderSecurityMonitoring{
   155  							Enabled: true,
   156  						},
   157  					},
   158  					WorkloadIdentity: &ManagedClusterSecurityProfileWorkloadIdentity{
   159  						Enabled: true,
   160  					},
   161  				},
   162  			},
   163  			ResourceGroupName: "fooRg",
   164  			SSHPublicKey:      ptr.To(""),
   165  		},
   166  	}
   167  	err = mcpw.Default(context.Background(), amcp)
   168  	g.Expect(err).NotTo(HaveOccurred())
   169  	g.Expect(amcp.Spec.VirtualNetwork.CIDRBlock).To(Equal(defaultAKSVnetCIDRForOverlay))
   170  	g.Expect(amcp.Spec.VirtualNetwork.Subnet.CIDRBlock).To(Equal(defaultAKSNodeSubnetCIDRForOverlay))
   171  	g.Expect(amcp.Spec.AutoUpgradeProfile).NotTo(BeNil())
   172  	g.Expect(amcp.Spec.AutoUpgradeProfile.UpgradeChannel).NotTo(BeNil())
   173  	g.Expect(*amcp.Spec.AutoUpgradeProfile.UpgradeChannel).To(Equal(UpgradeChannelRapid))
   174  }
   175  
   176  func TestValidateVersion(t *testing.T) {
   177  	tests := []struct {
   178  		name      string
   179  		version   string
   180  		expectErr bool
   181  	}{
   182  		{
   183  			name:      "Invalid Version",
   184  			version:   "honk",
   185  			expectErr: true,
   186  		},
   187  		{
   188  			name:      "not following the Kubernetes Version pattern: missing leading v",
   189  			version:   "1.19.0",
   190  			expectErr: true,
   191  		},
   192  		{
   193  			name:      "Version not set",
   194  			version:   "",
   195  			expectErr: true,
   196  		},
   197  		{
   198  			name:      "Valid Version",
   199  			version:   "v1.17.8",
   200  			expectErr: false,
   201  		},
   202  	}
   203  
   204  	for _, tt := range tests {
   205  		tt := tt
   206  		t.Run(tt.name, func(t *testing.T) {
   207  			g := NewWithT(t)
   208  			allErrs := validateVersion(tt.version, field.NewPath("spec").Child("Version"))
   209  			if tt.expectErr {
   210  				g.Expect(allErrs).NotTo(BeNil())
   211  			} else {
   212  				g.Expect(allErrs).To(BeNil())
   213  			}
   214  		})
   215  	}
   216  }
   217  
   218  func TestValidateLoadBalancerProfile(t *testing.T) {
   219  	tests := []struct {
   220  		name        string
   221  		profile     *LoadBalancerProfile
   222  		expectedErr field.Error
   223  	}{
   224  		{
   225  			name: "Valid LoadBalancerProfile",
   226  			profile: &LoadBalancerProfile{
   227  				ManagedOutboundIPs:     ptr.To(10),
   228  				AllocatedOutboundPorts: ptr.To(1000),
   229  				IdleTimeoutInMinutes:   ptr.To(60),
   230  			},
   231  		},
   232  		{
   233  			name: "Invalid LoadBalancerProfile.ManagedOutboundIPs",
   234  			profile: &LoadBalancerProfile{
   235  				ManagedOutboundIPs: ptr.To(200),
   236  			},
   237  			expectedErr: field.Error{
   238  				Type:     field.ErrorTypeInvalid,
   239  				Field:    "spec.LoadBalancerProfile.ManagedOutboundIPs",
   240  				BadValue: ptr.To(200),
   241  				Detail:   "value should be in between 1 and 100",
   242  			},
   243  		},
   244  		{
   245  			name: "Invalid LoadBalancerProfile.IdleTimeoutInMinutes",
   246  			profile: &LoadBalancerProfile{
   247  				IdleTimeoutInMinutes: ptr.To(600),
   248  			},
   249  			expectedErr: field.Error{
   250  				Type:     field.ErrorTypeInvalid,
   251  				Field:    "spec.LoadBalancerProfile.IdleTimeoutInMinutes",
   252  				BadValue: ptr.To(600),
   253  				Detail:   "value should be in between 4 and 120",
   254  			},
   255  		},
   256  		{
   257  			name: "LoadBalancerProfile must specify at most one of ManagedOutboundIPs, OutboundIPPrefixes and OutboundIPs",
   258  			profile: &LoadBalancerProfile{
   259  				ManagedOutboundIPs: ptr.To(1),
   260  				OutboundIPs: []string{
   261  					"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo-bar/providers/Microsoft.Network/publicIPAddresses/my-public-ip",
   262  				},
   263  			},
   264  			expectedErr: field.Error{
   265  				Type:     field.ErrorTypeForbidden,
   266  				Field:    "spec.LoadBalancerProfile",
   267  				BadValue: ptr.To(2),
   268  				Detail:   "load balancer profile must specify at most one of ManagedOutboundIPs, OutboundIPPrefixes and OutboundIPs",
   269  			},
   270  		},
   271  	}
   272  	for _, tt := range tests {
   273  		tt := tt
   274  		t.Run(tt.name, func(t *testing.T) {
   275  			g := NewWithT(t)
   276  			allErrs := validateLoadBalancerProfile(tt.profile, field.NewPath("spec").Child("LoadBalancerProfile"))
   277  			if tt.expectedErr != (field.Error{}) {
   278  				g.Expect(allErrs).To(ContainElement(MatchError(tt.expectedErr.Error())))
   279  			} else {
   280  				g.Expect(allErrs).To(BeNil())
   281  			}
   282  		})
   283  	}
   284  }
   285  
   286  func TestValidateAutoScalerProfile(t *testing.T) {
   287  	tests := []struct {
   288  		name      string
   289  		profile   *AutoScalerProfile
   290  		expectErr bool
   291  	}{
   292  		{
   293  			name: "Valid AutoScalerProfile",
   294  			profile: &AutoScalerProfile{
   295  				BalanceSimilarNodeGroups:      (*BalanceSimilarNodeGroups)(ptr.To(string(BalanceSimilarNodeGroupsFalse))),
   296  				Expander:                      (*Expander)(ptr.To(string(ExpanderRandom))),
   297  				MaxEmptyBulkDelete:            ptr.To("10"),
   298  				MaxGracefulTerminationSec:     ptr.To("600"),
   299  				MaxNodeProvisionTime:          ptr.To("10m"),
   300  				MaxTotalUnreadyPercentage:     ptr.To("45"),
   301  				NewPodScaleUpDelay:            ptr.To("10m"),
   302  				OkTotalUnreadyCount:           ptr.To("3"),
   303  				ScanInterval:                  ptr.To("60s"),
   304  				ScaleDownDelayAfterAdd:        ptr.To("10m"),
   305  				ScaleDownDelayAfterDelete:     ptr.To("10s"),
   306  				ScaleDownDelayAfterFailure:    ptr.To("10m"),
   307  				ScaleDownUnneededTime:         ptr.To("10m"),
   308  				ScaleDownUnreadyTime:          ptr.To("10m"),
   309  				ScaleDownUtilizationThreshold: ptr.To("0.5"),
   310  				SkipNodesWithLocalStorage:     (*SkipNodesWithLocalStorage)(ptr.To(string(SkipNodesWithLocalStorageTrue))),
   311  				SkipNodesWithSystemPods:       (*SkipNodesWithSystemPods)(ptr.To(string(SkipNodesWithSystemPodsTrue))),
   312  			},
   313  			expectErr: false,
   314  		},
   315  		{
   316  			name: "Testing valid AutoScalerProfile.ExpanderRandom",
   317  			profile: &AutoScalerProfile{
   318  				Expander: (*Expander)(ptr.To(string(ExpanderRandom))),
   319  			},
   320  			expectErr: false,
   321  		},
   322  		{
   323  			name: "Testing valid AutoScalerProfile.ExpanderLeastWaste",
   324  			profile: &AutoScalerProfile{
   325  				Expander: (*Expander)(ptr.To(string(ExpanderLeastWaste))),
   326  			},
   327  			expectErr: false,
   328  		},
   329  		{
   330  			name: "Testing valid AutoScalerProfile.ExpanderMostPods",
   331  			profile: &AutoScalerProfile{
   332  				Expander: (*Expander)(ptr.To(string(ExpanderMostPods))),
   333  			},
   334  			expectErr: false,
   335  		},
   336  		{
   337  			name: "Testing valid AutoScalerProfile.ExpanderPriority",
   338  			profile: &AutoScalerProfile{
   339  				Expander: (*Expander)(ptr.To(string(ExpanderPriority))),
   340  			},
   341  			expectErr: false,
   342  		},
   343  		{
   344  			name: "Testing valid AutoScalerProfile.BalanceSimilarNodeGroupsTrue",
   345  			profile: &AutoScalerProfile{
   346  				BalanceSimilarNodeGroups: (*BalanceSimilarNodeGroups)(ptr.To(string(BalanceSimilarNodeGroupsTrue))),
   347  			},
   348  			expectErr: false,
   349  		},
   350  		{
   351  			name: "Testing valid AutoScalerProfile.BalanceSimilarNodeGroupsFalse",
   352  			profile: &AutoScalerProfile{
   353  				BalanceSimilarNodeGroups: (*BalanceSimilarNodeGroups)(ptr.To(string(BalanceSimilarNodeGroupsFalse))),
   354  			},
   355  			expectErr: false,
   356  		},
   357  		{
   358  			name: "Testing invalid AutoScalerProfile.MaxEmptyBulkDelete",
   359  			profile: &AutoScalerProfile{
   360  				MaxEmptyBulkDelete: ptr.To("invalid"),
   361  			},
   362  			expectErr: true,
   363  		},
   364  		{
   365  			name: "Testing invalid AutoScalerProfile.MaxGracefulTerminationSec",
   366  			profile: &AutoScalerProfile{
   367  				MaxGracefulTerminationSec: ptr.To("invalid"),
   368  			},
   369  			expectErr: true,
   370  		},
   371  		{
   372  			name: "Testing invalid AutoScalerProfile.MaxNodeProvisionTime",
   373  			profile: &AutoScalerProfile{
   374  				MaxNodeProvisionTime: ptr.To("invalid"),
   375  			},
   376  			expectErr: true,
   377  		},
   378  		{
   379  			name: "Testing invalid AutoScalerProfile.MaxTotalUnreadyPercentage",
   380  			profile: &AutoScalerProfile{
   381  				MaxTotalUnreadyPercentage: ptr.To("invalid"),
   382  			},
   383  			expectErr: true,
   384  		},
   385  		{
   386  			name: "Testing invalid AutoScalerProfile.NewPodScaleUpDelay",
   387  			profile: &AutoScalerProfile{
   388  				NewPodScaleUpDelay: ptr.To("invalid"),
   389  			},
   390  			expectErr: true,
   391  		},
   392  		{
   393  			name: "Testing invalid AutoScalerProfile.OkTotalUnreadyCount",
   394  			profile: &AutoScalerProfile{
   395  				OkTotalUnreadyCount: ptr.To("invalid"),
   396  			},
   397  			expectErr: true,
   398  		},
   399  		{
   400  			name: "Testing invalid AutoScalerProfile.ScanInterval",
   401  			profile: &AutoScalerProfile{
   402  				ScanInterval: ptr.To("invalid"),
   403  			},
   404  			expectErr: true,
   405  		},
   406  		{
   407  			name: "Testing invalid AutoScalerProfile.ScaleDownDelayAfterAdd",
   408  			profile: &AutoScalerProfile{
   409  				ScaleDownDelayAfterAdd: ptr.To("invalid"),
   410  			},
   411  			expectErr: true,
   412  		},
   413  		{
   414  			name: "Testing invalid AutoScalerProfile.ScaleDownDelayAfterDelete",
   415  			profile: &AutoScalerProfile{
   416  				ScaleDownDelayAfterDelete: ptr.To("invalid"),
   417  			},
   418  			expectErr: true,
   419  		},
   420  		{
   421  			name: "Testing invalid AutoScalerProfile.ScaleDownDelayAfterFailure",
   422  			profile: &AutoScalerProfile{
   423  				ScaleDownDelayAfterFailure: ptr.To("invalid"),
   424  			},
   425  			expectErr: true,
   426  		},
   427  		{
   428  			name: "Testing invalid AutoScalerProfile.ScaleDownUnneededTime",
   429  			profile: &AutoScalerProfile{
   430  				ScaleDownUnneededTime: ptr.To("invalid"),
   431  			},
   432  			expectErr: true,
   433  		},
   434  		{
   435  			name: "Testing invalid AutoScalerProfile.ScaleDownUnreadyTime",
   436  			profile: &AutoScalerProfile{
   437  				ScaleDownUnreadyTime: ptr.To("invalid"),
   438  			},
   439  			expectErr: true,
   440  		},
   441  		{
   442  			name: "Testing invalid AutoScalerProfile.ScaleDownUtilizationThreshold",
   443  			profile: &AutoScalerProfile{
   444  				ScaleDownUtilizationThreshold: ptr.To("invalid"),
   445  			},
   446  			expectErr: true,
   447  		},
   448  		{
   449  			name: "Testing valid AutoScalerProfile.SkipNodesWithLocalStorageTrue",
   450  			profile: &AutoScalerProfile{
   451  				SkipNodesWithLocalStorage: (*SkipNodesWithLocalStorage)(ptr.To(string(SkipNodesWithLocalStorageTrue))),
   452  			},
   453  			expectErr: false,
   454  		},
   455  		{
   456  			name: "Testing valid AutoScalerProfile.SkipNodesWithLocalStorageFalse",
   457  			profile: &AutoScalerProfile{
   458  				SkipNodesWithSystemPods: (*SkipNodesWithSystemPods)(ptr.To(string(SkipNodesWithSystemPodsFalse))),
   459  			},
   460  			expectErr: false,
   461  		},
   462  	}
   463  
   464  	for _, tt := range tests {
   465  		tt := tt
   466  		t.Run(tt.name, func(t *testing.T) {
   467  			g := NewWithT(t)
   468  			allErrs := validateAutoScalerProfile(tt.profile, field.NewPath("spec").Child("AutoScalerProfile"))
   469  			if tt.expectErr {
   470  				g.Expect(allErrs).NotTo(BeNil())
   471  			} else {
   472  				g.Expect(allErrs).To(BeNil())
   473  			}
   474  		})
   475  	}
   476  }
   477  
   478  func TestValidatingWebhook(t *testing.T) {
   479  	// NOTE: AzureManageControlPlane is behind AKS feature gate flag; the webhook
   480  	// must prevent creating new objects in case the feature flag is disabled.
   481  	defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, capifeature.MachinePool, true)()
   482  	tests := []struct {
   483  		name      string
   484  		amcp      AzureManagedControlPlane
   485  		expectErr bool
   486  	}{
   487  		{
   488  			name: "Testing valid DNSServiceIP",
   489  			amcp: AzureManagedControlPlane{
   490  				ObjectMeta: getAMCPMetaData(),
   491  				Spec: AzureManagedControlPlaneSpec{
   492  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   493  						DNSServiceIP: ptr.To("192.168.0.10"),
   494  						Version:      "v1.17.8",
   495  					},
   496  				},
   497  			},
   498  			expectErr: false,
   499  		},
   500  		{
   501  			name: "Testing invalid DNSServiceIP",
   502  			amcp: AzureManagedControlPlane{
   503  				ObjectMeta: getAMCPMetaData(),
   504  				Spec: AzureManagedControlPlaneSpec{
   505  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   506  						DNSServiceIP: ptr.To("192.168.0.10.3"),
   507  						Version:      "v1.17.8",
   508  					},
   509  				},
   510  			},
   511  			expectErr: true,
   512  		},
   513  		{
   514  			name: "Testing invalid DNSServiceIP",
   515  			amcp: AzureManagedControlPlane{
   516  				ObjectMeta: getAMCPMetaData(),
   517  				Spec: AzureManagedControlPlaneSpec{
   518  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   519  						DNSServiceIP: ptr.To("192.168.0.11"),
   520  						Version:      "v1.17.8",
   521  					},
   522  				},
   523  			},
   524  			expectErr: true,
   525  		},
   526  		{
   527  			name: "Testing empty DNSServiceIP",
   528  			amcp: AzureManagedControlPlane{
   529  				ObjectMeta: getAMCPMetaData(),
   530  				Spec: AzureManagedControlPlaneSpec{
   531  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   532  						Version: "v1.17.8",
   533  					},
   534  				},
   535  			},
   536  			expectErr: false,
   537  		},
   538  		{
   539  			name: "Invalid Version",
   540  			amcp: AzureManagedControlPlane{
   541  				ObjectMeta: getAMCPMetaData(),
   542  				Spec: AzureManagedControlPlaneSpec{
   543  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   544  						DNSServiceIP: ptr.To("192.168.0.10"),
   545  						Version:      "honk",
   546  					},
   547  				},
   548  			},
   549  			expectErr: true,
   550  		},
   551  		{
   552  			name: "not following the Kubernetes Version pattern",
   553  			amcp: AzureManagedControlPlane{
   554  				ObjectMeta: getAMCPMetaData(),
   555  				Spec: AzureManagedControlPlaneSpec{
   556  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   557  						DNSServiceIP: ptr.To("192.168.0.10"),
   558  						Version:      "1.19.0",
   559  					},
   560  				},
   561  			},
   562  			expectErr: true,
   563  		},
   564  		{
   565  			name: "Version not set",
   566  			amcp: AzureManagedControlPlane{
   567  				ObjectMeta: getAMCPMetaData(),
   568  				Spec: AzureManagedControlPlaneSpec{
   569  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   570  						DNSServiceIP: ptr.To("192.168.0.10"),
   571  						Version:      "",
   572  					},
   573  				},
   574  			},
   575  			expectErr: true,
   576  		},
   577  		{
   578  			name: "Valid Version",
   579  			amcp: AzureManagedControlPlane{
   580  				ObjectMeta: getAMCPMetaData(),
   581  				Spec: AzureManagedControlPlaneSpec{
   582  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   583  						DNSServiceIP: ptr.To("192.168.0.10"),
   584  						Version:      "v1.17.8",
   585  					},
   586  				},
   587  			},
   588  			expectErr: false,
   589  		},
   590  		{
   591  			name: "Valid Managed AADProfile",
   592  			amcp: AzureManagedControlPlane{
   593  				ObjectMeta: getAMCPMetaData(),
   594  				Spec: AzureManagedControlPlaneSpec{
   595  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   596  						Version: "v1.21.2",
   597  						AADProfile: &AADProfile{
   598  							Managed: true,
   599  							AdminGroupObjectIDs: []string{
   600  								"616077a8-5db7-4c98-b856-b34619afg75h",
   601  							},
   602  						},
   603  					},
   604  				},
   605  			},
   606  			expectErr: false,
   607  		},
   608  		{
   609  			name: "Valid LoadBalancerProfile",
   610  			amcp: AzureManagedControlPlane{
   611  				ObjectMeta: getAMCPMetaData(),
   612  				Spec: AzureManagedControlPlaneSpec{
   613  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   614  						Version: "v1.21.2",
   615  						LoadBalancerProfile: &LoadBalancerProfile{
   616  							ManagedOutboundIPs:     ptr.To(10),
   617  							AllocatedOutboundPorts: ptr.To(1000),
   618  							IdleTimeoutInMinutes:   ptr.To(60),
   619  						},
   620  					},
   621  				},
   622  			},
   623  			expectErr: false,
   624  		},
   625  		{
   626  			name: "Invalid LoadBalancerProfile.ManagedOutboundIPs",
   627  			amcp: AzureManagedControlPlane{
   628  				ObjectMeta: getAMCPMetaData(),
   629  				Spec: AzureManagedControlPlaneSpec{
   630  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   631  						Version: "v1.21.2",
   632  						LoadBalancerProfile: &LoadBalancerProfile{
   633  							ManagedOutboundIPs: ptr.To(200),
   634  						},
   635  					},
   636  				},
   637  			},
   638  			expectErr: true,
   639  		},
   640  		{
   641  			name: "Invalid LoadBalancerProfile.AllocatedOutboundPorts",
   642  			amcp: AzureManagedControlPlane{
   643  				ObjectMeta: getAMCPMetaData(),
   644  				Spec: AzureManagedControlPlaneSpec{
   645  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   646  						Version: "v1.21.2",
   647  						LoadBalancerProfile: &LoadBalancerProfile{
   648  							AllocatedOutboundPorts: ptr.To(80000),
   649  						},
   650  					},
   651  				},
   652  			},
   653  			expectErr: true,
   654  		},
   655  		{
   656  			name: "Invalid LoadBalancerProfile.IdleTimeoutInMinutes",
   657  			amcp: AzureManagedControlPlane{
   658  				ObjectMeta: getAMCPMetaData(),
   659  				Spec: AzureManagedControlPlaneSpec{
   660  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   661  						Version: "v1.21.2",
   662  						LoadBalancerProfile: &LoadBalancerProfile{
   663  							IdleTimeoutInMinutes: ptr.To(600),
   664  						},
   665  					},
   666  				},
   667  			},
   668  			expectErr: true,
   669  		},
   670  		{
   671  			name: "LoadBalancerProfile must specify at most one of ManagedOutboundIPs, OutboundIPPrefixes and OutboundIPs",
   672  			amcp: AzureManagedControlPlane{
   673  				ObjectMeta: getAMCPMetaData(),
   674  				Spec: AzureManagedControlPlaneSpec{
   675  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   676  						Version: "v1.21.2",
   677  						LoadBalancerProfile: &LoadBalancerProfile{
   678  							ManagedOutboundIPs: ptr.To(1),
   679  							OutboundIPs: []string{
   680  								"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo-bar/providers/Microsoft.Network/publicIPAddresses/my-public-ip",
   681  							},
   682  						},
   683  					},
   684  				},
   685  			},
   686  			expectErr: true,
   687  		},
   688  		{
   689  			name: "Invalid CIDR for AuthorizedIPRanges",
   690  			amcp: AzureManagedControlPlane{
   691  				ObjectMeta: getAMCPMetaData(),
   692  				Spec: AzureManagedControlPlaneSpec{
   693  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   694  						Version: "v1.21.2",
   695  						APIServerAccessProfile: &APIServerAccessProfile{
   696  							AuthorizedIPRanges: []string{"1.2.3.400/32"},
   697  						},
   698  					},
   699  				},
   700  			},
   701  			expectErr: true,
   702  		},
   703  		{
   704  			name: "Testing valid AutoScalerProfile",
   705  			amcp: AzureManagedControlPlane{
   706  				ObjectMeta: getAMCPMetaData(),
   707  				Spec: AzureManagedControlPlaneSpec{
   708  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   709  						Version: "v1.24.1",
   710  						AutoScalerProfile: &AutoScalerProfile{
   711  							BalanceSimilarNodeGroups:      (*BalanceSimilarNodeGroups)(ptr.To(string(BalanceSimilarNodeGroupsFalse))),
   712  							Expander:                      (*Expander)(ptr.To(string(ExpanderRandom))),
   713  							MaxEmptyBulkDelete:            ptr.To("10"),
   714  							MaxGracefulTerminationSec:     ptr.To("600"),
   715  							MaxNodeProvisionTime:          ptr.To("10m"),
   716  							MaxTotalUnreadyPercentage:     ptr.To("45"),
   717  							NewPodScaleUpDelay:            ptr.To("10m"),
   718  							OkTotalUnreadyCount:           ptr.To("3"),
   719  							ScanInterval:                  ptr.To("60s"),
   720  							ScaleDownDelayAfterAdd:        ptr.To("10m"),
   721  							ScaleDownDelayAfterDelete:     ptr.To("10s"),
   722  							ScaleDownDelayAfterFailure:    ptr.To("10m"),
   723  							ScaleDownUnneededTime:         ptr.To("10m"),
   724  							ScaleDownUnreadyTime:          ptr.To("10m"),
   725  							ScaleDownUtilizationThreshold: ptr.To("0.5"),
   726  							SkipNodesWithLocalStorage:     (*SkipNodesWithLocalStorage)(ptr.To(string(SkipNodesWithLocalStorageTrue))),
   727  							SkipNodesWithSystemPods:       (*SkipNodesWithSystemPods)(ptr.To(string(SkipNodesWithSystemPodsTrue))),
   728  						},
   729  					},
   730  				},
   731  			},
   732  			expectErr: false,
   733  		},
   734  		{
   735  			name: "Testing valid AutoScalerProfile.ExpanderRandom",
   736  			amcp: AzureManagedControlPlane{
   737  				ObjectMeta: getAMCPMetaData(),
   738  				Spec: AzureManagedControlPlaneSpec{
   739  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   740  						Version: "v1.24.1",
   741  						AutoScalerProfile: &AutoScalerProfile{
   742  							Expander: (*Expander)(ptr.To(string(ExpanderRandom))),
   743  						},
   744  					},
   745  				},
   746  			},
   747  			expectErr: false,
   748  		},
   749  		{
   750  			name: "Testing valid AutoScalerProfile.ExpanderLeastWaste",
   751  			amcp: AzureManagedControlPlane{
   752  				ObjectMeta: getAMCPMetaData(),
   753  				Spec: AzureManagedControlPlaneSpec{
   754  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   755  						Version: "v1.24.1",
   756  						AutoScalerProfile: &AutoScalerProfile{
   757  							Expander: (*Expander)(ptr.To(string(ExpanderLeastWaste))),
   758  						},
   759  					},
   760  				},
   761  			},
   762  			expectErr: false,
   763  		},
   764  		{
   765  			name: "Testing valid AutoScalerProfile.ExpanderMostPods",
   766  			amcp: AzureManagedControlPlane{
   767  				ObjectMeta: getAMCPMetaData(),
   768  				Spec: AzureManagedControlPlaneSpec{
   769  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   770  						Version: "v1.24.1",
   771  						AutoScalerProfile: &AutoScalerProfile{
   772  							Expander: (*Expander)(ptr.To(string(ExpanderMostPods))),
   773  						},
   774  					},
   775  				},
   776  			},
   777  			expectErr: false,
   778  		},
   779  		{
   780  			name: "Testing valid AutoScalerProfile.ExpanderPriority",
   781  			amcp: AzureManagedControlPlane{
   782  				ObjectMeta: getAMCPMetaData(),
   783  				Spec: AzureManagedControlPlaneSpec{
   784  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   785  						Version: "v1.24.1",
   786  						AutoScalerProfile: &AutoScalerProfile{
   787  							Expander: (*Expander)(ptr.To(string(ExpanderPriority))),
   788  						},
   789  					},
   790  				},
   791  			},
   792  			expectErr: false,
   793  		},
   794  		{
   795  			name: "Testing valid AutoScalerProfile.BalanceSimilarNodeGroupsTrue",
   796  			amcp: AzureManagedControlPlane{
   797  				ObjectMeta: getAMCPMetaData(),
   798  				Spec: AzureManagedControlPlaneSpec{
   799  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   800  						Version: "v1.24.1",
   801  						AutoScalerProfile: &AutoScalerProfile{
   802  							BalanceSimilarNodeGroups: (*BalanceSimilarNodeGroups)(ptr.To(string(BalanceSimilarNodeGroupsTrue))),
   803  						},
   804  					},
   805  				},
   806  			},
   807  			expectErr: false,
   808  		},
   809  		{
   810  			name: "Testing valid AutoScalerProfile.BalanceSimilarNodeGroupsFalse",
   811  			amcp: AzureManagedControlPlane{
   812  				ObjectMeta: getAMCPMetaData(),
   813  				Spec: AzureManagedControlPlaneSpec{
   814  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   815  						Version: "v1.24.1",
   816  						AutoScalerProfile: &AutoScalerProfile{
   817  							BalanceSimilarNodeGroups: (*BalanceSimilarNodeGroups)(ptr.To(string(BalanceSimilarNodeGroupsFalse))),
   818  						},
   819  					},
   820  				},
   821  			},
   822  			expectErr: false,
   823  		},
   824  		{
   825  			name: "Testing invalid AutoScalerProfile.MaxEmptyBulkDelete",
   826  			amcp: AzureManagedControlPlane{
   827  				ObjectMeta: getAMCPMetaData(),
   828  				Spec: AzureManagedControlPlaneSpec{
   829  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   830  						Version: "v1.24.1",
   831  						AutoScalerProfile: &AutoScalerProfile{
   832  							MaxEmptyBulkDelete: ptr.To("invalid"),
   833  						},
   834  					},
   835  				},
   836  			},
   837  			expectErr: true,
   838  		},
   839  		{
   840  			name: "Testing invalid AutoScalerProfile.MaxGracefulTerminationSec",
   841  			amcp: AzureManagedControlPlane{
   842  				ObjectMeta: getAMCPMetaData(),
   843  				Spec: AzureManagedControlPlaneSpec{
   844  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   845  						Version: "v1.24.1",
   846  						AutoScalerProfile: &AutoScalerProfile{
   847  							MaxGracefulTerminationSec: ptr.To("invalid"),
   848  						},
   849  					},
   850  				},
   851  			},
   852  			expectErr: true,
   853  		},
   854  		{
   855  			name: "Testing invalid AutoScalerProfile.MaxNodeProvisionTime",
   856  			amcp: AzureManagedControlPlane{
   857  				ObjectMeta: getAMCPMetaData(),
   858  				Spec: AzureManagedControlPlaneSpec{
   859  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   860  						Version: "v1.24.1",
   861  						AutoScalerProfile: &AutoScalerProfile{
   862  							MaxNodeProvisionTime: ptr.To("invalid"),
   863  						},
   864  					},
   865  				},
   866  			},
   867  			expectErr: true,
   868  		},
   869  		{
   870  			name: "Testing invalid AutoScalerProfile.MaxTotalUnreadyPercentage",
   871  			amcp: AzureManagedControlPlane{
   872  				ObjectMeta: getAMCPMetaData(),
   873  				Spec: AzureManagedControlPlaneSpec{
   874  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   875  						Version: "v1.24.1",
   876  						AutoScalerProfile: &AutoScalerProfile{
   877  							MaxTotalUnreadyPercentage: ptr.To("invalid"),
   878  						},
   879  					},
   880  				},
   881  			},
   882  			expectErr: true,
   883  		},
   884  		{
   885  			name: "Testing invalid AutoScalerProfile.NewPodScaleUpDelay",
   886  			amcp: AzureManagedControlPlane{
   887  				ObjectMeta: getAMCPMetaData(),
   888  				Spec: AzureManagedControlPlaneSpec{
   889  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   890  						Version: "v1.24.1",
   891  						AutoScalerProfile: &AutoScalerProfile{
   892  							NewPodScaleUpDelay: ptr.To("invalid"),
   893  						},
   894  					},
   895  				},
   896  			},
   897  			expectErr: true,
   898  		},
   899  		{
   900  			name: "Testing invalid AutoScalerProfile.OkTotalUnreadyCount",
   901  			amcp: AzureManagedControlPlane{
   902  				ObjectMeta: getAMCPMetaData(),
   903  				Spec: AzureManagedControlPlaneSpec{
   904  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   905  						Version: "v1.24.1",
   906  						AutoScalerProfile: &AutoScalerProfile{
   907  							OkTotalUnreadyCount: ptr.To("invalid"),
   908  						},
   909  					},
   910  				},
   911  			},
   912  			expectErr: true,
   913  		},
   914  		{
   915  			name: "Testing invalid AutoScalerProfile.ScanInterval",
   916  			amcp: AzureManagedControlPlane{
   917  				ObjectMeta: getAMCPMetaData(),
   918  				Spec: AzureManagedControlPlaneSpec{
   919  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   920  						Version: "v1.24.1",
   921  						AutoScalerProfile: &AutoScalerProfile{
   922  							ScanInterval: ptr.To("invalid"),
   923  						},
   924  					},
   925  				},
   926  			},
   927  			expectErr: true,
   928  		},
   929  		{
   930  			name: "Testing invalid AutoScalerProfile.ScaleDownDelayAfterAdd",
   931  			amcp: AzureManagedControlPlane{
   932  				ObjectMeta: getAMCPMetaData(),
   933  				Spec: AzureManagedControlPlaneSpec{
   934  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   935  						Version: "v1.24.1",
   936  						AutoScalerProfile: &AutoScalerProfile{
   937  							ScaleDownDelayAfterAdd: ptr.To("invalid"),
   938  						},
   939  					},
   940  				},
   941  			},
   942  			expectErr: true,
   943  		},
   944  		{
   945  			name: "Testing invalid AutoScalerProfile.ScaleDownDelayAfterDelete",
   946  			amcp: AzureManagedControlPlane{
   947  				ObjectMeta: getAMCPMetaData(),
   948  				Spec: AzureManagedControlPlaneSpec{
   949  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   950  						Version: "v1.24.1",
   951  						AutoScalerProfile: &AutoScalerProfile{
   952  							ScaleDownDelayAfterDelete: ptr.To("invalid"),
   953  						},
   954  					},
   955  				},
   956  			},
   957  			expectErr: true,
   958  		},
   959  		{
   960  			name: "Testing invalid AutoScalerProfile.ScaleDownDelayAfterFailure",
   961  			amcp: AzureManagedControlPlane{
   962  				ObjectMeta: getAMCPMetaData(),
   963  				Spec: AzureManagedControlPlaneSpec{
   964  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   965  						Version: "v1.24.1",
   966  						AutoScalerProfile: &AutoScalerProfile{
   967  							ScaleDownDelayAfterFailure: ptr.To("invalid"),
   968  						},
   969  					},
   970  				},
   971  			},
   972  			expectErr: true,
   973  		},
   974  		{
   975  			name: "Testing invalid AutoScalerProfile.ScaleDownUnneededTime",
   976  			amcp: AzureManagedControlPlane{
   977  				ObjectMeta: getAMCPMetaData(),
   978  				Spec: AzureManagedControlPlaneSpec{
   979  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   980  						Version: "v1.24.1",
   981  						AutoScalerProfile: &AutoScalerProfile{
   982  							ScaleDownUnneededTime: ptr.To("invalid"),
   983  						},
   984  					},
   985  				},
   986  			},
   987  			expectErr: true,
   988  		},
   989  		{
   990  			name: "Testing invalid AutoScalerProfile.ScaleDownUnreadyTime",
   991  			amcp: AzureManagedControlPlane{
   992  				ObjectMeta: getAMCPMetaData(),
   993  				Spec: AzureManagedControlPlaneSpec{
   994  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
   995  						Version: "v1.24.1",
   996  						AutoScalerProfile: &AutoScalerProfile{
   997  							ScaleDownUnreadyTime: ptr.To("invalid"),
   998  						},
   999  					},
  1000  				},
  1001  			},
  1002  			expectErr: true,
  1003  		},
  1004  		{
  1005  			name: "Testing invalid AutoScalerProfile.ScaleDownUtilizationThreshold",
  1006  			amcp: AzureManagedControlPlane{
  1007  				ObjectMeta: getAMCPMetaData(),
  1008  				Spec: AzureManagedControlPlaneSpec{
  1009  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1010  						Version: "v1.24.1",
  1011  						AutoScalerProfile: &AutoScalerProfile{
  1012  							ScaleDownUtilizationThreshold: ptr.To("invalid"),
  1013  						},
  1014  					},
  1015  				},
  1016  			},
  1017  			expectErr: true,
  1018  		},
  1019  		{
  1020  			name: "Testing valid AutoScalerProfile.SkipNodesWithLocalStorageTrue",
  1021  			amcp: AzureManagedControlPlane{
  1022  				ObjectMeta: getAMCPMetaData(),
  1023  				Spec: AzureManagedControlPlaneSpec{
  1024  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1025  						Version: "v1.24.1",
  1026  						AutoScalerProfile: &AutoScalerProfile{
  1027  							SkipNodesWithLocalStorage: (*SkipNodesWithLocalStorage)(ptr.To(string(SkipNodesWithLocalStorageTrue))),
  1028  						},
  1029  					},
  1030  				},
  1031  			},
  1032  			expectErr: false,
  1033  		},
  1034  		{
  1035  			name: "Testing valid AutoScalerProfile.SkipNodesWithLocalStorageFalse",
  1036  			amcp: AzureManagedControlPlane{
  1037  				ObjectMeta: getAMCPMetaData(),
  1038  				Spec: AzureManagedControlPlaneSpec{
  1039  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1040  						Version: "v1.24.1",
  1041  						AutoScalerProfile: &AutoScalerProfile{
  1042  							SkipNodesWithLocalStorage: (*SkipNodesWithLocalStorage)(ptr.To(string(SkipNodesWithLocalStorageFalse))),
  1043  						},
  1044  					},
  1045  				},
  1046  			},
  1047  			expectErr: false,
  1048  		},
  1049  		{
  1050  			name: "Testing valid AutoScalerProfile.SkipNodesWithSystemPodsTrue",
  1051  			amcp: AzureManagedControlPlane{
  1052  				ObjectMeta: getAMCPMetaData(),
  1053  				Spec: AzureManagedControlPlaneSpec{
  1054  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1055  						Version: "v1.24.1",
  1056  						AutoScalerProfile: &AutoScalerProfile{
  1057  							SkipNodesWithSystemPods: (*SkipNodesWithSystemPods)(ptr.To(string(SkipNodesWithSystemPodsTrue))),
  1058  						},
  1059  					},
  1060  				},
  1061  			},
  1062  			expectErr: false,
  1063  		},
  1064  		{
  1065  			name: "Testing valid AutoScalerProfile.SkipNodesWithSystemPodsFalse",
  1066  			amcp: AzureManagedControlPlane{
  1067  				ObjectMeta: getAMCPMetaData(),
  1068  				Spec: AzureManagedControlPlaneSpec{
  1069  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1070  						Version: "v1.24.1",
  1071  						AutoScalerProfile: &AutoScalerProfile{
  1072  							SkipNodesWithSystemPods: (*SkipNodesWithSystemPods)(ptr.To(string(SkipNodesWithSystemPodsFalse))),
  1073  						},
  1074  					},
  1075  				},
  1076  			},
  1077  			expectErr: false,
  1078  		},
  1079  		{
  1080  			name: "Testing valid Identity: SystemAssigned",
  1081  			amcp: AzureManagedControlPlane{
  1082  				ObjectMeta: getAMCPMetaData(),
  1083  				Spec: AzureManagedControlPlaneSpec{
  1084  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1085  						Version: "v1.24.1",
  1086  						Identity: &Identity{
  1087  							Type: ManagedControlPlaneIdentityTypeSystemAssigned,
  1088  						},
  1089  					},
  1090  				},
  1091  			},
  1092  			expectErr: false,
  1093  		},
  1094  		{
  1095  			name: "Testing valid Identity: UserAssigned",
  1096  			amcp: AzureManagedControlPlane{
  1097  				ObjectMeta: getAMCPMetaData(),
  1098  				Spec: AzureManagedControlPlaneSpec{
  1099  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1100  						Version: "v1.24.1",
  1101  						Identity: &Identity{
  1102  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  1103  							UserAssignedIdentityResourceID: "/resource/id",
  1104  						},
  1105  					},
  1106  				},
  1107  			},
  1108  			expectErr: false,
  1109  		},
  1110  		{
  1111  			name: "Testing invalid Identity: SystemAssigned with UserAssigned values",
  1112  			amcp: AzureManagedControlPlane{
  1113  				ObjectMeta: getAMCPMetaData(),
  1114  				Spec: AzureManagedControlPlaneSpec{
  1115  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1116  						Version: "v1.24.1",
  1117  						Identity: &Identity{
  1118  							Type:                           ManagedControlPlaneIdentityTypeSystemAssigned,
  1119  							UserAssignedIdentityResourceID: "/resource/id",
  1120  						},
  1121  					},
  1122  				},
  1123  			},
  1124  			expectErr: true,
  1125  		},
  1126  		{
  1127  			name: "Testing invalid Identity: UserAssigned with missing properties",
  1128  			amcp: AzureManagedControlPlane{
  1129  				ObjectMeta: getAMCPMetaData(),
  1130  				Spec: AzureManagedControlPlaneSpec{
  1131  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1132  						Version: "v1.24.1",
  1133  						Identity: &Identity{
  1134  							Type: ManagedControlPlaneIdentityTypeUserAssigned,
  1135  						},
  1136  					},
  1137  				},
  1138  			},
  1139  			expectErr: true,
  1140  		},
  1141  		{
  1142  			name: "overlay cannot be used with kubenet",
  1143  			amcp: AzureManagedControlPlane{
  1144  				ObjectMeta: getAMCPMetaData(),
  1145  				Spec: AzureManagedControlPlaneSpec{
  1146  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1147  						Version:           "v1.24.1",
  1148  						NetworkPlugin:     ptr.To("kubenet"),
  1149  						NetworkPluginMode: ptr.To(NetworkPluginModeOverlay),
  1150  					},
  1151  				},
  1152  			},
  1153  			expectErr: true,
  1154  		},
  1155  		{
  1156  			name: "overlay can be used with azure",
  1157  			amcp: AzureManagedControlPlane{
  1158  				ObjectMeta: getAMCPMetaData(),
  1159  				Spec: AzureManagedControlPlaneSpec{
  1160  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1161  						Version:           "v1.24.1",
  1162  						NetworkPlugin:     ptr.To("azure"),
  1163  						NetworkPluginMode: ptr.To(NetworkPluginModeOverlay),
  1164  					},
  1165  				},
  1166  			},
  1167  			expectErr: false,
  1168  		},
  1169  		{
  1170  			name: "Testing valid AKS Extension",
  1171  			amcp: AzureManagedControlPlane{
  1172  				ObjectMeta: getAMCPMetaData(),
  1173  				Spec: AzureManagedControlPlaneSpec{
  1174  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1175  						Version: "v1.17.8",
  1176  						Extensions: []AKSExtension{
  1177  							{
  1178  								Name:          "extension1",
  1179  								ExtensionType: ptr.To("test-type"),
  1180  								Plan: &ExtensionPlan{
  1181  									Name:      "test-plan",
  1182  									Product:   "test-product",
  1183  									Publisher: "test-publisher",
  1184  								},
  1185  							},
  1186  						},
  1187  					},
  1188  				},
  1189  			},
  1190  			expectErr: false,
  1191  		},
  1192  		{
  1193  			name: "Testing invalid AKS Extension: version given when AutoUpgradeMinorVersion is true",
  1194  			amcp: AzureManagedControlPlane{
  1195  				ObjectMeta: getAMCPMetaData(),
  1196  				Spec: AzureManagedControlPlaneSpec{
  1197  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1198  						Version: "v1.17.8",
  1199  						Extensions: []AKSExtension{
  1200  							{
  1201  								Name:                    "extension1",
  1202  								ExtensionType:           ptr.To("test-type"),
  1203  								Version:                 ptr.To("1.0.0"),
  1204  								AutoUpgradeMinorVersion: ptr.To(true),
  1205  								Plan: &ExtensionPlan{
  1206  									Name:      "test-plan",
  1207  									Product:   "test-product",
  1208  									Publisher: "test-publisher",
  1209  								},
  1210  							},
  1211  						},
  1212  					},
  1213  				},
  1214  			},
  1215  			expectErr: true,
  1216  		},
  1217  		{
  1218  			name: "Testing invalid AKS Extension: missing plan.product and plan.publisher",
  1219  			amcp: AzureManagedControlPlane{
  1220  				ObjectMeta: getAMCPMetaData(),
  1221  				Spec: AzureManagedControlPlaneSpec{
  1222  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1223  						Version: "v1.17.8",
  1224  						Extensions: []AKSExtension{
  1225  							{
  1226  								Name:                    "extension1",
  1227  								ExtensionType:           ptr.To("test-type"),
  1228  								Version:                 ptr.To("1.0.0"),
  1229  								AutoUpgradeMinorVersion: ptr.To(true),
  1230  								Plan: &ExtensionPlan{
  1231  									Name: "test-plan",
  1232  								},
  1233  							},
  1234  						},
  1235  					},
  1236  				},
  1237  			},
  1238  			expectErr: true,
  1239  		},
  1240  		{
  1241  			name: "Test invalid AzureKeyVaultKms",
  1242  			amcp: AzureManagedControlPlane{
  1243  				Spec: AzureManagedControlPlaneSpec{
  1244  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1245  						Version: "v1.17.8",
  1246  						SecurityProfile: &ManagedClusterSecurityProfile{
  1247  							AzureKeyVaultKms: &AzureKeyVaultKms{
  1248  								Enabled:               true,
  1249  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPrivate),
  1250  							},
  1251  						},
  1252  					},
  1253  				},
  1254  			},
  1255  			expectErr: true,
  1256  		},
  1257  		{
  1258  			name: "Valid NetworkDataplane: cilium",
  1259  			amcp: AzureManagedControlPlane{
  1260  				ObjectMeta: getAMCPMetaData(),
  1261  				Spec: AzureManagedControlPlaneSpec{
  1262  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1263  						Version:           "v1.17.8",
  1264  						NetworkPluginMode: ptr.To(NetworkPluginModeOverlay),
  1265  						NetworkDataplane:  ptr.To(NetworkDataplaneTypeCilium),
  1266  						NetworkPolicy:     ptr.To("cilium"),
  1267  					},
  1268  				},
  1269  			},
  1270  			expectErr: false,
  1271  		},
  1272  		{
  1273  			name: "Testing invalid NetworkDataplane: cilium dataplane requires overlay network plugin mode",
  1274  			amcp: AzureManagedControlPlane{
  1275  				ObjectMeta: getAMCPMetaData(),
  1276  				Spec: AzureManagedControlPlaneSpec{
  1277  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1278  						Version:           "v1.17.8",
  1279  						NetworkPluginMode: nil,
  1280  						NetworkDataplane:  ptr.To(NetworkDataplaneTypeCilium),
  1281  						NetworkPolicy:     ptr.To("cilium"),
  1282  					},
  1283  				},
  1284  			},
  1285  			expectErr: true,
  1286  		},
  1287  		{
  1288  			name: "Test valid AzureKeyVaultKms",
  1289  			amcp: AzureManagedControlPlane{
  1290  				Spec: AzureManagedControlPlaneSpec{
  1291  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1292  						Version: "v1.17.8",
  1293  						Identity: &Identity{
  1294  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  1295  							UserAssignedIdentityResourceID: "not empty",
  1296  						},
  1297  						SecurityProfile: &ManagedClusterSecurityProfile{
  1298  							AzureKeyVaultKms: &AzureKeyVaultKms{
  1299  								Enabled:               true,
  1300  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPrivate),
  1301  								KeyVaultResourceID:    ptr.To("0000-0000-0000-000"),
  1302  							},
  1303  						},
  1304  					},
  1305  				},
  1306  			},
  1307  			expectErr: false,
  1308  		},
  1309  		{
  1310  			name: "Test valid AzureKeyVaultKms",
  1311  			amcp: AzureManagedControlPlane{
  1312  				Spec: AzureManagedControlPlaneSpec{
  1313  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1314  						Version: "v1.17.8",
  1315  						Identity: &Identity{
  1316  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  1317  							UserAssignedIdentityResourceID: "not empty",
  1318  						},
  1319  						SecurityProfile: &ManagedClusterSecurityProfile{
  1320  							AzureKeyVaultKms: &AzureKeyVaultKms{
  1321  								Enabled:               true,
  1322  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPublic),
  1323  							},
  1324  						},
  1325  					},
  1326  				},
  1327  			},
  1328  			expectErr: false,
  1329  		},
  1330  		{
  1331  			name: "Testing invalid NetworkDataplane: cilium dataplane requires network policy to be cilium",
  1332  			amcp: AzureManagedControlPlane{
  1333  				ObjectMeta: getAMCPMetaData(),
  1334  				Spec: AzureManagedControlPlaneSpec{
  1335  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1336  						Version:           "v1.17.8",
  1337  						NetworkPluginMode: nil,
  1338  						NetworkDataplane:  ptr.To(NetworkDataplaneTypeCilium),
  1339  						NetworkPolicy:     ptr.To("azure"),
  1340  					},
  1341  				},
  1342  			},
  1343  			expectErr: true,
  1344  		},
  1345  		{
  1346  			name: "Testing invalid NetworkPolicy: cilium network policy can only be used with cilium network dataplane",
  1347  			amcp: AzureManagedControlPlane{
  1348  				ObjectMeta: getAMCPMetaData(),
  1349  				Spec: AzureManagedControlPlaneSpec{
  1350  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1351  						Version:           "v1.17.8",
  1352  						NetworkPluginMode: nil,
  1353  						NetworkDataplane:  ptr.To(NetworkDataplaneTypeAzure),
  1354  						NetworkPolicy:     ptr.To("cilium"),
  1355  					},
  1356  				},
  1357  			},
  1358  			expectErr: true,
  1359  		},
  1360  	}
  1361  
  1362  	for _, tt := range tests {
  1363  		tt := tt
  1364  		// client is used to fetch the AzureManagedControlPlane, we do not want to return an error on client.Get
  1365  		client := mockClient{ReturnError: false}
  1366  		t.Run(tt.name, func(t *testing.T) {
  1367  			g := NewWithT(t)
  1368  			mcpw := &azureManagedControlPlaneWebhook{
  1369  				Client: client,
  1370  			}
  1371  			_, err := mcpw.ValidateCreate(context.Background(), &tt.amcp)
  1372  			if tt.expectErr {
  1373  				g.Expect(err).To(HaveOccurred())
  1374  			} else {
  1375  				g.Expect(err).NotTo(HaveOccurred())
  1376  			}
  1377  		})
  1378  	}
  1379  }
  1380  
  1381  func TestAzureManagedControlPlane_ValidateCreate(t *testing.T) {
  1382  	// NOTE: AzureManageControlPlane is behind AKS feature gate flag; the webhook
  1383  	// must prevent creating new objects in case the feature flag is disabled.
  1384  	defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, capifeature.MachinePool, true)()
  1385  
  1386  	tests := []struct {
  1387  		name     string
  1388  		amcp     *AzureManagedControlPlane
  1389  		wantErr  bool
  1390  		errorLen int
  1391  	}{
  1392  		{
  1393  			name:    "all valid",
  1394  			amcp:    getKnownValidAzureManagedControlPlane(),
  1395  			wantErr: false,
  1396  		},
  1397  		{
  1398  			name:     "invalid DNSServiceIP",
  1399  			amcp:     createAzureManagedControlPlane("192.168.0.10.3", "v1.18.0", generateSSHPublicKey(true)),
  1400  			wantErr:  true,
  1401  			errorLen: 1,
  1402  		},
  1403  		{
  1404  			name:     "invalid DNSServiceIP",
  1405  			amcp:     createAzureManagedControlPlane("192.168.0.11", "v1.18.0", generateSSHPublicKey(true)),
  1406  			wantErr:  true,
  1407  			errorLen: 1,
  1408  		},
  1409  		{
  1410  			name:     "invalid sshKey",
  1411  			amcp:     createAzureManagedControlPlane("192.168.0.10", "v1.18.0", generateSSHPublicKey(false)),
  1412  			wantErr:  true,
  1413  			errorLen: 1,
  1414  		},
  1415  		{
  1416  			name:     "invalid sshKey with a simple text and invalid DNSServiceIP",
  1417  			amcp:     createAzureManagedControlPlane("192.168.0.10.3", "v1.18.0", "invalid_sshkey_honk"),
  1418  			wantErr:  true,
  1419  			errorLen: 2,
  1420  		},
  1421  		{
  1422  			name:     "invalid version",
  1423  			amcp:     createAzureManagedControlPlane("192.168.0.10", "honk.version", generateSSHPublicKey(true)),
  1424  			wantErr:  true,
  1425  			errorLen: 1,
  1426  		},
  1427  		{
  1428  			name: "Testing inValid DNSPrefix for starting with invalid characters",
  1429  			amcp: &AzureManagedControlPlane{
  1430  				Spec: AzureManagedControlPlaneSpec{
  1431  					DNSPrefix: ptr.To("-thisi$"),
  1432  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1433  						Version: "v1.17.8",
  1434  					},
  1435  				},
  1436  			},
  1437  			wantErr: true,
  1438  		},
  1439  		{
  1440  			name: "Testing inValid DNSPrefix with more then 54 characters",
  1441  			amcp: &AzureManagedControlPlane{
  1442  				Spec: AzureManagedControlPlaneSpec{
  1443  					DNSPrefix: ptr.To("thisisaverylong$^clusternameconsistingofmorethan54characterswhichshouldbeinvalid"),
  1444  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1445  						Version: "v1.17.8",
  1446  					},
  1447  				},
  1448  			},
  1449  			wantErr: true,
  1450  		},
  1451  		{
  1452  			name: "Testing inValid DNSPrefix with underscore",
  1453  			amcp: &AzureManagedControlPlane{
  1454  				Spec: AzureManagedControlPlaneSpec{
  1455  					DNSPrefix: ptr.To("no_underscore"),
  1456  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1457  						Version: "v1.17.8",
  1458  					},
  1459  				},
  1460  			},
  1461  			wantErr: true,
  1462  		},
  1463  		{
  1464  			name: "Testing inValid DNSPrefix with special characters",
  1465  			amcp: &AzureManagedControlPlane{
  1466  				Spec: AzureManagedControlPlaneSpec{
  1467  					DNSPrefix: ptr.To("no-dollar$@%"),
  1468  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1469  						Version: "v1.17.8",
  1470  					},
  1471  				},
  1472  			},
  1473  			wantErr: true,
  1474  		},
  1475  		{
  1476  			name: "Testing Valid DNSPrefix with hyphen characters",
  1477  			amcp: &AzureManagedControlPlane{
  1478  				Spec: AzureManagedControlPlaneSpec{
  1479  					DNSPrefix: ptr.To("hyphen-allowed"),
  1480  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1481  						Version: "v1.17.8",
  1482  					},
  1483  				},
  1484  			},
  1485  			wantErr: false,
  1486  		},
  1487  		{
  1488  			name: "Testing Valid DNSPrefix with hyphen characters",
  1489  			amcp: &AzureManagedControlPlane{
  1490  				Spec: AzureManagedControlPlaneSpec{
  1491  					DNSPrefix: ptr.To("palette-test07"),
  1492  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1493  						Version: "v1.17.8",
  1494  					},
  1495  				},
  1496  			},
  1497  			wantErr: false,
  1498  		},
  1499  		{
  1500  			name: "Testing valid DNSPrefix ",
  1501  			amcp: &AzureManagedControlPlane{
  1502  				Spec: AzureManagedControlPlaneSpec{
  1503  					DNSPrefix: ptr.To("thisisavlerylongclu7l0sternam3leconsistingofmorethan54"),
  1504  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1505  						Version: "v1.17.8",
  1506  					},
  1507  				},
  1508  			},
  1509  			wantErr: false,
  1510  		},
  1511  		{
  1512  			name: "invalid name with microsoft",
  1513  			amcp: &AzureManagedControlPlane{
  1514  				ObjectMeta: metav1.ObjectMeta{
  1515  					Name: "microsoft-cluster",
  1516  				},
  1517  				Spec: AzureManagedControlPlaneSpec{
  1518  					SSHPublicKey: ptr.To(generateSSHPublicKey(true)),
  1519  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1520  						DNSServiceIP: ptr.To("192.168.0.10"),
  1521  						Version:      "v1.23.5",
  1522  					},
  1523  				},
  1524  			},
  1525  			wantErr:  true,
  1526  			errorLen: 1,
  1527  		},
  1528  		{
  1529  			name: "invalid name with windows",
  1530  			amcp: &AzureManagedControlPlane{
  1531  				ObjectMeta: metav1.ObjectMeta{
  1532  					Name: "a-windows-cluster",
  1533  				},
  1534  				Spec: AzureManagedControlPlaneSpec{
  1535  					SSHPublicKey: ptr.To(generateSSHPublicKey(true)),
  1536  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1537  						DNSServiceIP: ptr.To("192.168.0.10"),
  1538  						Version:      "v1.23.5",
  1539  					},
  1540  				},
  1541  			},
  1542  			wantErr:  true,
  1543  			errorLen: 1,
  1544  		},
  1545  		{
  1546  			name: "set Spec.ControlPlaneEndpoint.Host during create (clusterctl move scenario)",
  1547  			amcp: &AzureManagedControlPlane{
  1548  				Spec: AzureManagedControlPlaneSpec{
  1549  					ControlPlaneEndpoint: clusterv1.APIEndpoint{
  1550  						Host: "my-host",
  1551  					},
  1552  					SSHPublicKey: ptr.To(generateSSHPublicKey(true)),
  1553  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1554  						DNSServiceIP: ptr.To("192.168.0.10"),
  1555  						Version:      "v1.18.0",
  1556  						AADProfile: &AADProfile{
  1557  							Managed: true,
  1558  							AdminGroupObjectIDs: []string{
  1559  								"616077a8-5db7-4c98-b856-b34619afg75h",
  1560  							},
  1561  						},
  1562  					},
  1563  				},
  1564  			},
  1565  			wantErr: false,
  1566  		},
  1567  		{
  1568  			name: "can set Spec.ControlPlaneEndpoint.Port during create (clusterctl move scenario)",
  1569  			amcp: &AzureManagedControlPlane{
  1570  				Spec: AzureManagedControlPlaneSpec{
  1571  					ControlPlaneEndpoint: clusterv1.APIEndpoint{
  1572  						Port: 444,
  1573  					},
  1574  					SSHPublicKey: ptr.To(generateSSHPublicKey(true)),
  1575  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1576  						DNSServiceIP: ptr.To("192.168.0.10"),
  1577  						Version:      "v1.18.0",
  1578  						AADProfile: &AADProfile{
  1579  							Managed: true,
  1580  							AdminGroupObjectIDs: []string{
  1581  								"616077a8-5db7-4c98-b856-b34619afg75h",
  1582  							},
  1583  						},
  1584  					},
  1585  				},
  1586  			},
  1587  			wantErr: false,
  1588  		},
  1589  		{
  1590  			name: "DisableLocalAccounts cannot be set for non AAD clusters",
  1591  			amcp: &AzureManagedControlPlane{
  1592  				Spec: AzureManagedControlPlaneSpec{
  1593  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1594  						Version:              "v1.21.2",
  1595  						DisableLocalAccounts: ptr.To[bool](true),
  1596  					},
  1597  				},
  1598  			},
  1599  			wantErr: true,
  1600  		},
  1601  		{
  1602  			name: "DisableLocalAccounts can be set for AAD clusters",
  1603  			amcp: &AzureManagedControlPlane{
  1604  				Spec: AzureManagedControlPlaneSpec{
  1605  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1606  						Version: "v1.21.2",
  1607  						AADProfile: &AADProfile{
  1608  							Managed:             true,
  1609  							AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
  1610  						},
  1611  						DisableLocalAccounts: ptr.To[bool](true),
  1612  					},
  1613  				},
  1614  			},
  1615  			wantErr: false,
  1616  		},
  1617  	}
  1618  	client := mockClient{ReturnError: false}
  1619  	for _, tc := range tests {
  1620  		t.Run(tc.name, func(t *testing.T) {
  1621  			g := NewWithT(t)
  1622  			mcpw := &azureManagedControlPlaneWebhook{
  1623  				Client: client,
  1624  			}
  1625  			_, err := mcpw.ValidateCreate(context.Background(), tc.amcp)
  1626  			if tc.wantErr {
  1627  				g.Expect(err).To(HaveOccurred())
  1628  				if tc.errorLen > 0 {
  1629  					g.Expect(err).To(HaveLen(tc.errorLen))
  1630  				}
  1631  			} else {
  1632  				g.Expect(err).NotTo(HaveOccurred())
  1633  			}
  1634  		})
  1635  	}
  1636  }
  1637  
  1638  func TestAzureManagedControlPlane_ValidateCreateFailure(t *testing.T) {
  1639  	tests := []struct {
  1640  		name      string
  1641  		amcp      *AzureManagedControlPlane
  1642  		deferFunc func()
  1643  	}{
  1644  		{
  1645  			name:      "feature gate explicitly disabled",
  1646  			amcp:      getKnownValidAzureManagedControlPlane(),
  1647  			deferFunc: utilfeature.SetFeatureGateDuringTest(t, feature.Gates, capifeature.MachinePool, false),
  1648  		},
  1649  		{
  1650  			name:      "feature gate implicitly disabled",
  1651  			amcp:      getKnownValidAzureManagedControlPlane(),
  1652  			deferFunc: func() {},
  1653  		},
  1654  	}
  1655  	client := mockClient{ReturnError: false}
  1656  	for _, tc := range tests {
  1657  		t.Run(tc.name, func(t *testing.T) {
  1658  			g := NewWithT(t)
  1659  			defer tc.deferFunc()
  1660  			mcpw := &azureManagedControlPlaneWebhook{
  1661  				Client: client,
  1662  			}
  1663  			_, err := mcpw.ValidateCreate(context.Background(), tc.amcp)
  1664  			g.Expect(err).To(HaveOccurred())
  1665  		})
  1666  	}
  1667  }
  1668  
  1669  func TestAzureManagedControlPlane_ValidateUpdate(t *testing.T) {
  1670  	commonSSHKey := generateSSHPublicKey(true)
  1671  	tests := []struct {
  1672  		name    string
  1673  		oldAMCP *AzureManagedControlPlane
  1674  		amcp    *AzureManagedControlPlane
  1675  		wantErr bool
  1676  	}{
  1677  		{
  1678  			name:    "can't add a SSHPublicKey to an existing AzureManagedControlPlane",
  1679  			oldAMCP: createAzureManagedControlPlane("192.168.0.10", "v1.18.0", ""),
  1680  			amcp:    createAzureManagedControlPlane("192.168.0.10", "v1.18.0", generateSSHPublicKey(true)),
  1681  			wantErr: true,
  1682  		},
  1683  		{
  1684  			name:    "same SSHPublicKey is valid",
  1685  			oldAMCP: createAzureManagedControlPlane("192.168.0.10", "v1.18.0", commonSSHKey),
  1686  			amcp:    createAzureManagedControlPlane("192.168.0.10", "v1.18.0", commonSSHKey),
  1687  			wantErr: false,
  1688  		},
  1689  		{
  1690  			name:    "AzureManagedControlPlane with invalid serviceIP",
  1691  			oldAMCP: createAzureManagedControlPlane("", "v1.18.0", ""),
  1692  			amcp:    createAzureManagedControlPlane("192.168.0.10.3", "v1.18.0", generateSSHPublicKey(true)),
  1693  			wantErr: true,
  1694  		},
  1695  		{
  1696  			name:    "AzureManagedControlPlane with invalid serviceIP",
  1697  			oldAMCP: createAzureManagedControlPlane("", "v1.18.0", ""),
  1698  			amcp:    createAzureManagedControlPlane("192.168.0.11", "v1.18.0", generateSSHPublicKey(true)),
  1699  			wantErr: true,
  1700  		},
  1701  		{
  1702  			name:    "AzureManagedControlPlane with invalid version",
  1703  			oldAMCP: createAzureManagedControlPlane("", "v1.18.0", ""),
  1704  			amcp:    createAzureManagedControlPlane("192.168.0.10", "1.999.9", generateSSHPublicKey(true)),
  1705  			wantErr: true,
  1706  		},
  1707  		{
  1708  			name: "AzureManagedControlPlane AddonProfiles is mutable",
  1709  			oldAMCP: &AzureManagedControlPlane{
  1710  				Spec: AzureManagedControlPlaneSpec{
  1711  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1712  						Version: "v1.18.0",
  1713  					},
  1714  				},
  1715  			},
  1716  			amcp: &AzureManagedControlPlane{
  1717  				Spec: AzureManagedControlPlaneSpec{
  1718  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1719  						Version: "v1.18.0",
  1720  						AddonProfiles: []AddonProfile{
  1721  							{
  1722  								Name:    "first-addon-profile",
  1723  								Enabled: true,
  1724  							},
  1725  						},
  1726  					},
  1727  				},
  1728  			},
  1729  			wantErr: false,
  1730  		},
  1731  		{
  1732  			name: "AzureManagedControlPlane AddonProfiles can be disabled",
  1733  			oldAMCP: &AzureManagedControlPlane{
  1734  				Spec: AzureManagedControlPlaneSpec{
  1735  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1736  						AddonProfiles: []AddonProfile{
  1737  							{
  1738  								Name:    "first-addon-profile",
  1739  								Enabled: true,
  1740  							},
  1741  						},
  1742  						Version: "v1.18.0",
  1743  					},
  1744  				},
  1745  			},
  1746  			amcp: &AzureManagedControlPlane{
  1747  				Spec: AzureManagedControlPlaneSpec{
  1748  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1749  						Version: "v1.18.0",
  1750  						AddonProfiles: []AddonProfile{
  1751  							{
  1752  								Name:    "first-addon-profile",
  1753  								Enabled: false,
  1754  							},
  1755  						},
  1756  					},
  1757  				},
  1758  			},
  1759  			wantErr: false,
  1760  		},
  1761  		{
  1762  			name: "AzureManagedControlPlane AddonProfiles cannot update to empty array",
  1763  			oldAMCP: &AzureManagedControlPlane{
  1764  				Spec: AzureManagedControlPlaneSpec{
  1765  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1766  						AddonProfiles: []AddonProfile{
  1767  							{
  1768  								Name:    "first-addon-profile",
  1769  								Enabled: true,
  1770  							},
  1771  						},
  1772  						Version: "v1.18.0",
  1773  					},
  1774  				},
  1775  			},
  1776  			amcp: &AzureManagedControlPlane{
  1777  				Spec: AzureManagedControlPlaneSpec{
  1778  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1779  						Version: "v1.18.0",
  1780  					},
  1781  				},
  1782  			},
  1783  			wantErr: true,
  1784  		},
  1785  		{
  1786  			name: "AzureManagedControlPlane AddonProfiles cannot be completely removed",
  1787  			oldAMCP: &AzureManagedControlPlane{
  1788  				Spec: AzureManagedControlPlaneSpec{
  1789  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1790  						AddonProfiles: []AddonProfile{
  1791  							{
  1792  								Name:    "first-addon-profile",
  1793  								Enabled: true,
  1794  							},
  1795  							{
  1796  								Name:    "second-addon-profile",
  1797  								Enabled: true,
  1798  							},
  1799  						},
  1800  						Version: "v1.18.0",
  1801  					},
  1802  				},
  1803  			},
  1804  			amcp: &AzureManagedControlPlane{
  1805  				Spec: AzureManagedControlPlaneSpec{
  1806  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1807  						AddonProfiles: []AddonProfile{
  1808  							{
  1809  								Name:    "first-addon-profile",
  1810  								Enabled: true,
  1811  							},
  1812  						},
  1813  						Version: "v1.18.0",
  1814  					},
  1815  				},
  1816  			},
  1817  			wantErr: true,
  1818  		},
  1819  		{
  1820  			name: "AzureManagedControlPlane invalid version downgrade change",
  1821  			oldAMCP: &AzureManagedControlPlane{
  1822  				Spec: AzureManagedControlPlaneSpec{
  1823  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1824  						Version: "v1.18.0",
  1825  					},
  1826  				},
  1827  			},
  1828  			amcp: &AzureManagedControlPlane{
  1829  				Spec: AzureManagedControlPlaneSpec{
  1830  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1831  						Version: "v1.17.0",
  1832  					},
  1833  				},
  1834  			},
  1835  			wantErr: true,
  1836  		},
  1837  		{
  1838  			name: "AzureManagedControlPlane invalid version downgrade change",
  1839  			oldAMCP: &AzureManagedControlPlane{
  1840  				Spec: AzureManagedControlPlaneSpec{
  1841  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1842  						Version: "v1.18.0",
  1843  					},
  1844  				},
  1845  				Status: AzureManagedControlPlaneStatus{
  1846  					AutoUpgradeVersion: "v1.18.3",
  1847  				},
  1848  			},
  1849  			amcp: &AzureManagedControlPlane{
  1850  				Spec: AzureManagedControlPlaneSpec{
  1851  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1852  						Version: "v1.18.1",
  1853  					},
  1854  				},
  1855  			},
  1856  			wantErr: true,
  1857  		},
  1858  		{
  1859  			name: "AzureManagedControlPlane Autoupgrade cannot be set to nil",
  1860  			oldAMCP: &AzureManagedControlPlane{
  1861  				Spec: AzureManagedControlPlaneSpec{
  1862  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1863  						DNSServiceIP:   ptr.To("192.168.0.10"),
  1864  						SubscriptionID: "212ec1q8",
  1865  						Version:        "v1.18.0",
  1866  						AutoUpgradeProfile: &ManagedClusterAutoUpgradeProfile{
  1867  							UpgradeChannel: ptr.To(UpgradeChannelStable),
  1868  						},
  1869  					},
  1870  				},
  1871  			},
  1872  			amcp: &AzureManagedControlPlane{
  1873  				Spec: AzureManagedControlPlaneSpec{
  1874  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1875  						DNSServiceIP:   ptr.To("192.168.0.10"),
  1876  						SubscriptionID: "212ec1q8",
  1877  						Version:        "v1.18.0",
  1878  					},
  1879  				},
  1880  			},
  1881  			wantErr: true,
  1882  		},
  1883  		{
  1884  			name: "AzureManagedControlPlane Autoupgrade cannot be set to nil",
  1885  			oldAMCP: &AzureManagedControlPlane{
  1886  				Spec: AzureManagedControlPlaneSpec{
  1887  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1888  						DNSServiceIP:   ptr.To("192.168.0.10"),
  1889  						SubscriptionID: "212ec1q8",
  1890  						Version:        "v1.18.0",
  1891  						AutoUpgradeProfile: &ManagedClusterAutoUpgradeProfile{
  1892  							UpgradeChannel: ptr.To(UpgradeChannelStable),
  1893  						},
  1894  					},
  1895  				},
  1896  			},
  1897  			amcp: &AzureManagedControlPlane{
  1898  				Spec: AzureManagedControlPlaneSpec{
  1899  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1900  						DNSServiceIP:       ptr.To("192.168.0.10"),
  1901  						SubscriptionID:     "212ec1q8",
  1902  						Version:            "v1.18.0",
  1903  						AutoUpgradeProfile: &ManagedClusterAutoUpgradeProfile{},
  1904  					},
  1905  				},
  1906  			},
  1907  			wantErr: true,
  1908  		},
  1909  		{
  1910  			name: "AzureManagedControlPlane Autoupgrade is mutable",
  1911  			oldAMCP: &AzureManagedControlPlane{
  1912  				Spec: AzureManagedControlPlaneSpec{
  1913  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1914  						DNSServiceIP:   ptr.To("192.168.0.10"),
  1915  						SubscriptionID: "212ec1q8",
  1916  						Version:        "v1.18.0",
  1917  						AutoUpgradeProfile: &ManagedClusterAutoUpgradeProfile{
  1918  							UpgradeChannel: ptr.To(UpgradeChannelStable),
  1919  						},
  1920  					},
  1921  				},
  1922  			},
  1923  			amcp: &AzureManagedControlPlane{
  1924  				Spec: AzureManagedControlPlaneSpec{
  1925  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1926  						DNSServiceIP:   ptr.To("192.168.0.10"),
  1927  						SubscriptionID: "212ec1q8",
  1928  						Version:        "v1.18.0",
  1929  						AutoUpgradeProfile: &ManagedClusterAutoUpgradeProfile{
  1930  							UpgradeChannel: ptr.To(UpgradeChannelNone),
  1931  						},
  1932  					},
  1933  				},
  1934  			},
  1935  			wantErr: false,
  1936  		},
  1937  		{
  1938  			name: "AzureManagedControlPlane SubscriptionID is immutable",
  1939  			oldAMCP: &AzureManagedControlPlane{
  1940  				Spec: AzureManagedControlPlaneSpec{
  1941  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1942  						DNSServiceIP:   ptr.To("192.168.0.10"),
  1943  						SubscriptionID: "212ec1q8",
  1944  						Version:        "v1.18.0",
  1945  					},
  1946  				},
  1947  			},
  1948  			amcp: &AzureManagedControlPlane{
  1949  				Spec: AzureManagedControlPlaneSpec{
  1950  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1951  						DNSServiceIP:   ptr.To("192.168.0.10"),
  1952  						SubscriptionID: "212ec1q9",
  1953  						Version:        "v1.18.0",
  1954  					},
  1955  				},
  1956  			},
  1957  			wantErr: true,
  1958  		},
  1959  		{
  1960  			name: "AzureManagedControlPlane ResourceGroupName is immutable",
  1961  			oldAMCP: &AzureManagedControlPlane{
  1962  				Spec: AzureManagedControlPlaneSpec{
  1963  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1964  						DNSServiceIP: ptr.To("192.168.0.10"),
  1965  						Version:      "v1.18.0",
  1966  					},
  1967  					ResourceGroupName: "hello-1",
  1968  				},
  1969  			},
  1970  			amcp: &AzureManagedControlPlane{
  1971  				Spec: AzureManagedControlPlaneSpec{
  1972  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1973  						DNSServiceIP: ptr.To("192.168.0.10"),
  1974  						Version:      "v1.18.0",
  1975  					},
  1976  					ResourceGroupName: "hello-2",
  1977  				},
  1978  			},
  1979  			wantErr: true,
  1980  		},
  1981  		{
  1982  			name: "AzureManagedControlPlane NodeResourceGroupName is immutable",
  1983  			oldAMCP: &AzureManagedControlPlane{
  1984  				Spec: AzureManagedControlPlaneSpec{
  1985  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1986  						DNSServiceIP: ptr.To("192.168.0.10"),
  1987  						Version:      "v1.18.0",
  1988  					},
  1989  					NodeResourceGroupName: "hello-1",
  1990  				},
  1991  			},
  1992  			amcp: &AzureManagedControlPlane{
  1993  				Spec: AzureManagedControlPlaneSpec{
  1994  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  1995  						DNSServiceIP: ptr.To("192.168.0.10"),
  1996  						Version:      "v1.18.0",
  1997  					},
  1998  					NodeResourceGroupName: "hello-2",
  1999  				},
  2000  			},
  2001  			wantErr: true,
  2002  		},
  2003  		{
  2004  			name: "AzureManagedControlPlane Location is immutable",
  2005  			oldAMCP: &AzureManagedControlPlane{
  2006  				Spec: AzureManagedControlPlaneSpec{
  2007  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2008  						DNSServiceIP: ptr.To("192.168.0.10"),
  2009  						Location:     "westeurope",
  2010  						Version:      "v1.18.0",
  2011  					},
  2012  				},
  2013  			},
  2014  			amcp: &AzureManagedControlPlane{
  2015  				Spec: AzureManagedControlPlaneSpec{
  2016  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2017  						DNSServiceIP: ptr.To("192.168.0.10"),
  2018  						Location:     "eastus",
  2019  						Version:      "v1.18.0",
  2020  					},
  2021  				},
  2022  			},
  2023  			wantErr: true,
  2024  		},
  2025  		{
  2026  			name: "AzureManagedControlPlane SSHPublicKey is immutable",
  2027  			oldAMCP: &AzureManagedControlPlane{
  2028  				Spec: AzureManagedControlPlaneSpec{
  2029  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2030  						DNSServiceIP: ptr.To("192.168.0.10"),
  2031  						Version:      "v1.18.0",
  2032  					},
  2033  					SSHPublicKey: ptr.To(generateSSHPublicKey(true)),
  2034  				},
  2035  			},
  2036  			amcp: &AzureManagedControlPlane{
  2037  				Spec: AzureManagedControlPlaneSpec{
  2038  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2039  						DNSServiceIP: ptr.To("192.168.0.10"),
  2040  						Version:      "v1.18.0",
  2041  					},
  2042  					SSHPublicKey: ptr.To(generateSSHPublicKey(true)),
  2043  				},
  2044  			},
  2045  			wantErr: true,
  2046  		},
  2047  		{
  2048  			name: "AzureManagedControlPlane DNSServiceIP is immutable",
  2049  			oldAMCP: &AzureManagedControlPlane{
  2050  				Spec: AzureManagedControlPlaneSpec{
  2051  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2052  						DNSServiceIP: ptr.To("192.168.0.10"),
  2053  						Version:      "v1.18.0",
  2054  					},
  2055  				},
  2056  			},
  2057  			amcp: &AzureManagedControlPlane{
  2058  				Spec: AzureManagedControlPlaneSpec{
  2059  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2060  						DNSServiceIP: ptr.To("192.168.1.1"),
  2061  						Version:      "v1.18.0",
  2062  					},
  2063  				},
  2064  			},
  2065  			wantErr: true,
  2066  		},
  2067  		{
  2068  			name: "AzureManagedControlPlane DNSServiceIP is immutable, unsetting is not allowed",
  2069  			oldAMCP: &AzureManagedControlPlane{
  2070  				Spec: AzureManagedControlPlaneSpec{
  2071  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2072  						DNSServiceIP: ptr.To("192.168.0.10"),
  2073  						Version:      "v1.18.0",
  2074  					},
  2075  				},
  2076  			},
  2077  			amcp: &AzureManagedControlPlane{
  2078  				Spec: AzureManagedControlPlaneSpec{
  2079  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2080  						Version: "v1.18.0",
  2081  					},
  2082  				},
  2083  			},
  2084  			wantErr: true,
  2085  		},
  2086  		{
  2087  			name: "AzureManagedControlPlane NetworkPlugin is immutable",
  2088  			oldAMCP: &AzureManagedControlPlane{
  2089  				Spec: AzureManagedControlPlaneSpec{
  2090  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2091  						DNSServiceIP:  ptr.To("192.168.0.10"),
  2092  						NetworkPlugin: ptr.To("azure"),
  2093  						Version:       "v1.18.0",
  2094  					},
  2095  				},
  2096  			},
  2097  			amcp: &AzureManagedControlPlane{
  2098  				Spec: AzureManagedControlPlaneSpec{
  2099  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2100  						DNSServiceIP:  ptr.To("192.168.0.10"),
  2101  						NetworkPlugin: ptr.To("kubenet"),
  2102  						Version:       "v1.18.0",
  2103  					},
  2104  				},
  2105  			},
  2106  			wantErr: true,
  2107  		},
  2108  		{
  2109  			name: "AzureManagedControlPlane NetworkPlugin is immutable, unsetting is not allowed",
  2110  			oldAMCP: &AzureManagedControlPlane{
  2111  				Spec: AzureManagedControlPlaneSpec{
  2112  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2113  						DNSServiceIP:  ptr.To("192.168.0.10"),
  2114  						NetworkPlugin: ptr.To("azure"),
  2115  						Version:       "v1.18.0",
  2116  					},
  2117  				},
  2118  			},
  2119  			amcp: &AzureManagedControlPlane{
  2120  				Spec: AzureManagedControlPlaneSpec{
  2121  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2122  						DNSServiceIP: ptr.To("192.168.0.10"),
  2123  						Version:      "v1.18.0",
  2124  					},
  2125  				},
  2126  			},
  2127  			wantErr: true,
  2128  		},
  2129  		{
  2130  			name: "AzureManagedControlPlane NetworkPolicy is immutable",
  2131  			oldAMCP: &AzureManagedControlPlane{
  2132  				Spec: AzureManagedControlPlaneSpec{
  2133  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2134  						DNSServiceIP:  ptr.To("192.168.0.10"),
  2135  						NetworkPolicy: ptr.To("azure"),
  2136  						Version:       "v1.18.0",
  2137  					},
  2138  				},
  2139  			},
  2140  			amcp: &AzureManagedControlPlane{
  2141  				Spec: AzureManagedControlPlaneSpec{
  2142  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2143  						DNSServiceIP:  ptr.To("192.168.0.10"),
  2144  						NetworkPolicy: ptr.To("calico"),
  2145  						Version:       "v1.18.0",
  2146  					},
  2147  				},
  2148  			},
  2149  			wantErr: true,
  2150  		},
  2151  		{
  2152  			name: "AzureManagedControlPlane NetworkPolicy is immutable, unsetting is not allowed",
  2153  			oldAMCP: &AzureManagedControlPlane{
  2154  				Spec: AzureManagedControlPlaneSpec{
  2155  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2156  						DNSServiceIP:  ptr.To("192.168.0.10"),
  2157  						NetworkPolicy: ptr.To("azure"),
  2158  						Version:       "v1.18.0",
  2159  					},
  2160  				},
  2161  			},
  2162  			amcp: &AzureManagedControlPlane{
  2163  				Spec: AzureManagedControlPlaneSpec{
  2164  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2165  						DNSServiceIP: ptr.To("192.168.0.10"),
  2166  						Version:      "v1.18.0",
  2167  					},
  2168  				},
  2169  			},
  2170  			wantErr: true,
  2171  		},
  2172  		{
  2173  			name: "AzureManagedControlPlane NetworkPolicy is immutable",
  2174  			oldAMCP: &AzureManagedControlPlane{
  2175  				Spec: AzureManagedControlPlaneSpec{
  2176  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2177  						DNSServiceIP:     ptr.To("192.168.0.10"),
  2178  						NetworkDataplane: ptr.To(NetworkDataplaneTypeCilium),
  2179  						Version:          "v1.18.0",
  2180  					},
  2181  				},
  2182  			},
  2183  			amcp: &AzureManagedControlPlane{
  2184  				Spec: AzureManagedControlPlaneSpec{
  2185  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2186  						DNSServiceIP:     ptr.To("192.168.0.10"),
  2187  						NetworkDataplane: ptr.To(NetworkDataplaneTypeAzure),
  2188  						Version:          "v1.18.0",
  2189  					},
  2190  				},
  2191  			},
  2192  			wantErr: true,
  2193  		},
  2194  		{
  2195  			name: "AzureManagedControlPlane NetworkDataplane is immutable, unsetting is not allowed",
  2196  			oldAMCP: &AzureManagedControlPlane{
  2197  				Spec: AzureManagedControlPlaneSpec{
  2198  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2199  						DNSServiceIP:     ptr.To("192.168.0.10"),
  2200  						NetworkDataplane: ptr.To(NetworkDataplaneTypeCilium),
  2201  						Version:          "v1.18.0",
  2202  					},
  2203  				},
  2204  			},
  2205  			amcp: &AzureManagedControlPlane{
  2206  				Spec: AzureManagedControlPlaneSpec{
  2207  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2208  						DNSServiceIP: ptr.To("192.168.0.10"),
  2209  						Version:      "v1.18.0",
  2210  					},
  2211  				},
  2212  			},
  2213  			wantErr: true,
  2214  		},
  2215  		{
  2216  			name: "AzureManagedControlPlane LoadBalancerSKU is immutable",
  2217  			oldAMCP: &AzureManagedControlPlane{
  2218  				Spec: AzureManagedControlPlaneSpec{
  2219  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2220  						DNSServiceIP:    ptr.To("192.168.0.10"),
  2221  						LoadBalancerSKU: ptr.To("Standard"),
  2222  						Version:         "v1.18.0",
  2223  					},
  2224  				},
  2225  			},
  2226  			amcp: &AzureManagedControlPlane{
  2227  				Spec: AzureManagedControlPlaneSpec{
  2228  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2229  						DNSServiceIP:    ptr.To("192.168.0.10"),
  2230  						LoadBalancerSKU: ptr.To(LoadBalancerSKUBasic),
  2231  						Version:         "v1.18.0",
  2232  					},
  2233  				},
  2234  			},
  2235  			wantErr: true,
  2236  		},
  2237  		{
  2238  			name: "AzureManagedControlPlane LoadBalancerSKU is immutable, unsetting is not allowed",
  2239  			oldAMCP: &AzureManagedControlPlane{
  2240  				Spec: AzureManagedControlPlaneSpec{
  2241  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2242  						DNSServiceIP:    ptr.To("192.168.0.10"),
  2243  						LoadBalancerSKU: ptr.To(LoadBalancerSKUStandard),
  2244  						Version:         "v1.18.0",
  2245  					},
  2246  				},
  2247  			},
  2248  			amcp: &AzureManagedControlPlane{
  2249  				Spec: AzureManagedControlPlaneSpec{
  2250  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2251  						DNSServiceIP: ptr.To("192.168.0.10"),
  2252  						Version:      "v1.18.0",
  2253  					},
  2254  				},
  2255  			},
  2256  			wantErr: true,
  2257  		},
  2258  		{
  2259  			name: "AzureManagedControlPlane ManagedAad can be set after cluster creation",
  2260  			oldAMCP: &AzureManagedControlPlane{
  2261  				Spec: AzureManagedControlPlaneSpec{
  2262  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2263  						Version: "v1.18.0",
  2264  					},
  2265  				},
  2266  			},
  2267  			amcp: &AzureManagedControlPlane{
  2268  				Spec: AzureManagedControlPlaneSpec{
  2269  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2270  						Version: "v1.18.0",
  2271  						AADProfile: &AADProfile{
  2272  							Managed: true,
  2273  							AdminGroupObjectIDs: []string{
  2274  								"616077a8-5db7-4c98-b856-b34619afg75h",
  2275  							},
  2276  						},
  2277  					},
  2278  				},
  2279  			},
  2280  			wantErr: false,
  2281  		},
  2282  		{
  2283  			name: "AzureManagedControlPlane ManagedAad cannot be disabled",
  2284  			oldAMCP: &AzureManagedControlPlane{
  2285  				Spec: AzureManagedControlPlaneSpec{
  2286  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2287  						Version: "v1.18.0",
  2288  						AADProfile: &AADProfile{
  2289  							Managed: true,
  2290  							AdminGroupObjectIDs: []string{
  2291  								"616077a8-5db7-4c98-b856-b34619afg75h",
  2292  							},
  2293  						},
  2294  					},
  2295  				},
  2296  			},
  2297  			amcp: &AzureManagedControlPlane{
  2298  				Spec: AzureManagedControlPlaneSpec{
  2299  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2300  						Version:    "v1.18.0",
  2301  						AADProfile: &AADProfile{},
  2302  					},
  2303  				},
  2304  			},
  2305  			wantErr: true,
  2306  		},
  2307  		{
  2308  			name: "AzureManagedControlPlane managed field cannot set to false",
  2309  			oldAMCP: &AzureManagedControlPlane{
  2310  				Spec: AzureManagedControlPlaneSpec{
  2311  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2312  						Version: "v1.18.0",
  2313  						AADProfile: &AADProfile{
  2314  							Managed: true,
  2315  							AdminGroupObjectIDs: []string{
  2316  								"616077a8-5db7-4c98-b856-b34619afg75h",
  2317  							},
  2318  						},
  2319  					},
  2320  				},
  2321  			},
  2322  			amcp: &AzureManagedControlPlane{
  2323  				Spec: AzureManagedControlPlaneSpec{
  2324  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2325  						Version: "v1.18.0",
  2326  						AADProfile: &AADProfile{
  2327  							Managed: false,
  2328  							AdminGroupObjectIDs: []string{
  2329  								"616077a8-5db7-4c98-b856-b34619afg75h",
  2330  							},
  2331  						},
  2332  					},
  2333  				},
  2334  			},
  2335  			wantErr: true,
  2336  		},
  2337  		{
  2338  			name: "AzureManagedControlPlane adminGroupObjectIDs cannot set to empty",
  2339  			oldAMCP: &AzureManagedControlPlane{
  2340  				Spec: AzureManagedControlPlaneSpec{
  2341  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2342  						Version: "v1.18.0",
  2343  						AADProfile: &AADProfile{
  2344  							Managed: true,
  2345  							AdminGroupObjectIDs: []string{
  2346  								"616077a8-5db7-4c98-b856-b34619afg75h",
  2347  							},
  2348  						},
  2349  					},
  2350  				},
  2351  			},
  2352  			amcp: &AzureManagedControlPlane{
  2353  				Spec: AzureManagedControlPlaneSpec{
  2354  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2355  						Version: "v1.18.0",
  2356  						AADProfile: &AADProfile{
  2357  							Managed:             true,
  2358  							AdminGroupObjectIDs: []string{},
  2359  						},
  2360  					},
  2361  				},
  2362  			},
  2363  			wantErr: true,
  2364  		},
  2365  		{
  2366  			name: "AzureManagedControlPlane ManagedAad cannot be disabled",
  2367  			oldAMCP: &AzureManagedControlPlane{
  2368  				Spec: AzureManagedControlPlaneSpec{
  2369  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2370  						Version: "v1.18.0",
  2371  						AADProfile: &AADProfile{
  2372  							Managed: true,
  2373  							AdminGroupObjectIDs: []string{
  2374  								"616077a8-5db7-4c98-b856-b34619afg75h",
  2375  							},
  2376  						},
  2377  					},
  2378  				},
  2379  			},
  2380  			amcp: &AzureManagedControlPlane{
  2381  				Spec: AzureManagedControlPlaneSpec{
  2382  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2383  						Version: "v1.18.0",
  2384  					},
  2385  				},
  2386  			},
  2387  			wantErr: true,
  2388  		},
  2389  		{
  2390  			name: "AzureManagedControlPlane EnablePrivateCluster is immutable",
  2391  			oldAMCP: &AzureManagedControlPlane{
  2392  				Spec: AzureManagedControlPlaneSpec{
  2393  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2394  						DNSServiceIP: ptr.To("192.168.0.10"),
  2395  						Version:      "v1.18.0",
  2396  					},
  2397  				},
  2398  			},
  2399  			amcp: &AzureManagedControlPlane{
  2400  				Spec: AzureManagedControlPlaneSpec{
  2401  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2402  						DNSServiceIP: ptr.To("192.168.0.10"),
  2403  						Version:      "v1.18.0",
  2404  						APIServerAccessProfile: &APIServerAccessProfile{
  2405  							APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  2406  								EnablePrivateCluster: ptr.To(true),
  2407  							},
  2408  						},
  2409  					},
  2410  				},
  2411  			},
  2412  			wantErr: true,
  2413  		},
  2414  		{
  2415  			name: "AzureManagedControlPlane AuthorizedIPRanges is mutable",
  2416  			oldAMCP: &AzureManagedControlPlane{
  2417  				Spec: AzureManagedControlPlaneSpec{
  2418  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2419  						DNSServiceIP: ptr.To("192.168.0.10"),
  2420  						Version:      "v1.18.0",
  2421  					},
  2422  				},
  2423  			},
  2424  			amcp: &AzureManagedControlPlane{
  2425  				Spec: AzureManagedControlPlaneSpec{
  2426  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2427  						DNSServiceIP: ptr.To("192.168.0.10"),
  2428  						Version:      "v1.18.0",
  2429  						APIServerAccessProfile: &APIServerAccessProfile{
  2430  							AuthorizedIPRanges: []string{"192.168.0.1/32"},
  2431  						},
  2432  					},
  2433  				},
  2434  			},
  2435  			wantErr: false,
  2436  		},
  2437  		{
  2438  			name: "AzureManagedControlPlane.VirtualNetwork Name is mutable",
  2439  			oldAMCP: &AzureManagedControlPlane{
  2440  				ObjectMeta: metav1.ObjectMeta{
  2441  					Name: "test-cluster",
  2442  				},
  2443  				Spec: AzureManagedControlPlaneSpec{
  2444  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2445  						DNSServiceIP: ptr.To("192.168.0.10"),
  2446  						Version:      "v1.18.0",
  2447  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  2448  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  2449  								Name:      "test-network",
  2450  								CIDRBlock: "10.0.0.0/8",
  2451  								Subnet: ManagedControlPlaneSubnet{
  2452  									Name:      "test-subnet",
  2453  									CIDRBlock: "10.0.2.0/24",
  2454  								},
  2455  							},
  2456  							ResourceGroup: "test-rg",
  2457  						},
  2458  					},
  2459  				},
  2460  			},
  2461  			amcp: &AzureManagedControlPlane{
  2462  				ObjectMeta: metav1.ObjectMeta{
  2463  					Name: "test-cluster",
  2464  				},
  2465  				Spec: AzureManagedControlPlaneSpec{
  2466  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2467  						DNSServiceIP: ptr.To("192.168.0.10"),
  2468  						Version:      "v1.18.0",
  2469  					},
  2470  				},
  2471  			},
  2472  			wantErr: true,
  2473  		},
  2474  		{
  2475  			name: "AzureManagedControlPlane.VirtualNetwork Name is mutable",
  2476  			oldAMCP: &AzureManagedControlPlane{
  2477  				ObjectMeta: metav1.ObjectMeta{
  2478  					Name: "test-cluster",
  2479  				},
  2480  				Spec: AzureManagedControlPlaneSpec{
  2481  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2482  						DNSServiceIP: ptr.To("192.168.0.10"),
  2483  						Version:      "v1.18.0",
  2484  					},
  2485  				},
  2486  			},
  2487  			amcp: &AzureManagedControlPlane{
  2488  				ObjectMeta: metav1.ObjectMeta{
  2489  					Name: "test-cluster",
  2490  				},
  2491  				Spec: AzureManagedControlPlaneSpec{
  2492  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2493  						DNSServiceIP: ptr.To("192.168.0.10"),
  2494  						Version:      "v1.18.0",
  2495  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  2496  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  2497  								Name:      "test-network",
  2498  								CIDRBlock: "10.0.0.0/8",
  2499  								Subnet: ManagedControlPlaneSubnet{
  2500  									Name:      "test-subnet",
  2501  									CIDRBlock: "10.0.2.0/24",
  2502  								},
  2503  							},
  2504  							ResourceGroup: "test-rg",
  2505  						},
  2506  					},
  2507  				},
  2508  			},
  2509  			wantErr: true,
  2510  		},
  2511  		{
  2512  			name: "AzureManagedControlPlane.VirtualNetwork Name is mutable",
  2513  			oldAMCP: &AzureManagedControlPlane{
  2514  				ObjectMeta: metav1.ObjectMeta{
  2515  					Name: "test-cluster",
  2516  				},
  2517  				Spec: AzureManagedControlPlaneSpec{
  2518  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2519  						DNSServiceIP: ptr.To("192.168.0.10"),
  2520  						Version:      "v1.18.0",
  2521  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  2522  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  2523  								Name:      "test-network",
  2524  								CIDRBlock: "10.0.0.0/8",
  2525  								Subnet: ManagedControlPlaneSubnet{
  2526  									Name:      "test-subnet",
  2527  									CIDRBlock: "10.0.2.0/24",
  2528  								},
  2529  							},
  2530  							ResourceGroup: "test-rg",
  2531  						},
  2532  					},
  2533  				},
  2534  			},
  2535  			amcp: &AzureManagedControlPlane{
  2536  				ObjectMeta: metav1.ObjectMeta{
  2537  					Name: "test-cluster",
  2538  				},
  2539  				Spec: AzureManagedControlPlaneSpec{
  2540  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2541  						DNSServiceIP: ptr.To("192.168.0.10"),
  2542  						Version:      "v1.18.0",
  2543  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  2544  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  2545  								Name:      "test-network",
  2546  								CIDRBlock: "10.0.0.0/8",
  2547  								Subnet: ManagedControlPlaneSubnet{
  2548  									Name:      "test-subnet",
  2549  									CIDRBlock: "10.0.2.0/24",
  2550  								},
  2551  							},
  2552  							ResourceGroup: "test-rg",
  2553  						},
  2554  					},
  2555  				},
  2556  			},
  2557  			wantErr: false,
  2558  		},
  2559  		{
  2560  			name: "OutboundType update",
  2561  			oldAMCP: &AzureManagedControlPlane{
  2562  				ObjectMeta: metav1.ObjectMeta{
  2563  					Name: "test-cluster",
  2564  				},
  2565  				Spec: AzureManagedControlPlaneSpec{
  2566  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2567  						OutboundType: (*ManagedControlPlaneOutboundType)(ptr.To(string(ManagedControlPlaneOutboundTypeUserDefinedRouting))),
  2568  					},
  2569  				},
  2570  			},
  2571  			amcp: &AzureManagedControlPlane{
  2572  				ObjectMeta: metav1.ObjectMeta{
  2573  					Name: "test-cluster",
  2574  				},
  2575  				Spec: AzureManagedControlPlaneSpec{
  2576  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2577  						OutboundType: (*ManagedControlPlaneOutboundType)(ptr.To(string(ManagedControlPlaneOutboundTypeLoadBalancer))),
  2578  					},
  2579  				},
  2580  			},
  2581  			wantErr: true,
  2582  		},
  2583  		{
  2584  			name: "AzureManagedControlPlane HTTPProxyConfig is immutable",
  2585  			oldAMCP: &AzureManagedControlPlane{
  2586  				ObjectMeta: metav1.ObjectMeta{
  2587  					Name: "test-cluster",
  2588  				},
  2589  				Spec: AzureManagedControlPlaneSpec{
  2590  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2591  						HTTPProxyConfig: &HTTPProxyConfig{
  2592  							HTTPProxy:  ptr.To("http://1.2.3.4:8080"),
  2593  							HTTPSProxy: ptr.To("https://5.6.7.8:8443"),
  2594  							NoProxy:    []string{"endpoint1", "endpoint2"},
  2595  							TrustedCA:  ptr.To("ca"),
  2596  						},
  2597  					},
  2598  				},
  2599  			},
  2600  			amcp: &AzureManagedControlPlane{
  2601  				ObjectMeta: metav1.ObjectMeta{
  2602  					Name: "test-cluster",
  2603  				},
  2604  				Spec: AzureManagedControlPlaneSpec{
  2605  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2606  						HTTPProxyConfig: &HTTPProxyConfig{
  2607  							HTTPProxy:  ptr.To("http://10.20.3.4:8080"),
  2608  							HTTPSProxy: ptr.To("https://5.6.7.8:8443"),
  2609  							NoProxy:    []string{"endpoint1", "endpoint2"},
  2610  							TrustedCA:  ptr.To("ca"),
  2611  						},
  2612  					},
  2613  				},
  2614  			},
  2615  			wantErr: true,
  2616  		},
  2617  		{
  2618  			name: "NetworkPluginMode cannot change to \"overlay\" when NetworkPolicy is set",
  2619  			oldAMCP: &AzureManagedControlPlane{
  2620  				ObjectMeta: metav1.ObjectMeta{
  2621  					Name: "test-cluster",
  2622  				},
  2623  				Spec: AzureManagedControlPlaneSpec{
  2624  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2625  						NetworkPolicy:     ptr.To("anything"),
  2626  						NetworkPluginMode: nil,
  2627  					},
  2628  				},
  2629  			},
  2630  			amcp: &AzureManagedControlPlane{
  2631  				ObjectMeta: metav1.ObjectMeta{
  2632  					Name: "test-cluster",
  2633  				},
  2634  				Spec: AzureManagedControlPlaneSpec{
  2635  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2636  						NetworkPolicy:     ptr.To("anything"),
  2637  						NetworkPluginMode: ptr.To(NetworkPluginModeOverlay),
  2638  					},
  2639  				},
  2640  			},
  2641  			wantErr: true,
  2642  		},
  2643  		{
  2644  			name: "NetworkPluginMode can change to \"overlay\" when NetworkPolicy is not set",
  2645  			oldAMCP: &AzureManagedControlPlane{
  2646  				ObjectMeta: metav1.ObjectMeta{
  2647  					Name: "test-cluster",
  2648  				},
  2649  				Spec: AzureManagedControlPlaneSpec{
  2650  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2651  						NetworkPolicy:     nil,
  2652  						NetworkPluginMode: nil,
  2653  					},
  2654  				},
  2655  			},
  2656  			amcp: &AzureManagedControlPlane{
  2657  				ObjectMeta: metav1.ObjectMeta{
  2658  					Name: "test-cluster",
  2659  				},
  2660  				Spec: AzureManagedControlPlaneSpec{
  2661  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2662  						Version:           "v0.0.0",
  2663  						NetworkPluginMode: ptr.To(NetworkPluginModeOverlay),
  2664  					},
  2665  				},
  2666  			},
  2667  			wantErr: false,
  2668  		},
  2669  		{
  2670  			name: "NetworkPolicy is allowed when NetworkPluginMode is not changed",
  2671  			oldAMCP: &AzureManagedControlPlane{
  2672  				ObjectMeta: metav1.ObjectMeta{
  2673  					Name: "test-cluster",
  2674  				},
  2675  				Spec: AzureManagedControlPlaneSpec{
  2676  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2677  						NetworkPolicy:     ptr.To("anything"),
  2678  						NetworkPluginMode: ptr.To(NetworkPluginModeOverlay),
  2679  					},
  2680  				},
  2681  			},
  2682  			amcp: &AzureManagedControlPlane{
  2683  				ObjectMeta: metav1.ObjectMeta{
  2684  					Name: "test-cluster",
  2685  				},
  2686  				Spec: AzureManagedControlPlaneSpec{
  2687  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2688  						NetworkPolicy:     ptr.To("anything"),
  2689  						Version:           "v0.0.0",
  2690  						NetworkPluginMode: ptr.To(NetworkPluginModeOverlay),
  2691  					},
  2692  				},
  2693  			},
  2694  			wantErr: false,
  2695  		},
  2696  		{
  2697  			name: "AzureManagedControlPlane OIDCIssuerProfile.Enabled false -> false OK",
  2698  			oldAMCP: &AzureManagedControlPlane{
  2699  				ObjectMeta: metav1.ObjectMeta{
  2700  					Name: "test-cluster",
  2701  				},
  2702  				Spec: AzureManagedControlPlaneSpec{
  2703  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2704  						OIDCIssuerProfile: &OIDCIssuerProfile{
  2705  							Enabled: ptr.To(false),
  2706  						},
  2707  					},
  2708  				},
  2709  			},
  2710  			amcp: &AzureManagedControlPlane{
  2711  				ObjectMeta: metav1.ObjectMeta{
  2712  					Name: "test-cluster",
  2713  				},
  2714  				Spec: AzureManagedControlPlaneSpec{
  2715  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2716  						Version: "v0.0.0",
  2717  						OIDCIssuerProfile: &OIDCIssuerProfile{
  2718  							Enabled: ptr.To(false),
  2719  						},
  2720  					},
  2721  				},
  2722  			},
  2723  			wantErr: false,
  2724  		},
  2725  		{
  2726  			name: "AzureManagedControlPlane OIDCIssuerProfile.Enabled false -> true OK",
  2727  			oldAMCP: &AzureManagedControlPlane{
  2728  				ObjectMeta: metav1.ObjectMeta{
  2729  					Name: "test-cluster",
  2730  				},
  2731  				Spec: AzureManagedControlPlaneSpec{
  2732  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2733  						OIDCIssuerProfile: &OIDCIssuerProfile{
  2734  							Enabled: ptr.To(false),
  2735  						},
  2736  					},
  2737  				},
  2738  			},
  2739  			amcp: &AzureManagedControlPlane{
  2740  				ObjectMeta: metav1.ObjectMeta{
  2741  					Name: "test-cluster",
  2742  				},
  2743  				Spec: AzureManagedControlPlaneSpec{
  2744  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2745  						Version: "v0.0.0",
  2746  						OIDCIssuerProfile: &OIDCIssuerProfile{
  2747  							Enabled: ptr.To(true),
  2748  						},
  2749  					},
  2750  				},
  2751  			},
  2752  			wantErr: false,
  2753  		},
  2754  		{
  2755  			name: "AzureManagedControlPlane OIDCIssuerProfile.Enabled true -> false err",
  2756  			oldAMCP: &AzureManagedControlPlane{
  2757  				ObjectMeta: metav1.ObjectMeta{
  2758  					Name: "test-cluster",
  2759  				},
  2760  				Spec: AzureManagedControlPlaneSpec{
  2761  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2762  						OIDCIssuerProfile: &OIDCIssuerProfile{
  2763  							Enabled: ptr.To(true),
  2764  						},
  2765  					},
  2766  				},
  2767  			},
  2768  			amcp: &AzureManagedControlPlane{
  2769  				ObjectMeta: metav1.ObjectMeta{
  2770  					Name: "test-cluster",
  2771  				},
  2772  				Spec: AzureManagedControlPlaneSpec{
  2773  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2774  						Version: "v0.0.0",
  2775  						OIDCIssuerProfile: &OIDCIssuerProfile{
  2776  							Enabled: ptr.To(false),
  2777  						},
  2778  					},
  2779  				},
  2780  			},
  2781  			wantErr: true,
  2782  		},
  2783  		{
  2784  			name: "AzureManagedControlPlane OIDCIssuerProfile.Enabled true -> true OK",
  2785  			oldAMCP: &AzureManagedControlPlane{
  2786  				ObjectMeta: metav1.ObjectMeta{
  2787  					Name: "test-cluster",
  2788  				},
  2789  				Spec: AzureManagedControlPlaneSpec{
  2790  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2791  						OIDCIssuerProfile: &OIDCIssuerProfile{
  2792  							Enabled: ptr.To(true),
  2793  						},
  2794  					},
  2795  				},
  2796  			},
  2797  			amcp: &AzureManagedControlPlane{
  2798  				ObjectMeta: metav1.ObjectMeta{
  2799  					Name: "test-cluster",
  2800  				},
  2801  				Spec: AzureManagedControlPlaneSpec{
  2802  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2803  						Version: "v0.0.0",
  2804  						OIDCIssuerProfile: &OIDCIssuerProfile{
  2805  							Enabled: ptr.To(true),
  2806  						},
  2807  					},
  2808  				},
  2809  			},
  2810  			wantErr: false,
  2811  		},
  2812  		{
  2813  			name: "AzureManagedControlPlane DNSPrefix is immutable error",
  2814  			oldAMCP: &AzureManagedControlPlane{
  2815  				Spec: AzureManagedControlPlaneSpec{
  2816  					DNSPrefix: ptr.To("capz-aks-1"),
  2817  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2818  						Version: "v1.18.0",
  2819  					},
  2820  				},
  2821  			},
  2822  			amcp: &AzureManagedControlPlane{
  2823  				Spec: AzureManagedControlPlaneSpec{
  2824  					DNSPrefix: ptr.To("capz-aks"),
  2825  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2826  						Version: "v1.18.0",
  2827  					},
  2828  				},
  2829  			},
  2830  			wantErr: true,
  2831  		},
  2832  		{
  2833  			name: "AzureManagedControlPlane DNSPrefix is immutable no error",
  2834  			oldAMCP: &AzureManagedControlPlane{
  2835  				Spec: AzureManagedControlPlaneSpec{
  2836  					DNSPrefix: ptr.To("capz-aks"),
  2837  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2838  						Version: "v1.18.0",
  2839  					},
  2840  				},
  2841  			},
  2842  			amcp: &AzureManagedControlPlane{
  2843  				Spec: AzureManagedControlPlaneSpec{
  2844  					DNSPrefix: ptr.To("capz-aks"),
  2845  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2846  						Version: "v1.18.0",
  2847  					},
  2848  				},
  2849  			},
  2850  			wantErr: false,
  2851  		},
  2852  		{
  2853  			name: "DisableLocalAccounts can be set only for AAD enabled clusters",
  2854  			oldAMCP: &AzureManagedControlPlane{
  2855  				ObjectMeta: metav1.ObjectMeta{
  2856  					Name: "test-cluster",
  2857  				},
  2858  				Spec: AzureManagedControlPlaneSpec{
  2859  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2860  						Version: "v1.18.0",
  2861  						AADProfile: &AADProfile{
  2862  							Managed:             true,
  2863  							AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
  2864  						},
  2865  					},
  2866  				},
  2867  			},
  2868  			amcp: &AzureManagedControlPlane{
  2869  				ObjectMeta: metav1.ObjectMeta{
  2870  					Name: "test-cluster",
  2871  				},
  2872  				Spec: AzureManagedControlPlaneSpec{
  2873  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2874  						Version: "v1.18.0",
  2875  						AADProfile: &AADProfile{
  2876  							Managed:             true,
  2877  							AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
  2878  						},
  2879  						DisableLocalAccounts: ptr.To[bool](true),
  2880  					},
  2881  				},
  2882  			},
  2883  			wantErr: false,
  2884  		},
  2885  		{
  2886  			name: "DisableLocalAccounts cannot be disabled",
  2887  			oldAMCP: &AzureManagedControlPlane{
  2888  				ObjectMeta: metav1.ObjectMeta{
  2889  					Name: "test-cluster",
  2890  				},
  2891  				Spec: AzureManagedControlPlaneSpec{
  2892  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2893  						Version: "v1.18.0",
  2894  						AADProfile: &AADProfile{
  2895  							Managed:             true,
  2896  							AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
  2897  						},
  2898  						DisableLocalAccounts: ptr.To[bool](true),
  2899  					},
  2900  				},
  2901  			},
  2902  			amcp: &AzureManagedControlPlane{
  2903  				ObjectMeta: metav1.ObjectMeta{
  2904  					Name: "test-cluster",
  2905  				},
  2906  				Spec: AzureManagedControlPlaneSpec{
  2907  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2908  						Version: "v1.18.0",
  2909  						AADProfile: &AADProfile{
  2910  							Managed:             true,
  2911  							AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
  2912  						},
  2913  					},
  2914  				},
  2915  			},
  2916  			wantErr: true,
  2917  		},
  2918  		{
  2919  			name: "DisableLocalAccounts cannot be disabled",
  2920  			oldAMCP: &AzureManagedControlPlane{
  2921  				ObjectMeta: metav1.ObjectMeta{
  2922  					Name: "test-cluster",
  2923  				},
  2924  				Spec: AzureManagedControlPlaneSpec{
  2925  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2926  						Version: "v1.18.0",
  2927  						AADProfile: &AADProfile{
  2928  							Managed:             true,
  2929  							AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
  2930  						},
  2931  						DisableLocalAccounts: ptr.To[bool](true),
  2932  					},
  2933  				},
  2934  			},
  2935  			amcp: &AzureManagedControlPlane{
  2936  				ObjectMeta: metav1.ObjectMeta{
  2937  					Name: "test-cluster",
  2938  				},
  2939  				Spec: AzureManagedControlPlaneSpec{
  2940  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2941  						Version: "v1.18.0",
  2942  						AADProfile: &AADProfile{
  2943  							Managed:             true,
  2944  							AdminGroupObjectIDs: []string{"00000000-0000-0000-0000-000000000000"},
  2945  						},
  2946  						DisableLocalAccounts: ptr.To[bool](false),
  2947  					},
  2948  				},
  2949  			},
  2950  			wantErr: true,
  2951  		},
  2952  		{
  2953  			name: "AzureManagedControlPlane DNSPrefix is immutable error nil -> capz-aks",
  2954  			oldAMCP: &AzureManagedControlPlane{
  2955  				Spec: AzureManagedControlPlaneSpec{
  2956  					DNSPrefix: nil,
  2957  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2958  						Version: "v1.18.0",
  2959  					},
  2960  				},
  2961  			},
  2962  			amcp: &AzureManagedControlPlane{
  2963  				Spec: AzureManagedControlPlaneSpec{
  2964  					DNSPrefix: ptr.To("capz-aks"),
  2965  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2966  						Version: "v1.18.0",
  2967  					},
  2968  				},
  2969  			},
  2970  			wantErr: true,
  2971  		},
  2972  		{
  2973  			name: "AzureManagedControlPlane DNSPrefix can be updated from nil when resource name matches",
  2974  			oldAMCP: &AzureManagedControlPlane{
  2975  				ObjectMeta: metav1.ObjectMeta{
  2976  					Name: "capz-aks",
  2977  				},
  2978  				Spec: AzureManagedControlPlaneSpec{
  2979  					DNSPrefix: nil,
  2980  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2981  						Version: "v1.18.0",
  2982  					},
  2983  				},
  2984  			},
  2985  			amcp: &AzureManagedControlPlane{
  2986  				Spec: AzureManagedControlPlaneSpec{
  2987  					DNSPrefix: ptr.To("capz-aks"),
  2988  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  2989  						Version: "v1.18.0",
  2990  					},
  2991  				},
  2992  			},
  2993  			wantErr: false,
  2994  		},
  2995  		{
  2996  			name: "DisableLocalAccounts cannot be set for non AAD clusters",
  2997  			oldAMCP: &AzureManagedControlPlane{
  2998  				ObjectMeta: metav1.ObjectMeta{
  2999  					Name: "test-cluster",
  3000  				},
  3001  				Spec: AzureManagedControlPlaneSpec{
  3002  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3003  						Version: "v1.18.0",
  3004  					},
  3005  				},
  3006  			},
  3007  			amcp: &AzureManagedControlPlane{
  3008  				ObjectMeta: metav1.ObjectMeta{
  3009  					Name: "test-cluster",
  3010  				},
  3011  				Spec: AzureManagedControlPlaneSpec{
  3012  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3013  						Version:              "v1.18.0",
  3014  						DisableLocalAccounts: ptr.To[bool](true),
  3015  					},
  3016  				},
  3017  			},
  3018  			wantErr: true,
  3019  		},
  3020  		{
  3021  			name: "AzureManagedControlPlane DNSPrefix is immutable error nil -> empty",
  3022  			oldAMCP: &AzureManagedControlPlane{
  3023  				Spec: AzureManagedControlPlaneSpec{
  3024  					DNSPrefix: nil,
  3025  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3026  						Version: "v1.18.0",
  3027  					},
  3028  				},
  3029  			},
  3030  			amcp: &AzureManagedControlPlane{
  3031  				Spec: AzureManagedControlPlaneSpec{
  3032  					DNSPrefix: ptr.To(""),
  3033  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3034  						Version: "v1.18.0",
  3035  					},
  3036  				},
  3037  			},
  3038  			wantErr: true,
  3039  		},
  3040  		{
  3041  			name: "AzureManagedControlPlane DNSPrefix is immutable no error nil -> nil",
  3042  			oldAMCP: &AzureManagedControlPlane{
  3043  				Spec: AzureManagedControlPlaneSpec{
  3044  					DNSPrefix: nil,
  3045  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3046  						Version: "v1.18.0",
  3047  					},
  3048  				},
  3049  			},
  3050  			amcp: &AzureManagedControlPlane{
  3051  				Spec: AzureManagedControlPlaneSpec{
  3052  					DNSPrefix: nil,
  3053  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3054  						Version: "v1.18.0",
  3055  					},
  3056  				},
  3057  			},
  3058  			wantErr: false,
  3059  		},
  3060  		{
  3061  			name: "AzureManagedControlPlane AKSExtensions ConfigurationSettings and AutoUpgradeMinorVersion are mutable",
  3062  			oldAMCP: &AzureManagedControlPlane{
  3063  				Spec: AzureManagedControlPlaneSpec{
  3064  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3065  						Version: "v1.18.0",
  3066  						Extensions: []AKSExtension{
  3067  							{
  3068  								Name:                    "extension1",
  3069  								AutoUpgradeMinorVersion: ptr.To(false),
  3070  								ConfigurationSettings: map[string]string{
  3071  									"key1": "value1",
  3072  								},
  3073  								Plan: &ExtensionPlan{
  3074  									Name:      "planName",
  3075  									Product:   "planProduct",
  3076  									Publisher: "planPublisher",
  3077  								},
  3078  							},
  3079  						},
  3080  					},
  3081  				},
  3082  			},
  3083  			amcp: &AzureManagedControlPlane{
  3084  				Spec: AzureManagedControlPlaneSpec{
  3085  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3086  						Version: "v1.18.0",
  3087  						Extensions: []AKSExtension{
  3088  							{
  3089  								Name:                    "extension1",
  3090  								AutoUpgradeMinorVersion: ptr.To(true),
  3091  								ConfigurationSettings: map[string]string{
  3092  									"key1": "value1",
  3093  									"key2": "value2",
  3094  								},
  3095  								Plan: &ExtensionPlan{
  3096  									Name:      "planName",
  3097  									Product:   "planProduct",
  3098  									Publisher: "planPublisher",
  3099  								},
  3100  							},
  3101  						},
  3102  					},
  3103  				},
  3104  			},
  3105  			wantErr: false,
  3106  		},
  3107  		{
  3108  			name: "AzureManagedControlPlane all other fields are immutable",
  3109  			oldAMCP: &AzureManagedControlPlane{
  3110  				Spec: AzureManagedControlPlaneSpec{
  3111  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3112  						Version: "v1.18.0",
  3113  						Extensions: []AKSExtension{
  3114  							{
  3115  								Name:                    "extension1",
  3116  								AKSAssignedIdentityType: AKSAssignedIdentitySystemAssigned,
  3117  								ExtensionType:           ptr.To("extensionType"),
  3118  								Plan: &ExtensionPlan{
  3119  									Name:      "planName",
  3120  									Product:   "planProduct",
  3121  									Publisher: "planPublisher",
  3122  								},
  3123  								Scope: &ExtensionScope{
  3124  									ScopeType:        "Cluster",
  3125  									ReleaseNamespace: "default",
  3126  								},
  3127  								ReleaseTrain: ptr.To("releaseTrain"),
  3128  								Version:      ptr.To("v1.0.0"),
  3129  							},
  3130  						},
  3131  					},
  3132  				},
  3133  			},
  3134  			amcp: &AzureManagedControlPlane{
  3135  				Spec: AzureManagedControlPlaneSpec{
  3136  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3137  						Version: "v1.18.0",
  3138  						Extensions: []AKSExtension{
  3139  							{
  3140  								Name:                    "extension2",
  3141  								AKSAssignedIdentityType: AKSAssignedIdentityUserAssigned,
  3142  								ExtensionType:           ptr.To("extensionType1"),
  3143  								Plan: &ExtensionPlan{
  3144  									Name:      "planName1",
  3145  									Product:   "planProduct1",
  3146  									Publisher: "planPublisher1",
  3147  								},
  3148  								Scope: &ExtensionScope{
  3149  									ScopeType:        "Namespace",
  3150  									ReleaseNamespace: "default",
  3151  								},
  3152  								ReleaseTrain: ptr.To("releaseTrain1"),
  3153  								Version:      ptr.To("v1.1.0"),
  3154  							},
  3155  						},
  3156  					},
  3157  				},
  3158  			},
  3159  			wantErr: true,
  3160  		},
  3161  	}
  3162  	client := mockClient{ReturnError: false}
  3163  	for _, tc := range tests {
  3164  		t.Run(tc.name, func(t *testing.T) {
  3165  			g := NewWithT(t)
  3166  			mcpw := &azureManagedControlPlaneWebhook{
  3167  				Client: client,
  3168  			}
  3169  			_, err := mcpw.ValidateUpdate(context.Background(), tc.oldAMCP, tc.amcp)
  3170  			if tc.wantErr {
  3171  				g.Expect(err).To(HaveOccurred())
  3172  			} else {
  3173  				g.Expect(err).NotTo(HaveOccurred())
  3174  			}
  3175  		})
  3176  	}
  3177  }
  3178  
  3179  func createAzureManagedControlPlane(serviceIP, version, sshKey string) *AzureManagedControlPlane {
  3180  	return &AzureManagedControlPlane{
  3181  		ObjectMeta: getAMCPMetaData(),
  3182  		Spec: AzureManagedControlPlaneSpec{
  3183  			SSHPublicKey: &sshKey,
  3184  			AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3185  				DNSServiceIP: ptr.To(serviceIP),
  3186  				Version:      version,
  3187  			},
  3188  		},
  3189  	}
  3190  }
  3191  
  3192  func getKnownValidAzureManagedControlPlane() *AzureManagedControlPlane {
  3193  	return &AzureManagedControlPlane{
  3194  		ObjectMeta: getAMCPMetaData(),
  3195  		Spec: AzureManagedControlPlaneSpec{
  3196  			AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3197  				DNSServiceIP: ptr.To("192.168.0.10"),
  3198  				Version:      "v1.18.0",
  3199  				AADProfile: &AADProfile{
  3200  					Managed: true,
  3201  					AdminGroupObjectIDs: []string{
  3202  						"616077a8-5db7-4c98-b856-b34619afg75h",
  3203  					},
  3204  				},
  3205  			},
  3206  			SSHPublicKey: ptr.To(generateSSHPublicKey(true)),
  3207  		},
  3208  	}
  3209  }
  3210  
  3211  func getAMCPMetaData() metav1.ObjectMeta {
  3212  	return metav1.ObjectMeta{
  3213  		Name: "test-AMCP",
  3214  		Labels: map[string]string{
  3215  			"cluster.x-k8s.io/cluster-name": "test-cluster",
  3216  		},
  3217  		Namespace: "default",
  3218  	}
  3219  }
  3220  
  3221  func TestAzureManagedClusterSecurityProfileValidateCreate(t *testing.T) {
  3222  	defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, capifeature.MachinePool, true)()
  3223  	testsCreate := []struct {
  3224  		name    string
  3225  		amcp    *AzureManagedControlPlane
  3226  		wantErr string
  3227  	}{
  3228  		{
  3229  			name: "Cannot enable Workload Identity without enabling OIDC issuer",
  3230  			amcp: &AzureManagedControlPlane{
  3231  				Spec: AzureManagedControlPlaneSpec{
  3232  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3233  						Version: "v1.17.8",
  3234  						SecurityProfile: &ManagedClusterSecurityProfile{
  3235  							WorkloadIdentity: &ManagedClusterSecurityProfileWorkloadIdentity{
  3236  								Enabled: true,
  3237  							},
  3238  						},
  3239  					},
  3240  				},
  3241  			},
  3242  			wantErr: "Spec.SecurityProfile.WorkloadIdentity: Invalid value: v1beta1.ManagedClusterSecurityProfileWorkloadIdentity{Enabled:true}: Spec.SecurityProfile.WorkloadIdentity cannot be enabled when Spec.OIDCIssuerProfile is disabled",
  3243  		},
  3244  		{
  3245  			name: "Cannot enable AzureKms without user assigned identity",
  3246  			amcp: &AzureManagedControlPlane{
  3247  				Spec: AzureManagedControlPlaneSpec{
  3248  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3249  						Version: "v1.17.8",
  3250  						SecurityProfile: &ManagedClusterSecurityProfile{
  3251  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3252  								Enabled: true,
  3253  							},
  3254  						},
  3255  					},
  3256  				},
  3257  			},
  3258  			wantErr: "Spec.SecurityProfile.AzureKeyVaultKms.KeyVaultResourceID: Invalid value: \"null\": Spec.SecurityProfile.AzureKeyVaultKms can be set only when Spec.Identity.Type is UserAssigned",
  3259  		},
  3260  		{
  3261  			name: "When AzureKms.KeyVaultNetworkAccess is private AzureKeyVaultKms.KeyVaultResourceID cannot be empty",
  3262  			amcp: &AzureManagedControlPlane{
  3263  				Spec: AzureManagedControlPlaneSpec{
  3264  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3265  						Identity: &Identity{
  3266  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3267  							UserAssignedIdentityResourceID: "not empty",
  3268  						},
  3269  						Version: "v1.17.8",
  3270  						SecurityProfile: &ManagedClusterSecurityProfile{
  3271  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3272  								Enabled:               true,
  3273  								KeyID:                 "not empty",
  3274  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPrivate),
  3275  							},
  3276  						},
  3277  					},
  3278  				},
  3279  			},
  3280  			wantErr: "Spec.SecurityProfile.AzureKeyVaultKms.KeyVaultResourceID: Invalid value: \"null\": Spec.SecurityProfile.AzureKeyVaultKms.KeyVaultResourceID cannot be empty when Spec.SecurityProfile.AzureKeyVaultKms.KeyVaultNetworkAccess is Private",
  3281  		},
  3282  		{
  3283  			name: "When AzureKms.KeyVaultNetworkAccess is public AzureKeyVaultKms.KeyVaultResourceID should be empty",
  3284  			amcp: &AzureManagedControlPlane{
  3285  				Spec: AzureManagedControlPlaneSpec{
  3286  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3287  						Version: "v1.17.8",
  3288  						Identity: &Identity{
  3289  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3290  							UserAssignedIdentityResourceID: "not empty",
  3291  						},
  3292  						SecurityProfile: &ManagedClusterSecurityProfile{
  3293  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3294  								Enabled:               true,
  3295  								KeyID:                 "not empty",
  3296  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPublic),
  3297  								KeyVaultResourceID:    ptr.To("not empty"),
  3298  							},
  3299  						},
  3300  					},
  3301  				},
  3302  			},
  3303  			wantErr: "Spec.SecurityProfile.AzureKeyVaultKms.KeyVaultResourceID: Invalid value: \"not empty\": Spec.SecurityProfile.AzureKeyVaultKms.KeyVaultResourceID should be empty when Spec.SecurityProfile.AzureKeyVaultKms.KeyVaultNetworkAccess is Public",
  3304  		},
  3305  		{
  3306  			name: "Valid profile",
  3307  			amcp: &AzureManagedControlPlane{
  3308  				Spec: AzureManagedControlPlaneSpec{
  3309  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3310  						Version: "v1.17.8",
  3311  						Identity: &Identity{
  3312  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3313  							UserAssignedIdentityResourceID: "not empty",
  3314  						},
  3315  						OIDCIssuerProfile: &OIDCIssuerProfile{
  3316  							Enabled: ptr.To(true),
  3317  						},
  3318  						SecurityProfile: &ManagedClusterSecurityProfile{
  3319  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3320  								Enabled:               true,
  3321  								KeyID:                 "not empty",
  3322  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPublic),
  3323  							},
  3324  							Defender: &ManagedClusterSecurityProfileDefender{
  3325  								LogAnalyticsWorkspaceResourceID: "not empty",
  3326  								SecurityMonitoring: ManagedClusterSecurityProfileDefenderSecurityMonitoring{
  3327  									Enabled: true,
  3328  								},
  3329  							},
  3330  							WorkloadIdentity: &ManagedClusterSecurityProfileWorkloadIdentity{
  3331  								Enabled: true,
  3332  							},
  3333  							ImageCleaner: &ManagedClusterSecurityProfileImageCleaner{
  3334  								Enabled:       true,
  3335  								IntervalHours: ptr.To(24),
  3336  							},
  3337  						},
  3338  					},
  3339  				},
  3340  			},
  3341  			wantErr: "",
  3342  		},
  3343  	}
  3344  	client := mockClient{ReturnError: false}
  3345  	for _, tc := range testsCreate {
  3346  		t.Run(tc.name, func(t *testing.T) {
  3347  			g := NewWithT(t)
  3348  			mcpw := &azureManagedControlPlaneWebhook{
  3349  				Client: client,
  3350  			}
  3351  			_, err := mcpw.ValidateCreate(context.Background(), tc.amcp)
  3352  			if tc.wantErr != "" {
  3353  				g.Expect(err).To(HaveOccurred())
  3354  				g.Expect(err.Error()).To(Equal(tc.wantErr))
  3355  			} else {
  3356  				g.Expect(err).NotTo(HaveOccurred())
  3357  			}
  3358  		})
  3359  	}
  3360  }
  3361  
  3362  func TestAzureClusterSecurityProfileValidateUpdate(t *testing.T) {
  3363  	tests := []struct {
  3364  		name    string
  3365  		oldAMCP *AzureManagedControlPlane
  3366  		amcp    *AzureManagedControlPlane
  3367  		wantErr string
  3368  	}{
  3369  		{
  3370  			name: "AzureManagedControlPlane SecurityProfile.Defender is mutable",
  3371  			oldAMCP: &AzureManagedControlPlane{
  3372  				Spec: AzureManagedControlPlaneSpec{
  3373  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3374  						Version: "v1.18.0",
  3375  					},
  3376  				},
  3377  			},
  3378  			amcp: &AzureManagedControlPlane{
  3379  				Spec: AzureManagedControlPlaneSpec{
  3380  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3381  						Version: "v1.18.0",
  3382  						SecurityProfile: &ManagedClusterSecurityProfile{
  3383  							Defender: &ManagedClusterSecurityProfileDefender{
  3384  								LogAnalyticsWorkspaceResourceID: "0000-0000-0000-0000",
  3385  								SecurityMonitoring: ManagedClusterSecurityProfileDefenderSecurityMonitoring{
  3386  									Enabled: true,
  3387  								},
  3388  							},
  3389  						},
  3390  					},
  3391  				},
  3392  			},
  3393  			wantErr: "",
  3394  		},
  3395  		{
  3396  			name: "AzureManagedControlPlane SecurityProfile.Defender is mutable and cannot be unset",
  3397  			oldAMCP: &AzureManagedControlPlane{
  3398  				Spec: AzureManagedControlPlaneSpec{
  3399  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3400  						Version: "v1.18.0",
  3401  						SecurityProfile: &ManagedClusterSecurityProfile{
  3402  							Defender: &ManagedClusterSecurityProfileDefender{
  3403  								LogAnalyticsWorkspaceResourceID: "0000-0000-0000-0000",
  3404  								SecurityMonitoring: ManagedClusterSecurityProfileDefenderSecurityMonitoring{
  3405  									Enabled: true,
  3406  								},
  3407  							},
  3408  						},
  3409  					},
  3410  				},
  3411  			},
  3412  			amcp: &AzureManagedControlPlane{
  3413  				Spec: AzureManagedControlPlaneSpec{
  3414  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3415  						Version: "v1.18.0",
  3416  					},
  3417  				},
  3418  			},
  3419  			wantErr: "AzureManagedControlPlane.infrastructure.cluster.x-k8s.io \"\" is invalid: Spec.SecurityProfile.Defender: Invalid value: \"null\": cannot unset Spec.SecurityProfile.Defender, to disable defender please set Spec.SecurityProfile.Defender.SecurityMonitoring.Enabled to false",
  3420  		},
  3421  		{
  3422  			name: "AzureManagedControlPlane SecurityProfile.Defender is mutable and can be disabled",
  3423  			oldAMCP: &AzureManagedControlPlane{
  3424  				Spec: AzureManagedControlPlaneSpec{
  3425  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3426  						Version: "v1.18.0",
  3427  						SecurityProfile: &ManagedClusterSecurityProfile{
  3428  							Defender: &ManagedClusterSecurityProfileDefender{
  3429  								LogAnalyticsWorkspaceResourceID: "0000-0000-0000-0000",
  3430  								SecurityMonitoring: ManagedClusterSecurityProfileDefenderSecurityMonitoring{
  3431  									Enabled: true,
  3432  								},
  3433  							},
  3434  						},
  3435  					},
  3436  				},
  3437  			},
  3438  			amcp: &AzureManagedControlPlane{
  3439  				Spec: AzureManagedControlPlaneSpec{
  3440  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3441  						Version: "v1.18.0",
  3442  						SecurityProfile: &ManagedClusterSecurityProfile{
  3443  							Defender: &ManagedClusterSecurityProfileDefender{
  3444  								LogAnalyticsWorkspaceResourceID: "0000-0000-0000-0000",
  3445  								SecurityMonitoring: ManagedClusterSecurityProfileDefenderSecurityMonitoring{
  3446  									Enabled: false,
  3447  								},
  3448  							},
  3449  						},
  3450  					},
  3451  				},
  3452  			},
  3453  			wantErr: "",
  3454  		},
  3455  		{
  3456  			name: "AzureManagedControlPlane SecurityProfile.WorkloadIdentity is mutable",
  3457  			oldAMCP: &AzureManagedControlPlane{
  3458  				Spec: AzureManagedControlPlaneSpec{
  3459  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3460  						Version: "v1.18.0",
  3461  					},
  3462  				},
  3463  			},
  3464  			amcp: &AzureManagedControlPlane{
  3465  				Spec: AzureManagedControlPlaneSpec{
  3466  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3467  						Version: "v1.18.0",
  3468  						OIDCIssuerProfile: &OIDCIssuerProfile{
  3469  							Enabled: ptr.To(true),
  3470  						},
  3471  						SecurityProfile: &ManagedClusterSecurityProfile{
  3472  							WorkloadIdentity: &ManagedClusterSecurityProfileWorkloadIdentity{
  3473  								Enabled: true,
  3474  							},
  3475  						},
  3476  					},
  3477  				},
  3478  			},
  3479  			wantErr: "",
  3480  		},
  3481  		{
  3482  			name: "AzureManagedControlPlane SecurityProfile.WorkloadIdentity cannot be enabled without OIDC issuer",
  3483  			oldAMCP: &AzureManagedControlPlane{
  3484  				Spec: AzureManagedControlPlaneSpec{
  3485  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3486  						Version: "v1.18.0",
  3487  					},
  3488  				},
  3489  			},
  3490  			amcp: &AzureManagedControlPlane{
  3491  				Spec: AzureManagedControlPlaneSpec{
  3492  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3493  						Version: "v1.18.0",
  3494  						SecurityProfile: &ManagedClusterSecurityProfile{
  3495  							WorkloadIdentity: &ManagedClusterSecurityProfileWorkloadIdentity{
  3496  								Enabled: true,
  3497  							},
  3498  						},
  3499  					},
  3500  				},
  3501  			},
  3502  			wantErr: "Spec.SecurityProfile.WorkloadIdentity: Invalid value: v1beta1.ManagedClusterSecurityProfileWorkloadIdentity{Enabled:true}: Spec.SecurityProfile.WorkloadIdentity cannot be enabled when Spec.OIDCIssuerProfile is disabled",
  3503  		},
  3504  		{
  3505  			name: "AzureManagedControlPlane SecurityProfile.WorkloadIdentity cannot unset values",
  3506  			oldAMCP: &AzureManagedControlPlane{
  3507  				Spec: AzureManagedControlPlaneSpec{
  3508  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3509  						Version: "v1.18.0",
  3510  						OIDCIssuerProfile: &OIDCIssuerProfile{
  3511  							Enabled: ptr.To(true),
  3512  						},
  3513  						SecurityProfile: &ManagedClusterSecurityProfile{
  3514  							WorkloadIdentity: &ManagedClusterSecurityProfileWorkloadIdentity{
  3515  								Enabled: true,
  3516  							},
  3517  						},
  3518  					},
  3519  				},
  3520  			},
  3521  			amcp: &AzureManagedControlPlane{
  3522  				Spec: AzureManagedControlPlaneSpec{
  3523  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3524  						Version: "v1.18.0",
  3525  						OIDCIssuerProfile: &OIDCIssuerProfile{
  3526  							Enabled: ptr.To(true),
  3527  						},
  3528  					},
  3529  				},
  3530  			},
  3531  			wantErr: "AzureManagedControlPlane.infrastructure.cluster.x-k8s.io \"\" is invalid: Spec.SecurityProfile.WorkloadIdentity: Invalid value: \"null\": cannot unset Spec.SecurityProfile.WorkloadIdentity, to disable workloadIdentity please set Spec.SecurityProfile.WorkloadIdentity.Enabled to false",
  3532  		},
  3533  		{
  3534  			name: "AzureManagedControlPlane SecurityProfile.WorkloadIdentity can be disabled",
  3535  			oldAMCP: &AzureManagedControlPlane{
  3536  				Spec: AzureManagedControlPlaneSpec{
  3537  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3538  						Version: "v1.18.0",
  3539  						OIDCIssuerProfile: &OIDCIssuerProfile{
  3540  							Enabled: ptr.To(true),
  3541  						},
  3542  						SecurityProfile: &ManagedClusterSecurityProfile{
  3543  							WorkloadIdentity: &ManagedClusterSecurityProfileWorkloadIdentity{
  3544  								Enabled: true,
  3545  							},
  3546  						},
  3547  					},
  3548  				},
  3549  			},
  3550  			amcp: &AzureManagedControlPlane{
  3551  				Spec: AzureManagedControlPlaneSpec{
  3552  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3553  						Version: "v1.18.0",
  3554  						OIDCIssuerProfile: &OIDCIssuerProfile{
  3555  							Enabled: ptr.To(true),
  3556  						},
  3557  						SecurityProfile: &ManagedClusterSecurityProfile{
  3558  							WorkloadIdentity: &ManagedClusterSecurityProfileWorkloadIdentity{
  3559  								Enabled: false,
  3560  							},
  3561  						},
  3562  					},
  3563  				},
  3564  			},
  3565  			wantErr: "",
  3566  		},
  3567  		{
  3568  			name: "AzureManagedControlPlane SecurityProfile.AzureKeyVaultKms is mutable",
  3569  			oldAMCP: &AzureManagedControlPlane{
  3570  				Spec: AzureManagedControlPlaneSpec{
  3571  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3572  						Version: "v1.18.0",
  3573  					},
  3574  				},
  3575  			},
  3576  			amcp: &AzureManagedControlPlane{
  3577  				Spec: AzureManagedControlPlaneSpec{
  3578  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3579  						Version: "v1.18.0",
  3580  						Identity: &Identity{
  3581  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3582  							UserAssignedIdentityResourceID: "not empty",
  3583  						},
  3584  						SecurityProfile: &ManagedClusterSecurityProfile{
  3585  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3586  								Enabled:               true,
  3587  								KeyID:                 "0000-0000-0000-0000",
  3588  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPrivate),
  3589  								KeyVaultResourceID:    ptr.To("0000-0000-0000-0000"),
  3590  							},
  3591  						},
  3592  					},
  3593  				},
  3594  			},
  3595  			wantErr: "",
  3596  		},
  3597  		{
  3598  			name: "AzureManagedControlPlane SecurityProfile.AzureKeyVaultKms.KeyVaultNetworkAccess can be updated when KMS is enabled",
  3599  			oldAMCP: &AzureManagedControlPlane{
  3600  				Spec: AzureManagedControlPlaneSpec{
  3601  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3602  						Version: "v1.18.0",
  3603  						Identity: &Identity{
  3604  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3605  							UserAssignedIdentityResourceID: "not empty",
  3606  						},
  3607  						SecurityProfile: &ManagedClusterSecurityProfile{
  3608  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3609  								Enabled:               true,
  3610  								KeyID:                 "0000-0000-0000-0000",
  3611  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPublic),
  3612  							},
  3613  						},
  3614  					},
  3615  				},
  3616  			},
  3617  			amcp: &AzureManagedControlPlane{
  3618  				Spec: AzureManagedControlPlaneSpec{
  3619  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3620  						Version: "v1.18.0",
  3621  						Identity: &Identity{
  3622  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3623  							UserAssignedIdentityResourceID: "not empty",
  3624  						},
  3625  						SecurityProfile: &ManagedClusterSecurityProfile{
  3626  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3627  								Enabled:               true,
  3628  								KeyID:                 "0000-0000-0000-0000",
  3629  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPrivate),
  3630  								KeyVaultResourceID:    ptr.To("0000-0000-0000-0000"),
  3631  							},
  3632  						},
  3633  					},
  3634  				},
  3635  			},
  3636  			wantErr: "",
  3637  		},
  3638  		{
  3639  			name: "AzureManagedControlPlane SecurityProfile.AzureKeyVaultKms.Enabled can be disabled",
  3640  			oldAMCP: &AzureManagedControlPlane{
  3641  				Spec: AzureManagedControlPlaneSpec{
  3642  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3643  						Version: "v1.18.0",
  3644  						Identity: &Identity{
  3645  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3646  							UserAssignedIdentityResourceID: "not empty",
  3647  						},
  3648  						SecurityProfile: &ManagedClusterSecurityProfile{
  3649  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3650  								Enabled:               true,
  3651  								KeyID:                 "0000-0000-0000-0000",
  3652  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPublic),
  3653  							},
  3654  						},
  3655  					},
  3656  				},
  3657  			},
  3658  			amcp: &AzureManagedControlPlane{
  3659  				Spec: AzureManagedControlPlaneSpec{
  3660  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3661  						Version: "v1.18.0",
  3662  						Identity: &Identity{
  3663  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3664  							UserAssignedIdentityResourceID: "not empty",
  3665  						},
  3666  						SecurityProfile: &ManagedClusterSecurityProfile{
  3667  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3668  								Enabled:               false,
  3669  								KeyID:                 "0000-0000-0000-0000",
  3670  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPublic),
  3671  							},
  3672  						},
  3673  					},
  3674  				},
  3675  			},
  3676  			wantErr: "",
  3677  		},
  3678  		{
  3679  			name: "AzureManagedControlPlane SecurityProfile.AzureKeyVaultKms cannot unset",
  3680  			oldAMCP: &AzureManagedControlPlane{
  3681  				Spec: AzureManagedControlPlaneSpec{
  3682  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3683  						Version: "v1.18.0",
  3684  						Identity: &Identity{
  3685  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3686  							UserAssignedIdentityResourceID: "not empty",
  3687  						},
  3688  						SecurityProfile: &ManagedClusterSecurityProfile{
  3689  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3690  								Enabled:               true,
  3691  								KeyID:                 "0000-0000-0000-0000",
  3692  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPublic),
  3693  							},
  3694  						},
  3695  					},
  3696  				},
  3697  			},
  3698  			amcp: &AzureManagedControlPlane{
  3699  				Spec: AzureManagedControlPlaneSpec{
  3700  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3701  						Version: "v1.18.0",
  3702  						Identity: &Identity{
  3703  							Type:                           ManagedControlPlaneIdentityTypeUserAssigned,
  3704  							UserAssignedIdentityResourceID: "not empty",
  3705  						},
  3706  					},
  3707  				},
  3708  			},
  3709  			wantErr: "AzureManagedControlPlane.infrastructure.cluster.x-k8s.io \"\" is invalid: Spec.SecurityProfile.AzureKeyVaultKms: Invalid value: \"null\": cannot unset Spec.SecurityProfile.AzureKeyVaultKms profile to disable the profile please set Spec.SecurityProfile.AzureKeyVaultKms.Enabled to false",
  3710  		},
  3711  		{
  3712  			name: "AzureManagedControlPlane SecurityProfile.AzureKeyVaultKms cannot be enabled without UserAssigned Identity",
  3713  			oldAMCP: &AzureManagedControlPlane{
  3714  				Spec: AzureManagedControlPlaneSpec{
  3715  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3716  						Version: "v1.18.0",
  3717  					},
  3718  				},
  3719  			},
  3720  			amcp: &AzureManagedControlPlane{
  3721  				Spec: AzureManagedControlPlaneSpec{
  3722  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3723  						Version: "v1.18.0",
  3724  						SecurityProfile: &ManagedClusterSecurityProfile{
  3725  							AzureKeyVaultKms: &AzureKeyVaultKms{
  3726  								Enabled:               true,
  3727  								KeyID:                 "0000-0000-0000-0000",
  3728  								KeyVaultNetworkAccess: ptr.To(KeyVaultNetworkAccessTypesPrivate),
  3729  								KeyVaultResourceID:    ptr.To("0000-0000-0000-0000"),
  3730  							},
  3731  						},
  3732  					},
  3733  				},
  3734  			},
  3735  			wantErr: "Spec.SecurityProfile.AzureKeyVaultKms.KeyVaultResourceID: Invalid value: \"0000-0000-0000-0000\": Spec.SecurityProfile.AzureKeyVaultKms can be set only when Spec.Identity.Type is UserAssigned",
  3736  		},
  3737  		{
  3738  			name: "AzureManagedControlPlane SecurityProfile.ImageCleaner is mutable",
  3739  			oldAMCP: &AzureManagedControlPlane{
  3740  				Spec: AzureManagedControlPlaneSpec{
  3741  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3742  						Version: "v1.18.0",
  3743  					},
  3744  				},
  3745  			},
  3746  			amcp: &AzureManagedControlPlane{
  3747  				Spec: AzureManagedControlPlaneSpec{
  3748  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3749  						Version: "v1.18.0",
  3750  						SecurityProfile: &ManagedClusterSecurityProfile{
  3751  							ImageCleaner: &ManagedClusterSecurityProfileImageCleaner{
  3752  								Enabled:       true,
  3753  								IntervalHours: ptr.To(28),
  3754  							},
  3755  						},
  3756  					},
  3757  				},
  3758  			},
  3759  			wantErr: "",
  3760  		},
  3761  		{
  3762  			name: "AzureManagedControlPlane SecurityProfile.ImageCleaner cannot be unset",
  3763  			oldAMCP: &AzureManagedControlPlane{
  3764  				Spec: AzureManagedControlPlaneSpec{
  3765  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3766  						Version: "v1.18.0",
  3767  						SecurityProfile: &ManagedClusterSecurityProfile{
  3768  							ImageCleaner: &ManagedClusterSecurityProfileImageCleaner{
  3769  								Enabled:       true,
  3770  								IntervalHours: ptr.To(48),
  3771  							},
  3772  						},
  3773  					},
  3774  				},
  3775  			},
  3776  			amcp: &AzureManagedControlPlane{
  3777  				Spec: AzureManagedControlPlaneSpec{
  3778  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3779  						Version:         "v1.18.0",
  3780  						SecurityProfile: &ManagedClusterSecurityProfile{},
  3781  					},
  3782  				},
  3783  			},
  3784  			wantErr: "AzureManagedControlPlane.infrastructure.cluster.x-k8s.io \"\" is invalid: Spec.SecurityProfile.ImageCleaner: Invalid value: \"null\": cannot unset Spec.SecurityProfile.ImageCleaner, to disable imageCleaner please set Spec.SecurityProfile.ImageCleaner.Enabled to false",
  3785  		},
  3786  		{
  3787  			name: "AzureManagedControlPlane SecurityProfile.ImageCleaner is mutable",
  3788  			oldAMCP: &AzureManagedControlPlane{
  3789  				Spec: AzureManagedControlPlaneSpec{
  3790  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3791  						Version: "v1.18.0",
  3792  						SecurityProfile: &ManagedClusterSecurityProfile{
  3793  							ImageCleaner: &ManagedClusterSecurityProfileImageCleaner{
  3794  								Enabled: true,
  3795  							},
  3796  						},
  3797  					},
  3798  				},
  3799  			},
  3800  			amcp: &AzureManagedControlPlane{
  3801  				Spec: AzureManagedControlPlaneSpec{
  3802  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3803  						Version: "v1.18.0",
  3804  						SecurityProfile: &ManagedClusterSecurityProfile{
  3805  							ImageCleaner: &ManagedClusterSecurityProfileImageCleaner{
  3806  								IntervalHours: ptr.To(48),
  3807  							},
  3808  						},
  3809  					},
  3810  				},
  3811  			},
  3812  			wantErr: "",
  3813  		},
  3814  		{
  3815  			name: "AzureManagedControlPlane SecurityProfile.ImageCleaner can be disabled",
  3816  			oldAMCP: &AzureManagedControlPlane{
  3817  				Spec: AzureManagedControlPlaneSpec{
  3818  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3819  						Version: "v1.18.0",
  3820  						SecurityProfile: &ManagedClusterSecurityProfile{
  3821  							ImageCleaner: &ManagedClusterSecurityProfileImageCleaner{
  3822  								Enabled:       true,
  3823  								IntervalHours: ptr.To(48),
  3824  							},
  3825  						},
  3826  					},
  3827  				},
  3828  			},
  3829  			amcp: &AzureManagedControlPlane{
  3830  				Spec: AzureManagedControlPlaneSpec{
  3831  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  3832  						Version: "v1.18.0",
  3833  						SecurityProfile: &ManagedClusterSecurityProfile{
  3834  							ImageCleaner: &ManagedClusterSecurityProfileImageCleaner{
  3835  								Enabled:       false,
  3836  								IntervalHours: ptr.To(36),
  3837  							},
  3838  						},
  3839  					},
  3840  				},
  3841  			},
  3842  			wantErr: "",
  3843  		},
  3844  	}
  3845  	client := mockClient{ReturnError: false}
  3846  	for _, tc := range tests {
  3847  		t.Run(tc.name, func(t *testing.T) {
  3848  			g := NewWithT(t)
  3849  			mcpw := &azureManagedControlPlaneWebhook{
  3850  				Client: client,
  3851  			}
  3852  			_, err := mcpw.ValidateUpdate(context.Background(), tc.oldAMCP, tc.amcp)
  3853  			if tc.wantErr != "" {
  3854  				g.Expect(err).To(HaveOccurred())
  3855  				g.Expect(err.Error()).To(Equal(tc.wantErr))
  3856  			} else {
  3857  				g.Expect(err).NotTo(HaveOccurred())
  3858  			}
  3859  		})
  3860  	}
  3861  }
  3862  
  3863  func TestValidateAPIServerAccessProfile(t *testing.T) {
  3864  	tests := []struct {
  3865  		name      string
  3866  		profile   *APIServerAccessProfile
  3867  		expectErr bool
  3868  	}{
  3869  		{
  3870  			name: "Testing valid PrivateDNSZone:System",
  3871  			profile: &APIServerAccessProfile{
  3872  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3873  					PrivateDNSZone: ptr.To("System"),
  3874  				},
  3875  			},
  3876  			expectErr: false,
  3877  		},
  3878  		{
  3879  			name: "Testing valid PrivateDNSZone:None",
  3880  			profile: &APIServerAccessProfile{
  3881  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3882  					PrivateDNSZone: ptr.To("None"),
  3883  				},
  3884  			},
  3885  			expectErr: false,
  3886  		},
  3887  		{
  3888  			name: "Testing valid PrivateDNSZone:With privatelink region",
  3889  			profile: &APIServerAccessProfile{
  3890  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3891  					EnablePrivateCluster: ptr.To(true),
  3892  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/privatelink.eastus.azmk8s.io"),
  3893  				},
  3894  			},
  3895  			expectErr: false,
  3896  		},
  3897  		{
  3898  			name: "Testing valid PrivateDNSZone:With private region",
  3899  			profile: &APIServerAccessProfile{
  3900  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3901  					EnablePrivateCluster: ptr.To(true),
  3902  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/private.eastus.azmk8s.io"),
  3903  				},
  3904  			},
  3905  			expectErr: false,
  3906  		},
  3907  		{
  3908  			name: "Testing invalid EnablePrivateCluster and valid PrivateDNSZone",
  3909  			profile: &APIServerAccessProfile{
  3910  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3911  					EnablePrivateCluster: ptr.To(false),
  3912  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/private.eastus.azmk8s.io"),
  3913  				},
  3914  			},
  3915  			expectErr: true,
  3916  		},
  3917  		{
  3918  			name: "Testing valid PrivateDNSZone:With privatelink region and sub-region",
  3919  			profile: &APIServerAccessProfile{
  3920  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3921  					EnablePrivateCluster: ptr.To(true),
  3922  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/sublocation2.privatelink.eastus.azmk8s.io"),
  3923  				},
  3924  			},
  3925  			expectErr: false,
  3926  		},
  3927  		{
  3928  			name: "Testing valid PrivateDNSZone:With private region and sub-region",
  3929  			profile: &APIServerAccessProfile{
  3930  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3931  					EnablePrivateCluster: ptr.To(true),
  3932  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/sublocation2.private.eastus.azmk8s.io"),
  3933  				},
  3934  			},
  3935  			expectErr: false,
  3936  		},
  3937  		{
  3938  			name: "Testing invalid PrivateDNSZone: privatelink region: len(sub-region) > 32 characters",
  3939  			profile: &APIServerAccessProfile{
  3940  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3941  					EnablePrivateCluster: ptr.To(true),
  3942  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/thissublocationismorethan32characters.privatelink.eastus.azmk8s.io"),
  3943  				},
  3944  			},
  3945  			expectErr: true,
  3946  		},
  3947  		{
  3948  			name: "Testing invalid PrivateDNSZone: private region: len(sub-region) > 32 characters",
  3949  			profile: &APIServerAccessProfile{
  3950  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3951  					EnablePrivateCluster: ptr.To(true),
  3952  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/thissublocationismorethan32characters.private.eastus.azmk8s.io"),
  3953  				},
  3954  			},
  3955  			expectErr: true,
  3956  		},
  3957  		{
  3958  			name: "Testing invalid PrivateDNSZone: random string",
  3959  			profile: &APIServerAccessProfile{
  3960  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3961  					EnablePrivateCluster: ptr.To(true),
  3962  					PrivateDNSZone:       ptr.To("WrongPrivateDNSZone"),
  3963  				},
  3964  			},
  3965  			expectErr: true,
  3966  		},
  3967  		{
  3968  			name: "Testing invalid PrivateDNSZone: subzone has an invalid char %",
  3969  			profile: &APIServerAccessProfile{
  3970  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3971  					EnablePrivateCluster: ptr.To(true),
  3972  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/subzone%1.privatelink.eastus.azmk8s.io"),
  3973  				},
  3974  			},
  3975  			expectErr: true,
  3976  		},
  3977  		{
  3978  			name: "Testing invalid PrivateDNSZone: subzone has an invalid char _",
  3979  			profile: &APIServerAccessProfile{
  3980  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3981  					EnablePrivateCluster: ptr.To(true),
  3982  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/subzone_1.privatelink.eastus.azmk8s.io"),
  3983  				},
  3984  			},
  3985  			expectErr: true,
  3986  		},
  3987  		{
  3988  			name: "Testing invalid PrivateDNSZone: region has invalid char",
  3989  			profile: &APIServerAccessProfile{
  3990  				APIServerAccessProfileClassSpec: APIServerAccessProfileClassSpec{
  3991  					EnablePrivateCluster: ptr.To(true),
  3992  					PrivateDNSZone:       ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/privateDnsZones/subzone1.privatelink.location@1.azmk8s.io"),
  3993  				},
  3994  			},
  3995  			expectErr: true,
  3996  		},
  3997  	}
  3998  
  3999  	for _, tc := range tests {
  4000  		t.Run(tc.name, func(t *testing.T) {
  4001  			g := NewWithT(t)
  4002  			errs := validateAPIServerAccessProfile(tc.profile, field.NewPath("profile"))
  4003  			if tc.expectErr {
  4004  				g.Expect(errs).To(HaveLen(1))
  4005  			} else {
  4006  				g.Expect(errs).To(BeEmpty())
  4007  			}
  4008  		})
  4009  	}
  4010  }
  4011  
  4012  func TestValidateAMCPVirtualNetwork(t *testing.T) {
  4013  	tests := []struct {
  4014  		name    string
  4015  		amcp    *AzureManagedControlPlane
  4016  		wantErr string
  4017  	}{
  4018  		{
  4019  			name: "Testing valid VirtualNetwork in same resource group",
  4020  			amcp: &AzureManagedControlPlane{
  4021  				ObjectMeta: metav1.ObjectMeta{
  4022  					Name: "fooName",
  4023  					Labels: map[string]string{
  4024  						clusterv1.ClusterNameLabel: "fooCluster",
  4025  					},
  4026  				},
  4027  				Spec: AzureManagedControlPlaneSpec{
  4028  					ResourceGroupName: "rg1",
  4029  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  4030  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  4031  							ResourceGroup: "rg1",
  4032  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  4033  								Name:      "vnet1",
  4034  								CIDRBlock: defaultAKSVnetCIDR,
  4035  								Subnet: ManagedControlPlaneSubnet{
  4036  									Name:      "subnet1",
  4037  									CIDRBlock: defaultAKSNodeSubnetCIDR,
  4038  								},
  4039  							},
  4040  						},
  4041  					},
  4042  				},
  4043  			},
  4044  			wantErr: "",
  4045  		},
  4046  		{
  4047  			name: "Testing valid VirtualNetwork in different resource group",
  4048  			amcp: &AzureManagedControlPlane{
  4049  				ObjectMeta: metav1.ObjectMeta{
  4050  					Name: "fooName",
  4051  					Labels: map[string]string{
  4052  						clusterv1.ClusterNameLabel: "fooCluster",
  4053  					},
  4054  				},
  4055  				Spec: AzureManagedControlPlaneSpec{
  4056  					ResourceGroupName: "rg1",
  4057  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  4058  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  4059  							ResourceGroup: "rg2",
  4060  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  4061  								Name:      "vnet1",
  4062  								CIDRBlock: defaultAKSVnetCIDR,
  4063  								Subnet: ManagedControlPlaneSubnet{
  4064  									Name:      "subnet1",
  4065  									CIDRBlock: defaultAKSNodeSubnetCIDR,
  4066  								},
  4067  							},
  4068  						},
  4069  					},
  4070  				},
  4071  			},
  4072  			wantErr: "",
  4073  		},
  4074  		{
  4075  			name: "Testing invalid VirtualNetwork in different resource group: invalid subnet CIDR",
  4076  			amcp: &AzureManagedControlPlane{
  4077  				ObjectMeta: metav1.ObjectMeta{
  4078  					Name: "fooName",
  4079  					Labels: map[string]string{
  4080  						clusterv1.ClusterNameLabel: "fooCluster",
  4081  					},
  4082  				},
  4083  				Spec: AzureManagedControlPlaneSpec{
  4084  					ResourceGroupName: "rg1",
  4085  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  4086  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  4087  							ResourceGroup: "rg2",
  4088  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  4089  								Name:      "vnet1",
  4090  								CIDRBlock: "10.1.0.0/16",
  4091  								Subnet: ManagedControlPlaneSubnet{
  4092  									Name:      "subnet1",
  4093  									CIDRBlock: "10.0.0.0/24",
  4094  								},
  4095  							},
  4096  						},
  4097  					},
  4098  				},
  4099  			},
  4100  			wantErr: "pre-existing virtual networks CIDR block should contain the subnet CIDR block",
  4101  		},
  4102  		{
  4103  			name: "Testing invalid VirtualNetwork in different resource group: no subnet CIDR",
  4104  			amcp: &AzureManagedControlPlane{
  4105  				ObjectMeta: metav1.ObjectMeta{
  4106  					Name: "fooName",
  4107  					Labels: map[string]string{
  4108  						clusterv1.ClusterNameLabel: "fooCluster",
  4109  					},
  4110  				},
  4111  				Spec: AzureManagedControlPlaneSpec{
  4112  					ResourceGroupName: "rg1",
  4113  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  4114  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  4115  							ResourceGroup: "rg2",
  4116  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  4117  								Name:      "vnet1",
  4118  								CIDRBlock: "10.1.0.0/16",
  4119  								Subnet: ManagedControlPlaneSubnet{
  4120  									Name: "subnet1",
  4121  								},
  4122  							},
  4123  						},
  4124  					},
  4125  				},
  4126  			},
  4127  			wantErr: "pre-existing virtual networks CIDR block should contain the subnet CIDR block",
  4128  		},
  4129  		{
  4130  			name: "Testing invalid VirtualNetwork in different resource group: no VNet CIDR",
  4131  			amcp: &AzureManagedControlPlane{
  4132  				ObjectMeta: metav1.ObjectMeta{
  4133  					Name: "fooName",
  4134  					Labels: map[string]string{
  4135  						clusterv1.ClusterNameLabel: "fooCluster",
  4136  					},
  4137  				},
  4138  				Spec: AzureManagedControlPlaneSpec{
  4139  					ResourceGroupName: "rg1",
  4140  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  4141  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  4142  							ResourceGroup: "rg2",
  4143  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  4144  								Name: "vnet1",
  4145  								Subnet: ManagedControlPlaneSubnet{
  4146  									Name:      "subnet1",
  4147  									CIDRBlock: "11.0.0.0/24",
  4148  								},
  4149  							},
  4150  						},
  4151  					},
  4152  				},
  4153  			},
  4154  			wantErr: "pre-existing virtual networks CIDR block should contain the subnet CIDR block",
  4155  		},
  4156  		{
  4157  			name: "Testing invalid VirtualNetwork in different resource group: invalid VNet CIDR",
  4158  			amcp: &AzureManagedControlPlane{
  4159  				ObjectMeta: metav1.ObjectMeta{
  4160  					Name: "fooName",
  4161  					Labels: map[string]string{
  4162  						clusterv1.ClusterNameLabel: "fooCluster",
  4163  					},
  4164  				},
  4165  				Spec: AzureManagedControlPlaneSpec{
  4166  					ResourceGroupName: "rg1",
  4167  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  4168  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  4169  							ResourceGroup: "rg2",
  4170  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  4171  								Name:      "vnet1",
  4172  								CIDRBlock: "invalid_vnet_CIDR",
  4173  								Subnet: ManagedControlPlaneSubnet{
  4174  									Name:      "subnet1",
  4175  									CIDRBlock: "11.0.0.0/24",
  4176  								},
  4177  							},
  4178  						},
  4179  					},
  4180  				},
  4181  			},
  4182  			wantErr: "pre-existing virtual networks CIDR block is invalid",
  4183  		},
  4184  		{
  4185  			name: "Testing invalid VirtualNetwork in different resource group: invalid Subnet CIDR",
  4186  			amcp: &AzureManagedControlPlane{
  4187  				ObjectMeta: metav1.ObjectMeta{
  4188  					Name: "fooName",
  4189  					Labels: map[string]string{
  4190  						clusterv1.ClusterNameLabel: "fooCluster",
  4191  					},
  4192  				},
  4193  				Spec: AzureManagedControlPlaneSpec{
  4194  					ResourceGroupName: "rg1",
  4195  					AzureManagedControlPlaneClassSpec: AzureManagedControlPlaneClassSpec{
  4196  						VirtualNetwork: ManagedControlPlaneVirtualNetwork{
  4197  							ResourceGroup: "rg2",
  4198  							ManagedControlPlaneVirtualNetworkClassSpec: ManagedControlPlaneVirtualNetworkClassSpec{
  4199  								Name: "vnet1",
  4200  								Subnet: ManagedControlPlaneSubnet{
  4201  									Name:      "subnet1",
  4202  									CIDRBlock: "invalid_subnet_CIDR",
  4203  								},
  4204  							},
  4205  						},
  4206  					},
  4207  				},
  4208  			},
  4209  			wantErr: "pre-existing subnets CIDR block is invalid",
  4210  		},
  4211  	}
  4212  
  4213  	for _, tc := range tests {
  4214  		t.Run(tc.name, func(t *testing.T) {
  4215  			g := NewWithT(t)
  4216  			mcpw := &azureManagedControlPlaneWebhook{}
  4217  			err := mcpw.Default(context.Background(), tc.amcp)
  4218  			g.Expect(err).NotTo(HaveOccurred())
  4219  
  4220  			errs := validateAMCPVirtualNetwork(tc.amcp.Spec.VirtualNetwork, field.NewPath("spec", "VirtualNetwork"))
  4221  			if tc.wantErr != "" {
  4222  				g.Expect(errs).ToNot(BeEmpty())
  4223  				g.Expect(errs[0].Detail).To(Equal(tc.wantErr))
  4224  			} else {
  4225  				g.Expect(err).NotTo(HaveOccurred())
  4226  			}
  4227  		})
  4228  	}
  4229  }