sigs.k8s.io/cluster-api-provider-aws@v1.5.5/api/v1beta1/awsmachine_webhook_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 "context" 21 "strings" 22 "testing" 23 24 "github.com/aws/aws-sdk-go/aws" 25 . "github.com/onsi/gomega" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/utils/pointer" 28 29 utildefaulting "sigs.k8s.io/cluster-api/util/defaulting" 30 ) 31 32 func TestMachineDefault(t *testing.T) { 33 machine := &AWSMachine{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} 34 t.Run("for AWSMachine", utildefaulting.DefaultValidateTest(machine)) 35 machine.Default() 36 g := NewWithT(t) 37 g.Expect(machine.Spec.CloudInit.SecureSecretsBackend).To(Equal(SecretBackendSecretsManager)) 38 } 39 40 func TestAWSMachine_Create(t *testing.T) { 41 tests := []struct { 42 name string 43 machine *AWSMachine 44 wantErr bool 45 }{ 46 { 47 name: "ensure IOPS exists if type equal to io1", 48 machine: &AWSMachine{ 49 Spec: AWSMachineSpec{ 50 RootVolume: &Volume{ 51 Type: "io1", 52 }, 53 InstanceType: "test", 54 }, 55 }, 56 wantErr: true, 57 }, 58 { 59 name: "ensure IOPS exists if type equal to io2", 60 machine: &AWSMachine{ 61 Spec: AWSMachineSpec{ 62 RootVolume: &Volume{ 63 Type: "io2", 64 }, 65 InstanceType: "test", 66 }, 67 }, 68 wantErr: true, 69 }, 70 { 71 name: "ensure root volume throughput is nonnegative", 72 machine: &AWSMachine{ 73 Spec: AWSMachineSpec{ 74 RootVolume: &Volume{ 75 Throughput: aws.Int64(-125), 76 }, 77 InstanceType: "test", 78 }, 79 }, 80 wantErr: true, 81 }, 82 { 83 name: "ensure root volume has no device name", 84 machine: &AWSMachine{ 85 Spec: AWSMachineSpec{ 86 RootVolume: &Volume{ 87 DeviceName: "name", 88 }, 89 InstanceType: "test", 90 }, 91 }, 92 wantErr: true, 93 }, 94 { 95 name: "ensure non root volume have device names", 96 machine: &AWSMachine{ 97 Spec: AWSMachineSpec{ 98 NonRootVolumes: []Volume{ 99 {}, 100 }, 101 InstanceType: "test", 102 }, 103 }, 104 wantErr: true, 105 }, 106 { 107 name: "ensure ensure IOPS exists if type equal to io1 for non root volumes", 108 machine: &AWSMachine{ 109 Spec: AWSMachineSpec{ 110 NonRootVolumes: []Volume{ 111 { 112 DeviceName: "name", 113 Type: "io1", 114 }, 115 }, 116 InstanceType: "test", 117 }, 118 }, 119 wantErr: true, 120 }, 121 { 122 name: "ensure ensure IOPS exists if type equal to io2 for non root volumes", 123 machine: &AWSMachine{ 124 Spec: AWSMachineSpec{ 125 NonRootVolumes: []Volume{ 126 { 127 DeviceName: "name", 128 Type: "io2", 129 }, 130 }, 131 InstanceType: "test", 132 }, 133 }, 134 wantErr: true, 135 }, 136 { 137 name: "ensure non root volume throughput is nonnegative", 138 machine: &AWSMachine{ 139 Spec: AWSMachineSpec{ 140 NonRootVolumes: []Volume{ 141 { 142 Throughput: aws.Int64(-125), 143 }, 144 }, 145 InstanceType: "test", 146 }, 147 }, 148 wantErr: true, 149 }, 150 { 151 name: "additional security groups may have id", 152 machine: &AWSMachine{ 153 Spec: AWSMachineSpec{ 154 AdditionalSecurityGroups: []AWSResourceReference{ 155 { 156 ID: aws.String("id"), 157 }, 158 }, 159 InstanceType: "test", 160 }, 161 }, 162 wantErr: false, 163 }, 164 { 165 name: "additional security groups may have filters", 166 machine: &AWSMachine{ 167 Spec: AWSMachineSpec{ 168 AdditionalSecurityGroups: []AWSResourceReference{ 169 { 170 Filters: []Filter{ 171 { 172 Name: "example-name", 173 Values: []string{"example-value"}, 174 }, 175 }, 176 }, 177 }, 178 InstanceType: "test", 179 }, 180 }, 181 wantErr: false, 182 }, 183 { 184 name: "additional security groups can't have both id and filters", 185 machine: &AWSMachine{ 186 Spec: AWSMachineSpec{ 187 AdditionalSecurityGroups: []AWSResourceReference{ 188 { 189 ID: aws.String("id"), 190 Filters: []Filter{ 191 { 192 Name: "example-name", 193 Values: []string{"example-value"}, 194 }, 195 }, 196 }, 197 }, 198 InstanceType: "test", 199 }, 200 }, 201 wantErr: true, 202 }, 203 { 204 name: "valid additional tags are accepted", 205 machine: &AWSMachine{ 206 Spec: AWSMachineSpec{ 207 AdditionalTags: Tags{ 208 "key-1": "value-1", 209 "key-2": "value-2", 210 }, 211 InstanceType: "test", 212 }, 213 }, 214 wantErr: false, 215 }, 216 { 217 name: "empty instance type not allowed", 218 machine: &AWSMachine{ 219 Spec: AWSMachineSpec{ 220 InstanceType: "", 221 }, 222 }, 223 wantErr: true, 224 }, 225 { 226 name: "instance type minimum length is 2", 227 machine: &AWSMachine{ 228 Spec: AWSMachineSpec{ 229 InstanceType: "t", 230 }, 231 }, 232 wantErr: true, 233 }, 234 { 235 name: "invalid tags return error", 236 machine: &AWSMachine{ 237 Spec: AWSMachineSpec{ 238 AdditionalTags: Tags{ 239 "key-1": "value-1", 240 "": "value-2", 241 strings.Repeat("CAPI", 33): "value-3", 242 "key-4": strings.Repeat("CAPI", 65), 243 }, 244 InstanceType: "test", 245 }, 246 }, 247 wantErr: true, 248 }, 249 } 250 for _, tt := range tests { 251 t.Run(tt.name, func(t *testing.T) { 252 machine := tt.machine.DeepCopy() 253 machine.ObjectMeta = metav1.ObjectMeta{ 254 GenerateName: "machine-", 255 Namespace: "default", 256 } 257 ctx := context.TODO() 258 if err := testEnv.Create(ctx, machine); (err != nil) != tt.wantErr { 259 t.Errorf("ValidateCreate() error = %v, wantErr %v", err, tt.wantErr) 260 } 261 testEnv.Delete(ctx, machine) 262 }) 263 } 264 } 265 266 func TestAWSMachine_Update(t *testing.T) { 267 tests := []struct { 268 name string 269 oldMachine *AWSMachine 270 newMachine *AWSMachine 271 wantErr bool 272 }{ 273 { 274 name: "change in providerid, cloudinit, tags and securitygroups", 275 oldMachine: &AWSMachine{ 276 Spec: AWSMachineSpec{ 277 ProviderID: nil, 278 AdditionalTags: nil, 279 AdditionalSecurityGroups: nil, 280 InstanceType: "test", 281 }, 282 }, 283 newMachine: &AWSMachine{ 284 Spec: AWSMachineSpec{ 285 ProviderID: pointer.StringPtr("ID"), 286 InstanceType: "test", 287 AdditionalTags: Tags{ 288 "key-1": "value-1", 289 }, 290 AdditionalSecurityGroups: []AWSResourceReference{ 291 { 292 ID: pointer.StringPtr("ID"), 293 }, 294 }, 295 CloudInit: CloudInit{ 296 SecretPrefix: "test", 297 SecretCount: 5, 298 }, 299 }, 300 }, 301 wantErr: false, 302 }, 303 { 304 name: "change in fields other than providerid, tags and securitygroups", 305 oldMachine: &AWSMachine{ 306 Spec: AWSMachineSpec{ 307 ProviderID: nil, 308 AdditionalTags: nil, 309 AdditionalSecurityGroups: nil, 310 InstanceType: "test", 311 }, 312 }, 313 newMachine: &AWSMachine{ 314 Spec: AWSMachineSpec{ 315 ImageLookupOrg: "test", 316 InstanceType: "test", 317 ProviderID: pointer.StringPtr("ID"), 318 AdditionalTags: Tags{ 319 "key-1": "value-1", 320 }, 321 AdditionalSecurityGroups: []AWSResourceReference{ 322 { 323 ID: pointer.StringPtr("ID"), 324 }, 325 }, 326 }, 327 }, 328 wantErr: true, 329 }, 330 { 331 name: "change in tags adding invalid ones", 332 oldMachine: &AWSMachine{ 333 Spec: AWSMachineSpec{ 334 ProviderID: nil, 335 AdditionalTags: Tags{ 336 "key-1": "value-1", 337 }, 338 AdditionalSecurityGroups: nil, 339 InstanceType: "test", 340 }, 341 }, 342 newMachine: &AWSMachine{ 343 Spec: AWSMachineSpec{ 344 ProviderID: nil, 345 AdditionalTags: Tags{ 346 "key-1": "value-1", 347 "": "value-2", 348 strings.Repeat("CAPI", 33): "value-3", 349 "key-4": strings.Repeat("CAPI", 65), 350 }, 351 AdditionalSecurityGroups: nil, 352 InstanceType: "test", 353 }, 354 }, 355 wantErr: true, 356 }, 357 } 358 for _, tt := range tests { 359 ctx := context.TODO() 360 t.Run(tt.name, func(t *testing.T) { 361 machine := tt.oldMachine.DeepCopy() 362 machine.ObjectMeta = metav1.ObjectMeta{ 363 GenerateName: "machine-", 364 Namespace: "default", 365 } 366 if err := testEnv.Create(ctx, machine); err != nil { 367 t.Errorf("failed to create machine: %v", err) 368 } 369 machine.Spec = tt.newMachine.Spec 370 if err := testEnv.Update(ctx, machine); (err != nil) != tt.wantErr { 371 t.Errorf("ValidateUpdate() error = %v, wantErr %v", err, tt.wantErr) 372 } 373 }) 374 } 375 } 376 377 func TestAWSMachine_SecretsBackend(t *testing.T) { 378 baseMachine := &AWSMachine{ 379 Spec: AWSMachineSpec{ 380 ProviderID: nil, 381 AdditionalTags: nil, 382 AdditionalSecurityGroups: nil, 383 InstanceType: "test", 384 }, 385 } 386 387 tests := []struct { 388 name string 389 cloudInit CloudInit 390 expectedSecretsBackend string 391 }{ 392 { 393 name: "with insecure skip secrets manager unset", 394 cloudInit: CloudInit{InsecureSkipSecretsManager: false}, 395 expectedSecretsBackend: "secrets-manager", 396 }, 397 { 398 name: "with insecure skip secrets manager unset and secrets backend set", 399 cloudInit: CloudInit{InsecureSkipSecretsManager: false, SecureSecretsBackend: "ssm-parameter-store"}, 400 expectedSecretsBackend: "ssm-parameter-store", 401 }, 402 { 403 name: "with insecure skip secrets manager set", 404 cloudInit: CloudInit{InsecureSkipSecretsManager: true}, 405 expectedSecretsBackend: "", 406 }, 407 } 408 409 for _, tt := range tests { 410 ctx := context.TODO() 411 t.Run(tt.name, func(t *testing.T) { 412 machine := baseMachine.DeepCopy() 413 machine.ObjectMeta = metav1.ObjectMeta{ 414 GenerateName: "machine-", 415 Namespace: "default", 416 } 417 machine.Spec.CloudInit = tt.cloudInit 418 if err := testEnv.Create(ctx, machine); err != nil { 419 t.Errorf("failed to create machine: %v", err) 420 } 421 g := NewWithT(t) 422 g.Expect(machine.Spec.CloudInit.SecureSecretsBackend).To(Equal(SecretBackend(tt.expectedSecretsBackend))) 423 }) 424 } 425 }