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

     1  /*
     2  Copyright 2021 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  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/google/uuid"
    24  	. "github.com/onsi/gomega"
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/utils/ptr"
    29  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    30  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    31  	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
    32  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    33  )
    34  
    35  func TestAzureMachinePool_SetDefaultSSHPublicKey(t *testing.T) {
    36  	g := NewWithT(t)
    37  
    38  	type test struct {
    39  		amp *AzureMachinePool
    40  	}
    41  
    42  	existingPublicKey := "testpublickey"
    43  	publicKeyExistTest := test{amp: createMachinePoolWithSSHPublicKey(existingPublicKey)}
    44  	publicKeyNotExistTest := test{amp: createMachinePoolWithSSHPublicKey("")}
    45  
    46  	err := publicKeyExistTest.amp.SetDefaultSSHPublicKey()
    47  	g.Expect(err).NotTo(HaveOccurred())
    48  	g.Expect(publicKeyExistTest.amp.Spec.Template.SSHPublicKey).To(Equal(existingPublicKey))
    49  
    50  	err = publicKeyNotExistTest.amp.SetDefaultSSHPublicKey()
    51  	g.Expect(err).NotTo(HaveOccurred())
    52  	g.Expect(publicKeyNotExistTest.amp.Spec.Template.SSHPublicKey).NotTo(BeEmpty())
    53  }
    54  
    55  func TestAzureMachinePool_SetIdentityDefaults(t *testing.T) {
    56  	fakeSubscriptionID := uuid.New().String()
    57  	fakeClusterName := "testcluster"
    58  	fakeRoleDefinitionID := "testroledefinitionid"
    59  	fakeScope := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s", fakeSubscriptionID, fakeClusterName)
    60  	existingRoleAssignmentName := "42862306-e485-4319-9bf0-35dbc6f6fe9c"
    61  
    62  	tests := []struct {
    63  		name                               string
    64  		machinePool                        *AzureMachinePool
    65  		wantErr                            bool
    66  		expectedRoleAssignmentName         string
    67  		expectedSystemAssignedIdentityRole *infrav1.SystemAssignedIdentityRole
    68  	}{
    69  		{
    70  			name: "bothRoleAssignmentNamesPopulated",
    71  			machinePool: &AzureMachinePool{Spec: AzureMachinePoolSpec{
    72  				Identity:           infrav1.VMIdentitySystemAssigned,
    73  				RoleAssignmentName: existingRoleAssignmentName,
    74  				SystemAssignedIdentityRole: &infrav1.SystemAssignedIdentityRole{
    75  					Name: existingRoleAssignmentName,
    76  				},
    77  			}},
    78  			expectedRoleAssignmentName: existingRoleAssignmentName,
    79  			expectedSystemAssignedIdentityRole: &infrav1.SystemAssignedIdentityRole{
    80  				Name: existingRoleAssignmentName,
    81  			},
    82  		},
    83  		{
    84  			name: "roleAssignmentExist",
    85  			machinePool: &AzureMachinePool{Spec: AzureMachinePoolSpec{
    86  				Identity: infrav1.VMIdentitySystemAssigned,
    87  				SystemAssignedIdentityRole: &infrav1.SystemAssignedIdentityRole{
    88  					Name: existingRoleAssignmentName,
    89  				},
    90  			}},
    91  			expectedSystemAssignedIdentityRole: &infrav1.SystemAssignedIdentityRole{
    92  				Name:         existingRoleAssignmentName,
    93  				DefinitionID: fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/%s", fakeSubscriptionID, infrav1.ContributorRoleID),
    94  				Scope:        fmt.Sprintf("/subscriptions/%s/", fakeSubscriptionID),
    95  			},
    96  		},
    97  		{
    98  			name: "notSystemAssigned",
    99  			machinePool: &AzureMachinePool{Spec: AzureMachinePoolSpec{
   100  				Identity: infrav1.VMIdentityUserAssigned,
   101  			}},
   102  			expectedSystemAssignedIdentityRole: nil,
   103  		},
   104  		{
   105  			name: "systemAssignedIdentityRoleExist",
   106  			machinePool: &AzureMachinePool{Spec: AzureMachinePoolSpec{
   107  				Identity: infrav1.VMIdentitySystemAssigned,
   108  				SystemAssignedIdentityRole: &infrav1.SystemAssignedIdentityRole{
   109  					Name:         existingRoleAssignmentName,
   110  					DefinitionID: fakeRoleDefinitionID,
   111  					Scope:        fakeScope,
   112  				},
   113  			}},
   114  			expectedSystemAssignedIdentityRole: &infrav1.SystemAssignedIdentityRole{
   115  				Name:         existingRoleAssignmentName,
   116  				DefinitionID: fakeRoleDefinitionID,
   117  				Scope:        fakeScope,
   118  			},
   119  		},
   120  		{
   121  			name: "deprecatedRoleAssignmentName",
   122  			machinePool: &AzureMachinePool{Spec: AzureMachinePoolSpec{
   123  				Identity:           infrav1.VMIdentitySystemAssigned,
   124  				RoleAssignmentName: existingRoleAssignmentName,
   125  			}},
   126  			expectedSystemAssignedIdentityRole: &infrav1.SystemAssignedIdentityRole{
   127  				Name:         existingRoleAssignmentName,
   128  				DefinitionID: fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/%s", fakeSubscriptionID, infrav1.ContributorRoleID),
   129  				Scope:        fmt.Sprintf("/subscriptions/%s/", fakeSubscriptionID),
   130  			},
   131  		},
   132  	}
   133  
   134  	for _, tc := range tests {
   135  		t.Run(tc.name, func(t *testing.T) {
   136  			g := NewWithT(t)
   137  
   138  			scheme := runtime.NewScheme()
   139  			_ = AddToScheme(scheme)
   140  			_ = infrav1.AddToScheme(scheme)
   141  			_ = clusterv1.AddToScheme(scheme)
   142  			_ = expv1.AddToScheme(scheme)
   143  
   144  			machinePool := &expv1.MachinePool{
   145  				ObjectMeta: metav1.ObjectMeta{
   146  					Name:      "pool1",
   147  					Namespace: "default",
   148  					Labels: map[string]string{
   149  						clusterv1.ClusterNameLabel: "testcluster",
   150  					},
   151  				},
   152  				Spec: expv1.MachinePoolSpec{
   153  					ClusterName: "testcluster",
   154  				},
   155  			}
   156  			azureCluster := &infrav1.AzureCluster{
   157  				ObjectMeta: metav1.ObjectMeta{
   158  					Name:      "testcluster",
   159  					Namespace: "default",
   160  				},
   161  				Spec: infrav1.AzureClusterSpec{
   162  					AzureClusterClassSpec: infrav1.AzureClusterClassSpec{
   163  						SubscriptionID: fakeSubscriptionID,
   164  					},
   165  				},
   166  			}
   167  			cluster := &clusterv1.Cluster{
   168  				ObjectMeta: metav1.ObjectMeta{
   169  					Name:      "testcluster",
   170  					Namespace: "default",
   171  				},
   172  				Spec: clusterv1.ClusterSpec{
   173  					InfrastructureRef: &corev1.ObjectReference{
   174  						Name:      "testcluster",
   175  						Namespace: "default",
   176  					},
   177  				},
   178  			}
   179  
   180  			fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(tc.machinePool, machinePool, azureCluster, cluster).Build()
   181  			err := tc.machinePool.SetIdentityDefaults(fakeClient)
   182  			if tc.wantErr {
   183  				g.Expect(err).To(HaveOccurred())
   184  			} else {
   185  				g.Expect(err).NotTo(HaveOccurred())
   186  				g.Expect(tc.machinePool.Spec.RoleAssignmentName).To(Equal(tc.expectedRoleAssignmentName))
   187  				g.Expect(tc.machinePool.Spec.SystemAssignedIdentityRole).To(Equal(tc.expectedSystemAssignedIdentityRole))
   188  			}
   189  		})
   190  	}
   191  }
   192  
   193  func TestAzureMachinePool_SetDiagnosticsDefaults(t *testing.T) {
   194  	g := NewWithT(t)
   195  
   196  	type test struct {
   197  		machinePool *AzureMachinePool
   198  	}
   199  
   200  	bootDiagnosticsDefault := &infrav1.BootDiagnostics{
   201  		StorageAccountType: infrav1.ManagedDiagnosticsStorage,
   202  	}
   203  
   204  	managedStorageDiagnostics := test{machinePool: &AzureMachinePool{
   205  		Spec: AzureMachinePoolSpec{
   206  			Template: AzureMachinePoolMachineTemplate{
   207  				Diagnostics: &infrav1.Diagnostics{
   208  					Boot: &infrav1.BootDiagnostics{
   209  						StorageAccountType: infrav1.ManagedDiagnosticsStorage,
   210  					},
   211  				},
   212  			},
   213  		},
   214  	}}
   215  
   216  	disabledStorageDiagnostics := test{machinePool: &AzureMachinePool{
   217  		Spec: AzureMachinePoolSpec{
   218  			Template: AzureMachinePoolMachineTemplate{
   219  				Diagnostics: &infrav1.Diagnostics{
   220  					Boot: &infrav1.BootDiagnostics{
   221  						StorageAccountType: infrav1.DisabledDiagnosticsStorage,
   222  					},
   223  				},
   224  			},
   225  		},
   226  	}}
   227  
   228  	userManagedDiagnostics := test{machinePool: &AzureMachinePool{
   229  		Spec: AzureMachinePoolSpec{
   230  			Template: AzureMachinePoolMachineTemplate{
   231  				Diagnostics: &infrav1.Diagnostics{
   232  					Boot: &infrav1.BootDiagnostics{
   233  						StorageAccountType: infrav1.UserManagedDiagnosticsStorage,
   234  						UserManaged: &infrav1.UserManagedBootDiagnostics{
   235  							StorageAccountURI: "https://fakeurl",
   236  						},
   237  					},
   238  				},
   239  			},
   240  		},
   241  	}}
   242  
   243  	nilDiagnostics := test{machinePool: &AzureMachinePool{
   244  		Spec: AzureMachinePoolSpec{
   245  			Template: AzureMachinePoolMachineTemplate{
   246  				Diagnostics: nil,
   247  			},
   248  		},
   249  	}}
   250  
   251  	// Test that when no diagnostics are specified, the defaults are set correctly
   252  	nilBootDiagnostics := test{machinePool: &AzureMachinePool{
   253  		Spec: AzureMachinePoolSpec{
   254  			Template: AzureMachinePoolMachineTemplate{
   255  				Diagnostics: &infrav1.Diagnostics{},
   256  			},
   257  		},
   258  	}}
   259  
   260  	nilBootDiagnostics.machinePool.SetDiagnosticsDefaults()
   261  	g.Expect(nilBootDiagnostics.machinePool.Spec.Template.Diagnostics.Boot).To(Equal(bootDiagnosticsDefault))
   262  
   263  	managedStorageDiagnostics.machinePool.SetDiagnosticsDefaults()
   264  	g.Expect(managedStorageDiagnostics.machinePool.Spec.Template.Diagnostics.Boot.StorageAccountType).To(Equal(infrav1.ManagedDiagnosticsStorage))
   265  
   266  	disabledStorageDiagnostics.machinePool.SetDiagnosticsDefaults()
   267  	g.Expect(disabledStorageDiagnostics.machinePool.Spec.Template.Diagnostics.Boot.StorageAccountType).To(Equal(infrav1.DisabledDiagnosticsStorage))
   268  
   269  	userManagedDiagnostics.machinePool.SetDiagnosticsDefaults()
   270  	g.Expect(userManagedDiagnostics.machinePool.Spec.Template.Diagnostics.Boot.StorageAccountType).To(Equal(infrav1.UserManagedDiagnosticsStorage))
   271  
   272  	nilDiagnostics.machinePool.SetDiagnosticsDefaults()
   273  	g.Expect(nilDiagnostics.machinePool.Spec.Template.Diagnostics.Boot.StorageAccountType).To(Equal(infrav1.ManagedDiagnosticsStorage))
   274  }
   275  
   276  func TestAzureMachinePool_SetSpotEvictionPolicyDefaults(t *testing.T) {
   277  	g := NewWithT(t)
   278  
   279  	type test struct {
   280  		machinePool *AzureMachinePool
   281  	}
   282  
   283  	// test to Ensure the default policy is set to Deallocate if EvictionPolicy is nil
   284  	defaultEvictionPolicy := infrav1.SpotEvictionPolicyDeallocate
   285  	nilDiffDiskSettingsPolicy := test{machinePool: &AzureMachinePool{
   286  		Spec: AzureMachinePoolSpec{
   287  			Template: AzureMachinePoolMachineTemplate{
   288  				SpotVMOptions: &infrav1.SpotVMOptions{
   289  					EvictionPolicy: nil,
   290  				},
   291  			},
   292  		},
   293  	}}
   294  	nilDiffDiskSettingsPolicy.machinePool.SetSpotEvictionPolicyDefaults()
   295  	g.Expect(nilDiffDiskSettingsPolicy.machinePool.Spec.Template.SpotVMOptions.EvictionPolicy).To(Equal(&defaultEvictionPolicy))
   296  
   297  	// test to Ensure the default policy is set to Delete if diffDiskSettings option is set to "Local"
   298  	expectedEvictionPolicy := infrav1.SpotEvictionPolicyDelete
   299  	diffDiskSettingsPolicy := test{machinePool: &AzureMachinePool{
   300  		Spec: AzureMachinePoolSpec{
   301  			Template: AzureMachinePoolMachineTemplate{
   302  				SpotVMOptions: &infrav1.SpotVMOptions{},
   303  				OSDisk: infrav1.OSDisk{
   304  					DiffDiskSettings: &infrav1.DiffDiskSettings{
   305  						Option: "Local",
   306  					},
   307  				},
   308  			},
   309  		},
   310  	}}
   311  	diffDiskSettingsPolicy.machinePool.SetSpotEvictionPolicyDefaults()
   312  	g.Expect(diffDiskSettingsPolicy.machinePool.Spec.Template.SpotVMOptions.EvictionPolicy).To(Equal(&expectedEvictionPolicy))
   313  }
   314  
   315  func TestAzureMachinePool_SetNetworkInterfacesDefaults(t *testing.T) {
   316  	testCases := []struct {
   317  		name        string
   318  		machinePool *AzureMachinePool
   319  		want        *AzureMachinePool
   320  	}{
   321  		{
   322  			name: "defaulting webhook updates MachinePool with deprecated subnetName field",
   323  			machinePool: &AzureMachinePool{
   324  				Spec: AzureMachinePoolSpec{
   325  					Template: AzureMachinePoolMachineTemplate{
   326  						SubnetName: "test-subnet",
   327  					},
   328  				},
   329  			},
   330  			want: &AzureMachinePool{
   331  				Spec: AzureMachinePoolSpec{
   332  					Template: AzureMachinePoolMachineTemplate{
   333  						SubnetName: "",
   334  						NetworkInterfaces: []infrav1.NetworkInterface{
   335  							{
   336  								SubnetName:       "test-subnet",
   337  								PrivateIPConfigs: 1,
   338  							},
   339  						},
   340  					},
   341  				},
   342  			},
   343  		},
   344  		{
   345  			name: "defaulting webhook updates MachinePool with deprecated acceleratedNetworking field",
   346  			machinePool: &AzureMachinePool{
   347  				Spec: AzureMachinePoolSpec{
   348  					Template: AzureMachinePoolMachineTemplate{
   349  						SubnetName:            "test-subnet",
   350  						AcceleratedNetworking: ptr.To(true),
   351  					},
   352  				},
   353  			},
   354  			want: &AzureMachinePool{
   355  				Spec: AzureMachinePoolSpec{
   356  					Template: AzureMachinePoolMachineTemplate{
   357  						SubnetName:            "",
   358  						AcceleratedNetworking: nil,
   359  						NetworkInterfaces: []infrav1.NetworkInterface{
   360  							{
   361  								SubnetName:            "test-subnet",
   362  								PrivateIPConfigs:      1,
   363  								AcceleratedNetworking: ptr.To(true),
   364  							},
   365  						},
   366  					},
   367  				},
   368  			},
   369  		},
   370  		{
   371  			name: "defaulting webhook does nothing if both new and deprecated subnetName fields are set",
   372  			machinePool: &AzureMachinePool{
   373  				Spec: AzureMachinePoolSpec{
   374  					Template: AzureMachinePoolMachineTemplate{
   375  						SubnetName: "test-subnet",
   376  						NetworkInterfaces: []infrav1.NetworkInterface{{
   377  							SubnetName: "test-subnet",
   378  						}},
   379  					},
   380  				},
   381  			},
   382  			want: &AzureMachinePool{
   383  				Spec: AzureMachinePoolSpec{
   384  					Template: AzureMachinePoolMachineTemplate{
   385  						SubnetName:            "test-subnet",
   386  						AcceleratedNetworking: nil,
   387  						NetworkInterfaces: []infrav1.NetworkInterface{
   388  							{
   389  								SubnetName: "test-subnet",
   390  							},
   391  						},
   392  					},
   393  				},
   394  			},
   395  		},
   396  	}
   397  
   398  	for _, tc := range testCases {
   399  		t.Run(tc.name, func(t *testing.T) {
   400  			g := NewWithT(t)
   401  			tc.machinePool.SetNetworkInterfacesDefaults()
   402  			g.Expect(tc.machinePool).To(Equal(tc.want))
   403  		})
   404  	}
   405  }
   406  
   407  func createMachinePoolWithSSHPublicKey(sshPublicKey string) *AzureMachinePool {
   408  	return hardcodedAzureMachinePoolWithSSHKey(sshPublicKey)
   409  }
   410  
   411  func hardcodedAzureMachinePoolWithSSHKey(sshPublicKey string) *AzureMachinePool {
   412  	return &AzureMachinePool{
   413  		Spec: AzureMachinePoolSpec{
   414  			Template: AzureMachinePoolMachineTemplate{
   415  				SSHPublicKey: sshPublicKey,
   416  			},
   417  		},
   418  		ObjectMeta: metav1.ObjectMeta{
   419  			Name: "testmachinepool",
   420  		},
   421  	}
   422  }