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