@@ -36,7 +36,7 @@ import (
36
36
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
37
37
)
38
38
39
- func TestDeleteBastion (t * testing.T ) {
39
+ func TestService_DeleteBastion (t * testing.T ) {
40
40
clusterName := "cluster"
41
41
42
42
describeInput := & ec2.DescribeInstancesInput {
@@ -225,3 +225,239 @@ func TestDeleteBastion(t *testing.T) {
225
225
}
226
226
}
227
227
}
228
+
229
+ func TestService_ReconcileBastion (t * testing.T ) {
230
+ clusterName := "cluster"
231
+
232
+ describeInput := & ec2.DescribeInstancesInput {
233
+ Filters : []* ec2.Filter {
234
+ filter .EC2 .ProviderRole (infrav1 .BastionRoleTagValue ),
235
+ filter .EC2 .Cluster (clusterName ),
236
+ filter .EC2 .InstanceStates (
237
+ ec2 .InstanceStateNamePending ,
238
+ ec2 .InstanceStateNameRunning ,
239
+ ec2 .InstanceStateNameStopping ,
240
+ ec2 .InstanceStateNameStopped ,
241
+ ),
242
+ },
243
+ }
244
+
245
+ foundOutput := & ec2.DescribeInstancesOutput {
246
+ Reservations : []* ec2.Reservation {
247
+ {
248
+ Instances : []* ec2.Instance {
249
+ {
250
+ InstanceId : aws .String ("id123" ),
251
+ State : & ec2.InstanceState {
252
+ Name : aws .String (ec2 .InstanceStateNameRunning ),
253
+ },
254
+ Placement : & ec2.Placement {
255
+ AvailabilityZone : aws .String ("us-east-1" ),
256
+ },
257
+ },
258
+ },
259
+ },
260
+ },
261
+ }
262
+
263
+ tests := []struct {
264
+ name string
265
+ bastionEnabled bool
266
+ expect func (m * mock_ec2iface.MockEC2APIMockRecorder )
267
+ expectError bool
268
+ bastionStatus * infrav1.Instance
269
+ }{
270
+ {
271
+ name : "Should ignore reconciliation if instance not found" ,
272
+ expect : func (m * mock_ec2iface.MockEC2APIMockRecorder ) {
273
+ m .
274
+ DescribeInstances (gomock .Eq (describeInput )).
275
+ Return (& ec2.DescribeInstancesOutput {}, nil )
276
+ },
277
+ expectError : false ,
278
+ },
279
+ {
280
+ name : "Should fail reconcile if describe instance fails" ,
281
+ expect : func (m * mock_ec2iface.MockEC2APIMockRecorder ) {
282
+ m .
283
+ DescribeInstances (gomock .Eq (describeInput )).
284
+ Return (nil , errors .New ("some error" ))
285
+ },
286
+ expectError : true ,
287
+ },
288
+ {
289
+ name : "Should fail reconcile if terminate instance fails" ,
290
+ expect : func (m * mock_ec2iface.MockEC2APIMockRecorder ) {
291
+ m .
292
+ DescribeInstances (gomock .Eq (describeInput )).
293
+ Return (foundOutput , nil ).MinTimes (1 )
294
+ m .
295
+ TerminateInstances (
296
+ gomock .Eq (& ec2.TerminateInstancesInput {
297
+ InstanceIds : aws .StringSlice ([]string {"id123" }),
298
+ }),
299
+ ).
300
+ Return (nil , errors .New ("some error" ))
301
+ },
302
+ expectError : true ,
303
+ },
304
+ {
305
+ name : "Should create bastion successfully" ,
306
+ expect : func (m * mock_ec2iface.MockEC2APIMockRecorder ) {
307
+ m .DescribeInstances (gomock .Eq (describeInput )).
308
+ Return (& ec2.DescribeInstancesOutput {}, nil ).MinTimes (1 )
309
+ m .DescribeImages (gomock .Eq (& ec2.DescribeImagesInput {Filters : []* ec2.Filter {
310
+ {
311
+ Name : aws .String ("owner-id" ),
312
+ Values : aws .StringSlice ([]string {ubuntuOwnerID }),
313
+ },
314
+ {
315
+ Name : aws .String ("architecture" ),
316
+ Values : aws .StringSlice ([]string {"x86_64" }),
317
+ },
318
+ {
319
+ Name : aws .String ("state" ),
320
+ Values : aws .StringSlice ([]string {"available" }),
321
+ },
322
+ {
323
+ Name : aws .String ("virtualization-type" ),
324
+ Values : aws .StringSlice ([]string {"hvm" }),
325
+ },
326
+ {
327
+ Name : aws .String ("description" ),
328
+ Values : aws .StringSlice ([]string {ubuntuImageDescription }),
329
+ },
330
+ }})).Return (& ec2.DescribeImagesOutput {Images : images {
331
+ {
332
+ ImageId : aws .String ("ubuntu-ami-id-latest" ),
333
+ CreationDate : aws .String ("2019-02-08T17:02:31.000Z" ),
334
+ },
335
+ {
336
+ ImageId : aws .String ("ubuntu-ami-id-old" ),
337
+ CreationDate : aws .String ("2014-02-08T17:02:31.000Z" ),
338
+ },
339
+ }}, nil )
340
+ m .RunInstances (gomock .Any ()).
341
+ Return (& ec2.Reservation {
342
+ Instances : []* ec2.Instance {
343
+ {
344
+ State : & ec2.InstanceState {
345
+ Name : aws .String (ec2 .InstanceStateNameRunning ),
346
+ },
347
+ IamInstanceProfile : & ec2.IamInstanceProfile {
348
+ Arn : aws .String ("arn:aws:iam::123456789012:instance-profile/foo" ),
349
+ },
350
+ InstanceId : aws .String ("id123" ),
351
+ InstanceType : aws .String ("t3.micro" ),
352
+ SubnetId : aws .String ("subnet-1" ),
353
+ ImageId : aws .String ("ubuntu-ami-id-latest" ),
354
+ RootDeviceName : aws .String ("device-1" ),
355
+ BlockDeviceMappings : []* ec2.InstanceBlockDeviceMapping {
356
+ {
357
+ DeviceName : aws .String ("device-1" ),
358
+ Ebs : & ec2.EbsInstanceBlockDevice {
359
+ VolumeId : aws .String ("volume-1" ),
360
+ },
361
+ },
362
+ },
363
+ Placement : & ec2.Placement {
364
+ AvailabilityZone : aws .String ("us-east-1" ),
365
+ },
366
+ },
367
+ },
368
+ }, nil )
369
+ m .WaitUntilInstanceRunningWithContext (gomock .Any (), gomock .Any (), gomock .Any ()).
370
+ Return (nil )
371
+ },
372
+ bastionEnabled : true ,
373
+ expectError : false ,
374
+ bastionStatus : & infrav1.Instance {
375
+ ID : "id123" ,
376
+ State : "running" ,
377
+ Type : "t3.micro" ,
378
+ SubnetID : "subnet-1" ,
379
+ ImageID : "ubuntu-ami-id-latest" ,
380
+ IAMProfile : "foo" ,
381
+ Addresses : []clusterv1.MachineAddress {},
382
+ AvailabilityZone : "us-east-1" ,
383
+ VolumeIDs : []string {"volume-1" },
384
+ },
385
+ },
386
+ }
387
+
388
+ for _ , tc := range tests {
389
+ managedValues := []bool {false , true }
390
+ for i := range managedValues {
391
+ managed := managedValues [i ]
392
+
393
+ t .Run (fmt .Sprintf ("managed=%t %s" , managed , tc .name ), func (t * testing.T ) {
394
+ g := NewWithT (t )
395
+
396
+ mockControl := gomock .NewController (t )
397
+ defer mockControl .Finish ()
398
+
399
+ ec2Mock := mock_ec2iface .NewMockEC2API (mockControl )
400
+
401
+ scheme , err := setupScheme ()
402
+ g .Expect (err ).To (BeNil ())
403
+
404
+ awsCluster := & infrav1.AWSCluster {
405
+ ObjectMeta : metav1.ObjectMeta {Name : "test" },
406
+ Spec : infrav1.AWSClusterSpec {
407
+ NetworkSpec : infrav1.NetworkSpec {
408
+ VPC : infrav1.VPCSpec {
409
+ ID : "vpcID" ,
410
+ },
411
+ Subnets : infrav1.Subnets {
412
+ {
413
+ ID : "subnet-1" ,
414
+ },
415
+ {
416
+ ID : "subnet-2" ,
417
+ IsPublic : true ,
418
+ },
419
+ },
420
+ },
421
+ Bastion : infrav1.Bastion {Enabled : tc .bastionEnabled },
422
+ },
423
+ }
424
+
425
+ client := fake .NewClientBuilder ().WithScheme (scheme ).Build ()
426
+ ctx := context .TODO ()
427
+ client .Create (ctx , awsCluster )
428
+
429
+ scope , err := scope .NewClusterScope (scope.ClusterScopeParams {
430
+ Cluster : & clusterv1.Cluster {
431
+ ObjectMeta : metav1.ObjectMeta {
432
+ Namespace : "ns" ,
433
+ Name : clusterName ,
434
+ },
435
+ },
436
+ AWSCluster : awsCluster ,
437
+ Client : client ,
438
+ })
439
+ g .Expect (err ).To (BeNil ())
440
+
441
+ if managed {
442
+ scope .AWSCluster .Spec .NetworkSpec .VPC .Tags = infrav1.Tags {
443
+ infrav1 .ClusterTagKey (clusterName ): string (infrav1 .ResourceLifecycleOwned ),
444
+ }
445
+ }
446
+
447
+ tc .expect (ec2Mock .EXPECT ())
448
+ s := NewService (scope )
449
+ s .EC2Client = ec2Mock
450
+
451
+ err = s .ReconcileBastion ()
452
+ if tc .expectError {
453
+ g .Expect (err ).NotTo (BeNil ())
454
+ return
455
+ }
456
+
457
+ g .Expect (err ).To (BeNil ())
458
+
459
+ g .Expect (scope .AWSCluster .Status .Bastion ).To (BeEquivalentTo (tc .bastionStatus ))
460
+ })
461
+ }
462
+ }
463
+ }
0 commit comments