sigs.k8s.io/cluster-api-provider-aws@v1.5.5/test/e2e/shared/aws.go (about) 1 //go:build e2e 2 // +build e2e 3 4 /* 5 Copyright 2020 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package shared 21 22 import ( 23 "bytes" 24 "context" 25 b64 "encoding/base64" 26 "errors" 27 "fmt" 28 "os" 29 "os/exec" 30 "path" 31 "path/filepath" 32 "strings" 33 "time" 34 35 "github.com/aws/aws-sdk-go/aws" 36 "github.com/aws/aws-sdk-go/aws/client" 37 awscreds "github.com/aws/aws-sdk-go/aws/credentials" 38 "github.com/aws/aws-sdk-go/aws/session" 39 cfn "github.com/aws/aws-sdk-go/service/cloudformation" 40 "github.com/aws/aws-sdk-go/service/cloudtrail" 41 "github.com/aws/aws-sdk-go/service/configservice" 42 "github.com/aws/aws-sdk-go/service/ec2" 43 "github.com/aws/aws-sdk-go/service/ecrpublic" 44 "github.com/aws/aws-sdk-go/service/efs" 45 "github.com/aws/aws-sdk-go/service/eks" 46 "github.com/aws/aws-sdk-go/service/elb" 47 "github.com/aws/aws-sdk-go/service/iam" 48 "github.com/aws/aws-sdk-go/service/servicequotas" 49 cfn_iam "github.com/awslabs/goformation/v4/cloudformation/iam" 50 . "github.com/onsi/ginkgo" 51 . "github.com/onsi/gomega" 52 "k8s.io/utils/pointer" 53 "sigs.k8s.io/yaml" 54 55 cfn_bootstrap "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/cloudformation/bootstrap" 56 cloudformation "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/cloudformation/service" 57 "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/credentials" 58 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/awserrors" 59 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/filter" 60 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/wait" 61 ) 62 63 type AWSInfrastructureSpec struct { 64 ClusterName string `json:"clustername"` 65 VpcCidr string `json:"vpcCidr"` 66 PublicSubnetCidr string `json:"publicSubnetCidr"` 67 PrivateSubnetCidr string `json:"privateSubnetCidr"` 68 AvailabilityZone string `json:"availabilityZone"` 69 ExternalSecurityGroups bool `json:"externalSecurityGroups"` 70 } 71 72 type AWSInfrastructureState struct { 73 PrivateSubnetID *string `json:"privateSubnetID"` 74 PrivateSubnetState *string `json:"privateSubnetState"` 75 PublicSubnetID *string `json:"publicSubnetID"` 76 PublicSubnetState *string `json:"publicSubnetState"` 77 VpcState *string `json:"vpcState"` 78 NatGatewayState *string `json:"natGatewayState"` 79 PublicRouteTableID *string `json:"publicRouteTableID"` 80 PrivateRouteTableID *string `json:"privateRouteTableID"` 81 } 82 type AWSInfrastructure struct { 83 Spec AWSInfrastructureSpec `json:"spec"` 84 Context *E2EContext 85 VPC *ec2.Vpc 86 Subnets []*ec2.Subnet 87 RouteTables []*ec2.RouteTable 88 InternetGateway *ec2.InternetGateway 89 ElasticIP *ec2.Address 90 NatGateway *ec2.NatGateway 91 State AWSInfrastructureState `json:"state"` 92 Peering *ec2.VpcPeeringConnection 93 } 94 95 func (i *AWSInfrastructure) New(ais AWSInfrastructureSpec, e2eCtx *E2EContext) AWSInfrastructure { 96 i.Spec = ais 97 i.Context = e2eCtx 98 return *i 99 } 100 101 func (i *AWSInfrastructure) CreateVPC() AWSInfrastructure { 102 cv, err := CreateVPC(i.Context, i.Spec.ClusterName+"-vpc", i.Spec.VpcCidr) 103 if err != nil { 104 return *i 105 } 106 107 i.VPC = cv 108 i.State.VpcState = cv.State 109 return *i 110 } 111 112 func (i *AWSInfrastructure) RefreshVPCState() AWSInfrastructure { 113 vpc, err := GetVPC(i.Context, *i.VPC.VpcId) 114 if err != nil { 115 return *i 116 } 117 if vpc != nil { 118 i.VPC = vpc 119 i.State.VpcState = vpc.State 120 } 121 return *i 122 } 123 124 func (i *AWSInfrastructure) CreatePublicSubnet() AWSInfrastructure { 125 subnet, err := CreateSubnet(i.Context, i.Spec.ClusterName, i.Spec.PublicSubnetCidr, i.Spec.AvailabilityZone, *i.VPC.VpcId, "public") 126 if err != nil { 127 i.State.PublicSubnetState = pointer.String("failed") 128 return *i 129 } 130 i.State.PublicSubnetID = subnet.SubnetId 131 i.State.PublicSubnetState = subnet.State 132 i.Subnets = append(i.Subnets, subnet) 133 return *i 134 } 135 136 func (i *AWSInfrastructure) CreatePrivateSubnet() AWSInfrastructure { 137 subnet, err := CreateSubnet(i.Context, i.Spec.ClusterName, i.Spec.PrivateSubnetCidr, i.Spec.AvailabilityZone, *i.VPC.VpcId, "private") 138 if err != nil { 139 i.State.PrivateSubnetState = pointer.String("failed") 140 return *i 141 } 142 i.State.PrivateSubnetID = subnet.SubnetId 143 i.State.PrivateSubnetState = subnet.State 144 i.Subnets = append(i.Subnets, subnet) 145 return *i 146 } 147 148 func (i *AWSInfrastructure) CreateInternetGateway() AWSInfrastructure { 149 igwC, err := CreateInternetGateway(i.Context, i.Spec.ClusterName+"-igw") 150 if err != nil { 151 return *i 152 } 153 _, aerr := AttachInternetGateway(i.Context, *igwC.InternetGatewayId, *i.VPC.VpcId) 154 if aerr != nil { 155 i.InternetGateway = igwC 156 return *i 157 } 158 i.InternetGateway = igwC 159 return *i 160 } 161 162 func (i *AWSInfrastructure) AllocateAddress() AWSInfrastructure { 163 aa, err := AllocateAddress(i.Context, i.Spec.ClusterName+"-eip") 164 if err != nil { 165 return *i 166 } 167 168 t := 0 169 addr, _ := GetAddress(i.Context, *aa.AllocationId) 170 for addr == nil && t < 180 { 171 time.Sleep(1 * time.Second) 172 addr, _ = GetAddress(i.Context, *aa.AllocationId) 173 t++ 174 } 175 i.ElasticIP = addr 176 return *i 177 } 178 179 func (i *AWSInfrastructure) CreateNatGateway(ct string) AWSInfrastructure { 180 t := 0 181 s, serr := GetSubnetByName(i.Context, i.Spec.ClusterName+"-subnet-"+ct) 182 if serr != nil { 183 return *i 184 } 185 for s == nil && t < 180 { 186 time.Sleep(1 * time.Second) 187 s, _ = GetSubnetByName(i.Context, i.Spec.ClusterName+"-subnet-"+ct) 188 t++ 189 } 190 if s == nil { 191 return *i 192 } 193 ngwC, ngwce := CreateNatGateway(i.Context, i.Spec.ClusterName+"-nat", ct, *i.ElasticIP.AllocationId, *s.SubnetId) 194 if ngwce != nil { 195 return *i 196 } 197 if WaitForNatGatewayState(i.Context, *ngwC.NatGatewayId, 180, "available") { 198 ngw, _ := GetNatGateway(i.Context, *ngwC.NatGatewayId) 199 i.NatGateway = ngw 200 i.State.NatGatewayState = ngw.State 201 return *i 202 } 203 i.NatGateway = ngwC 204 return *i 205 } 206 207 func (i *AWSInfrastructure) CreateRouteTable(subnetType string) AWSInfrastructure { 208 rt, err := CreateRouteTable(i.Context, i.Spec.ClusterName+"-rt-"+subnetType, *i.VPC.VpcId) 209 if err != nil { 210 return *i 211 } 212 switch subnetType { 213 case "public": 214 if a, _ := AssociateRouteTable(i.Context, *rt.RouteTableId, *i.State.PublicSubnetID); a != nil { 215 i.State.PublicRouteTableID = rt.RouteTableId 216 } 217 case "private": 218 if a, _ := AssociateRouteTable(i.Context, *rt.RouteTableId, *i.State.PrivateSubnetID); a != nil { 219 i.State.PrivateRouteTableID = rt.RouteTableId 220 } 221 } 222 return *i 223 } 224 225 func (i *AWSInfrastructure) GetRouteTable(rtID string) AWSInfrastructure { 226 rt, err := GetRouteTable(i.Context, rtID) 227 if err != nil { 228 return *i 229 } 230 if rt != nil { 231 i.RouteTables = append(i.RouteTables, rt) 232 } 233 return *i 234 } 235 236 // CreateInfrastructure creates a VPC, two subnets with appropriate tags based on type(private/public) 237 // an internet gateway, an elastic IP address, a NAT gateway, a route table for each subnet and 238 // routes to their respective gateway. 239 func (i *AWSInfrastructure) CreateInfrastructure() AWSInfrastructure { 240 i.CreateVPC() 241 Byf("Created VPC - %s", *i.VPC.VpcId) 242 if i.VPC != nil { 243 i.CreatePublicSubnet() 244 if i.State.PublicSubnetID != nil { 245 Byf("Created Public Subnet - %s", *i.State.PublicSubnetID) 246 } 247 i.CreatePrivateSubnet() 248 if i.State.PrivateSubnetID != nil { 249 Byf("Created Private Subnet - %s", *i.State.PrivateSubnetID) 250 } 251 for t := 0; t < 30; t++ { 252 if *i.RefreshVPCState().State.VpcState == "available" { 253 break 254 } 255 time.Sleep(1 * time.Second) 256 } 257 i.CreateInternetGateway() 258 if i.InternetGateway != nil { 259 Byf("Created Internet Gateway - %s", *i.InternetGateway.InternetGatewayId) 260 } 261 } 262 i.AllocateAddress() 263 if i.ElasticIP != nil && i.ElasticIP.AllocationId != nil { 264 Byf("Created Elastic IP - %s", *i.ElasticIP.AllocationId) 265 i.CreateNatGateway("public") 266 if i.NatGateway != nil && i.NatGateway.NatGatewayId != nil { 267 WaitForNatGatewayState(i.Context, *i.NatGateway.NatGatewayId, 180, "available") 268 Byf("Created NAT Gateway - %s", *i.NatGateway.NatGatewayId) 269 } 270 } 271 if len(i.Subnets) == 2 { 272 i.CreateRouteTable("public") 273 if i.State.PublicRouteTableID != nil { 274 Byf("Created public route table - %s", *i.State.PublicRouteTableID) 275 } 276 i.CreateRouteTable("private") 277 if i.State.PrivateRouteTableID != nil { 278 Byf("Created private route table - %s", *i.State.PrivateRouteTableID) 279 } 280 if i.InternetGateway != nil && i.InternetGateway.InternetGatewayId != nil { 281 CreateRoute(i.Context, *i.State.PublicRouteTableID, "0.0.0.0/0", nil, i.InternetGateway.InternetGatewayId, nil) 282 } 283 if i.NatGateway != nil && i.NatGateway.NatGatewayId != nil { 284 CreateRoute(i.Context, *i.State.PrivateRouteTableID, "0.0.0.0/0", i.NatGateway.NatGatewayId, nil, nil) 285 } 286 if i.State.PublicRouteTableID != nil { 287 i.GetRouteTable(*i.State.PublicRouteTableID) 288 } 289 if i.State.PrivateRouteTableID != nil { 290 i.GetRouteTable(*i.State.PrivateRouteTableID) 291 } 292 } 293 return *i 294 } 295 296 // DeleteInfrastructure has calls added to discover and delete potential orphaned resources created 297 // by CAPA. In an attempt to avoid dependency violations it works in the following order 298 // Instances, Load Balancers, Route Tables, NAT gateway, Elastic IP, Internet Gateway, 299 // Security Group Rules, Security Groups, Subnets, VPC. 300 func (i *AWSInfrastructure) DeleteInfrastructure() { 301 instances, _ := ListClusterEC2Instances(i.Context, i.Spec.ClusterName) 302 for _, instance := range instances { 303 if instance.State.Code != aws.Int64(48) { 304 Byf("Deleting orphaned instance: %s - %v", *instance.InstanceId, TerminateInstance(i.Context, *instance.InstanceId)) 305 } 306 } 307 WaitForInstanceState(i.Context, i.Spec.ClusterName, 300, "terminated") 308 309 loadbalancers, _ := ListLoadBalancers(i.Context, i.Spec.ClusterName) 310 for _, lb := range loadbalancers { 311 Byf("Deleting orphaned load balancer: %s - %v", *lb.LoadBalancerName, DeleteLoadBalancer(i.Context, *lb.LoadBalancerName)) 312 } 313 314 for _, rt := range i.RouteTables { 315 for _, a := range rt.Associations { 316 Byf("Disassociating route table - %s - %v", *a.RouteTableAssociationId, DisassociateRouteTable(i.Context, *a.RouteTableAssociationId)) 317 } 318 Byf("Deleting route table - %s - %v", *rt.RouteTableId, DeleteRouteTable(i.Context, *rt.RouteTableId)) 319 } 320 321 if i.NatGateway != nil { 322 Byf("Deleting NAT Gateway - %s - %v", *i.NatGateway.NatGatewayId, DeleteNatGateway(i.Context, *i.NatGateway.NatGatewayId)) 323 WaitForNatGatewayState(i.Context, *i.NatGateway.NatGatewayId, 180, "deleted") 324 } 325 326 if i.ElasticIP != nil { 327 Byf("Deleting Elastic IP - %s - %v", *i.ElasticIP.AllocationId, ReleaseAddress(i.Context, *i.ElasticIP.AllocationId)) 328 } 329 330 if i.InternetGateway != nil { 331 Byf("Detaching Internet Gateway - %s - %v", *i.InternetGateway.InternetGatewayId, DetachInternetGateway(i.Context, *i.InternetGateway.InternetGatewayId, *i.VPC.VpcId)) 332 Byf("Deleting Internet Gateway - %s - %v", *i.InternetGateway.InternetGatewayId, DeleteInternetGateway(i.Context, *i.InternetGateway.InternetGatewayId)) 333 } 334 335 sgGroups, _ := GetSecurityGroupsByVPC(i.Context, *i.VPC.VpcId) 336 for _, sg := range sgGroups { 337 if *sg.GroupName != "default" { 338 sgRules, _ := ListSecurityGroupRules(i.Context, *sg.GroupId) 339 for _, sgr := range sgRules { 340 var d bool 341 if *sgr.IsEgress { 342 for d = DeleteSecurityGroupRule(i.Context, *sgr.GroupId, *sgr.SecurityGroupRuleId, "egress"); !d; { 343 d = DeleteSecurityGroupRule(i.Context, *sgr.GroupId, *sgr.SecurityGroupRuleId, "egress") 344 } 345 Byf("Deleting Egress Security Group Rule - %s - %v", *sgr.SecurityGroupRuleId, d) 346 } else { 347 for d = DeleteSecurityGroupRule(i.Context, *sgr.GroupId, *sgr.SecurityGroupRuleId, "ingress"); !d; { 348 d = DeleteSecurityGroupRule(i.Context, *sgr.GroupId, *sgr.SecurityGroupRuleId, "ingress") 349 } 350 Byf("Deleting Ingress Security Group Rule - %s - %v", *sgr.SecurityGroupRuleId, d) 351 } 352 } 353 } 354 } 355 356 sgGroups, _ = GetSecurityGroupsByVPC(i.Context, *i.VPC.VpcId) 357 for _, sg := range sgGroups { 358 if *sg.GroupName != "default" { 359 Byf("Deleting Security Group - %s - %v", *sg.GroupId, DeleteSecurityGroup(i.Context, *sg.GroupId)) 360 } 361 } 362 363 for _, subnet := range i.Subnets { 364 Byf("Deleting Subnet - %s - %v", *subnet.SubnetId, DeleteSubnet(i.Context, *subnet.SubnetId)) 365 } 366 367 if i.VPC != nil { 368 Byf("Deleting VPC - %s - %v", *i.VPC.VpcId, DeleteVPC(i.Context, *i.VPC.VpcId)) 369 } 370 } 371 372 func NewAWSSession() client.ConfigProvider { 373 By("Getting an AWS IAM session - from environment") 374 region, err := credentials.ResolveRegion("") 375 Expect(err).NotTo(HaveOccurred()) 376 config := aws.NewConfig().WithCredentialsChainVerboseErrors(true).WithRegion(region) 377 sess, err := session.NewSessionWithOptions(session.Options{ 378 SharedConfigState: session.SharedConfigEnable, 379 Config: *config, 380 }) 381 Expect(err).NotTo(HaveOccurred()) 382 _, err = sess.Config.Credentials.Get() 383 Expect(err).NotTo(HaveOccurred()) 384 return sess 385 } 386 387 func NewAWSSessionRepoWithKey(accessKey *iam.AccessKey) client.ConfigProvider { 388 By("Getting an AWS IAM session - from access key") 389 config := aws.NewConfig().WithCredentialsChainVerboseErrors(true).WithRegion("us-east-1") 390 config.Credentials = awscreds.NewStaticCredentials(*accessKey.AccessKeyId, *accessKey.SecretAccessKey, "") 391 392 sess, err := session.NewSessionWithOptions(session.Options{ 393 Config: *config, 394 }) 395 Expect(err).NotTo(HaveOccurred()) 396 _, err = sess.Config.Credentials.Get() 397 Expect(err).NotTo(HaveOccurred()) 398 return sess 399 } 400 401 func NewAWSSessionWithKey(accessKey *iam.AccessKey) client.ConfigProvider { 402 By("Getting an AWS IAM session - from access key") 403 region, err := credentials.ResolveRegion("") 404 Expect(err).NotTo(HaveOccurred()) 405 config := aws.NewConfig().WithCredentialsChainVerboseErrors(true).WithRegion(region) 406 config.Credentials = awscreds.NewStaticCredentials(*accessKey.AccessKeyId, *accessKey.SecretAccessKey, "") 407 408 sess, err := session.NewSessionWithOptions(session.Options{ 409 Config: *config, 410 }) 411 Expect(err).NotTo(HaveOccurred()) 412 _, err = sess.Config.Credentials.Get() 413 Expect(err).NotTo(HaveOccurred()) 414 return sess 415 } 416 417 // createCloudFormationStack ensures the cloudformation stack is up to date. 418 func createCloudFormationStack(prov client.ConfigProvider, t *cfn_bootstrap.Template, tags map[string]string) error { 419 Byf("Creating AWS CloudFormation stack for AWS IAM resources: stack-name=%s", t.Spec.StackName) 420 CFN := cfn.New(prov) 421 cfnSvc := cloudformation.NewService(CFN) 422 423 err := cfnSvc.ReconcileBootstrapStack(t.Spec.StackName, *renderCustomCloudFormation(t), tags) 424 if err != nil { 425 By(fmt.Sprintf("Error reconciling Cloud formation stack %v", err)) 426 stack, err := CFN.DescribeStacks(&cfn.DescribeStacksInput{StackName: aws.String(t.Spec.StackName)}) 427 if err == nil && len(stack.Stacks) > 0 { 428 deleteMultitenancyRoles(prov) 429 if aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackFailed || 430 aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackComplete || 431 aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackInProgress { 432 // If cloudformation stack creation fails due to resources that already exist, stack stays in rollback status and must be manually deleted. 433 // Delete resources that failed because they already exists. 434 deleteResourcesInCloudFormation(prov, t) 435 } 436 } 437 } 438 return err 439 } 440 441 func SetMultitenancyEnvVars(prov client.ConfigProvider) error { 442 for _, roles := range MultiTenancyRoles { 443 if err := roles.SetEnvVars(prov); err != nil { 444 return err 445 } 446 } 447 return nil 448 } 449 450 // Delete resources that already exists. 451 func deleteResourcesInCloudFormation(prov client.ConfigProvider, t *cfn_bootstrap.Template) { 452 iamSvc := iam.New(prov) 453 temp := *renderCustomCloudFormation(t) 454 for _, val := range temp.Resources { 455 tayp := val.AWSCloudFormationType() 456 if tayp == configservice.ResourceTypeAwsIamRole { 457 role := val.(*cfn_iam.Role) 458 _, err := iamSvc.DeleteRole(&iam.DeleteRoleInput{RoleName: aws.String(role.RoleName)}) 459 Expect(err).NotTo(HaveOccurred()) 460 } 461 if val.AWSCloudFormationType() == "AWS::IAM::InstanceProfile" { 462 profile := val.(*cfn_iam.InstanceProfile) 463 _, _ = iamSvc.DeleteInstanceProfile(&iam.DeleteInstanceProfileInput{InstanceProfileName: aws.String(profile.InstanceProfileName)}) 464 } 465 if val.AWSCloudFormationType() == "AWS::IAM::ManagedPolicy" { 466 policy := val.(*cfn_iam.ManagedPolicy) 467 policies, err := iamSvc.ListPolicies(&iam.ListPoliciesInput{}) 468 Expect(err).NotTo(HaveOccurred()) 469 if len(policies.Policies) > 0 { 470 for _, p := range policies.Policies { 471 if aws.StringValue(p.PolicyName) == policy.ManagedPolicyName { 472 _, _ = iamSvc.DeletePolicy(&iam.DeletePolicyInput{PolicyArn: p.Arn}) 473 break 474 } 475 } 476 } 477 } 478 if val.AWSCloudFormationType() == configservice.ResourceTypeAwsIamGroup { 479 group := val.(*cfn_iam.Group) 480 _, _ = iamSvc.DeleteGroup(&iam.DeleteGroupInput{GroupName: aws.String(group.GroupName)}) 481 } 482 } 483 } 484 485 // TODO: remove once test infra accounts are fixed. 486 func deleteMultitenancyRoles(prov client.ConfigProvider) { 487 DeleteRole(prov, "multi-tenancy-role") 488 DeleteRole(prov, "multi-tenancy-nested-role") 489 } 490 491 // detachAllPoliciesForRole detaches all policies for role. 492 func detachAllPoliciesForRole(prov client.ConfigProvider, name string) error { 493 iamSvc := iam.New(prov) 494 495 input := &iam.ListAttachedRolePoliciesInput{ 496 RoleName: &name, 497 } 498 policies, err := iamSvc.ListAttachedRolePolicies(input) 499 if err != nil { 500 return errors.New("error fetching policies for role") 501 } 502 for _, p := range policies.AttachedPolicies { 503 input := &iam.DetachRolePolicyInput{ 504 RoleName: aws.String(name), 505 PolicyArn: p.PolicyArn, 506 } 507 508 _, err := iamSvc.DetachRolePolicy(input) 509 if err != nil { 510 return errors.New("failed detaching policy from a role") 511 } 512 } 513 return nil 514 } 515 516 // DeleteRole deletes roles in a best effort manner. 517 func DeleteRole(prov client.ConfigProvider, name string) { 518 iamSvc := iam.New(prov) 519 520 // if role does not exist, return. 521 _, err := iamSvc.GetRole(&iam.GetRoleInput{RoleName: aws.String(name)}) 522 if err != nil { 523 return 524 } 525 526 if err := detachAllPoliciesForRole(prov, name); err != nil { 527 return 528 } 529 530 _, err = iamSvc.DeleteRole(&iam.DeleteRoleInput{RoleName: aws.String(name)}) 531 if err != nil { 532 return 533 } 534 } 535 536 func GetPolicyArn(prov client.ConfigProvider, name string) string { 537 iamSvc := iam.New(prov) 538 policyList, err := iamSvc.ListPolicies(&iam.ListPoliciesInput{ 539 Scope: aws.String(iam.PolicyScopeTypeLocal), 540 }) 541 Expect(err).NotTo(HaveOccurred()) 542 543 for _, policy := range policyList.Policies { 544 if aws.StringValue(policy.PolicyName) == name { 545 return aws.StringValue(policy.Arn) 546 } 547 } 548 return "" 549 } 550 551 // deleteCloudFormationStack removes the provisioned clusterawsadm stack. 552 func deleteCloudFormationStack(prov client.ConfigProvider, t *cfn_bootstrap.Template) { 553 Byf("Deleting %s CloudFormation stack", t.Spec.StackName) 554 CFN := cfn.New(prov) 555 cfnSvc := cloudformation.NewService(CFN) 556 err := cfnSvc.DeleteStack(t.Spec.StackName, nil) 557 if err != nil { 558 var retainResources []*string 559 out, err := CFN.DescribeStackResources(&cfn.DescribeStackResourcesInput{StackName: aws.String(t.Spec.StackName)}) 560 Expect(err).NotTo(HaveOccurred()) 561 for _, v := range out.StackResources { 562 if aws.StringValue(v.ResourceStatus) == cfn.ResourceStatusDeleteFailed { 563 retainResources = append(retainResources, v.LogicalResourceId) 564 } 565 } 566 err = cfnSvc.DeleteStack(t.Spec.StackName, retainResources) 567 Expect(err).NotTo(HaveOccurred()) 568 } 569 err = CFN.WaitUntilStackDeleteComplete(&cfn.DescribeStacksInput{ 570 StackName: aws.String(t.Spec.StackName), 571 }) 572 Expect(err).NotTo(HaveOccurred()) 573 } 574 575 func ensureTestImageUploaded(e2eCtx *E2EContext) error { 576 sessionForRepo := NewAWSSessionRepoWithKey(e2eCtx.Environment.BootstrapAccessKey) 577 578 ecrSvc := ecrpublic.New(sessionForRepo) 579 repoName := "" 580 if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) { 581 output, err := ecrSvc.CreateRepository(&ecrpublic.CreateRepositoryInput{ 582 RepositoryName: aws.String("capa/update"), 583 }) 584 585 if err != nil { 586 if !awserrors.IsRepositoryExists(err) { 587 return false, err 588 } 589 out, err := ecrSvc.DescribeRepositories(&ecrpublic.DescribeRepositoriesInput{RepositoryNames: []*string{aws.String("capa/update")}}) 590 if err != nil || len(out.Repositories) == 0 { 591 return false, err 592 } 593 repoName = aws.StringValue(out.Repositories[0].RepositoryUri) 594 } else { 595 repoName = aws.StringValue(output.Repository.RepositoryUri) 596 } 597 598 return true, nil 599 }, awserrors.UnrecognizedClientException); err != nil { 600 return err 601 } 602 603 cmd := exec.Command("docker", "inspect", "--format='{{index .Id}}'", "gcr.io/k8s-staging-cluster-api/capa-manager:e2e") 604 var stdOut bytes.Buffer 605 cmd.Stdout = &stdOut 606 err := cmd.Run() 607 if err != nil { 608 return err 609 } 610 611 imageSha := strings.ReplaceAll(strings.TrimSuffix(stdOut.String(), "\n"), "'", "") 612 613 ecrImageName := repoName + ":e2e" 614 cmd = exec.Command("docker", "tag", imageSha, ecrImageName) //nolint:gosec 615 err = cmd.Run() 616 if err != nil { 617 return err 618 } 619 620 outToken, err := ecrSvc.GetAuthorizationToken(&ecrpublic.GetAuthorizationTokenInput{}) 621 if err != nil { 622 return err 623 } 624 625 // Auth token is in username:password format. To login using it, we need to decode first and separate password and username 626 decodedUsernamePassword, _ := b64.StdEncoding.DecodeString(aws.StringValue(outToken.AuthorizationData.AuthorizationToken)) 627 628 strList := strings.Split(string(decodedUsernamePassword), ":") 629 if len(strList) != 2 { 630 return errors.New("failed to decode ECR authentication token") 631 } 632 633 cmd = exec.Command("docker", "login", "--username", strList[0], "--password", strList[1], "public.ecr.aws") //nolint:gosec 634 err = cmd.Run() 635 if err != nil { 636 return err 637 } 638 639 cmd = exec.Command("docker", "push", ecrImageName) 640 err = cmd.Run() 641 if err != nil { 642 return err 643 } 644 e2eCtx.E2EConfig.Variables["CAPI_IMAGES_REGISTRY"] = repoName 645 e2eCtx.E2EConfig.Variables["E2E_IMAGE_TAG"] = "e2e" 646 return nil 647 } 648 649 // ensureNoServiceLinkedRoles removes an auto-created IAM role, and tests 650 // the controller's IAM permissions to use ELB and Spot instances successfully. 651 func ensureNoServiceLinkedRoles(prov client.ConfigProvider) { 652 Byf("Deleting AWS IAM Service Linked Role: role-name=AWSServiceRoleForElasticLoadBalancing") 653 iamSvc := iam.New(prov) 654 _, err := iamSvc.DeleteServiceLinkedRole(&iam.DeleteServiceLinkedRoleInput{ 655 RoleName: aws.String("AWSServiceRoleForElasticLoadBalancing"), 656 }) 657 if code, _ := awserrors.Code(err); code != iam.ErrCodeNoSuchEntityException { 658 Expect(err).NotTo(HaveOccurred()) 659 } 660 661 Byf("Deleting AWS IAM Service Linked Role: role-name=AWSServiceRoleForEC2Spot") 662 _, err = iamSvc.DeleteServiceLinkedRole(&iam.DeleteServiceLinkedRoleInput{ 663 RoleName: aws.String("AWSServiceRoleForEC2Spot"), 664 }) 665 if code, _ := awserrors.Code(err); code != iam.ErrCodeNoSuchEntityException { 666 Expect(err).NotTo(HaveOccurred()) 667 } 668 } 669 670 // ensureSSHKeyPair ensures A SSH key is present under the name. 671 func ensureSSHKeyPair(prov client.ConfigProvider, keyPairName string) { 672 Byf("Ensuring presence of SSH key in EC2: key-name=%s", keyPairName) 673 ec2c := ec2.New(prov) 674 _, err := ec2c.CreateKeyPair(&ec2.CreateKeyPairInput{KeyName: aws.String(keyPairName)}) 675 if code, _ := awserrors.Code(err); code != "InvalidKeyPair.Duplicate" { 676 Expect(err).NotTo(HaveOccurred()) 677 } 678 } 679 680 func ensureStackTags(prov client.ConfigProvider, stackName string, expectedTags map[string]string) { 681 Byf("Ensuring AWS CloudFormation stack is created or updated with the specified tags: stack-name=%s", stackName) 682 CFN := cfn.New(prov) 683 r, err := CFN.DescribeStacks(&cfn.DescribeStacksInput{StackName: &stackName}) 684 Expect(err).NotTo(HaveOccurred()) 685 stacks := r.Stacks 686 Expect(len(stacks)).To(BeNumerically("==", 1)) 687 stackTags := stacks[0].Tags 688 Expect(len(stackTags)).To(BeNumerically("==", len(expectedTags))) 689 for _, tag := range stackTags { 690 Expect(*tag.Value).To(BeIdenticalTo(expectedTags[*tag.Key])) 691 } 692 } 693 694 // encodeCredentials leverages clusterawsadm to encode AWS credentials. 695 func encodeCredentials(accessKey *iam.AccessKey, region string) string { 696 creds := credentials.AWSCredentials{ 697 Region: region, 698 AccessKeyID: *accessKey.AccessKeyId, 699 SecretAccessKey: *accessKey.SecretAccessKey, 700 } 701 encCreds, err := creds.RenderBase64EncodedAWSDefaultProfile() 702 Expect(err).NotTo(HaveOccurred()) 703 return encCreds 704 } 705 706 // newUserAccessKey generates a new AWS Access Key pair based off of the 707 // bootstrap user. This tests that the CloudFormation policy is correct. 708 func newUserAccessKey(prov client.ConfigProvider, userName string) *iam.AccessKey { 709 iamSvc := iam.New(prov) 710 keyOuts, _ := iamSvc.ListAccessKeys(&iam.ListAccessKeysInput{ 711 UserName: aws.String(userName), 712 }) 713 for i := range keyOuts.AccessKeyMetadata { 714 Byf("Deleting an existing access key: user-name=%s", userName) 715 _, err := iamSvc.DeleteAccessKey(&iam.DeleteAccessKeyInput{ 716 UserName: aws.String(userName), 717 AccessKeyId: keyOuts.AccessKeyMetadata[i].AccessKeyId, 718 }) 719 Expect(err).NotTo(HaveOccurred()) 720 } 721 Byf("Creating an access key: user-name=%s", userName) 722 out, err := iamSvc.CreateAccessKey(&iam.CreateAccessKeyInput{UserName: aws.String(userName)}) 723 Expect(err).NotTo(HaveOccurred()) 724 Expect(out.AccessKey).ToNot(BeNil()) 725 726 return &iam.AccessKey{ 727 AccessKeyId: out.AccessKey.AccessKeyId, 728 SecretAccessKey: out.AccessKey.SecretAccessKey, 729 } 730 } 731 732 func DumpCloudTrailEvents(e2eCtx *E2EContext) { 733 client := cloudtrail.New(e2eCtx.BootstrapUserAWSSession) 734 events := []*cloudtrail.Event{} 735 err := client.LookupEventsPages( 736 &cloudtrail.LookupEventsInput{ 737 StartTime: aws.Time(e2eCtx.StartOfSuite), 738 EndTime: aws.Time(time.Now()), 739 }, 740 func(page *cloudtrail.LookupEventsOutput, lastPage bool) bool { 741 events = append(events, page.Events...) 742 return !lastPage 743 }, 744 ) 745 if err != nil { 746 fmt.Fprintf(GinkgoWriter, "couldn't get AWS CloudTrail events: err=%v", err) 747 } 748 logPath := filepath.Join(e2eCtx.Settings.ArtifactFolder, "cloudtrail-events.yaml") 749 dat, err := yaml.Marshal(events) 750 if err != nil { 751 fmt.Fprintf(GinkgoWriter, "Failed to marshal AWS CloudTrail events: err=%v", err) 752 } 753 if err := os.WriteFile(logPath, dat, 0600); err != nil { 754 fmt.Fprintf(GinkgoWriter, "couldn't write cloudtrail events to file: file=%s err=%s", logPath, err) 755 return 756 } 757 } 758 759 // conformanceImageID looks up a specific image for a given 760 // Kubernetes version in the e2econfig. 761 func conformanceImageID(e2eCtx *E2EContext) string { 762 ver := e2eCtx.E2EConfig.GetVariable("CONFORMANCE_CI_ARTIFACTS_KUBERNETES_VERSION") 763 amiName := AMIPrefix + ver + "*" 764 765 Byf("Searching for AMI: name=%s", amiName) 766 ec2Svc := ec2.New(e2eCtx.AWSSession) 767 filters := []*ec2.Filter{ 768 { 769 Name: aws.String("name"), 770 Values: []*string{aws.String(amiName)}, 771 }, 772 } 773 filters = append(filters, &ec2.Filter{ 774 Name: aws.String("owner-id"), 775 Values: []*string{aws.String(DefaultImageLookupOrg)}, 776 }) 777 resp, err := ec2Svc.DescribeImages(&ec2.DescribeImagesInput{ 778 Filters: filters, 779 }) 780 Expect(err).NotTo(HaveOccurred()) 781 Expect(len(resp.Images)).To(Not(BeZero())) 782 imageID := aws.StringValue(resp.Images[0].ImageId) 783 Byf("Using AMI: image-id=%s", imageID) 784 return imageID 785 } 786 787 func GetAvailabilityZones(sess client.ConfigProvider) []*ec2.AvailabilityZone { 788 ec2Client := ec2.New(sess) 789 azs, err := ec2Client.DescribeAvailabilityZones(nil) 790 Expect(err).NotTo(HaveOccurred()) 791 return azs.AvailabilityZones 792 } 793 794 type ServiceQuota struct { 795 ServiceCode string 796 QuotaName string 797 QuotaCode string 798 Value int 799 DesiredMinimumValue int 800 RequestStatus string 801 } 802 803 func EnsureServiceQuotas(sess client.ConfigProvider) map[string]*ServiceQuota { 804 limitedResources := getLimitedResources() 805 serviceQuotasClient := servicequotas.New(sess) 806 807 for k, v := range limitedResources { 808 out, err := serviceQuotasClient.GetServiceQuota(&servicequotas.GetServiceQuotaInput{ 809 QuotaCode: aws.String(v.QuotaCode), 810 ServiceCode: aws.String(v.ServiceCode), 811 }) 812 Expect(err).NotTo(HaveOccurred()) 813 v.Value = int(aws.Float64Value(out.Quota.Value)) 814 limitedResources[k] = v 815 if v.Value < v.DesiredMinimumValue { 816 v.attemptRaiseServiceQuotaRequest(serviceQuotasClient) 817 } 818 } 819 820 return limitedResources 821 } 822 823 func (s *ServiceQuota) attemptRaiseServiceQuotaRequest(serviceQuotasClient *servicequotas.ServiceQuotas) { 824 s.updateServiceQuotaRequestStatus(serviceQuotasClient) 825 if s.RequestStatus == "" { 826 s.raiseServiceRequest(serviceQuotasClient) 827 } 828 } 829 830 func (s *ServiceQuota) raiseServiceRequest(serviceQuotasClient *servicequotas.ServiceQuotas) { 831 fmt.Printf("Requesting service quota increase for %s/%s to %d\n", s.ServiceCode, s.QuotaName, s.DesiredMinimumValue) 832 out, err := serviceQuotasClient.RequestServiceQuotaIncrease( 833 &servicequotas.RequestServiceQuotaIncreaseInput{ 834 DesiredValue: aws.Float64(float64(s.DesiredMinimumValue)), 835 ServiceCode: aws.String(s.ServiceCode), 836 QuotaCode: aws.String(s.QuotaCode), 837 }, 838 ) 839 if err != nil { 840 fmt.Printf("Unable to raise quota for %s/%s: %s\n", s.ServiceCode, s.QuotaName, err) 841 } else { 842 s.RequestStatus = aws.StringValue(out.RequestedQuota.Status) 843 } 844 } 845 846 func (s *ServiceQuota) updateServiceQuotaRequestStatus(serviceQuotasClient *servicequotas.ServiceQuotas) { 847 params := &servicequotas.ListRequestedServiceQuotaChangeHistoryInput{ 848 ServiceCode: aws.String(s.ServiceCode), 849 } 850 latestRequest := &servicequotas.RequestedServiceQuotaChange{} 851 _ = serviceQuotasClient.ListRequestedServiceQuotaChangeHistoryPages(params, 852 func(page *servicequotas.ListRequestedServiceQuotaChangeHistoryOutput, lastPage bool) bool { 853 for _, v := range page.RequestedQuotas { 854 if int(aws.Float64Value(v.DesiredValue)) >= s.DesiredMinimumValue && aws.StringValue(v.QuotaCode) == s.QuotaCode && aws.TimeValue(v.Created).After(aws.TimeValue(latestRequest.Created)) { 855 latestRequest = v 856 } 857 } 858 return !lastPage 859 }, 860 ) 861 if latestRequest.Status != nil { 862 s.RequestStatus = aws.StringValue(latestRequest.Status) 863 } 864 } 865 866 func DumpEKSClusters(ctx context.Context, e2eCtx *E2EContext) { 867 logPath := filepath.Join(e2eCtx.Settings.ArtifactFolder, "clusters", e2eCtx.Environment.BootstrapClusterProxy.GetName(), "aws-resources") 868 if err := os.MkdirAll(logPath, os.ModePerm); err != nil { 869 fmt.Fprintf(GinkgoWriter, "couldn't create directory: path=%s, err=%s", logPath, err) 870 } 871 fmt.Fprintf(GinkgoWriter, "folder created for eks clusters: %s\n", logPath) 872 873 input := &eks.ListClustersInput{} 874 eksClient := eks.New(e2eCtx.BootstrapUserAWSSession) 875 output, err := eksClient.ListClusters(input) 876 if err != nil { 877 fmt.Fprintf(GinkgoWriter, "couldn't list EKS clusters: err=%s", err) 878 return 879 } 880 881 for _, clusterName := range output.Clusters { 882 describeInput := &eks.DescribeClusterInput{ 883 Name: clusterName, 884 } 885 describeOutput, err := eksClient.DescribeCluster(describeInput) 886 if err != nil { 887 fmt.Fprintf(GinkgoWriter, "couldn't describe EKS clusters: name=%s err=%s", *clusterName, err) 888 continue 889 } 890 dumpEKSCluster(describeOutput.Cluster, logPath) 891 } 892 } 893 894 func dumpEKSCluster(cluster *eks.Cluster, logPath string) { 895 clusterYAML, err := yaml.Marshal(cluster) 896 if err != nil { 897 fmt.Fprintf(GinkgoWriter, "couldn't marshal cluster to yaml: name=%s err=%s", *cluster.Name, err) 898 return 899 } 900 901 fileName := fmt.Sprintf("%s.yaml", *cluster.Name) 902 clusterLog := path.Join(logPath, fileName) 903 f, err := os.OpenFile(clusterLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm) //nolint:gosec 904 if err != nil { 905 fmt.Fprintf(GinkgoWriter, "couldn't open log file: name=%s err=%s", clusterLog, err) 906 return 907 } 908 defer f.Close() //nolint:gosec 909 910 if err := os.WriteFile(f.Name(), clusterYAML, 0600); err != nil { 911 fmt.Fprintf(GinkgoWriter, "couldn't write cluster yaml to file: name=%s file=%s err=%s", *cluster.Name, f.Name(), err) 912 return 913 } 914 } 915 916 // To calculate how much resources a test consumes, these helper functions below can be used. 917 // ListVpcInternetGateways, ListNATGateways, ListRunningEC2, ListVPC 918 919 func ListVpcInternetGateways(e2eCtx *E2EContext) ([]*ec2.InternetGateway, error) { 920 ec2Svc := ec2.New(e2eCtx.AWSSession) 921 922 out, err := ec2Svc.DescribeInternetGateways(&ec2.DescribeInternetGatewaysInput{}) 923 if err != nil { 924 return nil, err 925 } 926 927 return out.InternetGateways, nil 928 } 929 930 func ListNATGateways(e2eCtx *E2EContext) (map[string]*ec2.NatGateway, error) { 931 ec2Svc := ec2.New(e2eCtx.AWSSession) 932 933 describeNatGatewayInput := &ec2.DescribeNatGatewaysInput{ 934 Filter: []*ec2.Filter{ 935 filter.EC2.NATGatewayStates(ec2.NatGatewayStateAvailable), 936 }, 937 } 938 939 gateways := make(map[string]*ec2.NatGateway) 940 941 err := ec2Svc.DescribeNatGatewaysPages(describeNatGatewayInput, 942 func(page *ec2.DescribeNatGatewaysOutput, lastPage bool) bool { 943 for _, r := range page.NatGateways { 944 gateways[*r.SubnetId] = r 945 } 946 return !lastPage 947 }) 948 if err != nil { 949 return nil, err 950 } 951 952 return gateways, nil 953 } 954 955 func ListRunningEC2(e2eCtx *E2EContext) ([]instance, error) { 956 ec2Svc := ec2.New(e2eCtx.AWSSession) 957 958 resp, err := ec2Svc.DescribeInstancesWithContext(context.TODO(), &ec2.DescribeInstancesInput{ 959 Filters: []*ec2.Filter{filter.EC2.InstanceStates(ec2.InstanceStateNameRunning)}, 960 }) 961 if err != nil { 962 return nil, err 963 } 964 if len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 { 965 return nil, fmt.Errorf("no machines found") 966 } 967 instances := []instance{} 968 for _, r := range resp.Reservations { 969 for _, i := range r.Instances { 970 tags := i.Tags 971 name := "" 972 for _, t := range tags { 973 if aws.StringValue(t.Key) == "Name" { 974 name = aws.StringValue(t.Value) 975 } 976 } 977 if name == "" { 978 continue 979 } 980 instances = append(instances, 981 instance{ 982 name: name, 983 instanceID: aws.StringValue(i.InstanceId), 984 }, 985 ) 986 } 987 } 988 return instances, nil 989 } 990 991 func ListClusterEC2Instances(e2eCtx *E2EContext, clusterName string) ([]*ec2.Instance, error) { 992 ec2Svc := ec2.New(e2eCtx.AWSSession) 993 filter := &ec2.Filter{ 994 Name: aws.String("tag-key"), 995 Values: aws.StringSlice([]string{"sigs.k8s.io/cluster-api-provider-aws/cluster/" + clusterName}), 996 } 997 input := &ec2.DescribeInstancesInput{ 998 Filters: []*ec2.Filter{ 999 filter, 1000 }, 1001 } 1002 1003 result, err := ec2Svc.DescribeInstances(input) 1004 if err != nil { 1005 return nil, err 1006 } 1007 instances := []*ec2.Instance{} 1008 for _, r := range result.Reservations { 1009 instances = append(instances, r.Instances...) 1010 } 1011 return instances, nil 1012 } 1013 1014 func WaitForInstanceState(e2eCtx *E2EContext, clusterName string, timeout int, state string) bool { 1015 t := 0 1016 for t < timeout { 1017 st := map[string]int{ 1018 "pending": 0, 1019 "running": 0, 1020 "shutting-down": 0, 1021 "terminated": 0, 1022 } 1023 instances, _ := ListClusterEC2Instances(e2eCtx, clusterName) 1024 for _, i := range instances { 1025 iState := *i.State.Name 1026 st[iState]++ 1027 } 1028 if st[state] == len(instances) || len(instances) == 0 { 1029 return true 1030 } 1031 time.Sleep(1 * time.Second) 1032 t++ 1033 } 1034 return false 1035 } 1036 1037 func TerminateInstance(e2eCtx *E2EContext, instanceID string) bool { 1038 ec2Svc := ec2.New(e2eCtx.AWSSession) 1039 1040 input := &ec2.TerminateInstancesInput{ 1041 InstanceIds: aws.StringSlice([]string{instanceID}), 1042 } 1043 1044 if _, err := ec2Svc.TerminateInstances(input); err != nil { 1045 return false 1046 } 1047 return true 1048 } 1049 1050 func ListVPC(e2eCtx *E2EContext) int { 1051 ec2Svc := ec2.New(e2eCtx.AWSSession) 1052 1053 input := &ec2.DescribeVpcsInput{ 1054 Filters: []*ec2.Filter{ 1055 filter.EC2.VPCStates(ec2.VpcStateAvailable), 1056 }, 1057 } 1058 1059 out, err := ec2Svc.DescribeVpcs(input) 1060 if err != nil { 1061 return 0 1062 } 1063 1064 return len(out.Vpcs) 1065 } 1066 1067 func GetVPC(e2eCtx *E2EContext, vpcID string) (*ec2.Vpc, error) { 1068 ec2Svc := ec2.New(e2eCtx.AWSSession) 1069 1070 filter := &ec2.Filter{ 1071 Name: aws.String("vpc-id"), 1072 Values: aws.StringSlice([]string{vpcID}), 1073 } 1074 1075 input := &ec2.DescribeVpcsInput{ 1076 Filters: []*ec2.Filter{ 1077 filter, 1078 }, 1079 } 1080 1081 result, err := ec2Svc.DescribeVpcs(input) 1082 if err != nil { 1083 return nil, err 1084 } 1085 if result.Vpcs == nil { 1086 return nil, nil 1087 } 1088 return result.Vpcs[0], nil 1089 } 1090 1091 func GetVPCByName(e2eCtx *E2EContext, vpcName string) (*ec2.Vpc, error) { 1092 ec2Svc := ec2.New(e2eCtx.AWSSession) 1093 1094 filter := &ec2.Filter{ 1095 Name: aws.String("tag:Name"), 1096 Values: aws.StringSlice([]string{vpcName}), 1097 } 1098 1099 input := &ec2.DescribeVpcsInput{ 1100 Filters: []*ec2.Filter{ 1101 filter, 1102 }, 1103 } 1104 1105 result, err := ec2Svc.DescribeVpcs(input) 1106 if err != nil { 1107 return nil, err 1108 } 1109 if result.Vpcs == nil || len(result.Vpcs) == 0 { 1110 return nil, awserrors.NewNotFound("Vpc not found") 1111 } 1112 return result.Vpcs[0], nil 1113 } 1114 1115 func CreateVPC(e2eCtx *E2EContext, vpcName string, cidrBlock string) (*ec2.Vpc, error) { 1116 ec2Svc := ec2.New(e2eCtx.AWSSession) 1117 1118 input := &ec2.CreateVpcInput{ 1119 CidrBlock: aws.String(cidrBlock), 1120 TagSpecifications: []*ec2.TagSpecification{ 1121 { 1122 ResourceType: aws.String("vpc"), 1123 Tags: []*ec2.Tag{ 1124 { 1125 Key: aws.String("Name"), 1126 Value: aws.String(vpcName), 1127 }, 1128 }, 1129 }, 1130 }, 1131 } 1132 result, err := ec2Svc.CreateVpc(input) 1133 if err != nil { 1134 return nil, err 1135 } 1136 return result.Vpc, nil 1137 } 1138 1139 func DisassociateVpcCidrBlock(e2eCtx *E2EContext, assocID string) bool { 1140 ec2Svc := ec2.New(e2eCtx.AWSSession) 1141 1142 input := &ec2.DisassociateVpcCidrBlockInput{ 1143 AssociationId: aws.String(assocID), 1144 } 1145 1146 if _, err := ec2Svc.DisassociateVpcCidrBlock(input); err != nil { 1147 return false 1148 } 1149 return true 1150 } 1151 1152 func DeleteVPC(e2eCtx *E2EContext, vpcID string) bool { 1153 ec2Svc := ec2.New(e2eCtx.AWSSession) 1154 1155 input := &ec2.DeleteVpcInput{ 1156 VpcId: aws.String(vpcID), 1157 } 1158 if _, err := ec2Svc.DeleteVpc(input); err != nil { 1159 return false 1160 } 1161 return true 1162 } 1163 1164 func ListVpcSubnets(e2eCtx *E2EContext, vpcID string) ([]*ec2.Subnet, error) { 1165 ec2Svc := ec2.New(e2eCtx.AWSSession) 1166 1167 filter := &ec2.Filter{ 1168 Name: aws.String("vpc-id"), 1169 Values: aws.StringSlice([]string{vpcID}), 1170 } 1171 1172 input := &ec2.DescribeSubnetsInput{ 1173 Filters: []*ec2.Filter{ 1174 filter, 1175 }, 1176 } 1177 1178 result, err := ec2Svc.DescribeSubnets(input) 1179 if err != nil { 1180 return nil, err 1181 } 1182 return result.Subnets, nil 1183 } 1184 1185 func GetSubnet(e2eCtx *E2EContext, subnetID string) (*ec2.Subnet, error) { 1186 ec2Svc := ec2.New(e2eCtx.AWSSession) 1187 1188 filter := &ec2.Filter{ 1189 Name: aws.String("subnet-id"), 1190 Values: aws.StringSlice([]string{subnetID}), 1191 } 1192 1193 input := &ec2.DescribeSubnetsInput{ 1194 Filters: []*ec2.Filter{ 1195 filter, 1196 }, 1197 } 1198 1199 result, err := ec2Svc.DescribeSubnets(input) 1200 if err != nil { 1201 return nil, err 1202 } 1203 if result.Subnets == nil { 1204 return nil, nil 1205 } 1206 return result.Subnets[0], nil 1207 } 1208 1209 func GetSubnetByName(e2eCtx *E2EContext, name string) (*ec2.Subnet, error) { 1210 ec2Svc := ec2.New(e2eCtx.AWSSession) 1211 1212 filter := &ec2.Filter{ 1213 Name: aws.String("tag:Name"), 1214 Values: aws.StringSlice([]string{name}), 1215 } 1216 1217 input := &ec2.DescribeSubnetsInput{ 1218 Filters: []*ec2.Filter{ 1219 filter, 1220 }, 1221 } 1222 1223 result, err := ec2Svc.DescribeSubnets(input) 1224 if err != nil { 1225 return nil, err 1226 } 1227 if result.Subnets == nil { 1228 return nil, nil 1229 } 1230 return result.Subnets[0], nil 1231 } 1232 1233 func CreateSubnet(e2eCtx *E2EContext, clusterName string, cidrBlock string, az string, vpcID string, st string) (*ec2.Subnet, error) { 1234 ec2Svc := ec2.New(e2eCtx.AWSSession) 1235 1236 input := &ec2.CreateSubnetInput{ 1237 CidrBlock: aws.String(cidrBlock), 1238 VpcId: aws.String(vpcID), 1239 TagSpecifications: []*ec2.TagSpecification{ 1240 { 1241 ResourceType: aws.String("subnet"), 1242 Tags: []*ec2.Tag{ 1243 { 1244 Key: aws.String("Name"), 1245 Value: aws.String(clusterName + "-subnet-" + st), 1246 }, 1247 { 1248 Key: aws.String("kubernetes.io/cluster/" + clusterName), 1249 Value: aws.String("shared"), 1250 }, 1251 }, 1252 }, 1253 }, 1254 } 1255 1256 // Tag subnet based on type(st) 1257 switch st { 1258 case "private": 1259 input.TagSpecifications[0].Tags = append(input.TagSpecifications[0].Tags, &ec2.Tag{ 1260 Key: aws.String("kubernetes.io/role/internal-elb"), 1261 Value: aws.String("1"), 1262 }) 1263 case "public": 1264 input.TagSpecifications[0].Tags = append(input.TagSpecifications[0].Tags, &ec2.Tag{ 1265 Key: aws.String("kubernetes.io/role/elb"), 1266 Value: aws.String("1"), 1267 }) 1268 } 1269 1270 if az != "" { 1271 input.AvailabilityZone = aws.String(az) 1272 } 1273 1274 result, err := ec2Svc.CreateSubnet(input) 1275 if err != nil { 1276 return nil, err 1277 } 1278 return result.Subnet, nil 1279 } 1280 1281 func DeleteSubnet(e2eCtx *E2EContext, subnetID string) bool { 1282 ec2Svc := ec2.New(e2eCtx.AWSSession) 1283 1284 input := &ec2.DeleteSubnetInput{ 1285 SubnetId: aws.String(subnetID), 1286 } 1287 1288 if _, err := ec2Svc.DeleteSubnet(input); err != nil { 1289 return false 1290 } 1291 return true 1292 } 1293 1294 func GetAddress(e2eCtx *E2EContext, allocationID string) (*ec2.Address, error) { 1295 ec2Svc := ec2.New(e2eCtx.AWSSession) 1296 1297 filter := &ec2.Filter{ 1298 Name: aws.String("allocation-id"), 1299 Values: aws.StringSlice([]string{allocationID}), 1300 } 1301 1302 input := &ec2.DescribeAddressesInput{ 1303 Filters: []*ec2.Filter{ 1304 filter, 1305 }, 1306 } 1307 1308 result, err := ec2Svc.DescribeAddresses(input) 1309 if err != nil { 1310 return nil, err 1311 } 1312 if result.Addresses == nil { 1313 return nil, nil 1314 } 1315 return result.Addresses[0], nil 1316 } 1317 1318 func AllocateAddress(e2eCtx *E2EContext, eipName string) (*ec2.AllocateAddressOutput, error) { 1319 ec2Svc := ec2.New(e2eCtx.AWSSession) 1320 1321 input := &ec2.AllocateAddressInput{ 1322 Domain: aws.String("vpc"), 1323 TagSpecifications: []*ec2.TagSpecification{ 1324 { 1325 ResourceType: aws.String("elastic-ip"), 1326 Tags: []*ec2.Tag{ 1327 { 1328 Key: aws.String("Name"), 1329 Value: aws.String(eipName), 1330 }, 1331 }, 1332 }, 1333 }, 1334 } 1335 1336 result, err := ec2Svc.AllocateAddress(input) 1337 if err != nil { 1338 return nil, err 1339 } 1340 return result, nil 1341 } 1342 1343 func DisassociateAddress(e2eCtx *E2EContext, assocID string) bool { 1344 ec2Svc := ec2.New(e2eCtx.AWSSession) 1345 1346 input := &ec2.DisassociateAddressInput{ 1347 AssociationId: aws.String(assocID), 1348 } 1349 1350 if _, err := ec2Svc.DisassociateAddress(input); err != nil { 1351 return false 1352 } 1353 return true 1354 } 1355 1356 func ReleaseAddress(e2eCtx *E2EContext, allocationID string) bool { 1357 ec2Svc := ec2.New(e2eCtx.AWSSession) 1358 1359 input := &ec2.ReleaseAddressInput{ 1360 AllocationId: aws.String(allocationID), 1361 } 1362 1363 if _, err := ec2Svc.ReleaseAddress(input); err != nil { 1364 return false 1365 } 1366 return true 1367 } 1368 1369 func CreateNatGateway(e2eCtx *E2EContext, gatewayName string, connectType string, allocationID string, subnetID string) (*ec2.NatGateway, error) { 1370 ec2Svc := ec2.New(e2eCtx.AWSSession) 1371 1372 input := &ec2.CreateNatGatewayInput{ 1373 SubnetId: aws.String(subnetID), 1374 TagSpecifications: []*ec2.TagSpecification{ 1375 { 1376 ResourceType: aws.String("natgateway"), 1377 Tags: []*ec2.Tag{ 1378 { 1379 Key: aws.String("Name"), 1380 Value: aws.String(gatewayName), 1381 }, 1382 }, 1383 }, 1384 }, 1385 } 1386 1387 if connectType != "" { 1388 input.ConnectivityType = aws.String(connectType) 1389 } 1390 1391 if allocationID != "" { 1392 input.AllocationId = aws.String(allocationID) 1393 } 1394 1395 result, err := ec2Svc.CreateNatGateway(input) 1396 if err != nil { 1397 return nil, err 1398 } 1399 return result.NatGateway, nil 1400 } 1401 1402 func GetNatGateway(e2eCtx *E2EContext, gatewayID string) (*ec2.NatGateway, error) { 1403 ec2Svc := ec2.New(e2eCtx.AWSSession) 1404 1405 filter := &ec2.Filter{ 1406 Name: aws.String("nat-gateway-id"), 1407 Values: aws.StringSlice([]string{gatewayID}), 1408 } 1409 1410 input := &ec2.DescribeNatGatewaysInput{ 1411 Filter: []*ec2.Filter{ 1412 filter, 1413 }, 1414 } 1415 1416 result, err := ec2Svc.DescribeNatGateways(input) 1417 if err != nil { 1418 return nil, err 1419 } 1420 if result.NatGateways == nil { 1421 return nil, nil 1422 } 1423 return result.NatGateways[0], nil 1424 } 1425 1426 func DeleteNatGateway(e2eCtx *E2EContext, gatewayID string) bool { 1427 ec2Svc := ec2.New(e2eCtx.AWSSession) 1428 1429 input := &ec2.DeleteNatGatewayInput{ 1430 NatGatewayId: aws.String(gatewayID), 1431 } 1432 1433 if _, err := ec2Svc.DeleteNatGateway(input); err != nil { 1434 return false 1435 } 1436 return true 1437 } 1438 1439 func WaitForNatGatewayState(e2eCtx *E2EContext, gatewayID string, timeout int, state string) bool { 1440 t := 0 1441 for t < timeout { 1442 gw, _ := GetNatGateway(e2eCtx, gatewayID) 1443 gwState := *gw.State 1444 if gwState == state { 1445 return true 1446 } 1447 time.Sleep(1 * time.Second) 1448 t++ 1449 } 1450 return false 1451 } 1452 1453 func CreateInternetGateway(e2eCtx *E2EContext, gatewayName string) (*ec2.InternetGateway, error) { 1454 ec2Svc := ec2.New(e2eCtx.AWSSession) 1455 1456 input := &ec2.CreateInternetGatewayInput{ 1457 TagSpecifications: []*ec2.TagSpecification{ 1458 { 1459 ResourceType: aws.String("internet-gateway"), 1460 Tags: []*ec2.Tag{ 1461 { 1462 Key: aws.String("Name"), 1463 Value: aws.String(gatewayName), 1464 }, 1465 }, 1466 }, 1467 }, 1468 } 1469 1470 result, err := ec2Svc.CreateInternetGateway(input) 1471 if err != nil { 1472 return nil, err 1473 } 1474 return result.InternetGateway, nil 1475 } 1476 1477 func GetInternetGateway(e2eCtx *E2EContext, gatewayID string) (*ec2.InternetGateway, error) { 1478 ec2Svc := ec2.New(e2eCtx.AWSSession) 1479 1480 filter := &ec2.Filter{ 1481 Name: aws.String("internet-gateway-id"), 1482 Values: aws.StringSlice([]string{gatewayID}), 1483 } 1484 1485 input := &ec2.DescribeInternetGatewaysInput{ 1486 Filters: []*ec2.Filter{ 1487 filter, 1488 }, 1489 } 1490 1491 result, err := ec2Svc.DescribeInternetGateways(input) 1492 if err != nil { 1493 return nil, err 1494 } 1495 if result.InternetGateways == nil { 1496 return nil, nil 1497 } 1498 return result.InternetGateways[0], nil 1499 } 1500 1501 func DeleteInternetGateway(e2eCtx *E2EContext, gatewayID string) bool { 1502 ec2Svc := ec2.New(e2eCtx.AWSSession) 1503 1504 input := &ec2.DeleteInternetGatewayInput{ 1505 InternetGatewayId: aws.String(gatewayID), 1506 } 1507 1508 if _, err := ec2Svc.DeleteInternetGateway(input); err != nil { 1509 return false 1510 } 1511 return true 1512 } 1513 1514 func AttachInternetGateway(e2eCtx *E2EContext, gatewayID string, vpcID string) (bool, error) { 1515 ec2Svc := ec2.New(e2eCtx.AWSSession) 1516 1517 input := &ec2.AttachInternetGatewayInput{ 1518 InternetGatewayId: aws.String(gatewayID), 1519 VpcId: aws.String(vpcID), 1520 } 1521 1522 if _, err := ec2Svc.AttachInternetGateway(input); err != nil { 1523 return false, err 1524 } 1525 return true, nil 1526 } 1527 1528 func DetachInternetGateway(e2eCtx *E2EContext, gatewayID string, vpcID string) bool { 1529 ec2Svc := ec2.New(e2eCtx.AWSSession) 1530 1531 input := &ec2.DetachInternetGatewayInput{ 1532 InternetGatewayId: aws.String(gatewayID), 1533 VpcId: aws.String(vpcID), 1534 } 1535 1536 if _, err := ec2Svc.DetachInternetGateway(input); err != nil { 1537 return false 1538 } 1539 return true 1540 } 1541 1542 func CreatePeering(e2eCtx *E2EContext, peerName string, vpcID string, peerVpcID string) (*ec2.VpcPeeringConnection, error) { 1543 ec2Svc := ec2.New(e2eCtx.AWSSession) 1544 1545 input := &ec2.CreateVpcPeeringConnectionInput{ 1546 VpcId: aws.String(vpcID), 1547 PeerVpcId: aws.String(peerVpcID), 1548 TagSpecifications: []*ec2.TagSpecification{ 1549 { 1550 ResourceType: aws.String("vpc-peering-connection"), 1551 Tags: []*ec2.Tag{ 1552 { 1553 Key: aws.String("Name"), 1554 Value: aws.String(peerName), 1555 }, 1556 }, 1557 }, 1558 }, 1559 } 1560 1561 result, err := ec2Svc.CreateVpcPeeringConnection(input) 1562 if err != nil { 1563 return nil, err 1564 } 1565 return result.VpcPeeringConnection, nil 1566 } 1567 1568 func GetPeering(e2eCtx *E2EContext, peeringID string) (*ec2.VpcPeeringConnection, error) { 1569 ec2Svc := ec2.New(e2eCtx.AWSSession) 1570 1571 filter := &ec2.Filter{ 1572 Name: aws.String("vpc-peering-connection-id"), 1573 Values: aws.StringSlice([]string{peeringID}), 1574 } 1575 1576 input := &ec2.DescribeVpcPeeringConnectionsInput{ 1577 Filters: []*ec2.Filter{ 1578 filter, 1579 }, 1580 } 1581 1582 result, err := ec2Svc.DescribeVpcPeeringConnections(input) 1583 if err != nil { 1584 return nil, err 1585 } 1586 if result.VpcPeeringConnections == nil { 1587 return nil, nil 1588 } 1589 return result.VpcPeeringConnections[0], nil 1590 } 1591 1592 func DeletePeering(e2eCtx *E2EContext, peeringID string) bool { 1593 ec2Svc := ec2.New(e2eCtx.AWSSession) 1594 1595 input := &ec2.DeleteVpcPeeringConnectionInput{ 1596 VpcPeeringConnectionId: aws.String(peeringID), 1597 } 1598 1599 if _, err := ec2Svc.DeleteVpcPeeringConnection(input); err != nil { 1600 return false 1601 } 1602 return true 1603 } 1604 1605 func AcceptPeering(e2eCtx *E2EContext, peeringID string) (*ec2.VpcPeeringConnection, error) { 1606 ec2Svc := ec2.New(e2eCtx.AWSSession) 1607 1608 input := &ec2.AcceptVpcPeeringConnectionInput{ 1609 VpcPeeringConnectionId: aws.String(peeringID), 1610 } 1611 1612 result, err := ec2Svc.AcceptVpcPeeringConnection(input) 1613 if err != nil { 1614 return nil, err 1615 } 1616 return result.VpcPeeringConnection, nil 1617 } 1618 1619 func CreateRouteTable(e2eCtx *E2EContext, rtName string, vpcID string) (*ec2.RouteTable, error) { 1620 ec2Svc := ec2.New(e2eCtx.AWSSession) 1621 1622 input := &ec2.CreateRouteTableInput{ 1623 VpcId: aws.String(vpcID), 1624 TagSpecifications: []*ec2.TagSpecification{ 1625 { 1626 ResourceType: aws.String("route-table"), 1627 Tags: []*ec2.Tag{ 1628 { 1629 Key: aws.String("Name"), 1630 Value: aws.String(rtName), 1631 }, 1632 }, 1633 }, 1634 }, 1635 } 1636 1637 result, err := ec2Svc.CreateRouteTable(input) 1638 if err != nil { 1639 return nil, err 1640 } 1641 return result.RouteTable, nil 1642 } 1643 1644 func ListVpcRouteTables(e2eCtx *E2EContext, vpcID string) ([]*ec2.RouteTable, error) { 1645 ec2Svc := ec2.New(e2eCtx.AWSSession) 1646 1647 filter := &ec2.Filter{ 1648 Name: aws.String("vpc-id"), 1649 Values: aws.StringSlice([]string{vpcID}), 1650 } 1651 1652 input := &ec2.DescribeRouteTablesInput{ 1653 Filters: []*ec2.Filter{ 1654 filter, 1655 }, 1656 } 1657 1658 result, err := ec2Svc.DescribeRouteTables(input) 1659 if err != nil { 1660 return nil, err 1661 } 1662 return result.RouteTables, nil 1663 } 1664 1665 func ListSubnetRouteTables(e2eCtx *E2EContext, subnetID string) ([]*ec2.RouteTable, error) { 1666 ec2Svc := ec2.New(e2eCtx.AWSSession) 1667 1668 filter := &ec2.Filter{ 1669 Name: aws.String("association.subnet-id"), 1670 Values: aws.StringSlice([]string{subnetID}), 1671 } 1672 1673 input := &ec2.DescribeRouteTablesInput{ 1674 Filters: []*ec2.Filter{ 1675 filter, 1676 }, 1677 } 1678 1679 result, err := ec2Svc.DescribeRouteTables(input) 1680 if err != nil { 1681 return nil, err 1682 } 1683 return result.RouteTables, nil 1684 } 1685 1686 func GetRouteTable(e2eCtx *E2EContext, rtID string) (*ec2.RouteTable, error) { 1687 ec2Svc := ec2.New(e2eCtx.AWSSession) 1688 1689 filter := &ec2.Filter{ 1690 Name: aws.String("route-table-id"), 1691 Values: aws.StringSlice([]string{rtID}), 1692 } 1693 1694 input := &ec2.DescribeRouteTablesInput{ 1695 Filters: []*ec2.Filter{ 1696 filter, 1697 }, 1698 } 1699 1700 result, err := ec2Svc.DescribeRouteTables(input) 1701 if err != nil { 1702 return nil, err 1703 } 1704 if result.RouteTables == nil { 1705 return nil, nil 1706 } 1707 return result.RouteTables[0], nil 1708 } 1709 1710 func DeleteRouteTable(e2eCtx *E2EContext, rtID string) bool { 1711 ec2Svc := ec2.New(e2eCtx.AWSSession) 1712 1713 input := &ec2.DeleteRouteTableInput{ 1714 RouteTableId: aws.String(rtID), 1715 } 1716 1717 if _, err := ec2Svc.DeleteRouteTable(input); err != nil { 1718 return false 1719 } 1720 return true 1721 } 1722 1723 func CreateRoute(e2eCtx *E2EContext, rtID string, destinationCidr string, natID *string, igwID *string, pcxID *string) bool { 1724 ec2Svc := ec2.New(e2eCtx.AWSSession) 1725 1726 input := &ec2.CreateRouteInput{ 1727 RouteTableId: &rtID, 1728 DestinationCidrBlock: aws.String(destinationCidr), 1729 } 1730 1731 if natID != nil { 1732 input.NatGatewayId = natID 1733 } 1734 1735 if igwID != nil { 1736 input.GatewayId = igwID 1737 } 1738 1739 if pcxID != nil { 1740 input.VpcPeeringConnectionId = pcxID 1741 } 1742 1743 _, err := ec2Svc.CreateRoute(input) 1744 return err == nil 1745 } 1746 1747 func DeleteRoute(e2eCtx *E2EContext, rtID string, destinationCidr string) bool { 1748 ec2Svc := ec2.New(e2eCtx.AWSSession) 1749 1750 input := &ec2.DeleteRouteInput{ 1751 RouteTableId: aws.String(rtID), 1752 DestinationCidrBlock: aws.String(destinationCidr), 1753 } 1754 1755 if _, err := ec2Svc.DeleteRoute(input); err != nil { 1756 return false 1757 } 1758 return true 1759 } 1760 1761 func AssociateRouteTable(e2eCtx *E2EContext, rtID string, subnetID string) (*ec2.AssociateRouteTableOutput, error) { 1762 ec2Svc := ec2.New(e2eCtx.AWSSession) 1763 1764 input := &ec2.AssociateRouteTableInput{ 1765 RouteTableId: aws.String(rtID), 1766 SubnetId: aws.String(subnetID), 1767 } 1768 1769 result, err := ec2Svc.AssociateRouteTable(input) 1770 if err != nil { 1771 return nil, err 1772 } 1773 return result, nil 1774 } 1775 1776 func DisassociateRouteTable(e2eCtx *E2EContext, assocID string) bool { 1777 ec2Svc := ec2.New(e2eCtx.AWSSession) 1778 1779 input := &ec2.DisassociateRouteTableInput{ 1780 AssociationId: aws.String(assocID), 1781 } 1782 1783 if _, err := ec2Svc.DisassociateRouteTable(input); err != nil { 1784 return false 1785 } 1786 return true 1787 } 1788 1789 func CreateSecurityGroup(e2eCtx *E2EContext, sgName string, sgDescription string, vpcID string) (*ec2.CreateSecurityGroupOutput, error) { 1790 ec2Svc := ec2.New(e2eCtx.AWSSession) 1791 1792 input := &ec2.CreateSecurityGroupInput{ 1793 VpcId: aws.String(vpcID), 1794 GroupName: aws.String(sgName), 1795 Description: aws.String(sgDescription), 1796 TagSpecifications: []*ec2.TagSpecification{ 1797 { 1798 ResourceType: aws.String("security-group"), 1799 Tags: []*ec2.Tag{ 1800 { 1801 Key: aws.String("Name"), 1802 Value: aws.String(sgName), 1803 }, 1804 }, 1805 }, 1806 }, 1807 } 1808 1809 result, err := ec2Svc.CreateSecurityGroup(input) 1810 if err != nil { 1811 return nil, err 1812 } 1813 return result, nil 1814 } 1815 1816 func GetSecurityGroupByFilters(e2eCtx *E2EContext, filters []*ec2.Filter) ([]*ec2.SecurityGroup, error) { 1817 ec2Svc := ec2.New(e2eCtx.AWSSession) 1818 input := &ec2.DescribeSecurityGroupsInput{ 1819 Filters: filters, 1820 } 1821 result, err := ec2Svc.DescribeSecurityGroups(input) 1822 if err != nil { 1823 return nil, err 1824 } 1825 return result.SecurityGroups, nil 1826 } 1827 1828 func GetSecurityGroup(e2eCtx *E2EContext, sgID string) (*ec2.SecurityGroup, error) { 1829 ec2Svc := ec2.New(e2eCtx.AWSSession) 1830 1831 filter := &ec2.Filter{ 1832 Name: aws.String("group-id"), 1833 Values: aws.StringSlice([]string{sgID}), 1834 } 1835 1836 input := &ec2.DescribeSecurityGroupsInput{ 1837 Filters: []*ec2.Filter{ 1838 filter, 1839 }, 1840 } 1841 1842 result, err := ec2Svc.DescribeSecurityGroups(input) 1843 if err != nil { 1844 return nil, err 1845 } 1846 if result.SecurityGroups == nil { 1847 return nil, nil 1848 } 1849 return result.SecurityGroups[0], nil 1850 } 1851 1852 func GetSecurityGroupsByVPC(e2eCtx *E2EContext, vpcID string) ([]*ec2.SecurityGroup, error) { 1853 ec2Svc := ec2.New(e2eCtx.AWSSession) 1854 1855 filter := &ec2.Filter{ 1856 Name: aws.String("vpc-id"), 1857 Values: []*string{ 1858 aws.String(vpcID), 1859 }, 1860 } 1861 1862 input := &ec2.DescribeSecurityGroupsInput{ 1863 Filters: []*ec2.Filter{ 1864 filter, 1865 }, 1866 } 1867 1868 result, err := ec2Svc.DescribeSecurityGroups(input) 1869 if err != nil { 1870 return nil, err 1871 } 1872 if result.SecurityGroups == nil { 1873 return nil, nil 1874 } 1875 return result.SecurityGroups, nil 1876 } 1877 1878 func DeleteSecurityGroup(e2eCtx *E2EContext, sgID string) bool { 1879 ec2Svc := ec2.New(e2eCtx.AWSSession) 1880 1881 input := &ec2.DeleteSecurityGroupInput{ 1882 GroupId: aws.String(sgID), 1883 } 1884 1885 if _, err := ec2Svc.DeleteSecurityGroup(input); err != nil { 1886 return false 1887 } 1888 return true 1889 } 1890 1891 func ListSecurityGroupRules(e2eCtx *E2EContext, sgID string) ([]*ec2.SecurityGroupRule, error) { 1892 ec2Svc := ec2.New(e2eCtx.AWSSession) 1893 1894 filter := &ec2.Filter{ 1895 Name: aws.String("group-id"), 1896 Values: aws.StringSlice([]string{sgID}), 1897 } 1898 1899 input := &ec2.DescribeSecurityGroupRulesInput{ 1900 Filters: []*ec2.Filter{ 1901 filter, 1902 }, 1903 } 1904 1905 result, err := ec2Svc.DescribeSecurityGroupRules(input) 1906 if err != nil { 1907 return nil, err 1908 } 1909 return result.SecurityGroupRules, nil 1910 } 1911 1912 func GetSecurityGroupRule(e2eCtx *E2EContext, sgrID string) (*ec2.SecurityGroupRule, error) { 1913 ec2Svc := ec2.New(e2eCtx.AWSSession) 1914 1915 filter := &ec2.Filter{ 1916 Name: aws.String("security-group-rule-id"), 1917 Values: aws.StringSlice([]string{sgrID}), 1918 } 1919 1920 input := &ec2.DescribeSecurityGroupRulesInput{ 1921 Filters: []*ec2.Filter{ 1922 filter, 1923 }, 1924 } 1925 1926 result, err := ec2Svc.DescribeSecurityGroupRules(input) 1927 if err != nil { 1928 return nil, err 1929 } 1930 if result.SecurityGroupRules == nil { 1931 return nil, nil 1932 } 1933 return result.SecurityGroupRules[0], nil 1934 } 1935 1936 func CreateSecurityGroupIngressRule(e2eCtx *E2EContext, sgID string, sgrDescription string, cidr string, protocol string, fromPort int64, toPort int64) (bool, error) { 1937 ec2Svc := ec2.New(e2eCtx.AWSSession) 1938 1939 ipPerm := &ec2.IpPermission{ 1940 FromPort: aws.Int64(fromPort), 1941 ToPort: aws.Int64(toPort), 1942 IpProtocol: aws.String(protocol), 1943 IpRanges: []*ec2.IpRange{ 1944 { 1945 CidrIp: aws.String(cidr), 1946 Description: aws.String(sgrDescription), 1947 }, 1948 }, 1949 } 1950 1951 input := &ec2.AuthorizeSecurityGroupIngressInput{ 1952 GroupId: aws.String(sgID), 1953 IpPermissions: []*ec2.IpPermission{ 1954 ipPerm, 1955 }, 1956 } 1957 1958 result, err := ec2Svc.AuthorizeSecurityGroupIngress(input) 1959 if err != nil { 1960 return false, err 1961 } 1962 return *result.Return, nil 1963 } 1964 1965 func CreateSecurityGroupEgressRule(e2eCtx *E2EContext, sgID string, sgrDescription string, cidr string, protocol string, fromPort int64, toPort int64) (bool, error) { 1966 ec2Svc := ec2.New(e2eCtx.AWSSession) 1967 1968 ipPerm := &ec2.IpPermission{ 1969 FromPort: aws.Int64(fromPort), 1970 ToPort: aws.Int64(toPort), 1971 IpProtocol: aws.String(protocol), 1972 IpRanges: []*ec2.IpRange{ 1973 { 1974 CidrIp: aws.String(cidr), 1975 Description: aws.String(sgrDescription), 1976 }, 1977 }, 1978 } 1979 1980 input := &ec2.AuthorizeSecurityGroupEgressInput{ 1981 GroupId: aws.String(sgID), 1982 IpPermissions: []*ec2.IpPermission{ 1983 ipPerm, 1984 }, 1985 } 1986 result, err := ec2Svc.AuthorizeSecurityGroupEgress(input) 1987 if err != nil { 1988 return false, err 1989 } 1990 return *result.Return, nil 1991 } 1992 1993 func CreateSecurityGroupRule(e2eCtx *E2EContext, sgID string, sgrDescription string, cidr string, protocol string, fromPort int64, toPort int64, rt string) (bool, error) { 1994 switch rt { 1995 case "ingress": 1996 return CreateSecurityGroupIngressRule(e2eCtx, sgID, sgrDescription, cidr, protocol, fromPort, toPort) 1997 case "egress": 1998 return CreateSecurityGroupEgressRule(e2eCtx, sgID, sgrDescription, cidr, protocol, fromPort, toPort) 1999 } 2000 return false, nil 2001 } 2002 2003 func CreateSecurityGroupIngressRuleWithSourceSG(e2eCtx *E2EContext, sgID string, protocol string, toPort int64, sourceSecurityGroupID string) (bool, error) { 2004 ec2Svc := ec2.New(e2eCtx.AWSSession) 2005 2006 ipPerm := &ec2.IpPermission{ 2007 FromPort: aws.Int64(toPort), 2008 ToPort: aws.Int64(toPort), 2009 IpProtocol: aws.String(protocol), 2010 UserIdGroupPairs: []*ec2.UserIdGroupPair{ 2011 { 2012 GroupId: aws.String(sourceSecurityGroupID), 2013 }, 2014 }, 2015 } 2016 input := &ec2.AuthorizeSecurityGroupIngressInput{ 2017 GroupId: aws.String(sgID), 2018 IpPermissions: []*ec2.IpPermission{ 2019 ipPerm, 2020 }, 2021 } 2022 2023 result, err := ec2Svc.AuthorizeSecurityGroupIngress(input) 2024 if err != nil { 2025 return false, err 2026 } 2027 return *result.Return, nil 2028 } 2029 2030 func DeleteSecurityGroupIngressRule(e2eCtx *E2EContext, sgID, sgrID string) bool { 2031 ec2Svc := ec2.New(e2eCtx.AWSSession) 2032 2033 input := &ec2.RevokeSecurityGroupIngressInput{ 2034 SecurityGroupRuleIds: aws.StringSlice([]string{sgrID}), 2035 GroupId: aws.String(sgID), 2036 } 2037 2038 if _, err := ec2Svc.RevokeSecurityGroupIngress(input); err != nil { 2039 return false 2040 } 2041 return true 2042 } 2043 2044 func DeleteSecurityGroupEgressRule(e2eCtx *E2EContext, sgID, sgrID string) bool { 2045 ec2Svc := ec2.New(e2eCtx.AWSSession) 2046 2047 input := &ec2.RevokeSecurityGroupEgressInput{ 2048 SecurityGroupRuleIds: aws.StringSlice([]string{sgrID}), 2049 GroupId: aws.String(sgID), 2050 } 2051 2052 if _, err := ec2Svc.RevokeSecurityGroupEgress(input); err != nil { 2053 return false 2054 } 2055 return true 2056 } 2057 2058 func DeleteSecurityGroupRule(e2eCtx *E2EContext, sgID, sgrID, rt string) bool { 2059 switch rt { 2060 case "ingress": 2061 return DeleteSecurityGroupIngressRule(e2eCtx, sgID, sgrID) 2062 case "egress": 2063 return DeleteSecurityGroupEgressRule(e2eCtx, sgID, sgrID) 2064 } 2065 return false 2066 } 2067 2068 func ListLoadBalancers(e2eCtx *E2EContext, clusterName string) ([]*elb.LoadBalancerDescription, error) { 2069 elbSvc := elb.New(e2eCtx.AWSSession) 2070 2071 input := &elb.DescribeLoadBalancersInput{ 2072 LoadBalancerNames: aws.StringSlice([]string{clusterName + "-apiserver"}), 2073 } 2074 2075 result, err := elbSvc.DescribeLoadBalancers(input) 2076 if err != nil { 2077 return nil, err 2078 } 2079 if result.LoadBalancerDescriptions == nil { 2080 return nil, nil 2081 } 2082 return result.LoadBalancerDescriptions, nil 2083 } 2084 2085 func DeleteLoadBalancer(e2eCtx *E2EContext, loadbalancerName string) bool { 2086 elbSvc := elb.New(e2eCtx.AWSSession) 2087 2088 input := &elb.DeleteLoadBalancerInput{ 2089 LoadBalancerName: aws.String(loadbalancerName), 2090 } 2091 2092 if _, err := elbSvc.DeleteLoadBalancer(input); err != nil { 2093 return false 2094 } 2095 return true 2096 } 2097 2098 func CreateEFS(e2eCtx *E2EContext, creationToken string) (*efs.FileSystemDescription, error) { 2099 efsSvc := efs.New(e2eCtx.BootstrapUserAWSSession) 2100 2101 input := &efs.CreateFileSystemInput{ 2102 CreationToken: aws.String(creationToken), 2103 Encrypted: aws.Bool(true), 2104 } 2105 efsOutput, err := efsSvc.CreateFileSystem(input) 2106 if err != nil { 2107 return nil, err 2108 } 2109 return efsOutput, nil 2110 } 2111 2112 func DescribeEFS(e2eCtx *E2EContext, efsID string) (*efs.FileSystemDescription, error) { 2113 efsSvc := efs.New(e2eCtx.BootstrapUserAWSSession) 2114 2115 input := &efs.DescribeFileSystemsInput{ 2116 FileSystemId: aws.String(efsID), 2117 } 2118 efsOutput, err := efsSvc.DescribeFileSystems(input) 2119 if err != nil { 2120 return nil, err 2121 } 2122 if efsOutput == nil || len(efsOutput.FileSystems) == 0 { 2123 return nil, &efs.FileSystemNotFound{ 2124 ErrorCode: aws.String(efs.ErrCodeFileSystemNotFound), 2125 } 2126 } 2127 return efsOutput.FileSystems[0], nil 2128 } 2129 2130 func DeleteEFS(e2eCtx *E2EContext, efsID string) (*efs.DeleteFileSystemOutput, error) { 2131 efsSvc := efs.New(e2eCtx.BootstrapUserAWSSession) 2132 2133 input := &efs.DeleteFileSystemInput{ 2134 FileSystemId: aws.String(efsID), 2135 } 2136 result, err := efsSvc.DeleteFileSystem(input) 2137 if err != nil { 2138 return nil, err 2139 } 2140 return result, nil 2141 } 2142 2143 func GetEFSState(e2eCtx *E2EContext, efsID string) (*string, error) { 2144 efs, err := DescribeEFS(e2eCtx, efsID) 2145 if err != nil { 2146 return nil, err 2147 } 2148 return efs.LifeCycleState, nil 2149 } 2150 2151 func CreateMountTargetOnEFS(e2eCtx *E2EContext, efsID string, vpcID string, sg string) (*efs.MountTargetDescription, error) { 2152 efsSvc := efs.New(e2eCtx.BootstrapUserAWSSession) 2153 2154 subnets, err := ListVpcSubnets(e2eCtx, vpcID) 2155 if err != nil { 2156 return nil, err 2157 } 2158 input := &efs.CreateMountTargetInput{ 2159 FileSystemId: aws.String(efsID), 2160 SecurityGroups: aws.StringSlice([]string{sg}), 2161 SubnetId: subnets[0].SubnetId, 2162 } 2163 result, err := efsSvc.CreateMountTarget(input) 2164 if err != nil { 2165 return nil, err 2166 } 2167 return result, nil 2168 } 2169 2170 func DeleteMountTarget(e2eCtx *E2EContext, mountTargetID string) (*efs.DeleteMountTargetOutput, error) { 2171 efsSvc := efs.New(e2eCtx.BootstrapUserAWSSession) 2172 2173 input := &efs.DeleteMountTargetInput{ 2174 MountTargetId: aws.String(mountTargetID), 2175 } 2176 result, err := efsSvc.DeleteMountTarget(input) 2177 if err != nil { 2178 return nil, err 2179 } 2180 return result, nil 2181 } 2182 2183 func GetMountTarget(e2eCtx *E2EContext, mountTargetID string) (*efs.MountTargetDescription, error) { 2184 efsSvc := efs.New(e2eCtx.BootstrapUserAWSSession) 2185 2186 input := &efs.DescribeMountTargetsInput{ 2187 MountTargetId: aws.String(mountTargetID), 2188 } 2189 result, err := efsSvc.DescribeMountTargets(input) 2190 if err != nil { 2191 return nil, err 2192 } 2193 if result.MountTargets == nil || len(result.MountTargets) == 0 { 2194 return nil, &efs.MountTargetNotFound{ 2195 ErrorCode: aws.String(efs.ErrCodeMountTargetNotFound), 2196 } 2197 } 2198 return result.MountTargets[0], nil 2199 } 2200 2201 func GetMountTargetState(e2eCtx *E2EContext, mountTargetID string) (*string, error) { 2202 result, err := GetMountTarget(e2eCtx, mountTargetID) 2203 if err != nil { 2204 return nil, err 2205 } 2206 return result.LifeCycleState, nil 2207 }