sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/managedclusters/spec_test.go (about)

     1  /*
     2  Copyright 2022 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 managedclusters
    18  
    19  import (
    20  	"context"
    21  	"encoding/base64"
    22  	"testing"
    23  
    24  	asocontainerservicev1preview "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20230202preview"
    25  	asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001"
    26  	"github.com/Azure/azure-service-operator/v2/pkg/genruntime"
    27  	"github.com/google/go-cmp/cmp"
    28  	. "github.com/onsi/gomega"
    29  	"k8s.io/utils/ptr"
    30  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    31  	"sigs.k8s.io/cluster-api-provider-azure/azure"
    32  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/agentpools"
    33  	"sigs.k8s.io/cluster-api/util/secret"
    34  )
    35  
    36  func TestParameters(t *testing.T) {
    37  	t.Run("no existing managed cluster", func(t *testing.T) {
    38  		g := NewGomegaWithT(t)
    39  
    40  		spec := &ManagedClusterSpec{
    41  			Name:              "name",
    42  			ResourceGroup:     "rg",
    43  			NodeResourceGroup: "node rg",
    44  			ClusterName:       "cluster",
    45  			VnetSubnetID:      "vnet subnet id",
    46  			Location:          "location",
    47  			Tags:              map[string]string{"additional": "tags"},
    48  			Version:           "version",
    49  			LoadBalancerSKU:   "lb sku",
    50  			NetworkPlugin:     "network plugin",
    51  			NetworkPluginMode: ptr.To(infrav1.NetworkPluginMode("network plugin mode")),
    52  			NetworkPolicy:     "network policy",
    53  			OutboundType:      ptr.To(infrav1.ManagedControlPlaneOutboundType("outbound type")),
    54  			SSHPublicKey:      base64.StdEncoding.EncodeToString([]byte("ssh")),
    55  			GetAllAgentPools: func() ([]azure.ASOResourceSpecGetter[genruntime.MetaObject], error) {
    56  				return []azure.ASOResourceSpecGetter[genruntime.MetaObject]{
    57  					&agentpools.AgentPoolSpec{
    58  						Replicas:  5,
    59  						Mode:      "mode",
    60  						AzureName: "agentpool",
    61  						Patches:   []string{`{"spec": {"tags": {"from": "patches"}}}`},
    62  					},
    63  				}, nil
    64  			},
    65  			PodCIDR:      "pod cidr",
    66  			ServiceCIDR:  "0.0.0.0/10",
    67  			DNSServiceIP: nil,
    68  			AddonProfiles: []AddonProfile{
    69  				{
    70  					Name:    "addon name",
    71  					Enabled: true,
    72  					Config:  map[string]string{"addon": "config"},
    73  				},
    74  			},
    75  			AADProfile: &AADProfile{
    76  				Managed: true,
    77  			},
    78  			SKU: &SKU{
    79  				Tier: "sku tier",
    80  			},
    81  			LoadBalancerProfile: &LoadBalancerProfile{
    82  				ManagedOutboundIPs: ptr.To(16),
    83  				OutboundIPPrefixes: []string{"outbound ip prefixes"},
    84  				OutboundIPs:        []string{"outbound ips"},
    85  			},
    86  			APIServerAccessProfile: &APIServerAccessProfile{
    87  				AuthorizedIPRanges: []string{"authorized ip ranges"},
    88  			},
    89  			AutoScalerProfile: &AutoScalerProfile{
    90  				Expander: ptr.To("expander"),
    91  			},
    92  			AutoUpgradeProfile: &ManagedClusterAutoUpgradeProfile{
    93  				UpgradeChannel: ptr.To(infrav1.UpgradeChannelRapid),
    94  			},
    95  			Identity: &infrav1.Identity{
    96  				Type:                           infrav1.ManagedControlPlaneIdentityType(asocontainerservicev1.ManagedClusterIdentity_Type_UserAssigned),
    97  				UserAssignedIdentityResourceID: "user assigned id",
    98  			},
    99  			KubeletUserAssignedIdentity: "kubelet id",
   100  			HTTPProxyConfig: &HTTPProxyConfig{
   101  				NoProxy: []string{"noproxy"},
   102  			},
   103  			OIDCIssuerProfile: &OIDCIssuerProfile{
   104  				Enabled: ptr.To(true),
   105  			},
   106  			DNSPrefix:            ptr.To("dns prefix"),
   107  			DisableLocalAccounts: ptr.To(true),
   108  			SecurityProfile: &ManagedClusterSecurityProfile{
   109  				AzureKeyVaultKms: &AzureKeyVaultKms{
   110  					Enabled:               ptr.To(true),
   111  					KeyID:                 ptr.To("KeyID"),
   112  					KeyVaultNetworkAccess: ptr.To(infrav1.KeyVaultNetworkAccessTypesPublic),
   113  				},
   114  				Defender: &ManagedClusterSecurityProfileDefender{
   115  					LogAnalyticsWorkspaceResourceID: ptr.To("LogAnalyticsWorkspaceResourceID"),
   116  					SecurityMonitoring: &ManagedClusterSecurityProfileDefenderSecurityMonitoring{
   117  						Enabled: ptr.To(true),
   118  					},
   119  				},
   120  				ImageCleaner: &ManagedClusterSecurityProfileImageCleaner{
   121  					Enabled:       ptr.To(true),
   122  					IntervalHours: ptr.To(24),
   123  				},
   124  				WorkloadIdentity: &ManagedClusterSecurityProfileWorkloadIdentity{
   125  					Enabled: ptr.To(true),
   126  				},
   127  			},
   128  		}
   129  
   130  		expected := &asocontainerservicev1.ManagedCluster{
   131  			Spec: asocontainerservicev1.ManagedCluster_Spec{
   132  				AadProfile: &asocontainerservicev1.ManagedClusterAADProfile{
   133  					EnableAzureRBAC: ptr.To(false),
   134  					Managed:         ptr.To(true),
   135  				},
   136  				AddonProfiles: map[string]asocontainerservicev1.ManagedClusterAddonProfile{
   137  					"addon name": {
   138  						Config:  map[string]string{"addon": "config"},
   139  						Enabled: ptr.To(true),
   140  					},
   141  				},
   142  				AgentPoolProfiles: []asocontainerservicev1.ManagedClusterAgentPoolProfile{
   143  					{
   144  						Count:             ptr.To(5),
   145  						EnableAutoScaling: ptr.To(false),
   146  						Mode:              ptr.To(asocontainerservicev1.AgentPoolMode("mode")),
   147  						Name:              ptr.To("agentpool"),
   148  						OsDiskSizeGB:      ptr.To(asocontainerservicev1.ContainerServiceOSDisk(0)),
   149  						Type:              ptr.To(asocontainerservicev1.AgentPoolType_VirtualMachineScaleSets),
   150  						Tags:              map[string]string{"from": "patches"},
   151  					},
   152  				},
   153  				ApiServerAccessProfile: &asocontainerservicev1.ManagedClusterAPIServerAccessProfile{
   154  					AuthorizedIPRanges: []string{"authorized ip ranges"},
   155  				},
   156  				AutoScalerProfile: &asocontainerservicev1.ManagedClusterProperties_AutoScalerProfile{
   157  					Expander: ptr.To(asocontainerservicev1.ManagedClusterProperties_AutoScalerProfile_Expander("expander")),
   158  				},
   159  				AutoUpgradeProfile: &asocontainerservicev1.ManagedClusterAutoUpgradeProfile{
   160  					UpgradeChannel: ptr.To(asocontainerservicev1.ManagedClusterAutoUpgradeProfile_UpgradeChannel_Rapid),
   161  				},
   162  				AzureName:            "name",
   163  				DisableLocalAccounts: ptr.To(true),
   164  				DnsPrefix:            ptr.To("dns prefix"),
   165  				EnableRBAC:           ptr.To(true),
   166  				HttpProxyConfig: &asocontainerservicev1.ManagedClusterHTTPProxyConfig{
   167  					NoProxy: []string{"noproxy"},
   168  				},
   169  				Identity: &asocontainerservicev1.ManagedClusterIdentity{
   170  					Type: ptr.To(asocontainerservicev1.ManagedClusterIdentity_Type_UserAssigned),
   171  					UserAssignedIdentities: []asocontainerservicev1.UserAssignedIdentityDetails{
   172  						{
   173  							Reference: genruntime.ResourceReference{
   174  								ARMID: "user assigned id",
   175  							},
   176  						},
   177  					},
   178  				},
   179  				IdentityProfile: map[string]asocontainerservicev1.UserAssignedIdentity{
   180  					kubeletIdentityKey: {
   181  						ResourceReference: &genruntime.ResourceReference{
   182  							ARMID: "kubelet id",
   183  						},
   184  					},
   185  				},
   186  				KubernetesVersion: ptr.To("version"),
   187  				LinuxProfile: &asocontainerservicev1.ContainerServiceLinuxProfile{
   188  					AdminUsername: ptr.To(azure.DefaultAKSUserName),
   189  					Ssh: &asocontainerservicev1.ContainerServiceSshConfiguration{
   190  						PublicKeys: []asocontainerservicev1.ContainerServiceSshPublicKey{
   191  							{
   192  								KeyData: ptr.To("ssh"),
   193  							},
   194  						},
   195  					},
   196  				},
   197  				Location: ptr.To("location"),
   198  				NetworkProfile: &asocontainerservicev1.ContainerServiceNetworkProfile{
   199  					DnsServiceIP: ptr.To("0.0.0.10"),
   200  					LoadBalancerProfile: &asocontainerservicev1.ManagedClusterLoadBalancerProfile{
   201  						ManagedOutboundIPs: &asocontainerservicev1.ManagedClusterLoadBalancerProfile_ManagedOutboundIPs{
   202  							Count: ptr.To(16),
   203  						},
   204  						OutboundIPPrefixes: &asocontainerservicev1.ManagedClusterLoadBalancerProfile_OutboundIPPrefixes{
   205  							PublicIPPrefixes: []asocontainerservicev1.ResourceReference{
   206  								{
   207  									Reference: &genruntime.ResourceReference{
   208  										ARMID: "outbound ip prefixes",
   209  									},
   210  								},
   211  							},
   212  						},
   213  						OutboundIPs: &asocontainerservicev1.ManagedClusterLoadBalancerProfile_OutboundIPs{
   214  							PublicIPs: []asocontainerservicev1.ResourceReference{
   215  								{
   216  									Reference: &genruntime.ResourceReference{
   217  										ARMID: "outbound ips",
   218  									},
   219  								},
   220  							},
   221  						},
   222  					},
   223  					LoadBalancerSku:   ptr.To(asocontainerservicev1.ContainerServiceNetworkProfile_LoadBalancerSku("lb sku")),
   224  					NetworkPlugin:     ptr.To(asocontainerservicev1.NetworkPlugin("network plugin")),
   225  					NetworkPluginMode: ptr.To(asocontainerservicev1.ContainerServiceNetworkProfile_NetworkPluginMode("network plugin mode")),
   226  					NetworkPolicy:     ptr.To(asocontainerservicev1.ContainerServiceNetworkProfile_NetworkPolicy("network policy")),
   227  					OutboundType:      ptr.To(asocontainerservicev1.ContainerServiceNetworkProfile_OutboundType("outbound type")),
   228  					PodCidr:           ptr.To("pod cidr"),
   229  					ServiceCidr:       ptr.To("0.0.0.0/10"),
   230  				},
   231  				NodeResourceGroup: ptr.To("node rg"),
   232  				OidcIssuerProfile: &asocontainerservicev1.ManagedClusterOIDCIssuerProfile{
   233  					Enabled: ptr.To(true),
   234  				},
   235  				OperatorSpec: &asocontainerservicev1.ManagedClusterOperatorSpec{
   236  					Secrets: &asocontainerservicev1.ManagedClusterOperatorSecrets{
   237  						UserCredentials: &genruntime.SecretDestination{
   238  							Name: userKubeconfigSecretName("cluster"),
   239  							Key:  secret.KubeconfigDataName,
   240  						},
   241  					},
   242  					ConfigMaps: &asocontainerservicev1.ManagedClusterOperatorConfigMaps{
   243  						OIDCIssuerProfile: &genruntime.ConfigMapDestination{
   244  							Name: oidcIssuerURLConfigMapName("cluster"),
   245  							Key:  oidcIssuerProfileURL,
   246  						},
   247  					},
   248  				},
   249  				Owner: &genruntime.KnownResourceReference{
   250  					Name: "rg",
   251  				},
   252  				ServicePrincipalProfile: &asocontainerservicev1.ManagedClusterServicePrincipalProfile{
   253  					ClientId: ptr.To("msi"),
   254  				},
   255  				Sku: &asocontainerservicev1.ManagedClusterSKU{
   256  					Name: ptr.To(asocontainerservicev1.ManagedClusterSKU_Name_Base),
   257  					Tier: ptr.To(asocontainerservicev1.ManagedClusterSKU_Tier("sku tier")),
   258  				},
   259  				Tags: map[string]string{
   260  					"Name": "name",
   261  					"sigs.k8s.io_cluster-api-provider-azure_cluster_cluster": "owned",
   262  					"sigs.k8s.io_cluster-api-provider-azure_role":            "common",
   263  				},
   264  				SecurityProfile: &asocontainerservicev1.ManagedClusterSecurityProfile{
   265  					AzureKeyVaultKms: &asocontainerservicev1.AzureKeyVaultKms{
   266  						Enabled:               ptr.To(true),
   267  						KeyId:                 ptr.To("KeyID"),
   268  						KeyVaultNetworkAccess: ptr.To(asocontainerservicev1.AzureKeyVaultKms_KeyVaultNetworkAccess_Public),
   269  					},
   270  					Defender: &asocontainerservicev1.ManagedClusterSecurityProfileDefender{
   271  						LogAnalyticsWorkspaceResourceReference: &genruntime.ResourceReference{
   272  							ARMID: "LogAnalyticsWorkspaceResourceID",
   273  						},
   274  						SecurityMonitoring: &asocontainerservicev1.ManagedClusterSecurityProfileDefenderSecurityMonitoring{
   275  							Enabled: ptr.To(true),
   276  						},
   277  					},
   278  					ImageCleaner: &asocontainerservicev1.ManagedClusterSecurityProfileImageCleaner{
   279  						Enabled:       ptr.To(true),
   280  						IntervalHours: ptr.To(24),
   281  					},
   282  					WorkloadIdentity: &asocontainerservicev1.ManagedClusterSecurityProfileWorkloadIdentity{
   283  						Enabled: ptr.To(true),
   284  					},
   285  				},
   286  			},
   287  		}
   288  
   289  		actual, err := spec.Parameters(context.Background(), nil)
   290  
   291  		g.Expect(err).NotTo(HaveOccurred())
   292  		g.Expect(cmp.Diff(actual, expected)).To(BeEmpty())
   293  	})
   294  
   295  	t.Run("no existing preview managed cluster", func(t *testing.T) {
   296  		g := NewGomegaWithT(t)
   297  
   298  		spec := &ManagedClusterSpec{
   299  			Name:    "name",
   300  			Preview: true,
   301  			GetAllAgentPools: func() ([]azure.ASOResourceSpecGetter[genruntime.MetaObject], error) {
   302  				return []azure.ASOResourceSpecGetter[genruntime.MetaObject]{
   303  					&agentpools.AgentPoolSpec{
   304  						Replicas:  5,
   305  						Mode:      "mode",
   306  						AzureName: "agentpool",
   307  						Patches:   []string{`{"spec": {"tags": {"from": "patches"}}}`},
   308  						Preview:   true,
   309  					},
   310  				}, nil
   311  			},
   312  		}
   313  
   314  		actual, err := spec.Parameters(context.Background(), nil)
   315  		g.Expect(err).NotTo(HaveOccurred())
   316  		_, ok := actual.(*asocontainerservicev1preview.ManagedCluster)
   317  		g.Expect(ok).To(BeTrue())
   318  	})
   319  
   320  	t.Run("with existing managed cluster", func(t *testing.T) {
   321  		g := NewGomegaWithT(t)
   322  
   323  		spec := &ManagedClusterSpec{
   324  			DNSPrefix: ptr.To("managed by CAPZ"),
   325  			Tags:      map[string]string{"additional": "tags"},
   326  			Version:   "1.25.9",
   327  		}
   328  		existing := &asocontainerservicev1.ManagedCluster{
   329  			Spec: asocontainerservicev1.ManagedCluster_Spec{
   330  				DnsPrefix:               ptr.To("set by the user"),
   331  				EnablePodSecurityPolicy: ptr.To(true), // set by the user
   332  			},
   333  			Status: asocontainerservicev1.ManagedCluster_STATUS{
   334  				AgentPoolProfiles:        []asocontainerservicev1.ManagedClusterAgentPoolProfile_STATUS{},
   335  				Tags:                     map[string]string{},
   336  				CurrentKubernetesVersion: ptr.To("1.26.6"),
   337  			},
   338  		}
   339  
   340  		actualObj, err := spec.Parameters(context.Background(), existing)
   341  		actual := actualObj.(*asocontainerservicev1.ManagedCluster)
   342  
   343  		g.Expect(err).NotTo(HaveOccurred())
   344  		g.Expect(actual.Spec.AgentPoolProfiles).To(BeNil())
   345  		g.Expect(actual.Spec.Tags).To(BeNil())
   346  		g.Expect(actual.Spec.DnsPrefix).To(Equal(ptr.To("managed by CAPZ")))
   347  		g.Expect(actual.Spec.EnablePodSecurityPolicy).To(Equal(ptr.To(true)))
   348  		g.Expect(actual.Spec.KubernetesVersion).NotTo(BeNil())
   349  		g.Expect(*actual.Spec.KubernetesVersion).To(Equal("1.26.6"))
   350  	})
   351  
   352  	t.Run("updating existing managed cluster to a non nil DNS Service IP", func(t *testing.T) {
   353  		g := NewGomegaWithT(t)
   354  
   355  		spec := &ManagedClusterSpec{
   356  			DNSPrefix:    ptr.To("managed by CAPZ"),
   357  			Tags:         map[string]string{"additional": "tags"},
   358  			ServiceCIDR:  "123.200.198.0/10",
   359  			DNSServiceIP: ptr.To("123.200.198.99"),
   360  		}
   361  		existing := &asocontainerservicev1.ManagedCluster{
   362  			Spec: asocontainerservicev1.ManagedCluster_Spec{
   363  				DnsPrefix:               ptr.To("set by the user"),
   364  				EnablePodSecurityPolicy: ptr.To(true), // set by the user
   365  
   366  			},
   367  			Status: asocontainerservicev1.ManagedCluster_STATUS{
   368  				AgentPoolProfiles: []asocontainerservicev1.ManagedClusterAgentPoolProfile_STATUS{},
   369  				Tags:              map[string]string{},
   370  			},
   371  		}
   372  
   373  		actualObj, err := spec.Parameters(context.Background(), existing)
   374  		actual := actualObj.(*asocontainerservicev1.ManagedCluster)
   375  
   376  		g.Expect(err).NotTo(HaveOccurred())
   377  		g.Expect(actual.Spec.AgentPoolProfiles).To(BeNil())
   378  		g.Expect(actual.Spec.Tags).To(BeNil())
   379  		g.Expect(actual.Spec.DnsPrefix).To(Equal(ptr.To("managed by CAPZ")))
   380  		g.Expect(actual.Spec.EnablePodSecurityPolicy).To(Equal(ptr.To(true)))
   381  		g.Expect(actual.Spec.NetworkProfile.DnsServiceIP).To(Equal(ptr.To("123.200.198.99")))
   382  		g.Expect(actual.Spec.NetworkProfile.ServiceCidr).To(Equal(ptr.To("123.200.198.0/10")))
   383  	})
   384  }
   385  
   386  func TestOIDCIssuerURLConfigMap(t *testing.T) {
   387  	t.Run("get oidc issuer profile", func(t *testing.T) {
   388  		g := NewGomegaWithT(t)
   389  
   390  		clusterName := "my-cluster"
   391  		actualOIDCIssuerConfigMapName := oidcIssuerURLConfigMapName(clusterName)
   392  
   393  		g.Expect(actualOIDCIssuerConfigMapName).To(Equal("my-cluster-aso-oidc-issuer-profile"))
   394  	})
   395  }