sigs.k8s.io/cluster-api-provider-aws@v1.5.5/controllers/awsmachine_controller_test.go (about) 1 /* 2 Copyright 2019 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 controllers 18 19 import ( 20 "fmt" 21 "testing" 22 "time" 23 24 "github.com/aws/aws-sdk-go/aws" 25 "github.com/aws/aws-sdk-go/service/ec2" 26 "github.com/aws/aws-sdk-go/service/elb" 27 "github.com/golang/mock/gomock" 28 . "github.com/onsi/gomega" 29 "github.com/pkg/errors" 30 corev1 "k8s.io/api/core/v1" 31 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 32 "k8s.io/client-go/tools/record" 33 "k8s.io/utils/pointer" 34 "sigs.k8s.io/controller-runtime/pkg/client" 35 36 infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1" 37 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud" 38 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/scope" 39 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services" 40 ec2Service "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/ec2" 41 elbService "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/elb" 42 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/mock_services" 43 "sigs.k8s.io/cluster-api-provider-aws/test/mocks" 44 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 45 "sigs.k8s.io/cluster-api/util" 46 "sigs.k8s.io/cluster-api/util/conditions" 47 ) 48 49 func TestAWSMachineReconciler_IntegrationTests(t *testing.T) { 50 var ( 51 reconciler AWSMachineReconciler 52 mockCtrl *gomock.Controller 53 recorder *record.FakeRecorder 54 ) 55 56 setup := func(t *testing.T, g *WithT) { 57 t.Helper() 58 mockCtrl = gomock.NewController(t) 59 recorder = record.NewFakeRecorder(10) 60 reconciler = AWSMachineReconciler{ 61 Client: testEnv.Client, 62 Recorder: recorder, 63 } 64 } 65 66 teardown := func(g *WithT) { 67 mockCtrl.Finish() 68 } 69 70 t.Run("Should successfully reconcile control plane machine creation", func(t *testing.T) { 71 g := NewWithT(t) 72 mockCtrl = gomock.NewController(t) 73 ec2Mock := mocks.NewMockEC2API(mockCtrl) 74 secretMock := mock_services.NewMockSecretInterface(mockCtrl) 75 elbMock := mocks.NewMockELBAPI(mockCtrl) 76 77 expect := func(m *mocks.MockEC2APIMockRecorder, s *mock_services.MockSecretInterfaceMockRecorder, e *mocks.MockELBAPIMockRecorder) { 78 mockedCreateInstanceCalls(m) 79 mockedCreateSecretCall(s) 80 mockedCreateLBCalls(t, e) 81 } 82 expect(ec2Mock.EXPECT(), secretMock.EXPECT(), elbMock.EXPECT()) 83 84 ns, err := testEnv.CreateNamespace(ctx, fmt.Sprintf("integ-test-%s", util.RandomString(5))) 85 g.Expect(err).To(BeNil()) 86 87 secret := &corev1.Secret{ 88 ObjectMeta: metav1.ObjectMeta{ 89 Name: "bootstrap-data", 90 Namespace: ns.Name, 91 }, 92 Data: map[string][]byte{ 93 "value": []byte("shell-script"), 94 }, 95 } 96 g.Expect(testEnv.Create(ctx, secret)).To(Succeed()) 97 98 setup(t, g) 99 awsMachine := getAWSMachine() 100 awsMachine.Namespace = ns.Name 101 createAWSMachine(g, awsMachine) 102 103 defer teardown(g) 104 defer t.Cleanup(func() { 105 g.Expect(testEnv.Cleanup(ctx, awsMachine, ns, secret)).To(Succeed()) 106 }) 107 108 cs, err := getClusterScope(infrav1.AWSCluster{ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: infrav1.AWSClusterSpec{NetworkSpec: infrav1.NetworkSpec{Subnets: []infrav1.SubnetSpec{ 109 { 110 ID: "subnet-1", 111 AvailabilityZone: "us-east-1a", 112 }}, 113 }}}) 114 g.Expect(err).To(BeNil()) 115 cs.Cluster = &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "test-cluster"}} 116 cs.AWSCluster.Status.Network.APIServerELB.DNSName = DNSName 117 cs.AWSCluster.Status.Network.SecurityGroups = map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{ 118 infrav1.SecurityGroupNode: { 119 ID: "1", 120 }, 121 infrav1.SecurityGroupLB: { 122 ID: "2", 123 }, 124 infrav1.SecurityGroupControlPlane: { 125 ID: "3", 126 }} 127 ms, err := getMachineScope(cs, awsMachine) 128 g.Expect(err).To(BeNil()) 129 130 ms.Machine.Spec.Bootstrap.DataSecretName = aws.String("bootstrap-data") 131 ms.Machine.Spec.Version = aws.String("test") 132 ms.AWSMachine.Spec.Subnet = &infrav1.AWSResourceReference{ID: aws.String("subnet-1")} 133 ms.AWSMachine.Status.InstanceState = &infrav1.InstanceStateRunning 134 ms.Machine.Labels = map[string]string{clusterv1.MachineControlPlaneLabelName: ""} 135 136 ec2Svc := ec2Service.NewService(cs) 137 ec2Svc.EC2Client = ec2Mock 138 reconciler.ec2ServiceFactory = func(scope scope.EC2Scope) services.EC2Interface { 139 return ec2Svc 140 } 141 142 elbSvc := elbService.NewService(cs) 143 elbSvc.EC2Client = ec2Mock 144 elbSvc.ELBClient = elbMock 145 reconciler.elbServiceFactory = func(scope scope.ELBScope) services.ELBInterface { 146 return elbSvc 147 } 148 149 reconciler.secretsManagerServiceFactory = func(clusterScope cloud.ClusterScoper) services.SecretInterface { 150 return secretMock 151 } 152 153 _, err = reconciler.reconcileNormal(ctx, ms, cs, cs, cs, cs) 154 g.Expect(err).To(BeNil()) 155 expectConditions(g, ms.AWSMachine, []conditionAssertion{{infrav1.SecurityGroupsReadyCondition, corev1.ConditionTrue, "", ""}, 156 {infrav1.InstanceReadyCondition, corev1.ConditionTrue, "", ""}, 157 {infrav1.ELBAttachedCondition, corev1.ConditionTrue, "", ""}}) 158 g.Expect(ms.AWSMachine.Finalizers).Should(ContainElement(infrav1.MachineFinalizer)) 159 }) 160 t.Run("Should successfully reconcile control plane machine deletion", func(t *testing.T) { 161 g := NewWithT(t) 162 mockCtrl = gomock.NewController(t) 163 ec2Mock := mocks.NewMockEC2API(mockCtrl) 164 elbMock := mocks.NewMockELBAPI(mockCtrl) 165 166 expect := func(m *mocks.MockEC2APIMockRecorder, e *mocks.MockELBAPIMockRecorder) { 167 mockedDescribeInstanceCalls(m) 168 mockedDeleteLBCalls(e) 169 mockedDeleteInstanceCalls(m) 170 } 171 expect(ec2Mock.EXPECT(), elbMock.EXPECT()) 172 173 ns, err := testEnv.CreateNamespace(ctx, fmt.Sprintf("integ-test-%s", util.RandomString(5))) 174 g.Expect(err).To(BeNil()) 175 176 setup(t, g) 177 awsMachine := getAWSMachine() 178 awsMachine.Namespace = ns.Name 179 createAWSMachine(g, awsMachine) 180 181 defer teardown(g) 182 defer t.Cleanup(func() { 183 g.Expect(testEnv.Cleanup(ctx, awsMachine, ns)).To(Succeed()) 184 }) 185 186 cs, err := getClusterScope(infrav1.AWSCluster{ObjectMeta: metav1.ObjectMeta{Name: "test"}}) 187 g.Expect(err).To(BeNil()) 188 cs.Cluster = &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "test-cluster"}} 189 ms, err := getMachineScope(cs, awsMachine) 190 g.Expect(err).To(BeNil()) 191 192 ms.AWSMachine.Status.InstanceState = &infrav1.InstanceStateRunning 193 ms.Machine.Labels = map[string]string{clusterv1.MachineControlPlaneLabelName: ""} 194 ms.AWSMachine.Spec.ProviderID = aws.String("aws:////myMachine") 195 196 ec2Svc := ec2Service.NewService(cs) 197 ec2Svc.EC2Client = ec2Mock 198 reconciler.ec2ServiceFactory = func(scope scope.EC2Scope) services.EC2Interface { 199 return ec2Svc 200 } 201 202 elbSvc := elbService.NewService(cs) 203 elbSvc.EC2Client = ec2Mock 204 elbSvc.ELBClient = elbMock 205 reconciler.elbServiceFactory = func(scope scope.ELBScope) services.ELBInterface { 206 return elbSvc 207 } 208 209 _, err = reconciler.reconcileDelete(ms, cs, cs, cs, cs) 210 g.Expect(err).To(BeNil()) 211 expectConditions(g, ms.AWSMachine, []conditionAssertion{ 212 {infrav1.InstanceReadyCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityInfo, clusterv1.DeletedReason}, 213 {infrav1.ELBAttachedCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityInfo, clusterv1.DeletedReason}}) 214 g.Expect(ms.AWSMachine.Finalizers).ShouldNot(ContainElement(infrav1.MachineFinalizer)) 215 }) 216 t.Run("Should fail reconciling control-plane machine creation while attaching load balancer", func(t *testing.T) { 217 g := NewWithT(t) 218 mockCtrl = gomock.NewController(t) 219 ec2Mock := mocks.NewMockEC2API(mockCtrl) 220 secretMock := mock_services.NewMockSecretInterface(mockCtrl) 221 elbMock := mocks.NewMockELBAPI(mockCtrl) 222 223 expect := func(m *mocks.MockEC2APIMockRecorder, s *mock_services.MockSecretInterfaceMockRecorder, e *mocks.MockELBAPIMockRecorder) { 224 mockedCreateInstanceCalls(m) 225 mockedCreateSecretCall(s) 226 e.DescribeLoadBalancers(gomock.Eq(&elb.DescribeLoadBalancersInput{ 227 LoadBalancerNames: aws.StringSlice([]string{"test-cluster-apiserver"}), 228 })). 229 Return(&elb.DescribeLoadBalancersOutput{}, nil) 230 } 231 expect(ec2Mock.EXPECT(), secretMock.EXPECT(), elbMock.EXPECT()) 232 233 ns, err := testEnv.CreateNamespace(ctx, fmt.Sprintf("integ-test-%s", util.RandomString(5))) 234 g.Expect(err).To(BeNil()) 235 236 secret := &corev1.Secret{ 237 ObjectMeta: metav1.ObjectMeta{ 238 Name: "bootstrap-data", 239 Namespace: ns.Name, 240 }, 241 Data: map[string][]byte{ 242 "value": []byte("shell-script"), 243 }, 244 } 245 g.Expect(testEnv.Create(ctx, secret)).To(Succeed()) 246 247 setup(t, g) 248 awsMachine := getAWSMachine() 249 awsMachine.Namespace = ns.Name 250 createAWSMachine(g, awsMachine) 251 252 defer teardown(g) 253 defer t.Cleanup(func() { 254 g.Expect(testEnv.Cleanup(ctx, awsMachine, ns, secret)).To(Succeed()) 255 }) 256 257 cs, err := getClusterScope(infrav1.AWSCluster{ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: infrav1.AWSClusterSpec{NetworkSpec: infrav1.NetworkSpec{Subnets: []infrav1.SubnetSpec{ 258 { 259 ID: "subnet-1", 260 AvailabilityZone: "us-east-1a", 261 }}, 262 }}}) 263 g.Expect(err).To(BeNil()) 264 cs.Cluster = &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "test-cluster"}} 265 cs.AWSCluster.Status.Network.APIServerELB.DNSName = DNSName 266 cs.AWSCluster.Status.Network.SecurityGroups = map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{ 267 infrav1.SecurityGroupNode: { 268 ID: "1", 269 }, 270 infrav1.SecurityGroupLB: { 271 ID: "2", 272 }, 273 infrav1.SecurityGroupControlPlane: { 274 ID: "3", 275 }} 276 ms, err := getMachineScope(cs, awsMachine) 277 g.Expect(err).To(BeNil()) 278 279 ms.Machine.Spec.Bootstrap.DataSecretName = aws.String("bootstrap-data") 280 ms.Machine.Spec.Version = aws.String("test") 281 ms.AWSMachine.Spec.Subnet = &infrav1.AWSResourceReference{ID: aws.String("subnet-1")} 282 ms.AWSMachine.Status.InstanceState = &infrav1.InstanceStateRunning 283 ms.Machine.Labels = map[string]string{clusterv1.MachineControlPlaneLabelName: ""} 284 285 ec2Svc := ec2Service.NewService(cs) 286 ec2Svc.EC2Client = ec2Mock 287 reconciler.ec2ServiceFactory = func(scope scope.EC2Scope) services.EC2Interface { 288 return ec2Svc 289 } 290 291 elbSvc := elbService.NewService(cs) 292 elbSvc.EC2Client = ec2Mock 293 elbSvc.ELBClient = elbMock 294 reconciler.elbServiceFactory = func(scope scope.ELBScope) services.ELBInterface { 295 return elbSvc 296 } 297 298 reconciler.secretsManagerServiceFactory = func(clusterScope cloud.ClusterScoper) services.SecretInterface { 299 return secretMock 300 } 301 302 _, err = reconciler.reconcileNormal(ctx, ms, cs, cs, cs, cs) 303 g.Expect(err).Should(HaveOccurred()) 304 expectConditions(g, ms.AWSMachine, []conditionAssertion{{infrav1.InstanceReadyCondition, corev1.ConditionTrue, "", ""}}) 305 g.Expect(ms.AWSMachine.Finalizers).Should(ContainElement(infrav1.MachineFinalizer)) 306 }) 307 t.Run("Should fail in reconciling control-plane machine deletion while terminating instance ", func(t *testing.T) { 308 g := NewWithT(t) 309 mockCtrl = gomock.NewController(t) 310 ec2Mock := mocks.NewMockEC2API(mockCtrl) 311 elbMock := mocks.NewMockELBAPI(mockCtrl) 312 313 expect := func(m *mocks.MockEC2APIMockRecorder, e *mocks.MockELBAPIMockRecorder) { 314 mockedDescribeInstanceCalls(m) 315 mockedDeleteLBCalls(e) 316 m.TerminateInstances( 317 gomock.Eq(&ec2.TerminateInstancesInput{ 318 InstanceIds: aws.StringSlice([]string{"id-1"}), 319 }), 320 ). 321 Return(nil, errors.New("Failed to delete instance")) 322 } 323 expect(ec2Mock.EXPECT(), elbMock.EXPECT()) 324 325 ns, err := testEnv.CreateNamespace(ctx, fmt.Sprintf("integ-test-%s", util.RandomString(5))) 326 g.Expect(err).To(BeNil()) 327 328 setup(t, g) 329 awsMachine := getAWSMachine() 330 awsMachine.Namespace = ns.Name 331 createAWSMachine(g, awsMachine) 332 333 defer teardown(g) 334 defer t.Cleanup(func() { 335 g.Expect(testEnv.Cleanup(ctx, awsMachine, ns)).To(Succeed()) 336 }) 337 338 cs, err := getClusterScope(infrav1.AWSCluster{ObjectMeta: metav1.ObjectMeta{Name: "test"}}) 339 g.Expect(err).To(BeNil()) 340 cs.Cluster = &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "test-cluster"}} 341 ms, err := getMachineScope(cs, awsMachine) 342 g.Expect(err).To(BeNil()) 343 344 ms.AWSMachine.Status.InstanceState = &infrav1.InstanceStateRunning 345 ms.Machine.Labels = map[string]string{clusterv1.MachineControlPlaneLabelName: ""} 346 ms.AWSMachine.Spec.ProviderID = aws.String("aws:////myMachine") 347 348 ec2Svc := ec2Service.NewService(cs) 349 ec2Svc.EC2Client = ec2Mock 350 reconciler.ec2ServiceFactory = func(scope scope.EC2Scope) services.EC2Interface { 351 return ec2Svc 352 } 353 354 elbSvc := elbService.NewService(cs) 355 elbSvc.EC2Client = ec2Mock 356 elbSvc.ELBClient = elbMock 357 reconciler.elbServiceFactory = func(scope scope.ELBScope) services.ELBInterface { 358 return elbSvc 359 } 360 361 _, err = reconciler.reconcileDelete(ms, cs, cs, cs, cs) 362 g.Expect(err).Should(HaveOccurred()) 363 expectConditions(g, ms.AWSMachine, []conditionAssertion{{infrav1.InstanceReadyCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityWarning, "DeletingFailed"}, 364 {infrav1.ELBAttachedCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityInfo, clusterv1.DeletedReason}}) 365 g.Expect(ms.AWSMachine.Finalizers).ShouldNot(ContainElement(infrav1.MachineFinalizer)) 366 }) 367 } 368 369 func getMachineScope(cs *scope.ClusterScope, awsMachine *infrav1.AWSMachine) (*scope.MachineScope, error) { 370 return scope.NewMachineScope( 371 scope.MachineScopeParams{ 372 Client: testEnv, 373 Cluster: &clusterv1.Cluster{ 374 ObjectMeta: metav1.ObjectMeta{ 375 Name: "test", 376 }, 377 Status: clusterv1.ClusterStatus{ 378 InfrastructureReady: true, 379 }, 380 }, 381 Machine: &clusterv1.Machine{ 382 ObjectMeta: metav1.ObjectMeta{ 383 Name: "test", 384 }, 385 Spec: clusterv1.MachineSpec{ 386 Bootstrap: clusterv1.Bootstrap{ 387 DataSecretName: pointer.StringPtr("bootstrap-data"), 388 }, 389 }, 390 }, 391 InfraCluster: cs, 392 AWSMachine: awsMachine, 393 }, 394 ) 395 } 396 397 func createAWSMachine(g *WithT, awsMachine *infrav1.AWSMachine) { 398 g.Expect(testEnv.Create(ctx, awsMachine)).To(Succeed()) 399 g.Eventually(func() bool { 400 machine := &infrav1.AWSMachine{} 401 key := client.ObjectKey{ 402 Name: awsMachine.Name, 403 Namespace: awsMachine.Namespace, 404 } 405 return testEnv.Get(ctx, key, machine) == nil 406 }, 10*time.Second).Should(Equal(true)) 407 } 408 409 func getAWSMachine() *infrav1.AWSMachine { 410 return &infrav1.AWSMachine{ 411 ObjectMeta: metav1.ObjectMeta{ 412 Name: "test", 413 }, 414 Spec: infrav1.AWSMachineSpec{ 415 CloudInit: infrav1.CloudInit{ 416 SecureSecretsBackend: infrav1.SecretBackendSecretsManager, 417 SecretPrefix: "prefix", 418 SecretCount: 1000, 419 }, 420 InstanceType: "test", 421 Subnet: &infrav1.AWSResourceReference{ID: aws.String("subnet-1")}, 422 }, 423 } 424 } 425 426 func getAWSMachineWithAdditionalTags() *infrav1.AWSMachine { 427 return &infrav1.AWSMachine{ 428 ObjectMeta: metav1.ObjectMeta{ 429 Name: "test", 430 }, 431 Spec: infrav1.AWSMachineSpec{ 432 CloudInit: infrav1.CloudInit{ 433 SecureSecretsBackend: infrav1.SecretBackendSecretsManager, 434 }, 435 AdditionalTags: map[string]string{"foo": "bar"}, 436 }, 437 } 438 } 439 440 func PointsTo(s string) gomock.Matcher { 441 return &pointsTo{ 442 val: s, 443 } 444 } 445 446 type pointsTo struct { 447 val string 448 } 449 450 func (p *pointsTo) Matches(x interface{}) bool { 451 ptr, ok := x.(*string) 452 if !ok { 453 return false 454 } 455 456 if ptr == nil { 457 return false 458 } 459 460 return *ptr == p.val 461 } 462 463 func (p *pointsTo) String() string { 464 return fmt.Sprintf("Pointer to string %q", p.val) 465 } 466 467 type conditionAssertion struct { 468 conditionType clusterv1.ConditionType 469 status corev1.ConditionStatus 470 severity clusterv1.ConditionSeverity 471 reason string 472 } 473 474 func expectConditions(g *WithT, m *infrav1.AWSMachine, expected []conditionAssertion) { 475 g.Expect(len(m.Status.Conditions)).To(BeNumerically(">=", len(expected)), "number of conditions") 476 for _, c := range expected { 477 actual := conditions.Get(m, c.conditionType) 478 g.Expect(actual).To(Not(BeNil())) 479 g.Expect(actual.Type).To(Equal(c.conditionType)) 480 g.Expect(actual.Status).To(Equal(c.status)) 481 g.Expect(actual.Severity).To(Equal(c.severity)) 482 g.Expect(actual.Reason).To(Equal(c.reason)) 483 } 484 } 485 486 func mockedCreateSecretCall(s *mock_services.MockSecretInterfaceMockRecorder) { 487 s.Create(gomock.AssignableToTypeOf(&scope.MachineScope{}), gomock.AssignableToTypeOf([]byte{})) 488 s.UserData(gomock.Any(), gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf([]scope.ServiceEndpoint{})) 489 } 490 491 func mockedCreateInstanceCalls(m *mocks.MockEC2APIMockRecorder) { 492 m.DescribeInstances(gomock.Eq(&ec2.DescribeInstancesInput{ 493 Filters: []*ec2.Filter{ 494 { 495 Name: aws.String("vpc-id"), 496 Values: aws.StringSlice([]string{""}), 497 }, 498 { 499 Name: aws.String("tag:sigs.k8s.io/cluster-api-provider-aws/cluster/test-cluster"), 500 Values: aws.StringSlice([]string{"owned"}), 501 }, 502 { 503 Name: aws.String("tag:Name"), 504 Values: aws.StringSlice([]string{"test"}), 505 }, 506 { 507 Name: aws.String("instance-state-name"), 508 Values: aws.StringSlice([]string{"pending", "running"}), 509 }, 510 }, 511 })).Return(&ec2.DescribeInstancesOutput{}, nil) 512 m.DescribeImages(gomock.Eq(&ec2.DescribeImagesInput{ 513 Filters: []*ec2.Filter{ 514 { 515 Name: aws.String("owner-id"), 516 Values: aws.StringSlice([]string{"258751437250"}), 517 }, 518 { 519 Name: aws.String("name"), 520 Values: aws.StringSlice([]string{"capa-ami-ubuntu-18.04-?test-*"}), 521 }, 522 { 523 Name: aws.String("architecture"), 524 Values: aws.StringSlice([]string{"x86_64"}), 525 }, 526 { 527 Name: aws.String("state"), 528 Values: aws.StringSlice([]string{"available"}), 529 }, 530 { 531 Name: aws.String("virtualization-type"), 532 Values: aws.StringSlice([]string{"hvm"}), 533 }, 534 }})).Return(&ec2.DescribeImagesOutput{Images: []*ec2.Image{ 535 { 536 ImageId: aws.String("latest"), 537 CreationDate: aws.String("2019-02-08T17:02:31.000Z"), 538 }, 539 }}, nil) 540 m.RunInstances(gomock.Any()).Return(&ec2.Reservation{ 541 Instances: []*ec2.Instance{ 542 { 543 State: &ec2.InstanceState{ 544 Name: aws.String(ec2.InstanceStateNameRunning), 545 }, 546 IamInstanceProfile: &ec2.IamInstanceProfile{ 547 Arn: aws.String("arn:aws:iam::123456789012:instance-profile/foo"), 548 }, 549 InstanceId: aws.String("two"), 550 InstanceType: aws.String("m5.large"), 551 SubnetId: aws.String("subnet-1"), 552 ImageId: aws.String("ami-1"), 553 RootDeviceName: aws.String("device-1"), 554 BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{ 555 { 556 DeviceName: aws.String("device-1"), 557 Ebs: &ec2.EbsInstanceBlockDevice{ 558 VolumeId: aws.String("volume-1"), 559 }, 560 }, 561 }, 562 Placement: &ec2.Placement{ 563 AvailabilityZone: aws.String("us-east-1a"), 564 }, 565 }, 566 }, 567 }, nil) 568 m.WaitUntilInstanceRunningWithContext(gomock.Any(), gomock.Any(), gomock.Any()). 569 Return(nil) 570 m.DescribeNetworkInterfaces(gomock.Eq(&ec2.DescribeNetworkInterfacesInput{Filters: []*ec2.Filter{ 571 { 572 Name: aws.String("attachment.instance-id"), 573 Values: aws.StringSlice([]string{"two"}), 574 }, 575 }})).Return(&ec2.DescribeNetworkInterfacesOutput{ 576 NetworkInterfaces: []*ec2.NetworkInterface{ 577 { 578 NetworkInterfaceId: aws.String("eni-1"), 579 Groups: []*ec2.GroupIdentifier{ 580 { 581 GroupId: aws.String("3"), 582 }, 583 }, 584 }, 585 }}, nil).MaxTimes(2) 586 m.DescribeNetworkInterfaceAttribute(gomock.Eq(&ec2.DescribeNetworkInterfaceAttributeInput{ 587 NetworkInterfaceId: aws.String("eni-1"), 588 Attribute: aws.String("groupSet"), 589 })).Return(&ec2.DescribeNetworkInterfaceAttributeOutput{Groups: []*ec2.GroupIdentifier{{GroupId: aws.String("3")}}}, nil).MaxTimes(1) 590 m.ModifyNetworkInterfaceAttribute(gomock.Any()).AnyTimes() 591 m.DescribeSubnets(gomock.Eq(&ec2.DescribeSubnetsInput{Filters: []*ec2.Filter{ 592 { 593 Name: aws.String("state"), 594 Values: aws.StringSlice([]string{"pending", "available"}), 595 }, 596 { 597 Name: aws.String("vpc-id"), 598 Values: aws.StringSlice([]string{""}), 599 }, 600 { 601 Name: aws.String("subnet-id"), 602 Values: aws.StringSlice([]string{"subnet-1"}), 603 }, 604 }})).Return(&ec2.DescribeSubnetsOutput{Subnets: []*ec2.Subnet{ 605 { 606 SubnetId: aws.String("subnet-1"), 607 }, 608 }}, nil) 609 } 610 611 func mockedDescribeInstanceCalls(m *mocks.MockEC2APIMockRecorder) { 612 m.DescribeInstances(gomock.Eq(&ec2.DescribeInstancesInput{ 613 InstanceIds: aws.StringSlice([]string{"myMachine"}), 614 })).Return(&ec2.DescribeInstancesOutput{ 615 Reservations: []*ec2.Reservation{{Instances: []*ec2.Instance{{Placement: &ec2.Placement{AvailabilityZone: aws.String("us-east-1a")}, InstanceId: aws.String("id-1"), State: &ec2.InstanceState{Name: aws.String("id-1"), Code: aws.Int64(16)}}}}}, 616 }, nil) 617 }