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  }