From 782ef31b9effa263cccbd84e1c5f472c7ab42dce Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Tue, 24 Oct 2023 22:05:42 +0200 Subject: [PATCH 01/33] tfvars: export config type This config will be use as a contractual input for alternative provision infrastructures. --- pkg/tfvars/aws/aws.go | 5 +++-- pkg/tfvars/tfvars.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/tfvars/aws/aws.go b/pkg/tfvars/aws/aws.go index 4b84d920695..976525217c8 100644 --- a/pkg/tfvars/aws/aws.go +++ b/pkg/tfvars/aws/aws.go @@ -16,7 +16,8 @@ import ( typesaws "github.com/openshift/installer/pkg/types/aws" ) -type config struct { +// Config contains the AWS platform data for terraform. +type Config struct { AMI string `json:"aws_ami"` AMIRegion string `json:"aws_ami_region"` CustomEndpoints map[string]string `json:"custom_endpoints,omitempty"` @@ -179,7 +180,7 @@ func TFVars(sources TFVarsSources) ([]byte, error) { return nil, errors.New("EBS IOPS must be configured for the io1 root volume") } - cfg := &config{ + cfg := &Config{ CustomEndpoints: endpoints, Region: masterConfig.Placement.Region, ExtraTags: tags, diff --git a/pkg/tfvars/tfvars.go b/pkg/tfvars/tfvars.go index 0ee415c9354..3e2bbd799a1 100644 --- a/pkg/tfvars/tfvars.go +++ b/pkg/tfvars/tfvars.go @@ -9,7 +9,8 @@ import ( "github.com/pkg/errors" ) -type config struct { +// Config contains the cluster data for terraform. +type Config struct { ClusterID string `json:"cluster_id,omitempty"` ClusterDomain string `json:"cluster_domain,omitempty"` BaseDomain string `json:"base_domain,omitempty"` @@ -38,7 +39,7 @@ func TFVars(clusterID string, clusterDomain string, baseDomain string, machineV4 return nil, errors.Wrap(err, "failed to write bootstrap ignition") } - config := &config{ + config := &Config{ ClusterID: clusterID, ClusterDomain: strings.TrimSuffix(clusterDomain, "."), BaseDomain: strings.TrimSuffix(baseDomain, "."), From 8f5c083d24feefbe9682e498c10599bc9e40edee Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 27 Oct 2023 14:44:51 +0200 Subject: [PATCH 02/33] pkg/infra/aws: add AWS SDK provisioning skeleton This commit lays out the foundation for the provision of the cluster infrastructure using the AWS SDK instead of terraform. Co-authored-by: Enxebre Co-authored-by: Patrick --- pkg/infrastructure/aws/aws.go | 109 ++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 pkg/infrastructure/aws/aws.go diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go new file mode 100644 index 00000000000..9ee41eba507 --- /dev/null +++ b/pkg/infrastructure/aws/aws.go @@ -0,0 +1,109 @@ +package aws + +import ( + "encoding/json" + "fmt" + + "github.com/aws/aws-sdk-go/service/ec2" + "k8s.io/apimachinery/pkg/util/sets" + + "github.com/openshift/installer/pkg/asset" + awssession "github.com/openshift/installer/pkg/asset/installconfig/aws" + "github.com/openshift/installer/pkg/infrastructure" + "github.com/openshift/installer/pkg/tfvars" + awstfvars "github.com/openshift/installer/pkg/tfvars/aws" + "github.com/openshift/installer/pkg/types" + awstypes "github.com/openshift/installer/pkg/types/aws" +) + +const ( + tfVarsFileName = "terraform.tfvars.json" + tfPlatformVarsFileName = "terraform.platform.auto.tfvars.json" + + ownedTagKey = "kubernetes.io/cluster/%s" + ownedTagValue = "owned" +) + +// InfraProvider is the AWS SDK infra provider. +type InfraProvider struct{} + +// InitializeProvider initializes the AWS SDK provider. +func InitializeProvider() infrastructure.Provider { + return InfraProvider{} +} + +// Provision creates the infrastructure resources for the stage. +// dir: the path of the install dir +// vars: cluster configuration input variables, such as terraform variables files +// returns a slice of File assets, which will be appended to the cluster asset file list. +func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, error) { + // Unmarshall input from tf variables, so we can use it along with + // installConfig and other assets as the contractual input regardless of + // the implementation. + clusterConfig := &tfvars.Config{} + clusterAWSConfig := &awstfvars.Config{} + for _, file := range vars { + switch file.Filename { + case tfVarsFileName: + if err := json.Unmarshal(file.Data, clusterConfig); err != nil { + return nil, err + } + case tfPlatformVarsFileName: + if err := json.Unmarshal(file.Data, clusterAWSConfig); err != nil { + return nil, err + } + } + } + + if clusterConfig == (&tfvars.Config{}) || clusterAWSConfig == (&awstfvars.Config{}) { + return nil, fmt.Errorf("could not find terraform config files") + } + + eps := []awstypes.ServiceEndpoint{} + for k, v := range clusterAWSConfig.CustomEndpoints { + eps = append(eps, awstypes.ServiceEndpoint{Name: k, URL: v}) + } + + awsSession, err := awssession.GetSessionWithOptions( + awssession.WithRegion(clusterAWSConfig.Region), + awssession.WithServiceEndpoints(clusterAWSConfig.Region, eps), + ) + if err != nil { + return nil, err + } + + availabilityZones := sets.New(clusterAWSConfig.MasterSecurityGroups...) + availabilityZones.Insert(clusterAWSConfig.WorkerAvailabilityZones...) + + tags := mergeTags(clusterAWSConfig.ExtraTags, map[string]string{ + clusterOwnedTag(clusterConfig.ClusterID): ownedTagValue, + }) + _ = ec2.New(awsSession) + + return nil, fmt.Errorf("provision stage not implemented yet") +} + +// DestroyBootstrap destroys the temporary bootstrap resources. +func (a InfraProvider) DestroyBootstrap(dir string) error { + return nil +} + +// ExtractHostAddresses extracts the IPs of the bootstrap and control plane machines. +func (a InfraProvider) ExtractHostAddresses(dir string, ic *types.InstallConfig, ha *infrastructure.HostAddresses) error { + return nil +} + +func mergeTags(lhsTags, rhsTags map[string]string) map[string]string { + merged := make(map[string]string, len(lhsTags)+len(rhsTags)) + for k, v := range lhsTags { + merged[k] = v + } + for k, v := range rhsTags { + merged[k] = v + } + return merged +} + +func clusterOwnedTag(infraID string) string { + return fmt.Sprintf(ownedTagKey, infraID) +} From 1d345f95e1bcf1ee0b1ec6f5795e1f39758a99de Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 27 Oct 2023 14:35:49 +0200 Subject: [PATCH 03/33] CORS-2885: infra/aws: create VPC with minimal customizations For now we create all the resources and don't support BYO. Co-authored-by: Enxebre --- pkg/infrastructure/aws/aws.go | 28 +- pkg/infrastructure/aws/vpc.go | 999 ++++++++++++++++++++++++++++++++++ 2 files changed, 1026 insertions(+), 1 deletion(-) create mode 100644 pkg/infrastructure/aws/vpc.go diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 9ee41eba507..261fb2125b6 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -1,10 +1,13 @@ package aws import ( + "context" "encoding/json" "fmt" + "time" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/sets" "github.com/openshift/installer/pkg/asset" @@ -78,7 +81,30 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, tags := mergeTags(clusterAWSConfig.ExtraTags, map[string]string{ clusterOwnedTag(clusterConfig.ClusterID): ownedTagValue, }) - _ = ec2.New(awsSession) + + logger := logrus.StandardLogger() + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) + defer cancel() + + logger.Infoln("Creating VPC resources") + ec2Client := ec2.New(awsSession) + vpcInput := vpcInputOptions{ + infraID: clusterConfig.ClusterID, + region: clusterAWSConfig.Region, + vpcID: clusterAWSConfig.VPC, + cidrV4Block: clusterConfig.MachineV4CIDRs[0], + zones: sets.List(availabilityZones), + tags: tags, + privateSubnetIDs: clusterAWSConfig.PrivateSubnets, + } + if clusterAWSConfig.PublicSubnets != nil { + vpcInput.publicSubnetIDs = *clusterAWSConfig.PublicSubnets + } + + _, err = createVPCResources(ctx, logger, ec2Client, &vpcInput) + if err != nil { + return nil, fmt.Errorf("failed to create VPC resources: %w", err) + } return nil, fmt.Errorf("provision stage not implemented yet") } diff --git a/pkg/infrastructure/aws/vpc.go b/pkg/infrastructure/aws/vpc.go new file mode 100644 index 00000000000..63c1d0747a1 --- /dev/null +++ b/pkg/infrastructure/aws/vpc.go @@ -0,0 +1,999 @@ +package aws + +import ( + "context" + "errors" + "fmt" + "math" + "net" + "strings" + "time" + + "github.com/apparentlymart/go-cidr/cidr" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/util/wait" +) + +var ( + errNotFound = errors.New("not found") + + defaultBackoff = wait.Backoff{ + Steps: 10, + Duration: 3 * time.Second, + Factor: 1.0, + Jitter: 0.1, + } +) + +const ( + errVpcIDNotFound = "InvalidVpcID.NotFound" + errNatGatewayIDNotFound = "InvalidNatGatewayID.NotFound" + errInvalidEIPNotFound = "InvalidElasticIpID.NotFound" + errRouteTableIDNotFound = "InvalidRouteTableId.NotFound" + errInvalidSubnet = "InvalidSubnet" + errAuthFailure = "AuthFailure" + errIPAddrInUse = "InvalidIPAddress.InUse" + + quadZeroRoute = "0.0.0.0/0" +) + +type vpcInputOptions struct { + infraID string + region string + vpcID string + cidrV4Block string + zones []string + publicSubnetIDs []string + privateSubnetIDs []string + tags map[string]string +} + +type vpcState struct { + input *vpcInputOptions + // created resources + vpcID *string + igwID *string +} + +type vpcOutput struct { + vpcID string + publicSubnetIDs []string + privateSubnetIDs []string + zoneToSubnetMap map[string]string +} + +func createVPCResources(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, vpcInput *vpcInputOptions) (*vpcOutput, error) { + state := vpcState{input: vpcInput} + endpointRouteTableIDs := make([]*string, 0, len(vpcInput.zones)+1) + + vpc, err := state.ensureVPC(ctx, logger, ec2Client) + if err != nil { + return nil, err + } + state.vpcID = vpc.VpcId + + _, err = state.ensureDHCPOptions(ctx, logger, ec2Client, vpc.VpcId) + if err != nil { + return nil, err + } + + igw, err := state.ensureInternetGateway(ctx, logger, ec2Client, vpc.VpcId) + if err != nil { + return nil, err + } + state.igwID = igw.InternetGatewayId + + publicRouteTable, err := state.ensurePublicRouteTable(ctx, logger, ec2Client) + if err != nil { + return nil, err + } + endpointRouteTableIDs = append(endpointRouteTableIDs, publicRouteTable.RouteTableId) + + // Per-zone resources + privateNetwork, publicNetwork, err := splitNetworks(vpcInput.cidrV4Block, len(vpcInput.zones)) + if err != nil { + return nil, err + } + + publicSubnetIDs, publicSubnetZoneMap, err := state.ensurePublicSubnets(ctx, logger, ec2Client, publicNetwork, publicRouteTable) + if err != nil { + return nil, err + } + + privateSubnetIDs, privateSubnetZoneMap, err := state.ensurePrivateSubnets(ctx, logger, ec2Client, privateNetwork) + if err != nil { + return nil, err + } + + for _, zone := range vpcInput.zones { + var natGwID *string + if len(publicSubnetZoneMap) > 0 { + natGw, err := state.ensureNatGateway(ctx, logger, ec2Client, publicSubnetZoneMap[zone], zone) + if err != nil { + return nil, fmt.Errorf("failed to create NAT gateway for zone (%s): %w", zone, err) + } + natGwID = natGw.NatGatewayId + } + + privateRouteTable, err := state.ensurePrivateRouteTable(ctx, logger, ec2Client, natGwID, privateSubnetZoneMap[zone], zone) + if err != nil { + return nil, fmt.Errorf("failed to create private route table for zone (%s): %w", zone, err) + } + endpointRouteTableIDs = append(endpointRouteTableIDs, privateRouteTable.RouteTableId) + } + + _, err = state.ensureVPCS3Endpoint(ctx, logger, ec2Client, endpointRouteTableIDs) + if err != nil { + return nil, fmt.Errorf("failed to create VPC S3 endpoint: %w", err) + } + + return &vpcOutput{ + vpcID: aws.StringValue(state.vpcID), + privateSubnetIDs: aws.StringValueSlice(privateSubnetIDs), + publicSubnetIDs: aws.StringValueSlice(publicSubnetIDs), + zoneToSubnetMap: aws.StringValueMap(privateSubnetZoneMap), + }, nil +} + +func (o *vpcState) ensureVPC(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API) (*ec2.Vpc, error) { + vpcName := fmt.Sprintf("%s-vpc", o.input.infraID) + l := logger.WithField("vpc", vpcName) + + createdOrFoundMsg := "Found existing VPC" + vpc, err := existingVPC(ctx, client, ec2Filters(o.input.infraID, vpcName)) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + createdOrFoundMsg = "Created VPC" + tags := mergeTags(o.input.tags, map[string]string{"Name": vpcName}) + var res *ec2.CreateVpcOutput + res, err = client.CreateVpcWithContext(ctx, + &ec2.CreateVpcInput{ + CidrBlock: aws.String(o.input.cidrV4Block), + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("vpc"), + Tags: ec2Tags(tags), + }, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to create VPC: %w", err) + } + vpc = res.Vpc + } + l = l.WithField("id", aws.StringValue(vpc.VpcId)) + l.Infoln(createdOrFoundMsg) + + // Enable DNS support + _, err = client.ModifyVpcAttributeWithContext(ctx, + &ec2.ModifyVpcAttributeInput{ + VpcId: vpc.VpcId, + EnableDnsSupport: &ec2.AttributeBooleanValue{Value: aws.Bool(true)}, + }) + if err != nil { + return nil, fmt.Errorf("failed to enable DNS support on VPC: %w", err) + } + l.Infoln("Enabled DNS support on VPC") + + // Enable DNS hostnames + _, err = client.ModifyVpcAttributeWithContext(ctx, + &ec2.ModifyVpcAttributeInput{ + VpcId: vpc.VpcId, + EnableDnsHostnames: &ec2.AttributeBooleanValue{Value: aws.Bool(true)}, + }) + if err != nil { + return nil, fmt.Errorf("failed to enable DNS hostnames on VPC: %w", err) + } + l.Infoln("Enabled DNS hostnames on VPC") + + return vpc, nil +} + +func existingVPC(ctx context.Context, client ec2iface.EC2API, filters []*ec2.Filter) (*ec2.Vpc, error) { + result, err := client.DescribeVpcsWithContext(ctx, &ec2.DescribeVpcsInput{Filters: filters}) + if err != nil { + return nil, fmt.Errorf("failed to list VPCs: %w", err) + } + for _, vpc := range result.Vpcs { + return vpc, nil + } + return nil, errNotFound +} + +func (o *vpcState) ensureDHCPOptions(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, vpcID *string) (*ec2.DhcpOptions, error) { + filters := ec2Filters(o.input.infraID, "") + foundOrCreatedMsg := "Found existing DHCP options" + opt, err := existingDHCPOptions(ctx, client, filters) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + var domainName string + switch o.input.region { + case "us-east-1": + domainName = "ec2.internal" + default: + domainName = fmt.Sprintf("%s.compute.internal", o.input.region) + } + foundOrCreatedMsg = "Created DHCP options" + res, err := client.CreateDhcpOptionsWithContext(ctx, &ec2.CreateDhcpOptionsInput{ + DhcpConfigurations: []*ec2.NewDhcpConfiguration{ + { + Key: aws.String("domain-name"), + Values: aws.StringSlice([]string{domainName}), + }, + { + Key: aws.String("domain-name-servers"), + Values: aws.StringSlice([]string{"AmazonProvidedDNS"}), + }, + }, + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("dhcp-options"), + Tags: ec2Tags(o.input.tags), + }, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to create DHCP options: %w", err) + } + opt = res.DhcpOptions + } + l := logger.WithField("id", aws.StringValue(opt.DhcpOptionsId)) + l.Infoln(foundOrCreatedMsg) + + _, err = client.AssociateDhcpOptionsWithContext(ctx, &ec2.AssociateDhcpOptionsInput{ + DhcpOptionsId: opt.DhcpOptionsId, + VpcId: vpcID, + }) + if err != nil { + return nil, fmt.Errorf("failed to associate DHCP options to VPC: %w", err) + } + l.WithField("vpcID", aws.StringValue(vpcID)).Infoln("Associated DHCP options with VPC") + + return opt, nil +} + +func existingDHCPOptions(ctx context.Context, client ec2iface.EC2API, filters []*ec2.Filter) (*ec2.DhcpOptions, error) { + res, err := client.DescribeDhcpOptionsWithContext(ctx, &ec2.DescribeDhcpOptionsInput{Filters: filters}) + if err != nil { + return nil, fmt.Errorf("failed to list DHCP options: %w", err) + } + for _, opt := range res.DhcpOptions { + return opt, nil + } + return nil, errNotFound +} + +func (o *vpcState) ensureInternetGateway(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, vpcID *string) (*ec2.InternetGateway, error) { + gatewayName := fmt.Sprintf("%s-igw", o.input.infraID) + filters := ec2Filters(o.input.infraID, gatewayName) + foundOrCreatedMsg := "Found existing Internet Gateway" + igw, err := existingInternetGateway(ctx, client, filters) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + tags := mergeTags(o.input.tags, map[string]string{"Name": gatewayName}) + foundOrCreatedMsg = "Created Internet Gateway" + res, err := client.CreateInternetGatewayWithContext(ctx, &ec2.CreateInternetGatewayInput{ + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("internet-gateway"), + Tags: ec2Tags(tags), + }, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to create internet gateway: %w", err) + } + igw = res.InternetGateway + } + l := logger.WithField("id", aws.StringValue(igw.InternetGatewayId)) + l.Infoln(foundOrCreatedMsg) + + l = l.WithField("vpc", aws.StringValue(vpcID)) + attached := false + for _, attachment := range igw.Attachments { + if aws.StringValue(attachment.VpcId) == aws.StringValue(vpcID) { + attached = true + break + } + } + if !attached { + _, err := client.AttachInternetGatewayWithContext(ctx, &ec2.AttachInternetGatewayInput{ + InternetGatewayId: igw.InternetGatewayId, + VpcId: vpcID, + }) + if err != nil { + return nil, fmt.Errorf("failed to attach internet gateway to VPC: %w", err) + } + l.Infoln("Attached Internet Gateway to VPC") + } else { + l.Infoln("Internet Gateway already attached to VPC") + } + + return igw, nil +} + +func existingInternetGateway(ctx context.Context, client ec2iface.EC2API, filters []*ec2.Filter) (*ec2.InternetGateway, error) { + res, err := client.DescribeInternetGatewaysWithContext(ctx, &ec2.DescribeInternetGatewaysInput{Filters: filters}) + if err != nil { + return nil, fmt.Errorf("failed to list internet gateways: %w", err) + } + for _, igw := range res.InternetGateways { + return igw, nil + } + return nil, errNotFound +} + +func (o *vpcState) ensurePublicRouteTable(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API) (*ec2.RouteTable, error) { + tableName := fmt.Sprintf("%s-public", o.input.infraID) + l := logger.WithField("route table", tableName) + routeTable, err := o.ensureRouteTable(ctx, l, client, tableName) + if err != nil { + return nil, fmt.Errorf("failed to create public route table: %w", err) + } + l = l.WithField("id", aws.StringValue(routeTable.RouteTableId)) + + // Replace the VPC's main route table + l.Debugln("Replacing VPC's main route table association") + filters := []*ec2.Filter{ + {Name: aws.String("vpc-id"), Values: []*string{o.vpcID}}, + {Name: aws.String("association.main"), Values: aws.StringSlice([]string{"true"})}, + } + rTableInfo, err := existingRouteTable(ctx, client, filters) + if err != nil { + if errors.Is(err, errNotFound) { + return nil, fmt.Errorf("no main route table associated with the VPC") + } + return nil, fmt.Errorf("failed to get main route table: %w", err) + } + ml := logger.WithField("id", aws.StringValue(rTableInfo.RouteTableId)) + ml.Debugln("Found main route table") + + // Replace route table association only if it's not the associated route table already + if tID := rTableInfo.RouteTableId; tID != routeTable.RouteTableId { + var associationID *string + for _, assoc := range rTableInfo.Associations { + associationID = assoc.RouteTableAssociationId + break + } + if associationID == nil { + return nil, fmt.Errorf("no associations found for main route table") + } + _, err := client.ReplaceRouteTableAssociationWithContext(ctx, &ec2.ReplaceRouteTableAssociationInput{ + AssociationId: associationID, + RouteTableId: routeTable.RouteTableId, + }) + if err != nil { + return nil, fmt.Errorf("failed to replace vpc main route table: %w", err) + } + ml.Infoln("Associated public route table with VPC's main route table") + } else { + ml.Infoln("Public route table is already VPC's main route table association") + } + + // Create route to Internet Gateway + l.Debugln("Creating route to Internet Gateway") + if !hasInternetGatewayRoute(routeTable, o.igwID) { + _, err := client.CreateRouteWithContext(ctx, &ec2.CreateRouteInput{ + GatewayId: o.igwID, + RouteTableId: routeTable.RouteTableId, + DestinationCidrBlock: aws.String(quadZeroRoute), + }) + if err != nil { + return nil, fmt.Errorf("failed to create route to internet gateway: %w", err) + } + l.Infoln("Created route to Internet Gateway") + } else { + l.Infoln("Found existing route to Internet Gateway") + } + + return routeTable, nil +} + +func (o *vpcState) ensurePrivateRouteTable(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, natGwID *string, subnetID *string, zone string) (*ec2.RouteTable, error) { + tableName := fmt.Sprintf("%s-private-%s", o.input.infraID, zone) + l := logger.WithField("route table", tableName) + table, err := o.ensureRouteTable(ctx, l, client, tableName) + if err != nil { + return nil, err + } + + // Everything bellow is only needed if direct internet access is used + if natGwID == nil { + return table, nil + } + + createdOrFoundMsg := "Found existing route to Nat gateway" + if !hasNatGatewayRoute(table, natGwID) { + createdOrFoundMsg = "Created route to Nat gateway" + if err := createNatGatewayRoute(ctx, client, natGwID, table.RouteTableId); err != nil { + return nil, fmt.Errorf("failed to create route to nat gateway (%s): %w", aws.StringValue(natGwID), err) + } + } + l.WithField("nat gateway", aws.StringValue(natGwID)).Infoln(createdOrFoundMsg) + + createdOrFoundMsg = "Subnet already associated with route table" + if !hasAssociatedSubnet(table, subnetID) { + createdOrFoundMsg = "Associated subnet with route table" + _, err := client.AssociateRouteTableWithContext(ctx, &ec2.AssociateRouteTableInput{ + RouteTableId: table.RouteTableId, + SubnetId: subnetID, + }) + if err != nil { + return nil, fmt.Errorf("failed to associate subnet (%s) to route table (%s): %w", aws.StringValue(subnetID), aws.StringValue(table.RouteTableId), err) + } + } + l.WithField("subnet", aws.StringValue(subnetID)).Infoln(createdOrFoundMsg) + + return table, nil +} + +func createNatGatewayRoute(ctx context.Context, client ec2iface.EC2API, natGwID *string, tableID *string) error { + return wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + _, err = client.CreateRouteWithContext(ctx, &ec2.CreateRouteInput{ + NatGatewayId: natGwID, + RouteTableId: tableID, + DestinationCidrBlock: aws.String(quadZeroRoute), + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && (strings.EqualFold(awsErr.Code(), errNatGatewayIDNotFound) || strings.EqualFold(awsErr.Code(), errRouteTableIDNotFound)) { + return false, nil + } + return false, err + } + return true, nil + }, + ) +} + +func (o *vpcState) ensureRouteTable(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, tableName string) (*ec2.RouteTable, error) { + filters := ec2Filters(o.input.infraID, tableName) + createdOrFoundMsg := "Found existing route table" + routeTable, err := existingRouteTable(ctx, client, filters) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + tags := mergeTags(o.input.tags, map[string]string{"Name": tableName}) + createdOrFoundMsg = "Created route table" + routeTable, err = createRouteTable(ctx, client, o.vpcID, tags) + if err != nil { + return nil, err + } + } + logger.WithField("id", aws.StringValue(routeTable.RouteTableId)).Infoln(createdOrFoundMsg) + + return routeTable, nil +} + +// creates a route table and waits until it shows up. +func createRouteTable(ctx context.Context, client ec2iface.EC2API, vpcID *string, tags map[string]string) (*ec2.RouteTable, error) { + res, err := client.CreateRouteTableWithContext(ctx, &ec2.CreateRouteTableInput{ + VpcId: vpcID, + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("route-table"), + Tags: ec2Tags(tags), + }, + }, + }) + if err != nil { + return nil, err + } + routeTable := res.RouteTable + err = wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + res, err := client.DescribeRouteTablesWithContext(ctx, &ec2.DescribeRouteTablesInput{ + RouteTableIds: []*string{routeTable.RouteTableId}, + }) + if err != nil || len(res.RouteTables) == 0 { + return false, nil + } + return true, nil + }) + if err != nil { + return nil, fmt.Errorf("failed to find route table (%s) that was just created: %w", aws.StringValue(routeTable.RouteTableId), err) + } + + return routeTable, nil +} + +func existingRouteTable(ctx context.Context, client ec2iface.EC2API, filters []*ec2.Filter) (*ec2.RouteTable, error) { + res, err := client.DescribeRouteTablesWithContext(ctx, &ec2.DescribeRouteTablesInput{Filters: filters}) + if err != nil { + return nil, fmt.Errorf("failed to list route tables: %w", err) + } + for _, rt := range res.RouteTables { + return rt, nil + } + return nil, errNotFound +} + +func hasInternetGatewayRoute(table *ec2.RouteTable, igwID *string) bool { + for _, route := range table.Routes { + if aws.StringValue(route.GatewayId) == aws.StringValue(igwID) && aws.StringValue(route.DestinationCidrBlock) == quadZeroRoute { + return true + } + } + return false +} + +func hasNatGatewayRoute(table *ec2.RouteTable, natID *string) bool { + for _, route := range table.Routes { + if aws.StringValue(route.NatGatewayId) == aws.StringValue(natID) && aws.StringValue(route.DestinationCidrBlock) == quadZeroRoute { + return true + } + } + return false +} + +func hasAssociatedSubnet(table *ec2.RouteTable, subnetID *string) bool { + for _, assoc := range table.Associations { + if aws.StringValue(assoc.SubnetId) == aws.StringValue(subnetID) { + return true + } + } + return false +} + +func (o *vpcState) ensurePublicSubnets(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, network *net.IPNet, publicTable *ec2.RouteTable) ([]*string, map[string]*string, error) { + // used to designate it should be used for internet ELBs + const tagNameSubnetPublicELB = "kubernetes.io/role/elb" + tags := mergeTags(o.input.tags, map[string]string{ + tagNameSubnetPublicELB: "true", + }) + + ids, zoneMap, err := o.ensureSubnets(ctx, logger, client, network, "public", tags) + if err != nil { + return nil, nil, fmt.Errorf("failed to create public subnets: %w", err) + } + + err = addSubnetsToRouteTable(ctx, client, publicTable, ids) + if err != nil { + return nil, nil, fmt.Errorf("failed to associate public subnets with public route table (%s): %w", aws.StringValue(publicTable.RouteTableId), err) + } + + return ids, zoneMap, nil +} + +func (o *vpcState) ensurePrivateSubnets(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, network *net.IPNet) ([]*string, map[string]*string, error) { + // tag name used to designate the subnet should be used for internal ELBs + const tagNameSubnetInternalELB = "kubernetes.io/role/internal-elb" + tags := mergeTags(o.input.tags, map[string]string{ + tagNameSubnetInternalELB: "true", + }) + + ids, zoneMap, err := o.ensureSubnets(ctx, logger, client, network, "private", tags) + if err != nil { + return nil, nil, fmt.Errorf("failed to create private subnets: %w", err) + } + return ids, zoneMap, nil +} + +func (o *vpcState) ensureSubnets(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, network *net.IPNet, subnetType string, tags map[string]string) ([]*string, map[string]*string, error) { + subnetIDs := make([]*string, 0, len(o.input.zones)) + subnetZoneMap := make(map[string]*string, len(o.input.zones)) + newBits := int(math.Ceil(math.Log2(float64(len(o.input.zones))))) + for i, zone := range o.input.zones { + cidr, err := cidr.Subnet(network, newBits, i) + if err != nil { + return nil, nil, fmt.Errorf("failed to subnet %s network: %w", subnetType, err) + } + + name := fmt.Sprintf("%s-%s-%s", o.input.infraID, subnetType, zone) + subnet, err := o.ensureSubnet(ctx, logger, client, zone, cidr.String(), name, tags) + if err != nil { + return nil, nil, fmt.Errorf("failed to create %s subnet (%s): %w", subnetType, name, err) + } + subnetIDs = append(subnetIDs, subnet.SubnetId) + subnetZoneMap[zone] = subnet.SubnetId + } + + return subnetIDs, subnetZoneMap, nil +} + +func (o *vpcState) ensureSubnet(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, zone string, cidr string, name string, tags map[string]string) (*ec2.Subnet, error) { + l := logger.WithField("subnet", name) + filters := ec2Filters(o.input.infraID, name) + createdOrFoundMsg := "Found existing subnet" + subnet, err := existingSubnet(ctx, client, filters) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + tags := mergeTags(tags, map[string]string{"Name": name}) + createdOrFoundMsg = "Created subnet" + res, err := client.CreateSubnetWithContext(ctx, &ec2.CreateSubnetInput{ + AvailabilityZone: aws.String(zone), + VpcId: o.vpcID, + CidrBlock: aws.String(cidr), + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("subnet"), + Tags: ec2Tags(tags), + }, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to create subnet: %w", err) + } + subnet = res.Subnet + } + l.Infoln(createdOrFoundMsg) + + err = wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + res, err := client.DescribeSubnetsWithContext(ctx, &ec2.DescribeSubnetsInput{ + SubnetIds: []*string{subnet.SubnetId}, + }) + if err != nil || len(res.Subnets) == 0 { + return false, nil + } + return true, nil + }) + if err != nil { + return nil, fmt.Errorf("failed to find subnet (%s) that was just created: %w", aws.StringValue(subnet.SubnetId), err) + } + + return subnet, nil +} + +func existingSubnet(ctx context.Context, client ec2iface.EC2API, filters []*ec2.Filter) (*ec2.Subnet, error) { + res, err := client.DescribeSubnetsWithContext(ctx, &ec2.DescribeSubnetsInput{Filters: filters}) + if err != nil { + return nil, fmt.Errorf("failed to list subnets: %w", err) + } + for _, subnet := range res.Subnets { + return subnet, nil + } + return nil, errNotFound +} + +func (o *vpcState) ensureNatGateway(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, subnetID *string, zone string) (*ec2.NatGateway, error) { + natName := fmt.Sprintf("%s-nat-%s", o.input.infraID, zone) + l := logger.WithField("nat gateway", natName) + filters := ec2Filters(o.input.infraID, natName) + + createdOrFoundMsg := "Found existing Nat gateway" + natGW, err := existingNatGateway(ctx, client, filters) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + + // First allocate an EIP address + eipName := fmt.Sprintf("%s-eip-%s", o.input.infraID, zone) + eipTags := mergeTags(o.input.tags, map[string]string{"Name": eipName}) + allocID, err := ensureEIP(ctx, client, eipTags) + if err != nil { + return nil, err + } + + tags := mergeTags(o.input.tags, map[string]string{"Name": natName}) + createdOrFoundMsg = "Created Nat gateway" + natGW, err = createNatGateway(ctx, client, allocID, subnetID, tags) + if err != nil { + return nil, fmt.Errorf("failed to create nat gateway: %w", err) + } + } + l.WithField("id", aws.StringValue(natGW.NatGatewayId)).Infoln(createdOrFoundMsg) + + return natGW, nil +} + +func ensureEIP(ctx context.Context, client ec2iface.EC2API, tags map[string]string) (*string, error) { + res, err := client.AllocateAddressWithContext(ctx, &ec2.AllocateAddressInput{ + Domain: aws.String("vpc"), + }) + if err != nil { + return nil, fmt.Errorf("failed to allocate EIP: %w", err) + } + + isErrorRetriable := func(err error) bool { + var awsErr awserr.Error + if errors.As(err, &awsErr) { + return strings.EqualFold(awsErr.Code(), errInvalidEIPNotFound) + } + return false + } + + ec2Tags := ec2Tags(tags) + // NOTE: there is a potential to leak EIP addresses if the following tag + // and release operations fail, since we have no way of recognizing the EIP + // as belonging to the cluster + err = wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + _, err = client.CreateTagsWithContext(ctx, &ec2.CreateTagsInput{ + Resources: []*string{res.AllocationId}, + Tags: ec2Tags, + }) + if err != nil { + if isErrorRetriable(err) { + return false, nil + } + return true, err + } + return true, nil + }, + ) + if err != nil { + if rerr := releaseEIP(ctx, client, res.AllocationId); rerr != nil { + return nil, rerr + } + return nil, fmt.Errorf("failed to tag EIP (%s): %w", aws.StringValue(res.AllocationId), err) + } + + return res.AllocationId, nil +} + +func releaseEIP(ctx context.Context, client ec2iface.EC2API, allocID *string) error { + err := wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + _, err = client.DisassociateAddressWithContext(ctx, &ec2.DisassociateAddressInput{ + AssociationId: allocID, + }) + if err != nil { + return false, nil + } + + _, err = client.ReleaseAddressWithContext(ctx, &ec2.ReleaseAddressInput{ + AllocationId: allocID, + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) { + // IP address already released: see https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ReleaseAddress.html + if strings.EqualFold(awsErr.Code(), errAuthFailure) { + return true, nil + } + // Must be disassociated first + if strings.EqualFold(awsErr.Code(), errIPAddrInUse) { + return false, nil + } + } + return false, nil + } + return true, nil + }, + ) + if err != nil { + return fmt.Errorf("failed to release untagged EIP (%s): %w", aws.StringValue(allocID), err) + } + return nil +} + +func createNatGateway(ctx context.Context, client ec2iface.EC2API, allocID *string, subnetID *string, tags map[string]string) (*ec2.NatGateway, error) { + isErrorRetriable := func(err error) bool { + var awsErr awserr.Error + if errors.As(err, &awsErr) { + return strings.EqualFold(awsErr.Code(), errInvalidSubnet) || strings.EqualFold(awsErr.Code(), errInvalidEIPNotFound) + } + return false + } + ec2Tags := ec2Tags(tags) + var natGW *ec2.NatGateway + err := wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + res, err := client.CreateNatGatewayWithContext(ctx, &ec2.CreateNatGatewayInput{ + AllocationId: allocID, + SubnetId: subnetID, + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("natgateway"), + Tags: ec2Tags, + }, + }, + }) + if err != nil { + if isErrorRetriable(err) { + return false, nil + } + return true, err + } + natGW = res.NatGateway + return true, nil + }, + ) + if err != nil { + return nil, err + } + + return natGW, nil +} + +func existingNatGateway(ctx context.Context, client ec2iface.EC2API, filters []*ec2.Filter) (*ec2.NatGateway, error) { + res, err := client.DescribeNatGatewaysWithContext(ctx, &ec2.DescribeNatGatewaysInput{Filter: filters}) + if err != nil { + return nil, fmt.Errorf("failed to list Nat gateways: %w", err) + } + for _, nat := range res.NatGateways { + state := aws.StringValue(nat.State) + if state == "deleted" || state == "deleting" || state == "failed" { + continue + } + return nat, nil + } + return nil, errNotFound +} + +func (o *vpcState) ensureVPCS3Endpoint(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, routeTableIDs []*string) (*ec2.VpcEndpoint, error) { + filters := ec2Filters(o.input.infraID, "") + createdOrFoundMsg := "Found existing VPC S3 endpoint" + endpoint, err := existingVPCEndpoint(ctx, client, filters) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + createdOrFoundMsg = "Created VPC S3 endpoint" + serviceName := fmt.Sprintf("com.amazonaws.%s.s3", o.input.region) + endpoint, err = createVPCEndpoint(ctx, client, serviceName, o.vpcID, routeTableIDs, o.input.tags) + if err != nil { + return nil, err + } + } + logger.WithField("id", aws.StringValue(endpoint.VpcEndpointId)).Infoln(createdOrFoundMsg) + + return endpoint, nil +} + +func createVPCEndpoint(ctx context.Context, client ec2iface.EC2API, serviceName string, vpcID *string, routeTableIDs []*string, tags map[string]string) (*ec2.VpcEndpoint, error) { + ec2Tags := ec2Tags(tags) + var vpcEndpoint *ec2.VpcEndpoint + err := wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + res, err := client.CreateVpcEndpointWithContext(ctx, &ec2.CreateVpcEndpointInput{ + VpcId: vpcID, + ServiceName: aws.String(serviceName), + RouteTableIds: routeTableIDs, + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("vpc-endpoint"), + Tags: ec2Tags, + }, + }, + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) { + if strings.EqualFold(awsErr.Code(), errRouteTableIDNotFound) { + return false, nil + } + } + return true, err + } + vpcEndpoint = res.VpcEndpoint + return true, nil + }, + ) + if err != nil { + return nil, fmt.Errorf("failed to create VPC endpoint: %w", err) + } + + return vpcEndpoint, nil +} + +func existingVPCEndpoint(ctx context.Context, client ec2iface.EC2API, filters []*ec2.Filter) (*ec2.VpcEndpoint, error) { + res, err := client.DescribeVpcEndpointsWithContext(ctx, &ec2.DescribeVpcEndpointsInput{Filters: filters}) + if err != nil { + return nil, fmt.Errorf("failed to list VPC endpoints: %w", err) + } + for _, endpoint := range res.VpcEndpoints { + return endpoint, nil + } + return nil, errNotFound +} + +func splitNetworks(cidrBlock string, numZones int) (*net.IPNet, *net.IPNet, error) { + _, network, err := net.ParseCIDR(cidrBlock) + if err != nil { + return nil, nil, fmt.Errorf("failed to parse IPv4 CIDR blocks: %w", err) + } + + privateNetwork, err := cidr.Subnet(network, 1, 0) + if err != nil { + return nil, nil, fmt.Errorf("failed to determine private subnet: %w", err) + } + + publicNetwork, err := cidr.Subnet(network, 1, 1) + if err != nil { + return nil, nil, fmt.Errorf("failed to determine public subnet: %w", err) + } + + // If a single-zone deployment, the available CIDR block is split into two + // to allow for user expansion + if numZones == 1 { + privateNetwork, err = cidr.Subnet(privateNetwork, 1, 0) + if err != nil { + return nil, nil, fmt.Errorf("failed to split private subnet in single-zone deployment: %w", err) + } + publicNetwork, err = cidr.Subnet(publicNetwork, 1, 0) + if err != nil { + return nil, nil, fmt.Errorf("failed to split public subnet in single-zone deployment: %w", err) + } + } + + return privateNetwork, publicNetwork, nil +} + +func addSubnetsToRouteTable(ctx context.Context, client ec2iface.EC2API, table *ec2.RouteTable, subnetIDs []*string) error { + for _, subnetID := range subnetIDs { + if hasAssociatedSubnet(table, subnetID) { + continue + } + err := wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (bool, error) { + _, err := client.AssociateRouteTableWithContext(ctx, &ec2.AssociateRouteTableInput{ + RouteTableId: table.RouteTableId, + SubnetId: subnetID, + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && strings.EqualFold(awsErr.Code(), errRouteTableIDNotFound) { + return false, nil + } + return false, err + } + return true, nil + }, + ) + if err != nil { + return fmt.Errorf("failed to associate subnet (%s) with route table: %w", aws.StringValue(subnetID), err) + } + } + return nil +} + +func ec2Filters(infraID, name string) []*ec2.Filter { + filters := []*ec2.Filter{ + { + Name: aws.String(fmt.Sprintf("tag:%s", clusterOwnedTag(infraID))), + Values: aws.StringSlice([]string{ownedTagValue}), + }, + } + if len(name) > 0 { + filters = append(filters, &ec2.Filter{ + Name: aws.String("tag:Name"), + Values: aws.StringSlice([]string{name}), + }) + } + return filters +} + +func ec2Tags(tags map[string]string) []*ec2.Tag { + ec2Tags := make([]*ec2.Tag, 0, len(tags)) + for k, v := range tags { + k, v := k, v // needed because we use the addresses + ec2Tags = append(ec2Tags, &ec2.Tag{ + Key: aws.String(k), + Value: aws.String(v), + }) + } + return ec2Tags +} From 160c49773b6fee7047198f59c7748b7469a22ca6 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 27 Oct 2023 14:37:46 +0200 Subject: [PATCH 04/33] infra/aws: add unit tests for VPC creation --- pkg/infrastructure/aws/provision_test.go | 1932 ++++++++++++++++++++++ 1 file changed, 1932 insertions(+) create mode 100644 pkg/infrastructure/aws/provision_test.go diff --git a/pkg/infrastructure/aws/provision_test.go b/pkg/infrastructure/aws/provision_test.go new file mode 100644 index 00000000000..e6660684fb3 --- /dev/null +++ b/pkg/infrastructure/aws/provision_test.go @@ -0,0 +1,1932 @@ +package aws + +import ( + "context" + "errors" + "io" + "net" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +type mockEC2Client struct { + ec2iface.EC2API + + // swappable functions + createVpc func(*ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) + describeVpcs func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) + modifyVpcAttribute func(*ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) + + createIgw func(*ec2.CreateInternetGatewayInput) (*ec2.CreateInternetGatewayOutput, error) + describeIgws func(*ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) + attachIgw func(*ec2.AttachInternetGatewayInput) (*ec2.AttachInternetGatewayOutput, error) + + createDHCPOpts func(*ec2.CreateDhcpOptionsInput) (*ec2.CreateDhcpOptionsOutput, error) + describeDHCPOpts func(*ec2.DescribeDhcpOptionsInput) (*ec2.DescribeDhcpOptionsOutput, error) + assocOpts func(*ec2.AssociateDhcpOptionsInput) (*ec2.AssociateDhcpOptionsOutput, error) + + createRouteTable func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) + describeRouteTables func(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) + replaceRouteTableAssoc func(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) + assocRouteTable func(*ec2.AssociateRouteTableInput) (*ec2.AssociateRouteTableOutput, error) + createRoute func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) + + createSubnet func(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) + describeSubnets func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) + + allocAddr func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) + createTags func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) + disassocAddr func(*ec2.DisassociateAddressInput) (*ec2.DisassociateAddressOutput, error) + releaseAddr func(*ec2.ReleaseAddressInput) (*ec2.ReleaseAddressOutput, error) + + createNat func(*ec2.CreateNatGatewayInput) (*ec2.CreateNatGatewayOutput, error) + describeNats func(*ec2.DescribeNatGatewaysInput) (*ec2.DescribeNatGatewaysOutput, error) + + createVpcEndpoint func(*ec2.CreateVpcEndpointInput) (*ec2.CreateVpcEndpointOutput, error) + describeVpcEndpoints func(*ec2.DescribeVpcEndpointsInput) (*ec2.DescribeVpcEndpointsOutput, error) +} + +func (m *mockEC2Client) DescribeVpcsWithContext(_ context.Context, in *ec2.DescribeVpcsInput, _ ...request.Option) (*ec2.DescribeVpcsOutput, error) { + return m.describeVpcs(in) +} + +func (m *mockEC2Client) CreateVpcWithContext(_ context.Context, in *ec2.CreateVpcInput, _ ...request.Option) (*ec2.CreateVpcOutput, error) { + return m.createVpc(in) +} + +func (m *mockEC2Client) ModifyVpcAttributeWithContext(_ context.Context, in *ec2.ModifyVpcAttributeInput, _ ...request.Option) (*ec2.ModifyVpcAttributeOutput, error) { + return m.modifyVpcAttribute(in) +} + +func (m *mockEC2Client) DescribeInternetGatewaysWithContext(_ context.Context, in *ec2.DescribeInternetGatewaysInput, _ ...request.Option) (*ec2.DescribeInternetGatewaysOutput, error) { + return m.describeIgws(in) +} + +func (m *mockEC2Client) CreateInternetGatewayWithContext(_ context.Context, in *ec2.CreateInternetGatewayInput, _ ...request.Option) (*ec2.CreateInternetGatewayOutput, error) { + return m.createIgw(in) +} + +func (m *mockEC2Client) AttachInternetGatewayWithContext(_ context.Context, in *ec2.AttachInternetGatewayInput, _ ...request.Option) (*ec2.AttachInternetGatewayOutput, error) { + return m.attachIgw(in) +} + +func (m *mockEC2Client) CreateDhcpOptionsWithContext(_ context.Context, in *ec2.CreateDhcpOptionsInput, _ ...request.Option) (*ec2.CreateDhcpOptionsOutput, error) { + return m.createDHCPOpts(in) +} + +func (m *mockEC2Client) DescribeDhcpOptionsWithContext(_ context.Context, in *ec2.DescribeDhcpOptionsInput, _ ...request.Option) (*ec2.DescribeDhcpOptionsOutput, error) { + return m.describeDHCPOpts(in) +} + +func (m *mockEC2Client) AssociateDhcpOptionsWithContext(_ context.Context, in *ec2.AssociateDhcpOptionsInput, _ ...request.Option) (*ec2.AssociateDhcpOptionsOutput, error) { + return m.assocOpts(in) +} + +func (m *mockEC2Client) CreateRouteTableWithContext(_ context.Context, in *ec2.CreateRouteTableInput, _ ...request.Option) (*ec2.CreateRouteTableOutput, error) { + return m.createRouteTable(in) +} + +func (m *mockEC2Client) DescribeRouteTablesWithContext(_ context.Context, in *ec2.DescribeRouteTablesInput, _ ...request.Option) (*ec2.DescribeRouteTablesOutput, error) { + return m.describeRouteTables(in) +} + +func (m *mockEC2Client) ReplaceRouteTableAssociationWithContext(_ context.Context, in *ec2.ReplaceRouteTableAssociationInput, _ ...request.Option) (*ec2.ReplaceRouteTableAssociationOutput, error) { + return m.replaceRouteTableAssoc(in) +} + +func (m *mockEC2Client) AssociateRouteTableWithContext(_ context.Context, in *ec2.AssociateRouteTableInput, _ ...request.Option) (*ec2.AssociateRouteTableOutput, error) { + return m.assocRouteTable(in) +} + +func (m *mockEC2Client) CreateRouteWithContext(_ context.Context, in *ec2.CreateRouteInput, _ ...request.Option) (*ec2.CreateRouteOutput, error) { + return m.createRoute(in) +} + +func (m *mockEC2Client) CreateSubnetWithContext(_ context.Context, in *ec2.CreateSubnetInput, _ ...request.Option) (*ec2.CreateSubnetOutput, error) { + return m.createSubnet(in) +} + +func (m *mockEC2Client) DescribeSubnetsWithContext(_ context.Context, in *ec2.DescribeSubnetsInput, _ ...request.Option) (*ec2.DescribeSubnetsOutput, error) { + return m.describeSubnets(in) +} + +func (m *mockEC2Client) AllocateAddressWithContext(_ context.Context, in *ec2.AllocateAddressInput, _ ...request.Option) (*ec2.AllocateAddressOutput, error) { + return m.allocAddr(in) +} + +func (m *mockEC2Client) DisassociateAddressWithContext(_ context.Context, in *ec2.DisassociateAddressInput, _ ...request.Option) (*ec2.DisassociateAddressOutput, error) { + return m.disassocAddr(in) +} + +func (m *mockEC2Client) ReleaseAddressWithContext(_ context.Context, in *ec2.ReleaseAddressInput, _ ...request.Option) (*ec2.ReleaseAddressOutput, error) { + return m.releaseAddr(in) +} + +func (m *mockEC2Client) CreateTagsWithContext(_ context.Context, in *ec2.CreateTagsInput, _ ...request.Option) (*ec2.CreateTagsOutput, error) { + return m.createTags(in) +} + +func (m *mockEC2Client) CreateNatGatewayWithContext(_ context.Context, in *ec2.CreateNatGatewayInput, _ ...request.Option) (*ec2.CreateNatGatewayOutput, error) { + return m.createNat(in) +} + +func (m *mockEC2Client) DescribeNatGatewaysWithContext(_ context.Context, in *ec2.DescribeNatGatewaysInput, _ ...request.Option) (*ec2.DescribeNatGatewaysOutput, error) { + return m.describeNats(in) +} + +func (m *mockEC2Client) CreateVpcEndpointWithContext(_ context.Context, in *ec2.CreateVpcEndpointInput, _ ...request.Option) (*ec2.CreateVpcEndpointOutput, error) { + return m.createVpcEndpoint(in) +} + +func (m *mockEC2Client) DescribeVpcEndpointsWithContext(_ context.Context, in *ec2.DescribeVpcEndpointsInput, _ ...request.Option) (*ec2.DescribeVpcEndpointsOutput, error) { + return m.describeVpcEndpoints(in) +} + +var errAwsSdk = errors.New("some AWS SDK error") + +func TestEnsureVPC(t *testing.T) { + vpcID := aws.String("vpc-1") + expectedVpc := &ec2.Vpc{VpcId: vpcID} + + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.Vpc + expectedErr string + }{ + { + name: "SDK error fetching VPCs", + mockSvc: mockEC2Client{ + describeVpcs: func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + return nil, errAwsSdk + }, + createVpc: func(*ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) { + panic("should not be called") + }, + modifyVpcAttribute: func(*ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list VPCs: some AWS SDK error$`, + }, + { + name: "VPC found but enabling DNS support fails", + mockSvc: mockEC2Client{ + describeVpcs: func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + return &ec2.DescribeVpcsOutput{ + Vpcs: []*ec2.Vpc{ + {VpcId: vpcID}, + {VpcId: aws.String("vpc-2")}, + }, + }, nil + }, + createVpc: func(*ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) { + panic("should not be called") + }, + modifyVpcAttribute: func(*ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to enable DNS support on VPC: some AWS SDK error$`, + }, + { + name: "VPC found but enabling DNS hostnames fails", + mockSvc: mockEC2Client{ + describeVpcs: func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + return &ec2.DescribeVpcsOutput{ + Vpcs: []*ec2.Vpc{{VpcId: vpcID}}, + }, nil + }, + createVpc: func(*ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) { + panic("should not be called") + }, + modifyVpcAttribute: func(in *ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) { + if in.EnableDnsHostnames != nil { + return nil, errAwsSdk + } + return &ec2.ModifyVpcAttributeOutput{}, nil + }, + }, + expectedErr: `^failed to enable DNS hostnames on VPC: some AWS SDK error$`, + }, + { + name: "VPC found and attributes set", + mockSvc: mockEC2Client{ + describeVpcs: func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + return &ec2.DescribeVpcsOutput{ + Vpcs: []*ec2.Vpc{{VpcId: vpcID}}, + }, nil + }, + createVpc: func(*ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) { + panic("should not be called") + }, + modifyVpcAttribute: func(*ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) { + return &ec2.ModifyVpcAttributeOutput{}, nil + }, + }, + expectedOut: expectedVpc, + }, + { + name: "VPC created", + mockSvc: mockEC2Client{ + describeVpcs: func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + return &ec2.DescribeVpcsOutput{Vpcs: []*ec2.Vpc{}}, nil + }, + createVpc: func(in *ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) { + if len(in.TagSpecifications) == 0 || len(in.TagSpecifications[0].Tags) == 0 { + panic("vpc not tagged") + } + if aws.StringValue(in.TagSpecifications[0].ResourceType) != "vpc" { + panic("vpc tagged with wrong resource type") + } + return &ec2.CreateVpcOutput{Vpc: &ec2.Vpc{VpcId: vpcID}}, nil + }, + modifyVpcAttribute: func(*ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) { + return &ec2.ModifyVpcAttributeOutput{}, nil + }, + }, + expectedOut: expectedVpc, + }, + { + name: "VPC creation fails", + mockSvc: mockEC2Client{ + describeVpcs: func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + return &ec2.DescribeVpcsOutput{Vpcs: []*ec2.Vpc{}}, nil + }, + createVpc: func(*ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) { + return nil, errAwsSdk + }, + modifyVpcAttribute: func(*ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create VPC: some AWS SDK error$`, + }, + { + name: "VPC created but enabling DNS support fails", + mockSvc: mockEC2Client{ + describeVpcs: func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + return &ec2.DescribeVpcsOutput{Vpcs: []*ec2.Vpc{}}, nil + }, + createVpc: func(*ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) { + return &ec2.CreateVpcOutput{Vpc: &ec2.Vpc{VpcId: vpcID}}, nil + }, + modifyVpcAttribute: func(*ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `failed to enable DNS support on VPC: some AWS SDK error$`, + }, + { + name: "VPC created but enabling DNS hostnames fails", + mockSvc: mockEC2Client{ + describeVpcs: func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + return &ec2.DescribeVpcsOutput{Vpcs: []*ec2.Vpc{}}, nil + }, + createVpc: func(*ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) { + return &ec2.CreateVpcOutput{Vpc: &ec2.Vpc{VpcId: vpcID}}, nil + }, + modifyVpcAttribute: func(in *ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) { + if in.EnableDnsHostnames != nil { + return nil, errAwsSdk + } + return &ec2.ModifyVpcAttributeOutput{}, nil + }, + }, + expectedErr: `failed to enable DNS hostnames on VPC: some AWS SDK error$`, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + tags: map[string]string{"custom-tag": "custom-value"}, + }, + } + res, err := state.ensureVPC(context.TODO(), logger, &test.mockSvc) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureIntergetGateway(t *testing.T) { + vpcID := aws.String("vpc-1") + igwID := aws.String("igw-1") + attachedIgw := &ec2.InternetGateway{ + InternetGatewayId: igwID, + Attachments: []*ec2.InternetGatewayAttachment{{VpcId: vpcID}}, + } + unattachedIgw := &ec2.InternetGateway{InternetGatewayId: igwID} + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.InternetGateway + expectedErr string + }{ + { + name: "SDK error fetching Internet Gateways", + mockSvc: mockEC2Client{ + describeIgws: func(*ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) { + return nil, errAwsSdk + }, + createIgw: func(*ec2.CreateInternetGatewayInput) (*ec2.CreateInternetGatewayOutput, error) { + panic("should not be called") + }, + attachIgw: func(*ec2.AttachInternetGatewayInput) (*ec2.AttachInternetGatewayOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list internet gateways: some AWS SDK error$`, + }, + { + name: "Internet Gateway found but attaching to VPC fails", + mockSvc: mockEC2Client{ + describeIgws: func(*ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) { + return &ec2.DescribeInternetGatewaysOutput{ + InternetGateways: []*ec2.InternetGateway{unattachedIgw}, + }, nil + }, + createIgw: func(*ec2.CreateInternetGatewayInput) (*ec2.CreateInternetGatewayOutput, error) { + panic("should not be called") + }, + attachIgw: func(*ec2.AttachInternetGatewayInput) (*ec2.AttachInternetGatewayOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to attach internet gateway to VPC: some AWS SDK error$`, + }, + { + name: "Internet Gateway found and already attached to VPC", + mockSvc: mockEC2Client{ + describeIgws: func(*ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) { + return &ec2.DescribeInternetGatewaysOutput{ + InternetGateways: []*ec2.InternetGateway{attachedIgw}, + }, nil + }, + createIgw: func(*ec2.CreateInternetGatewayInput) (*ec2.CreateInternetGatewayOutput, error) { + panic("should not be called") + }, + attachIgw: func(*ec2.AttachInternetGatewayInput) (*ec2.AttachInternetGatewayOutput, error) { + panic("should not be called") + }, + }, + expectedOut: attachedIgw, + }, + { + name: "Internet Gateway found and attaching to VPC succeeds", + mockSvc: mockEC2Client{ + describeIgws: func(*ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) { + return &ec2.DescribeInternetGatewaysOutput{ + InternetGateways: []*ec2.InternetGateway{unattachedIgw}, + }, nil + }, + createIgw: func(*ec2.CreateInternetGatewayInput) (*ec2.CreateInternetGatewayOutput, error) { + panic("should not be called") + }, + attachIgw: func(*ec2.AttachInternetGatewayInput) (*ec2.AttachInternetGatewayOutput, error) { + return &ec2.AttachInternetGatewayOutput{}, nil + }, + }, + expectedOut: unattachedIgw, + }, + { + name: "Internet Gateway creation fails", + mockSvc: mockEC2Client{ + describeIgws: func(*ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) { + return &ec2.DescribeInternetGatewaysOutput{}, nil + }, + createIgw: func(*ec2.CreateInternetGatewayInput) (*ec2.CreateInternetGatewayOutput, error) { + return nil, errAwsSdk + }, + attachIgw: func(*ec2.AttachInternetGatewayInput) (*ec2.AttachInternetGatewayOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create internet gateway: some AWS SDK error$`, + }, + { + name: "Internet Gateway created but attaching to VPC fails", + mockSvc: mockEC2Client{ + describeIgws: func(*ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) { + return &ec2.DescribeInternetGatewaysOutput{}, nil + }, + createIgw: func(*ec2.CreateInternetGatewayInput) (*ec2.CreateInternetGatewayOutput, error) { + return &ec2.CreateInternetGatewayOutput{InternetGateway: unattachedIgw}, nil + }, + attachIgw: func(*ec2.AttachInternetGatewayInput) (*ec2.AttachInternetGatewayOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to attach internet gateway to VPC: some AWS SDK error$`, + }, + { + name: "Internet Gateway created and attaching to VPC succeeds", + mockSvc: mockEC2Client{ + describeIgws: func(*ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) { + return &ec2.DescribeInternetGatewaysOutput{}, nil + }, + createIgw: func(in *ec2.CreateInternetGatewayInput) (*ec2.CreateInternetGatewayOutput, error) { + if len(in.TagSpecifications) == 0 || len(in.TagSpecifications[0].Tags) == 0 { + panic("internet gateway not tagged") + } + if aws.StringValue(in.TagSpecifications[0].ResourceType) != "internet-gateway" { + panic("internet gateway tagged with wrong resource type") + } + return &ec2.CreateInternetGatewayOutput{InternetGateway: unattachedIgw}, nil + }, + attachIgw: func(*ec2.AttachInternetGatewayInput) (*ec2.AttachInternetGatewayOutput, error) { + return &ec2.AttachInternetGatewayOutput{}, nil + }, + }, + expectedOut: unattachedIgw, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + tags: map[string]string{"custom-tag": "custom-value"}, + }, + } + res, err := state.ensureInternetGateway(context.TODO(), logger, &test.mockSvc, vpcID) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureDHCPOptions(t *testing.T) { + vpcID := aws.String("vpc-1") + expectedOpt := &ec2.DhcpOptions{ + DhcpOptionsId: aws.String("dhcp-opt-1"), + } + + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.DhcpOptions + expectedErr string + }{ + { + name: "SDK error fetching DHCP options", + mockSvc: mockEC2Client{ + describeDHCPOpts: func(*ec2.DescribeDhcpOptionsInput) (*ec2.DescribeDhcpOptionsOutput, error) { + return nil, errAwsSdk + }, + createDHCPOpts: func(*ec2.CreateDhcpOptionsInput) (*ec2.CreateDhcpOptionsOutput, error) { + panic("should not be called") + }, + assocOpts: func(*ec2.AssociateDhcpOptionsInput) (*ec2.AssociateDhcpOptionsOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list DHCP options: some AWS SDK error$`, + }, + { + name: "DHCP options found but association with VPC fails", + mockSvc: mockEC2Client{ + describeDHCPOpts: func(*ec2.DescribeDhcpOptionsInput) (*ec2.DescribeDhcpOptionsOutput, error) { + return &ec2.DescribeDhcpOptionsOutput{ + DhcpOptions: []*ec2.DhcpOptions{expectedOpt}, + }, nil + }, + createDHCPOpts: func(*ec2.CreateDhcpOptionsInput) (*ec2.CreateDhcpOptionsOutput, error) { + panic("should not be called") + }, + assocOpts: func(*ec2.AssociateDhcpOptionsInput) (*ec2.AssociateDhcpOptionsOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to associate DHCP options to VPC: some AWS SDK error$`, + }, + { + name: "DHCP options found and association with VPC succeeds", + mockSvc: mockEC2Client{ + describeDHCPOpts: func(*ec2.DescribeDhcpOptionsInput) (*ec2.DescribeDhcpOptionsOutput, error) { + return &ec2.DescribeDhcpOptionsOutput{ + DhcpOptions: []*ec2.DhcpOptions{expectedOpt}, + }, nil + }, + createDHCPOpts: func(*ec2.CreateDhcpOptionsInput) (*ec2.CreateDhcpOptionsOutput, error) { + panic("should not be called") + }, + assocOpts: func(*ec2.AssociateDhcpOptionsInput) (*ec2.AssociateDhcpOptionsOutput, error) { + return &ec2.AssociateDhcpOptionsOutput{}, nil + }, + }, + expectedOut: expectedOpt, + }, + { + name: "DHCP creation fails", + mockSvc: mockEC2Client{ + describeDHCPOpts: func(*ec2.DescribeDhcpOptionsInput) (*ec2.DescribeDhcpOptionsOutput, error) { + return &ec2.DescribeDhcpOptionsOutput{ + DhcpOptions: []*ec2.DhcpOptions{}, + }, nil + }, + createDHCPOpts: func(*ec2.CreateDhcpOptionsInput) (*ec2.CreateDhcpOptionsOutput, error) { + return nil, errAwsSdk + }, + assocOpts: func(*ec2.AssociateDhcpOptionsInput) (*ec2.AssociateDhcpOptionsOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create DHCP options: some AWS SDK error$`, + }, + { + name: "DHCP created but association with VPC fails", + mockSvc: mockEC2Client{ + describeDHCPOpts: func(*ec2.DescribeDhcpOptionsInput) (*ec2.DescribeDhcpOptionsOutput, error) { + return &ec2.DescribeDhcpOptionsOutput{ + DhcpOptions: []*ec2.DhcpOptions{}, + }, nil + }, + createDHCPOpts: func(*ec2.CreateDhcpOptionsInput) (*ec2.CreateDhcpOptionsOutput, error) { + return &ec2.CreateDhcpOptionsOutput{DhcpOptions: expectedOpt}, nil + }, + assocOpts: func(*ec2.AssociateDhcpOptionsInput) (*ec2.AssociateDhcpOptionsOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to associate DHCP options to VPC: some AWS SDK error$`, + }, + { + name: "DHCP created and association with VPC succeeds", + mockSvc: mockEC2Client{ + describeDHCPOpts: func(*ec2.DescribeDhcpOptionsInput) (*ec2.DescribeDhcpOptionsOutput, error) { + return &ec2.DescribeDhcpOptionsOutput{ + DhcpOptions: []*ec2.DhcpOptions{}, + }, nil + }, + createDHCPOpts: func(in *ec2.CreateDhcpOptionsInput) (*ec2.CreateDhcpOptionsOutput, error) { + if len(in.TagSpecifications) == 0 || len(in.TagSpecifications[0].Tags) == 0 { + panic("DHCP options not tagged") + } + if aws.StringValue(in.TagSpecifications[0].ResourceType) != "dhcp-options" { + panic("DHCP options tagged with wrong resource type") + } + return &ec2.CreateDhcpOptionsOutput{DhcpOptions: expectedOpt}, nil + }, + assocOpts: func(*ec2.AssociateDhcpOptionsInput) (*ec2.AssociateDhcpOptionsOutput, error) { + return &ec2.AssociateDhcpOptionsOutput{}, nil + }, + }, + expectedOut: expectedOpt, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + tags: map[string]string{"custom-tag": "custom-value"}, + }, + } + res, err := state.ensureDHCPOptions(context.TODO(), logger, &test.mockSvc, vpcID) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureRouteTable(t *testing.T) { + vpcID := aws.String("vpc-1") + tableID := aws.String("route-table-1") + tableName := "route-table" + + expectedTable := &ec2.RouteTable{ + RouteTableId: tableID, + } + + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.RouteTable + expectedErr string + }{ + { + name: "SDK error listing route tables", + mockSvc: mockEC2Client{ + describeRouteTables: func(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return nil, errAwsSdk + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `failed to list route tables: some AWS SDK error$`, + }, + { + name: "Route table found", + mockSvc: mockEC2Client{ + describeRouteTables: func(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{RouteTables: []*ec2.RouteTable{expectedTable}}, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + }, + expectedOut: expectedTable, + }, + { + name: "Route table creation fails", + mockSvc: mockEC2Client{ + describeRouteTables: func(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{RouteTables: []*ec2.RouteTable{}}, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^some AWS SDK error$`, + }, + { + name: "Route table created but not found", + mockSvc: mockEC2Client{ + describeRouteTables: func(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{RouteTables: []*ec2.RouteTable{}}, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + return &ec2.CreateRouteTableOutput{RouteTable: expectedTable}, nil + }, + }, + expectedErr: `^failed to find route table \(route\-table\-1\) that was just created: .*$`, + }, + { + name: "Route table creation succeeds", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeRouteTablesOutput{RouteTables: []*ec2.RouteTable{}}, nil + } + return &ec2.DescribeRouteTablesOutput{RouteTables: []*ec2.RouteTable{expectedTable}}, nil + }, + createRouteTable: func(in *ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + if len(in.TagSpecifications) == 0 || len(in.TagSpecifications[0].Tags) == 0 { + panic("route table not tagged") + } + if aws.StringValue(in.TagSpecifications[0].ResourceType) != "route-table" { + panic("route table tagged with wrong resource type") + } + return &ec2.CreateRouteTableOutput{RouteTable: expectedTable}, nil + }, + }, + expectedOut: expectedTable, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + tags: map[string]string{"custom-tag": "custom-value"}, + }, + vpcID: vpcID, + } + res, err := state.ensureRouteTable(context.TODO(), logger, &test.mockSvc, tableName) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsurePublicRouteTable(t *testing.T) { + vpcID := aws.String("vpc-1") + igwID := aws.String("igw-1") + tableID := aws.String("route-table-1") + mainTableID := aws.String("route-table-main") + + const vpcIDFilter = "vpc-id" + + nonMainTable := &ec2.RouteTable{ + RouteTableId: tableID, + } + mainTable := &ec2.RouteTable{ + RouteTableId: tableID, + Associations: []*ec2.RouteTableAssociation{ + { + RouteTableAssociationId: aws.String("assoc-1"), + RouteTableId: aws.String("route-table-2"), + }, + }, + } + mainTableNoAssoc := &ec2.RouteTable{ + RouteTableId: mainTableID, + Associations: []*ec2.RouteTableAssociation{}, + } + mainTableNotVPC := &ec2.RouteTable{ + RouteTableId: mainTableID, + Associations: []*ec2.RouteTableAssociation{ + { + RouteTableAssociationId: aws.String("assoc-1"), + RouteTableId: aws.String("route-table-2"), + }, + }, + } + mainTableIgw := &ec2.RouteTable{ + RouteTableId: tableID, + Associations: []*ec2.RouteTableAssociation{ + { + RouteTableAssociationId: aws.String("assoc-1"), + RouteTableId: aws.String("route-table-2"), + }, + }, + Routes: []*ec2.Route{ + { + GatewayId: igwID, + DestinationCidrBlock: aws.String("0.0.0.0/0"), + }, + }, + } + + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.RouteTable + expectedErr string + }{ + { + name: "Route table creation fails", + mockSvc: mockEC2Client{ + describeRouteTables: func(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return nil, errAwsSdk + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + replaceRouteTableAssoc: func(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create public route table: failed to list route tables: some AWS SDK error$`, + }, + { + name: "Route table created but VPC main route table fetching fails", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + if aws.StringValue(in.Filters[0].Name) == vpcIDFilter { + return nil, errAwsSdk + } + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{nonMainTable}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + replaceRouteTableAssoc: func(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to get main route table: failed to list route tables: some AWS SDK error$`, + }, + { + name: "Route table created but VPC main route table not found", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + // main route table filter + if aws.StringValue(in.Filters[0].Name) == vpcIDFilter { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{}, + }, nil + } + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{nonMainTable}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + replaceRouteTableAssoc: func(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^no main route table associated with the VPC$`, + }, + { + name: "Route table created but VPC main route table has no associations", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + // main route table filter + if aws.StringValue(in.Filters[0].Name) == vpcIDFilter { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{mainTableNoAssoc}, + }, nil + } + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{nonMainTable}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + replaceRouteTableAssoc: func(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^no associations found for main route table$`, + }, + { + name: "Route table created but replacing main route table association fails", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + // main route table filter + if aws.StringValue(in.Filters[0].Name) == vpcIDFilter { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{mainTableNotVPC}, + }, nil + } + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{nonMainTable}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + replaceRouteTableAssoc: func(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) { + return nil, errAwsSdk + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to replace vpc main route table: some AWS SDK error$`, + }, + { + name: "Route table created and already main route table but Internet Gateway route fails", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{mainTable}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + replaceRouteTableAssoc: func(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create route to internet gateway: some AWS SDK error$`, + }, + { + name: "Route table created and already main route table and Internet Gateway route already exists", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{mainTableIgw}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + replaceRouteTableAssoc: func(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + panic("should not be called") + }, + }, + expectedOut: mainTableIgw, + }, + { + name: "Route table created and already main route table and Internet Gateway route created", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{mainTable}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + replaceRouteTableAssoc: func(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + return &ec2.CreateRouteOutput{}, nil + }, + }, + expectedOut: mainTable, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + tags: map[string]string{"custom-tag": "custom-value"}, + }, + vpcID: vpcID, + igwID: igwID, + } + res, err := state.ensurePublicRouteTable(context.TODO(), logger, &test.mockSvc) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureSubnet(t *testing.T) { + vpcID := aws.String("vpc-1") + subnetName := "subnet-zone1" + + expectedSubnet := &ec2.Subnet{SubnetId: aws.String("subnet-1")} + + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.Subnet + expectedErr string + }{ + { + name: "SDK error listing subnets", + mockSvc: mockEC2Client{ + describeSubnets: func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + return nil, errAwsSdk + }, + createSubnet: func(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list subnets: some AWS SDK error$`, + }, + { + name: "Subnet creation fails", + mockSvc: mockEC2Client{ + describeSubnets: func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + return &ec2.DescribeSubnetsOutput{Subnets: []*ec2.Subnet{}}, nil + }, + createSubnet: func(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create subnet: some AWS SDK error$`, + }, + { + name: "Subnet created but not found", + mockSvc: mockEC2Client{ + describeSubnets: func(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSubnetsOutput{Subnets: []*ec2.Subnet{}}, nil + } + return &ec2.DescribeSubnetsOutput{Subnets: []*ec2.Subnet{}}, nil + }, + createSubnet: func(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + return &ec2.CreateSubnetOutput{Subnet: expectedSubnet}, nil + }, + }, + expectedErr: `^failed to find subnet \(subnet-1\) that was just created: .*$`, + }, + { + name: "Subnet created and found", + mockSvc: mockEC2Client{ + describeSubnets: func(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSubnetsOutput{Subnets: []*ec2.Subnet{}}, nil + } + return &ec2.DescribeSubnetsOutput{Subnets: []*ec2.Subnet{expectedSubnet}}, nil + }, + createSubnet: func(in *ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + if len(in.TagSpecifications) == 0 || len(in.TagSpecifications[0].Tags) == 0 { + panic("subnet not tagged") + } + if aws.StringValue(in.TagSpecifications[0].ResourceType) != "subnet" { + panic("subnet tagged with wrong resource type") + } + return &ec2.CreateSubnetOutput{Subnet: expectedSubnet}, nil + }, + }, + expectedOut: expectedSubnet, + }, + { + name: "Existing subnet found", + mockSvc: mockEC2Client{ + describeSubnets: func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + return &ec2.DescribeSubnetsOutput{Subnets: []*ec2.Subnet{expectedSubnet}}, nil + }, + createSubnet: func(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + panic("should not be called") + }, + }, + expectedOut: expectedSubnet, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + tags: map[string]string{"custom-tag": "custom-value"}, + }, + vpcID: vpcID, + } + res, err := state.ensureSubnet(context.TODO(), logger, &test.mockSvc, "zone1", "10.0.1.0/17", subnetName, map[string]string{}) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsurePublicSubnets(t *testing.T) { + vpcID := aws.String("vpc-1") + _, network, err := net.ParseCIDR("10.0.0.0/17") + assert.NoError(t, err, "parsing CIDR should not fail") + + subnet1 := aws.String("subnet-zone1") + subnet2 := aws.String("subnet-zone2") + subnet3 := aws.String("subnet-zone3") + expectSubnets := []*string{subnet1, subnet2, subnet3} + expectedMap := map[string]*string{ + "zone1": subnet1, + "zone2": subnet2, + "zone3": subnet3, + } + + tests := []struct { + name string + mockSvc mockEC2Client + expectedSubnets []*string + expectedMap map[string]*string + expectedErr string + }{ + { + name: "AWS SDK error listing subnets", + mockSvc: mockEC2Client{ + describeSubnets: func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create public subnets: failed to create public subnet \(infraID-public-zone1\): failed to list subnets: some AWS SDK error$`, + }, + { + name: "AWS SDK error creating a subnet", + mockSvc: mockEC2Client{ + describeSubnets: func(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSubnetsOutput{}, nil + } + panic("should not be reached") + }, + createSubnet: func(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create public subnets: failed to create public subnet \(infraID-public-zone1\): failed to create subnet: some AWS SDK error$`, + }, + { + name: "Subnet created but failed to be fetched", + mockSvc: mockEC2Client{ + describeSubnets: func(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSubnetsOutput{}, nil + } + return &ec2.DescribeSubnetsOutput{}, nil + }, + createSubnet: func(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + return &ec2.CreateSubnetOutput{ + Subnet: &ec2.Subnet{SubnetId: subnet1}, + }, nil + }, + }, + expectedErr: `^failed to create public subnets: failed to create public subnet \(infraID-public-zone1\): failed to find subnet \(subnet-zone1\) that was just created: .*$`, + }, + { + name: "Public subnets created but associating with public route table fails", + mockSvc: mockEC2Client{ + describeSubnets: func(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSubnetsOutput{}, nil + } + return &ec2.DescribeSubnetsOutput{ + Subnets: []*ec2.Subnet{{SubnetId: in.SubnetIds[0]}}, + }, nil + }, + createSubnet: func(in *ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + publicELBTagFound := false + for _, ec2Tag := range in.TagSpecifications[0].Tags { + if aws.StringValue(ec2Tag.Key) == "kubernetes.io/role/elb" && aws.StringValue(ec2Tag.Value) == "true" { + publicELBTagFound = true + break + } + } + if !publicELBTagFound { + panic("public subnet not tagged with public ELB") + } + return &ec2.CreateSubnetOutput{ + Subnet: &ec2.Subnet{SubnetId: expectedMap[*in.AvailabilityZone]}, + }, nil + }, + assocRouteTable: func(*ec2.AssociateRouteTableInput) (*ec2.AssociateRouteTableOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to associate public subnets with public route table \(table-1\): failed to associate subnet \(subnet-zone1\) with route table: some AWS SDK error$`, + }, + { + name: "Public subnets created", + mockSvc: mockEC2Client{ + describeSubnets: func(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSubnetsOutput{}, nil + } + return &ec2.DescribeSubnetsOutput{ + Subnets: []*ec2.Subnet{{SubnetId: in.SubnetIds[0]}}, + }, nil + }, + createSubnet: func(in *ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + publicELBTagFound := false + for _, ec2Tag := range in.TagSpecifications[0].Tags { + if aws.StringValue(ec2Tag.Key) == "kubernetes.io/role/elb" && aws.StringValue(ec2Tag.Value) == "true" { + publicELBTagFound = true + break + } + } + if !publicELBTagFound { + panic("public subnet not tagged with public ELB") + } + return &ec2.CreateSubnetOutput{ + Subnet: &ec2.Subnet{SubnetId: expectedMap[*in.AvailabilityZone]}, + }, nil + }, + assocRouteTable: func(*ec2.AssociateRouteTableInput) (*ec2.AssociateRouteTableOutput, error) { + return &ec2.AssociateRouteTableOutput{}, nil + }, + }, + expectedSubnets: expectSubnets, + expectedMap: expectedMap, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + zones: []string{"zone1", "zone2", "zone3"}, + tags: map[string]string{"custom-tag": "custom-value"}, + }, + vpcID: vpcID, + } + publicRouteTable := &ec2.RouteTable{RouteTableId: aws.String("table-1")} + subnets, subnetMap, err := state.ensurePublicSubnets(context.TODO(), logger, &test.mockSvc, network, publicRouteTable) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedSubnets, subnets) + assert.Equal(t, test.expectedMap, subnetMap) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsurePrivateSubnets(t *testing.T) { + vpcID := aws.String("vpc-1") + _, network, err := net.ParseCIDR("10.0.0.0/17") + assert.NoError(t, err, "parsing CIDR should not fail") + + subnet1 := aws.String("subnet-zone1") + subnet2 := aws.String("subnet-zone2") + subnet3 := aws.String("subnet-zone3") + expectedSubnets := []*string{subnet1, subnet2, subnet3} + expectedMap := map[string]*string{ + "zone1": subnet1, + "zone2": subnet2, + "zone3": subnet3, + } + + tests := []struct { + name string + mockSvc mockEC2Client + expectedSubnets []*string + expectedMap map[string]*string + expectedErr string + }{ + { + name: "AWS SDK error listing subnets", + mockSvc: mockEC2Client{ + describeSubnets: func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create private subnets: failed to create private subnet \(infraID-private-zone1\): failed to list subnets: some AWS SDK error$`, + }, + { + name: "AWS SDK error creating a subnet", + mockSvc: mockEC2Client{ + describeSubnets: func(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSubnetsOutput{}, nil + } + panic("should not be reached") + }, + createSubnet: func(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create private subnets: failed to create private subnet \(infraID-private-zone1\): failed to create subnet: some AWS SDK error$`, + }, + { + name: "Subnet created but failed to be fetched", + mockSvc: mockEC2Client{ + describeSubnets: func(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSubnetsOutput{}, nil + } + return &ec2.DescribeSubnetsOutput{}, nil + }, + createSubnet: func(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + return &ec2.CreateSubnetOutput{ + Subnet: &ec2.Subnet{SubnetId: subnet1}, + }, nil + }, + }, + expectedErr: `^failed to create private subnets: failed to create private subnet \(infraID-private-zone1\): failed to find subnet \(subnet-zone1\) that was just created: .*$`, + }, + { + name: "Private subnets created", + mockSvc: mockEC2Client{ + describeSubnets: func(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSubnetsOutput{}, nil + } + return &ec2.DescribeSubnetsOutput{ + Subnets: []*ec2.Subnet{{SubnetId: in.SubnetIds[0]}}, + }, nil + }, + createSubnet: func(in *ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) { + privateELBTagFound := false + for _, ec2Tag := range in.TagSpecifications[0].Tags { + if aws.StringValue(ec2Tag.Key) == "kubernetes.io/role/internal-elb" && aws.StringValue(ec2Tag.Value) == "true" { + privateELBTagFound = true + break + } + } + if !privateELBTagFound { + panic("private subnet not tagged with private ELB") + } + return &ec2.CreateSubnetOutput{ + Subnet: &ec2.Subnet{SubnetId: expectedMap[*in.AvailabilityZone]}, + }, nil + }, + }, + expectedSubnets: expectedSubnets, + expectedMap: expectedMap, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + zones: []string{"zone1", "zone2", "zone3"}, + tags: map[string]string{"custom-tag": "custom-value"}, + }, + vpcID: vpcID, + } + subnets, subnetMap, err := state.ensurePrivateSubnets(context.TODO(), logger, &test.mockSvc, network) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedSubnets, subnets) + assert.Equal(t, test.expectedMap, subnetMap) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureEIP(t *testing.T) { + expectedAlloc := aws.String("eip-1") + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *string + expectedErr string + }{ + { + name: "AWS SDK error allocating EIP address", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return nil, errAwsSdk + }, + createTags: func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to allocate EIP: some AWS SDK error$`, + }, + { + name: "EIP created but tagging fails with non-retriable error", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return &ec2.AllocateAddressOutput{AllocationId: expectedAlloc}, nil + }, + createTags: func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + return nil, awserr.New(errInvalidEIPNotFound, "", errAwsSdk) + }, + disassocAddr: func(*ec2.DisassociateAddressInput) (*ec2.DisassociateAddressOutput, error) { + return &ec2.DisassociateAddressOutput{}, nil + }, + releaseAddr: func(*ec2.ReleaseAddressInput) (*ec2.ReleaseAddressOutput, error) { + return &ec2.ReleaseAddressOutput{}, nil + }, + }, + expectedErr: `^failed to tag EIP \(eip-1\): .*$`, + }, + { + name: "EIP created but tagging fails with retriable error", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return &ec2.AllocateAddressOutput{AllocationId: expectedAlloc}, nil + }, + createTags: func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + return nil, errAwsSdk + }, + disassocAddr: func(*ec2.DisassociateAddressInput) (*ec2.DisassociateAddressOutput, error) { + return &ec2.DisassociateAddressOutput{}, nil + }, + releaseAddr: func(*ec2.ReleaseAddressInput) (*ec2.ReleaseAddressOutput, error) { + return &ec2.ReleaseAddressOutput{}, nil + }, + }, + expectedErr: `^failed to tag EIP \(eip-1\): some AWS SDK error$`, + }, + { + name: "EIP created, tagging fails and disassociation fails", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return &ec2.AllocateAddressOutput{AllocationId: expectedAlloc}, nil + }, + createTags: func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + return nil, errAwsSdk + }, + disassocAddr: func(*ec2.DisassociateAddressInput) (*ec2.DisassociateAddressOutput, error) { + return nil, errAwsSdk + }, + releaseAddr: func(*ec2.ReleaseAddressInput) (*ec2.ReleaseAddressOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to release untagged EIP \(eip-1\): .*$`, + }, + { + name: "EIP created, tagging fails, address disassociated but releasing fails", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return &ec2.AllocateAddressOutput{AllocationId: expectedAlloc}, nil + }, + createTags: func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + return nil, errAwsSdk + }, + disassocAddr: func(*ec2.DisassociateAddressInput) (*ec2.DisassociateAddressOutput, error) { + return &ec2.DisassociateAddressOutput{}, nil + }, + releaseAddr: func(*ec2.ReleaseAddressInput) (*ec2.ReleaseAddressOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to release untagged EIP \(eip-1\): .*$`, + }, + { + name: "EIP created, tagging fails, address disassociated and already released", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return &ec2.AllocateAddressOutput{AllocationId: expectedAlloc}, nil + }, + createTags: func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + return nil, errAwsSdk + }, + disassocAddr: func(*ec2.DisassociateAddressInput) (*ec2.DisassociateAddressOutput, error) { + return &ec2.DisassociateAddressOutput{}, nil + }, + releaseAddr: func(*ec2.ReleaseAddressInput) (*ec2.ReleaseAddressOutput, error) { + return nil, awserr.New(errAuthFailure, "", errAwsSdk) + }, + }, + expectedErr: `^failed to tag EIP \(eip-1\): some AWS SDK error$`, + }, + { + name: "EIP created and tagged", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return &ec2.AllocateAddressOutput{AllocationId: expectedAlloc}, nil + }, + createTags: func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + return &ec2.CreateTagsOutput{}, nil + }, + disassocAddr: func(*ec2.DisassociateAddressInput) (*ec2.DisassociateAddressOutput, error) { + panic("should not be called") + }, + releaseAddr: func(*ec2.ReleaseAddressInput) (*ec2.ReleaseAddressOutput, error) { + panic("should not be called") + }, + }, + expectedOut: expectedAlloc, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + res, err := ensureEIP(context.TODO(), &test.mockSvc, map[string]string{}) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureNatGateway(t *testing.T) { + vpcID := aws.String("vpc-1") + allocID := aws.String("eip-1") + subnet1 := aws.String("subnet-zone1") + expectedNat := &ec2.NatGateway{} + + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.NatGateway + expectedErr string + }{ + { + name: "AWS SDK error listing Nat gateways", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + panic("should not be called") + }, + describeNats: func(*ec2.DescribeNatGatewaysInput) (*ec2.DescribeNatGatewaysOutput, error) { + return nil, errAwsSdk + }, + createNat: func(*ec2.CreateNatGatewayInput) (*ec2.CreateNatGatewayOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list Nat gateways: some AWS SDK error$`, + }, + { + name: "AWS SDK error creating EIP for Nat gateway", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return nil, errAwsSdk + }, + describeNats: func(*ec2.DescribeNatGatewaysInput) (*ec2.DescribeNatGatewaysOutput, error) { + return &ec2.DescribeNatGatewaysOutput{}, nil + }, + createNat: func(*ec2.CreateNatGatewayInput) (*ec2.CreateNatGatewayOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to allocate EIP: some AWS SDK error$`, + }, + { + name: "EIP created but non-retriable error creating Nat gateway", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return &ec2.AllocateAddressOutput{AllocationId: allocID}, nil + }, + createTags: func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + return &ec2.CreateTagsOutput{}, nil + }, + describeNats: func(*ec2.DescribeNatGatewaysInput) (*ec2.DescribeNatGatewaysOutput, error) { + return &ec2.DescribeNatGatewaysOutput{}, nil + }, + createNat: func(*ec2.CreateNatGatewayInput) (*ec2.CreateNatGatewayOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create nat gateway: some AWS SDK error$`, + }, + { + name: "EIP created but retriable error creating Nat gateway", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return &ec2.AllocateAddressOutput{AllocationId: allocID}, nil + }, + createTags: func(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + return &ec2.CreateTagsOutput{}, nil + }, + describeNats: func(*ec2.DescribeNatGatewaysInput) (*ec2.DescribeNatGatewaysOutput, error) { + return &ec2.DescribeNatGatewaysOutput{}, nil + }, + createNat: func(*ec2.CreateNatGatewayInput) (*ec2.CreateNatGatewayOutput, error) { + return nil, awserr.New(errInvalidSubnet, "", errAwsSdk) + }, + }, + expectedErr: `^failed to create nat gateway: .*$`, + }, + { + name: "EIP and Nat gateway created", + mockSvc: mockEC2Client{ + allocAddr: func(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) { + return &ec2.AllocateAddressOutput{AllocationId: allocID}, nil + }, + createTags: func(in *ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { + if len(in.Tags) == 0 { + panic("EIP not tagged") + } + return &ec2.CreateTagsOutput{}, nil + }, + describeNats: func(*ec2.DescribeNatGatewaysInput) (*ec2.DescribeNatGatewaysOutput, error) { + return &ec2.DescribeNatGatewaysOutput{}, nil + }, + createNat: func(in *ec2.CreateNatGatewayInput) (*ec2.CreateNatGatewayOutput, error) { + if len(in.TagSpecifications) == 0 || len(in.TagSpecifications[0].Tags) == 0 { + panic("nat gateway not tagged") + } + if aws.StringValue(in.TagSpecifications[0].ResourceType) != "natgateway" { + panic("nat gateway tagged with wrong resource type") + } + return &ec2.CreateNatGatewayOutput{NatGateway: expectedNat}, nil + }, + }, + expectedOut: expectedNat, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + zones: []string{"zone1", "zone2", "zone3"}, + tags: map[string]string{"custom-tag": "custom-value"}, + }, + vpcID: vpcID, + } + res, err := state.ensureNatGateway(context.TODO(), logger, &test.mockSvc, subnet1, "zone1") + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsurePrivateRouteTable(t *testing.T) { + vpcID := aws.String("vpc-1") + tableID := aws.String("route-table-1") + natGwID := aws.String("natgw-1") + subnetID := aws.String("subnet-1") + + emptyTable := &ec2.RouteTable{ + RouteTableId: tableID, + } + tableNat := &ec2.RouteTable{ + RouteTableId: tableID, + Routes: []*ec2.Route{ + { + NatGatewayId: natGwID, + DestinationCidrBlock: aws.String("0.0.0.0/0"), + }, + }, + } + expectedTable := &ec2.RouteTable{ + RouteTableId: tableID, + Associations: []*ec2.RouteTableAssociation{ + {SubnetId: subnetID}, + }, + Routes: []*ec2.Route{ + { + NatGatewayId: natGwID, + DestinationCidrBlock: aws.String("0.0.0.0/0"), + }, + }, + } + + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.RouteTable + expectedErr string + }{ + { + name: "Route table creation fails", + mockSvc: mockEC2Client{ + describeRouteTables: func(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return nil, errAwsSdk + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + panic("should not be called") + }, + assocRouteTable: func(*ec2.AssociateRouteTableInput) (*ec2.AssociateRouteTableOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list route tables: some AWS SDK error$`, + }, + { + name: "Route table created but Nat Gateway route fails", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{emptyTable}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create route to nat gateway \(natgw-1\): some AWS SDK error$`, + }, + { + name: "Route table created and Nat Gateway route created but subnet association to route table fails", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{emptyTable}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + return &ec2.CreateRouteOutput{}, nil + }, + assocRouteTable: func(*ec2.AssociateRouteTableInput) (*ec2.AssociateRouteTableOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to associate subnet \(subnet-1\) to route table \(route-table-1\): some AWS SDK error$`, + }, + { + name: "Route table created and Nat Gateway route already exists but subnet association to route table fails", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{tableNat}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + panic("should not be called") + }, + assocRouteTable: func(*ec2.AssociateRouteTableInput) (*ec2.AssociateRouteTableOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to associate subnet \(subnet-1\) to route table \(route-table-1\): some AWS SDK error$`, + }, + { + name: "Route table created, Nat Gateway route created and subnet associated", + mockSvc: mockEC2Client{ + describeRouteTables: func(in *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { + return &ec2.DescribeRouteTablesOutput{ + RouteTables: []*ec2.RouteTable{expectedTable}, + }, nil + }, + createRouteTable: func(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) { + panic("should not be called") + }, + createRoute: func(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) { + return &ec2.CreateRouteOutput{}, nil + }, + assocRouteTable: func(*ec2.AssociateRouteTableInput) (*ec2.AssociateRouteTableOutput, error) { + return &ec2.AssociateRouteTableOutput{}, nil + }, + }, + expectedOut: expectedTable, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + cidrV4Block: "10.0.0.0/16", + tags: map[string]string{"custom-tag": "custom-value"}, + }, + vpcID: vpcID, + } + res, err := state.ensurePrivateRouteTable(context.TODO(), logger, &test.mockSvc, natGwID, subnetID, "zone1") + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureS3VPCEndpoint(t *testing.T) { + vpcID := aws.String("vpc-1") + endpointID := aws.String("endpoint-1") + + expectedEndpoint := &ec2.VpcEndpoint{ + VpcEndpointId: endpointID, + } + + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.VpcEndpoint + expectedErr string + }{ + { + name: "AWS SDK error listing VPC endpoints", + mockSvc: mockEC2Client{ + describeVpcEndpoints: func(*ec2.DescribeVpcEndpointsInput) (*ec2.DescribeVpcEndpointsOutput, error) { + return nil, errAwsSdk + }, + createVpcEndpoint: func(*ec2.CreateVpcEndpointInput) (*ec2.CreateVpcEndpointOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list VPC endpoints: some AWS SDK error$`, + }, + { + name: "VPC S3 endpoint creation fails with non-retriable error", + mockSvc: mockEC2Client{ + describeVpcEndpoints: func(*ec2.DescribeVpcEndpointsInput) (*ec2.DescribeVpcEndpointsOutput, error) { + return &ec2.DescribeVpcEndpointsOutput{}, nil + }, + createVpcEndpoint: func(*ec2.CreateVpcEndpointInput) (*ec2.CreateVpcEndpointOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create VPC endpoint: some AWS SDK error$`, + }, + { + name: "VPC S3 endpoint creation fails with retriable error", + mockSvc: mockEC2Client{ + describeVpcEndpoints: func(*ec2.DescribeVpcEndpointsInput) (*ec2.DescribeVpcEndpointsOutput, error) { + return &ec2.DescribeVpcEndpointsOutput{}, nil + }, + createVpcEndpoint: func(*ec2.CreateVpcEndpointInput) (*ec2.CreateVpcEndpointOutput, error) { + return nil, awserr.New(errRouteTableIDNotFound, "", errAwsSdk) + }, + }, + expectedErr: `^failed to create VPC endpoint: .*$`, + }, + { + name: "VPC S3 endpoint created", + mockSvc: mockEC2Client{ + describeVpcEndpoints: func(*ec2.DescribeVpcEndpointsInput) (*ec2.DescribeVpcEndpointsOutput, error) { + return &ec2.DescribeVpcEndpointsOutput{}, nil + }, + createVpcEndpoint: func(in *ec2.CreateVpcEndpointInput) (*ec2.CreateVpcEndpointOutput, error) { + if aws.StringValue(in.ServiceName) != "com.amazonaws.region1.s3" { + panic("S3 VPC endpoint has wrong service name") + } + if len(in.TagSpecifications) == 0 || len(in.TagSpecifications[0].Tags) == 0 { + panic("S3 VPC endpoint not tagged") + } + if aws.StringValue(in.TagSpecifications[0].ResourceType) != "vpc-endpoint" { + panic("S3 VPC endpoint tagged with wrong resource type") + } + return &ec2.CreateVpcEndpointOutput{VpcEndpoint: expectedEndpoint}, nil + }, + }, + expectedOut: expectedEndpoint, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := vpcState{ + input: &vpcInputOptions{ + infraID: "infraID", + region: "region1", + cidrV4Block: "10.0.0.0/16", + tags: map[string]string{"custom-tag": "custom-value"}, + }, + vpcID: vpcID, + } + res, err := state.ensureVPCS3Endpoint(context.TODO(), logger, &test.mockSvc, []*string{}) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} From 380fcf0125be76fde20e678d2eee0e7ee0571e6a Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 27 Oct 2023 18:28:37 +0200 Subject: [PATCH 05/33] infra/aws: create load balancers Create load balancers and related resources. Co-authored-by: Enxebre --- pkg/infrastructure/aws/aws.go | 18 +- pkg/infrastructure/aws/loadbalancer.go | 336 +++++++++++++++++++++++++ 2 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 pkg/infrastructure/aws/loadbalancer.go diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 261fb2125b6..cee8b6754f2 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -7,6 +7,7 @@ import ( "time" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/elbv2" "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/sets" @@ -101,11 +102,26 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, vpcInput.publicSubnetIDs = *clusterAWSConfig.PublicSubnets } - _, err = createVPCResources(ctx, logger, ec2Client, &vpcInput) + vpcOutput, err := createVPCResources(ctx, logger, ec2Client, &vpcInput) if err != nil { return nil, fmt.Errorf("failed to create VPC resources: %w", err) } + logger.Infoln("Creating Load Balancer resources") + elbClient := elbv2.New(awsSession) + lbInput := lbInputOptions{ + infraID: clusterConfig.ClusterID, + vpcID: vpcOutput.vpcID, + privateSubnetIDs: vpcOutput.privateSubnetIDs, + publicSubnetIDs: vpcOutput.publicSubnetIDs, + tags: tags, + isPrivateCluster: clusterAWSConfig.PublishStrategy != "External", + } + _, err = createLoadBalancers(ctx, logger, elbClient, &lbInput) + if err != nil { + return nil, fmt.Errorf("failed to create load balancers: %w", err) + } + return nil, fmt.Errorf("provision stage not implemented yet") } diff --git a/pkg/infrastructure/aws/loadbalancer.go b/pkg/infrastructure/aws/loadbalancer.go new file mode 100644 index 00000000000..cf3a0bdbae6 --- /dev/null +++ b/pkg/infrastructure/aws/loadbalancer.go @@ -0,0 +1,336 @@ +package aws + +import ( + "context" + "errors" + "fmt" + "strconv" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/util/sets" +) + +const ( + readyzPath = "/readyz" + healthzPath = "/healthz" + apiPort = 6443 + servicePort = 22623 +) + +type lbInputOptions struct { + infraID string + vpcID string + isPrivateCluster bool + tags map[string]string + privateSubnetIDs []string + publicSubnetIDs []string +} + +type lbState struct { + input *lbInputOptions + targetGroupArns sets.Set[string] +} + +type lbOutput struct { + internal struct { + zoneID string + dnsName string + } + external struct { + zoneID string + dnsName string + } + targetGroupArns []string +} + +func createLoadBalancers(ctx context.Context, logger logrus.FieldLogger, elbClient elbv2iface.ELBV2API, input *lbInputOptions) (*lbOutput, error) { + state := lbState{ + input: input, + targetGroupArns: sets.New[string](), + } + output := &lbOutput{} + + internalLB, err := state.ensureInternalLoadBalancer(ctx, logger, elbClient, input.privateSubnetIDs, input.tags) + if err != nil { + return nil, fmt.Errorf("failed to create internal load balancer: %w", err) + } + output.internal.zoneID = aws.StringValue(internalLB.CanonicalHostedZoneId) + output.internal.dnsName = aws.StringValue(internalLB.DNSName) + + if input.isPrivateCluster { + logger.Debugln("Skipping creation of public LB because of private cluster") + output.targetGroupArns = sets.List(state.targetGroupArns) + return output, nil + } + + externalLB, err := state.ensureExternalLoadBalancer(ctx, logger, elbClient, input.publicSubnetIDs, input.tags) + if err != nil { + return nil, fmt.Errorf("failed to create external load balancer: %w", err) + } + output.external.zoneID = aws.StringValue(externalLB.CanonicalHostedZoneId) + output.external.dnsName = aws.StringValue(externalLB.DNSName) + + output.targetGroupArns = sets.List(state.targetGroupArns) + + return output, nil +} + +func (o *lbState) ensureInternalLoadBalancer(ctx context.Context, logger logrus.FieldLogger, client elbv2iface.ELBV2API, subnets []string, tags map[string]string) (*elbv2.LoadBalancer, error) { + lbName := fmt.Sprintf("%s-int", o.input.infraID) + lb, err := ensureLoadBalancer(ctx, logger, client, lbName, subnets, false, tags) + if err != nil { + return nil, err + } + + // Create internalA target group + aTGName := fmt.Sprintf("%s-aint", o.input.infraID) + aTG, err := ensureTargetGroup(ctx, logger, client, aTGName, o.input.vpcID, readyzPath, apiPort, tags) + if err != nil { + return nil, fmt.Errorf("failed to create internalA target group: %w", err) + } + o.targetGroupArns.Insert(aws.StringValue(aTG.TargetGroupArn)) + + // Create internalA listener + aListenerName := fmt.Sprintf("%s-aint", o.input.infraID) + aListener, err := createListener(ctx, client, aListenerName, lb.LoadBalancerArn, aTG.TargetGroupArn, 6443, tags) + if err != nil { + return nil, fmt.Errorf("failed to create internalA listener: %w", err) + } + logger.WithField("arn", aws.StringValue(aListener.ListenerArn)).Infoln("Created internalA listener") + + // Create internalS target group + sTGName := fmt.Sprintf("%s-sint", o.input.infraID) + sTG, err := ensureTargetGroup(ctx, logger, client, sTGName, o.input.vpcID, healthzPath, servicePort, tags) + if err != nil { + return nil, fmt.Errorf("failed to create internalS target group: %w", err) + } + o.targetGroupArns.Insert(aws.StringValue(sTG.TargetGroupArn)) + + // Create internalS listener + sListenerName := fmt.Sprintf("%s-sint", o.input.infraID) + sListener, err := createListener(ctx, client, sListenerName, lb.LoadBalancerArn, sTG.TargetGroupArn, servicePort, tags) + if err != nil { + return nil, fmt.Errorf("failed to create internalS listener: %w", err) + } + logger.WithField("arn", aws.StringValue(sListener.ListenerArn)).Infoln("Created internalS listener") + + return lb, nil +} + +func (o *lbState) ensureExternalLoadBalancer(ctx context.Context, logger logrus.FieldLogger, client elbv2iface.ELBV2API, subnets []string, tags map[string]string) (*elbv2.LoadBalancer, error) { + lbName := fmt.Sprintf("%s-ext", o.input.infraID) + lb, err := ensureLoadBalancer(ctx, logger, client, lbName, subnets, true, tags) + if err != nil { + return nil, err + } + + // Create target group + tgName := fmt.Sprintf("%s-aext", o.input.infraID) + tg, err := ensureTargetGroup(ctx, logger, client, tgName, o.input.vpcID, readyzPath, apiPort, tags) + if err != nil { + return nil, fmt.Errorf("failed to create external target group: %w", err) + } + o.targetGroupArns.Insert(aws.StringValue(tg.TargetGroupArn)) + + listenerName := fmt.Sprintf("%s-aext", o.input.infraID) + listener, err := createListener(ctx, client, listenerName, lb.LoadBalancerArn, tg.TargetGroupArn, apiPort, tags) + if err != nil { + return nil, fmt.Errorf("failed to create external listener: %w", err) + } + logger.WithField("arn", aws.StringValue(listener.ListenerArn)).Infoln("Created external listener") + + return lb, nil +} + +func ensureLoadBalancer(ctx context.Context, logger logrus.FieldLogger, client elbv2iface.ELBV2API, lbName string, subnets []string, isPublic bool, tags map[string]string) (*elbv2.LoadBalancer, error) { + l := logger.WithField("name", lbName) + createdOrFoundMsg := "Found existing load balancer" + lb, err := existingLoadBalancer(ctx, client, lbName) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + createdOrFoundMsg = "Created load balancer" + lb, err = createLoadBalancer(ctx, client, lbName, subnets, isPublic, tags) + if err != nil { + return nil, err + } + } + l.Infoln(createdOrFoundMsg) + + // enable cross zone + attrIn := &elbv2.ModifyLoadBalancerAttributesInput{ + LoadBalancerArn: lb.LoadBalancerArn, + Attributes: []*elbv2.LoadBalancerAttribute{ + { + Key: aws.String("load_balancing.cross_zone.enabled"), + Value: aws.String("true"), + }, + }, + } + _, err = client.ModifyLoadBalancerAttributesWithContext(ctx, attrIn) + if err != nil { + return nil, fmt.Errorf("failed to enable cross_zone attribute: %w", err) + } + l.Infoln("Enabled load balancer cross zone attribute") + + return lb, nil +} + +func createLoadBalancer(ctx context.Context, client elbv2iface.ELBV2API, lbName string, subnets []string, isPublic bool, tags map[string]string) (*elbv2.LoadBalancer, error) { + scheme := "internal" + if isPublic { + scheme = "internet-facing" + } + + res, err := client.CreateLoadBalancerWithContext(ctx, &elbv2.CreateLoadBalancerInput{ + CustomerOwnedIpv4Pool: nil, + IpAddressType: nil, + Name: aws.String(lbName), + Scheme: aws.String(scheme), + SecurityGroups: nil, + SubnetMappings: nil, + Subnets: aws.StringSlice(subnets), + Tags: elbTags(tags), + Type: aws.String(elbv2.LoadBalancerTypeEnumNetwork), + }) + if err != nil { + return nil, err + } + + return res.LoadBalancers[0], nil +} + +func existingLoadBalancer(ctx context.Context, client elbv2iface.ELBV2API, lbName string) (*elbv2.LoadBalancer, error) { + lbInput := &elbv2.DescribeLoadBalancersInput{ + Names: aws.StringSlice([]string{lbName}), + } + res, err := client.DescribeLoadBalancersWithContext(ctx, lbInput) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && awsErr.Code() == elbv2.ErrCodeLoadBalancerNotFoundException { + return nil, errNotFound + } + return nil, fmt.Errorf("failed to list load balancers: %w", err) + } + for _, lb := range res.LoadBalancers { + return lb, nil + } + + return nil, errNotFound +} + +func ensureTargetGroup(ctx context.Context, logger logrus.FieldLogger, client elbv2iface.ELBV2API, targetName string, vpcID string, healthCheckPath string, port int64, tags map[string]string) (*elbv2.TargetGroup, error) { + l := logger.WithField("name", targetName) + createdOrFoundMsg := "Found existing Target Group" + tg, err := existingTargetGroup(ctx, client, targetName) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + createdOrFoundMsg = "Created Target Group" + tg, err = createTargetGroup(ctx, client, targetName, vpcID, healthCheckPath, port, tags) + if err != nil { + return nil, err + } + } + l.Infoln(createdOrFoundMsg) + + return tg, nil +} + +func existingTargetGroup(ctx context.Context, client elbv2iface.ELBV2API, targetName string) (*elbv2.TargetGroup, error) { + input := &elbv2.DescribeTargetGroupsInput{ + Names: aws.StringSlice([]string{targetName}), + } + res, err := client.DescribeTargetGroupsWithContext(ctx, input) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && awsErr.Code() == elbv2.ErrCodeTargetGroupNotFoundException { + return nil, errNotFound + } + return nil, fmt.Errorf("failed to list target groups: %w", err) + } + for _, tg := range res.TargetGroups { + return tg, nil + } + + return nil, errNotFound +} + +func createTargetGroup(ctx context.Context, client elbv2iface.ELBV2API, targetName string, vpcID string, healthCheckPath string, port int64, tags map[string]string) (*elbv2.TargetGroup, error) { + ttags := mergeTags(tags, map[string]string{ + "Name": targetName, + }) + input := &elbv2.CreateTargetGroupInput{ + HealthCheckEnabled: aws.Bool(true), + HealthCheckPath: aws.String(healthCheckPath), + HealthCheckPort: aws.String(strconv.FormatInt(port, 10)), + HealthCheckProtocol: aws.String("HTTPS"), + HealthCheckIntervalSeconds: aws.Int64(10), + HealthyThresholdCount: aws.Int64(2), + UnhealthyThresholdCount: aws.Int64(2), + Name: aws.String(targetName), + Port: aws.Int64(port), + Protocol: aws.String("TCP"), + Tags: elbTags(ttags), + TargetType: aws.String("ip"), + VpcId: aws.String(vpcID), + } + res, err := client.CreateTargetGroupWithContext(ctx, input) + if err != nil { + return nil, err + } + + return res.TargetGroups[0], nil +} + +func createListener(ctx context.Context, client elbv2iface.ELBV2API, listenerName string, lbARN *string, tgARN *string, port int64, tags map[string]string) (*elbv2.Listener, error) { + ltags := mergeTags(tags, map[string]string{ + "Name": listenerName, + }) + input := &elbv2.CreateListenerInput{ + LoadBalancerArn: lbARN, + Protocol: aws.String("TCP"), + Port: aws.Int64(port), + DefaultActions: []*elbv2.Action{ + { + Type: aws.String("forward"), + ForwardConfig: &elbv2.ForwardActionConfig{ + TargetGroups: []*elbv2.TargetGroupTuple{ + { + TargetGroupArn: tgARN, + }, + }, + }, + }, + }, + Tags: elbTags(ltags), + } + // This operation is idempotent, which means that it completes at most one + // time. If you attempt to create multiple listeners with the same + // settings, each call succeeds. + // https://docs.aws.amazon.com/sdk-for-go/api/service/elbv2/#ELBV2.CreateListener + res, err := client.CreateListenerWithContext(ctx, input) + if err != nil { + return nil, err + } + + return res.Listeners[0], nil +} + +func elbTags(tags map[string]string) []*elbv2.Tag { + etags := make([]*elbv2.Tag, 0, len(tags)) + for k, v := range tags { + k, v := k, v + etags = append(etags, &elbv2.Tag{ + Key: aws.String(k), + Value: aws.String(v), + }) + } + return etags +} From 7181aa18d5db6b2265b12db962d30bacdc98c680 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 27 Oct 2023 18:28:57 +0200 Subject: [PATCH 06/33] infra/aws: unit tests for load balancers --- pkg/infrastructure/aws/provision_test.go | 851 +++++++++++++++++++++++ 1 file changed, 851 insertions(+) diff --git a/pkg/infrastructure/aws/provision_test.go b/pkg/infrastructure/aws/provision_test.go index e6660684fb3..ae561cf7df5 100644 --- a/pkg/infrastructure/aws/provision_test.go +++ b/pkg/infrastructure/aws/provision_test.go @@ -12,8 +12,11 @@ import ( "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/util/sets" ) type mockEC2Client struct { @@ -1930,3 +1933,851 @@ func TestEnsureS3VPCEndpoint(t *testing.T) { }) } } + +type mockELBClient struct { + elbv2iface.ELBV2API + + // swappable functions + createListener func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) + + createTargetGroup func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) + describeTargetGroups func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) + + createLoadBalancer func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) + describeLoadBalancers func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) + modifyLBAttr func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) +} + +func (m *mockELBClient) CreateListenerWithContext(_ context.Context, in *elbv2.CreateListenerInput, _ ...request.Option) (*elbv2.CreateListenerOutput, error) { + return m.createListener(in) +} + +func (m *mockELBClient) CreateTargetGroupWithContext(_ context.Context, in *elbv2.CreateTargetGroupInput, _ ...request.Option) (*elbv2.CreateTargetGroupOutput, error) { + return m.createTargetGroup(in) +} + +func (m *mockELBClient) DescribeTargetGroupsWithContext(_ context.Context, in *elbv2.DescribeTargetGroupsInput, _ ...request.Option) (*elbv2.DescribeTargetGroupsOutput, error) { + return m.describeTargetGroups(in) +} + +func (m *mockELBClient) CreateLoadBalancerWithContext(_ context.Context, in *elbv2.CreateLoadBalancerInput, _ ...request.Option) (*elbv2.CreateLoadBalancerOutput, error) { + return m.createLoadBalancer(in) +} + +func (m *mockELBClient) DescribeLoadBalancersWithContext(_ context.Context, in *elbv2.DescribeLoadBalancersInput, _ ...request.Option) (*elbv2.DescribeLoadBalancersOutput, error) { + return m.describeLoadBalancers(in) +} + +func (m *mockELBClient) ModifyLoadBalancerAttributesWithContext(_ context.Context, in *elbv2.ModifyLoadBalancerAttributesInput, _ ...request.Option) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return m.modifyLBAttr(in) +} + +func TestEnsureTargetGroup(t *testing.T) { + expectedTargetGroup := &elbv2.TargetGroup{} + + tests := []struct { + name string + mockSvc mockELBClient + expectedOut *elbv2.TargetGroup + expectedErr string + }{ + { + name: "AWS SDK error listing target groups", + mockSvc: mockELBClient{ + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, errAwsSdk + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list target groups: some AWS SDK error$`, + }, + { + name: "Target group already created", + mockSvc: mockELBClient{ + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return &elbv2.DescribeTargetGroupsOutput{TargetGroups: []*elbv2.TargetGroup{expectedTargetGroup}}, nil + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + }, + expectedOut: expectedTargetGroup, + }, + { + name: "Creating target group fails", + mockSvc: mockELBClient{ + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return &elbv2.DescribeTargetGroupsOutput{}, nil + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^some AWS SDK error$`, + }, + { + name: "Creating target group succeeds", + mockSvc: mockELBClient{ + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, awserr.New(elbv2.ErrCodeTargetGroupNotFoundException, "", errAwsSdk) + }, + createTargetGroup: func(in *elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + return &elbv2.CreateTargetGroupOutput{TargetGroups: []*elbv2.TargetGroup{expectedTargetGroup}}, nil + }, + }, + expectedOut: expectedTargetGroup, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + res, err := ensureTargetGroup(context.TODO(), logger, &test.mockSvc, "tgName", "vpc-1", readyzPath, apiPort, map[string]string{}) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureLoadBalancer(t *testing.T) { + expectedLoadBalancer := &elbv2.LoadBalancer{} + + tests := []struct { + name string + mockSvc mockELBClient + expectedOut *elbv2.LoadBalancer + expectedErr string + }{ + { + name: "AWS SDK error listing load balancers", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errAwsSdk + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + panic("should not be called") + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list load balancers: some AWS SDK error$`, + }, + { + name: "Load balancer already exists but enabling cross zone fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return &elbv2.DescribeLoadBalancersOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + panic("should not be called") + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to enable cross_zone attribute: some AWS SDK error$`, + }, + { + name: "Creating load balancer fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, awserr.New(elbv2.ErrCodeLoadBalancerNotFoundException, "", errAwsSdk) + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return nil, errAwsSdk + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^some AWS SDK error$`, + }, + { + name: "Load balancer created but enabling cross zone fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to enable cross_zone attribute: some AWS SDK error$`, + }, + { + name: "Load balancer created and cross zone attribute set", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + }, + expectedOut: expectedLoadBalancer, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + res, err := ensureLoadBalancer(context.TODO(), logger, &test.mockSvc, "lbName", []string{}, true, map[string]string{}) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureInternalLoadBalancer(t *testing.T) { + expectedLoadBalancer := &elbv2.LoadBalancer{} + const tgAName = "infraID-aint" + targetA := &elbv2.TargetGroup{ + TargetGroupName: aws.String(tgAName), + TargetGroupArn: aws.String("aint-arn"), + } + listenerA := &elbv2.Listener{ + ListenerArn: aws.String("aint-arn"), + Port: aws.Int64(apiPort), + } + const tgSName = "infraID-sint" + targetS := &elbv2.TargetGroup{ + TargetGroupName: aws.String(tgSName), + TargetGroupArn: aws.String("sint-arn"), + } + listenerS := &elbv2.Listener{ + ListenerArn: aws.String("sint-arn"), + Port: aws.Int64(servicePort), + } + + tests := []struct { + name string + mockSvc mockELBClient + expectedOut *elbv2.LoadBalancer + expectedErr string + }{ + { + name: "AWS SDK error listing load balancers", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errAwsSdk + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + panic("should not be called") + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + panic("should not be called") + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + panic("should not be called") + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list load balancers: some AWS SDK error$`, + }, + { + name: "Load balancer already exists but creating target group A fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return &elbv2.DescribeLoadBalancersOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + panic("should not be called") + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, errNotFound + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + return nil, errAwsSdk + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create internalA target group: some AWS SDK error$`, + }, + { + name: "Creating load balancer fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, awserr.New(elbv2.ErrCodeLoadBalancerNotFoundException, "", errAwsSdk) + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return nil, errAwsSdk + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + panic("should not be called") + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^some AWS SDK error$`, + }, + { + name: "Load balancer created but listing target group fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, errAwsSdk + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create internalA target group: failed to list target groups: some AWS SDK error$`, + }, + { + name: "Load balancer created but creating target group A fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, awserr.New(elbv2.ErrCodeTargetGroupNotFoundException, "", errAwsSdk) + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + return nil, errAwsSdk + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create internalA target group: some AWS SDK error$`, + }, + { + name: "Load balancer created but creating listener A fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, errAwsSdk + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + return &elbv2.CreateTargetGroupOutput{}, nil + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create internalA target group: failed to list target groups: some AWS SDK error$`, + }, + { + name: "Load balancer created, target A and listener created but listing target groups fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(in *elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + if aws.StringValue(in.Names[0]) == tgAName { + return &elbv2.DescribeTargetGroupsOutput{ + TargetGroups: []*elbv2.TargetGroup{targetA}, + }, nil + } + return nil, errAwsSdk + }, + createTargetGroup: func(in *elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + createListener: func(in *elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + if aws.Int64Value(in.Port) == apiPort { + return &elbv2.CreateListenerOutput{ + Listeners: []*elbv2.Listener{listenerA}, + }, nil + } + panic("should not be called") + }, + }, + expectedErr: `^failed to create internalS target group: failed to list target groups: some AWS SDK error$`, + }, + { + name: "Load balancer created, target A and listener created but creating target S fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return &elbv2.DescribeLoadBalancersOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + panic("should not be called") + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(in *elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + switch aws.StringValue(in.Names[0]) { + case tgAName: + return &elbv2.DescribeTargetGroupsOutput{ + TargetGroups: []*elbv2.TargetGroup{targetA}, + }, nil + case tgSName: + return nil, errNotFound + default: + panic("should not be called") + } + }, + createTargetGroup: func(in *elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + switch aws.StringValue(in.Name) { + case tgAName: + panic("should not be called") + case tgSName: + return nil, errAwsSdk + default: + panic("should not be called") + } + }, + createListener: func(in *elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + if aws.Int64Value(in.Port) == apiPort { + return &elbv2.CreateListenerOutput{ + Listeners: []*elbv2.Listener{listenerA}, + }, nil + } + panic("should not be called") + }, + }, + expectedErr: `^failed to create internalS target group: some AWS SDK error$`, + }, + { + name: "Load balancer created, target A and listener created, target S created but listener fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return &elbv2.DescribeLoadBalancersOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + panic("should not be called") + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(in *elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + switch aws.StringValue(in.Names[0]) { + case tgAName: + return &elbv2.DescribeTargetGroupsOutput{ + TargetGroups: []*elbv2.TargetGroup{targetA}, + }, nil + case tgSName: + return nil, errNotFound + default: + panic("should not be called") + } + }, + createTargetGroup: func(in *elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + switch aws.StringValue(in.Name) { + case tgAName: + panic("should not be called") + case tgSName: + return &elbv2.CreateTargetGroupOutput{ + TargetGroups: []*elbv2.TargetGroup{targetS}, + }, nil + default: + panic("should not be called") + } + }, + createListener: func(in *elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + switch aws.Int64Value(in.Port) { + case apiPort: + return &elbv2.CreateListenerOutput{ + Listeners: []*elbv2.Listener{listenerA}, + }, nil + case servicePort: + return nil, errAwsSdk + default: + panic("should not be called") + } + }, + }, + expectedErr: `^failed to create internalS listener: some AWS SDK error$`, + }, + { + name: "Load balancer, target groups and listeners created", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(in *elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + switch aws.StringValue(in.Names[0]) { + case tgAName: + return &elbv2.DescribeTargetGroupsOutput{ + TargetGroups: []*elbv2.TargetGroup{targetA}, + }, nil + case tgSName: + return &elbv2.DescribeTargetGroupsOutput{ + TargetGroups: []*elbv2.TargetGroup{targetS}, + }, nil + default: + return nil, errAwsSdk + } + }, + createTargetGroup: func(in *elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + createListener: func(in *elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + switch aws.Int64Value(in.Port) { + case apiPort: + return &elbv2.CreateListenerOutput{ + Listeners: []*elbv2.Listener{listenerA}, + }, nil + case servicePort: + return &elbv2.CreateListenerOutput{ + Listeners: []*elbv2.Listener{listenerS}, + }, nil + default: + panic("should not be called") + } + }, + }, + expectedOut: expectedLoadBalancer, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := lbState{ + input: &lbInputOptions{ + infraID: "infraID", + vpcID: "vpc-1", + }, + targetGroupArns: sets.New[string](), + } + res, err := state.ensureInternalLoadBalancer(context.TODO(), logger, &test.mockSvc, []string{}, map[string]string{}) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestEnsureExternalLoadBalancer(t *testing.T) { + expectedLoadBalancer := &elbv2.LoadBalancer{} + const tgAName = "infraID-aext" + targetA := &elbv2.TargetGroup{ + TargetGroupName: aws.String(tgAName), + TargetGroupArn: aws.String("aext-arn"), + } + listenerA := &elbv2.Listener{ + ListenerArn: aws.String("aext-arn"), + Port: aws.Int64(apiPort), + } + + tests := []struct { + name string + mockSvc mockELBClient + expectedOut *elbv2.LoadBalancer + expectedErr string + }{ + { + name: "AWS SDK error listing load balancers", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errAwsSdk + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + panic("should not be called") + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + panic("should not be called") + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + panic("should not be called") + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list load balancers: some AWS SDK error$`, + }, + { + name: "Load balancer already exists but creating target group A fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return &elbv2.DescribeLoadBalancersOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + panic("should not be called") + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, errNotFound + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + return nil, errAwsSdk + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create external target group: some AWS SDK error$`, + }, + { + name: "Creating load balancer fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, awserr.New(elbv2.ErrCodeLoadBalancerNotFoundException, "", errAwsSdk) + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return nil, errAwsSdk + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + panic("should not be called") + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^some AWS SDK error$`, + }, + { + name: "Load balancer created but listing target group fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, errAwsSdk + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create external target group: failed to list target groups: some AWS SDK error$`, + }, + { + name: "Load balancer created but creating target group A fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, awserr.New(elbv2.ErrCodeTargetGroupNotFoundException, "", errAwsSdk) + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + return nil, errAwsSdk + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create external target group: some AWS SDK error$`, + }, + { + name: "Load balancer created but creating listener A fails", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + return nil, errAwsSdk + }, + createTargetGroup: func(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + return &elbv2.CreateTargetGroupOutput{}, nil + }, + createListener: func(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create external target group: failed to list target groups: some AWS SDK error$`, + }, + { + name: "Load balancer, target groups and listeners created", + mockSvc: mockELBClient{ + describeLoadBalancers: func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + return nil, errNotFound + }, + createLoadBalancer: func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) { + return &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{expectedLoadBalancer}, + }, nil + }, + modifyLBAttr: func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return &elbv2.ModifyLoadBalancerAttributesOutput{}, nil + }, + describeTargetGroups: func(in *elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + switch aws.StringValue(in.Names[0]) { + case tgAName: + return &elbv2.DescribeTargetGroupsOutput{ + TargetGroups: []*elbv2.TargetGroup{targetA}, + }, nil + default: + return nil, errAwsSdk + } + }, + createTargetGroup: func(in *elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) { + panic("should not be called") + }, + createListener: func(in *elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { + switch aws.Int64Value(in.Port) { + case apiPort: + return &elbv2.CreateListenerOutput{ + Listeners: []*elbv2.Listener{listenerA}, + }, nil + default: + panic("should not be called") + } + }, + }, + expectedOut: expectedLoadBalancer, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := lbState{ + input: &lbInputOptions{ + infraID: "infraID", + vpcID: "vpc-1", + }, + targetGroupArns: sets.New[string](), + } + res, err := state.ensureExternalLoadBalancer(context.TODO(), logger, &test.mockSvc, []string{}, map[string]string{}) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} From c4a04f420cc4f044f4a318e32cb9f576fbf7f33c Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Sat, 28 Oct 2023 23:55:08 +0200 Subject: [PATCH 07/33] infra/aws: create DNS resources Create DNS related resources. Co-authored-by: Enxebre --- pkg/infrastructure/aws/aws.go | 23 ++- pkg/infrastructure/aws/dns.go | 305 ++++++++++++++++++++++++++++++++++ 2 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 pkg/infrastructure/aws/dns.go diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index cee8b6754f2..4da472798c6 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/aws/aws-sdk-go/service/route53" "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/sets" @@ -117,11 +118,31 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, tags: tags, isPrivateCluster: clusterAWSConfig.PublishStrategy != "External", } - _, err = createLoadBalancers(ctx, logger, elbClient, &lbInput) + lbOutput, err := createLoadBalancers(ctx, logger, elbClient, &lbInput) if err != nil { return nil, fmt.Errorf("failed to create load balancers: %w", err) } + logger.Infoln("Creating DNS resources") + r53Client := route53.New(awsSession) + dnsInput := dnsInputOptions{ + infraID: clusterConfig.ClusterID, + region: clusterAWSConfig.Region, + baseDomain: clusterConfig.BaseDomain, + clusterDomain: clusterConfig.ClusterDomain, + vpcID: vpcOutput.vpcID, + tags: tags, + lbExternalZoneID: lbOutput.external.zoneID, + lbExternalZoneDNS: lbOutput.external.dnsName, + lbInternalZoneID: lbOutput.internal.zoneID, + lbInternalZoneDNS: lbOutput.internal.dnsName, + isPrivateCluster: clusterAWSConfig.PublishStrategy != "External", + } + err = createDNSResources(ctx, logger, r53Client, &dnsInput) + if err != nil { + return nil, fmt.Errorf("failed to create DNS rsources: %w", err) + } + return nil, fmt.Errorf("provision stage not implemented yet") } diff --git a/pkg/infrastructure/aws/dns.go b/pkg/infrastructure/aws/dns.go new file mode 100644 index 00000000000..6917d9beeef --- /dev/null +++ b/pkg/infrastructure/aws/dns.go @@ -0,0 +1,305 @@ +package aws + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/route53" + "github.com/aws/aws-sdk-go/service/route53/route53iface" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/util/wait" +) + +const ( + errSharedCredsLoad = "SharedCredsLoad" + + defaultDescription = "Created by Openshift Installer" +) + +type dnsInputOptions struct { + infraID string + region string + baseDomain string + clusterDomain string + vpcID string + lbExternalZoneID string + lbExternalZoneDNS string + lbInternalZoneID string + lbInternalZoneDNS string + isPrivateCluster bool + tags map[string]string +} + +func createDNSResources(ctx context.Context, logger logrus.FieldLogger, route53Client route53iface.Route53API, input *dnsInputOptions) error { + apiName := fmt.Sprintf("api.%s", input.clusterDomain) + apiIntName := fmt.Sprintf("api-int.%s", input.clusterDomain) + + if !input.isPrivateCluster { + publicZone, err := existingHostedZone(ctx, route53Client, input.baseDomain, false) + if err != nil { + return fmt.Errorf("failed to find public zone (%s): %w", input.baseDomain, err) + } + zoneID := cleanZoneID(publicZone.Id) + logger.WithFields(logrus.Fields{ + "domain": input.baseDomain, + "id": zoneID, + }).Infoln("Found existing public zone") + + // Create API record in public zone + _, err = createRecordA(ctx, route53Client, zoneID, apiName, input.lbExternalZoneDNS, input.lbExternalZoneID) + if err != nil { + return fmt.Errorf("failed to create api record (%s) in public zone: %w", apiName, err) + } + logger.Infoln("Created api DNS record for public zone") + } + + privateZone, err := ensurePrivateZone(ctx, logger, route53Client, input) + if err != nil { + return err + } + privateZoneID := cleanZoneID(privateZone.Id) + + // Create API record in private zone + _, err = createRecordA(ctx, route53Client, privateZoneID, apiName, input.lbInternalZoneDNS, input.lbInternalZoneID) + if err != nil { + return fmt.Errorf("failed to create api record (%s) in private zone: %w", apiName, err) + } + logger.Infoln("Created api DNS record for private zone") + + // Create API-int record in privat zone + _, err = createRecordA(ctx, route53Client, privateZoneID, apiIntName, input.lbInternalZoneDNS, input.lbInternalZoneID) + if err != nil { + return fmt.Errorf("failed to create api-int record (%s) in private zone: %w", apiIntName, err) + } + logger.Infoln("Created api-int DNS record for private zone") + + return nil +} + +func ensurePrivateZone(ctx context.Context, logger logrus.FieldLogger, client route53iface.Route53API, input *dnsInputOptions) (*route53.HostedZone, error) { + createdOrFoundMsg := "Found existing private hosted zone" + privateZone, err := existingHostedZone(ctx, client, input.clusterDomain, true) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + createdOrFoundMsg = "Created private hosted zone" + privateZone, err = createHostedZone(ctx, client, input.clusterDomain, input.vpcID, input.region, true) + if err != nil { + return nil, fmt.Errorf("failed to create private hosted zone: %w", err) + } + } + l := logger.WithField("id", cleanZoneID(privateZone.Id)) + l.Infoln(createdOrFoundMsg) + + // Tag the hosted zone + tags := mergeTags(input.tags, map[string]string{"Name": fmt.Sprintf("%s-int", input.infraID)}) + _, err = client.ChangeTagsForResourceWithContext(ctx, &route53.ChangeTagsForResourceInput{ + ResourceType: aws.String("hostedzone"), + ResourceId: privateZone.Id, + AddTags: r53Tags(tags), + }) + if err != nil { + return nil, fmt.Errorf("failed to tag private hosted zone: %w", err) + } + l.Infoln("Tagged private hosted zone") + + // Set SOA minimum TTL + recordSet, err := existingRecordSet(ctx, client, privateZone.Id, input.clusterDomain, "SOA") + if err != nil { + return nil, fmt.Errorf("failed to find SOA record set for private zone: %w", err) + } + if len(recordSet.ResourceRecords) == 0 || recordSet.ResourceRecords[0] == nil || recordSet.ResourceRecords[0].Value == nil { + return nil, fmt.Errorf("failed to find SOA record for private zone") + } + record := recordSet.ResourceRecords[0] + fields := strings.Split(aws.StringValue(record.Value), " ") + if len(fields) != 7 { + return nil, fmt.Errorf("SOA record value has %d fields, expected 7", len(fields)) + } + fields[6] = "60" + record.Value = aws.String(strings.Join(fields, " ")) + _, err = client.ChangeResourceRecordSetsWithContext(ctx, &route53.ChangeResourceRecordSetsInput{ + HostedZoneId: privateZone.Id, + ChangeBatch: &route53.ChangeBatch{ + Changes: []*route53.Change{ + { + Action: aws.String("UPSERT"), + ResourceRecordSet: recordSet, + }, + }, + }, + }, + ) + if err != nil { + return nil, fmt.Errorf("failed to set SOA TTL to minimum: %w", err) + } + + return privateZone, nil +} + +func existingHostedZone(ctx context.Context, client route53iface.Route53API, name string, isPrivate bool) (*route53.HostedZone, error) { + var hz *route53.HostedZone + if err := retryWithBackoff( + ctx, + func(ctx context.Context) error { + return client.ListHostedZonesPagesWithContext( + ctx, + &route53.ListHostedZonesInput{}, + func(res *route53.ListHostedZonesOutput, lastPage bool) bool { + for i, zone := range res.HostedZones { + if zone.Config != nil && aws.BoolValue(zone.Config.PrivateZone) == isPrivate && strings.TrimSuffix(aws.StringValue(zone.Name), ".") == strings.TrimSuffix(name, ".") { + hz = res.HostedZones[i] + return false + } + } + return !lastPage + }, + ) + }, + ); err != nil { + return nil, fmt.Errorf("failed to list hosted zones: %w", err) + } + if hz == nil { + return nil, errNotFound + } + + return hz, nil +} + +func createHostedZone(ctx context.Context, client route53iface.Route53API, name, vpcID, region string, isPrivate bool) (*route53.HostedZone, error) { + var res *route53.CreateHostedZoneOutput + err := retryWithBackoff( + ctx, + func(ctx context.Context) error { + var err error + callRef := fmt.Sprintf("%d", time.Now().Unix()) + res, err = client.CreateHostedZoneWithContext(ctx, &route53.CreateHostedZoneInput{ + CallerReference: aws.String(callRef), + Name: aws.String(name), + HostedZoneConfig: &route53.HostedZoneConfig{ + PrivateZone: aws.Bool(isPrivate), + Comment: aws.String(defaultDescription), + }, + VPC: &route53.VPC{ + VPCId: aws.String(vpcID), + VPCRegion: aws.String(region), + }, + }) + return err + }, + ) + if err != nil { + return nil, fmt.Errorf("failed to create hosted zone: %w", err) + } + if res == nil { + return nil, fmt.Errorf("unexpected output from hosted zone creation") + } + + return res.HostedZone, nil +} + +func createRecordA(ctx context.Context, client route53iface.Route53API, zoneID string, name string, aliasDNS string, aliasID string) (*route53.ChangeInfo, error) { + input := &route53.ChangeResourceRecordSetsInput{ + HostedZoneId: aws.String(zoneID), + ChangeBatch: &route53.ChangeBatch{ + Changes: []*route53.Change{ + { + Action: aws.String("UPSERT"), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String(cleanRecordName(name)), + Type: aws.String("A"), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String(aliasDNS), + HostedZoneId: aws.String(aliasID), + EvaluateTargetHealth: aws.Bool(false), + }, + }, + }, + }, + }, + } + res, err := client.ChangeResourceRecordSetsWithContext(ctx, input) + if err != nil { + return nil, fmt.Errorf("failed to create alias record: %w", err) + } + + return res.ChangeInfo, nil +} + +func existingRecordSet(ctx context.Context, client route53iface.Route53API, zoneID *string, recordName string, recordType string) (*route53.ResourceRecordSet, error) { + name := fqdn(strings.ToLower(recordName)) + input := &route53.ListResourceRecordSetsInput{ + HostedZoneId: zoneID, + StartRecordName: aws.String(name), + StartRecordType: aws.String(recordType), + MaxItems: aws.String("1"), + } + res, err := client.ListResourceRecordSetsWithContext(ctx, input) + if err != nil { + return nil, err + } + for _, rs := range res.ResourceRecordSets { + resName := strings.ToLower(cleanRecordName(aws.StringValue(rs.Name))) + resType := strings.ToUpper(aws.StringValue(rs.Type)) + if resName == name && resType == recordType { + return rs, nil + } + } + return nil, errNotFound +} + +func cleanZoneID(zoneID *string) string { + return strings.TrimPrefix(aws.StringValue(zoneID), "/hostedzone/") +} + +func cleanRecordName(name string) string { + s, err := strconv.Unquote(`"` + name + `"`) + if err != nil { + return name + } + return s +} + +func fqdn(name string) string { + n := len(name) + if n == 0 || name[n-1] == '.' { + return name + } + return name + "." +} + +func retryWithBackoff(ctx context.Context, fn func(ctx context.Context) error) error { + return wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (bool, error) { + if err := fn(ctx); err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && awsErr.Code() == errSharedCredsLoad { + return true, err + } + return false, nil + } + return true, nil + }, + ) +} + +func r53Tags(tags map[string]string) []*route53.Tag { + rtags := make([]*route53.Tag, 0, len(tags)) + for k, v := range tags { + k, v := k, v + rtags = append(rtags, &route53.Tag{ + Key: aws.String(k), + Value: aws.String(v), + }) + } + return rtags +} From 593aa9b373d7df3c5ec4f1e6f009afd74a1b2d1e Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Sat, 28 Oct 2023 23:55:45 +0200 Subject: [PATCH 08/33] infra/aws: add DNS unit tests --- pkg/infrastructure/aws/provision_test.go | 314 +++++++++++++++++++++++ 1 file changed, 314 insertions(+) diff --git a/pkg/infrastructure/aws/provision_test.go b/pkg/infrastructure/aws/provision_test.go index ae561cf7df5..4c39e03170d 100644 --- a/pkg/infrastructure/aws/provision_test.go +++ b/pkg/infrastructure/aws/provision_test.go @@ -14,6 +14,8 @@ import ( "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/aws/aws-sdk-go/service/elbv2" "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/aws/aws-sdk-go/service/route53" + "github.com/aws/aws-sdk-go/service/route53/route53iface" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "k8s.io/apimachinery/pkg/util/sets" @@ -2781,3 +2783,315 @@ func TestEnsureExternalLoadBalancer(t *testing.T) { }) } } + +type mockR53Client struct { + route53iface.Route53API + + createHostedZone func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) + listHostedZones func(*route53.ListHostedZonesInput, func(*route53.ListHostedZonesOutput, bool) bool) error + changeTags func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) + + listRecordSets func(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) + changeRecordSet func(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) +} + +func (m *mockR53Client) CreateHostedZoneWithContext(_ context.Context, in *route53.CreateHostedZoneInput, _ ...request.Option) (*route53.CreateHostedZoneOutput, error) { + return m.createHostedZone(in) +} + +func (m *mockR53Client) ListHostedZonesPagesWithContext(_ context.Context, in *route53.ListHostedZonesInput, fn func(*route53.ListHostedZonesOutput, bool) bool, _ ...request.Option) error { + return m.listHostedZones(in, fn) +} + +func (m *mockR53Client) ChangeTagsForResourceWithContext(_ context.Context, in *route53.ChangeTagsForResourceInput, _ ...request.Option) (*route53.ChangeTagsForResourceOutput, error) { + return m.changeTags(in) +} + +func (m *mockR53Client) ListResourceRecordSetsWithContext(_ context.Context, in *route53.ListResourceRecordSetsInput, _ ...request.Option) (*route53.ListResourceRecordSetsOutput, error) { + return m.listRecordSets(in) +} + +func (m *mockR53Client) ChangeResourceRecordSetsWithContext(_ context.Context, in *route53.ChangeResourceRecordSetsInput, _ ...request.Option) (*route53.ChangeResourceRecordSetsOutput, error) { + return m.changeRecordSet(in) +} + +func TestEnsurePrivateHostedZone(t *testing.T) { + privateHostedZone := &route53.HostedZone{ + Id: aws.String("hostedzone-1"), + Name: aws.String("domain.com."), + Config: &route53.HostedZoneConfig{PrivateZone: aws.Bool(true)}, + } + tests := []struct { + name string + mockSvc mockR53Client + isPrivate bool + expectedOut *route53.HostedZone + expectedErr string + }{ + { + name: "AWS SDK error listing hosted zones", + mockSvc: mockR53Client{ + listHostedZones: func(*route53.ListHostedZonesInput, func(*route53.ListHostedZonesOutput, bool) bool) error { + return errAwsSdk + }, + createHostedZone: func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) { + panic("should not be called") + }, + changeTags: func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list hosted zones: .*$`, + }, + { + name: "Create hosted zone fails", + mockSvc: mockR53Client{ + listHostedZones: func(*route53.ListHostedZonesInput, func(*route53.ListHostedZonesOutput, bool) bool) error { + return nil + }, + createHostedZone: func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) { + return nil, errAwsSdk + }, + changeTags: func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create private hosted zone: failed to create hosted zone: .*$`, + }, + { + name: "Hosted zone created but tagging fails", + mockSvc: mockR53Client{ + listHostedZones: func(*route53.ListHostedZonesInput, func(*route53.ListHostedZonesOutput, bool) bool) error { + return nil + }, + createHostedZone: func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) { + return &route53.CreateHostedZoneOutput{ + HostedZone: privateHostedZone, + }, nil + }, + changeTags: func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to tag private hosted zone: some AWS SDK error$`, + }, + { + name: "Existing zone and tagging succeeds but listing records fails", + mockSvc: mockR53Client{ + listHostedZones: func(_ *route53.ListHostedZonesInput, fn func(*route53.ListHostedZonesOutput, bool) bool) error { + fn(&route53.ListHostedZonesOutput{ + HostedZones: []*route53.HostedZone{privateHostedZone}, + }, true) + return nil + }, + createHostedZone: func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) { + panic("should not be called") + }, + changeTags: func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) { + return &route53.ChangeTagsForResourceOutput{}, nil + }, + listRecordSets: func(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) { + return nil, errAwsSdk + }, + changeRecordSet: func(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) { + panic("change records should not be called") + }, + }, + expectedErr: `failed to find SOA record set for private zone: some AWS SDK error$`, + }, + { + name: "Created and tagged zone but SOA record set not found", + mockSvc: mockR53Client{ + listHostedZones: func(_ *route53.ListHostedZonesInput, fn func(*route53.ListHostedZonesOutput, bool) bool) error { + fn(&route53.ListHostedZonesOutput{ + HostedZones: []*route53.HostedZone{privateHostedZone}, + }, true) + return nil + }, + createHostedZone: func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) { + panic("should not be called") + }, + changeTags: func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) { + return &route53.ChangeTagsForResourceOutput{}, nil + }, + listRecordSets: func(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) { + return &route53.ListResourceRecordSetsOutput{}, nil + }, + changeRecordSet: func(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `failed to find SOA record set for private zone: not found$`, + }, + { + name: "Created and tagged zone but SOA not found", + mockSvc: mockR53Client{ + listHostedZones: func(_ *route53.ListHostedZonesInput, fn func(*route53.ListHostedZonesOutput, bool) bool) error { + fn(&route53.ListHostedZonesOutput{ + HostedZones: []*route53.HostedZone{privateHostedZone}, + }, true) + return nil + }, + createHostedZone: func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) { + panic("create should not be called") + }, + changeTags: func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) { + return &route53.ChangeTagsForResourceOutput{}, nil + }, + listRecordSets: func(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) { + return &route53.ListResourceRecordSetsOutput{ + ResourceRecordSets: []*route53.ResourceRecordSet{ + { + Name: aws.String("domain.com."), + Type: aws.String("SOA"), + ResourceRecords: []*route53.ResourceRecord{}, + }, + }, + }, nil + }, + changeRecordSet: func(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) { + panic("change records should not be called") + }, + }, + expectedErr: `failed to find SOA record for private zone$`, + }, + { + name: "Created and tagged zone but SOA has wrong number of fields", + mockSvc: mockR53Client{ + listHostedZones: func(_ *route53.ListHostedZonesInput, fn func(*route53.ListHostedZonesOutput, bool) bool) error { + fn(&route53.ListHostedZonesOutput{ + HostedZones: []*route53.HostedZone{privateHostedZone}, + }, true) + return nil + }, + createHostedZone: func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) { + panic("create should not be called") + }, + changeTags: func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) { + return &route53.ChangeTagsForResourceOutput{}, nil + }, + listRecordSets: func(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) { + return &route53.ListResourceRecordSetsOutput{ + ResourceRecordSets: []*route53.ResourceRecordSet{ + { + Name: aws.String("domain.com."), + Type: aws.String("SOA"), + ResourceRecords: []*route53.ResourceRecord{ + {Value: aws.String("domain email 1")}, + }, + }, + }, + }, nil + }, + changeRecordSet: func(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) { + panic("change records should not be called") + }, + }, + expectedErr: `SOA record value has [^7] fields, expected 7$`, + }, + { + name: "Created and tagged zone but setting SOA minimum TTL fails", + mockSvc: mockR53Client{ + listHostedZones: func(_ *route53.ListHostedZonesInput, fn func(*route53.ListHostedZonesOutput, bool) bool) error { + fn(&route53.ListHostedZonesOutput{ + HostedZones: []*route53.HostedZone{privateHostedZone}, + }, true) + return nil + }, + createHostedZone: func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) { + panic("create should not be called") + }, + changeTags: func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) { + return &route53.ChangeTagsForResourceOutput{}, nil + }, + listRecordSets: func(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) { + return &route53.ListResourceRecordSetsOutput{ + ResourceRecordSets: []*route53.ResourceRecordSet{ + { + Name: aws.String("domain.com."), + Type: aws.String("SOA"), + ResourceRecords: []*route53.ResourceRecord{ + {Value: aws.String("domain email 1 7200 900 1209600 86400")}, + }, + }, + }, + }, nil + }, + changeRecordSet: func(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `failed to set SOA TTL to minimum: some AWS SDK error$`, + }, + { + name: "Zone created, tagged zone and SOA set to minimum TTL", + mockSvc: mockR53Client{ + listHostedZones: func(_ *route53.ListHostedZonesInput, fn func(*route53.ListHostedZonesOutput, bool) bool) error { + fn(&route53.ListHostedZonesOutput{ + HostedZones: []*route53.HostedZone{privateHostedZone}, + }, true) + return nil + }, + createHostedZone: func(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) { + panic("create should not be called") + }, + changeTags: func(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) { + return &route53.ChangeTagsForResourceOutput{}, nil + }, + listRecordSets: func(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) { + return &route53.ListResourceRecordSetsOutput{ + ResourceRecordSets: []*route53.ResourceRecordSet{ + { + Name: aws.String("domain.com."), + Type: aws.String("SOA"), + ResourceRecords: []*route53.ResourceRecord{ + {Value: aws.String("domain email 1 7200 900 1209600 86400")}, + }, + }, + }, + }, nil + }, + changeRecordSet: func(in *route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) { + updated := aws.StringValue(in.ChangeBatch.Changes[0].ResourceRecordSet.ResourceRecords[0].Value) + if updated != "domain email 1 7200 900 1209600 60" { + panic("SOA minimum TTL not set") + } + return &route53.ChangeResourceRecordSetsOutput{}, nil + }, + }, + expectedOut: privateHostedZone, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + input := dnsInputOptions{ + clusterDomain: "domain.com", + vpcID: "vpc-1", + region: "region-1", + infraID: "infraID", + tags: map[string]string{"custom-tag": "custom-value"}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + res, err := ensurePrivateZone(context.TODO(), logger, &test.mockSvc, &input) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +func TestFQDN(t *testing.T) { + assert.Equal(t, "domain.", fqdn("domain")) + assert.Equal(t, "domain.", fqdn("domain.")) + assert.Equal(t, "domain.com.", fqdn("domain.com")) + assert.Equal(t, "domain.com.", fqdn("domain.com.")) + assert.Equal(t, "", fqdn("")) + assert.Equal(t, ".", fqdn(".")) +} From fa61d2c8e2ad0fd6f54a0a8963b7f90a686a2b22 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Mon, 30 Oct 2023 15:24:11 +0100 Subject: [PATCH 09/33] infra/aws: create security group resources Create security group related resources Co-authored-by: Enxebre --- pkg/infrastructure/aws/aws.go | 13 + pkg/infrastructure/aws/securitygroup.go | 419 ++++++++++++++++++++++++ 2 files changed, 432 insertions(+) create mode 100644 pkg/infrastructure/aws/securitygroup.go diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 4da472798c6..5ccf192ea07 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -143,6 +143,19 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, return nil, fmt.Errorf("failed to create DNS rsources: %w", err) } + logger.Infoln("Creating security groups") + sgInput := sgInputOptions{ + infraID: clusterConfig.ClusterID, + vpcID: vpcOutput.vpcID, + cidrV4Blocks: clusterConfig.MachineV4CIDRs, + isPrivateCluster: clusterAWSConfig.PublishStrategy != "External", + tags: tags, + } + _, err = createSecurityGroups(ctx, logger, ec2Client, &sgInput) + if err != nil { + return nil, fmt.Errorf("failed to create security groups: %w", err) + } + return nil, fmt.Errorf("provision stage not implemented yet") } diff --git a/pkg/infrastructure/aws/securitygroup.go b/pkg/infrastructure/aws/securitygroup.go new file mode 100644 index 00000000000..8357b51d74e --- /dev/null +++ b/pkg/infrastructure/aws/securitygroup.go @@ -0,0 +1,419 @@ +package aws + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/util/wait" +) + +const errDuplicatePermission = "InvalidPermission.Duplicate" + +type sgInputOptions struct { + infraID string + vpcID string + cidrV4Blocks []string + isPrivateCluster bool + tags map[string]string +} + +type sgOutput struct { + bootstrap string + controlPlane string + compute string +} + +func createSecurityGroups(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, input *sgInputOptions) (*sgOutput, error) { + bootstrapSGName := fmt.Sprintf("%s-bootstrap-sg", input.infraID) + bootstrapSG, err := ensureSecurityGroup(ctx, logger, ec2Client, input.infraID, input.vpcID, bootstrapSGName, input.tags) + if err != nil { + return nil, fmt.Errorf("failed to create bootstrap security group: %w", err) + } + + cidrs := input.cidrV4Blocks + if !input.isPrivateCluster { + cidrs = []string{"0.0.0.0/0"} + } + bootstrapIngress := defaultBootstrapSGIngressRules(bootstrapSG.GroupId, cidrs) + err = authorizeIngressRules(ctx, ec2Client, bootstrapSG, bootstrapIngress) + if err != nil { + return nil, fmt.Errorf("failed to attach ingress rules to bootstrap security group: %w", err) + } + + masterSGName := fmt.Sprintf("%s-master-sg", input.infraID) + masterSG, err := ensureSecurityGroup(ctx, logger, ec2Client, input.infraID, input.vpcID, masterSGName, input.tags) + if err != nil { + return nil, fmt.Errorf("failed to create control plane security group: %w", err) + } + + workerSGName := fmt.Sprintf("%s-worker-sg", input.infraID) + workerSG, err := ensureSecurityGroup(ctx, logger, ec2Client, input.infraID, input.vpcID, workerSGName, input.tags) + if err != nil { + return nil, fmt.Errorf("failed to create compute security group: %w", err) + } + + masterIngress := defaultMasterSGIngressRules(masterSG.GroupId, workerSG.GroupId, input.cidrV4Blocks) + err = authorizeIngressRules(ctx, ec2Client, masterSG, masterIngress) + if err != nil { + return nil, fmt.Errorf("failed to attach ingress rules to master security group: %w", err) + } + workerIngress := defaultWorkerSGIngressRules(workerSG.GroupId, masterSG.GroupId, input.cidrV4Blocks) + err = authorizeIngressRules(ctx, ec2Client, workerSG, workerIngress) + if err != nil { + return nil, fmt.Errorf("failed to attach ingress rules to worker security group: %w", err) + } + + return &sgOutput{ + bootstrap: aws.StringValue(bootstrapSG.GroupId), + controlPlane: aws.StringValue(masterSG.GroupId), + compute: aws.StringValue(workerSG.GroupId), + }, nil +} + +func ensureSecurityGroup(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, infraID, vpcID string, name string, tags map[string]string) (*ec2.SecurityGroup, error) { + filters := ec2Filters(infraID, name) + l := logger.WithField("name", name) + createdOrFoundMsg := "Found existing security group" + sg, err := existingSecurityGroup(ctx, client, filters) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, err + } + createdOrFoundMsg = "Created security group" + gtags := mergeTags(tags, map[string]string{"Name": name}) + sg, err = createSecurityGroup(ctx, client, name, vpcID, gtags) + if err != nil { + return nil, err + } + } + l.WithField("id", aws.StringValue(sg.GroupId)).Infoln(createdOrFoundMsg) + + egressPermissions := defaultEgressRules(sg.GroupId) + // Apply egress rules that haven't been applied yet + toAuthorize := make([]*ec2.IpPermission, 0, len(egressPermissions)) + for _, permission := range egressPermissions { + permission := permission + if !includesPermission(sg.IpPermissionsEgress, permission) { + toAuthorize = append(toAuthorize, permission) + } + } + if len(toAuthorize) == 0 { + logger.Infoln("Egress rules already authorized") + return sg, nil + } + + err = wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + res, err := client.AuthorizeSecurityGroupEgressWithContext(ctx, &ec2.AuthorizeSecurityGroupEgressInput{ + GroupId: sg.GroupId, + IpPermissions: toAuthorize, + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && awsErr.Code() == errDuplicatePermission { + return true, nil + } + return false, nil + } + if len(res.SecurityGroupRules) < len(toAuthorize) { + return false, nil + } + return true, nil + }, + ) + if err != nil { + return nil, fmt.Errorf("failed to authorize egress rules for security group (%s): %w", name, err) + } + + return sg, nil +} + +func existingSecurityGroup(ctx context.Context, client ec2iface.EC2API, filters []*ec2.Filter) (*ec2.SecurityGroup, error) { + res, err := client.DescribeSecurityGroupsWithContext(ctx, &ec2.DescribeSecurityGroupsInput{ + Filters: filters, + }) + if err != nil { + return nil, fmt.Errorf("failed to list security groups: %w", err) + } + for _, sg := range res.SecurityGroups { + return sg, nil + } + + return nil, errNotFound +} + +func createSecurityGroup(ctx context.Context, client ec2iface.EC2API, name string, vpcID string, tags map[string]string) (*ec2.SecurityGroup, error) { + res, err := client.CreateSecurityGroupWithContext(ctx, &ec2.CreateSecurityGroupInput{ + GroupName: aws.String(name), + Description: aws.String(defaultDescription), + VpcId: aws.String(vpcID), + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("security-group"), + Tags: ec2Tags(tags), + }, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to create security group (%s): %w", name, err) + } + + // Wait for SG to show up + var out *ec2.DescribeSecurityGroupsOutput + err = wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + out, err = client.DescribeSecurityGroupsWithContext(ctx, &ec2.DescribeSecurityGroupsInput{GroupIds: []*string{res.GroupId}}) + if err != nil || len(out.SecurityGroups) == 0 { + return false, nil + } + return true, nil + }, + ) + if err != nil { + return nil, fmt.Errorf("failed to find security group (%s) that was just created: %w", name, err) + } + + return out.SecurityGroups[0], nil +} + +func defaultEgressRules(securityGroupID *string) []*ec2.IpPermission { + return []*ec2.IpPermission{ + createSGRule(securityGroupID, "-1", []string{"0.0.0.0/0"}, nil, 0, 0, false, nil), + } +} + +func defaultBootstrapSGIngressRules(securityGroupID *string, cidrBlocks []string) []*ec2.IpPermission { + return []*ec2.IpPermission{ + // bootstrap ssh + createSGRule(securityGroupID, "tcp", cidrBlocks, nil, 22, 22, false, nil), + // bootstrap journald gateway + createSGRule(securityGroupID, "tcp", cidrBlocks, nil, 19531, 19531, false, nil), + } +} + +func defaultMasterSGIngressRules(masterSGID *string, workerSGID *string, cidrBlocks []string) []*ec2.IpPermission { + return []*ec2.IpPermission{ + // master mcs + createSGRule(masterSGID, "tcp", cidrBlocks, nil, 22623, 22623, false, nil), + // master icmp + createSGRule(masterSGID, "icmp", cidrBlocks, nil, -1, -1, false, nil), + // master ssh + createSGRule(masterSGID, "tcp", cidrBlocks, nil, 22, 22, false, nil), + // master https + createSGRule(masterSGID, "tcp", cidrBlocks, nil, 6443, 6443, false, nil), + // master vxlan + createSGRule(masterSGID, "udp", nil, nil, 4789, 4789, true, nil), + // master geneve + createSGRule(masterSGID, "udp", nil, nil, 6081, 6081, true, nil), + // master ike + createSGRule(masterSGID, "udp", nil, nil, 500, 500, true, nil), + // master ike nat_t + createSGRule(masterSGID, "udp", nil, nil, 4500, 4500, true, nil), + // master esp + createSGRule(masterSGID, "50", nil, nil, 0, 0, true, nil), + // master ovndb + createSGRule(masterSGID, "tcp", nil, nil, 6641, 6642, true, nil), + // master internal + createSGRule(masterSGID, "tcp", nil, nil, 9000, 9999, true, nil), + // master internal udp + createSGRule(masterSGID, "udp", nil, nil, 9000, 9999, true, nil), + // master kube scheduler + createSGRule(masterSGID, "tcp", nil, nil, 10259, 10259, true, nil), + // master kube controller manager + createSGRule(masterSGID, "tcp", nil, nil, 10257, 10257, true, nil), + // master kubelet secure + createSGRule(masterSGID, "tcp", nil, nil, 10250, 10250, true, nil), + // master etcd + createSGRule(masterSGID, "tcp", nil, nil, 2379, 2380, true, nil), + // master services tcp + createSGRule(masterSGID, "tcp", nil, nil, 30000, 32767, true, nil), + // master services udp + createSGRule(masterSGID, "udp", nil, nil, 30000, 32767, true, nil), + // master vxlan from worker + createSGRule(masterSGID, "udp", nil, nil, 4789, 4789, false, workerSGID), + // master geneve from worker + createSGRule(masterSGID, "udp", nil, nil, 6081, 6081, false, workerSGID), + // master ike from worker + createSGRule(masterSGID, "udp", nil, nil, 500, 500, false, workerSGID), + // master ike nat_t from worker + createSGRule(masterSGID, "udp", nil, nil, 4500, 4500, false, workerSGID), + // master esp from worker + createSGRule(masterSGID, "50", nil, nil, 0, 0, false, workerSGID), + // master ovndb from worker + createSGRule(masterSGID, "tcp", nil, nil, 6641, 6642, false, workerSGID), + // master internal from worker + createSGRule(masterSGID, "tcp", nil, nil, 9000, 9999, false, workerSGID), + // master internal udp from worker + createSGRule(masterSGID, "udp", nil, nil, 9000, 9999, false, workerSGID), + // master kube scheduler from worker + createSGRule(masterSGID, "tcp", nil, nil, 10259, 10259, false, workerSGID), + // master kube controler manager from worker + createSGRule(masterSGID, "tcp", nil, nil, 10257, 10257, false, workerSGID), + // master kubelet secure from worker + createSGRule(masterSGID, "tcp", nil, nil, 10250, 10250, false, workerSGID), + // master services tcp from worker + createSGRule(masterSGID, "tcp", nil, nil, 30000, 32767, false, workerSGID), + // master services udp from worker + createSGRule(masterSGID, "udp", nil, nil, 30000, 32767, false, workerSGID), + } +} + +func defaultWorkerSGIngressRules(workerSGID *string, masterSGID *string, cidrBlocks []string) []*ec2.IpPermission { + return []*ec2.IpPermission{ + // worker icmp + createSGRule(workerSGID, "icmp", cidrBlocks, nil, -1, -1, false, nil), + // worker vxlan + createSGRule(workerSGID, "udp", nil, nil, 4789, 4789, true, nil), + // worker geneve + createSGRule(workerSGID, "udp", nil, nil, 6081, 6081, true, nil), + // worker ike + createSGRule(workerSGID, "udp", nil, nil, 500, 500, true, nil), + // worker ike nat_t + createSGRule(workerSGID, "udp", nil, nil, 4500, 4500, true, nil), + // worker esp + createSGRule(workerSGID, "50", nil, nil, 0, 0, true, nil), + // worker internal + createSGRule(workerSGID, "tcp", nil, nil, 9000, 9999, true, nil), + // worker internal udp + createSGRule(workerSGID, "udp", nil, nil, 9000, 9999, true, nil), + // worker kubelet insecure + createSGRule(workerSGID, "tcp", nil, nil, 10250, 10250, true, nil), + // worker services tcp + createSGRule(workerSGID, "tcp", nil, nil, 30000, 32767, true, nil), + // worker services udp + createSGRule(workerSGID, "udp", nil, nil, 30000, 32767, true, nil), + // worker vxlan from master + createSGRule(workerSGID, "udp", nil, nil, 4789, 4789, false, masterSGID), + // worker geneve from master + createSGRule(workerSGID, "udp", nil, nil, 6081, 6081, false, masterSGID), + // worker ike from master + createSGRule(workerSGID, "udp", nil, nil, 500, 500, false, masterSGID), + // worker ike nat_t from master + createSGRule(workerSGID, "udp", nil, nil, 4500, 4500, false, masterSGID), + // worker esp from master + createSGRule(workerSGID, "50", nil, nil, 0, 0, false, masterSGID), + // worker internal from master + createSGRule(workerSGID, "tcp", nil, nil, 9000, 9999, false, masterSGID), + // master internal udp from worker + createSGRule(workerSGID, "udp", nil, nil, 9000, 9999, false, masterSGID), + // worker kubelet insecure from master + createSGRule(workerSGID, "tcp", nil, nil, 10250, 10250, false, masterSGID), + // worker services tcp from master + createSGRule(workerSGID, "tcp", nil, nil, 30000, 32767, false, masterSGID), + // worker services udp from master + createSGRule(workerSGID, "udp", nil, nil, 30000, 32767, false, masterSGID), + } +} + +func createSGRule(sgID *string, protocol string, cidrV4Blocks, cidrV6Blocks []string, fromPort, toPort int64, self bool, sourceSGID *string) *ec2.IpPermission { + rule := &ec2.IpPermission{ + IpProtocol: aws.String(protocol), + } + if protocol != "-1" { + rule.FromPort = aws.Int64(fromPort) + rule.ToPort = aws.Int64(toPort) + } + + for _, v := range cidrV4Blocks { + v := v + rule.IpRanges = append(rule.IpRanges, &ec2.IpRange{CidrIp: aws.String(v)}) + } + for _, v := range cidrV6Blocks { + v := v + rule.Ipv6Ranges = append(rule.Ipv6Ranges, &ec2.Ipv6Range{CidrIpv6: aws.String(v)}) + } + + if self { + rule.UserIdGroupPairs = append(rule.UserIdGroupPairs, &ec2.UserIdGroupPair{ + GroupId: sgID, + }) + } + + if sourceSGID != nil && aws.StringValue(sourceSGID) != aws.StringValue(sgID) { + // [OnwerID/]SecurityGroupID + if parts := strings.Split(aws.StringValue(sourceSGID), "/"); len(parts) == 1 { + rule.UserIdGroupPairs = append(rule.UserIdGroupPairs, &ec2.UserIdGroupPair{ + GroupId: sourceSGID, + }) + } else { + rule.UserIdGroupPairs = append(rule.UserIdGroupPairs, &ec2.UserIdGroupPair{ + GroupId: aws.String(parts[0]), + UserId: aws.String(parts[1]), + }) + } + } + + for _, v := range rule.IpRanges { + v.Description = aws.String(defaultDescription) + } + for _, v := range rule.Ipv6Ranges { + v.Description = aws.String(defaultDescription) + } + for _, v := range rule.PrefixListIds { + v.Description = aws.String(defaultDescription) + } + for _, v := range rule.UserIdGroupPairs { + v.Description = aws.String(defaultDescription) + } + + return rule +} + +func authorizeIngressRules(ctx context.Context, client ec2iface.EC2API, securityGroup *ec2.SecurityGroup, permissions []*ec2.IpPermission) error { + toAuthorize := make([]*ec2.IpPermission, 0, len(permissions)) + for _, permission := range permissions { + permission := permission + if !includesPermission(securityGroup.IpPermissions, permission) { + toAuthorize = append(toAuthorize, permission) + } + } + if len(toAuthorize) == 0 { + return nil + } + + return wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (done bool, err error) { + res, err := client.AuthorizeSecurityGroupIngressWithContext(ctx, &ec2.AuthorizeSecurityGroupIngressInput{ + GroupId: securityGroup.GroupId, + IpPermissions: toAuthorize, + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && awsErr.Code() == errDuplicatePermission { + return true, nil + } + return false, nil + } + if len(res.SecurityGroupRules) < len(toAuthorize) { + return false, nil + } + return true, nil + }, + ) +} + +func includesPermission(list []*ec2.IpPermission, permission *ec2.IpPermission) bool { + for _, p := range list { + if samePermission(p, permission) { + return true + } + } + return false +} + +func samePermission(a, b *ec2.IpPermission) bool { + return a != nil && b != nil && a.String() == b.String() +} From 402ef1f51cfb36688736810ffdeb0beb3397778f Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Mon, 30 Oct 2023 22:31:53 +0100 Subject: [PATCH 10/33] infra/aws: add security group unit tests --- pkg/infrastructure/aws/provision_test.go | 560 +++++++++++++++++++++++ 1 file changed, 560 insertions(+) diff --git a/pkg/infrastructure/aws/provision_test.go b/pkg/infrastructure/aws/provision_test.go index 4c39e03170d..266aba139c9 100644 --- a/pkg/infrastructure/aws/provision_test.go +++ b/pkg/infrastructure/aws/provision_test.go @@ -56,6 +56,11 @@ type mockEC2Client struct { createVpcEndpoint func(*ec2.CreateVpcEndpointInput) (*ec2.CreateVpcEndpointOutput, error) describeVpcEndpoints func(*ec2.DescribeVpcEndpointsInput) (*ec2.DescribeVpcEndpointsOutput, error) + + describeSGs func(*ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) + createSG func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) + authorizeEgress func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) + authorizeIngress func(*ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) } func (m *mockEC2Client) DescribeVpcsWithContext(_ context.Context, in *ec2.DescribeVpcsInput, _ ...request.Option) (*ec2.DescribeVpcsOutput, error) { @@ -154,6 +159,22 @@ func (m *mockEC2Client) DescribeVpcEndpointsWithContext(_ context.Context, in *e return m.describeVpcEndpoints(in) } +func (m *mockEC2Client) DescribeSecurityGroupsWithContext(_ context.Context, in *ec2.DescribeSecurityGroupsInput, _ ...request.Option) (*ec2.DescribeSecurityGroupsOutput, error) { + return m.describeSGs(in) +} + +func (m *mockEC2Client) CreateSecurityGroupWithContext(_ context.Context, in *ec2.CreateSecurityGroupInput, _ ...request.Option) (*ec2.CreateSecurityGroupOutput, error) { + return m.createSG(in) +} + +func (m *mockEC2Client) AuthorizeSecurityGroupEgressWithContext(_ context.Context, in *ec2.AuthorizeSecurityGroupEgressInput, _ ...request.Option) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + return m.authorizeEgress(in) +} + +func (m *mockEC2Client) AuthorizeSecurityGroupIngressWithContext(_ context.Context, in *ec2.AuthorizeSecurityGroupIngressInput, _ ...request.Option) (*ec2.AuthorizeSecurityGroupIngressOutput, error) { + return m.authorizeIngress(in) +} + var errAwsSdk = errors.New("some AWS SDK error") func TestEnsureVPC(t *testing.T) { @@ -1936,6 +1957,545 @@ func TestEnsureS3VPCEndpoint(t *testing.T) { } } +func TestEnsureSecurityGroup(t *testing.T) { + emptySG := &ec2.SecurityGroup{ + GroupId: aws.String("sg-1"), + } + expectedSG := &ec2.SecurityGroup{ + GroupId: aws.String("sg-1"), + IpPermissionsEgress: []*ec2.IpPermission{ + { + IpProtocol: aws.String("-1"), + IpRanges: []*ec2.IpRange{ + {CidrIp: aws.String("0.0.0.0/0")}, + }, + }, + }, + } + + tests := []struct { + name string + mockSvc mockEC2Client + expectedOut *ec2.SecurityGroup + expectedErr string + }{ + { + name: "AWS SDK error listing security groups", + mockSvc: mockEC2Client{ + describeSGs: func(*ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + return nil, errAwsSdk + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + panic("should not be called") + }, + authorizeEgress: func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to list security groups: some AWS SDK error$`, + }, + { + name: "Failed to create security group", + mockSvc: mockEC2Client{ + describeSGs: func(*ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + return nil, errNotFound + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + return nil, errAwsSdk + }, + authorizeEgress: func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create security group \(node-sg\): some AWS SDK error$`, + }, + { + name: "Security group created but not found", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + return nil, errNotFound + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + return &ec2.CreateSecurityGroupOutput{ + GroupId: aws.String("sg-1"), + }, nil + }, + authorizeEgress: func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to find security group \(node-sg\) that was just created: .*$`, + }, + { + name: "Security group created but authorizing egress fails", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 0 { + return nil, errNotFound + } + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{emptySG}, + }, nil + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + return &ec2.CreateSecurityGroupOutput{ + GroupId: aws.String("sg-1"), + }, nil + }, + authorizeEgress: func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to authorize egress rules for security group \(node-sg\): .*$`, + }, + { + name: "Security group exists but authorizing egress fails", + mockSvc: mockEC2Client{ + describeSGs: func(*ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{emptySG}, + }, nil + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + panic("should not be called") + }, + authorizeEgress: func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to authorize egress rules for security group \(node-sg\): .*$`, + }, + { + name: "Security Group created and egress rules authorized", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 0 { + return nil, errNotFound + } + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{expectedSG}, + }, nil + }, + createSG: func(in *ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + if len(in.TagSpecifications) == 0 || len(in.TagSpecifications[0].Tags) == 0 { + panic("security group not tagged") + } + if aws.StringValue(in.TagSpecifications[0].ResourceType) != "security-group" { + panic("security group tagged with wrong resource type") + } + return &ec2.CreateSecurityGroupOutput{ + GroupId: aws.String("sg-1"), + }, nil + }, + authorizeEgress: func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + return &ec2.AuthorizeSecurityGroupEgressOutput{ + SecurityGroupRules: []*ec2.SecurityGroupRule{{}}, + }, nil + }, + }, + expectedOut: expectedSG, + }, + { + name: "Security Group already created and egress rules already authorized", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 0 { + return nil, errNotFound + } + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{expectedSG}, + }, nil + }, + createSG: func(in *ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + if len(in.TagSpecifications) == 0 || len(in.TagSpecifications[0].Tags) == 0 { + panic("security group not tagged") + } + if aws.StringValue(in.TagSpecifications[0].ResourceType) != "security-group" { + panic("security group tagged with wrong resource type") + } + return &ec2.CreateSecurityGroupOutput{ + GroupId: aws.String("sg-1"), + }, nil + }, + authorizeEgress: func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + return nil, awserr.New(errDuplicatePermission, "", errAwsSdk) + }, + }, + expectedOut: expectedSG, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + res, err := ensureSecurityGroup(context.TODO(), logger, &test.mockSvc, "infraID", "vpc-1", "node-sg", map[string]string{"custom-tag": "custom-value"}) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + +//nolint:gocyclo // we don't care about the cyclomatic complexity +func TestCreateSecurityGroups(t *testing.T) { + bootstrapSG := &ec2.SecurityGroup{ + GroupId: aws.String("sg-1"), + } + controlplaneSG := &ec2.SecurityGroup{ + GroupId: aws.String("sg-2"), + } + computeSG := &ec2.SecurityGroup{ + GroupId: aws.String("sg-3"), + } + cidrBlocks := []string{"10.0.0.0/16"} + defaultEgress := defaultEgressRules(aws.String("sg-1")) + bootstrapIngress := defaultBootstrapSGIngressRules(aws.String("sg-1"), cidrBlocks) + masterIngress := defaultMasterSGIngressRules(aws.String("sg-2"), aws.String("sg-3"), cidrBlocks) + workerIngress := defaultWorkerSGIngressRules(aws.String("sg-3"), aws.String("sg-2"), cidrBlocks) + + tests := []struct { + name string + mockSvc mockEC2Client + private bool + expectedOut *sgOutput + expectedErr string + }{ + { + name: "Creating bootstrap security group fails when listing security groups", + mockSvc: mockEC2Client{ + describeSGs: func(*ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + return nil, errAwsSdk + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create bootstrap security group: failed to list security groups: some AWS SDK error$`, + }, + { + name: "Creating bootstrap security group fails", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSecurityGroupsOutput{SecurityGroups: []*ec2.SecurityGroup{}}, nil + } + panic("should not be called") + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create bootstrap security group: failed to create security group \(infraID-bootstrap-sg\): some AWS SDK error$`, + }, + { + name: "Bootstrap security group created but authorizing ingress fails", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 0 { + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{bootstrapSG}, + }, nil + } + panic("should not be called") + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + panic("should not be called") + }, + authorizeEgress: func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + return &ec2.AuthorizeSecurityGroupEgressOutput{ + SecurityGroupRules: make([]*ec2.SecurityGroupRule, len(defaultEgress)), + }, nil + }, + authorizeIngress: func(*ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to attach ingress rules to bootstrap security group: .*$`, + }, + { + name: "Bootstrap security group created and authorizing ingress for public cluster uses all addresses but creating master security group fails", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 1 && aws.StringValue(in.Filters[1].Values[0]) == "infraID-bootstrap-sg" { + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{bootstrapSG}, + }, nil + } + return &ec2.DescribeSecurityGroupsOutput{}, nil + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + return nil, errAwsSdk + }, + authorizeEgress: func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + return &ec2.AuthorizeSecurityGroupEgressOutput{ + SecurityGroupRules: []*ec2.SecurityGroupRule{{}}, + }, nil + }, + authorizeIngress: func(in *ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) { + if aws.StringValue(in.IpPermissions[0].IpRanges[0].CidrIp) != "0.0.0.0/0" { + panic("should have used 0.0.0.0/0 for public clusters") + } + rules := make([]*ec2.SecurityGroupRule, len(bootstrapIngress)) + return &ec2.AuthorizeSecurityGroupIngressOutput{ + SecurityGroupRules: rules, + }, nil + }, + }, + expectedErr: `^failed to create control plane security group: failed to create security group \(infraID-master-sg\): some AWS SDK error$`, + }, + { + name: "Bootstrap security group created, master created but creating worker fails", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 1 { + switch aws.StringValue(in.Filters[1].Values[0]) { + case "infraID-bootstrap-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{bootstrapSG}, + }, nil + case "infraID-master-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{controlplaneSG}, + }, nil + default: + return &ec2.DescribeSecurityGroupsOutput{}, nil + } + } + return &ec2.DescribeSecurityGroupsOutput{}, nil + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + return nil, errAwsSdk + }, + authorizeEgress: func(in *ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + switch aws.StringValue(in.GroupId) { + case "sg-1", "sg-2": + return &ec2.AuthorizeSecurityGroupEgressOutput{ + SecurityGroupRules: make([]*ec2.SecurityGroupRule, len(defaultEgress)), + }, nil + } + panic("should not be called") + }, + authorizeIngress: func(in *ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) { + switch aws.StringValue(in.GroupId) { + case "sg-1": + return &ec2.AuthorizeSecurityGroupIngressOutput{ + SecurityGroupRules: make([]*ec2.SecurityGroupRule, len(bootstrapIngress)), + }, nil + default: + panic("should not be called") + } + }, + }, + expectedErr: `failed to create compute security group: failed to create security group \(infraID-worker-sg\): some AWS SDK error$`, + }, + { + name: "Bootstrap, master and worker security groups created but authorizing master ingress fails", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 1 { + switch aws.StringValue(in.Filters[1].Values[0]) { + case "infraID-bootstrap-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{bootstrapSG}, + }, nil + case "infraID-master-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{controlplaneSG}, + }, nil + case "infraID-worker-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{computeSG}, + }, nil + default: + panic("should not be called") + } + } + return &ec2.DescribeSecurityGroupsOutput{}, nil + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + return nil, errAwsSdk + }, + authorizeEgress: func(in *ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + switch aws.StringValue(in.GroupId) { + case "sg-1", "sg-2", "sg-3": + return &ec2.AuthorizeSecurityGroupEgressOutput{ + SecurityGroupRules: make([]*ec2.SecurityGroupRule, len(defaultEgress)), + }, nil + default: + panic("should not be called") + } + }, + authorizeIngress: func(in *ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) { + switch aws.StringValue(in.GroupId) { + case "sg-1": + rules := make([]*ec2.SecurityGroupRule, len(bootstrapIngress)) + return &ec2.AuthorizeSecurityGroupIngressOutput{ + SecurityGroupRules: rules, + }, nil + case "sg-2": + return nil, errAwsSdk + default: + panic("should not be called") + } + }, + }, + expectedErr: `failed to attach ingress rules to master security group: .*$`, + }, + { + name: "Bootstrap, master and worker security groups created but authorizing worker ingress fails", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 1 { + switch aws.StringValue(in.Filters[1].Values[0]) { + case "infraID-bootstrap-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{bootstrapSG}, + }, nil + case "infraID-master-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{controlplaneSG}, + }, nil + case "infraID-worker-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{computeSG}, + }, nil + default: + panic("should not be called") + } + } + return &ec2.DescribeSecurityGroupsOutput{}, nil + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + return nil, errAwsSdk + }, + authorizeEgress: func(in *ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + switch aws.StringValue(in.GroupId) { + case "sg-1", "sg-2", "sg-3": + return &ec2.AuthorizeSecurityGroupEgressOutput{ + SecurityGroupRules: make([]*ec2.SecurityGroupRule, len(defaultEgress)), + }, nil + default: + panic("should not be called") + } + }, + authorizeIngress: func(in *ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) { + switch aws.StringValue(in.GroupId) { + case "sg-1": + rules := make([]*ec2.SecurityGroupRule, len(bootstrapIngress)) + return &ec2.AuthorizeSecurityGroupIngressOutput{ + SecurityGroupRules: rules, + }, nil + case "sg-2": + rules := make([]*ec2.SecurityGroupRule, len(masterIngress)) + return &ec2.AuthorizeSecurityGroupIngressOutput{ + SecurityGroupRules: rules, + }, nil + case "sg-3": + return nil, errAwsSdk + default: + panic("should not be called") + } + }, + }, + expectedErr: `failed to attach ingress rules to worker security group: .*$`, + }, + { + name: "All security groups created and rules authorized", + mockSvc: mockEC2Client{ + describeSGs: func(in *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + if len(in.Filters) > 1 { + switch aws.StringValue(in.Filters[1].Values[0]) { + case "infraID-bootstrap-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{bootstrapSG}, + }, nil + case "infraID-master-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{controlplaneSG}, + }, nil + case "infraID-worker-sg": + return &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: []*ec2.SecurityGroup{computeSG}, + }, nil + default: + panic("should not be called") + } + } + return &ec2.DescribeSecurityGroupsOutput{}, nil + }, + createSG: func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + return nil, errAwsSdk + }, + authorizeEgress: func(in *ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + switch aws.StringValue(in.GroupId) { + case "sg-1", "sg-2", "sg-3": + return &ec2.AuthorizeSecurityGroupEgressOutput{ + SecurityGroupRules: make([]*ec2.SecurityGroupRule, len(defaultEgress)), + }, nil + default: + panic("should not be called") + } + }, + authorizeIngress: func(in *ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) { + switch aws.StringValue(in.GroupId) { + case "sg-1": + rules := make([]*ec2.SecurityGroupRule, len(bootstrapIngress)) + return &ec2.AuthorizeSecurityGroupIngressOutput{ + SecurityGroupRules: rules, + }, nil + case "sg-2": + rules := make([]*ec2.SecurityGroupRule, len(masterIngress)) + return &ec2.AuthorizeSecurityGroupIngressOutput{ + SecurityGroupRules: rules, + }, nil + case "sg-3": + rules := make([]*ec2.SecurityGroupRule, len(workerIngress)) + return &ec2.AuthorizeSecurityGroupIngressOutput{ + SecurityGroupRules: rules, + }, nil + default: + panic("should not be called") + } + }, + }, + expectedOut: &sgOutput{ + bootstrap: "sg-1", + controlPlane: "sg-2", + compute: "sg-3", + }, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + input := sgInputOptions{ + infraID: "infraID", + vpcID: "vpc-1", + cidrV4Blocks: []string{"10.0.0.0/16"}, + isPrivateCluster: test.private, + tags: map[string]string{"custom-tag": "custom-value"}, + } + res, err := createSecurityGroups(context.TODO(), logger, &test.mockSvc, &input) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + type mockELBClient struct { elbv2iface.ELBV2API From b5cdf6f1ad61d6da5d8b66a2f8e77a3725066cba Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Mon, 30 Oct 2023 22:33:26 +0100 Subject: [PATCH 11/33] infra/aws: add instance creation functions These functions will be used to create bootstrap and control plane instances and related resources. Partially implements CORS-2882, CORS-2884, CORS-2883, CORS-2879. Co-authored-by: Enxebre --- pkg/infrastructure/aws/instance.go | 383 +++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 pkg/infrastructure/aws/instance.go diff --git a/pkg/infrastructure/aws/instance.go b/pkg/infrastructure/aws/instance.go new file mode 100644 index 00000000000..e12f2bbda59 --- /dev/null +++ b/pkg/infrastructure/aws/instance.go @@ -0,0 +1,383 @@ +package aws + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/iam/iamiface" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/util/wait" +) + +var errInstanceNotCreated = errors.New("instance was not created") + +type instanceInputOptions struct { + infraID string + name string + amiID string + instanceType string + subnetID string + userData string + kmsKeyID string + iamRole string + instanceProfileARN string + volumeType string + metadataAuth string + volumeSize int64 + volumeIOPS int64 + isEncrypted bool + associatePublicIP bool + securityGroupIds []string + targetGroupARNs []string + tags map[string]string +} + +func ensureInstance(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, elbClient elbv2iface.ELBV2API, input *instanceInputOptions) (*ec2.Instance, error) { + l := logger.WithField("name", input.name) + filters := ec2Filters(input.infraID, input.name) + createdOrFoundMsg := "Found existing instance" + instance, err := existingInstance(ctx, ec2Client, filters) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, fmt.Errorf("failed to find instance: %w", err) + } + createdOrFoundMsg = "Created instance" + instance, err = createInstance(ctx, ec2Client, input) + if err != nil { + return nil, err + } + } + l.WithField("id", aws.StringValue(instance.InstanceId)).Infoln(createdOrFoundMsg) + + for _, targetGroup := range input.targetGroupARNs { + _, err = elbClient.RegisterTargetsWithContext(ctx, &elbv2.RegisterTargetsInput{ + TargetGroupArn: aws.String(targetGroup), + Targets: []*elbv2.TargetDescription{ + {Id: instance.PrivateIpAddress}, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to register target group (%s): %w", targetGroup, err) + } + } + l.Infoln("Target groups registered") + + return instance, nil +} + +func existingInstance(ctx context.Context, client ec2iface.EC2API, filters []*ec2.Filter) (*ec2.Instance, error) { + res, err := client.DescribeInstancesWithContext(ctx, &ec2.DescribeInstancesInput{Filters: filters}) + if err != nil { + return nil, err + } + if len(res.Reservations) > 0 && len(res.Reservations[0].Instances) > 0 { + return res.Reservations[0].Instances[0], nil + } + + return nil, errNotFound +} + +func createInstance(ctx context.Context, client ec2iface.EC2API, input *instanceInputOptions) (*ec2.Instance, error) { + kmsKeyID := input.kmsKeyID + if len(kmsKeyID) == 0 { + kmsKey, err := client.GetEbsDefaultKmsKeyIdWithContext(ctx, &ec2.GetEbsDefaultKmsKeyIdInput{}) + if err != nil { + return nil, fmt.Errorf("failed to get default KMS key: %w", err) + } + kmsKeyID = aws.StringValue(kmsKey.KmsKeyId) + } + + // The iops parameter is not support if the volume type is gp2 + var iops *int64 + if input.volumeIOPS > 0 && input.volumeType != ec2.VolumeTypeGp2 { + iops = aws.Int64(input.volumeIOPS) + } + + tags := mergeTags(input.tags, map[string]string{"Name": input.name}) + volTags := mergeTags(input.tags, map[string]string{"Name": fmt.Sprintf("%s-vol", input.name)}) + httpTokens := input.metadataAuth + if len(httpTokens) == 0 { + httpTokens = "optional" + } + res, err := client.RunInstancesWithContext(ctx, &ec2.RunInstancesInput{ + ImageId: aws.String(input.amiID), + InstanceType: aws.String(input.instanceType), + NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{ + { + DeviceIndex: aws.Int64(0), + SubnetId: aws.String(input.subnetID), + Groups: aws.StringSlice(input.securityGroupIds), + AssociatePublicIpAddress: aws.Bool(input.associatePublicIP), + }, + }, + MetadataOptions: &ec2.InstanceMetadataOptionsRequest{ + HttpEndpoint: aws.String("enabled"), + HttpTokens: aws.String(httpTokens), + }, + UserData: aws.String(base64.StdEncoding.EncodeToString([]byte(input.userData))), + // InvalidParameterCombination: Network interfaces and an instance-level security groups may not be specified on the same request + // SecurityGroupIds: aws.StringSlice(options.securityGroupIDs), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("instance"), + Tags: ec2Tags(tags), + }, + { + ResourceType: aws.String("volume"), + Tags: ec2Tags(volTags), + }, + }, + BlockDeviceMappings: []*ec2.BlockDeviceMapping{ + { + DeviceName: aws.String("/dev/xvda"), + Ebs: &ec2.EbsBlockDevice{ + VolumeType: aws.String(input.volumeType), + VolumeSize: aws.Int64(input.volumeSize), + Encrypted: aws.Bool(input.isEncrypted), + KmsKeyId: aws.String(kmsKeyID), + Iops: iops, + }, + }, + }, + IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ + Arn: aws.String(input.instanceProfileARN), + }, + }) + if err != nil { + return nil, err + } + if len(res.Instances) > 0 { + return res.Instances[0], nil + } + + return nil, errInstanceNotCreated +} + +type instanceProfileOptions struct { + namePrefix string + roleName string + assumeRolePolicy string + policyDocument string + tags map[string]string +} + +func createInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, input *instanceProfileOptions) (*iam.InstanceProfile, error) { + roleName := fmt.Sprintf("%s-role", input.namePrefix) + _, err := ensureRole(ctx, logger, client, roleName, input.assumeRolePolicy, input.tags) + if err != nil { + return nil, err + } + + profileName := fmt.Sprintf("%s-profile", input.namePrefix) + profile, err := ensureProfile(ctx, logger, client, profileName, input.tags) + if err != nil { + return nil, err + } + + hasRole := false + for _, role := range profile.Roles { + if aws.StringValue(role.RoleName) == roleName { + hasRole = true + break + } + } + if !hasRole { + _, err := client.AddRoleToInstanceProfileWithContext(ctx, &iam.AddRoleToInstanceProfileInput{ + InstanceProfileName: aws.String(profileName), + RoleName: aws.String(roleName), + }) + if err != nil { + return nil, fmt.Errorf("failed to add role (%s) to instance profile (%s): %w", roleName, profileName, err) + } + logger.WithFields(logrus.Fields{ + "role": roleName, + "profile": profileName, + }).Infoln("Added role to instance profile") + } else { + logger.WithFields(logrus.Fields{ + "role": roleName, + "profile": profileName, + }).Infoln("Role already added to instance profile") + } + + rolePolicyName := fmt.Sprintf("%s-policy", profileName) + err = existingRolePolicy(ctx, client, roleName, rolePolicyName) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, fmt.Errorf("failed to get profile policy: %w", err) + } + _, err = client.PutRolePolicyWithContext(ctx, &iam.PutRolePolicyInput{ + PolicyName: aws.String(rolePolicyName), + PolicyDocument: aws.String(input.policyDocument), + RoleName: aws.String(roleName), + }) + } + if err != nil { + return nil, fmt.Errorf("failed to create profile policy: %w", err) + } + + // We sleep here otherwise got an error when creating the ec2 instance + // referencing the profile. + time.Sleep(10 * time.Second) + + return profile, nil +} + +func ensureRole(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, assumeRolePolicy string, tags map[string]string) (*iam.Role, error) { + createdOrFoundMsg := "Found existing role" + role, err := existingRole(ctx, client, name) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, fmt.Errorf("failed to get existing role: %w", err) + } + createdOrFoundMsg = "Created role" + role, err = createRole(ctx, client, name, assumeRolePolicy, tags) + if err != nil { + return nil, fmt.Errorf("failed to create role (%s): %w", name, err) + } + } + logger.WithField("name", name).Infoln(createdOrFoundMsg) + + return role, nil +} + +func existingRole(ctx context.Context, client iamiface.IAMAPI, name string) (*iam.Role, error) { + res, err := client.GetRoleWithContext(ctx, &iam.GetRoleInput{ + RoleName: aws.String(name), + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && awsErr.Code() == iam.ErrCodeNoSuchEntityException { + return nil, errNotFound + } + return nil, err + } + return res.Role, nil +} + +func createRole(ctx context.Context, client iamiface.IAMAPI, name string, assumeRolePolicy string, tags map[string]string) (*iam.Role, error) { + rtags := mergeTags(tags, map[string]string{"Name": name}) + res, err := client.CreateRoleWithContext(ctx, &iam.CreateRoleInput{ + AssumeRolePolicyDocument: aws.String(assumeRolePolicy), + Path: aws.String("/"), + RoleName: aws.String(name), + Tags: iamTags(rtags), + }) + if err != nil { + return nil, err + } + return res.Role, nil +} + +func ensureProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, tags map[string]string) (*iam.InstanceProfile, error) { + createdOrFoundMsg := "Found existing instance profile" + profile, err := existingProfile(ctx, client, name) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, fmt.Errorf("failed to get instance profile: %w", err) + } + createdOrFoundMsg = "Created instance profile" + profile, err = createProfile(ctx, client, name, tags) + if err != nil { + return nil, fmt.Errorf("failed to create instance profile: %w", err) + } + } + logger.WithField("name", name).Infoln(createdOrFoundMsg) + + return profile, nil +} + +func existingProfile(ctx context.Context, client iamiface.IAMAPI, name string) (*iam.InstanceProfile, error) { + res, err := client.GetInstanceProfileWithContext(ctx, &iam.GetInstanceProfileInput{ + InstanceProfileName: aws.String(name), + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && awsErr.Code() == iam.ErrCodeNoSuchEntityException { + return nil, errNotFound + } + return nil, err + } + return res.InstanceProfile, nil +} + +func createProfile(ctx context.Context, client iamiface.IAMAPI, name string, tags map[string]string) (*iam.InstanceProfile, error) { + ptags := mergeTags(tags, map[string]string{"Name": name}) + res, err := client.CreateInstanceProfileWithContext(ctx, &iam.CreateInstanceProfileInput{ + InstanceProfileName: aws.String(name), + Path: aws.String("/"), + Tags: iamTags(ptags), + }) + if err != nil { + return nil, err + } + + waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + var lastError error + wait.UntilWithContext( + waitCtx, + func(ctx context.Context) { + _, err := existingProfile(ctx, client, name) + if err != nil { + lastError = err + } else { + lastError = nil + cancel() + } + }, + 2*time.Second, + ) + if err := waitCtx.Err(); err != nil { + // Canceled error means that we found the instance profile + if errors.Is(err, context.DeadlineExceeded) { + return nil, fmt.Errorf("timed out waiting for instance profile to exist: %w", lastError) + } + } + + return res.InstanceProfile, nil +} + +func existingRolePolicy(ctx context.Context, client iamiface.IAMAPI, roleName string, policyName string) error { + res, err := client.GetRolePolicyWithContext(ctx, &iam.GetRolePolicyInput{ + RoleName: aws.String(roleName), + PolicyName: aws.String(policyName), + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && awsErr.Code() == iam.ErrCodeNoSuchEntityException { + return errNotFound + } + return err + } + if aws.StringValue(res.PolicyName) != policyName { + return errNotFound + } + + return nil +} + +func iamTags(tags map[string]string) []*iam.Tag { + iamTags := make([]*iam.Tag, 0, len(tags)) + for k, v := range tags { + k, v := k, v + iamTags = append(iamTags, &iam.Tag{ + Key: aws.String(k), + Value: aws.String(v), + }) + } + return iamTags +} From cbd484d941a662f85cc95201b7dafe97e1a925d2 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Tue, 31 Oct 2023 17:16:00 +0100 Subject: [PATCH 12/33] infra/aws: add instance unit tests --- pkg/infrastructure/aws/provision_test.go | 229 +++++++++++++++++++++++ 1 file changed, 229 insertions(+) diff --git a/pkg/infrastructure/aws/provision_test.go b/pkg/infrastructure/aws/provision_test.go index 266aba139c9..1591454ecf5 100644 --- a/pkg/infrastructure/aws/provision_test.go +++ b/pkg/infrastructure/aws/provision_test.go @@ -61,6 +61,10 @@ type mockEC2Client struct { createSG func(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) authorizeEgress func(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) authorizeIngress func(*ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) + + describeInstances func(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) + runInstances func(*ec2.RunInstancesInput) (*ec2.Reservation, error) + getDefaultKmsKey func(*ec2.GetEbsDefaultKmsKeyIdInput) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) } func (m *mockEC2Client) DescribeVpcsWithContext(_ context.Context, in *ec2.DescribeVpcsInput, _ ...request.Option) (*ec2.DescribeVpcsOutput, error) { @@ -175,6 +179,18 @@ func (m *mockEC2Client) AuthorizeSecurityGroupIngressWithContext(_ context.Conte return m.authorizeIngress(in) } +func (m *mockEC2Client) DescribeInstancesWithContext(_ context.Context, in *ec2.DescribeInstancesInput, _ ...request.Option) (*ec2.DescribeInstancesOutput, error) { + return m.describeInstances(in) +} + +func (m *mockEC2Client) RunInstancesWithContext(_ context.Context, in *ec2.RunInstancesInput, _ ...request.Option) (*ec2.Reservation, error) { + return m.runInstances(in) +} + +func (m *mockEC2Client) GetEbsDefaultKmsKeyIdWithContext(_ context.Context, in *ec2.GetEbsDefaultKmsKeyIdInput, _ ...request.Option) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) { //nolint:revive,stylecheck //This is a mocked function so we cannot rename it + return m.getDefaultKmsKey(in) +} + var errAwsSdk = errors.New("some AWS SDK error") func TestEnsureVPC(t *testing.T) { @@ -2496,6 +2512,213 @@ func TestCreateSecurityGroups(t *testing.T) { } } +func TestEnsureInstance(t *testing.T) { + expectedInstance := &ec2.Instance{ + InstanceId: aws.String("instance-1"), + PrivateIpAddress: aws.String("ip-1"), + } + tests := []struct { + name string + mockEC2 mockEC2Client + mockELB mockELBClient + expectedOut *ec2.Instance + expectedErr string + }{ + { + name: "AWS SDK error listing instances", + mockEC2: mockEC2Client{ + describeInstances: func(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { + return nil, errAwsSdk + }, + runInstances: func(*ec2.RunInstancesInput) (*ec2.Reservation, error) { + panic("should not be called") + }, + }, + mockELB: mockELBClient{ + registerTargets: func(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to find instance: some AWS SDK error$`, + }, + { + name: "Creating instance fails getting default KMS key", + mockEC2: mockEC2Client{ + describeInstances: func(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { + return &ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{}, + }, nil + }, + getDefaultKmsKey: func(*ec2.GetEbsDefaultKmsKeyIdInput) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) { + return nil, errAwsSdk + }, + runInstances: func(*ec2.RunInstancesInput) (*ec2.Reservation, error) { + panic("should not be called") + }, + }, + mockELB: mockELBClient{ + registerTargets: func(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to get default KMS key: some AWS SDK error$`, + }, + { + name: "Creating instance fails", + mockEC2: mockEC2Client{ + describeInstances: func(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { + return &ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{}, + }, nil + }, + getDefaultKmsKey: func(*ec2.GetEbsDefaultKmsKeyIdInput) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) { + return &ec2.GetEbsDefaultKmsKeyIdOutput{ + KmsKeyId: aws.String("kms-1"), + }, nil + }, + runInstances: func(*ec2.RunInstancesInput) (*ec2.Reservation, error) { + return nil, errAwsSdk + }, + }, + mockELB: mockELBClient{ + registerTargets: func(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^some AWS SDK error$`, + }, + { + name: "Instance created but no reservations found", + mockEC2: mockEC2Client{ + describeInstances: func(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { + return &ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{}, + }, nil + }, + getDefaultKmsKey: func(*ec2.GetEbsDefaultKmsKeyIdInput) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) { + return &ec2.GetEbsDefaultKmsKeyIdOutput{ + KmsKeyId: aws.String("kms-1"), + }, nil + }, + runInstances: func(*ec2.RunInstancesInput) (*ec2.Reservation, error) { + return &ec2.Reservation{ + Instances: []*ec2.Instance{}, + }, nil + }, + }, + mockELB: mockELBClient{ + registerTargets: func(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^instance was not created$`, + }, + { + name: "Instance created but fails to register target groups", + mockEC2: mockEC2Client{ + describeInstances: func(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { + return &ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{}, + }, nil + }, + getDefaultKmsKey: func(*ec2.GetEbsDefaultKmsKeyIdInput) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) { + return &ec2.GetEbsDefaultKmsKeyIdOutput{ + KmsKeyId: aws.String("kms-1"), + }, nil + }, + runInstances: func(*ec2.RunInstancesInput) (*ec2.Reservation, error) { + return &ec2.Reservation{ + Instances: []*ec2.Instance{expectedInstance}, + }, nil + }, + }, + mockELB: mockELBClient{ + registerTargets: func(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to register target group \(tg-1\): some AWS SDK error$`, + }, + { + name: "Instance created and target groups registered", + mockEC2: mockEC2Client{ + describeInstances: func(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { + return &ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{}, + }, nil + }, + getDefaultKmsKey: func(*ec2.GetEbsDefaultKmsKeyIdInput) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) { + return &ec2.GetEbsDefaultKmsKeyIdOutput{ + KmsKeyId: aws.String("kms-1"), + }, nil + }, + runInstances: func(*ec2.RunInstancesInput) (*ec2.Reservation, error) { + return &ec2.Reservation{ + Instances: []*ec2.Instance{expectedInstance}, + }, nil + }, + }, + mockELB: mockELBClient{ + registerTargets: func(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) { + return &elbv2.RegisterTargetsOutput{}, nil + }, + }, + expectedOut: expectedInstance, + }, + { + name: "Instance found and target groups registered", + mockEC2: mockEC2Client{ + describeInstances: func(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { + return &ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{ + {Instances: []*ec2.Instance{expectedInstance}}, + }, + }, nil + }, + getDefaultKmsKey: func(*ec2.GetEbsDefaultKmsKeyIdInput) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) { + return &ec2.GetEbsDefaultKmsKeyIdOutput{ + KmsKeyId: aws.String("kms-1"), + }, nil + }, + runInstances: func(*ec2.RunInstancesInput) (*ec2.Reservation, error) { + panic("should not be called") + }, + }, + mockELB: mockELBClient{ + registerTargets: func(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) { + return &elbv2.RegisterTargetsOutput{}, nil + }, + }, + expectedOut: expectedInstance, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + input := instanceInputOptions{ + infraID: "infraID", + amiID: "ami-1", + name: "instance-1", + instanceType: "type-1", + subnetID: "subnet-1", + targetGroupARNs: []string{"tg-1"}, + tags: map[string]string{"custom-tag": "custom-value"}, + } + res, err := ensureInstance(context.TODO(), logger, &test.mockEC2, &test.mockELB, &input) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + type mockELBClient struct { elbv2iface.ELBV2API @@ -2508,6 +2731,8 @@ type mockELBClient struct { createLoadBalancer func(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) describeLoadBalancers func(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) modifyLBAttr func(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) + + registerTargets func(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) } func (m *mockELBClient) CreateListenerWithContext(_ context.Context, in *elbv2.CreateListenerInput, _ ...request.Option) (*elbv2.CreateListenerOutput, error) { @@ -2534,6 +2759,10 @@ func (m *mockELBClient) ModifyLoadBalancerAttributesWithContext(_ context.Contex return m.modifyLBAttr(in) } +func (m *mockELBClient) RegisterTargetsWithContext(_ context.Context, in *elbv2.RegisterTargetsInput, _ ...request.Option) (*elbv2.RegisterTargetsOutput, error) { + return m.registerTargets(in) +} + func TestEnsureTargetGroup(t *testing.T) { expectedTargetGroup := &elbv2.TargetGroup{} From 3b5a937dc55aeaa8b82cd29f7567ab89d90cea82 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Sun, 5 Nov 2023 22:27:31 +0100 Subject: [PATCH 13/33] infra/aws: add instance profile unit tests --- pkg/infrastructure/aws/provision_test.go | 320 +++++++++++++++++++++++ 1 file changed, 320 insertions(+) diff --git a/pkg/infrastructure/aws/provision_test.go b/pkg/infrastructure/aws/provision_test.go index 1591454ecf5..b1713edd252 100644 --- a/pkg/infrastructure/aws/provision_test.go +++ b/pkg/infrastructure/aws/provision_test.go @@ -14,6 +14,8 @@ import ( "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/aws/aws-sdk-go/service/elbv2" "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/iam/iamiface" "github.com/aws/aws-sdk-go/service/route53" "github.com/aws/aws-sdk-go/service/route53/route53iface" "github.com/sirupsen/logrus" @@ -2719,6 +2721,324 @@ func TestEnsureInstance(t *testing.T) { } } +type mockIAMClient struct { + iamiface.IAMAPI + + // swappable functions + getRole func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) + createRole func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) + getProfile func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) + createProfile func(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) + addRoleToProfile func(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) + getRolePolicy func(*iam.GetRolePolicyInput) (*iam.GetRolePolicyOutput, error) + putRolePolicy func(*iam.PutRolePolicyInput) (*iam.PutRolePolicyOutput, error) +} + +func (m *mockIAMClient) GetRoleWithContext(_ context.Context, in *iam.GetRoleInput, _ ...request.Option) (*iam.GetRoleOutput, error) { + return m.getRole(in) +} + +func (m *mockIAMClient) CreateRoleWithContext(_ context.Context, in *iam.CreateRoleInput, _ ...request.Option) (*iam.CreateRoleOutput, error) { + return m.createRole(in) +} + +func (m *mockIAMClient) GetInstanceProfileWithContext(_ context.Context, in *iam.GetInstanceProfileInput, _ ...request.Option) (*iam.GetInstanceProfileOutput, error) { + return m.getProfile(in) +} + +func (m *mockIAMClient) CreateInstanceProfileWithContext(_ context.Context, in *iam.CreateInstanceProfileInput, _ ...request.Option) (*iam.CreateInstanceProfileOutput, error) { + return m.createProfile(in) +} + +func (m *mockIAMClient) AddRoleToInstanceProfileWithContext(_ context.Context, in *iam.AddRoleToInstanceProfileInput, _ ...request.Option) (*iam.AddRoleToInstanceProfileOutput, error) { + return m.addRoleToProfile(in) +} + +func (m *mockIAMClient) GetRolePolicyWithContext(_ context.Context, in *iam.GetRolePolicyInput, _ ...request.Option) (*iam.GetRolePolicyOutput, error) { + return m.getRolePolicy(in) +} + +func (m *mockIAMClient) PutRolePolicyWithContext(_ context.Context, in *iam.PutRolePolicyInput, _ ...request.Option) (*iam.PutRolePolicyOutput, error) { + return m.putRolePolicy(in) +} + +func TestEnsureInstanceProfile(t *testing.T) { + expectedRole := &iam.Role{RoleName: aws.String("name-role")} + expectedProfile := &iam.InstanceProfile{ + InstanceProfileName: aws.String("name-profile"), + Roles: []*iam.Role{expectedRole}, + } + tests := []struct { + name string + mockIAM mockIAMClient + expectedOut *iam.InstanceProfile + expectedErr string + }{ + { + name: "AWS SDK error when retrieving role", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + return nil, errAwsSdk + }, + createRole: func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + panic("should not be called") + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + panic("should not be called") + }, + createProfile: func(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) { + panic("should not be called") + }, + addRoleToProfile: func(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) { + panic("should not be called") + }, + getRolePolicy: func(*iam.GetRolePolicyInput) (*iam.GetRolePolicyOutput, error) { + panic("should not be called") + }, + putRolePolicy: func(*iam.PutRolePolicyInput) (*iam.PutRolePolicyOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to get existing role: some AWS SDK error$`, + }, + { + name: "Creating role fails", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + return nil, awserr.New(iam.ErrCodeNoSuchEntityException, "", errAwsSdk) + }, + createRole: func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + return nil, errAwsSdk + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + panic("should not be called") + }, + createProfile: func(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) { + panic("should not be called") + }, + addRoleToProfile: func(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) { + panic("should not be called") + }, + getRolePolicy: func(*iam.GetRolePolicyInput) (*iam.GetRolePolicyOutput, error) { + panic("should not be called") + }, + putRolePolicy: func(*iam.PutRolePolicyInput) (*iam.PutRolePolicyOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create role \(name-role\): some AWS SDK error$`, + }, + { + name: "Role created but AWS SDK error when retrieving profile", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + return nil, awserr.New(iam.ErrCodeNoSuchEntityException, "", errAwsSdk) + }, + createRole: func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + return &iam.CreateRoleOutput{ + Role: expectedRole, + }, nil + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to get instance profile: some AWS SDK error$`, + }, + { + name: "Role created but creating profile fails", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + return nil, awserr.New(iam.ErrCodeNoSuchEntityException, "", errAwsSdk) + }, + createRole: func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + return &iam.CreateRoleOutput{ + Role: expectedRole, + }, nil + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + return nil, awserr.New(iam.ErrCodeNoSuchEntityException, "", errAwsSdk) + }, + createProfile: func(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create instance profile: some AWS SDK error$`, + }, + { + name: "Role created and profile created but times out waiting for profile to exist", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + return nil, awserr.New(iam.ErrCodeNoSuchEntityException, "", errAwsSdk) + }, + createRole: func(in *iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + if len(in.Tags) == 0 { + panic("role not tagged") + } + return &iam.CreateRoleOutput{ + Role: expectedRole, + }, nil + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + return nil, awserr.New(iam.ErrCodeNoSuchEntityException, "", errAwsSdk) + }, + createProfile: func(in *iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) { + if len(in.Tags) == 0 { + panic("profile not tagged") + } + return &iam.CreateInstanceProfileOutput{ + InstanceProfile: &iam.InstanceProfile{}, + }, nil + }, + addRoleToProfile: func(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to create instance profile: timed out waiting for instance profile to exist: .*$`, + }, + { + name: "Role created, profile created but adding role to profile fails", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + return &iam.GetRoleOutput{ + Role: expectedRole, + }, nil + }, + createRole: func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + panic("should not be called") + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + return &iam.GetInstanceProfileOutput{ + InstanceProfile: &iam.InstanceProfile{}, + }, nil + }, + createProfile: func(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) { + panic("should not be called") + }, + addRoleToProfile: func(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to add role \(name-role\) to instance profile \(name-profile\): some AWS SDK error$`, + }, + { + name: "Role created, profile created, role added to profile but getting policy fails", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + return &iam.GetRoleOutput{ + Role: expectedRole, + }, nil + }, + createRole: func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + panic("should not be called") + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + return &iam.GetInstanceProfileOutput{ + InstanceProfile: &iam.InstanceProfile{}, + }, nil + }, + createProfile: func(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) { + panic("should not be called") + }, + addRoleToProfile: func(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) { + return &iam.AddRoleToInstanceProfileOutput{}, nil + }, + getRolePolicy: func(*iam.GetRolePolicyInput) (*iam.GetRolePolicyOutput, error) { + return nil, errAwsSdk + }, + putRolePolicy: func(*iam.PutRolePolicyInput) (*iam.PutRolePolicyOutput, error) { + panic("should not be called") + }, + }, + expectedErr: `^failed to get role policy: some AWS SDK error$`, + }, + { + name: "Role created, profile created, role added to profile but adding policy fails", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + return &iam.GetRoleOutput{ + Role: expectedRole, + }, nil + }, + createRole: func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + panic("should not be called") + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + return &iam.GetInstanceProfileOutput{ + InstanceProfile: &iam.InstanceProfile{}, + }, nil + }, + createProfile: func(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) { + panic("should not be called") + }, + addRoleToProfile: func(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) { + return &iam.AddRoleToInstanceProfileOutput{}, nil + }, + getRolePolicy: func(*iam.GetRolePolicyInput) (*iam.GetRolePolicyOutput, error) { + return nil, awserr.New(iam.ErrCodeNoSuchEntityException, "", errAwsSdk) + }, + putRolePolicy: func(*iam.PutRolePolicyInput) (*iam.PutRolePolicyOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to create role policy: some AWS SDK error$`, + }, + { + name: "Role created, profile created, role added to profile and policy created", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + return &iam.GetRoleOutput{ + Role: expectedRole, + }, nil + }, + createRole: func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + panic("should not be called") + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + return &iam.GetInstanceProfileOutput{ + InstanceProfile: expectedProfile, + }, nil + }, + createProfile: func(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) { + panic("should not be called") + }, + addRoleToProfile: func(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) { + panic("should not be called") + }, + getRolePolicy: func(*iam.GetRolePolicyInput) (*iam.GetRolePolicyOutput, error) { + return nil, awserr.New(iam.ErrCodeNoSuchEntityException, "", errAwsSdk) + }, + putRolePolicy: func(*iam.PutRolePolicyInput) (*iam.PutRolePolicyOutput, error) { + return &iam.PutRolePolicyOutput{}, nil + }, + }, + expectedOut: expectedProfile, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + input := instanceProfileOptions{ + namePrefix: "name", + assumeRolePolicy: "policy-role", + policyDocument: "policy", + tags: map[string]string{"custom-tag": "custom-value"}, + } + res, err := createInstanceProfile(context.TODO(), logger, &test.mockIAM, &input) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + type mockELBClient struct { elbv2iface.ELBV2API From 5f02bdab4801efa924e47af4c2fa2082eabf49ee Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Mon, 30 Oct 2023 22:33:48 +0100 Subject: [PATCH 14/33] infra/aws: create bootstrap resources Co-authored-by: Enxebre --- pkg/infrastructure/aws/aws.go | 38 +++++- pkg/infrastructure/aws/bootstrap.go | 205 ++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 pkg/infrastructure/aws/bootstrap.go diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 5ccf192ea07..4f166e87448 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -8,7 +8,9 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/route53" + "github.com/aws/aws-sdk-go/service/s3" "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/sets" @@ -151,11 +153,45 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, isPrivateCluster: clusterAWSConfig.PublishStrategy != "External", tags: tags, } - _, err = createSecurityGroups(ctx, logger, ec2Client, &sgInput) + sgOutput, err := createSecurityGroups(ctx, logger, ec2Client, &sgInput) if err != nil { return nil, fmt.Errorf("failed to create security groups: %w", err) } + logger.Infoln("Creating bootstrap resources") + bootstrapSubnet := vpcOutput.privateSubnetIDs[0] + if clusterAWSConfig.PublishStrategy == "External" { + bootstrapSubnet = vpcOutput.publicSubnetIDs[0] + } + bootstrapInput := bootstrapInputOptions{ + instanceInputOptions: instanceInputOptions{ + infraID: clusterConfig.ClusterID, + amiID: clusterAWSConfig.AMI, + instanceType: clusterAWSConfig.MasterInstanceType, + iamRole: clusterAWSConfig.MasterIAMRoleName, + volumeType: "gp2", + volumeSize: 30, + volumeIOPS: 0, + isEncrypted: true, + metadataAuth: clusterAWSConfig.BootstrapMetadataAuthentication, + kmsKeyID: clusterAWSConfig.KMSKeyID, + securityGroupIds: []string{sgOutput.bootstrap, sgOutput.controlPlane}, + targetGroupARNs: lbOutput.targetGroupArns, + subnetID: bootstrapSubnet, + associatePublicIP: clusterAWSConfig.PublishStrategy == "External", + userData: clusterAWSConfig.BootstrapIgnitionStub, + tags: tags, + }, + ignitionBucket: clusterAWSConfig.IgnitionBucket, + ignitionContent: clusterConfig.IgnitionBootstrap, + } + iamClient := iam.New(awsSession) + s3Client := s3.New(awsSession) + err = createBootstrapResources(ctx, logger, ec2Client, iamClient, s3Client, elbClient, &bootstrapInput) + if err != nil { + return nil, fmt.Errorf("failed to create bootstrap resources: %w", err) + } + return nil, fmt.Errorf("provision stage not implemented yet") } diff --git a/pkg/infrastructure/aws/bootstrap.go b/pkg/infrastructure/aws/bootstrap.go new file mode 100644 index 00000000000..14f1e419509 --- /dev/null +++ b/pkg/infrastructure/aws/bootstrap.go @@ -0,0 +1,205 @@ +package aws + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/iam/iamiface" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go/service/s3/s3iface" + "github.com/sirupsen/logrus" +) + +type bootstrapInputOptions struct { + instanceInputOptions + ignitionBucket string + ignitionContent string +} + +func createBootstrapResources(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, iamClient iamiface.IAMAPI, s3Client s3iface.S3API, elbClient elbv2iface.ELBV2API, input *bootstrapInputOptions) error { + err := ensureIgnition(ctx, logger, s3Client, input.infraID, input.ignitionBucket, input.ignitionContent, input.tags) + if err != nil { + return fmt.Errorf("failed to create ignition resources: %w", err) + } + + profileName := fmt.Sprintf("%s-bootstrap", input.infraID) + instanceProfile, err := createBootstrapInstanceProfile(ctx, logger, iamClient, profileName, input.tags) + if err != nil { + return fmt.Errorf("failed to create bootstrap instance profile: %w", err) + } + input.instanceProfileARN = aws.StringValue(instanceProfile.Arn) + + input.name = fmt.Sprintf("%s-bootstrap", input.infraID) + _, err = ensureInstance(ctx, logger, ec2Client, elbClient, &input.instanceInputOptions) + if err != nil { + return fmt.Errorf("failed to create bootstrap instace: %w", err) + } + + return nil +} + +func ensureIgnition(ctx context.Context, logger logrus.FieldLogger, client s3iface.S3API, infraID string, bucket string, content string, tags map[string]string) error { + err := ensureIgnitionBucket(ctx, logger, client, bucket, tags) + if err != nil { + return err + } + + const ignitionKey = "bootstrap.ign" + // Upload the bootstrap.ign file to the S3 bucket + _, err = client.PutObjectWithContext(ctx, &s3.PutObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(ignitionKey), + Body: strings.NewReader(content), + ServerSideEncryption: aws.String(s3.ServerSideEncryptionAes256), + }) + if err != nil { + return fmt.Errorf("failed to upload %s to bucket: %w", ignitionKey, err) + } + logger.Infoln("Uploaded bootstrap.ign to S3 bucket") + + // S3 Object tagging supports only up to 10 tags + // https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html + objTags := limitTags(tags, 8) + objTags = mergeTags(objTags, map[string]string{ + clusterOwnedTag(infraID): ownedTagValue, + "Name": bucket, + }) + _, err = client.PutObjectTaggingWithContext(ctx, &s3.PutObjectTaggingInput{ + Bucket: aws.String(bucket), + Key: aws.String(ignitionKey), + Tagging: &s3.Tagging{ + TagSet: s3Tags(objTags), + }, + }) + if err != nil { + return fmt.Errorf("failed to tag ignition object: %w", err) + } + logger.Infoln("Tagged bootstrap.ign object") + + return nil +} + +func ensureIgnitionBucket(ctx context.Context, logger logrus.FieldLogger, client s3iface.S3API, name string, tags map[string]string) error { + l := logger.WithField("name", name) + createdOrFoundMsg := "Found existing ignition bucket" + err := existingBucket(ctx, client, name) + if err != nil { + if !errors.Is(err, errNotFound) { + return err + } + createdOrFoundMsg = "Created ignition bucket" + _, err = client.CreateBucketWithContext(ctx, &s3.CreateBucketInput{ + Bucket: aws.String(name), + }) + if err != nil { + return fmt.Errorf("failed to create ignition bucket: %w", err) + } + } + l.Infoln(createdOrFoundMsg) + + btags := mergeTags(tags, map[string]string{"Name": name}) + _, err = client.PutBucketTaggingWithContext(ctx, &s3.PutBucketTaggingInput{ + Bucket: aws.String(name), + Tagging: &s3.Tagging{ + TagSet: s3Tags(btags), + }, + }) + if err != nil { + return fmt.Errorf("failed to tag ignition bucket: %w", err) + } + l.Infoln("Tagged ignition bucket") + + return nil +} + +func existingBucket(ctx context.Context, client s3iface.S3API, name string) error { + _, err := client.HeadBucketWithContext(ctx, &s3.HeadBucketInput{ + Bucket: aws.String(name), + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && (awsErr.Code() == s3.ErrCodeNoSuchBucket || strings.EqualFold(awsErr.Code(), "NotFound")) { + return errNotFound + } + return err + } + return nil +} + +func s3Tags(tags map[string]string) []*s3.Tag { + stags := make([]*s3.Tag, 0, len(tags)) + for k, v := range tags { + k, v := k, v + stags = append(stags, &s3.Tag{ + Key: aws.String(k), + Value: aws.String(v), + }) + } + return stags +} + +func limitTags(tags map[string]string, size int) map[string]string { + curSize := 0 + resized := make(map[string]string, size) + for k, v := range tags { + if curSize > size { + break + } + resized[k] = v + curSize++ + } + return resized +} + +func createBootstrapInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, tags map[string]string) (*iam.InstanceProfile, error) { + const ( + assumeRolePolicy = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Principal": { + "Service": "ec2.amazonaws.com" + }, + "Effect": "Allow", + "Sid": "" + } + ] +}` + bootstrapPolicy = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "ec2:Describe*", + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": "ec2:AttachVolume", + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": "ec2:DetachVolume", + "Resource": "*" + } + ] +}` + ) + + profileInput := &instanceProfileOptions{ + namePrefix: name, + assumeRolePolicy: assumeRolePolicy, + policyDocument: bootstrapPolicy, + tags: tags, + } + return createInstanceProfile(ctx, logger, client, profileInput) +} From b0b6d5a609dc7f215845ede80492ec95b177460a Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Tue, 31 Oct 2023 17:17:06 +0100 Subject: [PATCH 15/33] infra/aws: create control plane resources Implements CORS-2882, CORS-2884, CORS-2883, CORS-2879, CORS-2885 Co-authored-by: Enxebre --- pkg/infrastructure/aws/aws.go | 29 ++++++ pkg/infrastructure/aws/controlplane.go | 121 +++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 pkg/infrastructure/aws/controlplane.go diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 4f166e87448..675dac2d98d 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -192,6 +192,35 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, return nil, fmt.Errorf("failed to create bootstrap resources: %w", err) } + logger.Infoln("Creating control plane resources") + controlPlaneInput := controlPlaneInputOptions{ + instanceInputOptions: instanceInputOptions{ + infraID: clusterConfig.ClusterID, + amiID: clusterAWSConfig.AMI, + instanceType: clusterAWSConfig.MasterInstanceType, + iamRole: clusterAWSConfig.MasterIAMRoleName, + volumeType: clusterAWSConfig.Type, + volumeSize: clusterAWSConfig.Size, + volumeIOPS: clusterAWSConfig.IOPS, + isEncrypted: clusterAWSConfig.Encrypted, + kmsKeyID: clusterAWSConfig.KMSKeyID, + metadataAuth: clusterAWSConfig.MasterMetadataAuthentication, + securityGroupIds: append(clusterAWSConfig.MasterSecurityGroups, sgOutput.controlPlane), + targetGroupARNs: lbOutput.targetGroupArns, + associatePublicIP: false, + userData: clusterConfig.IgnitionMaster, + tags: tags, + }, + nReplicas: clusterConfig.Masters, + privateSubnetIDs: vpcOutput.privateSubnetIDs, + zoneToSubnetMap: vpcOutput.zoneToSubnetMap, + availabilityZones: clusterAWSConfig.MasterAvailabilityZones, + } + err = createControlPlaneResources(ctx, logger, ec2Client, iamClient, elbClient, &controlPlaneInput) + if err != nil { + return nil, fmt.Errorf("failed to create control plane resources: %w", err) + } + return nil, fmt.Errorf("provision stage not implemented yet") } diff --git a/pkg/infrastructure/aws/controlplane.go b/pkg/infrastructure/aws/controlplane.go new file mode 100644 index 00000000000..d3e2a073005 --- /dev/null +++ b/pkg/infrastructure/aws/controlplane.go @@ -0,0 +1,121 @@ +package aws + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/iam/iamiface" + "github.com/sirupsen/logrus" +) + +type controlPlaneInputOptions struct { + instanceInputOptions + nReplicas int + privateSubnetIDs []string + zoneToSubnetMap map[string]string + availabilityZones []string +} + +func createControlPlaneResources(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, iamClient iamiface.IAMAPI, elbClient elbv2iface.ELBV2API, input *controlPlaneInputOptions) error { + profileName := fmt.Sprintf("%s-master", input.infraID) + instanceProfile, err := createControlPlaneInstanceProfile(ctx, logger, iamClient, profileName, input.tags) + if err != nil { + return fmt.Errorf("failed to create control plane instance profile: %w", err) + } + + for i := 0; i < input.nReplicas; i++ { + options := input.instanceInputOptions + options.name = fmt.Sprintf("%s-master-%d", input.infraID, i) + // Choose appropriate subnet according to zone + zoneIdx := i % len(input.availabilityZones) + options.subnetID = input.zoneToSubnetMap[input.availabilityZones[zoneIdx]] + options.instanceProfileARN = aws.StringValue(instanceProfile.Arn) + + _, err := ensureInstance(ctx, logger, ec2Client, elbClient, &options) + if err != nil { + return fmt.Errorf("failed to create control plane (%s): %w", options.name, err) + } + } + logger.Infoln("Created control plane instances") + + return nil +} + +func createControlPlaneInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, tags map[string]string) (*iam.InstanceProfile, error) { + const ( + assumeRolePolicy = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Principal": { + "Service": "ec2.amazonaws.com" + }, + "Effect": "Allow", + "Sid": "" + } + ] +}` + policy = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "ec2:AttachVolume", + "ec2:AuthorizeSecurityGroupIngress", + "ec2:CreateSecurityGroup", + "ec2:CreateTags", + "ec2:CreateVolume", + "ec2:DeleteSecurityGroup", + "ec2:DeleteVolume", + "ec2:Describe*", + "ec2:DetachVolume", + "ec2:ModifyInstanceAttribute", + "ec2:ModifyVolume", + "ec2:RevokeSecurityGroupIngress", + "elasticloadbalancing:AddTags", + "elasticloadbalancing:AttachLoadBalancerToSubnets", + "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer", + "elasticloadbalancing:CreateListener", + "elasticloadbalancing:CreateLoadBalancer", + "elasticloadbalancing:CreateLoadBalancerPolicy", + "elasticloadbalancing:CreateLoadBalancerListeners", + "elasticloadbalancing:CreateTargetGroup", + "elasticloadbalancing:ConfigureHealthCheck", + "elasticloadbalancing:DeleteListener", + "elasticloadbalancing:DeleteLoadBalancer", + "elasticloadbalancing:DeleteLoadBalancerListeners", + "elasticloadbalancing:DeleteTargetGroup", + "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", + "elasticloadbalancing:DeregisterTargets", + "elasticloadbalancing:Describe*", + "elasticloadbalancing:DetachLoadBalancerFromSubnets", + "elasticloadbalancing:ModifyListener", + "elasticloadbalancing:ModifyLoadBalancerAttributes", + "elasticloadbalancing:ModifyTargetGroup", + "elasticloadbalancing:ModifyTargetGroupAttributes", + "elasticloadbalancing:RegisterInstancesWithLoadBalancer", + "elasticloadbalancing:RegisterTargets", + "elasticloadbalancing:SetLoadBalancerPoliciesForBackendServer", + "elasticloadbalancing:SetLoadBalancerPoliciesOfListener", + "kms:DescribeKey" + ], + "Resource": "*", + "Effect": "Allow" + } + ] +}` + ) + + profileInput := &instanceProfileOptions{ + namePrefix: name, + assumeRolePolicy: assumeRolePolicy, + policyDocument: policy, + tags: tags, + } + return createInstanceProfile(ctx, logger, client, profileInput) +} From d3f15ef0191785fdd193db8c3013edb85505e6e8 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Tue, 31 Oct 2023 17:31:52 +0100 Subject: [PATCH 16/33] infra/aws: create compute resources --- pkg/infrastructure/aws/aws.go | 12 +++++- pkg/infrastructure/aws/compute.go | 64 +++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 pkg/infrastructure/aws/compute.go diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 675dac2d98d..9861e261653 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -221,7 +221,17 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, return nil, fmt.Errorf("failed to create control plane resources: %w", err) } - return nil, fmt.Errorf("provision stage not implemented yet") + logger.Infoln("Creating compute resources") + computeInput := computeInputOptions{ + infraID: clusterConfig.ClusterID, + tags: tags, + } + err = createComputeResources(ctx, logger, iamClient, &computeInput) + if err != nil { + return nil, fmt.Errorf("failed to create compute resources: %w", err) + } + + return nil, nil } // DestroyBootstrap destroys the temporary bootstrap resources. diff --git a/pkg/infrastructure/aws/compute.go b/pkg/infrastructure/aws/compute.go new file mode 100644 index 00000000000..98f3bc0e10f --- /dev/null +++ b/pkg/infrastructure/aws/compute.go @@ -0,0 +1,64 @@ +package aws + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/iam/iamiface" + "github.com/sirupsen/logrus" +) + +type computeInputOptions struct { + infraID string + tags map[string]string +} + +func createComputeResources(ctx context.Context, logger logrus.FieldLogger, iamClient iamiface.IAMAPI, input *computeInputOptions) error { + profileName := fmt.Sprintf("%s-worker", input.infraID) + _, err := createComputeInstanceProfile(ctx, logger, iamClient, profileName, input.tags) + if err != nil { + return fmt.Errorf("failed to create compute instance profile: %w", err) + } + logger.Infoln("Created compute instance profile") + return nil +} + +func createComputeInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, tags map[string]string) (*iam.InstanceProfile, error) { + const ( + assumeRolePolicy = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Principal": { + "Service": "ec2.amazonaws.com" + }, + "Effect": "Allow", + "Sid": "" + } + ] +}` + policy = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeRegions" + ], + "Resource": "*", + "Effect": "Allow" + } + ] +}` + ) + + input := &instanceProfileOptions{ + namePrefix: name, + assumeRolePolicy: assumeRolePolicy, + policyDocument: policy, + tags: tags, + } + return createInstanceProfile(ctx, logger, client, input) +} From 8c2c5d5ff563647f353242bda6934d2672db5b66 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Thu, 2 Nov 2023 17:18:11 +0100 Subject: [PATCH 17/33] destroy/aws: generalize functions for reuse These functions can be reused to destroy bootstrap resources when provisioning a cluster without terraform. --- pkg/destroy/aws/aws.go | 140 +++++++++++++++----------------- pkg/destroy/aws/ec2helpers.go | 38 +++++++++ pkg/destroy/aws/errortracker.go | 6 +- pkg/destroy/aws/iamhelpers.go | 44 +++++----- pkg/destroy/aws/shared.go | 12 +-- 5 files changed, 137 insertions(+), 103 deletions(-) diff --git a/pkg/destroy/aws/aws.go b/pkg/destroy/aws/aws.go index 744242762ae..14476539c50 100644 --- a/pkg/destroy/aws/aws.go +++ b/pkg/destroy/aws/aws.go @@ -12,7 +12,6 @@ import ( "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/efs" "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" @@ -158,12 +157,12 @@ func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, erro } iamClient := iam.New(awsSession) - iamRoleSearch := &iamRoleSearch{ - client: iamClient, - filters: o.Filters, - logger: o.Logger, + iamRoleSearch := &IamRoleSearch{ + Client: iamClient, + Filters: o.Filters, + Logger: o.Logger, } - iamUserSearch := &iamUserSearch{ + iamUserSearch := &IamUserSearch{ client: iamClient, filters: o.Filters, logger: o.Logger, @@ -180,45 +179,12 @@ func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, erro } } - tracker := new(errorTracker) + tracker := new(ErrorTracker) // Terminate EC2 instances. The instances need to be terminated first so that we can ensure that there is nothing // running on the cluster creating new resources while we are attempting to delete resources, which could leak // the new resources. - ec2Client := ec2.New(awsSession) - lastTerminateTime := time.Now() - err = wait.PollImmediateUntil( - time.Second*10, - func() (done bool, err error) { - instancesRunning, instancesNotTerminated, err := findEC2Instances(ctx, ec2Client, deleted, o.Filters, o.Logger) - if err != nil { - o.Logger.WithError(err).Info("error while finding EC2 instances to delete") - if err := ctx.Err(); err != nil { - return false, err - } - } - if len(instancesNotTerminated) == 0 && len(instancesRunning) == 0 && err == nil { - return true, nil - } - instancesToDelete := instancesRunning - if time.Since(lastTerminateTime) > 10*time.Minute { - instancesToDelete = instancesNotTerminated - lastTerminateTime = time.Now() - } - newlyDeleted, err := o.deleteResources(ctx, awsSession, instancesToDelete, tracker) - // Delete from the resources-to-delete set so that the current state of the resources to delete can be - // returned if the context is completed. - resourcesToDelete = resourcesToDelete.Difference(newlyDeleted) - deleted = deleted.Union(newlyDeleted) - if err != nil { - if err := ctx.Err(); err != nil { - return false, err - } - } - return false, nil - }, - ctx.Done(), - ) + err = DeleteEC2Instances(ctx, o.Logger, awsSession, o.Filters, resourcesToDelete, deleted, tracker) if err != nil { return resourcesToDelete.UnsortedList(), err } @@ -227,7 +193,7 @@ func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, erro err = wait.PollImmediateUntil( time.Second*10, func() (done bool, err error) { - newlyDeleted, loopError := o.deleteResources(ctx, awsSession, resourcesToDelete.UnsortedList(), tracker) + newlyDeleted, loopError := DeleteResources(ctx, o.Logger, awsSession, resourcesToDelete.UnsortedList(), tracker) // Delete from the resources-to-delete set so that the current state of the resources to delete can be // returned if the context is completed. resourcesToDelete = resourcesToDelete.Difference(newlyDeleted) @@ -292,14 +258,43 @@ func (o *ClusterUninstaller) findUntaggableResources(ctx context.Context, iamCli // findResourcesToDelete returns the resources that should be deleted. // -// tagClients - clients of the tagging API to use to search for resources. -// deleted - the resources that have already been deleted. Any resources specified in this set will be ignored. +// tagClients - clients of the tagging API to use to search for resources. +// deleted - the resources that have already been deleted. Any resources specified in this set will be ignored. func (o *ClusterUninstaller) findResourcesToDelete( ctx context.Context, tagClients []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, iamClient *iam.IAM, - iamRoleSearch *iamRoleSearch, - iamUserSearch *iamUserSearch, + iamRoleSearch *IamRoleSearch, + iamUserSearch *IamUserSearch, + deleted sets.Set[string], +) (sets.Set[string], []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, error) { + var errs []error + resources, tagClients, err := FindTaggedResourcesToDelete(ctx, o.Logger, tagClients, o.Filters, iamRoleSearch, iamUserSearch, deleted) + if err != nil { + errs = append(errs, err) + } + + // Find untaggable resources + untaggableResources, err := o.findUntaggableResources(ctx, iamClient, deleted) + if err != nil { + errs = append(errs, err) + } + resources = resources.Union(untaggableResources) + + return resources, tagClients, utilerrors.NewAggregate(errs) +} + +// FindTaggedResourcesToDelete returns the tagged resources that should be deleted. +// +// tagClients - clients of the tagging API to use to search for resources. +// deleted - the resources that have already been deleted. Any resources specified in this set will be ignored. +func FindTaggedResourcesToDelete( + ctx context.Context, + logger logrus.FieldLogger, + tagClients []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, + filters []Filter, + iamRoleSearch *IamRoleSearch, + iamUserSearch *IamUserSearch, deleted sets.Set[string], ) (sets.Set[string], []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, error) { resources := sets.New[string]() @@ -308,7 +303,7 @@ func (o *ClusterUninstaller) findResourcesToDelete( // Find resources by tag for _, tagClient := range tagClients { - resourcesInTagClient, err := o.findResourcesByTag(ctx, tagClient, deleted) + resourcesInTagClient, err := findResourcesByTag(ctx, logger, tagClient, filters, deleted) if err != nil { errs = append(errs, err) } @@ -318,30 +313,27 @@ func (o *ClusterUninstaller) findResourcesToDelete( if len(resourcesInTagClient) > 0 || err != nil { tagClientsWithResources = append(tagClientsWithResources, tagClient) } else { - o.Logger.Debugf("no deletions from %s, removing client", *tagClient.Config.Region) + logger.Debugf("no deletions from %s, removing client", *tagClient.Config.Region) } } // Find IAM roles - iamRoleResources, err := findIAMRoles(ctx, iamRoleSearch, deleted, o.Logger) - if err != nil { - errs = append(errs, err) + if iamRoleSearch != nil { + iamRoleResources, err := findIAMRoles(ctx, iamRoleSearch, deleted, logger) + if err != nil { + errs = append(errs, err) + } + resources = resources.Union(iamRoleResources) } - resources = resources.Union(iamRoleResources) // Find IAM users - iamUserResources, err := findIAMUsers(ctx, iamUserSearch, deleted, o.Logger) - if err != nil { - errs = append(errs, err) - } - resources = resources.Union(iamUserResources) - - // Find untaggable resources - untaggableResources, err := o.findUntaggableResources(ctx, iamClient, deleted) - if err != nil { - errs = append(errs, err) + if iamUserSearch != nil { + iamUserResources, err := findIAMUsers(ctx, iamUserSearch, deleted, logger) + if err != nil { + errs = append(errs, err) + } + resources = resources.Union(iamUserResources) } - resources = resources.Union(untaggableResources) return resources, tagClientsWithResources, utilerrors.NewAggregate(errs) } @@ -350,14 +342,16 @@ func (o *ClusterUninstaller) findResourcesToDelete( // // tagClients - clients of the tagging API to use to search for resources. // deleted - the resources that have already been deleted. Any resources specified in this set will be ignored. -func (o *ClusterUninstaller) findResourcesByTag( +func findResourcesByTag( ctx context.Context, + logger logrus.FieldLogger, tagClient *resourcegroupstaggingapi.ResourceGroupsTaggingAPI, + filters []Filter, deleted sets.Set[string], ) (sets.Set[string], error) { resources := sets.New[string]() - for _, filter := range o.Filters { - o.Logger.Debugf("search for matching resources by tag in %s matching %#+v", *tagClient.Config.Region, filter) + for _, filter := range filters { + logger.Debugf("search for matching resources by tag in %s matching %#+v", *tagClient.Config.Region, filter) tagFilters := make([]*resourcegroupstaggingapi.TagFilter, 0, len(filter)) for key, value := range filter { tagFilters = append(tagFilters, &resourcegroupstaggingapi.TagFilter{ @@ -380,29 +374,29 @@ func (o *ClusterUninstaller) findResourcesByTag( ) if err != nil { err = errors.Wrap(err, "get tagged resources") - o.Logger.Info(err) + logger.Info(err) return resources, err } } return resources, nil } -// deleteResources deletes the specified resources. +// DeleteResources deletes the specified resources. // // resources - the resources to be deleted. // // The first return is the ARNs of the resources that were successfully deleted -func (o *ClusterUninstaller) deleteResources(ctx context.Context, awsSession *session.Session, resources []string, tracker *errorTracker) (sets.Set[string], error) { +func DeleteResources(ctx context.Context, logger logrus.FieldLogger, awsSession *session.Session, resources []string, tracker *ErrorTracker) (sets.Set[string], error) { deleted := sets.New[string]() for _, arnString := range resources { - logger := o.Logger.WithField("arn", arnString) + l := logger.WithField("arn", arnString) parsedARN, err := arn.Parse(arnString) if err != nil { - logger.WithError(err).Debug("could not parse ARN") + l.WithError(err).Debug("could not parse ARN") continue } - if err := deleteARN(ctx, awsSession, parsedARN, o.Logger); err != nil { - tracker.suppressWarning(arnString, err, logger) + if err := deleteARN(ctx, awsSession, parsedARN, logger); err != nil { + tracker.suppressWarning(arnString, err, l) if err := ctx.Err(); err != nil { return deleted, err } diff --git a/pkg/destroy/aws/ec2helpers.go b/pkg/destroy/aws/ec2helpers.go index 3d06944f243..9aa0ca6f3dc 100644 --- a/pkg/destroy/aws/ec2helpers.go +++ b/pkg/destroy/aws/ec2helpers.go @@ -3,6 +3,7 @@ package aws import ( "context" "fmt" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" @@ -16,6 +17,7 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" ) // findEC2Instances returns the EC2 instances with tags that satisfy the filters. @@ -85,6 +87,42 @@ func findEC2Instances(ctx context.Context, ec2Client *ec2.EC2, deleted sets.Set[ return resourcesRunning, resourcesNotTerminated, nil } +// DeleteEC2Instances terminates all EC2 instances found. +func DeleteEC2Instances(ctx context.Context, logger logrus.FieldLogger, awsSession *session.Session, filters []Filter, toDelete sets.Set[string], deleted sets.Set[string], tracker *ErrorTracker) error { + ec2Client := ec2.New(awsSession) + lastTerminateTime := time.Now() + err := wait.PollUntilContextCancel( + ctx, + time.Second*10, + true, + func(ctx context.Context) (bool, error) { + instancesRunning, instancesNotTerminated, err := findEC2Instances(ctx, ec2Client, deleted, filters, logger) + if err != nil { + logger.WithError(err).Info("error while finding EC2 instances to delete") + return false, nil + } + if len(instancesNotTerminated) == 0 && len(instancesRunning) == 0 { + return true, nil + } + instancesToDelete := instancesRunning + if time.Since(lastTerminateTime) > 10*time.Minute { + instancesToDelete = instancesNotTerminated + lastTerminateTime = time.Now() + } + newlyDeleted, err := DeleteResources(ctx, logger, awsSession, instancesToDelete, tracker) + // Delete from the resources-to-delete set so that the current state of the resources to delete can be + // returned if the context is completed. + toDelete = toDelete.Difference(newlyDeleted) + deleted = deleted.Union(newlyDeleted) + if err != nil { + logger.WithError(err).Info("error while deleting EC2 instances") + } + return false, nil + }, + ) + return err +} + func deleteEC2(ctx context.Context, session *session.Session, arn arn.ARN, logger logrus.FieldLogger) error { client := ec2.New(session) diff --git a/pkg/destroy/aws/errortracker.go b/pkg/destroy/aws/errortracker.go index 048731ffb18..5ebba45c178 100644 --- a/pkg/destroy/aws/errortracker.go +++ b/pkg/destroy/aws/errortracker.go @@ -10,13 +10,13 @@ const ( suppressDuration = time.Minute * 5 ) -// errorTracker holds a history of errors -type errorTracker struct { +// ErrorTracker holds a history of errors. +type ErrorTracker struct { history map[string]time.Time } // suppressWarning logs errors WARN once every duration and the rest to DEBUG -func (o *errorTracker) suppressWarning(identifier string, err error, logger logrus.FieldLogger) { +func (o *ErrorTracker) suppressWarning(identifier string, err error, logger logrus.FieldLogger) { if o.history == nil { o.history = map[string]time.Time{} } diff --git a/pkg/destroy/aws/iamhelpers.go b/pkg/destroy/aws/iamhelpers.go index 142791b7207..4432aea0c50 100644 --- a/pkg/destroy/aws/iamhelpers.go +++ b/pkg/destroy/aws/iamhelpers.go @@ -14,31 +14,32 @@ import ( "k8s.io/apimachinery/pkg/util/sets" ) -type iamRoleSearch struct { - client *iam.IAM - filters []Filter - logger logrus.FieldLogger - unmatched map[string]struct{} +// IamRoleSearch holds data to search for IAM roles. +type IamRoleSearch struct { + Client *iam.IAM + Filters []Filter + Logger logrus.FieldLogger + Unmatched map[string]struct{} } -func (search *iamRoleSearch) find(ctx context.Context) (arns []string, names []string, returnErr error) { - if search.unmatched == nil { - search.unmatched = map[string]struct{}{} +func (search *IamRoleSearch) find(ctx context.Context) (arns []string, names []string, returnErr error) { + if search.Unmatched == nil { + search.Unmatched = map[string]struct{}{} } var lastError error - err := search.client.ListRolesPagesWithContext( + err := search.Client.ListRolesPagesWithContext( ctx, &iam.ListRolesInput{}, func(results *iam.ListRolesOutput, lastPage bool) bool { - search.logger.Debugf("iterating over a page of %d IAM roles", len(results.Roles)) + search.Logger.Debugf("iterating over a page of %d IAM roles", len(results.Roles)) for _, role := range results.Roles { - if _, ok := search.unmatched[*role.Arn]; ok { + if _, ok := search.Unmatched[*role.Arn]; ok { continue } // Unfortunately role.Tags is empty from ListRoles, so we need to query each one - response, err := search.client.GetRoleWithContext(ctx, &iam.GetRoleInput{RoleName: role.RoleName}) + response, err := search.Client.GetRoleWithContext(ctx, &iam.GetRoleInput{RoleName: role.RoleName}) if err != nil { var awsErr awserr.Error if errors.As(err, &awsErr) { @@ -47,15 +48,15 @@ func (search *iamRoleSearch) find(ctx context.Context) (arns []string, names []s // The role does not exist. // Ignore this IAM Role and donot report this error via // lastError - search.unmatched[*role.Arn] = exists + search.Unmatched[*role.Arn] = exists case strings.Contains(err.Error(), "AccessDenied"): // Installer does not have access to this IAM role // Ignore this IAM Role and donot report this error via // lastError - search.unmatched[*role.Arn] = exists + search.Unmatched[*role.Arn] = exists default: if lastError != nil { - search.logger.Debug(lastError) + search.Logger.Debug(lastError) } lastError = errors.Wrapf(err, "get tags for %s", *role.Arn) } @@ -66,11 +67,11 @@ func (search *iamRoleSearch) find(ctx context.Context) (arns []string, names []s for _, tag := range role.Tags { tags[*tag.Key] = *tag.Value } - if tagMatch(search.filters, tags) { + if tagMatch(search.Filters, tags) { arns = append(arns, *role.Arn) names = append(names, *role.RoleName) } else { - search.unmatched[*role.Arn] = exists + search.Unmatched[*role.Arn] = exists } } } @@ -85,14 +86,15 @@ func (search *iamRoleSearch) find(ctx context.Context) (arns []string, names []s return arns, names, err } -type iamUserSearch struct { +// IamUserSearch holds data to search for IAM users. +type IamUserSearch struct { client *iam.IAM filters []Filter logger logrus.FieldLogger unmatched map[string]struct{} } -func (search *iamUserSearch) arns(ctx context.Context) ([]string, error) { +func (search *IamUserSearch) arns(ctx context.Context) ([]string, error) { if search.unmatched == nil { search.unmatched = map[string]struct{}{} } @@ -158,7 +160,7 @@ func (search *iamUserSearch) arns(ctx context.Context) ([]string, error) { // findIAMRoles returns the IAM roles for the cluster. // // deleted - the resources that have already been deleted. Any resources specified in this set will be ignored. -func findIAMRoles(ctx context.Context, search *iamRoleSearch, deleted sets.Set[string], logger logrus.FieldLogger) (sets.Set[string], error) { +func findIAMRoles(ctx context.Context, search *IamRoleSearch, deleted sets.Set[string], logger logrus.FieldLogger) (sets.Set[string], error) { logger.Debug("search for IAM roles") resources, _, err := search.find(ctx) if err != nil { @@ -171,7 +173,7 @@ func findIAMRoles(ctx context.Context, search *iamRoleSearch, deleted sets.Set[s // findIAMUsers returns the IAM users for the cluster. // // deleted - the resources that have already been deleted. Any resources specified in this set will be ignored. -func findIAMUsers(ctx context.Context, search *iamUserSearch, deleted sets.Set[string], logger logrus.FieldLogger) (sets.Set[string], error) { +func findIAMUsers(ctx context.Context, search *IamUserSearch, deleted sets.Set[string], logger logrus.FieldLogger) (sets.Set[string], error) { logger.Debug("search for IAM users") resources, err := search.arns(ctx) if err != nil { diff --git a/pkg/destroy/aws/shared.go b/pkg/destroy/aws/shared.go index f216d1f8b21..23407445a78 100644 --- a/pkg/destroy/aws/shared.go +++ b/pkg/destroy/aws/shared.go @@ -23,7 +23,7 @@ func (o *ClusterUninstaller) removeSharedTags( ctx context.Context, session *session.Session, tagClients []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, - tracker *errorTracker, + tracker *ErrorTracker, ) error { for _, key := range o.clusterOwnedKeys() { if err := o.removeSharedTag(ctx, session, tagClients, key, tracker); err != nil { @@ -49,7 +49,7 @@ func (o *ClusterUninstaller) clusterOwnedKeys() []string { return keys } -func (o *ClusterUninstaller) removeSharedTag(ctx context.Context, session *session.Session, tagClients []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, key string, tracker *errorTracker) error { +func (o *ClusterUninstaller) removeSharedTag(ctx context.Context, session *session.Session, tagClients []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, key string, tracker *ErrorTracker) error { const sharedValue = "shared" request := &resourcegroupstaggingapi.UntagResourcesInput{ @@ -143,10 +143,10 @@ func (o *ClusterUninstaller) removeSharedTag(ctx context.Context, session *sessi } iamClient := iam.New(session) - iamRoleSearch := &iamRoleSearch{ - client: iamClient, - filters: []Filter{{key: sharedValue}}, - logger: o.Logger, + iamRoleSearch := &IamRoleSearch{ + Client: iamClient, + Filters: []Filter{{key: sharedValue}}, + Logger: o.Logger, } o.Logger.Debugf("Search for and remove shared tags for IAM roles matching %s: shared", key) if err := wait.PollImmediateUntil( From 4aa2b1991a7e952665d5ba062e62c8c99f0608cc Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Thu, 2 Nov 2023 17:20:02 +0100 Subject: [PATCH 18/33] CORS-2833: infra/aws: implement bootstrap destroy --- pkg/infrastructure/aws/aws.go | 54 +++++++++++++ pkg/infrastructure/aws/destroy.go | 124 ++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 pkg/infrastructure/aws/destroy.go diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 9861e261653..17e3f369540 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -4,8 +4,11 @@ import ( "context" "encoding/json" "fmt" + "os" + "path/filepath" "time" + "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/elbv2" "github.com/aws/aws-sdk-go/service/iam" @@ -21,6 +24,7 @@ import ( awstfvars "github.com/openshift/installer/pkg/tfvars/aws" "github.com/openshift/installer/pkg/types" awstypes "github.com/openshift/installer/pkg/types/aws" + "github.com/openshift/installer/pkg/version" ) const ( @@ -236,6 +240,56 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, // DestroyBootstrap destroys the temporary bootstrap resources. func (a InfraProvider) DestroyBootstrap(dir string) error { + // Unmarshall input from tf variables, so we can use it along with + // installConfig and other assets as the contractual input regardless of + // the implementation. + clusterConfig := &tfvars.Config{} + data, err := os.ReadFile(filepath.Join(dir, tfVarsFileName)) + if err == nil { + err = json.Unmarshal(data, clusterConfig) + } + if err != nil { + return fmt.Errorf("failed to load cluster terraform variables: %w", err) + } + clusterAWSConfig := &awstfvars.Config{} + data, err = os.ReadFile(filepath.Join(dir, tfPlatformVarsFileName)) + if err == nil { + err = json.Unmarshal(data, clusterAWSConfig) + } + if err != nil { + return fmt.Errorf("failed to load AWS terraform variables: %w", err) + } + + eps := []awstypes.ServiceEndpoint{} + for k, v := range clusterAWSConfig.CustomEndpoints { + eps = append(eps, awstypes.ServiceEndpoint{Name: k, URL: v}) + } + + awsSession, err := awssession.GetSessionWithOptions( + awssession.WithRegion(clusterAWSConfig.Region), + awssession.WithServiceEndpoints(clusterAWSConfig.Region, eps), + ) + if err != nil { + return err + } + awsSession.Handlers.Build.PushBackNamed(request.NamedHandler{ + Name: "openshiftInstaller.OpenshiftInstallerUserAgentHandler", + Fn: request.MakeAddToUserAgentHandler("OpenShift/4.x Destroyer", version.Raw), + }) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) + defer cancel() + + logger := logrus.StandardLogger() + input := &destroyInputOptions{ + infraID: clusterConfig.ClusterID, + region: clusterAWSConfig.Region, + } + err = destroyBootstrapResources(ctx, logger, awsSession, input) + if err != nil { + return fmt.Errorf("failed to delete bootstrap resources: %w", err) + } + return nil } diff --git a/pkg/infrastructure/aws/destroy.go b/pkg/infrastructure/aws/destroy.go new file mode 100644 index 00000000000..aa3b13585e1 --- /dev/null +++ b/pkg/infrastructure/aws/destroy.go @@ -0,0 +1,124 @@ +package aws + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/endpoints" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" + + awsdestroy "github.com/openshift/installer/pkg/destroy/aws" +) + +type destroyInputOptions struct { + infraID string + region string +} + +func destroyBootstrapResources(ctx context.Context, logger logrus.FieldLogger, awsSession *session.Session, input *destroyInputOptions) error { + iamClient := iam.New(awsSession) + iamRoleSearch := &awsdestroy.IamRoleSearch{ + Client: iamClient, + Filters: []awsdestroy.Filter{ + { + "Name": fmt.Sprintf("%s-bootstrap-role", input.infraID), + clusterOwnedTag(input.infraID): ownedTagValue, + }, + }, + Logger: logger, + } + + tagClients := []*resourcegroupstaggingapi.ResourceGroupsTaggingAPI{ + resourcegroupstaggingapi.New(awsSession), + } + switch input.region { + case endpoints.CnNorth1RegionID, endpoints.CnNorthwest1RegionID: + break + case endpoints.UsIsoEast1RegionID, endpoints.UsIsoWest1RegionID, endpoints.UsIsobEast1RegionID: + break + case endpoints.UsGovEast1RegionID: + tagClients = append(tagClients, resourcegroupstaggingapi.New(awsSession, aws.NewConfig().WithRegion(endpoints.UsGovWest1RegionID))) + case endpoints.UsGovWest1RegionID: + break + case endpoints.UsEast1RegionID: + break + default: + tagClients = append(tagClients, resourcegroupstaggingapi.New(awsSession, aws.NewConfig().WithRegion(endpoints.UsEast1RegionID))) + } + + entities := []string{"bootstrap", "bootstrap-profile", "bootstrap-role-policy", "bootstrap-sg"} + filters := make([]awsdestroy.Filter, 0, len(entities)) + for _, entity := range entities { + filters = append(filters, awsdestroy.Filter{ + "Name": fmt.Sprintf("%s-%s", input.infraID, entity), + clusterOwnedTag(input.infraID): ownedTagValue, + }) + } + + deleted := sets.New[string]() + // Get the initial resources to delete, so that they can be returned if the context is cancelled while terminating instances. + resourcesToDelete, tagClientsWithResources, err := awsdestroy.FindTaggedResourcesToDelete(ctx, logger, tagClients, filters, iamRoleSearch, nil, deleted) + if err != nil { + return fmt.Errorf("failed to collect bootstrap resources to delete: %w", err) + } + + tracker := new(awsdestroy.ErrorTracker) + instanceFilters := []awsdestroy.Filter{ + { + "Name": fmt.Sprintf("%s-bootstrap", input.infraID), + clusterOwnedTag(input.infraID): ownedTagValue, + }, + } + err = awsdestroy.DeleteEC2Instances(ctx, logger, awsSession, instanceFilters, resourcesToDelete, deleted, tracker) + if err != nil { + logger.WithError(err).Infof("failed to delete the following resources: %v", resourcesToDelete.UnsortedList()) + return fmt.Errorf("failed to terminate bootstrap instance: %w", err) + } + + // Delete the rest of the resources + err = wait.PollUntilContextCancel( + ctx, + time.Second*10, + true, + func(ctx context.Context) (bool, error) { + newlyDeleted, loopError := awsdestroy.DeleteResources(ctx, logger, awsSession, resourcesToDelete.UnsortedList(), tracker) + // Delete from the resources-to-delete set so that the current + // state of the resources to delete can be returned if the context + // is completed. + resourcesToDelete = resourcesToDelete.Difference(newlyDeleted) + deleted = deleted.Union(newlyDeleted) + if loopError != nil { + if err := ctx.Err(); err != nil { + return false, err + } + } + // Store resources to delete in a temporary variable so that, in + // case the context is cancelled, the current resources to delete + // are not lost. + nextResourcesToDelete, nextTagClients, err := awsdestroy.FindTaggedResourcesToDelete(ctx, logger, tagClientsWithResources, filters, iamRoleSearch, nil, deleted) + if err != nil { + logger.WithError(err).Info("error while finding resources to delete") + if err := ctx.Err(); err != nil { + return false, err + } + loopError = fmt.Errorf("error while finding resources to delete: %w", err) + } + resourcesToDelete = nextResourcesToDelete + tagClientsWithResources = nextTagClients + return len(resourcesToDelete) == 0 && loopError == nil, nil + }, + ) + if err != nil { + logger.WithError(err).Infof("failed to delete the following resources: %v", resourcesToDelete.UnsortedList()) + return fmt.Errorf("failed to delete bootstrap resources: %w", err) + } + + return nil +} From 4e3c1de93cd2032c7e7b6cd6bfe9661cfd66dda4 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 3 Nov 2023 16:18:49 +0100 Subject: [PATCH 19/33] infra/aws: generate output from cluster provisioning This output will be useful when information is needed about resources created during cluster provisioning. --- pkg/infrastructure/aws/aws.go | 38 ++++++++++++++++++++++++-- pkg/infrastructure/aws/bootstrap.go | 20 ++++++++++---- pkg/infrastructure/aws/controlplane.go | 16 +++++++---- 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 17e3f369540..ed4915c2829 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -30,6 +30,7 @@ import ( const ( tfVarsFileName = "terraform.tfvars.json" tfPlatformVarsFileName = "terraform.platform.auto.tfvars.json" + clusterOutputFileName = "cluster.awssdk.vars.json" ownedTagKey = "kubernetes.io/cluster/%s" ownedTagValue = "owned" @@ -43,6 +44,17 @@ func InitializeProvider() infrastructure.Provider { return InfraProvider{} } +type output struct { + VpcID string `json:"vpc_id,omitempty"` + MasterSGID string `json:"master_sg_id,omitempty"` + WorkerSGID string `json:"worker_sg_id,omitempty"` + BootstrapIP string `json:"bootstrap_ip,omitempty"` + ControlPlaneIPs []string `json:"master_ips,omitempty"` + TargetGroupARNs []string `json:"lb_target_group_arns,omitempty"` + PublicSubnetIDs []string `json:"public_subnet_ids,omitempty"` + PrivateSubnetIDs []string `json:"private_subnet_ids,omitempty"` +} + // Provision creates the infrastructure resources for the stage. // dir: the path of the install dir // vars: cluster configuration input variables, such as terraform variables files @@ -191,7 +203,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, } iamClient := iam.New(awsSession) s3Client := s3.New(awsSession) - err = createBootstrapResources(ctx, logger, ec2Client, iamClient, s3Client, elbClient, &bootstrapInput) + bootstrapOut, err := createBootstrapResources(ctx, logger, ec2Client, iamClient, s3Client, elbClient, &bootstrapInput) if err != nil { return nil, fmt.Errorf("failed to create bootstrap resources: %w", err) } @@ -220,7 +232,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, zoneToSubnetMap: vpcOutput.zoneToSubnetMap, availabilityZones: clusterAWSConfig.MasterAvailabilityZones, } - err = createControlPlaneResources(ctx, logger, ec2Client, iamClient, elbClient, &controlPlaneInput) + controlPlaneOut, err := createControlPlaneResources(ctx, logger, ec2Client, iamClient, elbClient, &controlPlaneInput) if err != nil { return nil, fmt.Errorf("failed to create control plane resources: %w", err) } @@ -235,7 +247,27 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, return nil, fmt.Errorf("failed to create compute resources: %w", err) } - return nil, nil + bootstrapIP := bootstrapOut.privateIP + if clusterAWSConfig.PublishStrategy == "External" { + bootstrapIP = bootstrapOut.publicIP + } + out := &output{ + BootstrapIP: bootstrapIP, + VpcID: vpcOutput.vpcID, + TargetGroupARNs: lbOutput.targetGroupArns, + PublicSubnetIDs: vpcOutput.publicSubnetIDs, + PrivateSubnetIDs: vpcOutput.privateSubnetIDs, + MasterSGID: sgOutput.controlPlane, + WorkerSGID: sgOutput.compute, + ControlPlaneIPs: controlPlaneOut.controlPlaneIPs, + } + data, err := json.MarshalIndent(out, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to write cluster output: %w", err) + } + return []*asset.File{ + {Filename: clusterOutputFileName, Data: data}, + }, nil } // DestroyBootstrap destroys the temporary bootstrap resources. diff --git a/pkg/infrastructure/aws/bootstrap.go b/pkg/infrastructure/aws/bootstrap.go index 14f1e419509..23a977d37ed 100644 --- a/pkg/infrastructure/aws/bootstrap.go +++ b/pkg/infrastructure/aws/bootstrap.go @@ -23,26 +23,34 @@ type bootstrapInputOptions struct { ignitionContent string } -func createBootstrapResources(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, iamClient iamiface.IAMAPI, s3Client s3iface.S3API, elbClient elbv2iface.ELBV2API, input *bootstrapInputOptions) error { +type bootstrapOutput struct { + privateIP string + publicIP string +} + +func createBootstrapResources(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, iamClient iamiface.IAMAPI, s3Client s3iface.S3API, elbClient elbv2iface.ELBV2API, input *bootstrapInputOptions) (*bootstrapOutput, error) { err := ensureIgnition(ctx, logger, s3Client, input.infraID, input.ignitionBucket, input.ignitionContent, input.tags) if err != nil { - return fmt.Errorf("failed to create ignition resources: %w", err) + return nil, fmt.Errorf("failed to create ignition resources: %w", err) } profileName := fmt.Sprintf("%s-bootstrap", input.infraID) instanceProfile, err := createBootstrapInstanceProfile(ctx, logger, iamClient, profileName, input.tags) if err != nil { - return fmt.Errorf("failed to create bootstrap instance profile: %w", err) + return nil, fmt.Errorf("failed to create bootstrap instance profile: %w", err) } input.instanceProfileARN = aws.StringValue(instanceProfile.Arn) input.name = fmt.Sprintf("%s-bootstrap", input.infraID) - _, err = ensureInstance(ctx, logger, ec2Client, elbClient, &input.instanceInputOptions) + instance, err := ensureInstance(ctx, logger, ec2Client, elbClient, &input.instanceInputOptions) if err != nil { - return fmt.Errorf("failed to create bootstrap instace: %w", err) + return nil, fmt.Errorf("failed to create bootstrap instace: %w", err) } - return nil + return &bootstrapOutput{ + privateIP: aws.StringValue(instance.PrivateIpAddress), + publicIP: aws.StringValue(instance.PublicIpAddress), + }, nil } func ensureIgnition(ctx context.Context, logger logrus.FieldLogger, client s3iface.S3API, infraID string, bucket string, content string, tags map[string]string) error { diff --git a/pkg/infrastructure/aws/controlplane.go b/pkg/infrastructure/aws/controlplane.go index d3e2a073005..183c70fa6f7 100644 --- a/pkg/infrastructure/aws/controlplane.go +++ b/pkg/infrastructure/aws/controlplane.go @@ -20,13 +20,18 @@ type controlPlaneInputOptions struct { availabilityZones []string } -func createControlPlaneResources(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, iamClient iamiface.IAMAPI, elbClient elbv2iface.ELBV2API, input *controlPlaneInputOptions) error { +type controlPlaneOutput struct { + controlPlaneIPs []string +} + +func createControlPlaneResources(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, iamClient iamiface.IAMAPI, elbClient elbv2iface.ELBV2API, input *controlPlaneInputOptions) (*controlPlaneOutput, error) { profileName := fmt.Sprintf("%s-master", input.infraID) instanceProfile, err := createControlPlaneInstanceProfile(ctx, logger, iamClient, profileName, input.tags) if err != nil { - return fmt.Errorf("failed to create control plane instance profile: %w", err) + return nil, fmt.Errorf("failed to create control plane instance profile: %w", err) } + instanceIPs := make([]string, 0, input.nReplicas) for i := 0; i < input.nReplicas; i++ { options := input.instanceInputOptions options.name = fmt.Sprintf("%s-master-%d", input.infraID, i) @@ -35,14 +40,15 @@ func createControlPlaneResources(ctx context.Context, logger logrus.FieldLogger, options.subnetID = input.zoneToSubnetMap[input.availabilityZones[zoneIdx]] options.instanceProfileARN = aws.StringValue(instanceProfile.Arn) - _, err := ensureInstance(ctx, logger, ec2Client, elbClient, &options) + instance, err := ensureInstance(ctx, logger, ec2Client, elbClient, &options) if err != nil { - return fmt.Errorf("failed to create control plane (%s): %w", options.name, err) + return nil, fmt.Errorf("failed to create control plane (%s): %w", options.name, err) } + instanceIPs = append(instanceIPs, aws.StringValue(instance.PrivateIpAddress)) } logger.Infoln("Created control plane instances") - return nil + return &controlPlaneOutput{controlPlaneIPs: instanceIPs}, nil } func createControlPlaneInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, tags map[string]string) (*iam.InstanceProfile, error) { From 9a20ef7e618168aad6ce5e87401133564a1029ac Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 3 Nov 2023 16:20:11 +0100 Subject: [PATCH 20/33] CORS-2834: infra/aws: implement bootstrap gather --- pkg/infrastructure/aws/aws.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index ed4915c2829..9e8ab431db3 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -327,6 +327,18 @@ func (a InfraProvider) DestroyBootstrap(dir string) error { // ExtractHostAddresses extracts the IPs of the bootstrap and control plane machines. func (a InfraProvider) ExtractHostAddresses(dir string, ic *types.InstallConfig, ha *infrastructure.HostAddresses) error { + clusterOutput := &output{} + data, err := os.ReadFile(filepath.Join(dir, clusterOutputFileName)) + if err == nil { + err = json.Unmarshal(data, clusterOutput) + } + if err != nil { + return fmt.Errorf("failed to load cluster terraform variables: %w", err) + } + + ha.Bootstrap = clusterOutput.BootstrapIP + ha.Masters = append(ha.Masters, clusterOutput.ControlPlaneIPs...) + return nil } From c8bbdaf844c0bb92fe78924048ff38791f471d8d Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 3 Nov 2023 16:45:03 +0100 Subject: [PATCH 21/33] CORS-2878: infra/aws: support existing/shared VPC Installs to existing subnets when installconfig.platform.aws.subnets is specified --- pkg/infrastructure/aws/provision_test.go | 94 ++++++++++++++++++++++++ pkg/infrastructure/aws/vpc.go | 24 ++++++ 2 files changed, 118 insertions(+) diff --git a/pkg/infrastructure/aws/provision_test.go b/pkg/infrastructure/aws/provision_test.go index b1713edd252..eb5ac61a8c7 100644 --- a/pkg/infrastructure/aws/provision_test.go +++ b/pkg/infrastructure/aws/provision_test.go @@ -1975,6 +1975,100 @@ func TestEnsureS3VPCEndpoint(t *testing.T) { } } +func TestEnsureUserVpc(t *testing.T) { + const vpcID = "vpc-1" + publicIDs := []string{"public-1", "public-2"} + privateIDs := []string{"private-1", "private-2"} + privateSubnets := []*ec2.Subnet{ + { + SubnetId: aws.String("private-1"), + AvailabilityZone: aws.String("zone-1"), + }, + { + SubnetId: aws.String("private-2"), + AvailabilityZone: aws.String("zone-2"), + }, + } + privateSubnetZoneMap := map[string]string{ + "zone-1": "private-1", + "zone-2": "private-2", + } + tests := []struct { + name string + mockSvc mockEC2Client + publicIDs []string + expectedOut *vpcOutput + expectedErr string + }{ + { + name: "AWS SDK error describing subnets", + mockSvc: mockEC2Client{ + describeSubnets: func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + return nil, errAwsSdk + }, + }, + expectedErr: `^failed to retrieve user-supplied subnets: some AWS SDK error$`, + }, + { + name: "Subnet zones mapped and no resources created in private-only VPC", + mockSvc: mockEC2Client{ + describeSubnets: func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + return &ec2.DescribeSubnetsOutput{ + Subnets: privateSubnets, + }, nil + }, + }, + expectedOut: &vpcOutput{ + vpcID: vpcID, + privateSubnetIDs: privateIDs, + zoneToSubnetMap: privateSubnetZoneMap, + publicSubnetIDs: nil, + }, + }, + { + name: "Subnet zones mapped and no resources created", + mockSvc: mockEC2Client{ + describeSubnets: func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + return &ec2.DescribeSubnetsOutput{ + Subnets: privateSubnets, + }, nil + }, + }, + publicIDs: publicIDs, + expectedOut: &vpcOutput{ + vpcID: vpcID, + privateSubnetIDs: privateIDs, + zoneToSubnetMap: privateSubnetZoneMap, + publicSubnetIDs: publicIDs, + }, + }, + } + + logger := logrus.New() + logger.SetOutput(io.Discard) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + input := &vpcInputOptions{ + infraID: "infraID", + region: "region", + vpcID: vpcID, + privateSubnetIDs: privateIDs, + tags: map[string]string{}, + } + input.publicSubnetIDs = test.publicIDs + res, err := createVPCResources(context.TODO(), logger, &test.mockSvc, input) + if test.expectedErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedOut, res) + } else { + assert.Error(t, err) + assert.Regexp(t, test.expectedErr, err.Error()) + } + }) + } +} + func TestEnsureSecurityGroup(t *testing.T) { emptySG := &ec2.SecurityGroup{ GroupId: aws.String("sg-1"), diff --git a/pkg/infrastructure/aws/vpc.go b/pkg/infrastructure/aws/vpc.go index 63c1d0747a1..8fb2c2252f9 100644 --- a/pkg/infrastructure/aws/vpc.go +++ b/pkg/infrastructure/aws/vpc.go @@ -67,6 +67,30 @@ type vpcOutput struct { } func createVPCResources(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, vpcInput *vpcInputOptions) (*vpcOutput, error) { + // User-supplied VPC. In this case we don't create any subnets + if len(vpcInput.vpcID) > 0 { + logger.WithField("id", vpcInput.vpcID).Infoln("Found user-supplied VPC") + + privateSubnetIDs := aws.StringSlice(vpcInput.privateSubnetIDs) + privateSubnetZoneMap := make(map[string]*string, len(privateSubnetIDs)) + result, err := ec2Client.DescribeSubnetsWithContext(ctx, &ec2.DescribeSubnetsInput{ + SubnetIds: privateSubnetIDs, + }) + if err != nil { + return nil, fmt.Errorf("failed to retrieve user-supplied subnets: %w", err) + } + for _, subnet := range result.Subnets { + privateSubnetZoneMap[aws.StringValue(subnet.AvailabilityZone)] = subnet.SubnetId + } + + return &vpcOutput{ + vpcID: vpcInput.vpcID, + publicSubnetIDs: vpcInput.publicSubnetIDs, + privateSubnetIDs: vpcInput.privateSubnetIDs, + zoneToSubnetMap: aws.StringValueMap(privateSubnetZoneMap), + }, nil + } + state := vpcState{input: vpcInput} endpointRouteTableIDs := make([]*string, 0, len(vpcInput.zones)+1) From b66a588e9dae03f8d8df5b9e116ed861e54e35f8 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 3 Nov 2023 17:27:56 +0100 Subject: [PATCH 22/33] CORS-2943: infra/aws: copy AMI when not in target region. --- pkg/infrastructure/aws/aws.go | 52 +++++++++++++++++++++++++++++++---- pkg/infrastructure/aws/dns.go | 6 +--- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 9e8ab431db3..28d2312e7cb 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -8,8 +8,10 @@ import ( "path/filepath" "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/aws/aws-sdk-go/service/elbv2" "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/route53" @@ -32,8 +34,9 @@ const ( tfPlatformVarsFileName = "terraform.platform.auto.tfvars.json" clusterOutputFileName = "cluster.awssdk.vars.json" - ownedTagKey = "kubernetes.io/cluster/%s" - ownedTagValue = "owned" + defaultDescription = "Created by Openshift Installer" + ownedTagKey = "kubernetes.io/cluster/%s" + ownedTagValue = "owned" ) // InfraProvider is the AWS SDK infra provider. @@ -106,8 +109,17 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) defer cancel() - logger.Infoln("Creating VPC resources") ec2Client := ec2.New(awsSession) + amiID := clusterAWSConfig.AMI + if clusterAWSConfig.Region != clusterAWSConfig.AMIRegion { + logger.Infof("Copying AMI to region %s", clusterAWSConfig.Region) + amiID, err = copyAMIToRegion(ctx, ec2Client, clusterAWSConfig.AMI, clusterAWSConfig.AMIRegion, clusterAWSConfig.Region, clusterConfig.ClusterID, tags) + if err != nil { + return nil, fmt.Errorf("failed to copy AMI to region (%s): %w", clusterAWSConfig.Region, err) + } + } + + logger.Infoln("Creating VPC resources") vpcInput := vpcInputOptions{ infraID: clusterConfig.ClusterID, region: clusterAWSConfig.Region, @@ -182,7 +194,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, bootstrapInput := bootstrapInputOptions{ instanceInputOptions: instanceInputOptions{ infraID: clusterConfig.ClusterID, - amiID: clusterAWSConfig.AMI, + amiID: amiID, instanceType: clusterAWSConfig.MasterInstanceType, iamRole: clusterAWSConfig.MasterIAMRoleName, volumeType: "gp2", @@ -212,7 +224,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, controlPlaneInput := controlPlaneInputOptions{ instanceInputOptions: instanceInputOptions{ infraID: clusterConfig.ClusterID, - amiID: clusterAWSConfig.AMI, + amiID: amiID, instanceType: clusterAWSConfig.MasterInstanceType, iamRole: clusterAWSConfig.MasterIAMRoleName, volumeType: clusterAWSConfig.Type, @@ -356,3 +368,33 @@ func mergeTags(lhsTags, rhsTags map[string]string) map[string]string { func clusterOwnedTag(infraID string) string { return fmt.Sprintf(ownedTagKey, infraID) } + +func copyAMIToRegion(ctx context.Context, client ec2iface.EC2API, sourceAMI string, sourceRegion string, targetRegion string, infraID string, tags map[string]string) (string, error) { + name := fmt.Sprintf("%s-ami-%s", infraID, targetRegion) + amiTags := mergeTags(tags, map[string]string{ + "Name": name, + "sourceAMI": sourceAMI, + "sourceRegion": sourceRegion, + }) + res, err := client.CopyImageWithContext(ctx, &ec2.CopyImageInput{ + Name: aws.String(fmt.Sprintf("%s-master", infraID)), + ClientToken: aws.String(infraID), + Description: aws.String(defaultDescription), + SourceImageId: aws.String(sourceAMI), + SourceRegion: aws.String(sourceRegion), + Encrypted: aws.Bool(true), + }) + if err != nil { + return "", err + } + + _, err = client.CreateTagsWithContext(ctx, &ec2.CreateTagsInput{ + Resources: []*string{res.ImageId}, + Tags: ec2Tags(amiTags), + }) + if err != nil { + return "", fmt.Errorf("failed to tag AMI copy (%s): %w", name, err) + } + + return aws.StringValue(res.ImageId), nil +} diff --git a/pkg/infrastructure/aws/dns.go b/pkg/infrastructure/aws/dns.go index 6917d9beeef..9d2b08241bc 100644 --- a/pkg/infrastructure/aws/dns.go +++ b/pkg/infrastructure/aws/dns.go @@ -16,11 +16,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" ) -const ( - errSharedCredsLoad = "SharedCredsLoad" - - defaultDescription = "Created by Openshift Installer" -) +const errSharedCredsLoad = "SharedCredsLoad" type dnsInputOptions struct { infraID string From 8e6aed02c22666323befa973effbc246f15cb3bf Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Fri, 3 Nov 2023 18:06:48 +0100 Subject: [PATCH 23/33] CORS-2944: infra/aws: support CNAME for gov cloud regions --- pkg/infrastructure/aws/dns.go | 43 +++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/pkg/infrastructure/aws/dns.go b/pkg/infrastructure/aws/dns.go index 9d2b08241bc..139e4ddf80b 100644 --- a/pkg/infrastructure/aws/dns.go +++ b/pkg/infrastructure/aws/dns.go @@ -13,11 +13,14 @@ import ( "github.com/aws/aws-sdk-go/service/route53" "github.com/aws/aws-sdk-go/service/route53/route53iface" "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" ) const errSharedCredsLoad = "SharedCredsLoad" +var cnameRegions = sets.New[string]("us-gov-west-1", "us-gov-east-1") + type dnsInputOptions struct { infraID string region string @@ -35,6 +38,7 @@ type dnsInputOptions struct { func createDNSResources(ctx context.Context, logger logrus.FieldLogger, route53Client route53iface.Route53API, input *dnsInputOptions) error { apiName := fmt.Sprintf("api.%s", input.clusterDomain) apiIntName := fmt.Sprintf("api-int.%s", input.clusterDomain) + useCNAME := cnameRegions.Has(input.region) if !input.isPrivateCluster { publicZone, err := existingHostedZone(ctx, route53Client, input.baseDomain, false) @@ -48,7 +52,7 @@ func createDNSResources(ctx context.Context, logger logrus.FieldLogger, route53C }).Infoln("Found existing public zone") // Create API record in public zone - _, err = createRecordA(ctx, route53Client, zoneID, apiName, input.lbExternalZoneDNS, input.lbExternalZoneID) + _, err = createRecord(ctx, route53Client, zoneID, apiName, input.lbExternalZoneDNS, input.lbExternalZoneID, useCNAME) if err != nil { return fmt.Errorf("failed to create api record (%s) in public zone: %w", apiName, err) } @@ -62,14 +66,14 @@ func createDNSResources(ctx context.Context, logger logrus.FieldLogger, route53C privateZoneID := cleanZoneID(privateZone.Id) // Create API record in private zone - _, err = createRecordA(ctx, route53Client, privateZoneID, apiName, input.lbInternalZoneDNS, input.lbInternalZoneID) + _, err = createRecord(ctx, route53Client, privateZoneID, apiName, input.lbInternalZoneDNS, input.lbInternalZoneID, useCNAME) if err != nil { return fmt.Errorf("failed to create api record (%s) in private zone: %w", apiName, err) } logger.Infoln("Created api DNS record for private zone") // Create API-int record in privat zone - _, err = createRecordA(ctx, route53Client, privateZoneID, apiIntName, input.lbInternalZoneDNS, input.lbInternalZoneID) + _, err = createRecord(ctx, route53Client, privateZoneID, apiIntName, input.lbInternalZoneDNS, input.lbInternalZoneID, useCNAME) if err != nil { return fmt.Errorf("failed to create api-int record (%s) in private zone: %w", apiIntName, err) } @@ -201,29 +205,38 @@ func createHostedZone(ctx context.Context, client route53iface.Route53API, name, return res.HostedZone, nil } -func createRecordA(ctx context.Context, client route53iface.Route53API, zoneID string, name string, aliasDNS string, aliasID string) (*route53.ChangeInfo, error) { +func createRecord(ctx context.Context, client route53iface.Route53API, zoneID string, name string, dnsName string, aliasZoneID string, useCNAME bool) (*route53.ChangeInfo, error) { + recordSet := &route53.ResourceRecordSet{ + Name: aws.String(cleanRecordName(name)), + } + if useCNAME { + recordSet.SetType("CNAME") + recordSet.SetTTL(10) + recordSet.SetResourceRecords([]*route53.ResourceRecord{ + {Value: aws.String(dnsName)}, + }) + } else { + recordSet.SetType("A") + recordSet.SetAliasTarget(&route53.AliasTarget{ + DNSName: aws.String(dnsName), + HostedZoneId: aws.String(aliasZoneID), + EvaluateTargetHealth: aws.Bool(false), + }) + } input := &route53.ChangeResourceRecordSetsInput{ HostedZoneId: aws.String(zoneID), ChangeBatch: &route53.ChangeBatch{ Changes: []*route53.Change{ { - Action: aws.String("UPSERT"), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String(cleanRecordName(name)), - Type: aws.String("A"), - AliasTarget: &route53.AliasTarget{ - DNSName: aws.String(aliasDNS), - HostedZoneId: aws.String(aliasID), - EvaluateTargetHealth: aws.Bool(false), - }, - }, + Action: aws.String("UPSERT"), + ResourceRecordSet: recordSet, }, }, }, } res, err := client.ChangeResourceRecordSetsWithContext(ctx, input) if err != nil { - return nil, fmt.Errorf("failed to create alias record: %w", err) + return nil, err } return res.ChangeInfo, nil From cba8f1dcdeb757c20bafcb4a7fe12bb87ddda75a Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Tue, 24 Oct 2023 22:09:18 +0200 Subject: [PATCH 24/33] aws: vendor changes --- .../service/ec2/ec2iface/interface.go | 2953 +++++++++++++++++ .../service/elbv2/elbv2iface/interface.go | 224 ++ .../service/route53/route53iface/interface.go | 368 ++ vendor/modules.txt | 3 + 4 files changed, 3548 insertions(+) create mode 100644 vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go create mode 100644 vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface/interface.go create mode 100644 vendor/github.com/aws/aws-sdk-go/service/route53/route53iface/interface.go diff --git a/vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go b/vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go new file mode 100644 index 00000000000..33214a6be6a --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go @@ -0,0 +1,2953 @@ +// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. + +// Package ec2iface provides an interface to enable mocking the Amazon Elastic Compute Cloud service client +// for testing your code. +// +// It is important to note that this interface will have breaking changes +// when the service model is updated and adds new API operations, paginators, +// and waiters. +package ec2iface + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/ec2" +) + +// EC2API provides an interface to enable mocking the +// ec2.EC2 service client's API operation, +// paginators, and waiters. This make unit testing your code that calls out +// to the SDK's service client's calls easier. +// +// The best way to use this interface is so the SDK's service client's calls +// can be stubbed out for unit testing your code with the SDK without needing +// to inject custom request handlers into the SDK's request pipeline. +// +// // myFunc uses an SDK service client to make a request to +// // Amazon Elastic Compute Cloud. +// func myFunc(svc ec2iface.EC2API) bool { +// // Make svc.AcceptAddressTransfer request +// } +// +// func main() { +// sess := session.New() +// svc := ec2.New(sess) +// +// myFunc(svc) +// } +// +// In your _test.go file: +// +// // Define a mock struct to be used in your unit tests of myFunc. +// type mockEC2Client struct { +// ec2iface.EC2API +// } +// func (m *mockEC2Client) AcceptAddressTransfer(input *ec2.AcceptAddressTransferInput) (*ec2.AcceptAddressTransferOutput, error) { +// // mock response/functionality +// } +// +// func TestMyFunc(t *testing.T) { +// // Setup Test +// mockSvc := &mockEC2Client{} +// +// myfunc(mockSvc) +// +// // Verify myFunc's functionality +// } +// +// It is important to note that this interface will have breaking changes +// when the service model is updated and adds new API operations, paginators, +// and waiters. Its suggested to use the pattern above for testing, or using +// tooling to generate mocks to satisfy the interfaces. +type EC2API interface { + AcceptAddressTransfer(*ec2.AcceptAddressTransferInput) (*ec2.AcceptAddressTransferOutput, error) + AcceptAddressTransferWithContext(aws.Context, *ec2.AcceptAddressTransferInput, ...request.Option) (*ec2.AcceptAddressTransferOutput, error) + AcceptAddressTransferRequest(*ec2.AcceptAddressTransferInput) (*request.Request, *ec2.AcceptAddressTransferOutput) + + AcceptReservedInstancesExchangeQuote(*ec2.AcceptReservedInstancesExchangeQuoteInput) (*ec2.AcceptReservedInstancesExchangeQuoteOutput, error) + AcceptReservedInstancesExchangeQuoteWithContext(aws.Context, *ec2.AcceptReservedInstancesExchangeQuoteInput, ...request.Option) (*ec2.AcceptReservedInstancesExchangeQuoteOutput, error) + AcceptReservedInstancesExchangeQuoteRequest(*ec2.AcceptReservedInstancesExchangeQuoteInput) (*request.Request, *ec2.AcceptReservedInstancesExchangeQuoteOutput) + + AcceptTransitGatewayMulticastDomainAssociations(*ec2.AcceptTransitGatewayMulticastDomainAssociationsInput) (*ec2.AcceptTransitGatewayMulticastDomainAssociationsOutput, error) + AcceptTransitGatewayMulticastDomainAssociationsWithContext(aws.Context, *ec2.AcceptTransitGatewayMulticastDomainAssociationsInput, ...request.Option) (*ec2.AcceptTransitGatewayMulticastDomainAssociationsOutput, error) + AcceptTransitGatewayMulticastDomainAssociationsRequest(*ec2.AcceptTransitGatewayMulticastDomainAssociationsInput) (*request.Request, *ec2.AcceptTransitGatewayMulticastDomainAssociationsOutput) + + AcceptTransitGatewayPeeringAttachment(*ec2.AcceptTransitGatewayPeeringAttachmentInput) (*ec2.AcceptTransitGatewayPeeringAttachmentOutput, error) + AcceptTransitGatewayPeeringAttachmentWithContext(aws.Context, *ec2.AcceptTransitGatewayPeeringAttachmentInput, ...request.Option) (*ec2.AcceptTransitGatewayPeeringAttachmentOutput, error) + AcceptTransitGatewayPeeringAttachmentRequest(*ec2.AcceptTransitGatewayPeeringAttachmentInput) (*request.Request, *ec2.AcceptTransitGatewayPeeringAttachmentOutput) + + AcceptTransitGatewayVpcAttachment(*ec2.AcceptTransitGatewayVpcAttachmentInput) (*ec2.AcceptTransitGatewayVpcAttachmentOutput, error) + AcceptTransitGatewayVpcAttachmentWithContext(aws.Context, *ec2.AcceptTransitGatewayVpcAttachmentInput, ...request.Option) (*ec2.AcceptTransitGatewayVpcAttachmentOutput, error) + AcceptTransitGatewayVpcAttachmentRequest(*ec2.AcceptTransitGatewayVpcAttachmentInput) (*request.Request, *ec2.AcceptTransitGatewayVpcAttachmentOutput) + + AcceptVpcEndpointConnections(*ec2.AcceptVpcEndpointConnectionsInput) (*ec2.AcceptVpcEndpointConnectionsOutput, error) + AcceptVpcEndpointConnectionsWithContext(aws.Context, *ec2.AcceptVpcEndpointConnectionsInput, ...request.Option) (*ec2.AcceptVpcEndpointConnectionsOutput, error) + AcceptVpcEndpointConnectionsRequest(*ec2.AcceptVpcEndpointConnectionsInput) (*request.Request, *ec2.AcceptVpcEndpointConnectionsOutput) + + AcceptVpcPeeringConnection(*ec2.AcceptVpcPeeringConnectionInput) (*ec2.AcceptVpcPeeringConnectionOutput, error) + AcceptVpcPeeringConnectionWithContext(aws.Context, *ec2.AcceptVpcPeeringConnectionInput, ...request.Option) (*ec2.AcceptVpcPeeringConnectionOutput, error) + AcceptVpcPeeringConnectionRequest(*ec2.AcceptVpcPeeringConnectionInput) (*request.Request, *ec2.AcceptVpcPeeringConnectionOutput) + + AdvertiseByoipCidr(*ec2.AdvertiseByoipCidrInput) (*ec2.AdvertiseByoipCidrOutput, error) + AdvertiseByoipCidrWithContext(aws.Context, *ec2.AdvertiseByoipCidrInput, ...request.Option) (*ec2.AdvertiseByoipCidrOutput, error) + AdvertiseByoipCidrRequest(*ec2.AdvertiseByoipCidrInput) (*request.Request, *ec2.AdvertiseByoipCidrOutput) + + AllocateAddress(*ec2.AllocateAddressInput) (*ec2.AllocateAddressOutput, error) + AllocateAddressWithContext(aws.Context, *ec2.AllocateAddressInput, ...request.Option) (*ec2.AllocateAddressOutput, error) + AllocateAddressRequest(*ec2.AllocateAddressInput) (*request.Request, *ec2.AllocateAddressOutput) + + AllocateHosts(*ec2.AllocateHostsInput) (*ec2.AllocateHostsOutput, error) + AllocateHostsWithContext(aws.Context, *ec2.AllocateHostsInput, ...request.Option) (*ec2.AllocateHostsOutput, error) + AllocateHostsRequest(*ec2.AllocateHostsInput) (*request.Request, *ec2.AllocateHostsOutput) + + AllocateIpamPoolCidr(*ec2.AllocateIpamPoolCidrInput) (*ec2.AllocateIpamPoolCidrOutput, error) + AllocateIpamPoolCidrWithContext(aws.Context, *ec2.AllocateIpamPoolCidrInput, ...request.Option) (*ec2.AllocateIpamPoolCidrOutput, error) + AllocateIpamPoolCidrRequest(*ec2.AllocateIpamPoolCidrInput) (*request.Request, *ec2.AllocateIpamPoolCidrOutput) + + ApplySecurityGroupsToClientVpnTargetNetwork(*ec2.ApplySecurityGroupsToClientVpnTargetNetworkInput) (*ec2.ApplySecurityGroupsToClientVpnTargetNetworkOutput, error) + ApplySecurityGroupsToClientVpnTargetNetworkWithContext(aws.Context, *ec2.ApplySecurityGroupsToClientVpnTargetNetworkInput, ...request.Option) (*ec2.ApplySecurityGroupsToClientVpnTargetNetworkOutput, error) + ApplySecurityGroupsToClientVpnTargetNetworkRequest(*ec2.ApplySecurityGroupsToClientVpnTargetNetworkInput) (*request.Request, *ec2.ApplySecurityGroupsToClientVpnTargetNetworkOutput) + + AssignIpv6Addresses(*ec2.AssignIpv6AddressesInput) (*ec2.AssignIpv6AddressesOutput, error) + AssignIpv6AddressesWithContext(aws.Context, *ec2.AssignIpv6AddressesInput, ...request.Option) (*ec2.AssignIpv6AddressesOutput, error) + AssignIpv6AddressesRequest(*ec2.AssignIpv6AddressesInput) (*request.Request, *ec2.AssignIpv6AddressesOutput) + + AssignPrivateIpAddresses(*ec2.AssignPrivateIpAddressesInput) (*ec2.AssignPrivateIpAddressesOutput, error) + AssignPrivateIpAddressesWithContext(aws.Context, *ec2.AssignPrivateIpAddressesInput, ...request.Option) (*ec2.AssignPrivateIpAddressesOutput, error) + AssignPrivateIpAddressesRequest(*ec2.AssignPrivateIpAddressesInput) (*request.Request, *ec2.AssignPrivateIpAddressesOutput) + + AssignPrivateNatGatewayAddress(*ec2.AssignPrivateNatGatewayAddressInput) (*ec2.AssignPrivateNatGatewayAddressOutput, error) + AssignPrivateNatGatewayAddressWithContext(aws.Context, *ec2.AssignPrivateNatGatewayAddressInput, ...request.Option) (*ec2.AssignPrivateNatGatewayAddressOutput, error) + AssignPrivateNatGatewayAddressRequest(*ec2.AssignPrivateNatGatewayAddressInput) (*request.Request, *ec2.AssignPrivateNatGatewayAddressOutput) + + AssociateAddress(*ec2.AssociateAddressInput) (*ec2.AssociateAddressOutput, error) + AssociateAddressWithContext(aws.Context, *ec2.AssociateAddressInput, ...request.Option) (*ec2.AssociateAddressOutput, error) + AssociateAddressRequest(*ec2.AssociateAddressInput) (*request.Request, *ec2.AssociateAddressOutput) + + AssociateClientVpnTargetNetwork(*ec2.AssociateClientVpnTargetNetworkInput) (*ec2.AssociateClientVpnTargetNetworkOutput, error) + AssociateClientVpnTargetNetworkWithContext(aws.Context, *ec2.AssociateClientVpnTargetNetworkInput, ...request.Option) (*ec2.AssociateClientVpnTargetNetworkOutput, error) + AssociateClientVpnTargetNetworkRequest(*ec2.AssociateClientVpnTargetNetworkInput) (*request.Request, *ec2.AssociateClientVpnTargetNetworkOutput) + + AssociateDhcpOptions(*ec2.AssociateDhcpOptionsInput) (*ec2.AssociateDhcpOptionsOutput, error) + AssociateDhcpOptionsWithContext(aws.Context, *ec2.AssociateDhcpOptionsInput, ...request.Option) (*ec2.AssociateDhcpOptionsOutput, error) + AssociateDhcpOptionsRequest(*ec2.AssociateDhcpOptionsInput) (*request.Request, *ec2.AssociateDhcpOptionsOutput) + + AssociateEnclaveCertificateIamRole(*ec2.AssociateEnclaveCertificateIamRoleInput) (*ec2.AssociateEnclaveCertificateIamRoleOutput, error) + AssociateEnclaveCertificateIamRoleWithContext(aws.Context, *ec2.AssociateEnclaveCertificateIamRoleInput, ...request.Option) (*ec2.AssociateEnclaveCertificateIamRoleOutput, error) + AssociateEnclaveCertificateIamRoleRequest(*ec2.AssociateEnclaveCertificateIamRoleInput) (*request.Request, *ec2.AssociateEnclaveCertificateIamRoleOutput) + + AssociateIamInstanceProfile(*ec2.AssociateIamInstanceProfileInput) (*ec2.AssociateIamInstanceProfileOutput, error) + AssociateIamInstanceProfileWithContext(aws.Context, *ec2.AssociateIamInstanceProfileInput, ...request.Option) (*ec2.AssociateIamInstanceProfileOutput, error) + AssociateIamInstanceProfileRequest(*ec2.AssociateIamInstanceProfileInput) (*request.Request, *ec2.AssociateIamInstanceProfileOutput) + + AssociateInstanceEventWindow(*ec2.AssociateInstanceEventWindowInput) (*ec2.AssociateInstanceEventWindowOutput, error) + AssociateInstanceEventWindowWithContext(aws.Context, *ec2.AssociateInstanceEventWindowInput, ...request.Option) (*ec2.AssociateInstanceEventWindowOutput, error) + AssociateInstanceEventWindowRequest(*ec2.AssociateInstanceEventWindowInput) (*request.Request, *ec2.AssociateInstanceEventWindowOutput) + + AssociateIpamResourceDiscovery(*ec2.AssociateIpamResourceDiscoveryInput) (*ec2.AssociateIpamResourceDiscoveryOutput, error) + AssociateIpamResourceDiscoveryWithContext(aws.Context, *ec2.AssociateIpamResourceDiscoveryInput, ...request.Option) (*ec2.AssociateIpamResourceDiscoveryOutput, error) + AssociateIpamResourceDiscoveryRequest(*ec2.AssociateIpamResourceDiscoveryInput) (*request.Request, *ec2.AssociateIpamResourceDiscoveryOutput) + + AssociateNatGatewayAddress(*ec2.AssociateNatGatewayAddressInput) (*ec2.AssociateNatGatewayAddressOutput, error) + AssociateNatGatewayAddressWithContext(aws.Context, *ec2.AssociateNatGatewayAddressInput, ...request.Option) (*ec2.AssociateNatGatewayAddressOutput, error) + AssociateNatGatewayAddressRequest(*ec2.AssociateNatGatewayAddressInput) (*request.Request, *ec2.AssociateNatGatewayAddressOutput) + + AssociateRouteTable(*ec2.AssociateRouteTableInput) (*ec2.AssociateRouteTableOutput, error) + AssociateRouteTableWithContext(aws.Context, *ec2.AssociateRouteTableInput, ...request.Option) (*ec2.AssociateRouteTableOutput, error) + AssociateRouteTableRequest(*ec2.AssociateRouteTableInput) (*request.Request, *ec2.AssociateRouteTableOutput) + + AssociateSubnetCidrBlock(*ec2.AssociateSubnetCidrBlockInput) (*ec2.AssociateSubnetCidrBlockOutput, error) + AssociateSubnetCidrBlockWithContext(aws.Context, *ec2.AssociateSubnetCidrBlockInput, ...request.Option) (*ec2.AssociateSubnetCidrBlockOutput, error) + AssociateSubnetCidrBlockRequest(*ec2.AssociateSubnetCidrBlockInput) (*request.Request, *ec2.AssociateSubnetCidrBlockOutput) + + AssociateTransitGatewayMulticastDomain(*ec2.AssociateTransitGatewayMulticastDomainInput) (*ec2.AssociateTransitGatewayMulticastDomainOutput, error) + AssociateTransitGatewayMulticastDomainWithContext(aws.Context, *ec2.AssociateTransitGatewayMulticastDomainInput, ...request.Option) (*ec2.AssociateTransitGatewayMulticastDomainOutput, error) + AssociateTransitGatewayMulticastDomainRequest(*ec2.AssociateTransitGatewayMulticastDomainInput) (*request.Request, *ec2.AssociateTransitGatewayMulticastDomainOutput) + + AssociateTransitGatewayPolicyTable(*ec2.AssociateTransitGatewayPolicyTableInput) (*ec2.AssociateTransitGatewayPolicyTableOutput, error) + AssociateTransitGatewayPolicyTableWithContext(aws.Context, *ec2.AssociateTransitGatewayPolicyTableInput, ...request.Option) (*ec2.AssociateTransitGatewayPolicyTableOutput, error) + AssociateTransitGatewayPolicyTableRequest(*ec2.AssociateTransitGatewayPolicyTableInput) (*request.Request, *ec2.AssociateTransitGatewayPolicyTableOutput) + + AssociateTransitGatewayRouteTable(*ec2.AssociateTransitGatewayRouteTableInput) (*ec2.AssociateTransitGatewayRouteTableOutput, error) + AssociateTransitGatewayRouteTableWithContext(aws.Context, *ec2.AssociateTransitGatewayRouteTableInput, ...request.Option) (*ec2.AssociateTransitGatewayRouteTableOutput, error) + AssociateTransitGatewayRouteTableRequest(*ec2.AssociateTransitGatewayRouteTableInput) (*request.Request, *ec2.AssociateTransitGatewayRouteTableOutput) + + AssociateTrunkInterface(*ec2.AssociateTrunkInterfaceInput) (*ec2.AssociateTrunkInterfaceOutput, error) + AssociateTrunkInterfaceWithContext(aws.Context, *ec2.AssociateTrunkInterfaceInput, ...request.Option) (*ec2.AssociateTrunkInterfaceOutput, error) + AssociateTrunkInterfaceRequest(*ec2.AssociateTrunkInterfaceInput) (*request.Request, *ec2.AssociateTrunkInterfaceOutput) + + AssociateVpcCidrBlock(*ec2.AssociateVpcCidrBlockInput) (*ec2.AssociateVpcCidrBlockOutput, error) + AssociateVpcCidrBlockWithContext(aws.Context, *ec2.AssociateVpcCidrBlockInput, ...request.Option) (*ec2.AssociateVpcCidrBlockOutput, error) + AssociateVpcCidrBlockRequest(*ec2.AssociateVpcCidrBlockInput) (*request.Request, *ec2.AssociateVpcCidrBlockOutput) + + AttachClassicLinkVpc(*ec2.AttachClassicLinkVpcInput) (*ec2.AttachClassicLinkVpcOutput, error) + AttachClassicLinkVpcWithContext(aws.Context, *ec2.AttachClassicLinkVpcInput, ...request.Option) (*ec2.AttachClassicLinkVpcOutput, error) + AttachClassicLinkVpcRequest(*ec2.AttachClassicLinkVpcInput) (*request.Request, *ec2.AttachClassicLinkVpcOutput) + + AttachInternetGateway(*ec2.AttachInternetGatewayInput) (*ec2.AttachInternetGatewayOutput, error) + AttachInternetGatewayWithContext(aws.Context, *ec2.AttachInternetGatewayInput, ...request.Option) (*ec2.AttachInternetGatewayOutput, error) + AttachInternetGatewayRequest(*ec2.AttachInternetGatewayInput) (*request.Request, *ec2.AttachInternetGatewayOutput) + + AttachNetworkInterface(*ec2.AttachNetworkInterfaceInput) (*ec2.AttachNetworkInterfaceOutput, error) + AttachNetworkInterfaceWithContext(aws.Context, *ec2.AttachNetworkInterfaceInput, ...request.Option) (*ec2.AttachNetworkInterfaceOutput, error) + AttachNetworkInterfaceRequest(*ec2.AttachNetworkInterfaceInput) (*request.Request, *ec2.AttachNetworkInterfaceOutput) + + AttachVerifiedAccessTrustProvider(*ec2.AttachVerifiedAccessTrustProviderInput) (*ec2.AttachVerifiedAccessTrustProviderOutput, error) + AttachVerifiedAccessTrustProviderWithContext(aws.Context, *ec2.AttachVerifiedAccessTrustProviderInput, ...request.Option) (*ec2.AttachVerifiedAccessTrustProviderOutput, error) + AttachVerifiedAccessTrustProviderRequest(*ec2.AttachVerifiedAccessTrustProviderInput) (*request.Request, *ec2.AttachVerifiedAccessTrustProviderOutput) + + AttachVolume(*ec2.AttachVolumeInput) (*ec2.VolumeAttachment, error) + AttachVolumeWithContext(aws.Context, *ec2.AttachVolumeInput, ...request.Option) (*ec2.VolumeAttachment, error) + AttachVolumeRequest(*ec2.AttachVolumeInput) (*request.Request, *ec2.VolumeAttachment) + + AttachVpnGateway(*ec2.AttachVpnGatewayInput) (*ec2.AttachVpnGatewayOutput, error) + AttachVpnGatewayWithContext(aws.Context, *ec2.AttachVpnGatewayInput, ...request.Option) (*ec2.AttachVpnGatewayOutput, error) + AttachVpnGatewayRequest(*ec2.AttachVpnGatewayInput) (*request.Request, *ec2.AttachVpnGatewayOutput) + + AuthorizeClientVpnIngress(*ec2.AuthorizeClientVpnIngressInput) (*ec2.AuthorizeClientVpnIngressOutput, error) + AuthorizeClientVpnIngressWithContext(aws.Context, *ec2.AuthorizeClientVpnIngressInput, ...request.Option) (*ec2.AuthorizeClientVpnIngressOutput, error) + AuthorizeClientVpnIngressRequest(*ec2.AuthorizeClientVpnIngressInput) (*request.Request, *ec2.AuthorizeClientVpnIngressOutput) + + AuthorizeSecurityGroupEgress(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) + AuthorizeSecurityGroupEgressWithContext(aws.Context, *ec2.AuthorizeSecurityGroupEgressInput, ...request.Option) (*ec2.AuthorizeSecurityGroupEgressOutput, error) + AuthorizeSecurityGroupEgressRequest(*ec2.AuthorizeSecurityGroupEgressInput) (*request.Request, *ec2.AuthorizeSecurityGroupEgressOutput) + + AuthorizeSecurityGroupIngress(*ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) + AuthorizeSecurityGroupIngressWithContext(aws.Context, *ec2.AuthorizeSecurityGroupIngressInput, ...request.Option) (*ec2.AuthorizeSecurityGroupIngressOutput, error) + AuthorizeSecurityGroupIngressRequest(*ec2.AuthorizeSecurityGroupIngressInput) (*request.Request, *ec2.AuthorizeSecurityGroupIngressOutput) + + BundleInstance(*ec2.BundleInstanceInput) (*ec2.BundleInstanceOutput, error) + BundleInstanceWithContext(aws.Context, *ec2.BundleInstanceInput, ...request.Option) (*ec2.BundleInstanceOutput, error) + BundleInstanceRequest(*ec2.BundleInstanceInput) (*request.Request, *ec2.BundleInstanceOutput) + + CancelBundleTask(*ec2.CancelBundleTaskInput) (*ec2.CancelBundleTaskOutput, error) + CancelBundleTaskWithContext(aws.Context, *ec2.CancelBundleTaskInput, ...request.Option) (*ec2.CancelBundleTaskOutput, error) + CancelBundleTaskRequest(*ec2.CancelBundleTaskInput) (*request.Request, *ec2.CancelBundleTaskOutput) + + CancelCapacityReservation(*ec2.CancelCapacityReservationInput) (*ec2.CancelCapacityReservationOutput, error) + CancelCapacityReservationWithContext(aws.Context, *ec2.CancelCapacityReservationInput, ...request.Option) (*ec2.CancelCapacityReservationOutput, error) + CancelCapacityReservationRequest(*ec2.CancelCapacityReservationInput) (*request.Request, *ec2.CancelCapacityReservationOutput) + + CancelCapacityReservationFleets(*ec2.CancelCapacityReservationFleetsInput) (*ec2.CancelCapacityReservationFleetsOutput, error) + CancelCapacityReservationFleetsWithContext(aws.Context, *ec2.CancelCapacityReservationFleetsInput, ...request.Option) (*ec2.CancelCapacityReservationFleetsOutput, error) + CancelCapacityReservationFleetsRequest(*ec2.CancelCapacityReservationFleetsInput) (*request.Request, *ec2.CancelCapacityReservationFleetsOutput) + + CancelConversionTask(*ec2.CancelConversionTaskInput) (*ec2.CancelConversionTaskOutput, error) + CancelConversionTaskWithContext(aws.Context, *ec2.CancelConversionTaskInput, ...request.Option) (*ec2.CancelConversionTaskOutput, error) + CancelConversionTaskRequest(*ec2.CancelConversionTaskInput) (*request.Request, *ec2.CancelConversionTaskOutput) + + CancelExportTask(*ec2.CancelExportTaskInput) (*ec2.CancelExportTaskOutput, error) + CancelExportTaskWithContext(aws.Context, *ec2.CancelExportTaskInput, ...request.Option) (*ec2.CancelExportTaskOutput, error) + CancelExportTaskRequest(*ec2.CancelExportTaskInput) (*request.Request, *ec2.CancelExportTaskOutput) + + CancelImageLaunchPermission(*ec2.CancelImageLaunchPermissionInput) (*ec2.CancelImageLaunchPermissionOutput, error) + CancelImageLaunchPermissionWithContext(aws.Context, *ec2.CancelImageLaunchPermissionInput, ...request.Option) (*ec2.CancelImageLaunchPermissionOutput, error) + CancelImageLaunchPermissionRequest(*ec2.CancelImageLaunchPermissionInput) (*request.Request, *ec2.CancelImageLaunchPermissionOutput) + + CancelImportTask(*ec2.CancelImportTaskInput) (*ec2.CancelImportTaskOutput, error) + CancelImportTaskWithContext(aws.Context, *ec2.CancelImportTaskInput, ...request.Option) (*ec2.CancelImportTaskOutput, error) + CancelImportTaskRequest(*ec2.CancelImportTaskInput) (*request.Request, *ec2.CancelImportTaskOutput) + + CancelReservedInstancesListing(*ec2.CancelReservedInstancesListingInput) (*ec2.CancelReservedInstancesListingOutput, error) + CancelReservedInstancesListingWithContext(aws.Context, *ec2.CancelReservedInstancesListingInput, ...request.Option) (*ec2.CancelReservedInstancesListingOutput, error) + CancelReservedInstancesListingRequest(*ec2.CancelReservedInstancesListingInput) (*request.Request, *ec2.CancelReservedInstancesListingOutput) + + CancelSpotFleetRequests(*ec2.CancelSpotFleetRequestsInput) (*ec2.CancelSpotFleetRequestsOutput, error) + CancelSpotFleetRequestsWithContext(aws.Context, *ec2.CancelSpotFleetRequestsInput, ...request.Option) (*ec2.CancelSpotFleetRequestsOutput, error) + CancelSpotFleetRequestsRequest(*ec2.CancelSpotFleetRequestsInput) (*request.Request, *ec2.CancelSpotFleetRequestsOutput) + + CancelSpotInstanceRequests(*ec2.CancelSpotInstanceRequestsInput) (*ec2.CancelSpotInstanceRequestsOutput, error) + CancelSpotInstanceRequestsWithContext(aws.Context, *ec2.CancelSpotInstanceRequestsInput, ...request.Option) (*ec2.CancelSpotInstanceRequestsOutput, error) + CancelSpotInstanceRequestsRequest(*ec2.CancelSpotInstanceRequestsInput) (*request.Request, *ec2.CancelSpotInstanceRequestsOutput) + + ConfirmProductInstance(*ec2.ConfirmProductInstanceInput) (*ec2.ConfirmProductInstanceOutput, error) + ConfirmProductInstanceWithContext(aws.Context, *ec2.ConfirmProductInstanceInput, ...request.Option) (*ec2.ConfirmProductInstanceOutput, error) + ConfirmProductInstanceRequest(*ec2.ConfirmProductInstanceInput) (*request.Request, *ec2.ConfirmProductInstanceOutput) + + CopyFpgaImage(*ec2.CopyFpgaImageInput) (*ec2.CopyFpgaImageOutput, error) + CopyFpgaImageWithContext(aws.Context, *ec2.CopyFpgaImageInput, ...request.Option) (*ec2.CopyFpgaImageOutput, error) + CopyFpgaImageRequest(*ec2.CopyFpgaImageInput) (*request.Request, *ec2.CopyFpgaImageOutput) + + CopyImage(*ec2.CopyImageInput) (*ec2.CopyImageOutput, error) + CopyImageWithContext(aws.Context, *ec2.CopyImageInput, ...request.Option) (*ec2.CopyImageOutput, error) + CopyImageRequest(*ec2.CopyImageInput) (*request.Request, *ec2.CopyImageOutput) + + CopySnapshot(*ec2.CopySnapshotInput) (*ec2.CopySnapshotOutput, error) + CopySnapshotWithContext(aws.Context, *ec2.CopySnapshotInput, ...request.Option) (*ec2.CopySnapshotOutput, error) + CopySnapshotRequest(*ec2.CopySnapshotInput) (*request.Request, *ec2.CopySnapshotOutput) + + CreateCapacityReservation(*ec2.CreateCapacityReservationInput) (*ec2.CreateCapacityReservationOutput, error) + CreateCapacityReservationWithContext(aws.Context, *ec2.CreateCapacityReservationInput, ...request.Option) (*ec2.CreateCapacityReservationOutput, error) + CreateCapacityReservationRequest(*ec2.CreateCapacityReservationInput) (*request.Request, *ec2.CreateCapacityReservationOutput) + + CreateCapacityReservationFleet(*ec2.CreateCapacityReservationFleetInput) (*ec2.CreateCapacityReservationFleetOutput, error) + CreateCapacityReservationFleetWithContext(aws.Context, *ec2.CreateCapacityReservationFleetInput, ...request.Option) (*ec2.CreateCapacityReservationFleetOutput, error) + CreateCapacityReservationFleetRequest(*ec2.CreateCapacityReservationFleetInput) (*request.Request, *ec2.CreateCapacityReservationFleetOutput) + + CreateCarrierGateway(*ec2.CreateCarrierGatewayInput) (*ec2.CreateCarrierGatewayOutput, error) + CreateCarrierGatewayWithContext(aws.Context, *ec2.CreateCarrierGatewayInput, ...request.Option) (*ec2.CreateCarrierGatewayOutput, error) + CreateCarrierGatewayRequest(*ec2.CreateCarrierGatewayInput) (*request.Request, *ec2.CreateCarrierGatewayOutput) + + CreateClientVpnEndpoint(*ec2.CreateClientVpnEndpointInput) (*ec2.CreateClientVpnEndpointOutput, error) + CreateClientVpnEndpointWithContext(aws.Context, *ec2.CreateClientVpnEndpointInput, ...request.Option) (*ec2.CreateClientVpnEndpointOutput, error) + CreateClientVpnEndpointRequest(*ec2.CreateClientVpnEndpointInput) (*request.Request, *ec2.CreateClientVpnEndpointOutput) + + CreateClientVpnRoute(*ec2.CreateClientVpnRouteInput) (*ec2.CreateClientVpnRouteOutput, error) + CreateClientVpnRouteWithContext(aws.Context, *ec2.CreateClientVpnRouteInput, ...request.Option) (*ec2.CreateClientVpnRouteOutput, error) + CreateClientVpnRouteRequest(*ec2.CreateClientVpnRouteInput) (*request.Request, *ec2.CreateClientVpnRouteOutput) + + CreateCoipCidr(*ec2.CreateCoipCidrInput) (*ec2.CreateCoipCidrOutput, error) + CreateCoipCidrWithContext(aws.Context, *ec2.CreateCoipCidrInput, ...request.Option) (*ec2.CreateCoipCidrOutput, error) + CreateCoipCidrRequest(*ec2.CreateCoipCidrInput) (*request.Request, *ec2.CreateCoipCidrOutput) + + CreateCoipPool(*ec2.CreateCoipPoolInput) (*ec2.CreateCoipPoolOutput, error) + CreateCoipPoolWithContext(aws.Context, *ec2.CreateCoipPoolInput, ...request.Option) (*ec2.CreateCoipPoolOutput, error) + CreateCoipPoolRequest(*ec2.CreateCoipPoolInput) (*request.Request, *ec2.CreateCoipPoolOutput) + + CreateCustomerGateway(*ec2.CreateCustomerGatewayInput) (*ec2.CreateCustomerGatewayOutput, error) + CreateCustomerGatewayWithContext(aws.Context, *ec2.CreateCustomerGatewayInput, ...request.Option) (*ec2.CreateCustomerGatewayOutput, error) + CreateCustomerGatewayRequest(*ec2.CreateCustomerGatewayInput) (*request.Request, *ec2.CreateCustomerGatewayOutput) + + CreateDefaultSubnet(*ec2.CreateDefaultSubnetInput) (*ec2.CreateDefaultSubnetOutput, error) + CreateDefaultSubnetWithContext(aws.Context, *ec2.CreateDefaultSubnetInput, ...request.Option) (*ec2.CreateDefaultSubnetOutput, error) + CreateDefaultSubnetRequest(*ec2.CreateDefaultSubnetInput) (*request.Request, *ec2.CreateDefaultSubnetOutput) + + CreateDefaultVpc(*ec2.CreateDefaultVpcInput) (*ec2.CreateDefaultVpcOutput, error) + CreateDefaultVpcWithContext(aws.Context, *ec2.CreateDefaultVpcInput, ...request.Option) (*ec2.CreateDefaultVpcOutput, error) + CreateDefaultVpcRequest(*ec2.CreateDefaultVpcInput) (*request.Request, *ec2.CreateDefaultVpcOutput) + + CreateDhcpOptions(*ec2.CreateDhcpOptionsInput) (*ec2.CreateDhcpOptionsOutput, error) + CreateDhcpOptionsWithContext(aws.Context, *ec2.CreateDhcpOptionsInput, ...request.Option) (*ec2.CreateDhcpOptionsOutput, error) + CreateDhcpOptionsRequest(*ec2.CreateDhcpOptionsInput) (*request.Request, *ec2.CreateDhcpOptionsOutput) + + CreateEgressOnlyInternetGateway(*ec2.CreateEgressOnlyInternetGatewayInput) (*ec2.CreateEgressOnlyInternetGatewayOutput, error) + CreateEgressOnlyInternetGatewayWithContext(aws.Context, *ec2.CreateEgressOnlyInternetGatewayInput, ...request.Option) (*ec2.CreateEgressOnlyInternetGatewayOutput, error) + CreateEgressOnlyInternetGatewayRequest(*ec2.CreateEgressOnlyInternetGatewayInput) (*request.Request, *ec2.CreateEgressOnlyInternetGatewayOutput) + + CreateFleet(*ec2.CreateFleetInput) (*ec2.CreateFleetOutput, error) + CreateFleetWithContext(aws.Context, *ec2.CreateFleetInput, ...request.Option) (*ec2.CreateFleetOutput, error) + CreateFleetRequest(*ec2.CreateFleetInput) (*request.Request, *ec2.CreateFleetOutput) + + CreateFlowLogs(*ec2.CreateFlowLogsInput) (*ec2.CreateFlowLogsOutput, error) + CreateFlowLogsWithContext(aws.Context, *ec2.CreateFlowLogsInput, ...request.Option) (*ec2.CreateFlowLogsOutput, error) + CreateFlowLogsRequest(*ec2.CreateFlowLogsInput) (*request.Request, *ec2.CreateFlowLogsOutput) + + CreateFpgaImage(*ec2.CreateFpgaImageInput) (*ec2.CreateFpgaImageOutput, error) + CreateFpgaImageWithContext(aws.Context, *ec2.CreateFpgaImageInput, ...request.Option) (*ec2.CreateFpgaImageOutput, error) + CreateFpgaImageRequest(*ec2.CreateFpgaImageInput) (*request.Request, *ec2.CreateFpgaImageOutput) + + CreateImage(*ec2.CreateImageInput) (*ec2.CreateImageOutput, error) + CreateImageWithContext(aws.Context, *ec2.CreateImageInput, ...request.Option) (*ec2.CreateImageOutput, error) + CreateImageRequest(*ec2.CreateImageInput) (*request.Request, *ec2.CreateImageOutput) + + CreateInstanceConnectEndpoint(*ec2.CreateInstanceConnectEndpointInput) (*ec2.CreateInstanceConnectEndpointOutput, error) + CreateInstanceConnectEndpointWithContext(aws.Context, *ec2.CreateInstanceConnectEndpointInput, ...request.Option) (*ec2.CreateInstanceConnectEndpointOutput, error) + CreateInstanceConnectEndpointRequest(*ec2.CreateInstanceConnectEndpointInput) (*request.Request, *ec2.CreateInstanceConnectEndpointOutput) + + CreateInstanceEventWindow(*ec2.CreateInstanceEventWindowInput) (*ec2.CreateInstanceEventWindowOutput, error) + CreateInstanceEventWindowWithContext(aws.Context, *ec2.CreateInstanceEventWindowInput, ...request.Option) (*ec2.CreateInstanceEventWindowOutput, error) + CreateInstanceEventWindowRequest(*ec2.CreateInstanceEventWindowInput) (*request.Request, *ec2.CreateInstanceEventWindowOutput) + + CreateInstanceExportTask(*ec2.CreateInstanceExportTaskInput) (*ec2.CreateInstanceExportTaskOutput, error) + CreateInstanceExportTaskWithContext(aws.Context, *ec2.CreateInstanceExportTaskInput, ...request.Option) (*ec2.CreateInstanceExportTaskOutput, error) + CreateInstanceExportTaskRequest(*ec2.CreateInstanceExportTaskInput) (*request.Request, *ec2.CreateInstanceExportTaskOutput) + + CreateInternetGateway(*ec2.CreateInternetGatewayInput) (*ec2.CreateInternetGatewayOutput, error) + CreateInternetGatewayWithContext(aws.Context, *ec2.CreateInternetGatewayInput, ...request.Option) (*ec2.CreateInternetGatewayOutput, error) + CreateInternetGatewayRequest(*ec2.CreateInternetGatewayInput) (*request.Request, *ec2.CreateInternetGatewayOutput) + + CreateIpam(*ec2.CreateIpamInput) (*ec2.CreateIpamOutput, error) + CreateIpamWithContext(aws.Context, *ec2.CreateIpamInput, ...request.Option) (*ec2.CreateIpamOutput, error) + CreateIpamRequest(*ec2.CreateIpamInput) (*request.Request, *ec2.CreateIpamOutput) + + CreateIpamPool(*ec2.CreateIpamPoolInput) (*ec2.CreateIpamPoolOutput, error) + CreateIpamPoolWithContext(aws.Context, *ec2.CreateIpamPoolInput, ...request.Option) (*ec2.CreateIpamPoolOutput, error) + CreateIpamPoolRequest(*ec2.CreateIpamPoolInput) (*request.Request, *ec2.CreateIpamPoolOutput) + + CreateIpamResourceDiscovery(*ec2.CreateIpamResourceDiscoveryInput) (*ec2.CreateIpamResourceDiscoveryOutput, error) + CreateIpamResourceDiscoveryWithContext(aws.Context, *ec2.CreateIpamResourceDiscoveryInput, ...request.Option) (*ec2.CreateIpamResourceDiscoveryOutput, error) + CreateIpamResourceDiscoveryRequest(*ec2.CreateIpamResourceDiscoveryInput) (*request.Request, *ec2.CreateIpamResourceDiscoveryOutput) + + CreateIpamScope(*ec2.CreateIpamScopeInput) (*ec2.CreateIpamScopeOutput, error) + CreateIpamScopeWithContext(aws.Context, *ec2.CreateIpamScopeInput, ...request.Option) (*ec2.CreateIpamScopeOutput, error) + CreateIpamScopeRequest(*ec2.CreateIpamScopeInput) (*request.Request, *ec2.CreateIpamScopeOutput) + + CreateKeyPair(*ec2.CreateKeyPairInput) (*ec2.CreateKeyPairOutput, error) + CreateKeyPairWithContext(aws.Context, *ec2.CreateKeyPairInput, ...request.Option) (*ec2.CreateKeyPairOutput, error) + CreateKeyPairRequest(*ec2.CreateKeyPairInput) (*request.Request, *ec2.CreateKeyPairOutput) + + CreateLaunchTemplate(*ec2.CreateLaunchTemplateInput) (*ec2.CreateLaunchTemplateOutput, error) + CreateLaunchTemplateWithContext(aws.Context, *ec2.CreateLaunchTemplateInput, ...request.Option) (*ec2.CreateLaunchTemplateOutput, error) + CreateLaunchTemplateRequest(*ec2.CreateLaunchTemplateInput) (*request.Request, *ec2.CreateLaunchTemplateOutput) + + CreateLaunchTemplateVersion(*ec2.CreateLaunchTemplateVersionInput) (*ec2.CreateLaunchTemplateVersionOutput, error) + CreateLaunchTemplateVersionWithContext(aws.Context, *ec2.CreateLaunchTemplateVersionInput, ...request.Option) (*ec2.CreateLaunchTemplateVersionOutput, error) + CreateLaunchTemplateVersionRequest(*ec2.CreateLaunchTemplateVersionInput) (*request.Request, *ec2.CreateLaunchTemplateVersionOutput) + + CreateLocalGatewayRoute(*ec2.CreateLocalGatewayRouteInput) (*ec2.CreateLocalGatewayRouteOutput, error) + CreateLocalGatewayRouteWithContext(aws.Context, *ec2.CreateLocalGatewayRouteInput, ...request.Option) (*ec2.CreateLocalGatewayRouteOutput, error) + CreateLocalGatewayRouteRequest(*ec2.CreateLocalGatewayRouteInput) (*request.Request, *ec2.CreateLocalGatewayRouteOutput) + + CreateLocalGatewayRouteTable(*ec2.CreateLocalGatewayRouteTableInput) (*ec2.CreateLocalGatewayRouteTableOutput, error) + CreateLocalGatewayRouteTableWithContext(aws.Context, *ec2.CreateLocalGatewayRouteTableInput, ...request.Option) (*ec2.CreateLocalGatewayRouteTableOutput, error) + CreateLocalGatewayRouteTableRequest(*ec2.CreateLocalGatewayRouteTableInput) (*request.Request, *ec2.CreateLocalGatewayRouteTableOutput) + + CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociation(*ec2.CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationInput) (*ec2.CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationOutput, error) + CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationWithContext(aws.Context, *ec2.CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationInput, ...request.Option) (*ec2.CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationOutput, error) + CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationRequest(*ec2.CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationInput) (*request.Request, *ec2.CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationOutput) + + CreateLocalGatewayRouteTableVpcAssociation(*ec2.CreateLocalGatewayRouteTableVpcAssociationInput) (*ec2.CreateLocalGatewayRouteTableVpcAssociationOutput, error) + CreateLocalGatewayRouteTableVpcAssociationWithContext(aws.Context, *ec2.CreateLocalGatewayRouteTableVpcAssociationInput, ...request.Option) (*ec2.CreateLocalGatewayRouteTableVpcAssociationOutput, error) + CreateLocalGatewayRouteTableVpcAssociationRequest(*ec2.CreateLocalGatewayRouteTableVpcAssociationInput) (*request.Request, *ec2.CreateLocalGatewayRouteTableVpcAssociationOutput) + + CreateManagedPrefixList(*ec2.CreateManagedPrefixListInput) (*ec2.CreateManagedPrefixListOutput, error) + CreateManagedPrefixListWithContext(aws.Context, *ec2.CreateManagedPrefixListInput, ...request.Option) (*ec2.CreateManagedPrefixListOutput, error) + CreateManagedPrefixListRequest(*ec2.CreateManagedPrefixListInput) (*request.Request, *ec2.CreateManagedPrefixListOutput) + + CreateNatGateway(*ec2.CreateNatGatewayInput) (*ec2.CreateNatGatewayOutput, error) + CreateNatGatewayWithContext(aws.Context, *ec2.CreateNatGatewayInput, ...request.Option) (*ec2.CreateNatGatewayOutput, error) + CreateNatGatewayRequest(*ec2.CreateNatGatewayInput) (*request.Request, *ec2.CreateNatGatewayOutput) + + CreateNetworkAcl(*ec2.CreateNetworkAclInput) (*ec2.CreateNetworkAclOutput, error) + CreateNetworkAclWithContext(aws.Context, *ec2.CreateNetworkAclInput, ...request.Option) (*ec2.CreateNetworkAclOutput, error) + CreateNetworkAclRequest(*ec2.CreateNetworkAclInput) (*request.Request, *ec2.CreateNetworkAclOutput) + + CreateNetworkAclEntry(*ec2.CreateNetworkAclEntryInput) (*ec2.CreateNetworkAclEntryOutput, error) + CreateNetworkAclEntryWithContext(aws.Context, *ec2.CreateNetworkAclEntryInput, ...request.Option) (*ec2.CreateNetworkAclEntryOutput, error) + CreateNetworkAclEntryRequest(*ec2.CreateNetworkAclEntryInput) (*request.Request, *ec2.CreateNetworkAclEntryOutput) + + CreateNetworkInsightsAccessScope(*ec2.CreateNetworkInsightsAccessScopeInput) (*ec2.CreateNetworkInsightsAccessScopeOutput, error) + CreateNetworkInsightsAccessScopeWithContext(aws.Context, *ec2.CreateNetworkInsightsAccessScopeInput, ...request.Option) (*ec2.CreateNetworkInsightsAccessScopeOutput, error) + CreateNetworkInsightsAccessScopeRequest(*ec2.CreateNetworkInsightsAccessScopeInput) (*request.Request, *ec2.CreateNetworkInsightsAccessScopeOutput) + + CreateNetworkInsightsPath(*ec2.CreateNetworkInsightsPathInput) (*ec2.CreateNetworkInsightsPathOutput, error) + CreateNetworkInsightsPathWithContext(aws.Context, *ec2.CreateNetworkInsightsPathInput, ...request.Option) (*ec2.CreateNetworkInsightsPathOutput, error) + CreateNetworkInsightsPathRequest(*ec2.CreateNetworkInsightsPathInput) (*request.Request, *ec2.CreateNetworkInsightsPathOutput) + + CreateNetworkInterface(*ec2.CreateNetworkInterfaceInput) (*ec2.CreateNetworkInterfaceOutput, error) + CreateNetworkInterfaceWithContext(aws.Context, *ec2.CreateNetworkInterfaceInput, ...request.Option) (*ec2.CreateNetworkInterfaceOutput, error) + CreateNetworkInterfaceRequest(*ec2.CreateNetworkInterfaceInput) (*request.Request, *ec2.CreateNetworkInterfaceOutput) + + CreateNetworkInterfacePermission(*ec2.CreateNetworkInterfacePermissionInput) (*ec2.CreateNetworkInterfacePermissionOutput, error) + CreateNetworkInterfacePermissionWithContext(aws.Context, *ec2.CreateNetworkInterfacePermissionInput, ...request.Option) (*ec2.CreateNetworkInterfacePermissionOutput, error) + CreateNetworkInterfacePermissionRequest(*ec2.CreateNetworkInterfacePermissionInput) (*request.Request, *ec2.CreateNetworkInterfacePermissionOutput) + + CreatePlacementGroup(*ec2.CreatePlacementGroupInput) (*ec2.CreatePlacementGroupOutput, error) + CreatePlacementGroupWithContext(aws.Context, *ec2.CreatePlacementGroupInput, ...request.Option) (*ec2.CreatePlacementGroupOutput, error) + CreatePlacementGroupRequest(*ec2.CreatePlacementGroupInput) (*request.Request, *ec2.CreatePlacementGroupOutput) + + CreatePublicIpv4Pool(*ec2.CreatePublicIpv4PoolInput) (*ec2.CreatePublicIpv4PoolOutput, error) + CreatePublicIpv4PoolWithContext(aws.Context, *ec2.CreatePublicIpv4PoolInput, ...request.Option) (*ec2.CreatePublicIpv4PoolOutput, error) + CreatePublicIpv4PoolRequest(*ec2.CreatePublicIpv4PoolInput) (*request.Request, *ec2.CreatePublicIpv4PoolOutput) + + CreateReplaceRootVolumeTask(*ec2.CreateReplaceRootVolumeTaskInput) (*ec2.CreateReplaceRootVolumeTaskOutput, error) + CreateReplaceRootVolumeTaskWithContext(aws.Context, *ec2.CreateReplaceRootVolumeTaskInput, ...request.Option) (*ec2.CreateReplaceRootVolumeTaskOutput, error) + CreateReplaceRootVolumeTaskRequest(*ec2.CreateReplaceRootVolumeTaskInput) (*request.Request, *ec2.CreateReplaceRootVolumeTaskOutput) + + CreateReservedInstancesListing(*ec2.CreateReservedInstancesListingInput) (*ec2.CreateReservedInstancesListingOutput, error) + CreateReservedInstancesListingWithContext(aws.Context, *ec2.CreateReservedInstancesListingInput, ...request.Option) (*ec2.CreateReservedInstancesListingOutput, error) + CreateReservedInstancesListingRequest(*ec2.CreateReservedInstancesListingInput) (*request.Request, *ec2.CreateReservedInstancesListingOutput) + + CreateRestoreImageTask(*ec2.CreateRestoreImageTaskInput) (*ec2.CreateRestoreImageTaskOutput, error) + CreateRestoreImageTaskWithContext(aws.Context, *ec2.CreateRestoreImageTaskInput, ...request.Option) (*ec2.CreateRestoreImageTaskOutput, error) + CreateRestoreImageTaskRequest(*ec2.CreateRestoreImageTaskInput) (*request.Request, *ec2.CreateRestoreImageTaskOutput) + + CreateRoute(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error) + CreateRouteWithContext(aws.Context, *ec2.CreateRouteInput, ...request.Option) (*ec2.CreateRouteOutput, error) + CreateRouteRequest(*ec2.CreateRouteInput) (*request.Request, *ec2.CreateRouteOutput) + + CreateRouteTable(*ec2.CreateRouteTableInput) (*ec2.CreateRouteTableOutput, error) + CreateRouteTableWithContext(aws.Context, *ec2.CreateRouteTableInput, ...request.Option) (*ec2.CreateRouteTableOutput, error) + CreateRouteTableRequest(*ec2.CreateRouteTableInput) (*request.Request, *ec2.CreateRouteTableOutput) + + CreateSecurityGroup(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) + CreateSecurityGroupWithContext(aws.Context, *ec2.CreateSecurityGroupInput, ...request.Option) (*ec2.CreateSecurityGroupOutput, error) + CreateSecurityGroupRequest(*ec2.CreateSecurityGroupInput) (*request.Request, *ec2.CreateSecurityGroupOutput) + + CreateSnapshot(*ec2.CreateSnapshotInput) (*ec2.Snapshot, error) + CreateSnapshotWithContext(aws.Context, *ec2.CreateSnapshotInput, ...request.Option) (*ec2.Snapshot, error) + CreateSnapshotRequest(*ec2.CreateSnapshotInput) (*request.Request, *ec2.Snapshot) + + CreateSnapshots(*ec2.CreateSnapshotsInput) (*ec2.CreateSnapshotsOutput, error) + CreateSnapshotsWithContext(aws.Context, *ec2.CreateSnapshotsInput, ...request.Option) (*ec2.CreateSnapshotsOutput, error) + CreateSnapshotsRequest(*ec2.CreateSnapshotsInput) (*request.Request, *ec2.CreateSnapshotsOutput) + + CreateSpotDatafeedSubscription(*ec2.CreateSpotDatafeedSubscriptionInput) (*ec2.CreateSpotDatafeedSubscriptionOutput, error) + CreateSpotDatafeedSubscriptionWithContext(aws.Context, *ec2.CreateSpotDatafeedSubscriptionInput, ...request.Option) (*ec2.CreateSpotDatafeedSubscriptionOutput, error) + CreateSpotDatafeedSubscriptionRequest(*ec2.CreateSpotDatafeedSubscriptionInput) (*request.Request, *ec2.CreateSpotDatafeedSubscriptionOutput) + + CreateStoreImageTask(*ec2.CreateStoreImageTaskInput) (*ec2.CreateStoreImageTaskOutput, error) + CreateStoreImageTaskWithContext(aws.Context, *ec2.CreateStoreImageTaskInput, ...request.Option) (*ec2.CreateStoreImageTaskOutput, error) + CreateStoreImageTaskRequest(*ec2.CreateStoreImageTaskInput) (*request.Request, *ec2.CreateStoreImageTaskOutput) + + CreateSubnet(*ec2.CreateSubnetInput) (*ec2.CreateSubnetOutput, error) + CreateSubnetWithContext(aws.Context, *ec2.CreateSubnetInput, ...request.Option) (*ec2.CreateSubnetOutput, error) + CreateSubnetRequest(*ec2.CreateSubnetInput) (*request.Request, *ec2.CreateSubnetOutput) + + CreateSubnetCidrReservation(*ec2.CreateSubnetCidrReservationInput) (*ec2.CreateSubnetCidrReservationOutput, error) + CreateSubnetCidrReservationWithContext(aws.Context, *ec2.CreateSubnetCidrReservationInput, ...request.Option) (*ec2.CreateSubnetCidrReservationOutput, error) + CreateSubnetCidrReservationRequest(*ec2.CreateSubnetCidrReservationInput) (*request.Request, *ec2.CreateSubnetCidrReservationOutput) + + CreateTags(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) + CreateTagsWithContext(aws.Context, *ec2.CreateTagsInput, ...request.Option) (*ec2.CreateTagsOutput, error) + CreateTagsRequest(*ec2.CreateTagsInput) (*request.Request, *ec2.CreateTagsOutput) + + CreateTrafficMirrorFilter(*ec2.CreateTrafficMirrorFilterInput) (*ec2.CreateTrafficMirrorFilterOutput, error) + CreateTrafficMirrorFilterWithContext(aws.Context, *ec2.CreateTrafficMirrorFilterInput, ...request.Option) (*ec2.CreateTrafficMirrorFilterOutput, error) + CreateTrafficMirrorFilterRequest(*ec2.CreateTrafficMirrorFilterInput) (*request.Request, *ec2.CreateTrafficMirrorFilterOutput) + + CreateTrafficMirrorFilterRule(*ec2.CreateTrafficMirrorFilterRuleInput) (*ec2.CreateTrafficMirrorFilterRuleOutput, error) + CreateTrafficMirrorFilterRuleWithContext(aws.Context, *ec2.CreateTrafficMirrorFilterRuleInput, ...request.Option) (*ec2.CreateTrafficMirrorFilterRuleOutput, error) + CreateTrafficMirrorFilterRuleRequest(*ec2.CreateTrafficMirrorFilterRuleInput) (*request.Request, *ec2.CreateTrafficMirrorFilterRuleOutput) + + CreateTrafficMirrorSession(*ec2.CreateTrafficMirrorSessionInput) (*ec2.CreateTrafficMirrorSessionOutput, error) + CreateTrafficMirrorSessionWithContext(aws.Context, *ec2.CreateTrafficMirrorSessionInput, ...request.Option) (*ec2.CreateTrafficMirrorSessionOutput, error) + CreateTrafficMirrorSessionRequest(*ec2.CreateTrafficMirrorSessionInput) (*request.Request, *ec2.CreateTrafficMirrorSessionOutput) + + CreateTrafficMirrorTarget(*ec2.CreateTrafficMirrorTargetInput) (*ec2.CreateTrafficMirrorTargetOutput, error) + CreateTrafficMirrorTargetWithContext(aws.Context, *ec2.CreateTrafficMirrorTargetInput, ...request.Option) (*ec2.CreateTrafficMirrorTargetOutput, error) + CreateTrafficMirrorTargetRequest(*ec2.CreateTrafficMirrorTargetInput) (*request.Request, *ec2.CreateTrafficMirrorTargetOutput) + + CreateTransitGateway(*ec2.CreateTransitGatewayInput) (*ec2.CreateTransitGatewayOutput, error) + CreateTransitGatewayWithContext(aws.Context, *ec2.CreateTransitGatewayInput, ...request.Option) (*ec2.CreateTransitGatewayOutput, error) + CreateTransitGatewayRequest(*ec2.CreateTransitGatewayInput) (*request.Request, *ec2.CreateTransitGatewayOutput) + + CreateTransitGatewayConnect(*ec2.CreateTransitGatewayConnectInput) (*ec2.CreateTransitGatewayConnectOutput, error) + CreateTransitGatewayConnectWithContext(aws.Context, *ec2.CreateTransitGatewayConnectInput, ...request.Option) (*ec2.CreateTransitGatewayConnectOutput, error) + CreateTransitGatewayConnectRequest(*ec2.CreateTransitGatewayConnectInput) (*request.Request, *ec2.CreateTransitGatewayConnectOutput) + + CreateTransitGatewayConnectPeer(*ec2.CreateTransitGatewayConnectPeerInput) (*ec2.CreateTransitGatewayConnectPeerOutput, error) + CreateTransitGatewayConnectPeerWithContext(aws.Context, *ec2.CreateTransitGatewayConnectPeerInput, ...request.Option) (*ec2.CreateTransitGatewayConnectPeerOutput, error) + CreateTransitGatewayConnectPeerRequest(*ec2.CreateTransitGatewayConnectPeerInput) (*request.Request, *ec2.CreateTransitGatewayConnectPeerOutput) + + CreateTransitGatewayMulticastDomain(*ec2.CreateTransitGatewayMulticastDomainInput) (*ec2.CreateTransitGatewayMulticastDomainOutput, error) + CreateTransitGatewayMulticastDomainWithContext(aws.Context, *ec2.CreateTransitGatewayMulticastDomainInput, ...request.Option) (*ec2.CreateTransitGatewayMulticastDomainOutput, error) + CreateTransitGatewayMulticastDomainRequest(*ec2.CreateTransitGatewayMulticastDomainInput) (*request.Request, *ec2.CreateTransitGatewayMulticastDomainOutput) + + CreateTransitGatewayPeeringAttachment(*ec2.CreateTransitGatewayPeeringAttachmentInput) (*ec2.CreateTransitGatewayPeeringAttachmentOutput, error) + CreateTransitGatewayPeeringAttachmentWithContext(aws.Context, *ec2.CreateTransitGatewayPeeringAttachmentInput, ...request.Option) (*ec2.CreateTransitGatewayPeeringAttachmentOutput, error) + CreateTransitGatewayPeeringAttachmentRequest(*ec2.CreateTransitGatewayPeeringAttachmentInput) (*request.Request, *ec2.CreateTransitGatewayPeeringAttachmentOutput) + + CreateTransitGatewayPolicyTable(*ec2.CreateTransitGatewayPolicyTableInput) (*ec2.CreateTransitGatewayPolicyTableOutput, error) + CreateTransitGatewayPolicyTableWithContext(aws.Context, *ec2.CreateTransitGatewayPolicyTableInput, ...request.Option) (*ec2.CreateTransitGatewayPolicyTableOutput, error) + CreateTransitGatewayPolicyTableRequest(*ec2.CreateTransitGatewayPolicyTableInput) (*request.Request, *ec2.CreateTransitGatewayPolicyTableOutput) + + CreateTransitGatewayPrefixListReference(*ec2.CreateTransitGatewayPrefixListReferenceInput) (*ec2.CreateTransitGatewayPrefixListReferenceOutput, error) + CreateTransitGatewayPrefixListReferenceWithContext(aws.Context, *ec2.CreateTransitGatewayPrefixListReferenceInput, ...request.Option) (*ec2.CreateTransitGatewayPrefixListReferenceOutput, error) + CreateTransitGatewayPrefixListReferenceRequest(*ec2.CreateTransitGatewayPrefixListReferenceInput) (*request.Request, *ec2.CreateTransitGatewayPrefixListReferenceOutput) + + CreateTransitGatewayRoute(*ec2.CreateTransitGatewayRouteInput) (*ec2.CreateTransitGatewayRouteOutput, error) + CreateTransitGatewayRouteWithContext(aws.Context, *ec2.CreateTransitGatewayRouteInput, ...request.Option) (*ec2.CreateTransitGatewayRouteOutput, error) + CreateTransitGatewayRouteRequest(*ec2.CreateTransitGatewayRouteInput) (*request.Request, *ec2.CreateTransitGatewayRouteOutput) + + CreateTransitGatewayRouteTable(*ec2.CreateTransitGatewayRouteTableInput) (*ec2.CreateTransitGatewayRouteTableOutput, error) + CreateTransitGatewayRouteTableWithContext(aws.Context, *ec2.CreateTransitGatewayRouteTableInput, ...request.Option) (*ec2.CreateTransitGatewayRouteTableOutput, error) + CreateTransitGatewayRouteTableRequest(*ec2.CreateTransitGatewayRouteTableInput) (*request.Request, *ec2.CreateTransitGatewayRouteTableOutput) + + CreateTransitGatewayRouteTableAnnouncement(*ec2.CreateTransitGatewayRouteTableAnnouncementInput) (*ec2.CreateTransitGatewayRouteTableAnnouncementOutput, error) + CreateTransitGatewayRouteTableAnnouncementWithContext(aws.Context, *ec2.CreateTransitGatewayRouteTableAnnouncementInput, ...request.Option) (*ec2.CreateTransitGatewayRouteTableAnnouncementOutput, error) + CreateTransitGatewayRouteTableAnnouncementRequest(*ec2.CreateTransitGatewayRouteTableAnnouncementInput) (*request.Request, *ec2.CreateTransitGatewayRouteTableAnnouncementOutput) + + CreateTransitGatewayVpcAttachment(*ec2.CreateTransitGatewayVpcAttachmentInput) (*ec2.CreateTransitGatewayVpcAttachmentOutput, error) + CreateTransitGatewayVpcAttachmentWithContext(aws.Context, *ec2.CreateTransitGatewayVpcAttachmentInput, ...request.Option) (*ec2.CreateTransitGatewayVpcAttachmentOutput, error) + CreateTransitGatewayVpcAttachmentRequest(*ec2.CreateTransitGatewayVpcAttachmentInput) (*request.Request, *ec2.CreateTransitGatewayVpcAttachmentOutput) + + CreateVerifiedAccessEndpoint(*ec2.CreateVerifiedAccessEndpointInput) (*ec2.CreateVerifiedAccessEndpointOutput, error) + CreateVerifiedAccessEndpointWithContext(aws.Context, *ec2.CreateVerifiedAccessEndpointInput, ...request.Option) (*ec2.CreateVerifiedAccessEndpointOutput, error) + CreateVerifiedAccessEndpointRequest(*ec2.CreateVerifiedAccessEndpointInput) (*request.Request, *ec2.CreateVerifiedAccessEndpointOutput) + + CreateVerifiedAccessGroup(*ec2.CreateVerifiedAccessGroupInput) (*ec2.CreateVerifiedAccessGroupOutput, error) + CreateVerifiedAccessGroupWithContext(aws.Context, *ec2.CreateVerifiedAccessGroupInput, ...request.Option) (*ec2.CreateVerifiedAccessGroupOutput, error) + CreateVerifiedAccessGroupRequest(*ec2.CreateVerifiedAccessGroupInput) (*request.Request, *ec2.CreateVerifiedAccessGroupOutput) + + CreateVerifiedAccessInstance(*ec2.CreateVerifiedAccessInstanceInput) (*ec2.CreateVerifiedAccessInstanceOutput, error) + CreateVerifiedAccessInstanceWithContext(aws.Context, *ec2.CreateVerifiedAccessInstanceInput, ...request.Option) (*ec2.CreateVerifiedAccessInstanceOutput, error) + CreateVerifiedAccessInstanceRequest(*ec2.CreateVerifiedAccessInstanceInput) (*request.Request, *ec2.CreateVerifiedAccessInstanceOutput) + + CreateVerifiedAccessTrustProvider(*ec2.CreateVerifiedAccessTrustProviderInput) (*ec2.CreateVerifiedAccessTrustProviderOutput, error) + CreateVerifiedAccessTrustProviderWithContext(aws.Context, *ec2.CreateVerifiedAccessTrustProviderInput, ...request.Option) (*ec2.CreateVerifiedAccessTrustProviderOutput, error) + CreateVerifiedAccessTrustProviderRequest(*ec2.CreateVerifiedAccessTrustProviderInput) (*request.Request, *ec2.CreateVerifiedAccessTrustProviderOutput) + + CreateVolume(*ec2.CreateVolumeInput) (*ec2.Volume, error) + CreateVolumeWithContext(aws.Context, *ec2.CreateVolumeInput, ...request.Option) (*ec2.Volume, error) + CreateVolumeRequest(*ec2.CreateVolumeInput) (*request.Request, *ec2.Volume) + + CreateVpc(*ec2.CreateVpcInput) (*ec2.CreateVpcOutput, error) + CreateVpcWithContext(aws.Context, *ec2.CreateVpcInput, ...request.Option) (*ec2.CreateVpcOutput, error) + CreateVpcRequest(*ec2.CreateVpcInput) (*request.Request, *ec2.CreateVpcOutput) + + CreateVpcEndpoint(*ec2.CreateVpcEndpointInput) (*ec2.CreateVpcEndpointOutput, error) + CreateVpcEndpointWithContext(aws.Context, *ec2.CreateVpcEndpointInput, ...request.Option) (*ec2.CreateVpcEndpointOutput, error) + CreateVpcEndpointRequest(*ec2.CreateVpcEndpointInput) (*request.Request, *ec2.CreateVpcEndpointOutput) + + CreateVpcEndpointConnectionNotification(*ec2.CreateVpcEndpointConnectionNotificationInput) (*ec2.CreateVpcEndpointConnectionNotificationOutput, error) + CreateVpcEndpointConnectionNotificationWithContext(aws.Context, *ec2.CreateVpcEndpointConnectionNotificationInput, ...request.Option) (*ec2.CreateVpcEndpointConnectionNotificationOutput, error) + CreateVpcEndpointConnectionNotificationRequest(*ec2.CreateVpcEndpointConnectionNotificationInput) (*request.Request, *ec2.CreateVpcEndpointConnectionNotificationOutput) + + CreateVpcEndpointServiceConfiguration(*ec2.CreateVpcEndpointServiceConfigurationInput) (*ec2.CreateVpcEndpointServiceConfigurationOutput, error) + CreateVpcEndpointServiceConfigurationWithContext(aws.Context, *ec2.CreateVpcEndpointServiceConfigurationInput, ...request.Option) (*ec2.CreateVpcEndpointServiceConfigurationOutput, error) + CreateVpcEndpointServiceConfigurationRequest(*ec2.CreateVpcEndpointServiceConfigurationInput) (*request.Request, *ec2.CreateVpcEndpointServiceConfigurationOutput) + + CreateVpcPeeringConnection(*ec2.CreateVpcPeeringConnectionInput) (*ec2.CreateVpcPeeringConnectionOutput, error) + CreateVpcPeeringConnectionWithContext(aws.Context, *ec2.CreateVpcPeeringConnectionInput, ...request.Option) (*ec2.CreateVpcPeeringConnectionOutput, error) + CreateVpcPeeringConnectionRequest(*ec2.CreateVpcPeeringConnectionInput) (*request.Request, *ec2.CreateVpcPeeringConnectionOutput) + + CreateVpnConnection(*ec2.CreateVpnConnectionInput) (*ec2.CreateVpnConnectionOutput, error) + CreateVpnConnectionWithContext(aws.Context, *ec2.CreateVpnConnectionInput, ...request.Option) (*ec2.CreateVpnConnectionOutput, error) + CreateVpnConnectionRequest(*ec2.CreateVpnConnectionInput) (*request.Request, *ec2.CreateVpnConnectionOutput) + + CreateVpnConnectionRoute(*ec2.CreateVpnConnectionRouteInput) (*ec2.CreateVpnConnectionRouteOutput, error) + CreateVpnConnectionRouteWithContext(aws.Context, *ec2.CreateVpnConnectionRouteInput, ...request.Option) (*ec2.CreateVpnConnectionRouteOutput, error) + CreateVpnConnectionRouteRequest(*ec2.CreateVpnConnectionRouteInput) (*request.Request, *ec2.CreateVpnConnectionRouteOutput) + + CreateVpnGateway(*ec2.CreateVpnGatewayInput) (*ec2.CreateVpnGatewayOutput, error) + CreateVpnGatewayWithContext(aws.Context, *ec2.CreateVpnGatewayInput, ...request.Option) (*ec2.CreateVpnGatewayOutput, error) + CreateVpnGatewayRequest(*ec2.CreateVpnGatewayInput) (*request.Request, *ec2.CreateVpnGatewayOutput) + + DeleteCarrierGateway(*ec2.DeleteCarrierGatewayInput) (*ec2.DeleteCarrierGatewayOutput, error) + DeleteCarrierGatewayWithContext(aws.Context, *ec2.DeleteCarrierGatewayInput, ...request.Option) (*ec2.DeleteCarrierGatewayOutput, error) + DeleteCarrierGatewayRequest(*ec2.DeleteCarrierGatewayInput) (*request.Request, *ec2.DeleteCarrierGatewayOutput) + + DeleteClientVpnEndpoint(*ec2.DeleteClientVpnEndpointInput) (*ec2.DeleteClientVpnEndpointOutput, error) + DeleteClientVpnEndpointWithContext(aws.Context, *ec2.DeleteClientVpnEndpointInput, ...request.Option) (*ec2.DeleteClientVpnEndpointOutput, error) + DeleteClientVpnEndpointRequest(*ec2.DeleteClientVpnEndpointInput) (*request.Request, *ec2.DeleteClientVpnEndpointOutput) + + DeleteClientVpnRoute(*ec2.DeleteClientVpnRouteInput) (*ec2.DeleteClientVpnRouteOutput, error) + DeleteClientVpnRouteWithContext(aws.Context, *ec2.DeleteClientVpnRouteInput, ...request.Option) (*ec2.DeleteClientVpnRouteOutput, error) + DeleteClientVpnRouteRequest(*ec2.DeleteClientVpnRouteInput) (*request.Request, *ec2.DeleteClientVpnRouteOutput) + + DeleteCoipCidr(*ec2.DeleteCoipCidrInput) (*ec2.DeleteCoipCidrOutput, error) + DeleteCoipCidrWithContext(aws.Context, *ec2.DeleteCoipCidrInput, ...request.Option) (*ec2.DeleteCoipCidrOutput, error) + DeleteCoipCidrRequest(*ec2.DeleteCoipCidrInput) (*request.Request, *ec2.DeleteCoipCidrOutput) + + DeleteCoipPool(*ec2.DeleteCoipPoolInput) (*ec2.DeleteCoipPoolOutput, error) + DeleteCoipPoolWithContext(aws.Context, *ec2.DeleteCoipPoolInput, ...request.Option) (*ec2.DeleteCoipPoolOutput, error) + DeleteCoipPoolRequest(*ec2.DeleteCoipPoolInput) (*request.Request, *ec2.DeleteCoipPoolOutput) + + DeleteCustomerGateway(*ec2.DeleteCustomerGatewayInput) (*ec2.DeleteCustomerGatewayOutput, error) + DeleteCustomerGatewayWithContext(aws.Context, *ec2.DeleteCustomerGatewayInput, ...request.Option) (*ec2.DeleteCustomerGatewayOutput, error) + DeleteCustomerGatewayRequest(*ec2.DeleteCustomerGatewayInput) (*request.Request, *ec2.DeleteCustomerGatewayOutput) + + DeleteDhcpOptions(*ec2.DeleteDhcpOptionsInput) (*ec2.DeleteDhcpOptionsOutput, error) + DeleteDhcpOptionsWithContext(aws.Context, *ec2.DeleteDhcpOptionsInput, ...request.Option) (*ec2.DeleteDhcpOptionsOutput, error) + DeleteDhcpOptionsRequest(*ec2.DeleteDhcpOptionsInput) (*request.Request, *ec2.DeleteDhcpOptionsOutput) + + DeleteEgressOnlyInternetGateway(*ec2.DeleteEgressOnlyInternetGatewayInput) (*ec2.DeleteEgressOnlyInternetGatewayOutput, error) + DeleteEgressOnlyInternetGatewayWithContext(aws.Context, *ec2.DeleteEgressOnlyInternetGatewayInput, ...request.Option) (*ec2.DeleteEgressOnlyInternetGatewayOutput, error) + DeleteEgressOnlyInternetGatewayRequest(*ec2.DeleteEgressOnlyInternetGatewayInput) (*request.Request, *ec2.DeleteEgressOnlyInternetGatewayOutput) + + DeleteFleets(*ec2.DeleteFleetsInput) (*ec2.DeleteFleetsOutput, error) + DeleteFleetsWithContext(aws.Context, *ec2.DeleteFleetsInput, ...request.Option) (*ec2.DeleteFleetsOutput, error) + DeleteFleetsRequest(*ec2.DeleteFleetsInput) (*request.Request, *ec2.DeleteFleetsOutput) + + DeleteFlowLogs(*ec2.DeleteFlowLogsInput) (*ec2.DeleteFlowLogsOutput, error) + DeleteFlowLogsWithContext(aws.Context, *ec2.DeleteFlowLogsInput, ...request.Option) (*ec2.DeleteFlowLogsOutput, error) + DeleteFlowLogsRequest(*ec2.DeleteFlowLogsInput) (*request.Request, *ec2.DeleteFlowLogsOutput) + + DeleteFpgaImage(*ec2.DeleteFpgaImageInput) (*ec2.DeleteFpgaImageOutput, error) + DeleteFpgaImageWithContext(aws.Context, *ec2.DeleteFpgaImageInput, ...request.Option) (*ec2.DeleteFpgaImageOutput, error) + DeleteFpgaImageRequest(*ec2.DeleteFpgaImageInput) (*request.Request, *ec2.DeleteFpgaImageOutput) + + DeleteInstanceConnectEndpoint(*ec2.DeleteInstanceConnectEndpointInput) (*ec2.DeleteInstanceConnectEndpointOutput, error) + DeleteInstanceConnectEndpointWithContext(aws.Context, *ec2.DeleteInstanceConnectEndpointInput, ...request.Option) (*ec2.DeleteInstanceConnectEndpointOutput, error) + DeleteInstanceConnectEndpointRequest(*ec2.DeleteInstanceConnectEndpointInput) (*request.Request, *ec2.DeleteInstanceConnectEndpointOutput) + + DeleteInstanceEventWindow(*ec2.DeleteInstanceEventWindowInput) (*ec2.DeleteInstanceEventWindowOutput, error) + DeleteInstanceEventWindowWithContext(aws.Context, *ec2.DeleteInstanceEventWindowInput, ...request.Option) (*ec2.DeleteInstanceEventWindowOutput, error) + DeleteInstanceEventWindowRequest(*ec2.DeleteInstanceEventWindowInput) (*request.Request, *ec2.DeleteInstanceEventWindowOutput) + + DeleteInternetGateway(*ec2.DeleteInternetGatewayInput) (*ec2.DeleteInternetGatewayOutput, error) + DeleteInternetGatewayWithContext(aws.Context, *ec2.DeleteInternetGatewayInput, ...request.Option) (*ec2.DeleteInternetGatewayOutput, error) + DeleteInternetGatewayRequest(*ec2.DeleteInternetGatewayInput) (*request.Request, *ec2.DeleteInternetGatewayOutput) + + DeleteIpam(*ec2.DeleteIpamInput) (*ec2.DeleteIpamOutput, error) + DeleteIpamWithContext(aws.Context, *ec2.DeleteIpamInput, ...request.Option) (*ec2.DeleteIpamOutput, error) + DeleteIpamRequest(*ec2.DeleteIpamInput) (*request.Request, *ec2.DeleteIpamOutput) + + DeleteIpamPool(*ec2.DeleteIpamPoolInput) (*ec2.DeleteIpamPoolOutput, error) + DeleteIpamPoolWithContext(aws.Context, *ec2.DeleteIpamPoolInput, ...request.Option) (*ec2.DeleteIpamPoolOutput, error) + DeleteIpamPoolRequest(*ec2.DeleteIpamPoolInput) (*request.Request, *ec2.DeleteIpamPoolOutput) + + DeleteIpamResourceDiscovery(*ec2.DeleteIpamResourceDiscoveryInput) (*ec2.DeleteIpamResourceDiscoveryOutput, error) + DeleteIpamResourceDiscoveryWithContext(aws.Context, *ec2.DeleteIpamResourceDiscoveryInput, ...request.Option) (*ec2.DeleteIpamResourceDiscoveryOutput, error) + DeleteIpamResourceDiscoveryRequest(*ec2.DeleteIpamResourceDiscoveryInput) (*request.Request, *ec2.DeleteIpamResourceDiscoveryOutput) + + DeleteIpamScope(*ec2.DeleteIpamScopeInput) (*ec2.DeleteIpamScopeOutput, error) + DeleteIpamScopeWithContext(aws.Context, *ec2.DeleteIpamScopeInput, ...request.Option) (*ec2.DeleteIpamScopeOutput, error) + DeleteIpamScopeRequest(*ec2.DeleteIpamScopeInput) (*request.Request, *ec2.DeleteIpamScopeOutput) + + DeleteKeyPair(*ec2.DeleteKeyPairInput) (*ec2.DeleteKeyPairOutput, error) + DeleteKeyPairWithContext(aws.Context, *ec2.DeleteKeyPairInput, ...request.Option) (*ec2.DeleteKeyPairOutput, error) + DeleteKeyPairRequest(*ec2.DeleteKeyPairInput) (*request.Request, *ec2.DeleteKeyPairOutput) + + DeleteLaunchTemplate(*ec2.DeleteLaunchTemplateInput) (*ec2.DeleteLaunchTemplateOutput, error) + DeleteLaunchTemplateWithContext(aws.Context, *ec2.DeleteLaunchTemplateInput, ...request.Option) (*ec2.DeleteLaunchTemplateOutput, error) + DeleteLaunchTemplateRequest(*ec2.DeleteLaunchTemplateInput) (*request.Request, *ec2.DeleteLaunchTemplateOutput) + + DeleteLaunchTemplateVersions(*ec2.DeleteLaunchTemplateVersionsInput) (*ec2.DeleteLaunchTemplateVersionsOutput, error) + DeleteLaunchTemplateVersionsWithContext(aws.Context, *ec2.DeleteLaunchTemplateVersionsInput, ...request.Option) (*ec2.DeleteLaunchTemplateVersionsOutput, error) + DeleteLaunchTemplateVersionsRequest(*ec2.DeleteLaunchTemplateVersionsInput) (*request.Request, *ec2.DeleteLaunchTemplateVersionsOutput) + + DeleteLocalGatewayRoute(*ec2.DeleteLocalGatewayRouteInput) (*ec2.DeleteLocalGatewayRouteOutput, error) + DeleteLocalGatewayRouteWithContext(aws.Context, *ec2.DeleteLocalGatewayRouteInput, ...request.Option) (*ec2.DeleteLocalGatewayRouteOutput, error) + DeleteLocalGatewayRouteRequest(*ec2.DeleteLocalGatewayRouteInput) (*request.Request, *ec2.DeleteLocalGatewayRouteOutput) + + DeleteLocalGatewayRouteTable(*ec2.DeleteLocalGatewayRouteTableInput) (*ec2.DeleteLocalGatewayRouteTableOutput, error) + DeleteLocalGatewayRouteTableWithContext(aws.Context, *ec2.DeleteLocalGatewayRouteTableInput, ...request.Option) (*ec2.DeleteLocalGatewayRouteTableOutput, error) + DeleteLocalGatewayRouteTableRequest(*ec2.DeleteLocalGatewayRouteTableInput) (*request.Request, *ec2.DeleteLocalGatewayRouteTableOutput) + + DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociation(*ec2.DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationInput) (*ec2.DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationOutput, error) + DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationWithContext(aws.Context, *ec2.DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationInput, ...request.Option) (*ec2.DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationOutput, error) + DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationRequest(*ec2.DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationInput) (*request.Request, *ec2.DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationOutput) + + DeleteLocalGatewayRouteTableVpcAssociation(*ec2.DeleteLocalGatewayRouteTableVpcAssociationInput) (*ec2.DeleteLocalGatewayRouteTableVpcAssociationOutput, error) + DeleteLocalGatewayRouteTableVpcAssociationWithContext(aws.Context, *ec2.DeleteLocalGatewayRouteTableVpcAssociationInput, ...request.Option) (*ec2.DeleteLocalGatewayRouteTableVpcAssociationOutput, error) + DeleteLocalGatewayRouteTableVpcAssociationRequest(*ec2.DeleteLocalGatewayRouteTableVpcAssociationInput) (*request.Request, *ec2.DeleteLocalGatewayRouteTableVpcAssociationOutput) + + DeleteManagedPrefixList(*ec2.DeleteManagedPrefixListInput) (*ec2.DeleteManagedPrefixListOutput, error) + DeleteManagedPrefixListWithContext(aws.Context, *ec2.DeleteManagedPrefixListInput, ...request.Option) (*ec2.DeleteManagedPrefixListOutput, error) + DeleteManagedPrefixListRequest(*ec2.DeleteManagedPrefixListInput) (*request.Request, *ec2.DeleteManagedPrefixListOutput) + + DeleteNatGateway(*ec2.DeleteNatGatewayInput) (*ec2.DeleteNatGatewayOutput, error) + DeleteNatGatewayWithContext(aws.Context, *ec2.DeleteNatGatewayInput, ...request.Option) (*ec2.DeleteNatGatewayOutput, error) + DeleteNatGatewayRequest(*ec2.DeleteNatGatewayInput) (*request.Request, *ec2.DeleteNatGatewayOutput) + + DeleteNetworkAcl(*ec2.DeleteNetworkAclInput) (*ec2.DeleteNetworkAclOutput, error) + DeleteNetworkAclWithContext(aws.Context, *ec2.DeleteNetworkAclInput, ...request.Option) (*ec2.DeleteNetworkAclOutput, error) + DeleteNetworkAclRequest(*ec2.DeleteNetworkAclInput) (*request.Request, *ec2.DeleteNetworkAclOutput) + + DeleteNetworkAclEntry(*ec2.DeleteNetworkAclEntryInput) (*ec2.DeleteNetworkAclEntryOutput, error) + DeleteNetworkAclEntryWithContext(aws.Context, *ec2.DeleteNetworkAclEntryInput, ...request.Option) (*ec2.DeleteNetworkAclEntryOutput, error) + DeleteNetworkAclEntryRequest(*ec2.DeleteNetworkAclEntryInput) (*request.Request, *ec2.DeleteNetworkAclEntryOutput) + + DeleteNetworkInsightsAccessScope(*ec2.DeleteNetworkInsightsAccessScopeInput) (*ec2.DeleteNetworkInsightsAccessScopeOutput, error) + DeleteNetworkInsightsAccessScopeWithContext(aws.Context, *ec2.DeleteNetworkInsightsAccessScopeInput, ...request.Option) (*ec2.DeleteNetworkInsightsAccessScopeOutput, error) + DeleteNetworkInsightsAccessScopeRequest(*ec2.DeleteNetworkInsightsAccessScopeInput) (*request.Request, *ec2.DeleteNetworkInsightsAccessScopeOutput) + + DeleteNetworkInsightsAccessScopeAnalysis(*ec2.DeleteNetworkInsightsAccessScopeAnalysisInput) (*ec2.DeleteNetworkInsightsAccessScopeAnalysisOutput, error) + DeleteNetworkInsightsAccessScopeAnalysisWithContext(aws.Context, *ec2.DeleteNetworkInsightsAccessScopeAnalysisInput, ...request.Option) (*ec2.DeleteNetworkInsightsAccessScopeAnalysisOutput, error) + DeleteNetworkInsightsAccessScopeAnalysisRequest(*ec2.DeleteNetworkInsightsAccessScopeAnalysisInput) (*request.Request, *ec2.DeleteNetworkInsightsAccessScopeAnalysisOutput) + + DeleteNetworkInsightsAnalysis(*ec2.DeleteNetworkInsightsAnalysisInput) (*ec2.DeleteNetworkInsightsAnalysisOutput, error) + DeleteNetworkInsightsAnalysisWithContext(aws.Context, *ec2.DeleteNetworkInsightsAnalysisInput, ...request.Option) (*ec2.DeleteNetworkInsightsAnalysisOutput, error) + DeleteNetworkInsightsAnalysisRequest(*ec2.DeleteNetworkInsightsAnalysisInput) (*request.Request, *ec2.DeleteNetworkInsightsAnalysisOutput) + + DeleteNetworkInsightsPath(*ec2.DeleteNetworkInsightsPathInput) (*ec2.DeleteNetworkInsightsPathOutput, error) + DeleteNetworkInsightsPathWithContext(aws.Context, *ec2.DeleteNetworkInsightsPathInput, ...request.Option) (*ec2.DeleteNetworkInsightsPathOutput, error) + DeleteNetworkInsightsPathRequest(*ec2.DeleteNetworkInsightsPathInput) (*request.Request, *ec2.DeleteNetworkInsightsPathOutput) + + DeleteNetworkInterface(*ec2.DeleteNetworkInterfaceInput) (*ec2.DeleteNetworkInterfaceOutput, error) + DeleteNetworkInterfaceWithContext(aws.Context, *ec2.DeleteNetworkInterfaceInput, ...request.Option) (*ec2.DeleteNetworkInterfaceOutput, error) + DeleteNetworkInterfaceRequest(*ec2.DeleteNetworkInterfaceInput) (*request.Request, *ec2.DeleteNetworkInterfaceOutput) + + DeleteNetworkInterfacePermission(*ec2.DeleteNetworkInterfacePermissionInput) (*ec2.DeleteNetworkInterfacePermissionOutput, error) + DeleteNetworkInterfacePermissionWithContext(aws.Context, *ec2.DeleteNetworkInterfacePermissionInput, ...request.Option) (*ec2.DeleteNetworkInterfacePermissionOutput, error) + DeleteNetworkInterfacePermissionRequest(*ec2.DeleteNetworkInterfacePermissionInput) (*request.Request, *ec2.DeleteNetworkInterfacePermissionOutput) + + DeletePlacementGroup(*ec2.DeletePlacementGroupInput) (*ec2.DeletePlacementGroupOutput, error) + DeletePlacementGroupWithContext(aws.Context, *ec2.DeletePlacementGroupInput, ...request.Option) (*ec2.DeletePlacementGroupOutput, error) + DeletePlacementGroupRequest(*ec2.DeletePlacementGroupInput) (*request.Request, *ec2.DeletePlacementGroupOutput) + + DeletePublicIpv4Pool(*ec2.DeletePublicIpv4PoolInput) (*ec2.DeletePublicIpv4PoolOutput, error) + DeletePublicIpv4PoolWithContext(aws.Context, *ec2.DeletePublicIpv4PoolInput, ...request.Option) (*ec2.DeletePublicIpv4PoolOutput, error) + DeletePublicIpv4PoolRequest(*ec2.DeletePublicIpv4PoolInput) (*request.Request, *ec2.DeletePublicIpv4PoolOutput) + + DeleteQueuedReservedInstances(*ec2.DeleteQueuedReservedInstancesInput) (*ec2.DeleteQueuedReservedInstancesOutput, error) + DeleteQueuedReservedInstancesWithContext(aws.Context, *ec2.DeleteQueuedReservedInstancesInput, ...request.Option) (*ec2.DeleteQueuedReservedInstancesOutput, error) + DeleteQueuedReservedInstancesRequest(*ec2.DeleteQueuedReservedInstancesInput) (*request.Request, *ec2.DeleteQueuedReservedInstancesOutput) + + DeleteRoute(*ec2.DeleteRouteInput) (*ec2.DeleteRouteOutput, error) + DeleteRouteWithContext(aws.Context, *ec2.DeleteRouteInput, ...request.Option) (*ec2.DeleteRouteOutput, error) + DeleteRouteRequest(*ec2.DeleteRouteInput) (*request.Request, *ec2.DeleteRouteOutput) + + DeleteRouteTable(*ec2.DeleteRouteTableInput) (*ec2.DeleteRouteTableOutput, error) + DeleteRouteTableWithContext(aws.Context, *ec2.DeleteRouteTableInput, ...request.Option) (*ec2.DeleteRouteTableOutput, error) + DeleteRouteTableRequest(*ec2.DeleteRouteTableInput) (*request.Request, *ec2.DeleteRouteTableOutput) + + DeleteSecurityGroup(*ec2.DeleteSecurityGroupInput) (*ec2.DeleteSecurityGroupOutput, error) + DeleteSecurityGroupWithContext(aws.Context, *ec2.DeleteSecurityGroupInput, ...request.Option) (*ec2.DeleteSecurityGroupOutput, error) + DeleteSecurityGroupRequest(*ec2.DeleteSecurityGroupInput) (*request.Request, *ec2.DeleteSecurityGroupOutput) + + DeleteSnapshot(*ec2.DeleteSnapshotInput) (*ec2.DeleteSnapshotOutput, error) + DeleteSnapshotWithContext(aws.Context, *ec2.DeleteSnapshotInput, ...request.Option) (*ec2.DeleteSnapshotOutput, error) + DeleteSnapshotRequest(*ec2.DeleteSnapshotInput) (*request.Request, *ec2.DeleteSnapshotOutput) + + DeleteSpotDatafeedSubscription(*ec2.DeleteSpotDatafeedSubscriptionInput) (*ec2.DeleteSpotDatafeedSubscriptionOutput, error) + DeleteSpotDatafeedSubscriptionWithContext(aws.Context, *ec2.DeleteSpotDatafeedSubscriptionInput, ...request.Option) (*ec2.DeleteSpotDatafeedSubscriptionOutput, error) + DeleteSpotDatafeedSubscriptionRequest(*ec2.DeleteSpotDatafeedSubscriptionInput) (*request.Request, *ec2.DeleteSpotDatafeedSubscriptionOutput) + + DeleteSubnet(*ec2.DeleteSubnetInput) (*ec2.DeleteSubnetOutput, error) + DeleteSubnetWithContext(aws.Context, *ec2.DeleteSubnetInput, ...request.Option) (*ec2.DeleteSubnetOutput, error) + DeleteSubnetRequest(*ec2.DeleteSubnetInput) (*request.Request, *ec2.DeleteSubnetOutput) + + DeleteSubnetCidrReservation(*ec2.DeleteSubnetCidrReservationInput) (*ec2.DeleteSubnetCidrReservationOutput, error) + DeleteSubnetCidrReservationWithContext(aws.Context, *ec2.DeleteSubnetCidrReservationInput, ...request.Option) (*ec2.DeleteSubnetCidrReservationOutput, error) + DeleteSubnetCidrReservationRequest(*ec2.DeleteSubnetCidrReservationInput) (*request.Request, *ec2.DeleteSubnetCidrReservationOutput) + + DeleteTags(*ec2.DeleteTagsInput) (*ec2.DeleteTagsOutput, error) + DeleteTagsWithContext(aws.Context, *ec2.DeleteTagsInput, ...request.Option) (*ec2.DeleteTagsOutput, error) + DeleteTagsRequest(*ec2.DeleteTagsInput) (*request.Request, *ec2.DeleteTagsOutput) + + DeleteTrafficMirrorFilter(*ec2.DeleteTrafficMirrorFilterInput) (*ec2.DeleteTrafficMirrorFilterOutput, error) + DeleteTrafficMirrorFilterWithContext(aws.Context, *ec2.DeleteTrafficMirrorFilterInput, ...request.Option) (*ec2.DeleteTrafficMirrorFilterOutput, error) + DeleteTrafficMirrorFilterRequest(*ec2.DeleteTrafficMirrorFilterInput) (*request.Request, *ec2.DeleteTrafficMirrorFilterOutput) + + DeleteTrafficMirrorFilterRule(*ec2.DeleteTrafficMirrorFilterRuleInput) (*ec2.DeleteTrafficMirrorFilterRuleOutput, error) + DeleteTrafficMirrorFilterRuleWithContext(aws.Context, *ec2.DeleteTrafficMirrorFilterRuleInput, ...request.Option) (*ec2.DeleteTrafficMirrorFilterRuleOutput, error) + DeleteTrafficMirrorFilterRuleRequest(*ec2.DeleteTrafficMirrorFilterRuleInput) (*request.Request, *ec2.DeleteTrafficMirrorFilterRuleOutput) + + DeleteTrafficMirrorSession(*ec2.DeleteTrafficMirrorSessionInput) (*ec2.DeleteTrafficMirrorSessionOutput, error) + DeleteTrafficMirrorSessionWithContext(aws.Context, *ec2.DeleteTrafficMirrorSessionInput, ...request.Option) (*ec2.DeleteTrafficMirrorSessionOutput, error) + DeleteTrafficMirrorSessionRequest(*ec2.DeleteTrafficMirrorSessionInput) (*request.Request, *ec2.DeleteTrafficMirrorSessionOutput) + + DeleteTrafficMirrorTarget(*ec2.DeleteTrafficMirrorTargetInput) (*ec2.DeleteTrafficMirrorTargetOutput, error) + DeleteTrafficMirrorTargetWithContext(aws.Context, *ec2.DeleteTrafficMirrorTargetInput, ...request.Option) (*ec2.DeleteTrafficMirrorTargetOutput, error) + DeleteTrafficMirrorTargetRequest(*ec2.DeleteTrafficMirrorTargetInput) (*request.Request, *ec2.DeleteTrafficMirrorTargetOutput) + + DeleteTransitGateway(*ec2.DeleteTransitGatewayInput) (*ec2.DeleteTransitGatewayOutput, error) + DeleteTransitGatewayWithContext(aws.Context, *ec2.DeleteTransitGatewayInput, ...request.Option) (*ec2.DeleteTransitGatewayOutput, error) + DeleteTransitGatewayRequest(*ec2.DeleteTransitGatewayInput) (*request.Request, *ec2.DeleteTransitGatewayOutput) + + DeleteTransitGatewayConnect(*ec2.DeleteTransitGatewayConnectInput) (*ec2.DeleteTransitGatewayConnectOutput, error) + DeleteTransitGatewayConnectWithContext(aws.Context, *ec2.DeleteTransitGatewayConnectInput, ...request.Option) (*ec2.DeleteTransitGatewayConnectOutput, error) + DeleteTransitGatewayConnectRequest(*ec2.DeleteTransitGatewayConnectInput) (*request.Request, *ec2.DeleteTransitGatewayConnectOutput) + + DeleteTransitGatewayConnectPeer(*ec2.DeleteTransitGatewayConnectPeerInput) (*ec2.DeleteTransitGatewayConnectPeerOutput, error) + DeleteTransitGatewayConnectPeerWithContext(aws.Context, *ec2.DeleteTransitGatewayConnectPeerInput, ...request.Option) (*ec2.DeleteTransitGatewayConnectPeerOutput, error) + DeleteTransitGatewayConnectPeerRequest(*ec2.DeleteTransitGatewayConnectPeerInput) (*request.Request, *ec2.DeleteTransitGatewayConnectPeerOutput) + + DeleteTransitGatewayMulticastDomain(*ec2.DeleteTransitGatewayMulticastDomainInput) (*ec2.DeleteTransitGatewayMulticastDomainOutput, error) + DeleteTransitGatewayMulticastDomainWithContext(aws.Context, *ec2.DeleteTransitGatewayMulticastDomainInput, ...request.Option) (*ec2.DeleteTransitGatewayMulticastDomainOutput, error) + DeleteTransitGatewayMulticastDomainRequest(*ec2.DeleteTransitGatewayMulticastDomainInput) (*request.Request, *ec2.DeleteTransitGatewayMulticastDomainOutput) + + DeleteTransitGatewayPeeringAttachment(*ec2.DeleteTransitGatewayPeeringAttachmentInput) (*ec2.DeleteTransitGatewayPeeringAttachmentOutput, error) + DeleteTransitGatewayPeeringAttachmentWithContext(aws.Context, *ec2.DeleteTransitGatewayPeeringAttachmentInput, ...request.Option) (*ec2.DeleteTransitGatewayPeeringAttachmentOutput, error) + DeleteTransitGatewayPeeringAttachmentRequest(*ec2.DeleteTransitGatewayPeeringAttachmentInput) (*request.Request, *ec2.DeleteTransitGatewayPeeringAttachmentOutput) + + DeleteTransitGatewayPolicyTable(*ec2.DeleteTransitGatewayPolicyTableInput) (*ec2.DeleteTransitGatewayPolicyTableOutput, error) + DeleteTransitGatewayPolicyTableWithContext(aws.Context, *ec2.DeleteTransitGatewayPolicyTableInput, ...request.Option) (*ec2.DeleteTransitGatewayPolicyTableOutput, error) + DeleteTransitGatewayPolicyTableRequest(*ec2.DeleteTransitGatewayPolicyTableInput) (*request.Request, *ec2.DeleteTransitGatewayPolicyTableOutput) + + DeleteTransitGatewayPrefixListReference(*ec2.DeleteTransitGatewayPrefixListReferenceInput) (*ec2.DeleteTransitGatewayPrefixListReferenceOutput, error) + DeleteTransitGatewayPrefixListReferenceWithContext(aws.Context, *ec2.DeleteTransitGatewayPrefixListReferenceInput, ...request.Option) (*ec2.DeleteTransitGatewayPrefixListReferenceOutput, error) + DeleteTransitGatewayPrefixListReferenceRequest(*ec2.DeleteTransitGatewayPrefixListReferenceInput) (*request.Request, *ec2.DeleteTransitGatewayPrefixListReferenceOutput) + + DeleteTransitGatewayRoute(*ec2.DeleteTransitGatewayRouteInput) (*ec2.DeleteTransitGatewayRouteOutput, error) + DeleteTransitGatewayRouteWithContext(aws.Context, *ec2.DeleteTransitGatewayRouteInput, ...request.Option) (*ec2.DeleteTransitGatewayRouteOutput, error) + DeleteTransitGatewayRouteRequest(*ec2.DeleteTransitGatewayRouteInput) (*request.Request, *ec2.DeleteTransitGatewayRouteOutput) + + DeleteTransitGatewayRouteTable(*ec2.DeleteTransitGatewayRouteTableInput) (*ec2.DeleteTransitGatewayRouteTableOutput, error) + DeleteTransitGatewayRouteTableWithContext(aws.Context, *ec2.DeleteTransitGatewayRouteTableInput, ...request.Option) (*ec2.DeleteTransitGatewayRouteTableOutput, error) + DeleteTransitGatewayRouteTableRequest(*ec2.DeleteTransitGatewayRouteTableInput) (*request.Request, *ec2.DeleteTransitGatewayRouteTableOutput) + + DeleteTransitGatewayRouteTableAnnouncement(*ec2.DeleteTransitGatewayRouteTableAnnouncementInput) (*ec2.DeleteTransitGatewayRouteTableAnnouncementOutput, error) + DeleteTransitGatewayRouteTableAnnouncementWithContext(aws.Context, *ec2.DeleteTransitGatewayRouteTableAnnouncementInput, ...request.Option) (*ec2.DeleteTransitGatewayRouteTableAnnouncementOutput, error) + DeleteTransitGatewayRouteTableAnnouncementRequest(*ec2.DeleteTransitGatewayRouteTableAnnouncementInput) (*request.Request, *ec2.DeleteTransitGatewayRouteTableAnnouncementOutput) + + DeleteTransitGatewayVpcAttachment(*ec2.DeleteTransitGatewayVpcAttachmentInput) (*ec2.DeleteTransitGatewayVpcAttachmentOutput, error) + DeleteTransitGatewayVpcAttachmentWithContext(aws.Context, *ec2.DeleteTransitGatewayVpcAttachmentInput, ...request.Option) (*ec2.DeleteTransitGatewayVpcAttachmentOutput, error) + DeleteTransitGatewayVpcAttachmentRequest(*ec2.DeleteTransitGatewayVpcAttachmentInput) (*request.Request, *ec2.DeleteTransitGatewayVpcAttachmentOutput) + + DeleteVerifiedAccessEndpoint(*ec2.DeleteVerifiedAccessEndpointInput) (*ec2.DeleteVerifiedAccessEndpointOutput, error) + DeleteVerifiedAccessEndpointWithContext(aws.Context, *ec2.DeleteVerifiedAccessEndpointInput, ...request.Option) (*ec2.DeleteVerifiedAccessEndpointOutput, error) + DeleteVerifiedAccessEndpointRequest(*ec2.DeleteVerifiedAccessEndpointInput) (*request.Request, *ec2.DeleteVerifiedAccessEndpointOutput) + + DeleteVerifiedAccessGroup(*ec2.DeleteVerifiedAccessGroupInput) (*ec2.DeleteVerifiedAccessGroupOutput, error) + DeleteVerifiedAccessGroupWithContext(aws.Context, *ec2.DeleteVerifiedAccessGroupInput, ...request.Option) (*ec2.DeleteVerifiedAccessGroupOutput, error) + DeleteVerifiedAccessGroupRequest(*ec2.DeleteVerifiedAccessGroupInput) (*request.Request, *ec2.DeleteVerifiedAccessGroupOutput) + + DeleteVerifiedAccessInstance(*ec2.DeleteVerifiedAccessInstanceInput) (*ec2.DeleteVerifiedAccessInstanceOutput, error) + DeleteVerifiedAccessInstanceWithContext(aws.Context, *ec2.DeleteVerifiedAccessInstanceInput, ...request.Option) (*ec2.DeleteVerifiedAccessInstanceOutput, error) + DeleteVerifiedAccessInstanceRequest(*ec2.DeleteVerifiedAccessInstanceInput) (*request.Request, *ec2.DeleteVerifiedAccessInstanceOutput) + + DeleteVerifiedAccessTrustProvider(*ec2.DeleteVerifiedAccessTrustProviderInput) (*ec2.DeleteVerifiedAccessTrustProviderOutput, error) + DeleteVerifiedAccessTrustProviderWithContext(aws.Context, *ec2.DeleteVerifiedAccessTrustProviderInput, ...request.Option) (*ec2.DeleteVerifiedAccessTrustProviderOutput, error) + DeleteVerifiedAccessTrustProviderRequest(*ec2.DeleteVerifiedAccessTrustProviderInput) (*request.Request, *ec2.DeleteVerifiedAccessTrustProviderOutput) + + DeleteVolume(*ec2.DeleteVolumeInput) (*ec2.DeleteVolumeOutput, error) + DeleteVolumeWithContext(aws.Context, *ec2.DeleteVolumeInput, ...request.Option) (*ec2.DeleteVolumeOutput, error) + DeleteVolumeRequest(*ec2.DeleteVolumeInput) (*request.Request, *ec2.DeleteVolumeOutput) + + DeleteVpc(*ec2.DeleteVpcInput) (*ec2.DeleteVpcOutput, error) + DeleteVpcWithContext(aws.Context, *ec2.DeleteVpcInput, ...request.Option) (*ec2.DeleteVpcOutput, error) + DeleteVpcRequest(*ec2.DeleteVpcInput) (*request.Request, *ec2.DeleteVpcOutput) + + DeleteVpcEndpointConnectionNotifications(*ec2.DeleteVpcEndpointConnectionNotificationsInput) (*ec2.DeleteVpcEndpointConnectionNotificationsOutput, error) + DeleteVpcEndpointConnectionNotificationsWithContext(aws.Context, *ec2.DeleteVpcEndpointConnectionNotificationsInput, ...request.Option) (*ec2.DeleteVpcEndpointConnectionNotificationsOutput, error) + DeleteVpcEndpointConnectionNotificationsRequest(*ec2.DeleteVpcEndpointConnectionNotificationsInput) (*request.Request, *ec2.DeleteVpcEndpointConnectionNotificationsOutput) + + DeleteVpcEndpointServiceConfigurations(*ec2.DeleteVpcEndpointServiceConfigurationsInput) (*ec2.DeleteVpcEndpointServiceConfigurationsOutput, error) + DeleteVpcEndpointServiceConfigurationsWithContext(aws.Context, *ec2.DeleteVpcEndpointServiceConfigurationsInput, ...request.Option) (*ec2.DeleteVpcEndpointServiceConfigurationsOutput, error) + DeleteVpcEndpointServiceConfigurationsRequest(*ec2.DeleteVpcEndpointServiceConfigurationsInput) (*request.Request, *ec2.DeleteVpcEndpointServiceConfigurationsOutput) + + DeleteVpcEndpoints(*ec2.DeleteVpcEndpointsInput) (*ec2.DeleteVpcEndpointsOutput, error) + DeleteVpcEndpointsWithContext(aws.Context, *ec2.DeleteVpcEndpointsInput, ...request.Option) (*ec2.DeleteVpcEndpointsOutput, error) + DeleteVpcEndpointsRequest(*ec2.DeleteVpcEndpointsInput) (*request.Request, *ec2.DeleteVpcEndpointsOutput) + + DeleteVpcPeeringConnection(*ec2.DeleteVpcPeeringConnectionInput) (*ec2.DeleteVpcPeeringConnectionOutput, error) + DeleteVpcPeeringConnectionWithContext(aws.Context, *ec2.DeleteVpcPeeringConnectionInput, ...request.Option) (*ec2.DeleteVpcPeeringConnectionOutput, error) + DeleteVpcPeeringConnectionRequest(*ec2.DeleteVpcPeeringConnectionInput) (*request.Request, *ec2.DeleteVpcPeeringConnectionOutput) + + DeleteVpnConnection(*ec2.DeleteVpnConnectionInput) (*ec2.DeleteVpnConnectionOutput, error) + DeleteVpnConnectionWithContext(aws.Context, *ec2.DeleteVpnConnectionInput, ...request.Option) (*ec2.DeleteVpnConnectionOutput, error) + DeleteVpnConnectionRequest(*ec2.DeleteVpnConnectionInput) (*request.Request, *ec2.DeleteVpnConnectionOutput) + + DeleteVpnConnectionRoute(*ec2.DeleteVpnConnectionRouteInput) (*ec2.DeleteVpnConnectionRouteOutput, error) + DeleteVpnConnectionRouteWithContext(aws.Context, *ec2.DeleteVpnConnectionRouteInput, ...request.Option) (*ec2.DeleteVpnConnectionRouteOutput, error) + DeleteVpnConnectionRouteRequest(*ec2.DeleteVpnConnectionRouteInput) (*request.Request, *ec2.DeleteVpnConnectionRouteOutput) + + DeleteVpnGateway(*ec2.DeleteVpnGatewayInput) (*ec2.DeleteVpnGatewayOutput, error) + DeleteVpnGatewayWithContext(aws.Context, *ec2.DeleteVpnGatewayInput, ...request.Option) (*ec2.DeleteVpnGatewayOutput, error) + DeleteVpnGatewayRequest(*ec2.DeleteVpnGatewayInput) (*request.Request, *ec2.DeleteVpnGatewayOutput) + + DeprovisionByoipCidr(*ec2.DeprovisionByoipCidrInput) (*ec2.DeprovisionByoipCidrOutput, error) + DeprovisionByoipCidrWithContext(aws.Context, *ec2.DeprovisionByoipCidrInput, ...request.Option) (*ec2.DeprovisionByoipCidrOutput, error) + DeprovisionByoipCidrRequest(*ec2.DeprovisionByoipCidrInput) (*request.Request, *ec2.DeprovisionByoipCidrOutput) + + DeprovisionIpamPoolCidr(*ec2.DeprovisionIpamPoolCidrInput) (*ec2.DeprovisionIpamPoolCidrOutput, error) + DeprovisionIpamPoolCidrWithContext(aws.Context, *ec2.DeprovisionIpamPoolCidrInput, ...request.Option) (*ec2.DeprovisionIpamPoolCidrOutput, error) + DeprovisionIpamPoolCidrRequest(*ec2.DeprovisionIpamPoolCidrInput) (*request.Request, *ec2.DeprovisionIpamPoolCidrOutput) + + DeprovisionPublicIpv4PoolCidr(*ec2.DeprovisionPublicIpv4PoolCidrInput) (*ec2.DeprovisionPublicIpv4PoolCidrOutput, error) + DeprovisionPublicIpv4PoolCidrWithContext(aws.Context, *ec2.DeprovisionPublicIpv4PoolCidrInput, ...request.Option) (*ec2.DeprovisionPublicIpv4PoolCidrOutput, error) + DeprovisionPublicIpv4PoolCidrRequest(*ec2.DeprovisionPublicIpv4PoolCidrInput) (*request.Request, *ec2.DeprovisionPublicIpv4PoolCidrOutput) + + DeregisterImage(*ec2.DeregisterImageInput) (*ec2.DeregisterImageOutput, error) + DeregisterImageWithContext(aws.Context, *ec2.DeregisterImageInput, ...request.Option) (*ec2.DeregisterImageOutput, error) + DeregisterImageRequest(*ec2.DeregisterImageInput) (*request.Request, *ec2.DeregisterImageOutput) + + DeregisterInstanceEventNotificationAttributes(*ec2.DeregisterInstanceEventNotificationAttributesInput) (*ec2.DeregisterInstanceEventNotificationAttributesOutput, error) + DeregisterInstanceEventNotificationAttributesWithContext(aws.Context, *ec2.DeregisterInstanceEventNotificationAttributesInput, ...request.Option) (*ec2.DeregisterInstanceEventNotificationAttributesOutput, error) + DeregisterInstanceEventNotificationAttributesRequest(*ec2.DeregisterInstanceEventNotificationAttributesInput) (*request.Request, *ec2.DeregisterInstanceEventNotificationAttributesOutput) + + DeregisterTransitGatewayMulticastGroupMembers(*ec2.DeregisterTransitGatewayMulticastGroupMembersInput) (*ec2.DeregisterTransitGatewayMulticastGroupMembersOutput, error) + DeregisterTransitGatewayMulticastGroupMembersWithContext(aws.Context, *ec2.DeregisterTransitGatewayMulticastGroupMembersInput, ...request.Option) (*ec2.DeregisterTransitGatewayMulticastGroupMembersOutput, error) + DeregisterTransitGatewayMulticastGroupMembersRequest(*ec2.DeregisterTransitGatewayMulticastGroupMembersInput) (*request.Request, *ec2.DeregisterTransitGatewayMulticastGroupMembersOutput) + + DeregisterTransitGatewayMulticastGroupSources(*ec2.DeregisterTransitGatewayMulticastGroupSourcesInput) (*ec2.DeregisterTransitGatewayMulticastGroupSourcesOutput, error) + DeregisterTransitGatewayMulticastGroupSourcesWithContext(aws.Context, *ec2.DeregisterTransitGatewayMulticastGroupSourcesInput, ...request.Option) (*ec2.DeregisterTransitGatewayMulticastGroupSourcesOutput, error) + DeregisterTransitGatewayMulticastGroupSourcesRequest(*ec2.DeregisterTransitGatewayMulticastGroupSourcesInput) (*request.Request, *ec2.DeregisterTransitGatewayMulticastGroupSourcesOutput) + + DescribeAccountAttributes(*ec2.DescribeAccountAttributesInput) (*ec2.DescribeAccountAttributesOutput, error) + DescribeAccountAttributesWithContext(aws.Context, *ec2.DescribeAccountAttributesInput, ...request.Option) (*ec2.DescribeAccountAttributesOutput, error) + DescribeAccountAttributesRequest(*ec2.DescribeAccountAttributesInput) (*request.Request, *ec2.DescribeAccountAttributesOutput) + + DescribeAddressTransfers(*ec2.DescribeAddressTransfersInput) (*ec2.DescribeAddressTransfersOutput, error) + DescribeAddressTransfersWithContext(aws.Context, *ec2.DescribeAddressTransfersInput, ...request.Option) (*ec2.DescribeAddressTransfersOutput, error) + DescribeAddressTransfersRequest(*ec2.DescribeAddressTransfersInput) (*request.Request, *ec2.DescribeAddressTransfersOutput) + + DescribeAddressTransfersPages(*ec2.DescribeAddressTransfersInput, func(*ec2.DescribeAddressTransfersOutput, bool) bool) error + DescribeAddressTransfersPagesWithContext(aws.Context, *ec2.DescribeAddressTransfersInput, func(*ec2.DescribeAddressTransfersOutput, bool) bool, ...request.Option) error + + DescribeAddresses(*ec2.DescribeAddressesInput) (*ec2.DescribeAddressesOutput, error) + DescribeAddressesWithContext(aws.Context, *ec2.DescribeAddressesInput, ...request.Option) (*ec2.DescribeAddressesOutput, error) + DescribeAddressesRequest(*ec2.DescribeAddressesInput) (*request.Request, *ec2.DescribeAddressesOutput) + + DescribeAddressesAttribute(*ec2.DescribeAddressesAttributeInput) (*ec2.DescribeAddressesAttributeOutput, error) + DescribeAddressesAttributeWithContext(aws.Context, *ec2.DescribeAddressesAttributeInput, ...request.Option) (*ec2.DescribeAddressesAttributeOutput, error) + DescribeAddressesAttributeRequest(*ec2.DescribeAddressesAttributeInput) (*request.Request, *ec2.DescribeAddressesAttributeOutput) + + DescribeAddressesAttributePages(*ec2.DescribeAddressesAttributeInput, func(*ec2.DescribeAddressesAttributeOutput, bool) bool) error + DescribeAddressesAttributePagesWithContext(aws.Context, *ec2.DescribeAddressesAttributeInput, func(*ec2.DescribeAddressesAttributeOutput, bool) bool, ...request.Option) error + + DescribeAggregateIdFormat(*ec2.DescribeAggregateIdFormatInput) (*ec2.DescribeAggregateIdFormatOutput, error) + DescribeAggregateIdFormatWithContext(aws.Context, *ec2.DescribeAggregateIdFormatInput, ...request.Option) (*ec2.DescribeAggregateIdFormatOutput, error) + DescribeAggregateIdFormatRequest(*ec2.DescribeAggregateIdFormatInput) (*request.Request, *ec2.DescribeAggregateIdFormatOutput) + + DescribeAvailabilityZones(*ec2.DescribeAvailabilityZonesInput) (*ec2.DescribeAvailabilityZonesOutput, error) + DescribeAvailabilityZonesWithContext(aws.Context, *ec2.DescribeAvailabilityZonesInput, ...request.Option) (*ec2.DescribeAvailabilityZonesOutput, error) + DescribeAvailabilityZonesRequest(*ec2.DescribeAvailabilityZonesInput) (*request.Request, *ec2.DescribeAvailabilityZonesOutput) + + DescribeAwsNetworkPerformanceMetricSubscriptions(*ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsInput) (*ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsOutput, error) + DescribeAwsNetworkPerformanceMetricSubscriptionsWithContext(aws.Context, *ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsInput, ...request.Option) (*ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsOutput, error) + DescribeAwsNetworkPerformanceMetricSubscriptionsRequest(*ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsInput) (*request.Request, *ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsOutput) + + DescribeAwsNetworkPerformanceMetricSubscriptionsPages(*ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsInput, func(*ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsOutput, bool) bool) error + DescribeAwsNetworkPerformanceMetricSubscriptionsPagesWithContext(aws.Context, *ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsInput, func(*ec2.DescribeAwsNetworkPerformanceMetricSubscriptionsOutput, bool) bool, ...request.Option) error + + DescribeBundleTasks(*ec2.DescribeBundleTasksInput) (*ec2.DescribeBundleTasksOutput, error) + DescribeBundleTasksWithContext(aws.Context, *ec2.DescribeBundleTasksInput, ...request.Option) (*ec2.DescribeBundleTasksOutput, error) + DescribeBundleTasksRequest(*ec2.DescribeBundleTasksInput) (*request.Request, *ec2.DescribeBundleTasksOutput) + + DescribeByoipCidrs(*ec2.DescribeByoipCidrsInput) (*ec2.DescribeByoipCidrsOutput, error) + DescribeByoipCidrsWithContext(aws.Context, *ec2.DescribeByoipCidrsInput, ...request.Option) (*ec2.DescribeByoipCidrsOutput, error) + DescribeByoipCidrsRequest(*ec2.DescribeByoipCidrsInput) (*request.Request, *ec2.DescribeByoipCidrsOutput) + + DescribeByoipCidrsPages(*ec2.DescribeByoipCidrsInput, func(*ec2.DescribeByoipCidrsOutput, bool) bool) error + DescribeByoipCidrsPagesWithContext(aws.Context, *ec2.DescribeByoipCidrsInput, func(*ec2.DescribeByoipCidrsOutput, bool) bool, ...request.Option) error + + DescribeCapacityReservationFleets(*ec2.DescribeCapacityReservationFleetsInput) (*ec2.DescribeCapacityReservationFleetsOutput, error) + DescribeCapacityReservationFleetsWithContext(aws.Context, *ec2.DescribeCapacityReservationFleetsInput, ...request.Option) (*ec2.DescribeCapacityReservationFleetsOutput, error) + DescribeCapacityReservationFleetsRequest(*ec2.DescribeCapacityReservationFleetsInput) (*request.Request, *ec2.DescribeCapacityReservationFleetsOutput) + + DescribeCapacityReservationFleetsPages(*ec2.DescribeCapacityReservationFleetsInput, func(*ec2.DescribeCapacityReservationFleetsOutput, bool) bool) error + DescribeCapacityReservationFleetsPagesWithContext(aws.Context, *ec2.DescribeCapacityReservationFleetsInput, func(*ec2.DescribeCapacityReservationFleetsOutput, bool) bool, ...request.Option) error + + DescribeCapacityReservations(*ec2.DescribeCapacityReservationsInput) (*ec2.DescribeCapacityReservationsOutput, error) + DescribeCapacityReservationsWithContext(aws.Context, *ec2.DescribeCapacityReservationsInput, ...request.Option) (*ec2.DescribeCapacityReservationsOutput, error) + DescribeCapacityReservationsRequest(*ec2.DescribeCapacityReservationsInput) (*request.Request, *ec2.DescribeCapacityReservationsOutput) + + DescribeCapacityReservationsPages(*ec2.DescribeCapacityReservationsInput, func(*ec2.DescribeCapacityReservationsOutput, bool) bool) error + DescribeCapacityReservationsPagesWithContext(aws.Context, *ec2.DescribeCapacityReservationsInput, func(*ec2.DescribeCapacityReservationsOutput, bool) bool, ...request.Option) error + + DescribeCarrierGateways(*ec2.DescribeCarrierGatewaysInput) (*ec2.DescribeCarrierGatewaysOutput, error) + DescribeCarrierGatewaysWithContext(aws.Context, *ec2.DescribeCarrierGatewaysInput, ...request.Option) (*ec2.DescribeCarrierGatewaysOutput, error) + DescribeCarrierGatewaysRequest(*ec2.DescribeCarrierGatewaysInput) (*request.Request, *ec2.DescribeCarrierGatewaysOutput) + + DescribeCarrierGatewaysPages(*ec2.DescribeCarrierGatewaysInput, func(*ec2.DescribeCarrierGatewaysOutput, bool) bool) error + DescribeCarrierGatewaysPagesWithContext(aws.Context, *ec2.DescribeCarrierGatewaysInput, func(*ec2.DescribeCarrierGatewaysOutput, bool) bool, ...request.Option) error + + DescribeClassicLinkInstances(*ec2.DescribeClassicLinkInstancesInput) (*ec2.DescribeClassicLinkInstancesOutput, error) + DescribeClassicLinkInstancesWithContext(aws.Context, *ec2.DescribeClassicLinkInstancesInput, ...request.Option) (*ec2.DescribeClassicLinkInstancesOutput, error) + DescribeClassicLinkInstancesRequest(*ec2.DescribeClassicLinkInstancesInput) (*request.Request, *ec2.DescribeClassicLinkInstancesOutput) + + DescribeClassicLinkInstancesPages(*ec2.DescribeClassicLinkInstancesInput, func(*ec2.DescribeClassicLinkInstancesOutput, bool) bool) error + DescribeClassicLinkInstancesPagesWithContext(aws.Context, *ec2.DescribeClassicLinkInstancesInput, func(*ec2.DescribeClassicLinkInstancesOutput, bool) bool, ...request.Option) error + + DescribeClientVpnAuthorizationRules(*ec2.DescribeClientVpnAuthorizationRulesInput) (*ec2.DescribeClientVpnAuthorizationRulesOutput, error) + DescribeClientVpnAuthorizationRulesWithContext(aws.Context, *ec2.DescribeClientVpnAuthorizationRulesInput, ...request.Option) (*ec2.DescribeClientVpnAuthorizationRulesOutput, error) + DescribeClientVpnAuthorizationRulesRequest(*ec2.DescribeClientVpnAuthorizationRulesInput) (*request.Request, *ec2.DescribeClientVpnAuthorizationRulesOutput) + + DescribeClientVpnAuthorizationRulesPages(*ec2.DescribeClientVpnAuthorizationRulesInput, func(*ec2.DescribeClientVpnAuthorizationRulesOutput, bool) bool) error + DescribeClientVpnAuthorizationRulesPagesWithContext(aws.Context, *ec2.DescribeClientVpnAuthorizationRulesInput, func(*ec2.DescribeClientVpnAuthorizationRulesOutput, bool) bool, ...request.Option) error + + DescribeClientVpnConnections(*ec2.DescribeClientVpnConnectionsInput) (*ec2.DescribeClientVpnConnectionsOutput, error) + DescribeClientVpnConnectionsWithContext(aws.Context, *ec2.DescribeClientVpnConnectionsInput, ...request.Option) (*ec2.DescribeClientVpnConnectionsOutput, error) + DescribeClientVpnConnectionsRequest(*ec2.DescribeClientVpnConnectionsInput) (*request.Request, *ec2.DescribeClientVpnConnectionsOutput) + + DescribeClientVpnConnectionsPages(*ec2.DescribeClientVpnConnectionsInput, func(*ec2.DescribeClientVpnConnectionsOutput, bool) bool) error + DescribeClientVpnConnectionsPagesWithContext(aws.Context, *ec2.DescribeClientVpnConnectionsInput, func(*ec2.DescribeClientVpnConnectionsOutput, bool) bool, ...request.Option) error + + DescribeClientVpnEndpoints(*ec2.DescribeClientVpnEndpointsInput) (*ec2.DescribeClientVpnEndpointsOutput, error) + DescribeClientVpnEndpointsWithContext(aws.Context, *ec2.DescribeClientVpnEndpointsInput, ...request.Option) (*ec2.DescribeClientVpnEndpointsOutput, error) + DescribeClientVpnEndpointsRequest(*ec2.DescribeClientVpnEndpointsInput) (*request.Request, *ec2.DescribeClientVpnEndpointsOutput) + + DescribeClientVpnEndpointsPages(*ec2.DescribeClientVpnEndpointsInput, func(*ec2.DescribeClientVpnEndpointsOutput, bool) bool) error + DescribeClientVpnEndpointsPagesWithContext(aws.Context, *ec2.DescribeClientVpnEndpointsInput, func(*ec2.DescribeClientVpnEndpointsOutput, bool) bool, ...request.Option) error + + DescribeClientVpnRoutes(*ec2.DescribeClientVpnRoutesInput) (*ec2.DescribeClientVpnRoutesOutput, error) + DescribeClientVpnRoutesWithContext(aws.Context, *ec2.DescribeClientVpnRoutesInput, ...request.Option) (*ec2.DescribeClientVpnRoutesOutput, error) + DescribeClientVpnRoutesRequest(*ec2.DescribeClientVpnRoutesInput) (*request.Request, *ec2.DescribeClientVpnRoutesOutput) + + DescribeClientVpnRoutesPages(*ec2.DescribeClientVpnRoutesInput, func(*ec2.DescribeClientVpnRoutesOutput, bool) bool) error + DescribeClientVpnRoutesPagesWithContext(aws.Context, *ec2.DescribeClientVpnRoutesInput, func(*ec2.DescribeClientVpnRoutesOutput, bool) bool, ...request.Option) error + + DescribeClientVpnTargetNetworks(*ec2.DescribeClientVpnTargetNetworksInput) (*ec2.DescribeClientVpnTargetNetworksOutput, error) + DescribeClientVpnTargetNetworksWithContext(aws.Context, *ec2.DescribeClientVpnTargetNetworksInput, ...request.Option) (*ec2.DescribeClientVpnTargetNetworksOutput, error) + DescribeClientVpnTargetNetworksRequest(*ec2.DescribeClientVpnTargetNetworksInput) (*request.Request, *ec2.DescribeClientVpnTargetNetworksOutput) + + DescribeClientVpnTargetNetworksPages(*ec2.DescribeClientVpnTargetNetworksInput, func(*ec2.DescribeClientVpnTargetNetworksOutput, bool) bool) error + DescribeClientVpnTargetNetworksPagesWithContext(aws.Context, *ec2.DescribeClientVpnTargetNetworksInput, func(*ec2.DescribeClientVpnTargetNetworksOutput, bool) bool, ...request.Option) error + + DescribeCoipPools(*ec2.DescribeCoipPoolsInput) (*ec2.DescribeCoipPoolsOutput, error) + DescribeCoipPoolsWithContext(aws.Context, *ec2.DescribeCoipPoolsInput, ...request.Option) (*ec2.DescribeCoipPoolsOutput, error) + DescribeCoipPoolsRequest(*ec2.DescribeCoipPoolsInput) (*request.Request, *ec2.DescribeCoipPoolsOutput) + + DescribeCoipPoolsPages(*ec2.DescribeCoipPoolsInput, func(*ec2.DescribeCoipPoolsOutput, bool) bool) error + DescribeCoipPoolsPagesWithContext(aws.Context, *ec2.DescribeCoipPoolsInput, func(*ec2.DescribeCoipPoolsOutput, bool) bool, ...request.Option) error + + DescribeConversionTasks(*ec2.DescribeConversionTasksInput) (*ec2.DescribeConversionTasksOutput, error) + DescribeConversionTasksWithContext(aws.Context, *ec2.DescribeConversionTasksInput, ...request.Option) (*ec2.DescribeConversionTasksOutput, error) + DescribeConversionTasksRequest(*ec2.DescribeConversionTasksInput) (*request.Request, *ec2.DescribeConversionTasksOutput) + + DescribeCustomerGateways(*ec2.DescribeCustomerGatewaysInput) (*ec2.DescribeCustomerGatewaysOutput, error) + DescribeCustomerGatewaysWithContext(aws.Context, *ec2.DescribeCustomerGatewaysInput, ...request.Option) (*ec2.DescribeCustomerGatewaysOutput, error) + DescribeCustomerGatewaysRequest(*ec2.DescribeCustomerGatewaysInput) (*request.Request, *ec2.DescribeCustomerGatewaysOutput) + + DescribeDhcpOptions(*ec2.DescribeDhcpOptionsInput) (*ec2.DescribeDhcpOptionsOutput, error) + DescribeDhcpOptionsWithContext(aws.Context, *ec2.DescribeDhcpOptionsInput, ...request.Option) (*ec2.DescribeDhcpOptionsOutput, error) + DescribeDhcpOptionsRequest(*ec2.DescribeDhcpOptionsInput) (*request.Request, *ec2.DescribeDhcpOptionsOutput) + + DescribeDhcpOptionsPages(*ec2.DescribeDhcpOptionsInput, func(*ec2.DescribeDhcpOptionsOutput, bool) bool) error + DescribeDhcpOptionsPagesWithContext(aws.Context, *ec2.DescribeDhcpOptionsInput, func(*ec2.DescribeDhcpOptionsOutput, bool) bool, ...request.Option) error + + DescribeEgressOnlyInternetGateways(*ec2.DescribeEgressOnlyInternetGatewaysInput) (*ec2.DescribeEgressOnlyInternetGatewaysOutput, error) + DescribeEgressOnlyInternetGatewaysWithContext(aws.Context, *ec2.DescribeEgressOnlyInternetGatewaysInput, ...request.Option) (*ec2.DescribeEgressOnlyInternetGatewaysOutput, error) + DescribeEgressOnlyInternetGatewaysRequest(*ec2.DescribeEgressOnlyInternetGatewaysInput) (*request.Request, *ec2.DescribeEgressOnlyInternetGatewaysOutput) + + DescribeEgressOnlyInternetGatewaysPages(*ec2.DescribeEgressOnlyInternetGatewaysInput, func(*ec2.DescribeEgressOnlyInternetGatewaysOutput, bool) bool) error + DescribeEgressOnlyInternetGatewaysPagesWithContext(aws.Context, *ec2.DescribeEgressOnlyInternetGatewaysInput, func(*ec2.DescribeEgressOnlyInternetGatewaysOutput, bool) bool, ...request.Option) error + + DescribeElasticGpus(*ec2.DescribeElasticGpusInput) (*ec2.DescribeElasticGpusOutput, error) + DescribeElasticGpusWithContext(aws.Context, *ec2.DescribeElasticGpusInput, ...request.Option) (*ec2.DescribeElasticGpusOutput, error) + DescribeElasticGpusRequest(*ec2.DescribeElasticGpusInput) (*request.Request, *ec2.DescribeElasticGpusOutput) + + DescribeExportImageTasks(*ec2.DescribeExportImageTasksInput) (*ec2.DescribeExportImageTasksOutput, error) + DescribeExportImageTasksWithContext(aws.Context, *ec2.DescribeExportImageTasksInput, ...request.Option) (*ec2.DescribeExportImageTasksOutput, error) + DescribeExportImageTasksRequest(*ec2.DescribeExportImageTasksInput) (*request.Request, *ec2.DescribeExportImageTasksOutput) + + DescribeExportImageTasksPages(*ec2.DescribeExportImageTasksInput, func(*ec2.DescribeExportImageTasksOutput, bool) bool) error + DescribeExportImageTasksPagesWithContext(aws.Context, *ec2.DescribeExportImageTasksInput, func(*ec2.DescribeExportImageTasksOutput, bool) bool, ...request.Option) error + + DescribeExportTasks(*ec2.DescribeExportTasksInput) (*ec2.DescribeExportTasksOutput, error) + DescribeExportTasksWithContext(aws.Context, *ec2.DescribeExportTasksInput, ...request.Option) (*ec2.DescribeExportTasksOutput, error) + DescribeExportTasksRequest(*ec2.DescribeExportTasksInput) (*request.Request, *ec2.DescribeExportTasksOutput) + + DescribeFastLaunchImages(*ec2.DescribeFastLaunchImagesInput) (*ec2.DescribeFastLaunchImagesOutput, error) + DescribeFastLaunchImagesWithContext(aws.Context, *ec2.DescribeFastLaunchImagesInput, ...request.Option) (*ec2.DescribeFastLaunchImagesOutput, error) + DescribeFastLaunchImagesRequest(*ec2.DescribeFastLaunchImagesInput) (*request.Request, *ec2.DescribeFastLaunchImagesOutput) + + DescribeFastLaunchImagesPages(*ec2.DescribeFastLaunchImagesInput, func(*ec2.DescribeFastLaunchImagesOutput, bool) bool) error + DescribeFastLaunchImagesPagesWithContext(aws.Context, *ec2.DescribeFastLaunchImagesInput, func(*ec2.DescribeFastLaunchImagesOutput, bool) bool, ...request.Option) error + + DescribeFastSnapshotRestores(*ec2.DescribeFastSnapshotRestoresInput) (*ec2.DescribeFastSnapshotRestoresOutput, error) + DescribeFastSnapshotRestoresWithContext(aws.Context, *ec2.DescribeFastSnapshotRestoresInput, ...request.Option) (*ec2.DescribeFastSnapshotRestoresOutput, error) + DescribeFastSnapshotRestoresRequest(*ec2.DescribeFastSnapshotRestoresInput) (*request.Request, *ec2.DescribeFastSnapshotRestoresOutput) + + DescribeFastSnapshotRestoresPages(*ec2.DescribeFastSnapshotRestoresInput, func(*ec2.DescribeFastSnapshotRestoresOutput, bool) bool) error + DescribeFastSnapshotRestoresPagesWithContext(aws.Context, *ec2.DescribeFastSnapshotRestoresInput, func(*ec2.DescribeFastSnapshotRestoresOutput, bool) bool, ...request.Option) error + + DescribeFleetHistory(*ec2.DescribeFleetHistoryInput) (*ec2.DescribeFleetHistoryOutput, error) + DescribeFleetHistoryWithContext(aws.Context, *ec2.DescribeFleetHistoryInput, ...request.Option) (*ec2.DescribeFleetHistoryOutput, error) + DescribeFleetHistoryRequest(*ec2.DescribeFleetHistoryInput) (*request.Request, *ec2.DescribeFleetHistoryOutput) + + DescribeFleetInstances(*ec2.DescribeFleetInstancesInput) (*ec2.DescribeFleetInstancesOutput, error) + DescribeFleetInstancesWithContext(aws.Context, *ec2.DescribeFleetInstancesInput, ...request.Option) (*ec2.DescribeFleetInstancesOutput, error) + DescribeFleetInstancesRequest(*ec2.DescribeFleetInstancesInput) (*request.Request, *ec2.DescribeFleetInstancesOutput) + + DescribeFleets(*ec2.DescribeFleetsInput) (*ec2.DescribeFleetsOutput, error) + DescribeFleetsWithContext(aws.Context, *ec2.DescribeFleetsInput, ...request.Option) (*ec2.DescribeFleetsOutput, error) + DescribeFleetsRequest(*ec2.DescribeFleetsInput) (*request.Request, *ec2.DescribeFleetsOutput) + + DescribeFleetsPages(*ec2.DescribeFleetsInput, func(*ec2.DescribeFleetsOutput, bool) bool) error + DescribeFleetsPagesWithContext(aws.Context, *ec2.DescribeFleetsInput, func(*ec2.DescribeFleetsOutput, bool) bool, ...request.Option) error + + DescribeFlowLogs(*ec2.DescribeFlowLogsInput) (*ec2.DescribeFlowLogsOutput, error) + DescribeFlowLogsWithContext(aws.Context, *ec2.DescribeFlowLogsInput, ...request.Option) (*ec2.DescribeFlowLogsOutput, error) + DescribeFlowLogsRequest(*ec2.DescribeFlowLogsInput) (*request.Request, *ec2.DescribeFlowLogsOutput) + + DescribeFlowLogsPages(*ec2.DescribeFlowLogsInput, func(*ec2.DescribeFlowLogsOutput, bool) bool) error + DescribeFlowLogsPagesWithContext(aws.Context, *ec2.DescribeFlowLogsInput, func(*ec2.DescribeFlowLogsOutput, bool) bool, ...request.Option) error + + DescribeFpgaImageAttribute(*ec2.DescribeFpgaImageAttributeInput) (*ec2.DescribeFpgaImageAttributeOutput, error) + DescribeFpgaImageAttributeWithContext(aws.Context, *ec2.DescribeFpgaImageAttributeInput, ...request.Option) (*ec2.DescribeFpgaImageAttributeOutput, error) + DescribeFpgaImageAttributeRequest(*ec2.DescribeFpgaImageAttributeInput) (*request.Request, *ec2.DescribeFpgaImageAttributeOutput) + + DescribeFpgaImages(*ec2.DescribeFpgaImagesInput) (*ec2.DescribeFpgaImagesOutput, error) + DescribeFpgaImagesWithContext(aws.Context, *ec2.DescribeFpgaImagesInput, ...request.Option) (*ec2.DescribeFpgaImagesOutput, error) + DescribeFpgaImagesRequest(*ec2.DescribeFpgaImagesInput) (*request.Request, *ec2.DescribeFpgaImagesOutput) + + DescribeFpgaImagesPages(*ec2.DescribeFpgaImagesInput, func(*ec2.DescribeFpgaImagesOutput, bool) bool) error + DescribeFpgaImagesPagesWithContext(aws.Context, *ec2.DescribeFpgaImagesInput, func(*ec2.DescribeFpgaImagesOutput, bool) bool, ...request.Option) error + + DescribeHostReservationOfferings(*ec2.DescribeHostReservationOfferingsInput) (*ec2.DescribeHostReservationOfferingsOutput, error) + DescribeHostReservationOfferingsWithContext(aws.Context, *ec2.DescribeHostReservationOfferingsInput, ...request.Option) (*ec2.DescribeHostReservationOfferingsOutput, error) + DescribeHostReservationOfferingsRequest(*ec2.DescribeHostReservationOfferingsInput) (*request.Request, *ec2.DescribeHostReservationOfferingsOutput) + + DescribeHostReservationOfferingsPages(*ec2.DescribeHostReservationOfferingsInput, func(*ec2.DescribeHostReservationOfferingsOutput, bool) bool) error + DescribeHostReservationOfferingsPagesWithContext(aws.Context, *ec2.DescribeHostReservationOfferingsInput, func(*ec2.DescribeHostReservationOfferingsOutput, bool) bool, ...request.Option) error + + DescribeHostReservations(*ec2.DescribeHostReservationsInput) (*ec2.DescribeHostReservationsOutput, error) + DescribeHostReservationsWithContext(aws.Context, *ec2.DescribeHostReservationsInput, ...request.Option) (*ec2.DescribeHostReservationsOutput, error) + DescribeHostReservationsRequest(*ec2.DescribeHostReservationsInput) (*request.Request, *ec2.DescribeHostReservationsOutput) + + DescribeHostReservationsPages(*ec2.DescribeHostReservationsInput, func(*ec2.DescribeHostReservationsOutput, bool) bool) error + DescribeHostReservationsPagesWithContext(aws.Context, *ec2.DescribeHostReservationsInput, func(*ec2.DescribeHostReservationsOutput, bool) bool, ...request.Option) error + + DescribeHosts(*ec2.DescribeHostsInput) (*ec2.DescribeHostsOutput, error) + DescribeHostsWithContext(aws.Context, *ec2.DescribeHostsInput, ...request.Option) (*ec2.DescribeHostsOutput, error) + DescribeHostsRequest(*ec2.DescribeHostsInput) (*request.Request, *ec2.DescribeHostsOutput) + + DescribeHostsPages(*ec2.DescribeHostsInput, func(*ec2.DescribeHostsOutput, bool) bool) error + DescribeHostsPagesWithContext(aws.Context, *ec2.DescribeHostsInput, func(*ec2.DescribeHostsOutput, bool) bool, ...request.Option) error + + DescribeIamInstanceProfileAssociations(*ec2.DescribeIamInstanceProfileAssociationsInput) (*ec2.DescribeIamInstanceProfileAssociationsOutput, error) + DescribeIamInstanceProfileAssociationsWithContext(aws.Context, *ec2.DescribeIamInstanceProfileAssociationsInput, ...request.Option) (*ec2.DescribeIamInstanceProfileAssociationsOutput, error) + DescribeIamInstanceProfileAssociationsRequest(*ec2.DescribeIamInstanceProfileAssociationsInput) (*request.Request, *ec2.DescribeIamInstanceProfileAssociationsOutput) + + DescribeIamInstanceProfileAssociationsPages(*ec2.DescribeIamInstanceProfileAssociationsInput, func(*ec2.DescribeIamInstanceProfileAssociationsOutput, bool) bool) error + DescribeIamInstanceProfileAssociationsPagesWithContext(aws.Context, *ec2.DescribeIamInstanceProfileAssociationsInput, func(*ec2.DescribeIamInstanceProfileAssociationsOutput, bool) bool, ...request.Option) error + + DescribeIdFormat(*ec2.DescribeIdFormatInput) (*ec2.DescribeIdFormatOutput, error) + DescribeIdFormatWithContext(aws.Context, *ec2.DescribeIdFormatInput, ...request.Option) (*ec2.DescribeIdFormatOutput, error) + DescribeIdFormatRequest(*ec2.DescribeIdFormatInput) (*request.Request, *ec2.DescribeIdFormatOutput) + + DescribeIdentityIdFormat(*ec2.DescribeIdentityIdFormatInput) (*ec2.DescribeIdentityIdFormatOutput, error) + DescribeIdentityIdFormatWithContext(aws.Context, *ec2.DescribeIdentityIdFormatInput, ...request.Option) (*ec2.DescribeIdentityIdFormatOutput, error) + DescribeIdentityIdFormatRequest(*ec2.DescribeIdentityIdFormatInput) (*request.Request, *ec2.DescribeIdentityIdFormatOutput) + + DescribeImageAttribute(*ec2.DescribeImageAttributeInput) (*ec2.DescribeImageAttributeOutput, error) + DescribeImageAttributeWithContext(aws.Context, *ec2.DescribeImageAttributeInput, ...request.Option) (*ec2.DescribeImageAttributeOutput, error) + DescribeImageAttributeRequest(*ec2.DescribeImageAttributeInput) (*request.Request, *ec2.DescribeImageAttributeOutput) + + DescribeImages(*ec2.DescribeImagesInput) (*ec2.DescribeImagesOutput, error) + DescribeImagesWithContext(aws.Context, *ec2.DescribeImagesInput, ...request.Option) (*ec2.DescribeImagesOutput, error) + DescribeImagesRequest(*ec2.DescribeImagesInput) (*request.Request, *ec2.DescribeImagesOutput) + + DescribeImagesPages(*ec2.DescribeImagesInput, func(*ec2.DescribeImagesOutput, bool) bool) error + DescribeImagesPagesWithContext(aws.Context, *ec2.DescribeImagesInput, func(*ec2.DescribeImagesOutput, bool) bool, ...request.Option) error + + DescribeImportImageTasks(*ec2.DescribeImportImageTasksInput) (*ec2.DescribeImportImageTasksOutput, error) + DescribeImportImageTasksWithContext(aws.Context, *ec2.DescribeImportImageTasksInput, ...request.Option) (*ec2.DescribeImportImageTasksOutput, error) + DescribeImportImageTasksRequest(*ec2.DescribeImportImageTasksInput) (*request.Request, *ec2.DescribeImportImageTasksOutput) + + DescribeImportImageTasksPages(*ec2.DescribeImportImageTasksInput, func(*ec2.DescribeImportImageTasksOutput, bool) bool) error + DescribeImportImageTasksPagesWithContext(aws.Context, *ec2.DescribeImportImageTasksInput, func(*ec2.DescribeImportImageTasksOutput, bool) bool, ...request.Option) error + + DescribeImportSnapshotTasks(*ec2.DescribeImportSnapshotTasksInput) (*ec2.DescribeImportSnapshotTasksOutput, error) + DescribeImportSnapshotTasksWithContext(aws.Context, *ec2.DescribeImportSnapshotTasksInput, ...request.Option) (*ec2.DescribeImportSnapshotTasksOutput, error) + DescribeImportSnapshotTasksRequest(*ec2.DescribeImportSnapshotTasksInput) (*request.Request, *ec2.DescribeImportSnapshotTasksOutput) + + DescribeImportSnapshotTasksPages(*ec2.DescribeImportSnapshotTasksInput, func(*ec2.DescribeImportSnapshotTasksOutput, bool) bool) error + DescribeImportSnapshotTasksPagesWithContext(aws.Context, *ec2.DescribeImportSnapshotTasksInput, func(*ec2.DescribeImportSnapshotTasksOutput, bool) bool, ...request.Option) error + + DescribeInstanceAttribute(*ec2.DescribeInstanceAttributeInput) (*ec2.DescribeInstanceAttributeOutput, error) + DescribeInstanceAttributeWithContext(aws.Context, *ec2.DescribeInstanceAttributeInput, ...request.Option) (*ec2.DescribeInstanceAttributeOutput, error) + DescribeInstanceAttributeRequest(*ec2.DescribeInstanceAttributeInput) (*request.Request, *ec2.DescribeInstanceAttributeOutput) + + DescribeInstanceConnectEndpoints(*ec2.DescribeInstanceConnectEndpointsInput) (*ec2.DescribeInstanceConnectEndpointsOutput, error) + DescribeInstanceConnectEndpointsWithContext(aws.Context, *ec2.DescribeInstanceConnectEndpointsInput, ...request.Option) (*ec2.DescribeInstanceConnectEndpointsOutput, error) + DescribeInstanceConnectEndpointsRequest(*ec2.DescribeInstanceConnectEndpointsInput) (*request.Request, *ec2.DescribeInstanceConnectEndpointsOutput) + + DescribeInstanceConnectEndpointsPages(*ec2.DescribeInstanceConnectEndpointsInput, func(*ec2.DescribeInstanceConnectEndpointsOutput, bool) bool) error + DescribeInstanceConnectEndpointsPagesWithContext(aws.Context, *ec2.DescribeInstanceConnectEndpointsInput, func(*ec2.DescribeInstanceConnectEndpointsOutput, bool) bool, ...request.Option) error + + DescribeInstanceCreditSpecifications(*ec2.DescribeInstanceCreditSpecificationsInput) (*ec2.DescribeInstanceCreditSpecificationsOutput, error) + DescribeInstanceCreditSpecificationsWithContext(aws.Context, *ec2.DescribeInstanceCreditSpecificationsInput, ...request.Option) (*ec2.DescribeInstanceCreditSpecificationsOutput, error) + DescribeInstanceCreditSpecificationsRequest(*ec2.DescribeInstanceCreditSpecificationsInput) (*request.Request, *ec2.DescribeInstanceCreditSpecificationsOutput) + + DescribeInstanceCreditSpecificationsPages(*ec2.DescribeInstanceCreditSpecificationsInput, func(*ec2.DescribeInstanceCreditSpecificationsOutput, bool) bool) error + DescribeInstanceCreditSpecificationsPagesWithContext(aws.Context, *ec2.DescribeInstanceCreditSpecificationsInput, func(*ec2.DescribeInstanceCreditSpecificationsOutput, bool) bool, ...request.Option) error + + DescribeInstanceEventNotificationAttributes(*ec2.DescribeInstanceEventNotificationAttributesInput) (*ec2.DescribeInstanceEventNotificationAttributesOutput, error) + DescribeInstanceEventNotificationAttributesWithContext(aws.Context, *ec2.DescribeInstanceEventNotificationAttributesInput, ...request.Option) (*ec2.DescribeInstanceEventNotificationAttributesOutput, error) + DescribeInstanceEventNotificationAttributesRequest(*ec2.DescribeInstanceEventNotificationAttributesInput) (*request.Request, *ec2.DescribeInstanceEventNotificationAttributesOutput) + + DescribeInstanceEventWindows(*ec2.DescribeInstanceEventWindowsInput) (*ec2.DescribeInstanceEventWindowsOutput, error) + DescribeInstanceEventWindowsWithContext(aws.Context, *ec2.DescribeInstanceEventWindowsInput, ...request.Option) (*ec2.DescribeInstanceEventWindowsOutput, error) + DescribeInstanceEventWindowsRequest(*ec2.DescribeInstanceEventWindowsInput) (*request.Request, *ec2.DescribeInstanceEventWindowsOutput) + + DescribeInstanceEventWindowsPages(*ec2.DescribeInstanceEventWindowsInput, func(*ec2.DescribeInstanceEventWindowsOutput, bool) bool) error + DescribeInstanceEventWindowsPagesWithContext(aws.Context, *ec2.DescribeInstanceEventWindowsInput, func(*ec2.DescribeInstanceEventWindowsOutput, bool) bool, ...request.Option) error + + DescribeInstanceStatus(*ec2.DescribeInstanceStatusInput) (*ec2.DescribeInstanceStatusOutput, error) + DescribeInstanceStatusWithContext(aws.Context, *ec2.DescribeInstanceStatusInput, ...request.Option) (*ec2.DescribeInstanceStatusOutput, error) + DescribeInstanceStatusRequest(*ec2.DescribeInstanceStatusInput) (*request.Request, *ec2.DescribeInstanceStatusOutput) + + DescribeInstanceStatusPages(*ec2.DescribeInstanceStatusInput, func(*ec2.DescribeInstanceStatusOutput, bool) bool) error + DescribeInstanceStatusPagesWithContext(aws.Context, *ec2.DescribeInstanceStatusInput, func(*ec2.DescribeInstanceStatusOutput, bool) bool, ...request.Option) error + + DescribeInstanceTypeOfferings(*ec2.DescribeInstanceTypeOfferingsInput) (*ec2.DescribeInstanceTypeOfferingsOutput, error) + DescribeInstanceTypeOfferingsWithContext(aws.Context, *ec2.DescribeInstanceTypeOfferingsInput, ...request.Option) (*ec2.DescribeInstanceTypeOfferingsOutput, error) + DescribeInstanceTypeOfferingsRequest(*ec2.DescribeInstanceTypeOfferingsInput) (*request.Request, *ec2.DescribeInstanceTypeOfferingsOutput) + + DescribeInstanceTypeOfferingsPages(*ec2.DescribeInstanceTypeOfferingsInput, func(*ec2.DescribeInstanceTypeOfferingsOutput, bool) bool) error + DescribeInstanceTypeOfferingsPagesWithContext(aws.Context, *ec2.DescribeInstanceTypeOfferingsInput, func(*ec2.DescribeInstanceTypeOfferingsOutput, bool) bool, ...request.Option) error + + DescribeInstanceTypes(*ec2.DescribeInstanceTypesInput) (*ec2.DescribeInstanceTypesOutput, error) + DescribeInstanceTypesWithContext(aws.Context, *ec2.DescribeInstanceTypesInput, ...request.Option) (*ec2.DescribeInstanceTypesOutput, error) + DescribeInstanceTypesRequest(*ec2.DescribeInstanceTypesInput) (*request.Request, *ec2.DescribeInstanceTypesOutput) + + DescribeInstanceTypesPages(*ec2.DescribeInstanceTypesInput, func(*ec2.DescribeInstanceTypesOutput, bool) bool) error + DescribeInstanceTypesPagesWithContext(aws.Context, *ec2.DescribeInstanceTypesInput, func(*ec2.DescribeInstanceTypesOutput, bool) bool, ...request.Option) error + + DescribeInstances(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) + DescribeInstancesWithContext(aws.Context, *ec2.DescribeInstancesInput, ...request.Option) (*ec2.DescribeInstancesOutput, error) + DescribeInstancesRequest(*ec2.DescribeInstancesInput) (*request.Request, *ec2.DescribeInstancesOutput) + + DescribeInstancesPages(*ec2.DescribeInstancesInput, func(*ec2.DescribeInstancesOutput, bool) bool) error + DescribeInstancesPagesWithContext(aws.Context, *ec2.DescribeInstancesInput, func(*ec2.DescribeInstancesOutput, bool) bool, ...request.Option) error + + DescribeInternetGateways(*ec2.DescribeInternetGatewaysInput) (*ec2.DescribeInternetGatewaysOutput, error) + DescribeInternetGatewaysWithContext(aws.Context, *ec2.DescribeInternetGatewaysInput, ...request.Option) (*ec2.DescribeInternetGatewaysOutput, error) + DescribeInternetGatewaysRequest(*ec2.DescribeInternetGatewaysInput) (*request.Request, *ec2.DescribeInternetGatewaysOutput) + + DescribeInternetGatewaysPages(*ec2.DescribeInternetGatewaysInput, func(*ec2.DescribeInternetGatewaysOutput, bool) bool) error + DescribeInternetGatewaysPagesWithContext(aws.Context, *ec2.DescribeInternetGatewaysInput, func(*ec2.DescribeInternetGatewaysOutput, bool) bool, ...request.Option) error + + DescribeIpamPools(*ec2.DescribeIpamPoolsInput) (*ec2.DescribeIpamPoolsOutput, error) + DescribeIpamPoolsWithContext(aws.Context, *ec2.DescribeIpamPoolsInput, ...request.Option) (*ec2.DescribeIpamPoolsOutput, error) + DescribeIpamPoolsRequest(*ec2.DescribeIpamPoolsInput) (*request.Request, *ec2.DescribeIpamPoolsOutput) + + DescribeIpamPoolsPages(*ec2.DescribeIpamPoolsInput, func(*ec2.DescribeIpamPoolsOutput, bool) bool) error + DescribeIpamPoolsPagesWithContext(aws.Context, *ec2.DescribeIpamPoolsInput, func(*ec2.DescribeIpamPoolsOutput, bool) bool, ...request.Option) error + + DescribeIpamResourceDiscoveries(*ec2.DescribeIpamResourceDiscoveriesInput) (*ec2.DescribeIpamResourceDiscoveriesOutput, error) + DescribeIpamResourceDiscoveriesWithContext(aws.Context, *ec2.DescribeIpamResourceDiscoveriesInput, ...request.Option) (*ec2.DescribeIpamResourceDiscoveriesOutput, error) + DescribeIpamResourceDiscoveriesRequest(*ec2.DescribeIpamResourceDiscoveriesInput) (*request.Request, *ec2.DescribeIpamResourceDiscoveriesOutput) + + DescribeIpamResourceDiscoveriesPages(*ec2.DescribeIpamResourceDiscoveriesInput, func(*ec2.DescribeIpamResourceDiscoveriesOutput, bool) bool) error + DescribeIpamResourceDiscoveriesPagesWithContext(aws.Context, *ec2.DescribeIpamResourceDiscoveriesInput, func(*ec2.DescribeIpamResourceDiscoveriesOutput, bool) bool, ...request.Option) error + + DescribeIpamResourceDiscoveryAssociations(*ec2.DescribeIpamResourceDiscoveryAssociationsInput) (*ec2.DescribeIpamResourceDiscoveryAssociationsOutput, error) + DescribeIpamResourceDiscoveryAssociationsWithContext(aws.Context, *ec2.DescribeIpamResourceDiscoveryAssociationsInput, ...request.Option) (*ec2.DescribeIpamResourceDiscoveryAssociationsOutput, error) + DescribeIpamResourceDiscoveryAssociationsRequest(*ec2.DescribeIpamResourceDiscoveryAssociationsInput) (*request.Request, *ec2.DescribeIpamResourceDiscoveryAssociationsOutput) + + DescribeIpamResourceDiscoveryAssociationsPages(*ec2.DescribeIpamResourceDiscoveryAssociationsInput, func(*ec2.DescribeIpamResourceDiscoveryAssociationsOutput, bool) bool) error + DescribeIpamResourceDiscoveryAssociationsPagesWithContext(aws.Context, *ec2.DescribeIpamResourceDiscoveryAssociationsInput, func(*ec2.DescribeIpamResourceDiscoveryAssociationsOutput, bool) bool, ...request.Option) error + + DescribeIpamScopes(*ec2.DescribeIpamScopesInput) (*ec2.DescribeIpamScopesOutput, error) + DescribeIpamScopesWithContext(aws.Context, *ec2.DescribeIpamScopesInput, ...request.Option) (*ec2.DescribeIpamScopesOutput, error) + DescribeIpamScopesRequest(*ec2.DescribeIpamScopesInput) (*request.Request, *ec2.DescribeIpamScopesOutput) + + DescribeIpamScopesPages(*ec2.DescribeIpamScopesInput, func(*ec2.DescribeIpamScopesOutput, bool) bool) error + DescribeIpamScopesPagesWithContext(aws.Context, *ec2.DescribeIpamScopesInput, func(*ec2.DescribeIpamScopesOutput, bool) bool, ...request.Option) error + + DescribeIpams(*ec2.DescribeIpamsInput) (*ec2.DescribeIpamsOutput, error) + DescribeIpamsWithContext(aws.Context, *ec2.DescribeIpamsInput, ...request.Option) (*ec2.DescribeIpamsOutput, error) + DescribeIpamsRequest(*ec2.DescribeIpamsInput) (*request.Request, *ec2.DescribeIpamsOutput) + + DescribeIpamsPages(*ec2.DescribeIpamsInput, func(*ec2.DescribeIpamsOutput, bool) bool) error + DescribeIpamsPagesWithContext(aws.Context, *ec2.DescribeIpamsInput, func(*ec2.DescribeIpamsOutput, bool) bool, ...request.Option) error + + DescribeIpv6Pools(*ec2.DescribeIpv6PoolsInput) (*ec2.DescribeIpv6PoolsOutput, error) + DescribeIpv6PoolsWithContext(aws.Context, *ec2.DescribeIpv6PoolsInput, ...request.Option) (*ec2.DescribeIpv6PoolsOutput, error) + DescribeIpv6PoolsRequest(*ec2.DescribeIpv6PoolsInput) (*request.Request, *ec2.DescribeIpv6PoolsOutput) + + DescribeIpv6PoolsPages(*ec2.DescribeIpv6PoolsInput, func(*ec2.DescribeIpv6PoolsOutput, bool) bool) error + DescribeIpv6PoolsPagesWithContext(aws.Context, *ec2.DescribeIpv6PoolsInput, func(*ec2.DescribeIpv6PoolsOutput, bool) bool, ...request.Option) error + + DescribeKeyPairs(*ec2.DescribeKeyPairsInput) (*ec2.DescribeKeyPairsOutput, error) + DescribeKeyPairsWithContext(aws.Context, *ec2.DescribeKeyPairsInput, ...request.Option) (*ec2.DescribeKeyPairsOutput, error) + DescribeKeyPairsRequest(*ec2.DescribeKeyPairsInput) (*request.Request, *ec2.DescribeKeyPairsOutput) + + DescribeLaunchTemplateVersions(*ec2.DescribeLaunchTemplateVersionsInput) (*ec2.DescribeLaunchTemplateVersionsOutput, error) + DescribeLaunchTemplateVersionsWithContext(aws.Context, *ec2.DescribeLaunchTemplateVersionsInput, ...request.Option) (*ec2.DescribeLaunchTemplateVersionsOutput, error) + DescribeLaunchTemplateVersionsRequest(*ec2.DescribeLaunchTemplateVersionsInput) (*request.Request, *ec2.DescribeLaunchTemplateVersionsOutput) + + DescribeLaunchTemplateVersionsPages(*ec2.DescribeLaunchTemplateVersionsInput, func(*ec2.DescribeLaunchTemplateVersionsOutput, bool) bool) error + DescribeLaunchTemplateVersionsPagesWithContext(aws.Context, *ec2.DescribeLaunchTemplateVersionsInput, func(*ec2.DescribeLaunchTemplateVersionsOutput, bool) bool, ...request.Option) error + + DescribeLaunchTemplates(*ec2.DescribeLaunchTemplatesInput) (*ec2.DescribeLaunchTemplatesOutput, error) + DescribeLaunchTemplatesWithContext(aws.Context, *ec2.DescribeLaunchTemplatesInput, ...request.Option) (*ec2.DescribeLaunchTemplatesOutput, error) + DescribeLaunchTemplatesRequest(*ec2.DescribeLaunchTemplatesInput) (*request.Request, *ec2.DescribeLaunchTemplatesOutput) + + DescribeLaunchTemplatesPages(*ec2.DescribeLaunchTemplatesInput, func(*ec2.DescribeLaunchTemplatesOutput, bool) bool) error + DescribeLaunchTemplatesPagesWithContext(aws.Context, *ec2.DescribeLaunchTemplatesInput, func(*ec2.DescribeLaunchTemplatesOutput, bool) bool, ...request.Option) error + + DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociations(*ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsInput) (*ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsOutput, error) + DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsWithContext(aws.Context, *ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsInput, ...request.Option) (*ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsOutput, error) + DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsRequest(*ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsInput) (*request.Request, *ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsOutput) + + DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsPages(*ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsInput, func(*ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsOutput, bool) bool) error + DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsPagesWithContext(aws.Context, *ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsInput, func(*ec2.DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsOutput, bool) bool, ...request.Option) error + + DescribeLocalGatewayRouteTableVpcAssociations(*ec2.DescribeLocalGatewayRouteTableVpcAssociationsInput) (*ec2.DescribeLocalGatewayRouteTableVpcAssociationsOutput, error) + DescribeLocalGatewayRouteTableVpcAssociationsWithContext(aws.Context, *ec2.DescribeLocalGatewayRouteTableVpcAssociationsInput, ...request.Option) (*ec2.DescribeLocalGatewayRouteTableVpcAssociationsOutput, error) + DescribeLocalGatewayRouteTableVpcAssociationsRequest(*ec2.DescribeLocalGatewayRouteTableVpcAssociationsInput) (*request.Request, *ec2.DescribeLocalGatewayRouteTableVpcAssociationsOutput) + + DescribeLocalGatewayRouteTableVpcAssociationsPages(*ec2.DescribeLocalGatewayRouteTableVpcAssociationsInput, func(*ec2.DescribeLocalGatewayRouteTableVpcAssociationsOutput, bool) bool) error + DescribeLocalGatewayRouteTableVpcAssociationsPagesWithContext(aws.Context, *ec2.DescribeLocalGatewayRouteTableVpcAssociationsInput, func(*ec2.DescribeLocalGatewayRouteTableVpcAssociationsOutput, bool) bool, ...request.Option) error + + DescribeLocalGatewayRouteTables(*ec2.DescribeLocalGatewayRouteTablesInput) (*ec2.DescribeLocalGatewayRouteTablesOutput, error) + DescribeLocalGatewayRouteTablesWithContext(aws.Context, *ec2.DescribeLocalGatewayRouteTablesInput, ...request.Option) (*ec2.DescribeLocalGatewayRouteTablesOutput, error) + DescribeLocalGatewayRouteTablesRequest(*ec2.DescribeLocalGatewayRouteTablesInput) (*request.Request, *ec2.DescribeLocalGatewayRouteTablesOutput) + + DescribeLocalGatewayRouteTablesPages(*ec2.DescribeLocalGatewayRouteTablesInput, func(*ec2.DescribeLocalGatewayRouteTablesOutput, bool) bool) error + DescribeLocalGatewayRouteTablesPagesWithContext(aws.Context, *ec2.DescribeLocalGatewayRouteTablesInput, func(*ec2.DescribeLocalGatewayRouteTablesOutput, bool) bool, ...request.Option) error + + DescribeLocalGatewayVirtualInterfaceGroups(*ec2.DescribeLocalGatewayVirtualInterfaceGroupsInput) (*ec2.DescribeLocalGatewayVirtualInterfaceGroupsOutput, error) + DescribeLocalGatewayVirtualInterfaceGroupsWithContext(aws.Context, *ec2.DescribeLocalGatewayVirtualInterfaceGroupsInput, ...request.Option) (*ec2.DescribeLocalGatewayVirtualInterfaceGroupsOutput, error) + DescribeLocalGatewayVirtualInterfaceGroupsRequest(*ec2.DescribeLocalGatewayVirtualInterfaceGroupsInput) (*request.Request, *ec2.DescribeLocalGatewayVirtualInterfaceGroupsOutput) + + DescribeLocalGatewayVirtualInterfaceGroupsPages(*ec2.DescribeLocalGatewayVirtualInterfaceGroupsInput, func(*ec2.DescribeLocalGatewayVirtualInterfaceGroupsOutput, bool) bool) error + DescribeLocalGatewayVirtualInterfaceGroupsPagesWithContext(aws.Context, *ec2.DescribeLocalGatewayVirtualInterfaceGroupsInput, func(*ec2.DescribeLocalGatewayVirtualInterfaceGroupsOutput, bool) bool, ...request.Option) error + + DescribeLocalGatewayVirtualInterfaces(*ec2.DescribeLocalGatewayVirtualInterfacesInput) (*ec2.DescribeLocalGatewayVirtualInterfacesOutput, error) + DescribeLocalGatewayVirtualInterfacesWithContext(aws.Context, *ec2.DescribeLocalGatewayVirtualInterfacesInput, ...request.Option) (*ec2.DescribeLocalGatewayVirtualInterfacesOutput, error) + DescribeLocalGatewayVirtualInterfacesRequest(*ec2.DescribeLocalGatewayVirtualInterfacesInput) (*request.Request, *ec2.DescribeLocalGatewayVirtualInterfacesOutput) + + DescribeLocalGatewayVirtualInterfacesPages(*ec2.DescribeLocalGatewayVirtualInterfacesInput, func(*ec2.DescribeLocalGatewayVirtualInterfacesOutput, bool) bool) error + DescribeLocalGatewayVirtualInterfacesPagesWithContext(aws.Context, *ec2.DescribeLocalGatewayVirtualInterfacesInput, func(*ec2.DescribeLocalGatewayVirtualInterfacesOutput, bool) bool, ...request.Option) error + + DescribeLocalGateways(*ec2.DescribeLocalGatewaysInput) (*ec2.DescribeLocalGatewaysOutput, error) + DescribeLocalGatewaysWithContext(aws.Context, *ec2.DescribeLocalGatewaysInput, ...request.Option) (*ec2.DescribeLocalGatewaysOutput, error) + DescribeLocalGatewaysRequest(*ec2.DescribeLocalGatewaysInput) (*request.Request, *ec2.DescribeLocalGatewaysOutput) + + DescribeLocalGatewaysPages(*ec2.DescribeLocalGatewaysInput, func(*ec2.DescribeLocalGatewaysOutput, bool) bool) error + DescribeLocalGatewaysPagesWithContext(aws.Context, *ec2.DescribeLocalGatewaysInput, func(*ec2.DescribeLocalGatewaysOutput, bool) bool, ...request.Option) error + + DescribeManagedPrefixLists(*ec2.DescribeManagedPrefixListsInput) (*ec2.DescribeManagedPrefixListsOutput, error) + DescribeManagedPrefixListsWithContext(aws.Context, *ec2.DescribeManagedPrefixListsInput, ...request.Option) (*ec2.DescribeManagedPrefixListsOutput, error) + DescribeManagedPrefixListsRequest(*ec2.DescribeManagedPrefixListsInput) (*request.Request, *ec2.DescribeManagedPrefixListsOutput) + + DescribeManagedPrefixListsPages(*ec2.DescribeManagedPrefixListsInput, func(*ec2.DescribeManagedPrefixListsOutput, bool) bool) error + DescribeManagedPrefixListsPagesWithContext(aws.Context, *ec2.DescribeManagedPrefixListsInput, func(*ec2.DescribeManagedPrefixListsOutput, bool) bool, ...request.Option) error + + DescribeMovingAddresses(*ec2.DescribeMovingAddressesInput) (*ec2.DescribeMovingAddressesOutput, error) + DescribeMovingAddressesWithContext(aws.Context, *ec2.DescribeMovingAddressesInput, ...request.Option) (*ec2.DescribeMovingAddressesOutput, error) + DescribeMovingAddressesRequest(*ec2.DescribeMovingAddressesInput) (*request.Request, *ec2.DescribeMovingAddressesOutput) + + DescribeMovingAddressesPages(*ec2.DescribeMovingAddressesInput, func(*ec2.DescribeMovingAddressesOutput, bool) bool) error + DescribeMovingAddressesPagesWithContext(aws.Context, *ec2.DescribeMovingAddressesInput, func(*ec2.DescribeMovingAddressesOutput, bool) bool, ...request.Option) error + + DescribeNatGateways(*ec2.DescribeNatGatewaysInput) (*ec2.DescribeNatGatewaysOutput, error) + DescribeNatGatewaysWithContext(aws.Context, *ec2.DescribeNatGatewaysInput, ...request.Option) (*ec2.DescribeNatGatewaysOutput, error) + DescribeNatGatewaysRequest(*ec2.DescribeNatGatewaysInput) (*request.Request, *ec2.DescribeNatGatewaysOutput) + + DescribeNatGatewaysPages(*ec2.DescribeNatGatewaysInput, func(*ec2.DescribeNatGatewaysOutput, bool) bool) error + DescribeNatGatewaysPagesWithContext(aws.Context, *ec2.DescribeNatGatewaysInput, func(*ec2.DescribeNatGatewaysOutput, bool) bool, ...request.Option) error + + DescribeNetworkAcls(*ec2.DescribeNetworkAclsInput) (*ec2.DescribeNetworkAclsOutput, error) + DescribeNetworkAclsWithContext(aws.Context, *ec2.DescribeNetworkAclsInput, ...request.Option) (*ec2.DescribeNetworkAclsOutput, error) + DescribeNetworkAclsRequest(*ec2.DescribeNetworkAclsInput) (*request.Request, *ec2.DescribeNetworkAclsOutput) + + DescribeNetworkAclsPages(*ec2.DescribeNetworkAclsInput, func(*ec2.DescribeNetworkAclsOutput, bool) bool) error + DescribeNetworkAclsPagesWithContext(aws.Context, *ec2.DescribeNetworkAclsInput, func(*ec2.DescribeNetworkAclsOutput, bool) bool, ...request.Option) error + + DescribeNetworkInsightsAccessScopeAnalyses(*ec2.DescribeNetworkInsightsAccessScopeAnalysesInput) (*ec2.DescribeNetworkInsightsAccessScopeAnalysesOutput, error) + DescribeNetworkInsightsAccessScopeAnalysesWithContext(aws.Context, *ec2.DescribeNetworkInsightsAccessScopeAnalysesInput, ...request.Option) (*ec2.DescribeNetworkInsightsAccessScopeAnalysesOutput, error) + DescribeNetworkInsightsAccessScopeAnalysesRequest(*ec2.DescribeNetworkInsightsAccessScopeAnalysesInput) (*request.Request, *ec2.DescribeNetworkInsightsAccessScopeAnalysesOutput) + + DescribeNetworkInsightsAccessScopeAnalysesPages(*ec2.DescribeNetworkInsightsAccessScopeAnalysesInput, func(*ec2.DescribeNetworkInsightsAccessScopeAnalysesOutput, bool) bool) error + DescribeNetworkInsightsAccessScopeAnalysesPagesWithContext(aws.Context, *ec2.DescribeNetworkInsightsAccessScopeAnalysesInput, func(*ec2.DescribeNetworkInsightsAccessScopeAnalysesOutput, bool) bool, ...request.Option) error + + DescribeNetworkInsightsAccessScopes(*ec2.DescribeNetworkInsightsAccessScopesInput) (*ec2.DescribeNetworkInsightsAccessScopesOutput, error) + DescribeNetworkInsightsAccessScopesWithContext(aws.Context, *ec2.DescribeNetworkInsightsAccessScopesInput, ...request.Option) (*ec2.DescribeNetworkInsightsAccessScopesOutput, error) + DescribeNetworkInsightsAccessScopesRequest(*ec2.DescribeNetworkInsightsAccessScopesInput) (*request.Request, *ec2.DescribeNetworkInsightsAccessScopesOutput) + + DescribeNetworkInsightsAccessScopesPages(*ec2.DescribeNetworkInsightsAccessScopesInput, func(*ec2.DescribeNetworkInsightsAccessScopesOutput, bool) bool) error + DescribeNetworkInsightsAccessScopesPagesWithContext(aws.Context, *ec2.DescribeNetworkInsightsAccessScopesInput, func(*ec2.DescribeNetworkInsightsAccessScopesOutput, bool) bool, ...request.Option) error + + DescribeNetworkInsightsAnalyses(*ec2.DescribeNetworkInsightsAnalysesInput) (*ec2.DescribeNetworkInsightsAnalysesOutput, error) + DescribeNetworkInsightsAnalysesWithContext(aws.Context, *ec2.DescribeNetworkInsightsAnalysesInput, ...request.Option) (*ec2.DescribeNetworkInsightsAnalysesOutput, error) + DescribeNetworkInsightsAnalysesRequest(*ec2.DescribeNetworkInsightsAnalysesInput) (*request.Request, *ec2.DescribeNetworkInsightsAnalysesOutput) + + DescribeNetworkInsightsAnalysesPages(*ec2.DescribeNetworkInsightsAnalysesInput, func(*ec2.DescribeNetworkInsightsAnalysesOutput, bool) bool) error + DescribeNetworkInsightsAnalysesPagesWithContext(aws.Context, *ec2.DescribeNetworkInsightsAnalysesInput, func(*ec2.DescribeNetworkInsightsAnalysesOutput, bool) bool, ...request.Option) error + + DescribeNetworkInsightsPaths(*ec2.DescribeNetworkInsightsPathsInput) (*ec2.DescribeNetworkInsightsPathsOutput, error) + DescribeNetworkInsightsPathsWithContext(aws.Context, *ec2.DescribeNetworkInsightsPathsInput, ...request.Option) (*ec2.DescribeNetworkInsightsPathsOutput, error) + DescribeNetworkInsightsPathsRequest(*ec2.DescribeNetworkInsightsPathsInput) (*request.Request, *ec2.DescribeNetworkInsightsPathsOutput) + + DescribeNetworkInsightsPathsPages(*ec2.DescribeNetworkInsightsPathsInput, func(*ec2.DescribeNetworkInsightsPathsOutput, bool) bool) error + DescribeNetworkInsightsPathsPagesWithContext(aws.Context, *ec2.DescribeNetworkInsightsPathsInput, func(*ec2.DescribeNetworkInsightsPathsOutput, bool) bool, ...request.Option) error + + DescribeNetworkInterfaceAttribute(*ec2.DescribeNetworkInterfaceAttributeInput) (*ec2.DescribeNetworkInterfaceAttributeOutput, error) + DescribeNetworkInterfaceAttributeWithContext(aws.Context, *ec2.DescribeNetworkInterfaceAttributeInput, ...request.Option) (*ec2.DescribeNetworkInterfaceAttributeOutput, error) + DescribeNetworkInterfaceAttributeRequest(*ec2.DescribeNetworkInterfaceAttributeInput) (*request.Request, *ec2.DescribeNetworkInterfaceAttributeOutput) + + DescribeNetworkInterfacePermissions(*ec2.DescribeNetworkInterfacePermissionsInput) (*ec2.DescribeNetworkInterfacePermissionsOutput, error) + DescribeNetworkInterfacePermissionsWithContext(aws.Context, *ec2.DescribeNetworkInterfacePermissionsInput, ...request.Option) (*ec2.DescribeNetworkInterfacePermissionsOutput, error) + DescribeNetworkInterfacePermissionsRequest(*ec2.DescribeNetworkInterfacePermissionsInput) (*request.Request, *ec2.DescribeNetworkInterfacePermissionsOutput) + + DescribeNetworkInterfacePermissionsPages(*ec2.DescribeNetworkInterfacePermissionsInput, func(*ec2.DescribeNetworkInterfacePermissionsOutput, bool) bool) error + DescribeNetworkInterfacePermissionsPagesWithContext(aws.Context, *ec2.DescribeNetworkInterfacePermissionsInput, func(*ec2.DescribeNetworkInterfacePermissionsOutput, bool) bool, ...request.Option) error + + DescribeNetworkInterfaces(*ec2.DescribeNetworkInterfacesInput) (*ec2.DescribeNetworkInterfacesOutput, error) + DescribeNetworkInterfacesWithContext(aws.Context, *ec2.DescribeNetworkInterfacesInput, ...request.Option) (*ec2.DescribeNetworkInterfacesOutput, error) + DescribeNetworkInterfacesRequest(*ec2.DescribeNetworkInterfacesInput) (*request.Request, *ec2.DescribeNetworkInterfacesOutput) + + DescribeNetworkInterfacesPages(*ec2.DescribeNetworkInterfacesInput, func(*ec2.DescribeNetworkInterfacesOutput, bool) bool) error + DescribeNetworkInterfacesPagesWithContext(aws.Context, *ec2.DescribeNetworkInterfacesInput, func(*ec2.DescribeNetworkInterfacesOutput, bool) bool, ...request.Option) error + + DescribePlacementGroups(*ec2.DescribePlacementGroupsInput) (*ec2.DescribePlacementGroupsOutput, error) + DescribePlacementGroupsWithContext(aws.Context, *ec2.DescribePlacementGroupsInput, ...request.Option) (*ec2.DescribePlacementGroupsOutput, error) + DescribePlacementGroupsRequest(*ec2.DescribePlacementGroupsInput) (*request.Request, *ec2.DescribePlacementGroupsOutput) + + DescribePrefixLists(*ec2.DescribePrefixListsInput) (*ec2.DescribePrefixListsOutput, error) + DescribePrefixListsWithContext(aws.Context, *ec2.DescribePrefixListsInput, ...request.Option) (*ec2.DescribePrefixListsOutput, error) + DescribePrefixListsRequest(*ec2.DescribePrefixListsInput) (*request.Request, *ec2.DescribePrefixListsOutput) + + DescribePrefixListsPages(*ec2.DescribePrefixListsInput, func(*ec2.DescribePrefixListsOutput, bool) bool) error + DescribePrefixListsPagesWithContext(aws.Context, *ec2.DescribePrefixListsInput, func(*ec2.DescribePrefixListsOutput, bool) bool, ...request.Option) error + + DescribePrincipalIdFormat(*ec2.DescribePrincipalIdFormatInput) (*ec2.DescribePrincipalIdFormatOutput, error) + DescribePrincipalIdFormatWithContext(aws.Context, *ec2.DescribePrincipalIdFormatInput, ...request.Option) (*ec2.DescribePrincipalIdFormatOutput, error) + DescribePrincipalIdFormatRequest(*ec2.DescribePrincipalIdFormatInput) (*request.Request, *ec2.DescribePrincipalIdFormatOutput) + + DescribePrincipalIdFormatPages(*ec2.DescribePrincipalIdFormatInput, func(*ec2.DescribePrincipalIdFormatOutput, bool) bool) error + DescribePrincipalIdFormatPagesWithContext(aws.Context, *ec2.DescribePrincipalIdFormatInput, func(*ec2.DescribePrincipalIdFormatOutput, bool) bool, ...request.Option) error + + DescribePublicIpv4Pools(*ec2.DescribePublicIpv4PoolsInput) (*ec2.DescribePublicIpv4PoolsOutput, error) + DescribePublicIpv4PoolsWithContext(aws.Context, *ec2.DescribePublicIpv4PoolsInput, ...request.Option) (*ec2.DescribePublicIpv4PoolsOutput, error) + DescribePublicIpv4PoolsRequest(*ec2.DescribePublicIpv4PoolsInput) (*request.Request, *ec2.DescribePublicIpv4PoolsOutput) + + DescribePublicIpv4PoolsPages(*ec2.DescribePublicIpv4PoolsInput, func(*ec2.DescribePublicIpv4PoolsOutput, bool) bool) error + DescribePublicIpv4PoolsPagesWithContext(aws.Context, *ec2.DescribePublicIpv4PoolsInput, func(*ec2.DescribePublicIpv4PoolsOutput, bool) bool, ...request.Option) error + + DescribeRegions(*ec2.DescribeRegionsInput) (*ec2.DescribeRegionsOutput, error) + DescribeRegionsWithContext(aws.Context, *ec2.DescribeRegionsInput, ...request.Option) (*ec2.DescribeRegionsOutput, error) + DescribeRegionsRequest(*ec2.DescribeRegionsInput) (*request.Request, *ec2.DescribeRegionsOutput) + + DescribeReplaceRootVolumeTasks(*ec2.DescribeReplaceRootVolumeTasksInput) (*ec2.DescribeReplaceRootVolumeTasksOutput, error) + DescribeReplaceRootVolumeTasksWithContext(aws.Context, *ec2.DescribeReplaceRootVolumeTasksInput, ...request.Option) (*ec2.DescribeReplaceRootVolumeTasksOutput, error) + DescribeReplaceRootVolumeTasksRequest(*ec2.DescribeReplaceRootVolumeTasksInput) (*request.Request, *ec2.DescribeReplaceRootVolumeTasksOutput) + + DescribeReplaceRootVolumeTasksPages(*ec2.DescribeReplaceRootVolumeTasksInput, func(*ec2.DescribeReplaceRootVolumeTasksOutput, bool) bool) error + DescribeReplaceRootVolumeTasksPagesWithContext(aws.Context, *ec2.DescribeReplaceRootVolumeTasksInput, func(*ec2.DescribeReplaceRootVolumeTasksOutput, bool) bool, ...request.Option) error + + DescribeReservedInstances(*ec2.DescribeReservedInstancesInput) (*ec2.DescribeReservedInstancesOutput, error) + DescribeReservedInstancesWithContext(aws.Context, *ec2.DescribeReservedInstancesInput, ...request.Option) (*ec2.DescribeReservedInstancesOutput, error) + DescribeReservedInstancesRequest(*ec2.DescribeReservedInstancesInput) (*request.Request, *ec2.DescribeReservedInstancesOutput) + + DescribeReservedInstancesListings(*ec2.DescribeReservedInstancesListingsInput) (*ec2.DescribeReservedInstancesListingsOutput, error) + DescribeReservedInstancesListingsWithContext(aws.Context, *ec2.DescribeReservedInstancesListingsInput, ...request.Option) (*ec2.DescribeReservedInstancesListingsOutput, error) + DescribeReservedInstancesListingsRequest(*ec2.DescribeReservedInstancesListingsInput) (*request.Request, *ec2.DescribeReservedInstancesListingsOutput) + + DescribeReservedInstancesModifications(*ec2.DescribeReservedInstancesModificationsInput) (*ec2.DescribeReservedInstancesModificationsOutput, error) + DescribeReservedInstancesModificationsWithContext(aws.Context, *ec2.DescribeReservedInstancesModificationsInput, ...request.Option) (*ec2.DescribeReservedInstancesModificationsOutput, error) + DescribeReservedInstancesModificationsRequest(*ec2.DescribeReservedInstancesModificationsInput) (*request.Request, *ec2.DescribeReservedInstancesModificationsOutput) + + DescribeReservedInstancesModificationsPages(*ec2.DescribeReservedInstancesModificationsInput, func(*ec2.DescribeReservedInstancesModificationsOutput, bool) bool) error + DescribeReservedInstancesModificationsPagesWithContext(aws.Context, *ec2.DescribeReservedInstancesModificationsInput, func(*ec2.DescribeReservedInstancesModificationsOutput, bool) bool, ...request.Option) error + + DescribeReservedInstancesOfferings(*ec2.DescribeReservedInstancesOfferingsInput) (*ec2.DescribeReservedInstancesOfferingsOutput, error) + DescribeReservedInstancesOfferingsWithContext(aws.Context, *ec2.DescribeReservedInstancesOfferingsInput, ...request.Option) (*ec2.DescribeReservedInstancesOfferingsOutput, error) + DescribeReservedInstancesOfferingsRequest(*ec2.DescribeReservedInstancesOfferingsInput) (*request.Request, *ec2.DescribeReservedInstancesOfferingsOutput) + + DescribeReservedInstancesOfferingsPages(*ec2.DescribeReservedInstancesOfferingsInput, func(*ec2.DescribeReservedInstancesOfferingsOutput, bool) bool) error + DescribeReservedInstancesOfferingsPagesWithContext(aws.Context, *ec2.DescribeReservedInstancesOfferingsInput, func(*ec2.DescribeReservedInstancesOfferingsOutput, bool) bool, ...request.Option) error + + DescribeRouteTables(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) + DescribeRouteTablesWithContext(aws.Context, *ec2.DescribeRouteTablesInput, ...request.Option) (*ec2.DescribeRouteTablesOutput, error) + DescribeRouteTablesRequest(*ec2.DescribeRouteTablesInput) (*request.Request, *ec2.DescribeRouteTablesOutput) + + DescribeRouteTablesPages(*ec2.DescribeRouteTablesInput, func(*ec2.DescribeRouteTablesOutput, bool) bool) error + DescribeRouteTablesPagesWithContext(aws.Context, *ec2.DescribeRouteTablesInput, func(*ec2.DescribeRouteTablesOutput, bool) bool, ...request.Option) error + + DescribeScheduledInstanceAvailability(*ec2.DescribeScheduledInstanceAvailabilityInput) (*ec2.DescribeScheduledInstanceAvailabilityOutput, error) + DescribeScheduledInstanceAvailabilityWithContext(aws.Context, *ec2.DescribeScheduledInstanceAvailabilityInput, ...request.Option) (*ec2.DescribeScheduledInstanceAvailabilityOutput, error) + DescribeScheduledInstanceAvailabilityRequest(*ec2.DescribeScheduledInstanceAvailabilityInput) (*request.Request, *ec2.DescribeScheduledInstanceAvailabilityOutput) + + DescribeScheduledInstanceAvailabilityPages(*ec2.DescribeScheduledInstanceAvailabilityInput, func(*ec2.DescribeScheduledInstanceAvailabilityOutput, bool) bool) error + DescribeScheduledInstanceAvailabilityPagesWithContext(aws.Context, *ec2.DescribeScheduledInstanceAvailabilityInput, func(*ec2.DescribeScheduledInstanceAvailabilityOutput, bool) bool, ...request.Option) error + + DescribeScheduledInstances(*ec2.DescribeScheduledInstancesInput) (*ec2.DescribeScheduledInstancesOutput, error) + DescribeScheduledInstancesWithContext(aws.Context, *ec2.DescribeScheduledInstancesInput, ...request.Option) (*ec2.DescribeScheduledInstancesOutput, error) + DescribeScheduledInstancesRequest(*ec2.DescribeScheduledInstancesInput) (*request.Request, *ec2.DescribeScheduledInstancesOutput) + + DescribeScheduledInstancesPages(*ec2.DescribeScheduledInstancesInput, func(*ec2.DescribeScheduledInstancesOutput, bool) bool) error + DescribeScheduledInstancesPagesWithContext(aws.Context, *ec2.DescribeScheduledInstancesInput, func(*ec2.DescribeScheduledInstancesOutput, bool) bool, ...request.Option) error + + DescribeSecurityGroupReferences(*ec2.DescribeSecurityGroupReferencesInput) (*ec2.DescribeSecurityGroupReferencesOutput, error) + DescribeSecurityGroupReferencesWithContext(aws.Context, *ec2.DescribeSecurityGroupReferencesInput, ...request.Option) (*ec2.DescribeSecurityGroupReferencesOutput, error) + DescribeSecurityGroupReferencesRequest(*ec2.DescribeSecurityGroupReferencesInput) (*request.Request, *ec2.DescribeSecurityGroupReferencesOutput) + + DescribeSecurityGroupRules(*ec2.DescribeSecurityGroupRulesInput) (*ec2.DescribeSecurityGroupRulesOutput, error) + DescribeSecurityGroupRulesWithContext(aws.Context, *ec2.DescribeSecurityGroupRulesInput, ...request.Option) (*ec2.DescribeSecurityGroupRulesOutput, error) + DescribeSecurityGroupRulesRequest(*ec2.DescribeSecurityGroupRulesInput) (*request.Request, *ec2.DescribeSecurityGroupRulesOutput) + + DescribeSecurityGroupRulesPages(*ec2.DescribeSecurityGroupRulesInput, func(*ec2.DescribeSecurityGroupRulesOutput, bool) bool) error + DescribeSecurityGroupRulesPagesWithContext(aws.Context, *ec2.DescribeSecurityGroupRulesInput, func(*ec2.DescribeSecurityGroupRulesOutput, bool) bool, ...request.Option) error + + DescribeSecurityGroups(*ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) + DescribeSecurityGroupsWithContext(aws.Context, *ec2.DescribeSecurityGroupsInput, ...request.Option) (*ec2.DescribeSecurityGroupsOutput, error) + DescribeSecurityGroupsRequest(*ec2.DescribeSecurityGroupsInput) (*request.Request, *ec2.DescribeSecurityGroupsOutput) + + DescribeSecurityGroupsPages(*ec2.DescribeSecurityGroupsInput, func(*ec2.DescribeSecurityGroupsOutput, bool) bool) error + DescribeSecurityGroupsPagesWithContext(aws.Context, *ec2.DescribeSecurityGroupsInput, func(*ec2.DescribeSecurityGroupsOutput, bool) bool, ...request.Option) error + + DescribeSnapshotAttribute(*ec2.DescribeSnapshotAttributeInput) (*ec2.DescribeSnapshotAttributeOutput, error) + DescribeSnapshotAttributeWithContext(aws.Context, *ec2.DescribeSnapshotAttributeInput, ...request.Option) (*ec2.DescribeSnapshotAttributeOutput, error) + DescribeSnapshotAttributeRequest(*ec2.DescribeSnapshotAttributeInput) (*request.Request, *ec2.DescribeSnapshotAttributeOutput) + + DescribeSnapshotTierStatus(*ec2.DescribeSnapshotTierStatusInput) (*ec2.DescribeSnapshotTierStatusOutput, error) + DescribeSnapshotTierStatusWithContext(aws.Context, *ec2.DescribeSnapshotTierStatusInput, ...request.Option) (*ec2.DescribeSnapshotTierStatusOutput, error) + DescribeSnapshotTierStatusRequest(*ec2.DescribeSnapshotTierStatusInput) (*request.Request, *ec2.DescribeSnapshotTierStatusOutput) + + DescribeSnapshotTierStatusPages(*ec2.DescribeSnapshotTierStatusInput, func(*ec2.DescribeSnapshotTierStatusOutput, bool) bool) error + DescribeSnapshotTierStatusPagesWithContext(aws.Context, *ec2.DescribeSnapshotTierStatusInput, func(*ec2.DescribeSnapshotTierStatusOutput, bool) bool, ...request.Option) error + + DescribeSnapshots(*ec2.DescribeSnapshotsInput) (*ec2.DescribeSnapshotsOutput, error) + DescribeSnapshotsWithContext(aws.Context, *ec2.DescribeSnapshotsInput, ...request.Option) (*ec2.DescribeSnapshotsOutput, error) + DescribeSnapshotsRequest(*ec2.DescribeSnapshotsInput) (*request.Request, *ec2.DescribeSnapshotsOutput) + + DescribeSnapshotsPages(*ec2.DescribeSnapshotsInput, func(*ec2.DescribeSnapshotsOutput, bool) bool) error + DescribeSnapshotsPagesWithContext(aws.Context, *ec2.DescribeSnapshotsInput, func(*ec2.DescribeSnapshotsOutput, bool) bool, ...request.Option) error + + DescribeSpotDatafeedSubscription(*ec2.DescribeSpotDatafeedSubscriptionInput) (*ec2.DescribeSpotDatafeedSubscriptionOutput, error) + DescribeSpotDatafeedSubscriptionWithContext(aws.Context, *ec2.DescribeSpotDatafeedSubscriptionInput, ...request.Option) (*ec2.DescribeSpotDatafeedSubscriptionOutput, error) + DescribeSpotDatafeedSubscriptionRequest(*ec2.DescribeSpotDatafeedSubscriptionInput) (*request.Request, *ec2.DescribeSpotDatafeedSubscriptionOutput) + + DescribeSpotFleetInstances(*ec2.DescribeSpotFleetInstancesInput) (*ec2.DescribeSpotFleetInstancesOutput, error) + DescribeSpotFleetInstancesWithContext(aws.Context, *ec2.DescribeSpotFleetInstancesInput, ...request.Option) (*ec2.DescribeSpotFleetInstancesOutput, error) + DescribeSpotFleetInstancesRequest(*ec2.DescribeSpotFleetInstancesInput) (*request.Request, *ec2.DescribeSpotFleetInstancesOutput) + + DescribeSpotFleetRequestHistory(*ec2.DescribeSpotFleetRequestHistoryInput) (*ec2.DescribeSpotFleetRequestHistoryOutput, error) + DescribeSpotFleetRequestHistoryWithContext(aws.Context, *ec2.DescribeSpotFleetRequestHistoryInput, ...request.Option) (*ec2.DescribeSpotFleetRequestHistoryOutput, error) + DescribeSpotFleetRequestHistoryRequest(*ec2.DescribeSpotFleetRequestHistoryInput) (*request.Request, *ec2.DescribeSpotFleetRequestHistoryOutput) + + DescribeSpotFleetRequests(*ec2.DescribeSpotFleetRequestsInput) (*ec2.DescribeSpotFleetRequestsOutput, error) + DescribeSpotFleetRequestsWithContext(aws.Context, *ec2.DescribeSpotFleetRequestsInput, ...request.Option) (*ec2.DescribeSpotFleetRequestsOutput, error) + DescribeSpotFleetRequestsRequest(*ec2.DescribeSpotFleetRequestsInput) (*request.Request, *ec2.DescribeSpotFleetRequestsOutput) + + DescribeSpotFleetRequestsPages(*ec2.DescribeSpotFleetRequestsInput, func(*ec2.DescribeSpotFleetRequestsOutput, bool) bool) error + DescribeSpotFleetRequestsPagesWithContext(aws.Context, *ec2.DescribeSpotFleetRequestsInput, func(*ec2.DescribeSpotFleetRequestsOutput, bool) bool, ...request.Option) error + + DescribeSpotInstanceRequests(*ec2.DescribeSpotInstanceRequestsInput) (*ec2.DescribeSpotInstanceRequestsOutput, error) + DescribeSpotInstanceRequestsWithContext(aws.Context, *ec2.DescribeSpotInstanceRequestsInput, ...request.Option) (*ec2.DescribeSpotInstanceRequestsOutput, error) + DescribeSpotInstanceRequestsRequest(*ec2.DescribeSpotInstanceRequestsInput) (*request.Request, *ec2.DescribeSpotInstanceRequestsOutput) + + DescribeSpotInstanceRequestsPages(*ec2.DescribeSpotInstanceRequestsInput, func(*ec2.DescribeSpotInstanceRequestsOutput, bool) bool) error + DescribeSpotInstanceRequestsPagesWithContext(aws.Context, *ec2.DescribeSpotInstanceRequestsInput, func(*ec2.DescribeSpotInstanceRequestsOutput, bool) bool, ...request.Option) error + + DescribeSpotPriceHistory(*ec2.DescribeSpotPriceHistoryInput) (*ec2.DescribeSpotPriceHistoryOutput, error) + DescribeSpotPriceHistoryWithContext(aws.Context, *ec2.DescribeSpotPriceHistoryInput, ...request.Option) (*ec2.DescribeSpotPriceHistoryOutput, error) + DescribeSpotPriceHistoryRequest(*ec2.DescribeSpotPriceHistoryInput) (*request.Request, *ec2.DescribeSpotPriceHistoryOutput) + + DescribeSpotPriceHistoryPages(*ec2.DescribeSpotPriceHistoryInput, func(*ec2.DescribeSpotPriceHistoryOutput, bool) bool) error + DescribeSpotPriceHistoryPagesWithContext(aws.Context, *ec2.DescribeSpotPriceHistoryInput, func(*ec2.DescribeSpotPriceHistoryOutput, bool) bool, ...request.Option) error + + DescribeStaleSecurityGroups(*ec2.DescribeStaleSecurityGroupsInput) (*ec2.DescribeStaleSecurityGroupsOutput, error) + DescribeStaleSecurityGroupsWithContext(aws.Context, *ec2.DescribeStaleSecurityGroupsInput, ...request.Option) (*ec2.DescribeStaleSecurityGroupsOutput, error) + DescribeStaleSecurityGroupsRequest(*ec2.DescribeStaleSecurityGroupsInput) (*request.Request, *ec2.DescribeStaleSecurityGroupsOutput) + + DescribeStaleSecurityGroupsPages(*ec2.DescribeStaleSecurityGroupsInput, func(*ec2.DescribeStaleSecurityGroupsOutput, bool) bool) error + DescribeStaleSecurityGroupsPagesWithContext(aws.Context, *ec2.DescribeStaleSecurityGroupsInput, func(*ec2.DescribeStaleSecurityGroupsOutput, bool) bool, ...request.Option) error + + DescribeStoreImageTasks(*ec2.DescribeStoreImageTasksInput) (*ec2.DescribeStoreImageTasksOutput, error) + DescribeStoreImageTasksWithContext(aws.Context, *ec2.DescribeStoreImageTasksInput, ...request.Option) (*ec2.DescribeStoreImageTasksOutput, error) + DescribeStoreImageTasksRequest(*ec2.DescribeStoreImageTasksInput) (*request.Request, *ec2.DescribeStoreImageTasksOutput) + + DescribeStoreImageTasksPages(*ec2.DescribeStoreImageTasksInput, func(*ec2.DescribeStoreImageTasksOutput, bool) bool) error + DescribeStoreImageTasksPagesWithContext(aws.Context, *ec2.DescribeStoreImageTasksInput, func(*ec2.DescribeStoreImageTasksOutput, bool) bool, ...request.Option) error + + DescribeSubnets(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) + DescribeSubnetsWithContext(aws.Context, *ec2.DescribeSubnetsInput, ...request.Option) (*ec2.DescribeSubnetsOutput, error) + DescribeSubnetsRequest(*ec2.DescribeSubnetsInput) (*request.Request, *ec2.DescribeSubnetsOutput) + + DescribeSubnetsPages(*ec2.DescribeSubnetsInput, func(*ec2.DescribeSubnetsOutput, bool) bool) error + DescribeSubnetsPagesWithContext(aws.Context, *ec2.DescribeSubnetsInput, func(*ec2.DescribeSubnetsOutput, bool) bool, ...request.Option) error + + DescribeTags(*ec2.DescribeTagsInput) (*ec2.DescribeTagsOutput, error) + DescribeTagsWithContext(aws.Context, *ec2.DescribeTagsInput, ...request.Option) (*ec2.DescribeTagsOutput, error) + DescribeTagsRequest(*ec2.DescribeTagsInput) (*request.Request, *ec2.DescribeTagsOutput) + + DescribeTagsPages(*ec2.DescribeTagsInput, func(*ec2.DescribeTagsOutput, bool) bool) error + DescribeTagsPagesWithContext(aws.Context, *ec2.DescribeTagsInput, func(*ec2.DescribeTagsOutput, bool) bool, ...request.Option) error + + DescribeTrafficMirrorFilters(*ec2.DescribeTrafficMirrorFiltersInput) (*ec2.DescribeTrafficMirrorFiltersOutput, error) + DescribeTrafficMirrorFiltersWithContext(aws.Context, *ec2.DescribeTrafficMirrorFiltersInput, ...request.Option) (*ec2.DescribeTrafficMirrorFiltersOutput, error) + DescribeTrafficMirrorFiltersRequest(*ec2.DescribeTrafficMirrorFiltersInput) (*request.Request, *ec2.DescribeTrafficMirrorFiltersOutput) + + DescribeTrafficMirrorFiltersPages(*ec2.DescribeTrafficMirrorFiltersInput, func(*ec2.DescribeTrafficMirrorFiltersOutput, bool) bool) error + DescribeTrafficMirrorFiltersPagesWithContext(aws.Context, *ec2.DescribeTrafficMirrorFiltersInput, func(*ec2.DescribeTrafficMirrorFiltersOutput, bool) bool, ...request.Option) error + + DescribeTrafficMirrorSessions(*ec2.DescribeTrafficMirrorSessionsInput) (*ec2.DescribeTrafficMirrorSessionsOutput, error) + DescribeTrafficMirrorSessionsWithContext(aws.Context, *ec2.DescribeTrafficMirrorSessionsInput, ...request.Option) (*ec2.DescribeTrafficMirrorSessionsOutput, error) + DescribeTrafficMirrorSessionsRequest(*ec2.DescribeTrafficMirrorSessionsInput) (*request.Request, *ec2.DescribeTrafficMirrorSessionsOutput) + + DescribeTrafficMirrorSessionsPages(*ec2.DescribeTrafficMirrorSessionsInput, func(*ec2.DescribeTrafficMirrorSessionsOutput, bool) bool) error + DescribeTrafficMirrorSessionsPagesWithContext(aws.Context, *ec2.DescribeTrafficMirrorSessionsInput, func(*ec2.DescribeTrafficMirrorSessionsOutput, bool) bool, ...request.Option) error + + DescribeTrafficMirrorTargets(*ec2.DescribeTrafficMirrorTargetsInput) (*ec2.DescribeTrafficMirrorTargetsOutput, error) + DescribeTrafficMirrorTargetsWithContext(aws.Context, *ec2.DescribeTrafficMirrorTargetsInput, ...request.Option) (*ec2.DescribeTrafficMirrorTargetsOutput, error) + DescribeTrafficMirrorTargetsRequest(*ec2.DescribeTrafficMirrorTargetsInput) (*request.Request, *ec2.DescribeTrafficMirrorTargetsOutput) + + DescribeTrafficMirrorTargetsPages(*ec2.DescribeTrafficMirrorTargetsInput, func(*ec2.DescribeTrafficMirrorTargetsOutput, bool) bool) error + DescribeTrafficMirrorTargetsPagesWithContext(aws.Context, *ec2.DescribeTrafficMirrorTargetsInput, func(*ec2.DescribeTrafficMirrorTargetsOutput, bool) bool, ...request.Option) error + + DescribeTransitGatewayAttachments(*ec2.DescribeTransitGatewayAttachmentsInput) (*ec2.DescribeTransitGatewayAttachmentsOutput, error) + DescribeTransitGatewayAttachmentsWithContext(aws.Context, *ec2.DescribeTransitGatewayAttachmentsInput, ...request.Option) (*ec2.DescribeTransitGatewayAttachmentsOutput, error) + DescribeTransitGatewayAttachmentsRequest(*ec2.DescribeTransitGatewayAttachmentsInput) (*request.Request, *ec2.DescribeTransitGatewayAttachmentsOutput) + + DescribeTransitGatewayAttachmentsPages(*ec2.DescribeTransitGatewayAttachmentsInput, func(*ec2.DescribeTransitGatewayAttachmentsOutput, bool) bool) error + DescribeTransitGatewayAttachmentsPagesWithContext(aws.Context, *ec2.DescribeTransitGatewayAttachmentsInput, func(*ec2.DescribeTransitGatewayAttachmentsOutput, bool) bool, ...request.Option) error + + DescribeTransitGatewayConnectPeers(*ec2.DescribeTransitGatewayConnectPeersInput) (*ec2.DescribeTransitGatewayConnectPeersOutput, error) + DescribeTransitGatewayConnectPeersWithContext(aws.Context, *ec2.DescribeTransitGatewayConnectPeersInput, ...request.Option) (*ec2.DescribeTransitGatewayConnectPeersOutput, error) + DescribeTransitGatewayConnectPeersRequest(*ec2.DescribeTransitGatewayConnectPeersInput) (*request.Request, *ec2.DescribeTransitGatewayConnectPeersOutput) + + DescribeTransitGatewayConnectPeersPages(*ec2.DescribeTransitGatewayConnectPeersInput, func(*ec2.DescribeTransitGatewayConnectPeersOutput, bool) bool) error + DescribeTransitGatewayConnectPeersPagesWithContext(aws.Context, *ec2.DescribeTransitGatewayConnectPeersInput, func(*ec2.DescribeTransitGatewayConnectPeersOutput, bool) bool, ...request.Option) error + + DescribeTransitGatewayConnects(*ec2.DescribeTransitGatewayConnectsInput) (*ec2.DescribeTransitGatewayConnectsOutput, error) + DescribeTransitGatewayConnectsWithContext(aws.Context, *ec2.DescribeTransitGatewayConnectsInput, ...request.Option) (*ec2.DescribeTransitGatewayConnectsOutput, error) + DescribeTransitGatewayConnectsRequest(*ec2.DescribeTransitGatewayConnectsInput) (*request.Request, *ec2.DescribeTransitGatewayConnectsOutput) + + DescribeTransitGatewayConnectsPages(*ec2.DescribeTransitGatewayConnectsInput, func(*ec2.DescribeTransitGatewayConnectsOutput, bool) bool) error + DescribeTransitGatewayConnectsPagesWithContext(aws.Context, *ec2.DescribeTransitGatewayConnectsInput, func(*ec2.DescribeTransitGatewayConnectsOutput, bool) bool, ...request.Option) error + + DescribeTransitGatewayMulticastDomains(*ec2.DescribeTransitGatewayMulticastDomainsInput) (*ec2.DescribeTransitGatewayMulticastDomainsOutput, error) + DescribeTransitGatewayMulticastDomainsWithContext(aws.Context, *ec2.DescribeTransitGatewayMulticastDomainsInput, ...request.Option) (*ec2.DescribeTransitGatewayMulticastDomainsOutput, error) + DescribeTransitGatewayMulticastDomainsRequest(*ec2.DescribeTransitGatewayMulticastDomainsInput) (*request.Request, *ec2.DescribeTransitGatewayMulticastDomainsOutput) + + DescribeTransitGatewayMulticastDomainsPages(*ec2.DescribeTransitGatewayMulticastDomainsInput, func(*ec2.DescribeTransitGatewayMulticastDomainsOutput, bool) bool) error + DescribeTransitGatewayMulticastDomainsPagesWithContext(aws.Context, *ec2.DescribeTransitGatewayMulticastDomainsInput, func(*ec2.DescribeTransitGatewayMulticastDomainsOutput, bool) bool, ...request.Option) error + + DescribeTransitGatewayPeeringAttachments(*ec2.DescribeTransitGatewayPeeringAttachmentsInput) (*ec2.DescribeTransitGatewayPeeringAttachmentsOutput, error) + DescribeTransitGatewayPeeringAttachmentsWithContext(aws.Context, *ec2.DescribeTransitGatewayPeeringAttachmentsInput, ...request.Option) (*ec2.DescribeTransitGatewayPeeringAttachmentsOutput, error) + DescribeTransitGatewayPeeringAttachmentsRequest(*ec2.DescribeTransitGatewayPeeringAttachmentsInput) (*request.Request, *ec2.DescribeTransitGatewayPeeringAttachmentsOutput) + + DescribeTransitGatewayPeeringAttachmentsPages(*ec2.DescribeTransitGatewayPeeringAttachmentsInput, func(*ec2.DescribeTransitGatewayPeeringAttachmentsOutput, bool) bool) error + DescribeTransitGatewayPeeringAttachmentsPagesWithContext(aws.Context, *ec2.DescribeTransitGatewayPeeringAttachmentsInput, func(*ec2.DescribeTransitGatewayPeeringAttachmentsOutput, bool) bool, ...request.Option) error + + DescribeTransitGatewayPolicyTables(*ec2.DescribeTransitGatewayPolicyTablesInput) (*ec2.DescribeTransitGatewayPolicyTablesOutput, error) + DescribeTransitGatewayPolicyTablesWithContext(aws.Context, *ec2.DescribeTransitGatewayPolicyTablesInput, ...request.Option) (*ec2.DescribeTransitGatewayPolicyTablesOutput, error) + DescribeTransitGatewayPolicyTablesRequest(*ec2.DescribeTransitGatewayPolicyTablesInput) (*request.Request, *ec2.DescribeTransitGatewayPolicyTablesOutput) + + DescribeTransitGatewayPolicyTablesPages(*ec2.DescribeTransitGatewayPolicyTablesInput, func(*ec2.DescribeTransitGatewayPolicyTablesOutput, bool) bool) error + DescribeTransitGatewayPolicyTablesPagesWithContext(aws.Context, *ec2.DescribeTransitGatewayPolicyTablesInput, func(*ec2.DescribeTransitGatewayPolicyTablesOutput, bool) bool, ...request.Option) error + + DescribeTransitGatewayRouteTableAnnouncements(*ec2.DescribeTransitGatewayRouteTableAnnouncementsInput) (*ec2.DescribeTransitGatewayRouteTableAnnouncementsOutput, error) + DescribeTransitGatewayRouteTableAnnouncementsWithContext(aws.Context, *ec2.DescribeTransitGatewayRouteTableAnnouncementsInput, ...request.Option) (*ec2.DescribeTransitGatewayRouteTableAnnouncementsOutput, error) + DescribeTransitGatewayRouteTableAnnouncementsRequest(*ec2.DescribeTransitGatewayRouteTableAnnouncementsInput) (*request.Request, *ec2.DescribeTransitGatewayRouteTableAnnouncementsOutput) + + DescribeTransitGatewayRouteTableAnnouncementsPages(*ec2.DescribeTransitGatewayRouteTableAnnouncementsInput, func(*ec2.DescribeTransitGatewayRouteTableAnnouncementsOutput, bool) bool) error + DescribeTransitGatewayRouteTableAnnouncementsPagesWithContext(aws.Context, *ec2.DescribeTransitGatewayRouteTableAnnouncementsInput, func(*ec2.DescribeTransitGatewayRouteTableAnnouncementsOutput, bool) bool, ...request.Option) error + + DescribeTransitGatewayRouteTables(*ec2.DescribeTransitGatewayRouteTablesInput) (*ec2.DescribeTransitGatewayRouteTablesOutput, error) + DescribeTransitGatewayRouteTablesWithContext(aws.Context, *ec2.DescribeTransitGatewayRouteTablesInput, ...request.Option) (*ec2.DescribeTransitGatewayRouteTablesOutput, error) + DescribeTransitGatewayRouteTablesRequest(*ec2.DescribeTransitGatewayRouteTablesInput) (*request.Request, *ec2.DescribeTransitGatewayRouteTablesOutput) + + DescribeTransitGatewayRouteTablesPages(*ec2.DescribeTransitGatewayRouteTablesInput, func(*ec2.DescribeTransitGatewayRouteTablesOutput, bool) bool) error + DescribeTransitGatewayRouteTablesPagesWithContext(aws.Context, *ec2.DescribeTransitGatewayRouteTablesInput, func(*ec2.DescribeTransitGatewayRouteTablesOutput, bool) bool, ...request.Option) error + + DescribeTransitGatewayVpcAttachments(*ec2.DescribeTransitGatewayVpcAttachmentsInput) (*ec2.DescribeTransitGatewayVpcAttachmentsOutput, error) + DescribeTransitGatewayVpcAttachmentsWithContext(aws.Context, *ec2.DescribeTransitGatewayVpcAttachmentsInput, ...request.Option) (*ec2.DescribeTransitGatewayVpcAttachmentsOutput, error) + DescribeTransitGatewayVpcAttachmentsRequest(*ec2.DescribeTransitGatewayVpcAttachmentsInput) (*request.Request, *ec2.DescribeTransitGatewayVpcAttachmentsOutput) + + DescribeTransitGatewayVpcAttachmentsPages(*ec2.DescribeTransitGatewayVpcAttachmentsInput, func(*ec2.DescribeTransitGatewayVpcAttachmentsOutput, bool) bool) error + DescribeTransitGatewayVpcAttachmentsPagesWithContext(aws.Context, *ec2.DescribeTransitGatewayVpcAttachmentsInput, func(*ec2.DescribeTransitGatewayVpcAttachmentsOutput, bool) bool, ...request.Option) error + + DescribeTransitGateways(*ec2.DescribeTransitGatewaysInput) (*ec2.DescribeTransitGatewaysOutput, error) + DescribeTransitGatewaysWithContext(aws.Context, *ec2.DescribeTransitGatewaysInput, ...request.Option) (*ec2.DescribeTransitGatewaysOutput, error) + DescribeTransitGatewaysRequest(*ec2.DescribeTransitGatewaysInput) (*request.Request, *ec2.DescribeTransitGatewaysOutput) + + DescribeTransitGatewaysPages(*ec2.DescribeTransitGatewaysInput, func(*ec2.DescribeTransitGatewaysOutput, bool) bool) error + DescribeTransitGatewaysPagesWithContext(aws.Context, *ec2.DescribeTransitGatewaysInput, func(*ec2.DescribeTransitGatewaysOutput, bool) bool, ...request.Option) error + + DescribeTrunkInterfaceAssociations(*ec2.DescribeTrunkInterfaceAssociationsInput) (*ec2.DescribeTrunkInterfaceAssociationsOutput, error) + DescribeTrunkInterfaceAssociationsWithContext(aws.Context, *ec2.DescribeTrunkInterfaceAssociationsInput, ...request.Option) (*ec2.DescribeTrunkInterfaceAssociationsOutput, error) + DescribeTrunkInterfaceAssociationsRequest(*ec2.DescribeTrunkInterfaceAssociationsInput) (*request.Request, *ec2.DescribeTrunkInterfaceAssociationsOutput) + + DescribeTrunkInterfaceAssociationsPages(*ec2.DescribeTrunkInterfaceAssociationsInput, func(*ec2.DescribeTrunkInterfaceAssociationsOutput, bool) bool) error + DescribeTrunkInterfaceAssociationsPagesWithContext(aws.Context, *ec2.DescribeTrunkInterfaceAssociationsInput, func(*ec2.DescribeTrunkInterfaceAssociationsOutput, bool) bool, ...request.Option) error + + DescribeVerifiedAccessEndpoints(*ec2.DescribeVerifiedAccessEndpointsInput) (*ec2.DescribeVerifiedAccessEndpointsOutput, error) + DescribeVerifiedAccessEndpointsWithContext(aws.Context, *ec2.DescribeVerifiedAccessEndpointsInput, ...request.Option) (*ec2.DescribeVerifiedAccessEndpointsOutput, error) + DescribeVerifiedAccessEndpointsRequest(*ec2.DescribeVerifiedAccessEndpointsInput) (*request.Request, *ec2.DescribeVerifiedAccessEndpointsOutput) + + DescribeVerifiedAccessEndpointsPages(*ec2.DescribeVerifiedAccessEndpointsInput, func(*ec2.DescribeVerifiedAccessEndpointsOutput, bool) bool) error + DescribeVerifiedAccessEndpointsPagesWithContext(aws.Context, *ec2.DescribeVerifiedAccessEndpointsInput, func(*ec2.DescribeVerifiedAccessEndpointsOutput, bool) bool, ...request.Option) error + + DescribeVerifiedAccessGroups(*ec2.DescribeVerifiedAccessGroupsInput) (*ec2.DescribeVerifiedAccessGroupsOutput, error) + DescribeVerifiedAccessGroupsWithContext(aws.Context, *ec2.DescribeVerifiedAccessGroupsInput, ...request.Option) (*ec2.DescribeVerifiedAccessGroupsOutput, error) + DescribeVerifiedAccessGroupsRequest(*ec2.DescribeVerifiedAccessGroupsInput) (*request.Request, *ec2.DescribeVerifiedAccessGroupsOutput) + + DescribeVerifiedAccessGroupsPages(*ec2.DescribeVerifiedAccessGroupsInput, func(*ec2.DescribeVerifiedAccessGroupsOutput, bool) bool) error + DescribeVerifiedAccessGroupsPagesWithContext(aws.Context, *ec2.DescribeVerifiedAccessGroupsInput, func(*ec2.DescribeVerifiedAccessGroupsOutput, bool) bool, ...request.Option) error + + DescribeVerifiedAccessInstanceLoggingConfigurations(*ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsInput) (*ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsOutput, error) + DescribeVerifiedAccessInstanceLoggingConfigurationsWithContext(aws.Context, *ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsInput, ...request.Option) (*ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsOutput, error) + DescribeVerifiedAccessInstanceLoggingConfigurationsRequest(*ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsInput) (*request.Request, *ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsOutput) + + DescribeVerifiedAccessInstanceLoggingConfigurationsPages(*ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsInput, func(*ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsOutput, bool) bool) error + DescribeVerifiedAccessInstanceLoggingConfigurationsPagesWithContext(aws.Context, *ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsInput, func(*ec2.DescribeVerifiedAccessInstanceLoggingConfigurationsOutput, bool) bool, ...request.Option) error + + DescribeVerifiedAccessInstances(*ec2.DescribeVerifiedAccessInstancesInput) (*ec2.DescribeVerifiedAccessInstancesOutput, error) + DescribeVerifiedAccessInstancesWithContext(aws.Context, *ec2.DescribeVerifiedAccessInstancesInput, ...request.Option) (*ec2.DescribeVerifiedAccessInstancesOutput, error) + DescribeVerifiedAccessInstancesRequest(*ec2.DescribeVerifiedAccessInstancesInput) (*request.Request, *ec2.DescribeVerifiedAccessInstancesOutput) + + DescribeVerifiedAccessInstancesPages(*ec2.DescribeVerifiedAccessInstancesInput, func(*ec2.DescribeVerifiedAccessInstancesOutput, bool) bool) error + DescribeVerifiedAccessInstancesPagesWithContext(aws.Context, *ec2.DescribeVerifiedAccessInstancesInput, func(*ec2.DescribeVerifiedAccessInstancesOutput, bool) bool, ...request.Option) error + + DescribeVerifiedAccessTrustProviders(*ec2.DescribeVerifiedAccessTrustProvidersInput) (*ec2.DescribeVerifiedAccessTrustProvidersOutput, error) + DescribeVerifiedAccessTrustProvidersWithContext(aws.Context, *ec2.DescribeVerifiedAccessTrustProvidersInput, ...request.Option) (*ec2.DescribeVerifiedAccessTrustProvidersOutput, error) + DescribeVerifiedAccessTrustProvidersRequest(*ec2.DescribeVerifiedAccessTrustProvidersInput) (*request.Request, *ec2.DescribeVerifiedAccessTrustProvidersOutput) + + DescribeVerifiedAccessTrustProvidersPages(*ec2.DescribeVerifiedAccessTrustProvidersInput, func(*ec2.DescribeVerifiedAccessTrustProvidersOutput, bool) bool) error + DescribeVerifiedAccessTrustProvidersPagesWithContext(aws.Context, *ec2.DescribeVerifiedAccessTrustProvidersInput, func(*ec2.DescribeVerifiedAccessTrustProvidersOutput, bool) bool, ...request.Option) error + + DescribeVolumeAttribute(*ec2.DescribeVolumeAttributeInput) (*ec2.DescribeVolumeAttributeOutput, error) + DescribeVolumeAttributeWithContext(aws.Context, *ec2.DescribeVolumeAttributeInput, ...request.Option) (*ec2.DescribeVolumeAttributeOutput, error) + DescribeVolumeAttributeRequest(*ec2.DescribeVolumeAttributeInput) (*request.Request, *ec2.DescribeVolumeAttributeOutput) + + DescribeVolumeStatus(*ec2.DescribeVolumeStatusInput) (*ec2.DescribeVolumeStatusOutput, error) + DescribeVolumeStatusWithContext(aws.Context, *ec2.DescribeVolumeStatusInput, ...request.Option) (*ec2.DescribeVolumeStatusOutput, error) + DescribeVolumeStatusRequest(*ec2.DescribeVolumeStatusInput) (*request.Request, *ec2.DescribeVolumeStatusOutput) + + DescribeVolumeStatusPages(*ec2.DescribeVolumeStatusInput, func(*ec2.DescribeVolumeStatusOutput, bool) bool) error + DescribeVolumeStatusPagesWithContext(aws.Context, *ec2.DescribeVolumeStatusInput, func(*ec2.DescribeVolumeStatusOutput, bool) bool, ...request.Option) error + + DescribeVolumes(*ec2.DescribeVolumesInput) (*ec2.DescribeVolumesOutput, error) + DescribeVolumesWithContext(aws.Context, *ec2.DescribeVolumesInput, ...request.Option) (*ec2.DescribeVolumesOutput, error) + DescribeVolumesRequest(*ec2.DescribeVolumesInput) (*request.Request, *ec2.DescribeVolumesOutput) + + DescribeVolumesPages(*ec2.DescribeVolumesInput, func(*ec2.DescribeVolumesOutput, bool) bool) error + DescribeVolumesPagesWithContext(aws.Context, *ec2.DescribeVolumesInput, func(*ec2.DescribeVolumesOutput, bool) bool, ...request.Option) error + + DescribeVolumesModifications(*ec2.DescribeVolumesModificationsInput) (*ec2.DescribeVolumesModificationsOutput, error) + DescribeVolumesModificationsWithContext(aws.Context, *ec2.DescribeVolumesModificationsInput, ...request.Option) (*ec2.DescribeVolumesModificationsOutput, error) + DescribeVolumesModificationsRequest(*ec2.DescribeVolumesModificationsInput) (*request.Request, *ec2.DescribeVolumesModificationsOutput) + + DescribeVolumesModificationsPages(*ec2.DescribeVolumesModificationsInput, func(*ec2.DescribeVolumesModificationsOutput, bool) bool) error + DescribeVolumesModificationsPagesWithContext(aws.Context, *ec2.DescribeVolumesModificationsInput, func(*ec2.DescribeVolumesModificationsOutput, bool) bool, ...request.Option) error + + DescribeVpcAttribute(*ec2.DescribeVpcAttributeInput) (*ec2.DescribeVpcAttributeOutput, error) + DescribeVpcAttributeWithContext(aws.Context, *ec2.DescribeVpcAttributeInput, ...request.Option) (*ec2.DescribeVpcAttributeOutput, error) + DescribeVpcAttributeRequest(*ec2.DescribeVpcAttributeInput) (*request.Request, *ec2.DescribeVpcAttributeOutput) + + DescribeVpcClassicLink(*ec2.DescribeVpcClassicLinkInput) (*ec2.DescribeVpcClassicLinkOutput, error) + DescribeVpcClassicLinkWithContext(aws.Context, *ec2.DescribeVpcClassicLinkInput, ...request.Option) (*ec2.DescribeVpcClassicLinkOutput, error) + DescribeVpcClassicLinkRequest(*ec2.DescribeVpcClassicLinkInput) (*request.Request, *ec2.DescribeVpcClassicLinkOutput) + + DescribeVpcClassicLinkDnsSupport(*ec2.DescribeVpcClassicLinkDnsSupportInput) (*ec2.DescribeVpcClassicLinkDnsSupportOutput, error) + DescribeVpcClassicLinkDnsSupportWithContext(aws.Context, *ec2.DescribeVpcClassicLinkDnsSupportInput, ...request.Option) (*ec2.DescribeVpcClassicLinkDnsSupportOutput, error) + DescribeVpcClassicLinkDnsSupportRequest(*ec2.DescribeVpcClassicLinkDnsSupportInput) (*request.Request, *ec2.DescribeVpcClassicLinkDnsSupportOutput) + + DescribeVpcClassicLinkDnsSupportPages(*ec2.DescribeVpcClassicLinkDnsSupportInput, func(*ec2.DescribeVpcClassicLinkDnsSupportOutput, bool) bool) error + DescribeVpcClassicLinkDnsSupportPagesWithContext(aws.Context, *ec2.DescribeVpcClassicLinkDnsSupportInput, func(*ec2.DescribeVpcClassicLinkDnsSupportOutput, bool) bool, ...request.Option) error + + DescribeVpcEndpointConnectionNotifications(*ec2.DescribeVpcEndpointConnectionNotificationsInput) (*ec2.DescribeVpcEndpointConnectionNotificationsOutput, error) + DescribeVpcEndpointConnectionNotificationsWithContext(aws.Context, *ec2.DescribeVpcEndpointConnectionNotificationsInput, ...request.Option) (*ec2.DescribeVpcEndpointConnectionNotificationsOutput, error) + DescribeVpcEndpointConnectionNotificationsRequest(*ec2.DescribeVpcEndpointConnectionNotificationsInput) (*request.Request, *ec2.DescribeVpcEndpointConnectionNotificationsOutput) + + DescribeVpcEndpointConnectionNotificationsPages(*ec2.DescribeVpcEndpointConnectionNotificationsInput, func(*ec2.DescribeVpcEndpointConnectionNotificationsOutput, bool) bool) error + DescribeVpcEndpointConnectionNotificationsPagesWithContext(aws.Context, *ec2.DescribeVpcEndpointConnectionNotificationsInput, func(*ec2.DescribeVpcEndpointConnectionNotificationsOutput, bool) bool, ...request.Option) error + + DescribeVpcEndpointConnections(*ec2.DescribeVpcEndpointConnectionsInput) (*ec2.DescribeVpcEndpointConnectionsOutput, error) + DescribeVpcEndpointConnectionsWithContext(aws.Context, *ec2.DescribeVpcEndpointConnectionsInput, ...request.Option) (*ec2.DescribeVpcEndpointConnectionsOutput, error) + DescribeVpcEndpointConnectionsRequest(*ec2.DescribeVpcEndpointConnectionsInput) (*request.Request, *ec2.DescribeVpcEndpointConnectionsOutput) + + DescribeVpcEndpointConnectionsPages(*ec2.DescribeVpcEndpointConnectionsInput, func(*ec2.DescribeVpcEndpointConnectionsOutput, bool) bool) error + DescribeVpcEndpointConnectionsPagesWithContext(aws.Context, *ec2.DescribeVpcEndpointConnectionsInput, func(*ec2.DescribeVpcEndpointConnectionsOutput, bool) bool, ...request.Option) error + + DescribeVpcEndpointServiceConfigurations(*ec2.DescribeVpcEndpointServiceConfigurationsInput) (*ec2.DescribeVpcEndpointServiceConfigurationsOutput, error) + DescribeVpcEndpointServiceConfigurationsWithContext(aws.Context, *ec2.DescribeVpcEndpointServiceConfigurationsInput, ...request.Option) (*ec2.DescribeVpcEndpointServiceConfigurationsOutput, error) + DescribeVpcEndpointServiceConfigurationsRequest(*ec2.DescribeVpcEndpointServiceConfigurationsInput) (*request.Request, *ec2.DescribeVpcEndpointServiceConfigurationsOutput) + + DescribeVpcEndpointServiceConfigurationsPages(*ec2.DescribeVpcEndpointServiceConfigurationsInput, func(*ec2.DescribeVpcEndpointServiceConfigurationsOutput, bool) bool) error + DescribeVpcEndpointServiceConfigurationsPagesWithContext(aws.Context, *ec2.DescribeVpcEndpointServiceConfigurationsInput, func(*ec2.DescribeVpcEndpointServiceConfigurationsOutput, bool) bool, ...request.Option) error + + DescribeVpcEndpointServicePermissions(*ec2.DescribeVpcEndpointServicePermissionsInput) (*ec2.DescribeVpcEndpointServicePermissionsOutput, error) + DescribeVpcEndpointServicePermissionsWithContext(aws.Context, *ec2.DescribeVpcEndpointServicePermissionsInput, ...request.Option) (*ec2.DescribeVpcEndpointServicePermissionsOutput, error) + DescribeVpcEndpointServicePermissionsRequest(*ec2.DescribeVpcEndpointServicePermissionsInput) (*request.Request, *ec2.DescribeVpcEndpointServicePermissionsOutput) + + DescribeVpcEndpointServicePermissionsPages(*ec2.DescribeVpcEndpointServicePermissionsInput, func(*ec2.DescribeVpcEndpointServicePermissionsOutput, bool) bool) error + DescribeVpcEndpointServicePermissionsPagesWithContext(aws.Context, *ec2.DescribeVpcEndpointServicePermissionsInput, func(*ec2.DescribeVpcEndpointServicePermissionsOutput, bool) bool, ...request.Option) error + + DescribeVpcEndpointServices(*ec2.DescribeVpcEndpointServicesInput) (*ec2.DescribeVpcEndpointServicesOutput, error) + DescribeVpcEndpointServicesWithContext(aws.Context, *ec2.DescribeVpcEndpointServicesInput, ...request.Option) (*ec2.DescribeVpcEndpointServicesOutput, error) + DescribeVpcEndpointServicesRequest(*ec2.DescribeVpcEndpointServicesInput) (*request.Request, *ec2.DescribeVpcEndpointServicesOutput) + + DescribeVpcEndpoints(*ec2.DescribeVpcEndpointsInput) (*ec2.DescribeVpcEndpointsOutput, error) + DescribeVpcEndpointsWithContext(aws.Context, *ec2.DescribeVpcEndpointsInput, ...request.Option) (*ec2.DescribeVpcEndpointsOutput, error) + DescribeVpcEndpointsRequest(*ec2.DescribeVpcEndpointsInput) (*request.Request, *ec2.DescribeVpcEndpointsOutput) + + DescribeVpcEndpointsPages(*ec2.DescribeVpcEndpointsInput, func(*ec2.DescribeVpcEndpointsOutput, bool) bool) error + DescribeVpcEndpointsPagesWithContext(aws.Context, *ec2.DescribeVpcEndpointsInput, func(*ec2.DescribeVpcEndpointsOutput, bool) bool, ...request.Option) error + + DescribeVpcPeeringConnections(*ec2.DescribeVpcPeeringConnectionsInput) (*ec2.DescribeVpcPeeringConnectionsOutput, error) + DescribeVpcPeeringConnectionsWithContext(aws.Context, *ec2.DescribeVpcPeeringConnectionsInput, ...request.Option) (*ec2.DescribeVpcPeeringConnectionsOutput, error) + DescribeVpcPeeringConnectionsRequest(*ec2.DescribeVpcPeeringConnectionsInput) (*request.Request, *ec2.DescribeVpcPeeringConnectionsOutput) + + DescribeVpcPeeringConnectionsPages(*ec2.DescribeVpcPeeringConnectionsInput, func(*ec2.DescribeVpcPeeringConnectionsOutput, bool) bool) error + DescribeVpcPeeringConnectionsPagesWithContext(aws.Context, *ec2.DescribeVpcPeeringConnectionsInput, func(*ec2.DescribeVpcPeeringConnectionsOutput, bool) bool, ...request.Option) error + + DescribeVpcs(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) + DescribeVpcsWithContext(aws.Context, *ec2.DescribeVpcsInput, ...request.Option) (*ec2.DescribeVpcsOutput, error) + DescribeVpcsRequest(*ec2.DescribeVpcsInput) (*request.Request, *ec2.DescribeVpcsOutput) + + DescribeVpcsPages(*ec2.DescribeVpcsInput, func(*ec2.DescribeVpcsOutput, bool) bool) error + DescribeVpcsPagesWithContext(aws.Context, *ec2.DescribeVpcsInput, func(*ec2.DescribeVpcsOutput, bool) bool, ...request.Option) error + + DescribeVpnConnections(*ec2.DescribeVpnConnectionsInput) (*ec2.DescribeVpnConnectionsOutput, error) + DescribeVpnConnectionsWithContext(aws.Context, *ec2.DescribeVpnConnectionsInput, ...request.Option) (*ec2.DescribeVpnConnectionsOutput, error) + DescribeVpnConnectionsRequest(*ec2.DescribeVpnConnectionsInput) (*request.Request, *ec2.DescribeVpnConnectionsOutput) + + DescribeVpnGateways(*ec2.DescribeVpnGatewaysInput) (*ec2.DescribeVpnGatewaysOutput, error) + DescribeVpnGatewaysWithContext(aws.Context, *ec2.DescribeVpnGatewaysInput, ...request.Option) (*ec2.DescribeVpnGatewaysOutput, error) + DescribeVpnGatewaysRequest(*ec2.DescribeVpnGatewaysInput) (*request.Request, *ec2.DescribeVpnGatewaysOutput) + + DetachClassicLinkVpc(*ec2.DetachClassicLinkVpcInput) (*ec2.DetachClassicLinkVpcOutput, error) + DetachClassicLinkVpcWithContext(aws.Context, *ec2.DetachClassicLinkVpcInput, ...request.Option) (*ec2.DetachClassicLinkVpcOutput, error) + DetachClassicLinkVpcRequest(*ec2.DetachClassicLinkVpcInput) (*request.Request, *ec2.DetachClassicLinkVpcOutput) + + DetachInternetGateway(*ec2.DetachInternetGatewayInput) (*ec2.DetachInternetGatewayOutput, error) + DetachInternetGatewayWithContext(aws.Context, *ec2.DetachInternetGatewayInput, ...request.Option) (*ec2.DetachInternetGatewayOutput, error) + DetachInternetGatewayRequest(*ec2.DetachInternetGatewayInput) (*request.Request, *ec2.DetachInternetGatewayOutput) + + DetachNetworkInterface(*ec2.DetachNetworkInterfaceInput) (*ec2.DetachNetworkInterfaceOutput, error) + DetachNetworkInterfaceWithContext(aws.Context, *ec2.DetachNetworkInterfaceInput, ...request.Option) (*ec2.DetachNetworkInterfaceOutput, error) + DetachNetworkInterfaceRequest(*ec2.DetachNetworkInterfaceInput) (*request.Request, *ec2.DetachNetworkInterfaceOutput) + + DetachVerifiedAccessTrustProvider(*ec2.DetachVerifiedAccessTrustProviderInput) (*ec2.DetachVerifiedAccessTrustProviderOutput, error) + DetachVerifiedAccessTrustProviderWithContext(aws.Context, *ec2.DetachVerifiedAccessTrustProviderInput, ...request.Option) (*ec2.DetachVerifiedAccessTrustProviderOutput, error) + DetachVerifiedAccessTrustProviderRequest(*ec2.DetachVerifiedAccessTrustProviderInput) (*request.Request, *ec2.DetachVerifiedAccessTrustProviderOutput) + + DetachVolume(*ec2.DetachVolumeInput) (*ec2.VolumeAttachment, error) + DetachVolumeWithContext(aws.Context, *ec2.DetachVolumeInput, ...request.Option) (*ec2.VolumeAttachment, error) + DetachVolumeRequest(*ec2.DetachVolumeInput) (*request.Request, *ec2.VolumeAttachment) + + DetachVpnGateway(*ec2.DetachVpnGatewayInput) (*ec2.DetachVpnGatewayOutput, error) + DetachVpnGatewayWithContext(aws.Context, *ec2.DetachVpnGatewayInput, ...request.Option) (*ec2.DetachVpnGatewayOutput, error) + DetachVpnGatewayRequest(*ec2.DetachVpnGatewayInput) (*request.Request, *ec2.DetachVpnGatewayOutput) + + DisableAddressTransfer(*ec2.DisableAddressTransferInput) (*ec2.DisableAddressTransferOutput, error) + DisableAddressTransferWithContext(aws.Context, *ec2.DisableAddressTransferInput, ...request.Option) (*ec2.DisableAddressTransferOutput, error) + DisableAddressTransferRequest(*ec2.DisableAddressTransferInput) (*request.Request, *ec2.DisableAddressTransferOutput) + + DisableAwsNetworkPerformanceMetricSubscription(*ec2.DisableAwsNetworkPerformanceMetricSubscriptionInput) (*ec2.DisableAwsNetworkPerformanceMetricSubscriptionOutput, error) + DisableAwsNetworkPerformanceMetricSubscriptionWithContext(aws.Context, *ec2.DisableAwsNetworkPerformanceMetricSubscriptionInput, ...request.Option) (*ec2.DisableAwsNetworkPerformanceMetricSubscriptionOutput, error) + DisableAwsNetworkPerformanceMetricSubscriptionRequest(*ec2.DisableAwsNetworkPerformanceMetricSubscriptionInput) (*request.Request, *ec2.DisableAwsNetworkPerformanceMetricSubscriptionOutput) + + DisableEbsEncryptionByDefault(*ec2.DisableEbsEncryptionByDefaultInput) (*ec2.DisableEbsEncryptionByDefaultOutput, error) + DisableEbsEncryptionByDefaultWithContext(aws.Context, *ec2.DisableEbsEncryptionByDefaultInput, ...request.Option) (*ec2.DisableEbsEncryptionByDefaultOutput, error) + DisableEbsEncryptionByDefaultRequest(*ec2.DisableEbsEncryptionByDefaultInput) (*request.Request, *ec2.DisableEbsEncryptionByDefaultOutput) + + DisableFastLaunch(*ec2.DisableFastLaunchInput) (*ec2.DisableFastLaunchOutput, error) + DisableFastLaunchWithContext(aws.Context, *ec2.DisableFastLaunchInput, ...request.Option) (*ec2.DisableFastLaunchOutput, error) + DisableFastLaunchRequest(*ec2.DisableFastLaunchInput) (*request.Request, *ec2.DisableFastLaunchOutput) + + DisableFastSnapshotRestores(*ec2.DisableFastSnapshotRestoresInput) (*ec2.DisableFastSnapshotRestoresOutput, error) + DisableFastSnapshotRestoresWithContext(aws.Context, *ec2.DisableFastSnapshotRestoresInput, ...request.Option) (*ec2.DisableFastSnapshotRestoresOutput, error) + DisableFastSnapshotRestoresRequest(*ec2.DisableFastSnapshotRestoresInput) (*request.Request, *ec2.DisableFastSnapshotRestoresOutput) + + DisableImageDeprecation(*ec2.DisableImageDeprecationInput) (*ec2.DisableImageDeprecationOutput, error) + DisableImageDeprecationWithContext(aws.Context, *ec2.DisableImageDeprecationInput, ...request.Option) (*ec2.DisableImageDeprecationOutput, error) + DisableImageDeprecationRequest(*ec2.DisableImageDeprecationInput) (*request.Request, *ec2.DisableImageDeprecationOutput) + + DisableIpamOrganizationAdminAccount(*ec2.DisableIpamOrganizationAdminAccountInput) (*ec2.DisableIpamOrganizationAdminAccountOutput, error) + DisableIpamOrganizationAdminAccountWithContext(aws.Context, *ec2.DisableIpamOrganizationAdminAccountInput, ...request.Option) (*ec2.DisableIpamOrganizationAdminAccountOutput, error) + DisableIpamOrganizationAdminAccountRequest(*ec2.DisableIpamOrganizationAdminAccountInput) (*request.Request, *ec2.DisableIpamOrganizationAdminAccountOutput) + + DisableSerialConsoleAccess(*ec2.DisableSerialConsoleAccessInput) (*ec2.DisableSerialConsoleAccessOutput, error) + DisableSerialConsoleAccessWithContext(aws.Context, *ec2.DisableSerialConsoleAccessInput, ...request.Option) (*ec2.DisableSerialConsoleAccessOutput, error) + DisableSerialConsoleAccessRequest(*ec2.DisableSerialConsoleAccessInput) (*request.Request, *ec2.DisableSerialConsoleAccessOutput) + + DisableTransitGatewayRouteTablePropagation(*ec2.DisableTransitGatewayRouteTablePropagationInput) (*ec2.DisableTransitGatewayRouteTablePropagationOutput, error) + DisableTransitGatewayRouteTablePropagationWithContext(aws.Context, *ec2.DisableTransitGatewayRouteTablePropagationInput, ...request.Option) (*ec2.DisableTransitGatewayRouteTablePropagationOutput, error) + DisableTransitGatewayRouteTablePropagationRequest(*ec2.DisableTransitGatewayRouteTablePropagationInput) (*request.Request, *ec2.DisableTransitGatewayRouteTablePropagationOutput) + + DisableVgwRoutePropagation(*ec2.DisableVgwRoutePropagationInput) (*ec2.DisableVgwRoutePropagationOutput, error) + DisableVgwRoutePropagationWithContext(aws.Context, *ec2.DisableVgwRoutePropagationInput, ...request.Option) (*ec2.DisableVgwRoutePropagationOutput, error) + DisableVgwRoutePropagationRequest(*ec2.DisableVgwRoutePropagationInput) (*request.Request, *ec2.DisableVgwRoutePropagationOutput) + + DisableVpcClassicLink(*ec2.DisableVpcClassicLinkInput) (*ec2.DisableVpcClassicLinkOutput, error) + DisableVpcClassicLinkWithContext(aws.Context, *ec2.DisableVpcClassicLinkInput, ...request.Option) (*ec2.DisableVpcClassicLinkOutput, error) + DisableVpcClassicLinkRequest(*ec2.DisableVpcClassicLinkInput) (*request.Request, *ec2.DisableVpcClassicLinkOutput) + + DisableVpcClassicLinkDnsSupport(*ec2.DisableVpcClassicLinkDnsSupportInput) (*ec2.DisableVpcClassicLinkDnsSupportOutput, error) + DisableVpcClassicLinkDnsSupportWithContext(aws.Context, *ec2.DisableVpcClassicLinkDnsSupportInput, ...request.Option) (*ec2.DisableVpcClassicLinkDnsSupportOutput, error) + DisableVpcClassicLinkDnsSupportRequest(*ec2.DisableVpcClassicLinkDnsSupportInput) (*request.Request, *ec2.DisableVpcClassicLinkDnsSupportOutput) + + DisassociateAddress(*ec2.DisassociateAddressInput) (*ec2.DisassociateAddressOutput, error) + DisassociateAddressWithContext(aws.Context, *ec2.DisassociateAddressInput, ...request.Option) (*ec2.DisassociateAddressOutput, error) + DisassociateAddressRequest(*ec2.DisassociateAddressInput) (*request.Request, *ec2.DisassociateAddressOutput) + + DisassociateClientVpnTargetNetwork(*ec2.DisassociateClientVpnTargetNetworkInput) (*ec2.DisassociateClientVpnTargetNetworkOutput, error) + DisassociateClientVpnTargetNetworkWithContext(aws.Context, *ec2.DisassociateClientVpnTargetNetworkInput, ...request.Option) (*ec2.DisassociateClientVpnTargetNetworkOutput, error) + DisassociateClientVpnTargetNetworkRequest(*ec2.DisassociateClientVpnTargetNetworkInput) (*request.Request, *ec2.DisassociateClientVpnTargetNetworkOutput) + + DisassociateEnclaveCertificateIamRole(*ec2.DisassociateEnclaveCertificateIamRoleInput) (*ec2.DisassociateEnclaveCertificateIamRoleOutput, error) + DisassociateEnclaveCertificateIamRoleWithContext(aws.Context, *ec2.DisassociateEnclaveCertificateIamRoleInput, ...request.Option) (*ec2.DisassociateEnclaveCertificateIamRoleOutput, error) + DisassociateEnclaveCertificateIamRoleRequest(*ec2.DisassociateEnclaveCertificateIamRoleInput) (*request.Request, *ec2.DisassociateEnclaveCertificateIamRoleOutput) + + DisassociateIamInstanceProfile(*ec2.DisassociateIamInstanceProfileInput) (*ec2.DisassociateIamInstanceProfileOutput, error) + DisassociateIamInstanceProfileWithContext(aws.Context, *ec2.DisassociateIamInstanceProfileInput, ...request.Option) (*ec2.DisassociateIamInstanceProfileOutput, error) + DisassociateIamInstanceProfileRequest(*ec2.DisassociateIamInstanceProfileInput) (*request.Request, *ec2.DisassociateIamInstanceProfileOutput) + + DisassociateInstanceEventWindow(*ec2.DisassociateInstanceEventWindowInput) (*ec2.DisassociateInstanceEventWindowOutput, error) + DisassociateInstanceEventWindowWithContext(aws.Context, *ec2.DisassociateInstanceEventWindowInput, ...request.Option) (*ec2.DisassociateInstanceEventWindowOutput, error) + DisassociateInstanceEventWindowRequest(*ec2.DisassociateInstanceEventWindowInput) (*request.Request, *ec2.DisassociateInstanceEventWindowOutput) + + DisassociateIpamResourceDiscovery(*ec2.DisassociateIpamResourceDiscoveryInput) (*ec2.DisassociateIpamResourceDiscoveryOutput, error) + DisassociateIpamResourceDiscoveryWithContext(aws.Context, *ec2.DisassociateIpamResourceDiscoveryInput, ...request.Option) (*ec2.DisassociateIpamResourceDiscoveryOutput, error) + DisassociateIpamResourceDiscoveryRequest(*ec2.DisassociateIpamResourceDiscoveryInput) (*request.Request, *ec2.DisassociateIpamResourceDiscoveryOutput) + + DisassociateNatGatewayAddress(*ec2.DisassociateNatGatewayAddressInput) (*ec2.DisassociateNatGatewayAddressOutput, error) + DisassociateNatGatewayAddressWithContext(aws.Context, *ec2.DisassociateNatGatewayAddressInput, ...request.Option) (*ec2.DisassociateNatGatewayAddressOutput, error) + DisassociateNatGatewayAddressRequest(*ec2.DisassociateNatGatewayAddressInput) (*request.Request, *ec2.DisassociateNatGatewayAddressOutput) + + DisassociateRouteTable(*ec2.DisassociateRouteTableInput) (*ec2.DisassociateRouteTableOutput, error) + DisassociateRouteTableWithContext(aws.Context, *ec2.DisassociateRouteTableInput, ...request.Option) (*ec2.DisassociateRouteTableOutput, error) + DisassociateRouteTableRequest(*ec2.DisassociateRouteTableInput) (*request.Request, *ec2.DisassociateRouteTableOutput) + + DisassociateSubnetCidrBlock(*ec2.DisassociateSubnetCidrBlockInput) (*ec2.DisassociateSubnetCidrBlockOutput, error) + DisassociateSubnetCidrBlockWithContext(aws.Context, *ec2.DisassociateSubnetCidrBlockInput, ...request.Option) (*ec2.DisassociateSubnetCidrBlockOutput, error) + DisassociateSubnetCidrBlockRequest(*ec2.DisassociateSubnetCidrBlockInput) (*request.Request, *ec2.DisassociateSubnetCidrBlockOutput) + + DisassociateTransitGatewayMulticastDomain(*ec2.DisassociateTransitGatewayMulticastDomainInput) (*ec2.DisassociateTransitGatewayMulticastDomainOutput, error) + DisassociateTransitGatewayMulticastDomainWithContext(aws.Context, *ec2.DisassociateTransitGatewayMulticastDomainInput, ...request.Option) (*ec2.DisassociateTransitGatewayMulticastDomainOutput, error) + DisassociateTransitGatewayMulticastDomainRequest(*ec2.DisassociateTransitGatewayMulticastDomainInput) (*request.Request, *ec2.DisassociateTransitGatewayMulticastDomainOutput) + + DisassociateTransitGatewayPolicyTable(*ec2.DisassociateTransitGatewayPolicyTableInput) (*ec2.DisassociateTransitGatewayPolicyTableOutput, error) + DisassociateTransitGatewayPolicyTableWithContext(aws.Context, *ec2.DisassociateTransitGatewayPolicyTableInput, ...request.Option) (*ec2.DisassociateTransitGatewayPolicyTableOutput, error) + DisassociateTransitGatewayPolicyTableRequest(*ec2.DisassociateTransitGatewayPolicyTableInput) (*request.Request, *ec2.DisassociateTransitGatewayPolicyTableOutput) + + DisassociateTransitGatewayRouteTable(*ec2.DisassociateTransitGatewayRouteTableInput) (*ec2.DisassociateTransitGatewayRouteTableOutput, error) + DisassociateTransitGatewayRouteTableWithContext(aws.Context, *ec2.DisassociateTransitGatewayRouteTableInput, ...request.Option) (*ec2.DisassociateTransitGatewayRouteTableOutput, error) + DisassociateTransitGatewayRouteTableRequest(*ec2.DisassociateTransitGatewayRouteTableInput) (*request.Request, *ec2.DisassociateTransitGatewayRouteTableOutput) + + DisassociateTrunkInterface(*ec2.DisassociateTrunkInterfaceInput) (*ec2.DisassociateTrunkInterfaceOutput, error) + DisassociateTrunkInterfaceWithContext(aws.Context, *ec2.DisassociateTrunkInterfaceInput, ...request.Option) (*ec2.DisassociateTrunkInterfaceOutput, error) + DisassociateTrunkInterfaceRequest(*ec2.DisassociateTrunkInterfaceInput) (*request.Request, *ec2.DisassociateTrunkInterfaceOutput) + + DisassociateVpcCidrBlock(*ec2.DisassociateVpcCidrBlockInput) (*ec2.DisassociateVpcCidrBlockOutput, error) + DisassociateVpcCidrBlockWithContext(aws.Context, *ec2.DisassociateVpcCidrBlockInput, ...request.Option) (*ec2.DisassociateVpcCidrBlockOutput, error) + DisassociateVpcCidrBlockRequest(*ec2.DisassociateVpcCidrBlockInput) (*request.Request, *ec2.DisassociateVpcCidrBlockOutput) + + EnableAddressTransfer(*ec2.EnableAddressTransferInput) (*ec2.EnableAddressTransferOutput, error) + EnableAddressTransferWithContext(aws.Context, *ec2.EnableAddressTransferInput, ...request.Option) (*ec2.EnableAddressTransferOutput, error) + EnableAddressTransferRequest(*ec2.EnableAddressTransferInput) (*request.Request, *ec2.EnableAddressTransferOutput) + + EnableAwsNetworkPerformanceMetricSubscription(*ec2.EnableAwsNetworkPerformanceMetricSubscriptionInput) (*ec2.EnableAwsNetworkPerformanceMetricSubscriptionOutput, error) + EnableAwsNetworkPerformanceMetricSubscriptionWithContext(aws.Context, *ec2.EnableAwsNetworkPerformanceMetricSubscriptionInput, ...request.Option) (*ec2.EnableAwsNetworkPerformanceMetricSubscriptionOutput, error) + EnableAwsNetworkPerformanceMetricSubscriptionRequest(*ec2.EnableAwsNetworkPerformanceMetricSubscriptionInput) (*request.Request, *ec2.EnableAwsNetworkPerformanceMetricSubscriptionOutput) + + EnableEbsEncryptionByDefault(*ec2.EnableEbsEncryptionByDefaultInput) (*ec2.EnableEbsEncryptionByDefaultOutput, error) + EnableEbsEncryptionByDefaultWithContext(aws.Context, *ec2.EnableEbsEncryptionByDefaultInput, ...request.Option) (*ec2.EnableEbsEncryptionByDefaultOutput, error) + EnableEbsEncryptionByDefaultRequest(*ec2.EnableEbsEncryptionByDefaultInput) (*request.Request, *ec2.EnableEbsEncryptionByDefaultOutput) + + EnableFastLaunch(*ec2.EnableFastLaunchInput) (*ec2.EnableFastLaunchOutput, error) + EnableFastLaunchWithContext(aws.Context, *ec2.EnableFastLaunchInput, ...request.Option) (*ec2.EnableFastLaunchOutput, error) + EnableFastLaunchRequest(*ec2.EnableFastLaunchInput) (*request.Request, *ec2.EnableFastLaunchOutput) + + EnableFastSnapshotRestores(*ec2.EnableFastSnapshotRestoresInput) (*ec2.EnableFastSnapshotRestoresOutput, error) + EnableFastSnapshotRestoresWithContext(aws.Context, *ec2.EnableFastSnapshotRestoresInput, ...request.Option) (*ec2.EnableFastSnapshotRestoresOutput, error) + EnableFastSnapshotRestoresRequest(*ec2.EnableFastSnapshotRestoresInput) (*request.Request, *ec2.EnableFastSnapshotRestoresOutput) + + EnableImageDeprecation(*ec2.EnableImageDeprecationInput) (*ec2.EnableImageDeprecationOutput, error) + EnableImageDeprecationWithContext(aws.Context, *ec2.EnableImageDeprecationInput, ...request.Option) (*ec2.EnableImageDeprecationOutput, error) + EnableImageDeprecationRequest(*ec2.EnableImageDeprecationInput) (*request.Request, *ec2.EnableImageDeprecationOutput) + + EnableIpamOrganizationAdminAccount(*ec2.EnableIpamOrganizationAdminAccountInput) (*ec2.EnableIpamOrganizationAdminAccountOutput, error) + EnableIpamOrganizationAdminAccountWithContext(aws.Context, *ec2.EnableIpamOrganizationAdminAccountInput, ...request.Option) (*ec2.EnableIpamOrganizationAdminAccountOutput, error) + EnableIpamOrganizationAdminAccountRequest(*ec2.EnableIpamOrganizationAdminAccountInput) (*request.Request, *ec2.EnableIpamOrganizationAdminAccountOutput) + + EnableReachabilityAnalyzerOrganizationSharing(*ec2.EnableReachabilityAnalyzerOrganizationSharingInput) (*ec2.EnableReachabilityAnalyzerOrganizationSharingOutput, error) + EnableReachabilityAnalyzerOrganizationSharingWithContext(aws.Context, *ec2.EnableReachabilityAnalyzerOrganizationSharingInput, ...request.Option) (*ec2.EnableReachabilityAnalyzerOrganizationSharingOutput, error) + EnableReachabilityAnalyzerOrganizationSharingRequest(*ec2.EnableReachabilityAnalyzerOrganizationSharingInput) (*request.Request, *ec2.EnableReachabilityAnalyzerOrganizationSharingOutput) + + EnableSerialConsoleAccess(*ec2.EnableSerialConsoleAccessInput) (*ec2.EnableSerialConsoleAccessOutput, error) + EnableSerialConsoleAccessWithContext(aws.Context, *ec2.EnableSerialConsoleAccessInput, ...request.Option) (*ec2.EnableSerialConsoleAccessOutput, error) + EnableSerialConsoleAccessRequest(*ec2.EnableSerialConsoleAccessInput) (*request.Request, *ec2.EnableSerialConsoleAccessOutput) + + EnableTransitGatewayRouteTablePropagation(*ec2.EnableTransitGatewayRouteTablePropagationInput) (*ec2.EnableTransitGatewayRouteTablePropagationOutput, error) + EnableTransitGatewayRouteTablePropagationWithContext(aws.Context, *ec2.EnableTransitGatewayRouteTablePropagationInput, ...request.Option) (*ec2.EnableTransitGatewayRouteTablePropagationOutput, error) + EnableTransitGatewayRouteTablePropagationRequest(*ec2.EnableTransitGatewayRouteTablePropagationInput) (*request.Request, *ec2.EnableTransitGatewayRouteTablePropagationOutput) + + EnableVgwRoutePropagation(*ec2.EnableVgwRoutePropagationInput) (*ec2.EnableVgwRoutePropagationOutput, error) + EnableVgwRoutePropagationWithContext(aws.Context, *ec2.EnableVgwRoutePropagationInput, ...request.Option) (*ec2.EnableVgwRoutePropagationOutput, error) + EnableVgwRoutePropagationRequest(*ec2.EnableVgwRoutePropagationInput) (*request.Request, *ec2.EnableVgwRoutePropagationOutput) + + EnableVolumeIO(*ec2.EnableVolumeIOInput) (*ec2.EnableVolumeIOOutput, error) + EnableVolumeIOWithContext(aws.Context, *ec2.EnableVolumeIOInput, ...request.Option) (*ec2.EnableVolumeIOOutput, error) + EnableVolumeIORequest(*ec2.EnableVolumeIOInput) (*request.Request, *ec2.EnableVolumeIOOutput) + + EnableVpcClassicLink(*ec2.EnableVpcClassicLinkInput) (*ec2.EnableVpcClassicLinkOutput, error) + EnableVpcClassicLinkWithContext(aws.Context, *ec2.EnableVpcClassicLinkInput, ...request.Option) (*ec2.EnableVpcClassicLinkOutput, error) + EnableVpcClassicLinkRequest(*ec2.EnableVpcClassicLinkInput) (*request.Request, *ec2.EnableVpcClassicLinkOutput) + + EnableVpcClassicLinkDnsSupport(*ec2.EnableVpcClassicLinkDnsSupportInput) (*ec2.EnableVpcClassicLinkDnsSupportOutput, error) + EnableVpcClassicLinkDnsSupportWithContext(aws.Context, *ec2.EnableVpcClassicLinkDnsSupportInput, ...request.Option) (*ec2.EnableVpcClassicLinkDnsSupportOutput, error) + EnableVpcClassicLinkDnsSupportRequest(*ec2.EnableVpcClassicLinkDnsSupportInput) (*request.Request, *ec2.EnableVpcClassicLinkDnsSupportOutput) + + ExportClientVpnClientCertificateRevocationList(*ec2.ExportClientVpnClientCertificateRevocationListInput) (*ec2.ExportClientVpnClientCertificateRevocationListOutput, error) + ExportClientVpnClientCertificateRevocationListWithContext(aws.Context, *ec2.ExportClientVpnClientCertificateRevocationListInput, ...request.Option) (*ec2.ExportClientVpnClientCertificateRevocationListOutput, error) + ExportClientVpnClientCertificateRevocationListRequest(*ec2.ExportClientVpnClientCertificateRevocationListInput) (*request.Request, *ec2.ExportClientVpnClientCertificateRevocationListOutput) + + ExportClientVpnClientConfiguration(*ec2.ExportClientVpnClientConfigurationInput) (*ec2.ExportClientVpnClientConfigurationOutput, error) + ExportClientVpnClientConfigurationWithContext(aws.Context, *ec2.ExportClientVpnClientConfigurationInput, ...request.Option) (*ec2.ExportClientVpnClientConfigurationOutput, error) + ExportClientVpnClientConfigurationRequest(*ec2.ExportClientVpnClientConfigurationInput) (*request.Request, *ec2.ExportClientVpnClientConfigurationOutput) + + ExportImage(*ec2.ExportImageInput) (*ec2.ExportImageOutput, error) + ExportImageWithContext(aws.Context, *ec2.ExportImageInput, ...request.Option) (*ec2.ExportImageOutput, error) + ExportImageRequest(*ec2.ExportImageInput) (*request.Request, *ec2.ExportImageOutput) + + ExportTransitGatewayRoutes(*ec2.ExportTransitGatewayRoutesInput) (*ec2.ExportTransitGatewayRoutesOutput, error) + ExportTransitGatewayRoutesWithContext(aws.Context, *ec2.ExportTransitGatewayRoutesInput, ...request.Option) (*ec2.ExportTransitGatewayRoutesOutput, error) + ExportTransitGatewayRoutesRequest(*ec2.ExportTransitGatewayRoutesInput) (*request.Request, *ec2.ExportTransitGatewayRoutesOutput) + + GetAssociatedEnclaveCertificateIamRoles(*ec2.GetAssociatedEnclaveCertificateIamRolesInput) (*ec2.GetAssociatedEnclaveCertificateIamRolesOutput, error) + GetAssociatedEnclaveCertificateIamRolesWithContext(aws.Context, *ec2.GetAssociatedEnclaveCertificateIamRolesInput, ...request.Option) (*ec2.GetAssociatedEnclaveCertificateIamRolesOutput, error) + GetAssociatedEnclaveCertificateIamRolesRequest(*ec2.GetAssociatedEnclaveCertificateIamRolesInput) (*request.Request, *ec2.GetAssociatedEnclaveCertificateIamRolesOutput) + + GetAssociatedIpv6PoolCidrs(*ec2.GetAssociatedIpv6PoolCidrsInput) (*ec2.GetAssociatedIpv6PoolCidrsOutput, error) + GetAssociatedIpv6PoolCidrsWithContext(aws.Context, *ec2.GetAssociatedIpv6PoolCidrsInput, ...request.Option) (*ec2.GetAssociatedIpv6PoolCidrsOutput, error) + GetAssociatedIpv6PoolCidrsRequest(*ec2.GetAssociatedIpv6PoolCidrsInput) (*request.Request, *ec2.GetAssociatedIpv6PoolCidrsOutput) + + GetAssociatedIpv6PoolCidrsPages(*ec2.GetAssociatedIpv6PoolCidrsInput, func(*ec2.GetAssociatedIpv6PoolCidrsOutput, bool) bool) error + GetAssociatedIpv6PoolCidrsPagesWithContext(aws.Context, *ec2.GetAssociatedIpv6PoolCidrsInput, func(*ec2.GetAssociatedIpv6PoolCidrsOutput, bool) bool, ...request.Option) error + + GetAwsNetworkPerformanceData(*ec2.GetAwsNetworkPerformanceDataInput) (*ec2.GetAwsNetworkPerformanceDataOutput, error) + GetAwsNetworkPerformanceDataWithContext(aws.Context, *ec2.GetAwsNetworkPerformanceDataInput, ...request.Option) (*ec2.GetAwsNetworkPerformanceDataOutput, error) + GetAwsNetworkPerformanceDataRequest(*ec2.GetAwsNetworkPerformanceDataInput) (*request.Request, *ec2.GetAwsNetworkPerformanceDataOutput) + + GetAwsNetworkPerformanceDataPages(*ec2.GetAwsNetworkPerformanceDataInput, func(*ec2.GetAwsNetworkPerformanceDataOutput, bool) bool) error + GetAwsNetworkPerformanceDataPagesWithContext(aws.Context, *ec2.GetAwsNetworkPerformanceDataInput, func(*ec2.GetAwsNetworkPerformanceDataOutput, bool) bool, ...request.Option) error + + GetCapacityReservationUsage(*ec2.GetCapacityReservationUsageInput) (*ec2.GetCapacityReservationUsageOutput, error) + GetCapacityReservationUsageWithContext(aws.Context, *ec2.GetCapacityReservationUsageInput, ...request.Option) (*ec2.GetCapacityReservationUsageOutput, error) + GetCapacityReservationUsageRequest(*ec2.GetCapacityReservationUsageInput) (*request.Request, *ec2.GetCapacityReservationUsageOutput) + + GetCoipPoolUsage(*ec2.GetCoipPoolUsageInput) (*ec2.GetCoipPoolUsageOutput, error) + GetCoipPoolUsageWithContext(aws.Context, *ec2.GetCoipPoolUsageInput, ...request.Option) (*ec2.GetCoipPoolUsageOutput, error) + GetCoipPoolUsageRequest(*ec2.GetCoipPoolUsageInput) (*request.Request, *ec2.GetCoipPoolUsageOutput) + + GetConsoleOutput(*ec2.GetConsoleOutputInput) (*ec2.GetConsoleOutputOutput, error) + GetConsoleOutputWithContext(aws.Context, *ec2.GetConsoleOutputInput, ...request.Option) (*ec2.GetConsoleOutputOutput, error) + GetConsoleOutputRequest(*ec2.GetConsoleOutputInput) (*request.Request, *ec2.GetConsoleOutputOutput) + + GetConsoleScreenshot(*ec2.GetConsoleScreenshotInput) (*ec2.GetConsoleScreenshotOutput, error) + GetConsoleScreenshotWithContext(aws.Context, *ec2.GetConsoleScreenshotInput, ...request.Option) (*ec2.GetConsoleScreenshotOutput, error) + GetConsoleScreenshotRequest(*ec2.GetConsoleScreenshotInput) (*request.Request, *ec2.GetConsoleScreenshotOutput) + + GetDefaultCreditSpecification(*ec2.GetDefaultCreditSpecificationInput) (*ec2.GetDefaultCreditSpecificationOutput, error) + GetDefaultCreditSpecificationWithContext(aws.Context, *ec2.GetDefaultCreditSpecificationInput, ...request.Option) (*ec2.GetDefaultCreditSpecificationOutput, error) + GetDefaultCreditSpecificationRequest(*ec2.GetDefaultCreditSpecificationInput) (*request.Request, *ec2.GetDefaultCreditSpecificationOutput) + + GetEbsDefaultKmsKeyId(*ec2.GetEbsDefaultKmsKeyIdInput) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) + GetEbsDefaultKmsKeyIdWithContext(aws.Context, *ec2.GetEbsDefaultKmsKeyIdInput, ...request.Option) (*ec2.GetEbsDefaultKmsKeyIdOutput, error) + GetEbsDefaultKmsKeyIdRequest(*ec2.GetEbsDefaultKmsKeyIdInput) (*request.Request, *ec2.GetEbsDefaultKmsKeyIdOutput) + + GetEbsEncryptionByDefault(*ec2.GetEbsEncryptionByDefaultInput) (*ec2.GetEbsEncryptionByDefaultOutput, error) + GetEbsEncryptionByDefaultWithContext(aws.Context, *ec2.GetEbsEncryptionByDefaultInput, ...request.Option) (*ec2.GetEbsEncryptionByDefaultOutput, error) + GetEbsEncryptionByDefaultRequest(*ec2.GetEbsEncryptionByDefaultInput) (*request.Request, *ec2.GetEbsEncryptionByDefaultOutput) + + GetFlowLogsIntegrationTemplate(*ec2.GetFlowLogsIntegrationTemplateInput) (*ec2.GetFlowLogsIntegrationTemplateOutput, error) + GetFlowLogsIntegrationTemplateWithContext(aws.Context, *ec2.GetFlowLogsIntegrationTemplateInput, ...request.Option) (*ec2.GetFlowLogsIntegrationTemplateOutput, error) + GetFlowLogsIntegrationTemplateRequest(*ec2.GetFlowLogsIntegrationTemplateInput) (*request.Request, *ec2.GetFlowLogsIntegrationTemplateOutput) + + GetGroupsForCapacityReservation(*ec2.GetGroupsForCapacityReservationInput) (*ec2.GetGroupsForCapacityReservationOutput, error) + GetGroupsForCapacityReservationWithContext(aws.Context, *ec2.GetGroupsForCapacityReservationInput, ...request.Option) (*ec2.GetGroupsForCapacityReservationOutput, error) + GetGroupsForCapacityReservationRequest(*ec2.GetGroupsForCapacityReservationInput) (*request.Request, *ec2.GetGroupsForCapacityReservationOutput) + + GetGroupsForCapacityReservationPages(*ec2.GetGroupsForCapacityReservationInput, func(*ec2.GetGroupsForCapacityReservationOutput, bool) bool) error + GetGroupsForCapacityReservationPagesWithContext(aws.Context, *ec2.GetGroupsForCapacityReservationInput, func(*ec2.GetGroupsForCapacityReservationOutput, bool) bool, ...request.Option) error + + GetHostReservationPurchasePreview(*ec2.GetHostReservationPurchasePreviewInput) (*ec2.GetHostReservationPurchasePreviewOutput, error) + GetHostReservationPurchasePreviewWithContext(aws.Context, *ec2.GetHostReservationPurchasePreviewInput, ...request.Option) (*ec2.GetHostReservationPurchasePreviewOutput, error) + GetHostReservationPurchasePreviewRequest(*ec2.GetHostReservationPurchasePreviewInput) (*request.Request, *ec2.GetHostReservationPurchasePreviewOutput) + + GetInstanceTypesFromInstanceRequirements(*ec2.GetInstanceTypesFromInstanceRequirementsInput) (*ec2.GetInstanceTypesFromInstanceRequirementsOutput, error) + GetInstanceTypesFromInstanceRequirementsWithContext(aws.Context, *ec2.GetInstanceTypesFromInstanceRequirementsInput, ...request.Option) (*ec2.GetInstanceTypesFromInstanceRequirementsOutput, error) + GetInstanceTypesFromInstanceRequirementsRequest(*ec2.GetInstanceTypesFromInstanceRequirementsInput) (*request.Request, *ec2.GetInstanceTypesFromInstanceRequirementsOutput) + + GetInstanceTypesFromInstanceRequirementsPages(*ec2.GetInstanceTypesFromInstanceRequirementsInput, func(*ec2.GetInstanceTypesFromInstanceRequirementsOutput, bool) bool) error + GetInstanceTypesFromInstanceRequirementsPagesWithContext(aws.Context, *ec2.GetInstanceTypesFromInstanceRequirementsInput, func(*ec2.GetInstanceTypesFromInstanceRequirementsOutput, bool) bool, ...request.Option) error + + GetInstanceUefiData(*ec2.GetInstanceUefiDataInput) (*ec2.GetInstanceUefiDataOutput, error) + GetInstanceUefiDataWithContext(aws.Context, *ec2.GetInstanceUefiDataInput, ...request.Option) (*ec2.GetInstanceUefiDataOutput, error) + GetInstanceUefiDataRequest(*ec2.GetInstanceUefiDataInput) (*request.Request, *ec2.GetInstanceUefiDataOutput) + + GetIpamAddressHistory(*ec2.GetIpamAddressHistoryInput) (*ec2.GetIpamAddressHistoryOutput, error) + GetIpamAddressHistoryWithContext(aws.Context, *ec2.GetIpamAddressHistoryInput, ...request.Option) (*ec2.GetIpamAddressHistoryOutput, error) + GetIpamAddressHistoryRequest(*ec2.GetIpamAddressHistoryInput) (*request.Request, *ec2.GetIpamAddressHistoryOutput) + + GetIpamAddressHistoryPages(*ec2.GetIpamAddressHistoryInput, func(*ec2.GetIpamAddressHistoryOutput, bool) bool) error + GetIpamAddressHistoryPagesWithContext(aws.Context, *ec2.GetIpamAddressHistoryInput, func(*ec2.GetIpamAddressHistoryOutput, bool) bool, ...request.Option) error + + GetIpamDiscoveredAccounts(*ec2.GetIpamDiscoveredAccountsInput) (*ec2.GetIpamDiscoveredAccountsOutput, error) + GetIpamDiscoveredAccountsWithContext(aws.Context, *ec2.GetIpamDiscoveredAccountsInput, ...request.Option) (*ec2.GetIpamDiscoveredAccountsOutput, error) + GetIpamDiscoveredAccountsRequest(*ec2.GetIpamDiscoveredAccountsInput) (*request.Request, *ec2.GetIpamDiscoveredAccountsOutput) + + GetIpamDiscoveredAccountsPages(*ec2.GetIpamDiscoveredAccountsInput, func(*ec2.GetIpamDiscoveredAccountsOutput, bool) bool) error + GetIpamDiscoveredAccountsPagesWithContext(aws.Context, *ec2.GetIpamDiscoveredAccountsInput, func(*ec2.GetIpamDiscoveredAccountsOutput, bool) bool, ...request.Option) error + + GetIpamDiscoveredResourceCidrs(*ec2.GetIpamDiscoveredResourceCidrsInput) (*ec2.GetIpamDiscoveredResourceCidrsOutput, error) + GetIpamDiscoveredResourceCidrsWithContext(aws.Context, *ec2.GetIpamDiscoveredResourceCidrsInput, ...request.Option) (*ec2.GetIpamDiscoveredResourceCidrsOutput, error) + GetIpamDiscoveredResourceCidrsRequest(*ec2.GetIpamDiscoveredResourceCidrsInput) (*request.Request, *ec2.GetIpamDiscoveredResourceCidrsOutput) + + GetIpamDiscoveredResourceCidrsPages(*ec2.GetIpamDiscoveredResourceCidrsInput, func(*ec2.GetIpamDiscoveredResourceCidrsOutput, bool) bool) error + GetIpamDiscoveredResourceCidrsPagesWithContext(aws.Context, *ec2.GetIpamDiscoveredResourceCidrsInput, func(*ec2.GetIpamDiscoveredResourceCidrsOutput, bool) bool, ...request.Option) error + + GetIpamPoolAllocations(*ec2.GetIpamPoolAllocationsInput) (*ec2.GetIpamPoolAllocationsOutput, error) + GetIpamPoolAllocationsWithContext(aws.Context, *ec2.GetIpamPoolAllocationsInput, ...request.Option) (*ec2.GetIpamPoolAllocationsOutput, error) + GetIpamPoolAllocationsRequest(*ec2.GetIpamPoolAllocationsInput) (*request.Request, *ec2.GetIpamPoolAllocationsOutput) + + GetIpamPoolAllocationsPages(*ec2.GetIpamPoolAllocationsInput, func(*ec2.GetIpamPoolAllocationsOutput, bool) bool) error + GetIpamPoolAllocationsPagesWithContext(aws.Context, *ec2.GetIpamPoolAllocationsInput, func(*ec2.GetIpamPoolAllocationsOutput, bool) bool, ...request.Option) error + + GetIpamPoolCidrs(*ec2.GetIpamPoolCidrsInput) (*ec2.GetIpamPoolCidrsOutput, error) + GetIpamPoolCidrsWithContext(aws.Context, *ec2.GetIpamPoolCidrsInput, ...request.Option) (*ec2.GetIpamPoolCidrsOutput, error) + GetIpamPoolCidrsRequest(*ec2.GetIpamPoolCidrsInput) (*request.Request, *ec2.GetIpamPoolCidrsOutput) + + GetIpamPoolCidrsPages(*ec2.GetIpamPoolCidrsInput, func(*ec2.GetIpamPoolCidrsOutput, bool) bool) error + GetIpamPoolCidrsPagesWithContext(aws.Context, *ec2.GetIpamPoolCidrsInput, func(*ec2.GetIpamPoolCidrsOutput, bool) bool, ...request.Option) error + + GetIpamResourceCidrs(*ec2.GetIpamResourceCidrsInput) (*ec2.GetIpamResourceCidrsOutput, error) + GetIpamResourceCidrsWithContext(aws.Context, *ec2.GetIpamResourceCidrsInput, ...request.Option) (*ec2.GetIpamResourceCidrsOutput, error) + GetIpamResourceCidrsRequest(*ec2.GetIpamResourceCidrsInput) (*request.Request, *ec2.GetIpamResourceCidrsOutput) + + GetIpamResourceCidrsPages(*ec2.GetIpamResourceCidrsInput, func(*ec2.GetIpamResourceCidrsOutput, bool) bool) error + GetIpamResourceCidrsPagesWithContext(aws.Context, *ec2.GetIpamResourceCidrsInput, func(*ec2.GetIpamResourceCidrsOutput, bool) bool, ...request.Option) error + + GetLaunchTemplateData(*ec2.GetLaunchTemplateDataInput) (*ec2.GetLaunchTemplateDataOutput, error) + GetLaunchTemplateDataWithContext(aws.Context, *ec2.GetLaunchTemplateDataInput, ...request.Option) (*ec2.GetLaunchTemplateDataOutput, error) + GetLaunchTemplateDataRequest(*ec2.GetLaunchTemplateDataInput) (*request.Request, *ec2.GetLaunchTemplateDataOutput) + + GetManagedPrefixListAssociations(*ec2.GetManagedPrefixListAssociationsInput) (*ec2.GetManagedPrefixListAssociationsOutput, error) + GetManagedPrefixListAssociationsWithContext(aws.Context, *ec2.GetManagedPrefixListAssociationsInput, ...request.Option) (*ec2.GetManagedPrefixListAssociationsOutput, error) + GetManagedPrefixListAssociationsRequest(*ec2.GetManagedPrefixListAssociationsInput) (*request.Request, *ec2.GetManagedPrefixListAssociationsOutput) + + GetManagedPrefixListAssociationsPages(*ec2.GetManagedPrefixListAssociationsInput, func(*ec2.GetManagedPrefixListAssociationsOutput, bool) bool) error + GetManagedPrefixListAssociationsPagesWithContext(aws.Context, *ec2.GetManagedPrefixListAssociationsInput, func(*ec2.GetManagedPrefixListAssociationsOutput, bool) bool, ...request.Option) error + + GetManagedPrefixListEntries(*ec2.GetManagedPrefixListEntriesInput) (*ec2.GetManagedPrefixListEntriesOutput, error) + GetManagedPrefixListEntriesWithContext(aws.Context, *ec2.GetManagedPrefixListEntriesInput, ...request.Option) (*ec2.GetManagedPrefixListEntriesOutput, error) + GetManagedPrefixListEntriesRequest(*ec2.GetManagedPrefixListEntriesInput) (*request.Request, *ec2.GetManagedPrefixListEntriesOutput) + + GetManagedPrefixListEntriesPages(*ec2.GetManagedPrefixListEntriesInput, func(*ec2.GetManagedPrefixListEntriesOutput, bool) bool) error + GetManagedPrefixListEntriesPagesWithContext(aws.Context, *ec2.GetManagedPrefixListEntriesInput, func(*ec2.GetManagedPrefixListEntriesOutput, bool) bool, ...request.Option) error + + GetNetworkInsightsAccessScopeAnalysisFindings(*ec2.GetNetworkInsightsAccessScopeAnalysisFindingsInput) (*ec2.GetNetworkInsightsAccessScopeAnalysisFindingsOutput, error) + GetNetworkInsightsAccessScopeAnalysisFindingsWithContext(aws.Context, *ec2.GetNetworkInsightsAccessScopeAnalysisFindingsInput, ...request.Option) (*ec2.GetNetworkInsightsAccessScopeAnalysisFindingsOutput, error) + GetNetworkInsightsAccessScopeAnalysisFindingsRequest(*ec2.GetNetworkInsightsAccessScopeAnalysisFindingsInput) (*request.Request, *ec2.GetNetworkInsightsAccessScopeAnalysisFindingsOutput) + + GetNetworkInsightsAccessScopeAnalysisFindingsPages(*ec2.GetNetworkInsightsAccessScopeAnalysisFindingsInput, func(*ec2.GetNetworkInsightsAccessScopeAnalysisFindingsOutput, bool) bool) error + GetNetworkInsightsAccessScopeAnalysisFindingsPagesWithContext(aws.Context, *ec2.GetNetworkInsightsAccessScopeAnalysisFindingsInput, func(*ec2.GetNetworkInsightsAccessScopeAnalysisFindingsOutput, bool) bool, ...request.Option) error + + GetNetworkInsightsAccessScopeContent(*ec2.GetNetworkInsightsAccessScopeContentInput) (*ec2.GetNetworkInsightsAccessScopeContentOutput, error) + GetNetworkInsightsAccessScopeContentWithContext(aws.Context, *ec2.GetNetworkInsightsAccessScopeContentInput, ...request.Option) (*ec2.GetNetworkInsightsAccessScopeContentOutput, error) + GetNetworkInsightsAccessScopeContentRequest(*ec2.GetNetworkInsightsAccessScopeContentInput) (*request.Request, *ec2.GetNetworkInsightsAccessScopeContentOutput) + + GetPasswordData(*ec2.GetPasswordDataInput) (*ec2.GetPasswordDataOutput, error) + GetPasswordDataWithContext(aws.Context, *ec2.GetPasswordDataInput, ...request.Option) (*ec2.GetPasswordDataOutput, error) + GetPasswordDataRequest(*ec2.GetPasswordDataInput) (*request.Request, *ec2.GetPasswordDataOutput) + + GetReservedInstancesExchangeQuote(*ec2.GetReservedInstancesExchangeQuoteInput) (*ec2.GetReservedInstancesExchangeQuoteOutput, error) + GetReservedInstancesExchangeQuoteWithContext(aws.Context, *ec2.GetReservedInstancesExchangeQuoteInput, ...request.Option) (*ec2.GetReservedInstancesExchangeQuoteOutput, error) + GetReservedInstancesExchangeQuoteRequest(*ec2.GetReservedInstancesExchangeQuoteInput) (*request.Request, *ec2.GetReservedInstancesExchangeQuoteOutput) + + GetSerialConsoleAccessStatus(*ec2.GetSerialConsoleAccessStatusInput) (*ec2.GetSerialConsoleAccessStatusOutput, error) + GetSerialConsoleAccessStatusWithContext(aws.Context, *ec2.GetSerialConsoleAccessStatusInput, ...request.Option) (*ec2.GetSerialConsoleAccessStatusOutput, error) + GetSerialConsoleAccessStatusRequest(*ec2.GetSerialConsoleAccessStatusInput) (*request.Request, *ec2.GetSerialConsoleAccessStatusOutput) + + GetSpotPlacementScores(*ec2.GetSpotPlacementScoresInput) (*ec2.GetSpotPlacementScoresOutput, error) + GetSpotPlacementScoresWithContext(aws.Context, *ec2.GetSpotPlacementScoresInput, ...request.Option) (*ec2.GetSpotPlacementScoresOutput, error) + GetSpotPlacementScoresRequest(*ec2.GetSpotPlacementScoresInput) (*request.Request, *ec2.GetSpotPlacementScoresOutput) + + GetSpotPlacementScoresPages(*ec2.GetSpotPlacementScoresInput, func(*ec2.GetSpotPlacementScoresOutput, bool) bool) error + GetSpotPlacementScoresPagesWithContext(aws.Context, *ec2.GetSpotPlacementScoresInput, func(*ec2.GetSpotPlacementScoresOutput, bool) bool, ...request.Option) error + + GetSubnetCidrReservations(*ec2.GetSubnetCidrReservationsInput) (*ec2.GetSubnetCidrReservationsOutput, error) + GetSubnetCidrReservationsWithContext(aws.Context, *ec2.GetSubnetCidrReservationsInput, ...request.Option) (*ec2.GetSubnetCidrReservationsOutput, error) + GetSubnetCidrReservationsRequest(*ec2.GetSubnetCidrReservationsInput) (*request.Request, *ec2.GetSubnetCidrReservationsOutput) + + GetTransitGatewayAttachmentPropagations(*ec2.GetTransitGatewayAttachmentPropagationsInput) (*ec2.GetTransitGatewayAttachmentPropagationsOutput, error) + GetTransitGatewayAttachmentPropagationsWithContext(aws.Context, *ec2.GetTransitGatewayAttachmentPropagationsInput, ...request.Option) (*ec2.GetTransitGatewayAttachmentPropagationsOutput, error) + GetTransitGatewayAttachmentPropagationsRequest(*ec2.GetTransitGatewayAttachmentPropagationsInput) (*request.Request, *ec2.GetTransitGatewayAttachmentPropagationsOutput) + + GetTransitGatewayAttachmentPropagationsPages(*ec2.GetTransitGatewayAttachmentPropagationsInput, func(*ec2.GetTransitGatewayAttachmentPropagationsOutput, bool) bool) error + GetTransitGatewayAttachmentPropagationsPagesWithContext(aws.Context, *ec2.GetTransitGatewayAttachmentPropagationsInput, func(*ec2.GetTransitGatewayAttachmentPropagationsOutput, bool) bool, ...request.Option) error + + GetTransitGatewayMulticastDomainAssociations(*ec2.GetTransitGatewayMulticastDomainAssociationsInput) (*ec2.GetTransitGatewayMulticastDomainAssociationsOutput, error) + GetTransitGatewayMulticastDomainAssociationsWithContext(aws.Context, *ec2.GetTransitGatewayMulticastDomainAssociationsInput, ...request.Option) (*ec2.GetTransitGatewayMulticastDomainAssociationsOutput, error) + GetTransitGatewayMulticastDomainAssociationsRequest(*ec2.GetTransitGatewayMulticastDomainAssociationsInput) (*request.Request, *ec2.GetTransitGatewayMulticastDomainAssociationsOutput) + + GetTransitGatewayMulticastDomainAssociationsPages(*ec2.GetTransitGatewayMulticastDomainAssociationsInput, func(*ec2.GetTransitGatewayMulticastDomainAssociationsOutput, bool) bool) error + GetTransitGatewayMulticastDomainAssociationsPagesWithContext(aws.Context, *ec2.GetTransitGatewayMulticastDomainAssociationsInput, func(*ec2.GetTransitGatewayMulticastDomainAssociationsOutput, bool) bool, ...request.Option) error + + GetTransitGatewayPolicyTableAssociations(*ec2.GetTransitGatewayPolicyTableAssociationsInput) (*ec2.GetTransitGatewayPolicyTableAssociationsOutput, error) + GetTransitGatewayPolicyTableAssociationsWithContext(aws.Context, *ec2.GetTransitGatewayPolicyTableAssociationsInput, ...request.Option) (*ec2.GetTransitGatewayPolicyTableAssociationsOutput, error) + GetTransitGatewayPolicyTableAssociationsRequest(*ec2.GetTransitGatewayPolicyTableAssociationsInput) (*request.Request, *ec2.GetTransitGatewayPolicyTableAssociationsOutput) + + GetTransitGatewayPolicyTableAssociationsPages(*ec2.GetTransitGatewayPolicyTableAssociationsInput, func(*ec2.GetTransitGatewayPolicyTableAssociationsOutput, bool) bool) error + GetTransitGatewayPolicyTableAssociationsPagesWithContext(aws.Context, *ec2.GetTransitGatewayPolicyTableAssociationsInput, func(*ec2.GetTransitGatewayPolicyTableAssociationsOutput, bool) bool, ...request.Option) error + + GetTransitGatewayPolicyTableEntries(*ec2.GetTransitGatewayPolicyTableEntriesInput) (*ec2.GetTransitGatewayPolicyTableEntriesOutput, error) + GetTransitGatewayPolicyTableEntriesWithContext(aws.Context, *ec2.GetTransitGatewayPolicyTableEntriesInput, ...request.Option) (*ec2.GetTransitGatewayPolicyTableEntriesOutput, error) + GetTransitGatewayPolicyTableEntriesRequest(*ec2.GetTransitGatewayPolicyTableEntriesInput) (*request.Request, *ec2.GetTransitGatewayPolicyTableEntriesOutput) + + GetTransitGatewayPrefixListReferences(*ec2.GetTransitGatewayPrefixListReferencesInput) (*ec2.GetTransitGatewayPrefixListReferencesOutput, error) + GetTransitGatewayPrefixListReferencesWithContext(aws.Context, *ec2.GetTransitGatewayPrefixListReferencesInput, ...request.Option) (*ec2.GetTransitGatewayPrefixListReferencesOutput, error) + GetTransitGatewayPrefixListReferencesRequest(*ec2.GetTransitGatewayPrefixListReferencesInput) (*request.Request, *ec2.GetTransitGatewayPrefixListReferencesOutput) + + GetTransitGatewayPrefixListReferencesPages(*ec2.GetTransitGatewayPrefixListReferencesInput, func(*ec2.GetTransitGatewayPrefixListReferencesOutput, bool) bool) error + GetTransitGatewayPrefixListReferencesPagesWithContext(aws.Context, *ec2.GetTransitGatewayPrefixListReferencesInput, func(*ec2.GetTransitGatewayPrefixListReferencesOutput, bool) bool, ...request.Option) error + + GetTransitGatewayRouteTableAssociations(*ec2.GetTransitGatewayRouteTableAssociationsInput) (*ec2.GetTransitGatewayRouteTableAssociationsOutput, error) + GetTransitGatewayRouteTableAssociationsWithContext(aws.Context, *ec2.GetTransitGatewayRouteTableAssociationsInput, ...request.Option) (*ec2.GetTransitGatewayRouteTableAssociationsOutput, error) + GetTransitGatewayRouteTableAssociationsRequest(*ec2.GetTransitGatewayRouteTableAssociationsInput) (*request.Request, *ec2.GetTransitGatewayRouteTableAssociationsOutput) + + GetTransitGatewayRouteTableAssociationsPages(*ec2.GetTransitGatewayRouteTableAssociationsInput, func(*ec2.GetTransitGatewayRouteTableAssociationsOutput, bool) bool) error + GetTransitGatewayRouteTableAssociationsPagesWithContext(aws.Context, *ec2.GetTransitGatewayRouteTableAssociationsInput, func(*ec2.GetTransitGatewayRouteTableAssociationsOutput, bool) bool, ...request.Option) error + + GetTransitGatewayRouteTablePropagations(*ec2.GetTransitGatewayRouteTablePropagationsInput) (*ec2.GetTransitGatewayRouteTablePropagationsOutput, error) + GetTransitGatewayRouteTablePropagationsWithContext(aws.Context, *ec2.GetTransitGatewayRouteTablePropagationsInput, ...request.Option) (*ec2.GetTransitGatewayRouteTablePropagationsOutput, error) + GetTransitGatewayRouteTablePropagationsRequest(*ec2.GetTransitGatewayRouteTablePropagationsInput) (*request.Request, *ec2.GetTransitGatewayRouteTablePropagationsOutput) + + GetTransitGatewayRouteTablePropagationsPages(*ec2.GetTransitGatewayRouteTablePropagationsInput, func(*ec2.GetTransitGatewayRouteTablePropagationsOutput, bool) bool) error + GetTransitGatewayRouteTablePropagationsPagesWithContext(aws.Context, *ec2.GetTransitGatewayRouteTablePropagationsInput, func(*ec2.GetTransitGatewayRouteTablePropagationsOutput, bool) bool, ...request.Option) error + + GetVerifiedAccessEndpointPolicy(*ec2.GetVerifiedAccessEndpointPolicyInput) (*ec2.GetVerifiedAccessEndpointPolicyOutput, error) + GetVerifiedAccessEndpointPolicyWithContext(aws.Context, *ec2.GetVerifiedAccessEndpointPolicyInput, ...request.Option) (*ec2.GetVerifiedAccessEndpointPolicyOutput, error) + GetVerifiedAccessEndpointPolicyRequest(*ec2.GetVerifiedAccessEndpointPolicyInput) (*request.Request, *ec2.GetVerifiedAccessEndpointPolicyOutput) + + GetVerifiedAccessGroupPolicy(*ec2.GetVerifiedAccessGroupPolicyInput) (*ec2.GetVerifiedAccessGroupPolicyOutput, error) + GetVerifiedAccessGroupPolicyWithContext(aws.Context, *ec2.GetVerifiedAccessGroupPolicyInput, ...request.Option) (*ec2.GetVerifiedAccessGroupPolicyOutput, error) + GetVerifiedAccessGroupPolicyRequest(*ec2.GetVerifiedAccessGroupPolicyInput) (*request.Request, *ec2.GetVerifiedAccessGroupPolicyOutput) + + GetVpnConnectionDeviceSampleConfiguration(*ec2.GetVpnConnectionDeviceSampleConfigurationInput) (*ec2.GetVpnConnectionDeviceSampleConfigurationOutput, error) + GetVpnConnectionDeviceSampleConfigurationWithContext(aws.Context, *ec2.GetVpnConnectionDeviceSampleConfigurationInput, ...request.Option) (*ec2.GetVpnConnectionDeviceSampleConfigurationOutput, error) + GetVpnConnectionDeviceSampleConfigurationRequest(*ec2.GetVpnConnectionDeviceSampleConfigurationInput) (*request.Request, *ec2.GetVpnConnectionDeviceSampleConfigurationOutput) + + GetVpnConnectionDeviceTypes(*ec2.GetVpnConnectionDeviceTypesInput) (*ec2.GetVpnConnectionDeviceTypesOutput, error) + GetVpnConnectionDeviceTypesWithContext(aws.Context, *ec2.GetVpnConnectionDeviceTypesInput, ...request.Option) (*ec2.GetVpnConnectionDeviceTypesOutput, error) + GetVpnConnectionDeviceTypesRequest(*ec2.GetVpnConnectionDeviceTypesInput) (*request.Request, *ec2.GetVpnConnectionDeviceTypesOutput) + + GetVpnConnectionDeviceTypesPages(*ec2.GetVpnConnectionDeviceTypesInput, func(*ec2.GetVpnConnectionDeviceTypesOutput, bool) bool) error + GetVpnConnectionDeviceTypesPagesWithContext(aws.Context, *ec2.GetVpnConnectionDeviceTypesInput, func(*ec2.GetVpnConnectionDeviceTypesOutput, bool) bool, ...request.Option) error + + GetVpnTunnelReplacementStatus(*ec2.GetVpnTunnelReplacementStatusInput) (*ec2.GetVpnTunnelReplacementStatusOutput, error) + GetVpnTunnelReplacementStatusWithContext(aws.Context, *ec2.GetVpnTunnelReplacementStatusInput, ...request.Option) (*ec2.GetVpnTunnelReplacementStatusOutput, error) + GetVpnTunnelReplacementStatusRequest(*ec2.GetVpnTunnelReplacementStatusInput) (*request.Request, *ec2.GetVpnTunnelReplacementStatusOutput) + + ImportClientVpnClientCertificateRevocationList(*ec2.ImportClientVpnClientCertificateRevocationListInput) (*ec2.ImportClientVpnClientCertificateRevocationListOutput, error) + ImportClientVpnClientCertificateRevocationListWithContext(aws.Context, *ec2.ImportClientVpnClientCertificateRevocationListInput, ...request.Option) (*ec2.ImportClientVpnClientCertificateRevocationListOutput, error) + ImportClientVpnClientCertificateRevocationListRequest(*ec2.ImportClientVpnClientCertificateRevocationListInput) (*request.Request, *ec2.ImportClientVpnClientCertificateRevocationListOutput) + + ImportImage(*ec2.ImportImageInput) (*ec2.ImportImageOutput, error) + ImportImageWithContext(aws.Context, *ec2.ImportImageInput, ...request.Option) (*ec2.ImportImageOutput, error) + ImportImageRequest(*ec2.ImportImageInput) (*request.Request, *ec2.ImportImageOutput) + + ImportInstance(*ec2.ImportInstanceInput) (*ec2.ImportInstanceOutput, error) + ImportInstanceWithContext(aws.Context, *ec2.ImportInstanceInput, ...request.Option) (*ec2.ImportInstanceOutput, error) + ImportInstanceRequest(*ec2.ImportInstanceInput) (*request.Request, *ec2.ImportInstanceOutput) + + ImportKeyPair(*ec2.ImportKeyPairInput) (*ec2.ImportKeyPairOutput, error) + ImportKeyPairWithContext(aws.Context, *ec2.ImportKeyPairInput, ...request.Option) (*ec2.ImportKeyPairOutput, error) + ImportKeyPairRequest(*ec2.ImportKeyPairInput) (*request.Request, *ec2.ImportKeyPairOutput) + + ImportSnapshot(*ec2.ImportSnapshotInput) (*ec2.ImportSnapshotOutput, error) + ImportSnapshotWithContext(aws.Context, *ec2.ImportSnapshotInput, ...request.Option) (*ec2.ImportSnapshotOutput, error) + ImportSnapshotRequest(*ec2.ImportSnapshotInput) (*request.Request, *ec2.ImportSnapshotOutput) + + ImportVolume(*ec2.ImportVolumeInput) (*ec2.ImportVolumeOutput, error) + ImportVolumeWithContext(aws.Context, *ec2.ImportVolumeInput, ...request.Option) (*ec2.ImportVolumeOutput, error) + ImportVolumeRequest(*ec2.ImportVolumeInput) (*request.Request, *ec2.ImportVolumeOutput) + + ListImagesInRecycleBin(*ec2.ListImagesInRecycleBinInput) (*ec2.ListImagesInRecycleBinOutput, error) + ListImagesInRecycleBinWithContext(aws.Context, *ec2.ListImagesInRecycleBinInput, ...request.Option) (*ec2.ListImagesInRecycleBinOutput, error) + ListImagesInRecycleBinRequest(*ec2.ListImagesInRecycleBinInput) (*request.Request, *ec2.ListImagesInRecycleBinOutput) + + ListImagesInRecycleBinPages(*ec2.ListImagesInRecycleBinInput, func(*ec2.ListImagesInRecycleBinOutput, bool) bool) error + ListImagesInRecycleBinPagesWithContext(aws.Context, *ec2.ListImagesInRecycleBinInput, func(*ec2.ListImagesInRecycleBinOutput, bool) bool, ...request.Option) error + + ListSnapshotsInRecycleBin(*ec2.ListSnapshotsInRecycleBinInput) (*ec2.ListSnapshotsInRecycleBinOutput, error) + ListSnapshotsInRecycleBinWithContext(aws.Context, *ec2.ListSnapshotsInRecycleBinInput, ...request.Option) (*ec2.ListSnapshotsInRecycleBinOutput, error) + ListSnapshotsInRecycleBinRequest(*ec2.ListSnapshotsInRecycleBinInput) (*request.Request, *ec2.ListSnapshotsInRecycleBinOutput) + + ListSnapshotsInRecycleBinPages(*ec2.ListSnapshotsInRecycleBinInput, func(*ec2.ListSnapshotsInRecycleBinOutput, bool) bool) error + ListSnapshotsInRecycleBinPagesWithContext(aws.Context, *ec2.ListSnapshotsInRecycleBinInput, func(*ec2.ListSnapshotsInRecycleBinOutput, bool) bool, ...request.Option) error + + ModifyAddressAttribute(*ec2.ModifyAddressAttributeInput) (*ec2.ModifyAddressAttributeOutput, error) + ModifyAddressAttributeWithContext(aws.Context, *ec2.ModifyAddressAttributeInput, ...request.Option) (*ec2.ModifyAddressAttributeOutput, error) + ModifyAddressAttributeRequest(*ec2.ModifyAddressAttributeInput) (*request.Request, *ec2.ModifyAddressAttributeOutput) + + ModifyAvailabilityZoneGroup(*ec2.ModifyAvailabilityZoneGroupInput) (*ec2.ModifyAvailabilityZoneGroupOutput, error) + ModifyAvailabilityZoneGroupWithContext(aws.Context, *ec2.ModifyAvailabilityZoneGroupInput, ...request.Option) (*ec2.ModifyAvailabilityZoneGroupOutput, error) + ModifyAvailabilityZoneGroupRequest(*ec2.ModifyAvailabilityZoneGroupInput) (*request.Request, *ec2.ModifyAvailabilityZoneGroupOutput) + + ModifyCapacityReservation(*ec2.ModifyCapacityReservationInput) (*ec2.ModifyCapacityReservationOutput, error) + ModifyCapacityReservationWithContext(aws.Context, *ec2.ModifyCapacityReservationInput, ...request.Option) (*ec2.ModifyCapacityReservationOutput, error) + ModifyCapacityReservationRequest(*ec2.ModifyCapacityReservationInput) (*request.Request, *ec2.ModifyCapacityReservationOutput) + + ModifyCapacityReservationFleet(*ec2.ModifyCapacityReservationFleetInput) (*ec2.ModifyCapacityReservationFleetOutput, error) + ModifyCapacityReservationFleetWithContext(aws.Context, *ec2.ModifyCapacityReservationFleetInput, ...request.Option) (*ec2.ModifyCapacityReservationFleetOutput, error) + ModifyCapacityReservationFleetRequest(*ec2.ModifyCapacityReservationFleetInput) (*request.Request, *ec2.ModifyCapacityReservationFleetOutput) + + ModifyClientVpnEndpoint(*ec2.ModifyClientVpnEndpointInput) (*ec2.ModifyClientVpnEndpointOutput, error) + ModifyClientVpnEndpointWithContext(aws.Context, *ec2.ModifyClientVpnEndpointInput, ...request.Option) (*ec2.ModifyClientVpnEndpointOutput, error) + ModifyClientVpnEndpointRequest(*ec2.ModifyClientVpnEndpointInput) (*request.Request, *ec2.ModifyClientVpnEndpointOutput) + + ModifyDefaultCreditSpecification(*ec2.ModifyDefaultCreditSpecificationInput) (*ec2.ModifyDefaultCreditSpecificationOutput, error) + ModifyDefaultCreditSpecificationWithContext(aws.Context, *ec2.ModifyDefaultCreditSpecificationInput, ...request.Option) (*ec2.ModifyDefaultCreditSpecificationOutput, error) + ModifyDefaultCreditSpecificationRequest(*ec2.ModifyDefaultCreditSpecificationInput) (*request.Request, *ec2.ModifyDefaultCreditSpecificationOutput) + + ModifyEbsDefaultKmsKeyId(*ec2.ModifyEbsDefaultKmsKeyIdInput) (*ec2.ModifyEbsDefaultKmsKeyIdOutput, error) + ModifyEbsDefaultKmsKeyIdWithContext(aws.Context, *ec2.ModifyEbsDefaultKmsKeyIdInput, ...request.Option) (*ec2.ModifyEbsDefaultKmsKeyIdOutput, error) + ModifyEbsDefaultKmsKeyIdRequest(*ec2.ModifyEbsDefaultKmsKeyIdInput) (*request.Request, *ec2.ModifyEbsDefaultKmsKeyIdOutput) + + ModifyFleet(*ec2.ModifyFleetInput) (*ec2.ModifyFleetOutput, error) + ModifyFleetWithContext(aws.Context, *ec2.ModifyFleetInput, ...request.Option) (*ec2.ModifyFleetOutput, error) + ModifyFleetRequest(*ec2.ModifyFleetInput) (*request.Request, *ec2.ModifyFleetOutput) + + ModifyFpgaImageAttribute(*ec2.ModifyFpgaImageAttributeInput) (*ec2.ModifyFpgaImageAttributeOutput, error) + ModifyFpgaImageAttributeWithContext(aws.Context, *ec2.ModifyFpgaImageAttributeInput, ...request.Option) (*ec2.ModifyFpgaImageAttributeOutput, error) + ModifyFpgaImageAttributeRequest(*ec2.ModifyFpgaImageAttributeInput) (*request.Request, *ec2.ModifyFpgaImageAttributeOutput) + + ModifyHosts(*ec2.ModifyHostsInput) (*ec2.ModifyHostsOutput, error) + ModifyHostsWithContext(aws.Context, *ec2.ModifyHostsInput, ...request.Option) (*ec2.ModifyHostsOutput, error) + ModifyHostsRequest(*ec2.ModifyHostsInput) (*request.Request, *ec2.ModifyHostsOutput) + + ModifyIdFormat(*ec2.ModifyIdFormatInput) (*ec2.ModifyIdFormatOutput, error) + ModifyIdFormatWithContext(aws.Context, *ec2.ModifyIdFormatInput, ...request.Option) (*ec2.ModifyIdFormatOutput, error) + ModifyIdFormatRequest(*ec2.ModifyIdFormatInput) (*request.Request, *ec2.ModifyIdFormatOutput) + + ModifyIdentityIdFormat(*ec2.ModifyIdentityIdFormatInput) (*ec2.ModifyIdentityIdFormatOutput, error) + ModifyIdentityIdFormatWithContext(aws.Context, *ec2.ModifyIdentityIdFormatInput, ...request.Option) (*ec2.ModifyIdentityIdFormatOutput, error) + ModifyIdentityIdFormatRequest(*ec2.ModifyIdentityIdFormatInput) (*request.Request, *ec2.ModifyIdentityIdFormatOutput) + + ModifyImageAttribute(*ec2.ModifyImageAttributeInput) (*ec2.ModifyImageAttributeOutput, error) + ModifyImageAttributeWithContext(aws.Context, *ec2.ModifyImageAttributeInput, ...request.Option) (*ec2.ModifyImageAttributeOutput, error) + ModifyImageAttributeRequest(*ec2.ModifyImageAttributeInput) (*request.Request, *ec2.ModifyImageAttributeOutput) + + ModifyInstanceAttribute(*ec2.ModifyInstanceAttributeInput) (*ec2.ModifyInstanceAttributeOutput, error) + ModifyInstanceAttributeWithContext(aws.Context, *ec2.ModifyInstanceAttributeInput, ...request.Option) (*ec2.ModifyInstanceAttributeOutput, error) + ModifyInstanceAttributeRequest(*ec2.ModifyInstanceAttributeInput) (*request.Request, *ec2.ModifyInstanceAttributeOutput) + + ModifyInstanceCapacityReservationAttributes(*ec2.ModifyInstanceCapacityReservationAttributesInput) (*ec2.ModifyInstanceCapacityReservationAttributesOutput, error) + ModifyInstanceCapacityReservationAttributesWithContext(aws.Context, *ec2.ModifyInstanceCapacityReservationAttributesInput, ...request.Option) (*ec2.ModifyInstanceCapacityReservationAttributesOutput, error) + ModifyInstanceCapacityReservationAttributesRequest(*ec2.ModifyInstanceCapacityReservationAttributesInput) (*request.Request, *ec2.ModifyInstanceCapacityReservationAttributesOutput) + + ModifyInstanceCreditSpecification(*ec2.ModifyInstanceCreditSpecificationInput) (*ec2.ModifyInstanceCreditSpecificationOutput, error) + ModifyInstanceCreditSpecificationWithContext(aws.Context, *ec2.ModifyInstanceCreditSpecificationInput, ...request.Option) (*ec2.ModifyInstanceCreditSpecificationOutput, error) + ModifyInstanceCreditSpecificationRequest(*ec2.ModifyInstanceCreditSpecificationInput) (*request.Request, *ec2.ModifyInstanceCreditSpecificationOutput) + + ModifyInstanceEventStartTime(*ec2.ModifyInstanceEventStartTimeInput) (*ec2.ModifyInstanceEventStartTimeOutput, error) + ModifyInstanceEventStartTimeWithContext(aws.Context, *ec2.ModifyInstanceEventStartTimeInput, ...request.Option) (*ec2.ModifyInstanceEventStartTimeOutput, error) + ModifyInstanceEventStartTimeRequest(*ec2.ModifyInstanceEventStartTimeInput) (*request.Request, *ec2.ModifyInstanceEventStartTimeOutput) + + ModifyInstanceEventWindow(*ec2.ModifyInstanceEventWindowInput) (*ec2.ModifyInstanceEventWindowOutput, error) + ModifyInstanceEventWindowWithContext(aws.Context, *ec2.ModifyInstanceEventWindowInput, ...request.Option) (*ec2.ModifyInstanceEventWindowOutput, error) + ModifyInstanceEventWindowRequest(*ec2.ModifyInstanceEventWindowInput) (*request.Request, *ec2.ModifyInstanceEventWindowOutput) + + ModifyInstanceMaintenanceOptions(*ec2.ModifyInstanceMaintenanceOptionsInput) (*ec2.ModifyInstanceMaintenanceOptionsOutput, error) + ModifyInstanceMaintenanceOptionsWithContext(aws.Context, *ec2.ModifyInstanceMaintenanceOptionsInput, ...request.Option) (*ec2.ModifyInstanceMaintenanceOptionsOutput, error) + ModifyInstanceMaintenanceOptionsRequest(*ec2.ModifyInstanceMaintenanceOptionsInput) (*request.Request, *ec2.ModifyInstanceMaintenanceOptionsOutput) + + ModifyInstanceMetadataOptions(*ec2.ModifyInstanceMetadataOptionsInput) (*ec2.ModifyInstanceMetadataOptionsOutput, error) + ModifyInstanceMetadataOptionsWithContext(aws.Context, *ec2.ModifyInstanceMetadataOptionsInput, ...request.Option) (*ec2.ModifyInstanceMetadataOptionsOutput, error) + ModifyInstanceMetadataOptionsRequest(*ec2.ModifyInstanceMetadataOptionsInput) (*request.Request, *ec2.ModifyInstanceMetadataOptionsOutput) + + ModifyInstancePlacement(*ec2.ModifyInstancePlacementInput) (*ec2.ModifyInstancePlacementOutput, error) + ModifyInstancePlacementWithContext(aws.Context, *ec2.ModifyInstancePlacementInput, ...request.Option) (*ec2.ModifyInstancePlacementOutput, error) + ModifyInstancePlacementRequest(*ec2.ModifyInstancePlacementInput) (*request.Request, *ec2.ModifyInstancePlacementOutput) + + ModifyIpam(*ec2.ModifyIpamInput) (*ec2.ModifyIpamOutput, error) + ModifyIpamWithContext(aws.Context, *ec2.ModifyIpamInput, ...request.Option) (*ec2.ModifyIpamOutput, error) + ModifyIpamRequest(*ec2.ModifyIpamInput) (*request.Request, *ec2.ModifyIpamOutput) + + ModifyIpamPool(*ec2.ModifyIpamPoolInput) (*ec2.ModifyIpamPoolOutput, error) + ModifyIpamPoolWithContext(aws.Context, *ec2.ModifyIpamPoolInput, ...request.Option) (*ec2.ModifyIpamPoolOutput, error) + ModifyIpamPoolRequest(*ec2.ModifyIpamPoolInput) (*request.Request, *ec2.ModifyIpamPoolOutput) + + ModifyIpamResourceCidr(*ec2.ModifyIpamResourceCidrInput) (*ec2.ModifyIpamResourceCidrOutput, error) + ModifyIpamResourceCidrWithContext(aws.Context, *ec2.ModifyIpamResourceCidrInput, ...request.Option) (*ec2.ModifyIpamResourceCidrOutput, error) + ModifyIpamResourceCidrRequest(*ec2.ModifyIpamResourceCidrInput) (*request.Request, *ec2.ModifyIpamResourceCidrOutput) + + ModifyIpamResourceDiscovery(*ec2.ModifyIpamResourceDiscoveryInput) (*ec2.ModifyIpamResourceDiscoveryOutput, error) + ModifyIpamResourceDiscoveryWithContext(aws.Context, *ec2.ModifyIpamResourceDiscoveryInput, ...request.Option) (*ec2.ModifyIpamResourceDiscoveryOutput, error) + ModifyIpamResourceDiscoveryRequest(*ec2.ModifyIpamResourceDiscoveryInput) (*request.Request, *ec2.ModifyIpamResourceDiscoveryOutput) + + ModifyIpamScope(*ec2.ModifyIpamScopeInput) (*ec2.ModifyIpamScopeOutput, error) + ModifyIpamScopeWithContext(aws.Context, *ec2.ModifyIpamScopeInput, ...request.Option) (*ec2.ModifyIpamScopeOutput, error) + ModifyIpamScopeRequest(*ec2.ModifyIpamScopeInput) (*request.Request, *ec2.ModifyIpamScopeOutput) + + ModifyLaunchTemplate(*ec2.ModifyLaunchTemplateInput) (*ec2.ModifyLaunchTemplateOutput, error) + ModifyLaunchTemplateWithContext(aws.Context, *ec2.ModifyLaunchTemplateInput, ...request.Option) (*ec2.ModifyLaunchTemplateOutput, error) + ModifyLaunchTemplateRequest(*ec2.ModifyLaunchTemplateInput) (*request.Request, *ec2.ModifyLaunchTemplateOutput) + + ModifyLocalGatewayRoute(*ec2.ModifyLocalGatewayRouteInput) (*ec2.ModifyLocalGatewayRouteOutput, error) + ModifyLocalGatewayRouteWithContext(aws.Context, *ec2.ModifyLocalGatewayRouteInput, ...request.Option) (*ec2.ModifyLocalGatewayRouteOutput, error) + ModifyLocalGatewayRouteRequest(*ec2.ModifyLocalGatewayRouteInput) (*request.Request, *ec2.ModifyLocalGatewayRouteOutput) + + ModifyManagedPrefixList(*ec2.ModifyManagedPrefixListInput) (*ec2.ModifyManagedPrefixListOutput, error) + ModifyManagedPrefixListWithContext(aws.Context, *ec2.ModifyManagedPrefixListInput, ...request.Option) (*ec2.ModifyManagedPrefixListOutput, error) + ModifyManagedPrefixListRequest(*ec2.ModifyManagedPrefixListInput) (*request.Request, *ec2.ModifyManagedPrefixListOutput) + + ModifyNetworkInterfaceAttribute(*ec2.ModifyNetworkInterfaceAttributeInput) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) + ModifyNetworkInterfaceAttributeWithContext(aws.Context, *ec2.ModifyNetworkInterfaceAttributeInput, ...request.Option) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) + ModifyNetworkInterfaceAttributeRequest(*ec2.ModifyNetworkInterfaceAttributeInput) (*request.Request, *ec2.ModifyNetworkInterfaceAttributeOutput) + + ModifyPrivateDnsNameOptions(*ec2.ModifyPrivateDnsNameOptionsInput) (*ec2.ModifyPrivateDnsNameOptionsOutput, error) + ModifyPrivateDnsNameOptionsWithContext(aws.Context, *ec2.ModifyPrivateDnsNameOptionsInput, ...request.Option) (*ec2.ModifyPrivateDnsNameOptionsOutput, error) + ModifyPrivateDnsNameOptionsRequest(*ec2.ModifyPrivateDnsNameOptionsInput) (*request.Request, *ec2.ModifyPrivateDnsNameOptionsOutput) + + ModifyReservedInstances(*ec2.ModifyReservedInstancesInput) (*ec2.ModifyReservedInstancesOutput, error) + ModifyReservedInstancesWithContext(aws.Context, *ec2.ModifyReservedInstancesInput, ...request.Option) (*ec2.ModifyReservedInstancesOutput, error) + ModifyReservedInstancesRequest(*ec2.ModifyReservedInstancesInput) (*request.Request, *ec2.ModifyReservedInstancesOutput) + + ModifySecurityGroupRules(*ec2.ModifySecurityGroupRulesInput) (*ec2.ModifySecurityGroupRulesOutput, error) + ModifySecurityGroupRulesWithContext(aws.Context, *ec2.ModifySecurityGroupRulesInput, ...request.Option) (*ec2.ModifySecurityGroupRulesOutput, error) + ModifySecurityGroupRulesRequest(*ec2.ModifySecurityGroupRulesInput) (*request.Request, *ec2.ModifySecurityGroupRulesOutput) + + ModifySnapshotAttribute(*ec2.ModifySnapshotAttributeInput) (*ec2.ModifySnapshotAttributeOutput, error) + ModifySnapshotAttributeWithContext(aws.Context, *ec2.ModifySnapshotAttributeInput, ...request.Option) (*ec2.ModifySnapshotAttributeOutput, error) + ModifySnapshotAttributeRequest(*ec2.ModifySnapshotAttributeInput) (*request.Request, *ec2.ModifySnapshotAttributeOutput) + + ModifySnapshotTier(*ec2.ModifySnapshotTierInput) (*ec2.ModifySnapshotTierOutput, error) + ModifySnapshotTierWithContext(aws.Context, *ec2.ModifySnapshotTierInput, ...request.Option) (*ec2.ModifySnapshotTierOutput, error) + ModifySnapshotTierRequest(*ec2.ModifySnapshotTierInput) (*request.Request, *ec2.ModifySnapshotTierOutput) + + ModifySpotFleetRequest(*ec2.ModifySpotFleetRequestInput) (*ec2.ModifySpotFleetRequestOutput, error) + ModifySpotFleetRequestWithContext(aws.Context, *ec2.ModifySpotFleetRequestInput, ...request.Option) (*ec2.ModifySpotFleetRequestOutput, error) + ModifySpotFleetRequestRequest(*ec2.ModifySpotFleetRequestInput) (*request.Request, *ec2.ModifySpotFleetRequestOutput) + + ModifySubnetAttribute(*ec2.ModifySubnetAttributeInput) (*ec2.ModifySubnetAttributeOutput, error) + ModifySubnetAttributeWithContext(aws.Context, *ec2.ModifySubnetAttributeInput, ...request.Option) (*ec2.ModifySubnetAttributeOutput, error) + ModifySubnetAttributeRequest(*ec2.ModifySubnetAttributeInput) (*request.Request, *ec2.ModifySubnetAttributeOutput) + + ModifyTrafficMirrorFilterNetworkServices(*ec2.ModifyTrafficMirrorFilterNetworkServicesInput) (*ec2.ModifyTrafficMirrorFilterNetworkServicesOutput, error) + ModifyTrafficMirrorFilterNetworkServicesWithContext(aws.Context, *ec2.ModifyTrafficMirrorFilterNetworkServicesInput, ...request.Option) (*ec2.ModifyTrafficMirrorFilterNetworkServicesOutput, error) + ModifyTrafficMirrorFilterNetworkServicesRequest(*ec2.ModifyTrafficMirrorFilterNetworkServicesInput) (*request.Request, *ec2.ModifyTrafficMirrorFilterNetworkServicesOutput) + + ModifyTrafficMirrorFilterRule(*ec2.ModifyTrafficMirrorFilterRuleInput) (*ec2.ModifyTrafficMirrorFilterRuleOutput, error) + ModifyTrafficMirrorFilterRuleWithContext(aws.Context, *ec2.ModifyTrafficMirrorFilterRuleInput, ...request.Option) (*ec2.ModifyTrafficMirrorFilterRuleOutput, error) + ModifyTrafficMirrorFilterRuleRequest(*ec2.ModifyTrafficMirrorFilterRuleInput) (*request.Request, *ec2.ModifyTrafficMirrorFilterRuleOutput) + + ModifyTrafficMirrorSession(*ec2.ModifyTrafficMirrorSessionInput) (*ec2.ModifyTrafficMirrorSessionOutput, error) + ModifyTrafficMirrorSessionWithContext(aws.Context, *ec2.ModifyTrafficMirrorSessionInput, ...request.Option) (*ec2.ModifyTrafficMirrorSessionOutput, error) + ModifyTrafficMirrorSessionRequest(*ec2.ModifyTrafficMirrorSessionInput) (*request.Request, *ec2.ModifyTrafficMirrorSessionOutput) + + ModifyTransitGateway(*ec2.ModifyTransitGatewayInput) (*ec2.ModifyTransitGatewayOutput, error) + ModifyTransitGatewayWithContext(aws.Context, *ec2.ModifyTransitGatewayInput, ...request.Option) (*ec2.ModifyTransitGatewayOutput, error) + ModifyTransitGatewayRequest(*ec2.ModifyTransitGatewayInput) (*request.Request, *ec2.ModifyTransitGatewayOutput) + + ModifyTransitGatewayPrefixListReference(*ec2.ModifyTransitGatewayPrefixListReferenceInput) (*ec2.ModifyTransitGatewayPrefixListReferenceOutput, error) + ModifyTransitGatewayPrefixListReferenceWithContext(aws.Context, *ec2.ModifyTransitGatewayPrefixListReferenceInput, ...request.Option) (*ec2.ModifyTransitGatewayPrefixListReferenceOutput, error) + ModifyTransitGatewayPrefixListReferenceRequest(*ec2.ModifyTransitGatewayPrefixListReferenceInput) (*request.Request, *ec2.ModifyTransitGatewayPrefixListReferenceOutput) + + ModifyTransitGatewayVpcAttachment(*ec2.ModifyTransitGatewayVpcAttachmentInput) (*ec2.ModifyTransitGatewayVpcAttachmentOutput, error) + ModifyTransitGatewayVpcAttachmentWithContext(aws.Context, *ec2.ModifyTransitGatewayVpcAttachmentInput, ...request.Option) (*ec2.ModifyTransitGatewayVpcAttachmentOutput, error) + ModifyTransitGatewayVpcAttachmentRequest(*ec2.ModifyTransitGatewayVpcAttachmentInput) (*request.Request, *ec2.ModifyTransitGatewayVpcAttachmentOutput) + + ModifyVerifiedAccessEndpoint(*ec2.ModifyVerifiedAccessEndpointInput) (*ec2.ModifyVerifiedAccessEndpointOutput, error) + ModifyVerifiedAccessEndpointWithContext(aws.Context, *ec2.ModifyVerifiedAccessEndpointInput, ...request.Option) (*ec2.ModifyVerifiedAccessEndpointOutput, error) + ModifyVerifiedAccessEndpointRequest(*ec2.ModifyVerifiedAccessEndpointInput) (*request.Request, *ec2.ModifyVerifiedAccessEndpointOutput) + + ModifyVerifiedAccessEndpointPolicy(*ec2.ModifyVerifiedAccessEndpointPolicyInput) (*ec2.ModifyVerifiedAccessEndpointPolicyOutput, error) + ModifyVerifiedAccessEndpointPolicyWithContext(aws.Context, *ec2.ModifyVerifiedAccessEndpointPolicyInput, ...request.Option) (*ec2.ModifyVerifiedAccessEndpointPolicyOutput, error) + ModifyVerifiedAccessEndpointPolicyRequest(*ec2.ModifyVerifiedAccessEndpointPolicyInput) (*request.Request, *ec2.ModifyVerifiedAccessEndpointPolicyOutput) + + ModifyVerifiedAccessGroup(*ec2.ModifyVerifiedAccessGroupInput) (*ec2.ModifyVerifiedAccessGroupOutput, error) + ModifyVerifiedAccessGroupWithContext(aws.Context, *ec2.ModifyVerifiedAccessGroupInput, ...request.Option) (*ec2.ModifyVerifiedAccessGroupOutput, error) + ModifyVerifiedAccessGroupRequest(*ec2.ModifyVerifiedAccessGroupInput) (*request.Request, *ec2.ModifyVerifiedAccessGroupOutput) + + ModifyVerifiedAccessGroupPolicy(*ec2.ModifyVerifiedAccessGroupPolicyInput) (*ec2.ModifyVerifiedAccessGroupPolicyOutput, error) + ModifyVerifiedAccessGroupPolicyWithContext(aws.Context, *ec2.ModifyVerifiedAccessGroupPolicyInput, ...request.Option) (*ec2.ModifyVerifiedAccessGroupPolicyOutput, error) + ModifyVerifiedAccessGroupPolicyRequest(*ec2.ModifyVerifiedAccessGroupPolicyInput) (*request.Request, *ec2.ModifyVerifiedAccessGroupPolicyOutput) + + ModifyVerifiedAccessInstance(*ec2.ModifyVerifiedAccessInstanceInput) (*ec2.ModifyVerifiedAccessInstanceOutput, error) + ModifyVerifiedAccessInstanceWithContext(aws.Context, *ec2.ModifyVerifiedAccessInstanceInput, ...request.Option) (*ec2.ModifyVerifiedAccessInstanceOutput, error) + ModifyVerifiedAccessInstanceRequest(*ec2.ModifyVerifiedAccessInstanceInput) (*request.Request, *ec2.ModifyVerifiedAccessInstanceOutput) + + ModifyVerifiedAccessInstanceLoggingConfiguration(*ec2.ModifyVerifiedAccessInstanceLoggingConfigurationInput) (*ec2.ModifyVerifiedAccessInstanceLoggingConfigurationOutput, error) + ModifyVerifiedAccessInstanceLoggingConfigurationWithContext(aws.Context, *ec2.ModifyVerifiedAccessInstanceLoggingConfigurationInput, ...request.Option) (*ec2.ModifyVerifiedAccessInstanceLoggingConfigurationOutput, error) + ModifyVerifiedAccessInstanceLoggingConfigurationRequest(*ec2.ModifyVerifiedAccessInstanceLoggingConfigurationInput) (*request.Request, *ec2.ModifyVerifiedAccessInstanceLoggingConfigurationOutput) + + ModifyVerifiedAccessTrustProvider(*ec2.ModifyVerifiedAccessTrustProviderInput) (*ec2.ModifyVerifiedAccessTrustProviderOutput, error) + ModifyVerifiedAccessTrustProviderWithContext(aws.Context, *ec2.ModifyVerifiedAccessTrustProviderInput, ...request.Option) (*ec2.ModifyVerifiedAccessTrustProviderOutput, error) + ModifyVerifiedAccessTrustProviderRequest(*ec2.ModifyVerifiedAccessTrustProviderInput) (*request.Request, *ec2.ModifyVerifiedAccessTrustProviderOutput) + + ModifyVolume(*ec2.ModifyVolumeInput) (*ec2.ModifyVolumeOutput, error) + ModifyVolumeWithContext(aws.Context, *ec2.ModifyVolumeInput, ...request.Option) (*ec2.ModifyVolumeOutput, error) + ModifyVolumeRequest(*ec2.ModifyVolumeInput) (*request.Request, *ec2.ModifyVolumeOutput) + + ModifyVolumeAttribute(*ec2.ModifyVolumeAttributeInput) (*ec2.ModifyVolumeAttributeOutput, error) + ModifyVolumeAttributeWithContext(aws.Context, *ec2.ModifyVolumeAttributeInput, ...request.Option) (*ec2.ModifyVolumeAttributeOutput, error) + ModifyVolumeAttributeRequest(*ec2.ModifyVolumeAttributeInput) (*request.Request, *ec2.ModifyVolumeAttributeOutput) + + ModifyVpcAttribute(*ec2.ModifyVpcAttributeInput) (*ec2.ModifyVpcAttributeOutput, error) + ModifyVpcAttributeWithContext(aws.Context, *ec2.ModifyVpcAttributeInput, ...request.Option) (*ec2.ModifyVpcAttributeOutput, error) + ModifyVpcAttributeRequest(*ec2.ModifyVpcAttributeInput) (*request.Request, *ec2.ModifyVpcAttributeOutput) + + ModifyVpcEndpoint(*ec2.ModifyVpcEndpointInput) (*ec2.ModifyVpcEndpointOutput, error) + ModifyVpcEndpointWithContext(aws.Context, *ec2.ModifyVpcEndpointInput, ...request.Option) (*ec2.ModifyVpcEndpointOutput, error) + ModifyVpcEndpointRequest(*ec2.ModifyVpcEndpointInput) (*request.Request, *ec2.ModifyVpcEndpointOutput) + + ModifyVpcEndpointConnectionNotification(*ec2.ModifyVpcEndpointConnectionNotificationInput) (*ec2.ModifyVpcEndpointConnectionNotificationOutput, error) + ModifyVpcEndpointConnectionNotificationWithContext(aws.Context, *ec2.ModifyVpcEndpointConnectionNotificationInput, ...request.Option) (*ec2.ModifyVpcEndpointConnectionNotificationOutput, error) + ModifyVpcEndpointConnectionNotificationRequest(*ec2.ModifyVpcEndpointConnectionNotificationInput) (*request.Request, *ec2.ModifyVpcEndpointConnectionNotificationOutput) + + ModifyVpcEndpointServiceConfiguration(*ec2.ModifyVpcEndpointServiceConfigurationInput) (*ec2.ModifyVpcEndpointServiceConfigurationOutput, error) + ModifyVpcEndpointServiceConfigurationWithContext(aws.Context, *ec2.ModifyVpcEndpointServiceConfigurationInput, ...request.Option) (*ec2.ModifyVpcEndpointServiceConfigurationOutput, error) + ModifyVpcEndpointServiceConfigurationRequest(*ec2.ModifyVpcEndpointServiceConfigurationInput) (*request.Request, *ec2.ModifyVpcEndpointServiceConfigurationOutput) + + ModifyVpcEndpointServicePayerResponsibility(*ec2.ModifyVpcEndpointServicePayerResponsibilityInput) (*ec2.ModifyVpcEndpointServicePayerResponsibilityOutput, error) + ModifyVpcEndpointServicePayerResponsibilityWithContext(aws.Context, *ec2.ModifyVpcEndpointServicePayerResponsibilityInput, ...request.Option) (*ec2.ModifyVpcEndpointServicePayerResponsibilityOutput, error) + ModifyVpcEndpointServicePayerResponsibilityRequest(*ec2.ModifyVpcEndpointServicePayerResponsibilityInput) (*request.Request, *ec2.ModifyVpcEndpointServicePayerResponsibilityOutput) + + ModifyVpcEndpointServicePermissions(*ec2.ModifyVpcEndpointServicePermissionsInput) (*ec2.ModifyVpcEndpointServicePermissionsOutput, error) + ModifyVpcEndpointServicePermissionsWithContext(aws.Context, *ec2.ModifyVpcEndpointServicePermissionsInput, ...request.Option) (*ec2.ModifyVpcEndpointServicePermissionsOutput, error) + ModifyVpcEndpointServicePermissionsRequest(*ec2.ModifyVpcEndpointServicePermissionsInput) (*request.Request, *ec2.ModifyVpcEndpointServicePermissionsOutput) + + ModifyVpcPeeringConnectionOptions(*ec2.ModifyVpcPeeringConnectionOptionsInput) (*ec2.ModifyVpcPeeringConnectionOptionsOutput, error) + ModifyVpcPeeringConnectionOptionsWithContext(aws.Context, *ec2.ModifyVpcPeeringConnectionOptionsInput, ...request.Option) (*ec2.ModifyVpcPeeringConnectionOptionsOutput, error) + ModifyVpcPeeringConnectionOptionsRequest(*ec2.ModifyVpcPeeringConnectionOptionsInput) (*request.Request, *ec2.ModifyVpcPeeringConnectionOptionsOutput) + + ModifyVpcTenancy(*ec2.ModifyVpcTenancyInput) (*ec2.ModifyVpcTenancyOutput, error) + ModifyVpcTenancyWithContext(aws.Context, *ec2.ModifyVpcTenancyInput, ...request.Option) (*ec2.ModifyVpcTenancyOutput, error) + ModifyVpcTenancyRequest(*ec2.ModifyVpcTenancyInput) (*request.Request, *ec2.ModifyVpcTenancyOutput) + + ModifyVpnConnection(*ec2.ModifyVpnConnectionInput) (*ec2.ModifyVpnConnectionOutput, error) + ModifyVpnConnectionWithContext(aws.Context, *ec2.ModifyVpnConnectionInput, ...request.Option) (*ec2.ModifyVpnConnectionOutput, error) + ModifyVpnConnectionRequest(*ec2.ModifyVpnConnectionInput) (*request.Request, *ec2.ModifyVpnConnectionOutput) + + ModifyVpnConnectionOptions(*ec2.ModifyVpnConnectionOptionsInput) (*ec2.ModifyVpnConnectionOptionsOutput, error) + ModifyVpnConnectionOptionsWithContext(aws.Context, *ec2.ModifyVpnConnectionOptionsInput, ...request.Option) (*ec2.ModifyVpnConnectionOptionsOutput, error) + ModifyVpnConnectionOptionsRequest(*ec2.ModifyVpnConnectionOptionsInput) (*request.Request, *ec2.ModifyVpnConnectionOptionsOutput) + + ModifyVpnTunnelCertificate(*ec2.ModifyVpnTunnelCertificateInput) (*ec2.ModifyVpnTunnelCertificateOutput, error) + ModifyVpnTunnelCertificateWithContext(aws.Context, *ec2.ModifyVpnTunnelCertificateInput, ...request.Option) (*ec2.ModifyVpnTunnelCertificateOutput, error) + ModifyVpnTunnelCertificateRequest(*ec2.ModifyVpnTunnelCertificateInput) (*request.Request, *ec2.ModifyVpnTunnelCertificateOutput) + + ModifyVpnTunnelOptions(*ec2.ModifyVpnTunnelOptionsInput) (*ec2.ModifyVpnTunnelOptionsOutput, error) + ModifyVpnTunnelOptionsWithContext(aws.Context, *ec2.ModifyVpnTunnelOptionsInput, ...request.Option) (*ec2.ModifyVpnTunnelOptionsOutput, error) + ModifyVpnTunnelOptionsRequest(*ec2.ModifyVpnTunnelOptionsInput) (*request.Request, *ec2.ModifyVpnTunnelOptionsOutput) + + MonitorInstances(*ec2.MonitorInstancesInput) (*ec2.MonitorInstancesOutput, error) + MonitorInstancesWithContext(aws.Context, *ec2.MonitorInstancesInput, ...request.Option) (*ec2.MonitorInstancesOutput, error) + MonitorInstancesRequest(*ec2.MonitorInstancesInput) (*request.Request, *ec2.MonitorInstancesOutput) + + MoveAddressToVpc(*ec2.MoveAddressToVpcInput) (*ec2.MoveAddressToVpcOutput, error) + MoveAddressToVpcWithContext(aws.Context, *ec2.MoveAddressToVpcInput, ...request.Option) (*ec2.MoveAddressToVpcOutput, error) + MoveAddressToVpcRequest(*ec2.MoveAddressToVpcInput) (*request.Request, *ec2.MoveAddressToVpcOutput) + + MoveByoipCidrToIpam(*ec2.MoveByoipCidrToIpamInput) (*ec2.MoveByoipCidrToIpamOutput, error) + MoveByoipCidrToIpamWithContext(aws.Context, *ec2.MoveByoipCidrToIpamInput, ...request.Option) (*ec2.MoveByoipCidrToIpamOutput, error) + MoveByoipCidrToIpamRequest(*ec2.MoveByoipCidrToIpamInput) (*request.Request, *ec2.MoveByoipCidrToIpamOutput) + + ProvisionByoipCidr(*ec2.ProvisionByoipCidrInput) (*ec2.ProvisionByoipCidrOutput, error) + ProvisionByoipCidrWithContext(aws.Context, *ec2.ProvisionByoipCidrInput, ...request.Option) (*ec2.ProvisionByoipCidrOutput, error) + ProvisionByoipCidrRequest(*ec2.ProvisionByoipCidrInput) (*request.Request, *ec2.ProvisionByoipCidrOutput) + + ProvisionIpamPoolCidr(*ec2.ProvisionIpamPoolCidrInput) (*ec2.ProvisionIpamPoolCidrOutput, error) + ProvisionIpamPoolCidrWithContext(aws.Context, *ec2.ProvisionIpamPoolCidrInput, ...request.Option) (*ec2.ProvisionIpamPoolCidrOutput, error) + ProvisionIpamPoolCidrRequest(*ec2.ProvisionIpamPoolCidrInput) (*request.Request, *ec2.ProvisionIpamPoolCidrOutput) + + ProvisionPublicIpv4PoolCidr(*ec2.ProvisionPublicIpv4PoolCidrInput) (*ec2.ProvisionPublicIpv4PoolCidrOutput, error) + ProvisionPublicIpv4PoolCidrWithContext(aws.Context, *ec2.ProvisionPublicIpv4PoolCidrInput, ...request.Option) (*ec2.ProvisionPublicIpv4PoolCidrOutput, error) + ProvisionPublicIpv4PoolCidrRequest(*ec2.ProvisionPublicIpv4PoolCidrInput) (*request.Request, *ec2.ProvisionPublicIpv4PoolCidrOutput) + + PurchaseHostReservation(*ec2.PurchaseHostReservationInput) (*ec2.PurchaseHostReservationOutput, error) + PurchaseHostReservationWithContext(aws.Context, *ec2.PurchaseHostReservationInput, ...request.Option) (*ec2.PurchaseHostReservationOutput, error) + PurchaseHostReservationRequest(*ec2.PurchaseHostReservationInput) (*request.Request, *ec2.PurchaseHostReservationOutput) + + PurchaseReservedInstancesOffering(*ec2.PurchaseReservedInstancesOfferingInput) (*ec2.PurchaseReservedInstancesOfferingOutput, error) + PurchaseReservedInstancesOfferingWithContext(aws.Context, *ec2.PurchaseReservedInstancesOfferingInput, ...request.Option) (*ec2.PurchaseReservedInstancesOfferingOutput, error) + PurchaseReservedInstancesOfferingRequest(*ec2.PurchaseReservedInstancesOfferingInput) (*request.Request, *ec2.PurchaseReservedInstancesOfferingOutput) + + PurchaseScheduledInstances(*ec2.PurchaseScheduledInstancesInput) (*ec2.PurchaseScheduledInstancesOutput, error) + PurchaseScheduledInstancesWithContext(aws.Context, *ec2.PurchaseScheduledInstancesInput, ...request.Option) (*ec2.PurchaseScheduledInstancesOutput, error) + PurchaseScheduledInstancesRequest(*ec2.PurchaseScheduledInstancesInput) (*request.Request, *ec2.PurchaseScheduledInstancesOutput) + + RebootInstances(*ec2.RebootInstancesInput) (*ec2.RebootInstancesOutput, error) + RebootInstancesWithContext(aws.Context, *ec2.RebootInstancesInput, ...request.Option) (*ec2.RebootInstancesOutput, error) + RebootInstancesRequest(*ec2.RebootInstancesInput) (*request.Request, *ec2.RebootInstancesOutput) + + RegisterImage(*ec2.RegisterImageInput) (*ec2.RegisterImageOutput, error) + RegisterImageWithContext(aws.Context, *ec2.RegisterImageInput, ...request.Option) (*ec2.RegisterImageOutput, error) + RegisterImageRequest(*ec2.RegisterImageInput) (*request.Request, *ec2.RegisterImageOutput) + + RegisterInstanceEventNotificationAttributes(*ec2.RegisterInstanceEventNotificationAttributesInput) (*ec2.RegisterInstanceEventNotificationAttributesOutput, error) + RegisterInstanceEventNotificationAttributesWithContext(aws.Context, *ec2.RegisterInstanceEventNotificationAttributesInput, ...request.Option) (*ec2.RegisterInstanceEventNotificationAttributesOutput, error) + RegisterInstanceEventNotificationAttributesRequest(*ec2.RegisterInstanceEventNotificationAttributesInput) (*request.Request, *ec2.RegisterInstanceEventNotificationAttributesOutput) + + RegisterTransitGatewayMulticastGroupMembers(*ec2.RegisterTransitGatewayMulticastGroupMembersInput) (*ec2.RegisterTransitGatewayMulticastGroupMembersOutput, error) + RegisterTransitGatewayMulticastGroupMembersWithContext(aws.Context, *ec2.RegisterTransitGatewayMulticastGroupMembersInput, ...request.Option) (*ec2.RegisterTransitGatewayMulticastGroupMembersOutput, error) + RegisterTransitGatewayMulticastGroupMembersRequest(*ec2.RegisterTransitGatewayMulticastGroupMembersInput) (*request.Request, *ec2.RegisterTransitGatewayMulticastGroupMembersOutput) + + RegisterTransitGatewayMulticastGroupSources(*ec2.RegisterTransitGatewayMulticastGroupSourcesInput) (*ec2.RegisterTransitGatewayMulticastGroupSourcesOutput, error) + RegisterTransitGatewayMulticastGroupSourcesWithContext(aws.Context, *ec2.RegisterTransitGatewayMulticastGroupSourcesInput, ...request.Option) (*ec2.RegisterTransitGatewayMulticastGroupSourcesOutput, error) + RegisterTransitGatewayMulticastGroupSourcesRequest(*ec2.RegisterTransitGatewayMulticastGroupSourcesInput) (*request.Request, *ec2.RegisterTransitGatewayMulticastGroupSourcesOutput) + + RejectTransitGatewayMulticastDomainAssociations(*ec2.RejectTransitGatewayMulticastDomainAssociationsInput) (*ec2.RejectTransitGatewayMulticastDomainAssociationsOutput, error) + RejectTransitGatewayMulticastDomainAssociationsWithContext(aws.Context, *ec2.RejectTransitGatewayMulticastDomainAssociationsInput, ...request.Option) (*ec2.RejectTransitGatewayMulticastDomainAssociationsOutput, error) + RejectTransitGatewayMulticastDomainAssociationsRequest(*ec2.RejectTransitGatewayMulticastDomainAssociationsInput) (*request.Request, *ec2.RejectTransitGatewayMulticastDomainAssociationsOutput) + + RejectTransitGatewayPeeringAttachment(*ec2.RejectTransitGatewayPeeringAttachmentInput) (*ec2.RejectTransitGatewayPeeringAttachmentOutput, error) + RejectTransitGatewayPeeringAttachmentWithContext(aws.Context, *ec2.RejectTransitGatewayPeeringAttachmentInput, ...request.Option) (*ec2.RejectTransitGatewayPeeringAttachmentOutput, error) + RejectTransitGatewayPeeringAttachmentRequest(*ec2.RejectTransitGatewayPeeringAttachmentInput) (*request.Request, *ec2.RejectTransitGatewayPeeringAttachmentOutput) + + RejectTransitGatewayVpcAttachment(*ec2.RejectTransitGatewayVpcAttachmentInput) (*ec2.RejectTransitGatewayVpcAttachmentOutput, error) + RejectTransitGatewayVpcAttachmentWithContext(aws.Context, *ec2.RejectTransitGatewayVpcAttachmentInput, ...request.Option) (*ec2.RejectTransitGatewayVpcAttachmentOutput, error) + RejectTransitGatewayVpcAttachmentRequest(*ec2.RejectTransitGatewayVpcAttachmentInput) (*request.Request, *ec2.RejectTransitGatewayVpcAttachmentOutput) + + RejectVpcEndpointConnections(*ec2.RejectVpcEndpointConnectionsInput) (*ec2.RejectVpcEndpointConnectionsOutput, error) + RejectVpcEndpointConnectionsWithContext(aws.Context, *ec2.RejectVpcEndpointConnectionsInput, ...request.Option) (*ec2.RejectVpcEndpointConnectionsOutput, error) + RejectVpcEndpointConnectionsRequest(*ec2.RejectVpcEndpointConnectionsInput) (*request.Request, *ec2.RejectVpcEndpointConnectionsOutput) + + RejectVpcPeeringConnection(*ec2.RejectVpcPeeringConnectionInput) (*ec2.RejectVpcPeeringConnectionOutput, error) + RejectVpcPeeringConnectionWithContext(aws.Context, *ec2.RejectVpcPeeringConnectionInput, ...request.Option) (*ec2.RejectVpcPeeringConnectionOutput, error) + RejectVpcPeeringConnectionRequest(*ec2.RejectVpcPeeringConnectionInput) (*request.Request, *ec2.RejectVpcPeeringConnectionOutput) + + ReleaseAddress(*ec2.ReleaseAddressInput) (*ec2.ReleaseAddressOutput, error) + ReleaseAddressWithContext(aws.Context, *ec2.ReleaseAddressInput, ...request.Option) (*ec2.ReleaseAddressOutput, error) + ReleaseAddressRequest(*ec2.ReleaseAddressInput) (*request.Request, *ec2.ReleaseAddressOutput) + + ReleaseHosts(*ec2.ReleaseHostsInput) (*ec2.ReleaseHostsOutput, error) + ReleaseHostsWithContext(aws.Context, *ec2.ReleaseHostsInput, ...request.Option) (*ec2.ReleaseHostsOutput, error) + ReleaseHostsRequest(*ec2.ReleaseHostsInput) (*request.Request, *ec2.ReleaseHostsOutput) + + ReleaseIpamPoolAllocation(*ec2.ReleaseIpamPoolAllocationInput) (*ec2.ReleaseIpamPoolAllocationOutput, error) + ReleaseIpamPoolAllocationWithContext(aws.Context, *ec2.ReleaseIpamPoolAllocationInput, ...request.Option) (*ec2.ReleaseIpamPoolAllocationOutput, error) + ReleaseIpamPoolAllocationRequest(*ec2.ReleaseIpamPoolAllocationInput) (*request.Request, *ec2.ReleaseIpamPoolAllocationOutput) + + ReplaceIamInstanceProfileAssociation(*ec2.ReplaceIamInstanceProfileAssociationInput) (*ec2.ReplaceIamInstanceProfileAssociationOutput, error) + ReplaceIamInstanceProfileAssociationWithContext(aws.Context, *ec2.ReplaceIamInstanceProfileAssociationInput, ...request.Option) (*ec2.ReplaceIamInstanceProfileAssociationOutput, error) + ReplaceIamInstanceProfileAssociationRequest(*ec2.ReplaceIamInstanceProfileAssociationInput) (*request.Request, *ec2.ReplaceIamInstanceProfileAssociationOutput) + + ReplaceNetworkAclAssociation(*ec2.ReplaceNetworkAclAssociationInput) (*ec2.ReplaceNetworkAclAssociationOutput, error) + ReplaceNetworkAclAssociationWithContext(aws.Context, *ec2.ReplaceNetworkAclAssociationInput, ...request.Option) (*ec2.ReplaceNetworkAclAssociationOutput, error) + ReplaceNetworkAclAssociationRequest(*ec2.ReplaceNetworkAclAssociationInput) (*request.Request, *ec2.ReplaceNetworkAclAssociationOutput) + + ReplaceNetworkAclEntry(*ec2.ReplaceNetworkAclEntryInput) (*ec2.ReplaceNetworkAclEntryOutput, error) + ReplaceNetworkAclEntryWithContext(aws.Context, *ec2.ReplaceNetworkAclEntryInput, ...request.Option) (*ec2.ReplaceNetworkAclEntryOutput, error) + ReplaceNetworkAclEntryRequest(*ec2.ReplaceNetworkAclEntryInput) (*request.Request, *ec2.ReplaceNetworkAclEntryOutput) + + ReplaceRoute(*ec2.ReplaceRouteInput) (*ec2.ReplaceRouteOutput, error) + ReplaceRouteWithContext(aws.Context, *ec2.ReplaceRouteInput, ...request.Option) (*ec2.ReplaceRouteOutput, error) + ReplaceRouteRequest(*ec2.ReplaceRouteInput) (*request.Request, *ec2.ReplaceRouteOutput) + + ReplaceRouteTableAssociation(*ec2.ReplaceRouteTableAssociationInput) (*ec2.ReplaceRouteTableAssociationOutput, error) + ReplaceRouteTableAssociationWithContext(aws.Context, *ec2.ReplaceRouteTableAssociationInput, ...request.Option) (*ec2.ReplaceRouteTableAssociationOutput, error) + ReplaceRouteTableAssociationRequest(*ec2.ReplaceRouteTableAssociationInput) (*request.Request, *ec2.ReplaceRouteTableAssociationOutput) + + ReplaceTransitGatewayRoute(*ec2.ReplaceTransitGatewayRouteInput) (*ec2.ReplaceTransitGatewayRouteOutput, error) + ReplaceTransitGatewayRouteWithContext(aws.Context, *ec2.ReplaceTransitGatewayRouteInput, ...request.Option) (*ec2.ReplaceTransitGatewayRouteOutput, error) + ReplaceTransitGatewayRouteRequest(*ec2.ReplaceTransitGatewayRouteInput) (*request.Request, *ec2.ReplaceTransitGatewayRouteOutput) + + ReplaceVpnTunnel(*ec2.ReplaceVpnTunnelInput) (*ec2.ReplaceVpnTunnelOutput, error) + ReplaceVpnTunnelWithContext(aws.Context, *ec2.ReplaceVpnTunnelInput, ...request.Option) (*ec2.ReplaceVpnTunnelOutput, error) + ReplaceVpnTunnelRequest(*ec2.ReplaceVpnTunnelInput) (*request.Request, *ec2.ReplaceVpnTunnelOutput) + + ReportInstanceStatus(*ec2.ReportInstanceStatusInput) (*ec2.ReportInstanceStatusOutput, error) + ReportInstanceStatusWithContext(aws.Context, *ec2.ReportInstanceStatusInput, ...request.Option) (*ec2.ReportInstanceStatusOutput, error) + ReportInstanceStatusRequest(*ec2.ReportInstanceStatusInput) (*request.Request, *ec2.ReportInstanceStatusOutput) + + RequestSpotFleet(*ec2.RequestSpotFleetInput) (*ec2.RequestSpotFleetOutput, error) + RequestSpotFleetWithContext(aws.Context, *ec2.RequestSpotFleetInput, ...request.Option) (*ec2.RequestSpotFleetOutput, error) + RequestSpotFleetRequest(*ec2.RequestSpotFleetInput) (*request.Request, *ec2.RequestSpotFleetOutput) + + RequestSpotInstances(*ec2.RequestSpotInstancesInput) (*ec2.RequestSpotInstancesOutput, error) + RequestSpotInstancesWithContext(aws.Context, *ec2.RequestSpotInstancesInput, ...request.Option) (*ec2.RequestSpotInstancesOutput, error) + RequestSpotInstancesRequest(*ec2.RequestSpotInstancesInput) (*request.Request, *ec2.RequestSpotInstancesOutput) + + ResetAddressAttribute(*ec2.ResetAddressAttributeInput) (*ec2.ResetAddressAttributeOutput, error) + ResetAddressAttributeWithContext(aws.Context, *ec2.ResetAddressAttributeInput, ...request.Option) (*ec2.ResetAddressAttributeOutput, error) + ResetAddressAttributeRequest(*ec2.ResetAddressAttributeInput) (*request.Request, *ec2.ResetAddressAttributeOutput) + + ResetEbsDefaultKmsKeyId(*ec2.ResetEbsDefaultKmsKeyIdInput) (*ec2.ResetEbsDefaultKmsKeyIdOutput, error) + ResetEbsDefaultKmsKeyIdWithContext(aws.Context, *ec2.ResetEbsDefaultKmsKeyIdInput, ...request.Option) (*ec2.ResetEbsDefaultKmsKeyIdOutput, error) + ResetEbsDefaultKmsKeyIdRequest(*ec2.ResetEbsDefaultKmsKeyIdInput) (*request.Request, *ec2.ResetEbsDefaultKmsKeyIdOutput) + + ResetFpgaImageAttribute(*ec2.ResetFpgaImageAttributeInput) (*ec2.ResetFpgaImageAttributeOutput, error) + ResetFpgaImageAttributeWithContext(aws.Context, *ec2.ResetFpgaImageAttributeInput, ...request.Option) (*ec2.ResetFpgaImageAttributeOutput, error) + ResetFpgaImageAttributeRequest(*ec2.ResetFpgaImageAttributeInput) (*request.Request, *ec2.ResetFpgaImageAttributeOutput) + + ResetImageAttribute(*ec2.ResetImageAttributeInput) (*ec2.ResetImageAttributeOutput, error) + ResetImageAttributeWithContext(aws.Context, *ec2.ResetImageAttributeInput, ...request.Option) (*ec2.ResetImageAttributeOutput, error) + ResetImageAttributeRequest(*ec2.ResetImageAttributeInput) (*request.Request, *ec2.ResetImageAttributeOutput) + + ResetInstanceAttribute(*ec2.ResetInstanceAttributeInput) (*ec2.ResetInstanceAttributeOutput, error) + ResetInstanceAttributeWithContext(aws.Context, *ec2.ResetInstanceAttributeInput, ...request.Option) (*ec2.ResetInstanceAttributeOutput, error) + ResetInstanceAttributeRequest(*ec2.ResetInstanceAttributeInput) (*request.Request, *ec2.ResetInstanceAttributeOutput) + + ResetNetworkInterfaceAttribute(*ec2.ResetNetworkInterfaceAttributeInput) (*ec2.ResetNetworkInterfaceAttributeOutput, error) + ResetNetworkInterfaceAttributeWithContext(aws.Context, *ec2.ResetNetworkInterfaceAttributeInput, ...request.Option) (*ec2.ResetNetworkInterfaceAttributeOutput, error) + ResetNetworkInterfaceAttributeRequest(*ec2.ResetNetworkInterfaceAttributeInput) (*request.Request, *ec2.ResetNetworkInterfaceAttributeOutput) + + ResetSnapshotAttribute(*ec2.ResetSnapshotAttributeInput) (*ec2.ResetSnapshotAttributeOutput, error) + ResetSnapshotAttributeWithContext(aws.Context, *ec2.ResetSnapshotAttributeInput, ...request.Option) (*ec2.ResetSnapshotAttributeOutput, error) + ResetSnapshotAttributeRequest(*ec2.ResetSnapshotAttributeInput) (*request.Request, *ec2.ResetSnapshotAttributeOutput) + + RestoreAddressToClassic(*ec2.RestoreAddressToClassicInput) (*ec2.RestoreAddressToClassicOutput, error) + RestoreAddressToClassicWithContext(aws.Context, *ec2.RestoreAddressToClassicInput, ...request.Option) (*ec2.RestoreAddressToClassicOutput, error) + RestoreAddressToClassicRequest(*ec2.RestoreAddressToClassicInput) (*request.Request, *ec2.RestoreAddressToClassicOutput) + + RestoreImageFromRecycleBin(*ec2.RestoreImageFromRecycleBinInput) (*ec2.RestoreImageFromRecycleBinOutput, error) + RestoreImageFromRecycleBinWithContext(aws.Context, *ec2.RestoreImageFromRecycleBinInput, ...request.Option) (*ec2.RestoreImageFromRecycleBinOutput, error) + RestoreImageFromRecycleBinRequest(*ec2.RestoreImageFromRecycleBinInput) (*request.Request, *ec2.RestoreImageFromRecycleBinOutput) + + RestoreManagedPrefixListVersion(*ec2.RestoreManagedPrefixListVersionInput) (*ec2.RestoreManagedPrefixListVersionOutput, error) + RestoreManagedPrefixListVersionWithContext(aws.Context, *ec2.RestoreManagedPrefixListVersionInput, ...request.Option) (*ec2.RestoreManagedPrefixListVersionOutput, error) + RestoreManagedPrefixListVersionRequest(*ec2.RestoreManagedPrefixListVersionInput) (*request.Request, *ec2.RestoreManagedPrefixListVersionOutput) + + RestoreSnapshotFromRecycleBin(*ec2.RestoreSnapshotFromRecycleBinInput) (*ec2.RestoreSnapshotFromRecycleBinOutput, error) + RestoreSnapshotFromRecycleBinWithContext(aws.Context, *ec2.RestoreSnapshotFromRecycleBinInput, ...request.Option) (*ec2.RestoreSnapshotFromRecycleBinOutput, error) + RestoreSnapshotFromRecycleBinRequest(*ec2.RestoreSnapshotFromRecycleBinInput) (*request.Request, *ec2.RestoreSnapshotFromRecycleBinOutput) + + RestoreSnapshotTier(*ec2.RestoreSnapshotTierInput) (*ec2.RestoreSnapshotTierOutput, error) + RestoreSnapshotTierWithContext(aws.Context, *ec2.RestoreSnapshotTierInput, ...request.Option) (*ec2.RestoreSnapshotTierOutput, error) + RestoreSnapshotTierRequest(*ec2.RestoreSnapshotTierInput) (*request.Request, *ec2.RestoreSnapshotTierOutput) + + RevokeClientVpnIngress(*ec2.RevokeClientVpnIngressInput) (*ec2.RevokeClientVpnIngressOutput, error) + RevokeClientVpnIngressWithContext(aws.Context, *ec2.RevokeClientVpnIngressInput, ...request.Option) (*ec2.RevokeClientVpnIngressOutput, error) + RevokeClientVpnIngressRequest(*ec2.RevokeClientVpnIngressInput) (*request.Request, *ec2.RevokeClientVpnIngressOutput) + + RevokeSecurityGroupEgress(*ec2.RevokeSecurityGroupEgressInput) (*ec2.RevokeSecurityGroupEgressOutput, error) + RevokeSecurityGroupEgressWithContext(aws.Context, *ec2.RevokeSecurityGroupEgressInput, ...request.Option) (*ec2.RevokeSecurityGroupEgressOutput, error) + RevokeSecurityGroupEgressRequest(*ec2.RevokeSecurityGroupEgressInput) (*request.Request, *ec2.RevokeSecurityGroupEgressOutput) + + RevokeSecurityGroupIngress(*ec2.RevokeSecurityGroupIngressInput) (*ec2.RevokeSecurityGroupIngressOutput, error) + RevokeSecurityGroupIngressWithContext(aws.Context, *ec2.RevokeSecurityGroupIngressInput, ...request.Option) (*ec2.RevokeSecurityGroupIngressOutput, error) + RevokeSecurityGroupIngressRequest(*ec2.RevokeSecurityGroupIngressInput) (*request.Request, *ec2.RevokeSecurityGroupIngressOutput) + + RunInstances(*ec2.RunInstancesInput) (*ec2.Reservation, error) + RunInstancesWithContext(aws.Context, *ec2.RunInstancesInput, ...request.Option) (*ec2.Reservation, error) + RunInstancesRequest(*ec2.RunInstancesInput) (*request.Request, *ec2.Reservation) + + RunScheduledInstances(*ec2.RunScheduledInstancesInput) (*ec2.RunScheduledInstancesOutput, error) + RunScheduledInstancesWithContext(aws.Context, *ec2.RunScheduledInstancesInput, ...request.Option) (*ec2.RunScheduledInstancesOutput, error) + RunScheduledInstancesRequest(*ec2.RunScheduledInstancesInput) (*request.Request, *ec2.RunScheduledInstancesOutput) + + SearchLocalGatewayRoutes(*ec2.SearchLocalGatewayRoutesInput) (*ec2.SearchLocalGatewayRoutesOutput, error) + SearchLocalGatewayRoutesWithContext(aws.Context, *ec2.SearchLocalGatewayRoutesInput, ...request.Option) (*ec2.SearchLocalGatewayRoutesOutput, error) + SearchLocalGatewayRoutesRequest(*ec2.SearchLocalGatewayRoutesInput) (*request.Request, *ec2.SearchLocalGatewayRoutesOutput) + + SearchLocalGatewayRoutesPages(*ec2.SearchLocalGatewayRoutesInput, func(*ec2.SearchLocalGatewayRoutesOutput, bool) bool) error + SearchLocalGatewayRoutesPagesWithContext(aws.Context, *ec2.SearchLocalGatewayRoutesInput, func(*ec2.SearchLocalGatewayRoutesOutput, bool) bool, ...request.Option) error + + SearchTransitGatewayMulticastGroups(*ec2.SearchTransitGatewayMulticastGroupsInput) (*ec2.SearchTransitGatewayMulticastGroupsOutput, error) + SearchTransitGatewayMulticastGroupsWithContext(aws.Context, *ec2.SearchTransitGatewayMulticastGroupsInput, ...request.Option) (*ec2.SearchTransitGatewayMulticastGroupsOutput, error) + SearchTransitGatewayMulticastGroupsRequest(*ec2.SearchTransitGatewayMulticastGroupsInput) (*request.Request, *ec2.SearchTransitGatewayMulticastGroupsOutput) + + SearchTransitGatewayMulticastGroupsPages(*ec2.SearchTransitGatewayMulticastGroupsInput, func(*ec2.SearchTransitGatewayMulticastGroupsOutput, bool) bool) error + SearchTransitGatewayMulticastGroupsPagesWithContext(aws.Context, *ec2.SearchTransitGatewayMulticastGroupsInput, func(*ec2.SearchTransitGatewayMulticastGroupsOutput, bool) bool, ...request.Option) error + + SearchTransitGatewayRoutes(*ec2.SearchTransitGatewayRoutesInput) (*ec2.SearchTransitGatewayRoutesOutput, error) + SearchTransitGatewayRoutesWithContext(aws.Context, *ec2.SearchTransitGatewayRoutesInput, ...request.Option) (*ec2.SearchTransitGatewayRoutesOutput, error) + SearchTransitGatewayRoutesRequest(*ec2.SearchTransitGatewayRoutesInput) (*request.Request, *ec2.SearchTransitGatewayRoutesOutput) + + SendDiagnosticInterrupt(*ec2.SendDiagnosticInterruptInput) (*ec2.SendDiagnosticInterruptOutput, error) + SendDiagnosticInterruptWithContext(aws.Context, *ec2.SendDiagnosticInterruptInput, ...request.Option) (*ec2.SendDiagnosticInterruptOutput, error) + SendDiagnosticInterruptRequest(*ec2.SendDiagnosticInterruptInput) (*request.Request, *ec2.SendDiagnosticInterruptOutput) + + StartInstances(*ec2.StartInstancesInput) (*ec2.StartInstancesOutput, error) + StartInstancesWithContext(aws.Context, *ec2.StartInstancesInput, ...request.Option) (*ec2.StartInstancesOutput, error) + StartInstancesRequest(*ec2.StartInstancesInput) (*request.Request, *ec2.StartInstancesOutput) + + StartNetworkInsightsAccessScopeAnalysis(*ec2.StartNetworkInsightsAccessScopeAnalysisInput) (*ec2.StartNetworkInsightsAccessScopeAnalysisOutput, error) + StartNetworkInsightsAccessScopeAnalysisWithContext(aws.Context, *ec2.StartNetworkInsightsAccessScopeAnalysisInput, ...request.Option) (*ec2.StartNetworkInsightsAccessScopeAnalysisOutput, error) + StartNetworkInsightsAccessScopeAnalysisRequest(*ec2.StartNetworkInsightsAccessScopeAnalysisInput) (*request.Request, *ec2.StartNetworkInsightsAccessScopeAnalysisOutput) + + StartNetworkInsightsAnalysis(*ec2.StartNetworkInsightsAnalysisInput) (*ec2.StartNetworkInsightsAnalysisOutput, error) + StartNetworkInsightsAnalysisWithContext(aws.Context, *ec2.StartNetworkInsightsAnalysisInput, ...request.Option) (*ec2.StartNetworkInsightsAnalysisOutput, error) + StartNetworkInsightsAnalysisRequest(*ec2.StartNetworkInsightsAnalysisInput) (*request.Request, *ec2.StartNetworkInsightsAnalysisOutput) + + StartVpcEndpointServicePrivateDnsVerification(*ec2.StartVpcEndpointServicePrivateDnsVerificationInput) (*ec2.StartVpcEndpointServicePrivateDnsVerificationOutput, error) + StartVpcEndpointServicePrivateDnsVerificationWithContext(aws.Context, *ec2.StartVpcEndpointServicePrivateDnsVerificationInput, ...request.Option) (*ec2.StartVpcEndpointServicePrivateDnsVerificationOutput, error) + StartVpcEndpointServicePrivateDnsVerificationRequest(*ec2.StartVpcEndpointServicePrivateDnsVerificationInput) (*request.Request, *ec2.StartVpcEndpointServicePrivateDnsVerificationOutput) + + StopInstances(*ec2.StopInstancesInput) (*ec2.StopInstancesOutput, error) + StopInstancesWithContext(aws.Context, *ec2.StopInstancesInput, ...request.Option) (*ec2.StopInstancesOutput, error) + StopInstancesRequest(*ec2.StopInstancesInput) (*request.Request, *ec2.StopInstancesOutput) + + TerminateClientVpnConnections(*ec2.TerminateClientVpnConnectionsInput) (*ec2.TerminateClientVpnConnectionsOutput, error) + TerminateClientVpnConnectionsWithContext(aws.Context, *ec2.TerminateClientVpnConnectionsInput, ...request.Option) (*ec2.TerminateClientVpnConnectionsOutput, error) + TerminateClientVpnConnectionsRequest(*ec2.TerminateClientVpnConnectionsInput) (*request.Request, *ec2.TerminateClientVpnConnectionsOutput) + + TerminateInstances(*ec2.TerminateInstancesInput) (*ec2.TerminateInstancesOutput, error) + TerminateInstancesWithContext(aws.Context, *ec2.TerminateInstancesInput, ...request.Option) (*ec2.TerminateInstancesOutput, error) + TerminateInstancesRequest(*ec2.TerminateInstancesInput) (*request.Request, *ec2.TerminateInstancesOutput) + + UnassignIpv6Addresses(*ec2.UnassignIpv6AddressesInput) (*ec2.UnassignIpv6AddressesOutput, error) + UnassignIpv6AddressesWithContext(aws.Context, *ec2.UnassignIpv6AddressesInput, ...request.Option) (*ec2.UnassignIpv6AddressesOutput, error) + UnassignIpv6AddressesRequest(*ec2.UnassignIpv6AddressesInput) (*request.Request, *ec2.UnassignIpv6AddressesOutput) + + UnassignPrivateIpAddresses(*ec2.UnassignPrivateIpAddressesInput) (*ec2.UnassignPrivateIpAddressesOutput, error) + UnassignPrivateIpAddressesWithContext(aws.Context, *ec2.UnassignPrivateIpAddressesInput, ...request.Option) (*ec2.UnassignPrivateIpAddressesOutput, error) + UnassignPrivateIpAddressesRequest(*ec2.UnassignPrivateIpAddressesInput) (*request.Request, *ec2.UnassignPrivateIpAddressesOutput) + + UnassignPrivateNatGatewayAddress(*ec2.UnassignPrivateNatGatewayAddressInput) (*ec2.UnassignPrivateNatGatewayAddressOutput, error) + UnassignPrivateNatGatewayAddressWithContext(aws.Context, *ec2.UnassignPrivateNatGatewayAddressInput, ...request.Option) (*ec2.UnassignPrivateNatGatewayAddressOutput, error) + UnassignPrivateNatGatewayAddressRequest(*ec2.UnassignPrivateNatGatewayAddressInput) (*request.Request, *ec2.UnassignPrivateNatGatewayAddressOutput) + + UnmonitorInstances(*ec2.UnmonitorInstancesInput) (*ec2.UnmonitorInstancesOutput, error) + UnmonitorInstancesWithContext(aws.Context, *ec2.UnmonitorInstancesInput, ...request.Option) (*ec2.UnmonitorInstancesOutput, error) + UnmonitorInstancesRequest(*ec2.UnmonitorInstancesInput) (*request.Request, *ec2.UnmonitorInstancesOutput) + + UpdateSecurityGroupRuleDescriptionsEgress(*ec2.UpdateSecurityGroupRuleDescriptionsEgressInput) (*ec2.UpdateSecurityGroupRuleDescriptionsEgressOutput, error) + UpdateSecurityGroupRuleDescriptionsEgressWithContext(aws.Context, *ec2.UpdateSecurityGroupRuleDescriptionsEgressInput, ...request.Option) (*ec2.UpdateSecurityGroupRuleDescriptionsEgressOutput, error) + UpdateSecurityGroupRuleDescriptionsEgressRequest(*ec2.UpdateSecurityGroupRuleDescriptionsEgressInput) (*request.Request, *ec2.UpdateSecurityGroupRuleDescriptionsEgressOutput) + + UpdateSecurityGroupRuleDescriptionsIngress(*ec2.UpdateSecurityGroupRuleDescriptionsIngressInput) (*ec2.UpdateSecurityGroupRuleDescriptionsIngressOutput, error) + UpdateSecurityGroupRuleDescriptionsIngressWithContext(aws.Context, *ec2.UpdateSecurityGroupRuleDescriptionsIngressInput, ...request.Option) (*ec2.UpdateSecurityGroupRuleDescriptionsIngressOutput, error) + UpdateSecurityGroupRuleDescriptionsIngressRequest(*ec2.UpdateSecurityGroupRuleDescriptionsIngressInput) (*request.Request, *ec2.UpdateSecurityGroupRuleDescriptionsIngressOutput) + + WithdrawByoipCidr(*ec2.WithdrawByoipCidrInput) (*ec2.WithdrawByoipCidrOutput, error) + WithdrawByoipCidrWithContext(aws.Context, *ec2.WithdrawByoipCidrInput, ...request.Option) (*ec2.WithdrawByoipCidrOutput, error) + WithdrawByoipCidrRequest(*ec2.WithdrawByoipCidrInput) (*request.Request, *ec2.WithdrawByoipCidrOutput) + + WaitUntilBundleTaskComplete(*ec2.DescribeBundleTasksInput) error + WaitUntilBundleTaskCompleteWithContext(aws.Context, *ec2.DescribeBundleTasksInput, ...request.WaiterOption) error + + WaitUntilConversionTaskCancelled(*ec2.DescribeConversionTasksInput) error + WaitUntilConversionTaskCancelledWithContext(aws.Context, *ec2.DescribeConversionTasksInput, ...request.WaiterOption) error + + WaitUntilConversionTaskCompleted(*ec2.DescribeConversionTasksInput) error + WaitUntilConversionTaskCompletedWithContext(aws.Context, *ec2.DescribeConversionTasksInput, ...request.WaiterOption) error + + WaitUntilConversionTaskDeleted(*ec2.DescribeConversionTasksInput) error + WaitUntilConversionTaskDeletedWithContext(aws.Context, *ec2.DescribeConversionTasksInput, ...request.WaiterOption) error + + WaitUntilCustomerGatewayAvailable(*ec2.DescribeCustomerGatewaysInput) error + WaitUntilCustomerGatewayAvailableWithContext(aws.Context, *ec2.DescribeCustomerGatewaysInput, ...request.WaiterOption) error + + WaitUntilExportTaskCancelled(*ec2.DescribeExportTasksInput) error + WaitUntilExportTaskCancelledWithContext(aws.Context, *ec2.DescribeExportTasksInput, ...request.WaiterOption) error + + WaitUntilExportTaskCompleted(*ec2.DescribeExportTasksInput) error + WaitUntilExportTaskCompletedWithContext(aws.Context, *ec2.DescribeExportTasksInput, ...request.WaiterOption) error + + WaitUntilImageAvailable(*ec2.DescribeImagesInput) error + WaitUntilImageAvailableWithContext(aws.Context, *ec2.DescribeImagesInput, ...request.WaiterOption) error + + WaitUntilImageExists(*ec2.DescribeImagesInput) error + WaitUntilImageExistsWithContext(aws.Context, *ec2.DescribeImagesInput, ...request.WaiterOption) error + + WaitUntilInstanceExists(*ec2.DescribeInstancesInput) error + WaitUntilInstanceExistsWithContext(aws.Context, *ec2.DescribeInstancesInput, ...request.WaiterOption) error + + WaitUntilInstanceRunning(*ec2.DescribeInstancesInput) error + WaitUntilInstanceRunningWithContext(aws.Context, *ec2.DescribeInstancesInput, ...request.WaiterOption) error + + WaitUntilInstanceStatusOk(*ec2.DescribeInstanceStatusInput) error + WaitUntilInstanceStatusOkWithContext(aws.Context, *ec2.DescribeInstanceStatusInput, ...request.WaiterOption) error + + WaitUntilInstanceStopped(*ec2.DescribeInstancesInput) error + WaitUntilInstanceStoppedWithContext(aws.Context, *ec2.DescribeInstancesInput, ...request.WaiterOption) error + + WaitUntilInstanceTerminated(*ec2.DescribeInstancesInput) error + WaitUntilInstanceTerminatedWithContext(aws.Context, *ec2.DescribeInstancesInput, ...request.WaiterOption) error + + WaitUntilInternetGatewayExists(*ec2.DescribeInternetGatewaysInput) error + WaitUntilInternetGatewayExistsWithContext(aws.Context, *ec2.DescribeInternetGatewaysInput, ...request.WaiterOption) error + + WaitUntilKeyPairExists(*ec2.DescribeKeyPairsInput) error + WaitUntilKeyPairExistsWithContext(aws.Context, *ec2.DescribeKeyPairsInput, ...request.WaiterOption) error + + WaitUntilNatGatewayAvailable(*ec2.DescribeNatGatewaysInput) error + WaitUntilNatGatewayAvailableWithContext(aws.Context, *ec2.DescribeNatGatewaysInput, ...request.WaiterOption) error + + WaitUntilNatGatewayDeleted(*ec2.DescribeNatGatewaysInput) error + WaitUntilNatGatewayDeletedWithContext(aws.Context, *ec2.DescribeNatGatewaysInput, ...request.WaiterOption) error + + WaitUntilNetworkInterfaceAvailable(*ec2.DescribeNetworkInterfacesInput) error + WaitUntilNetworkInterfaceAvailableWithContext(aws.Context, *ec2.DescribeNetworkInterfacesInput, ...request.WaiterOption) error + + WaitUntilPasswordDataAvailable(*ec2.GetPasswordDataInput) error + WaitUntilPasswordDataAvailableWithContext(aws.Context, *ec2.GetPasswordDataInput, ...request.WaiterOption) error + + WaitUntilSecurityGroupExists(*ec2.DescribeSecurityGroupsInput) error + WaitUntilSecurityGroupExistsWithContext(aws.Context, *ec2.DescribeSecurityGroupsInput, ...request.WaiterOption) error + + WaitUntilSnapshotCompleted(*ec2.DescribeSnapshotsInput) error + WaitUntilSnapshotCompletedWithContext(aws.Context, *ec2.DescribeSnapshotsInput, ...request.WaiterOption) error + + WaitUntilSnapshotImported(*ec2.DescribeImportSnapshotTasksInput) error + WaitUntilSnapshotImportedWithContext(aws.Context, *ec2.DescribeImportSnapshotTasksInput, ...request.WaiterOption) error + + WaitUntilSpotInstanceRequestFulfilled(*ec2.DescribeSpotInstanceRequestsInput) error + WaitUntilSpotInstanceRequestFulfilledWithContext(aws.Context, *ec2.DescribeSpotInstanceRequestsInput, ...request.WaiterOption) error + + WaitUntilSubnetAvailable(*ec2.DescribeSubnetsInput) error + WaitUntilSubnetAvailableWithContext(aws.Context, *ec2.DescribeSubnetsInput, ...request.WaiterOption) error + + WaitUntilSystemStatusOk(*ec2.DescribeInstanceStatusInput) error + WaitUntilSystemStatusOkWithContext(aws.Context, *ec2.DescribeInstanceStatusInput, ...request.WaiterOption) error + + WaitUntilVolumeAvailable(*ec2.DescribeVolumesInput) error + WaitUntilVolumeAvailableWithContext(aws.Context, *ec2.DescribeVolumesInput, ...request.WaiterOption) error + + WaitUntilVolumeDeleted(*ec2.DescribeVolumesInput) error + WaitUntilVolumeDeletedWithContext(aws.Context, *ec2.DescribeVolumesInput, ...request.WaiterOption) error + + WaitUntilVolumeInUse(*ec2.DescribeVolumesInput) error + WaitUntilVolumeInUseWithContext(aws.Context, *ec2.DescribeVolumesInput, ...request.WaiterOption) error + + WaitUntilVpcAvailable(*ec2.DescribeVpcsInput) error + WaitUntilVpcAvailableWithContext(aws.Context, *ec2.DescribeVpcsInput, ...request.WaiterOption) error + + WaitUntilVpcExists(*ec2.DescribeVpcsInput) error + WaitUntilVpcExistsWithContext(aws.Context, *ec2.DescribeVpcsInput, ...request.WaiterOption) error + + WaitUntilVpcPeeringConnectionDeleted(*ec2.DescribeVpcPeeringConnectionsInput) error + WaitUntilVpcPeeringConnectionDeletedWithContext(aws.Context, *ec2.DescribeVpcPeeringConnectionsInput, ...request.WaiterOption) error + + WaitUntilVpcPeeringConnectionExists(*ec2.DescribeVpcPeeringConnectionsInput) error + WaitUntilVpcPeeringConnectionExistsWithContext(aws.Context, *ec2.DescribeVpcPeeringConnectionsInput, ...request.WaiterOption) error + + WaitUntilVpnConnectionAvailable(*ec2.DescribeVpnConnectionsInput) error + WaitUntilVpnConnectionAvailableWithContext(aws.Context, *ec2.DescribeVpnConnectionsInput, ...request.WaiterOption) error + + WaitUntilVpnConnectionDeleted(*ec2.DescribeVpnConnectionsInput) error + WaitUntilVpnConnectionDeletedWithContext(aws.Context, *ec2.DescribeVpnConnectionsInput, ...request.WaiterOption) error +} + +var _ EC2API = (*ec2.EC2)(nil) diff --git a/vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface/interface.go b/vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface/interface.go new file mode 100644 index 00000000000..a80cdb1f530 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface/interface.go @@ -0,0 +1,224 @@ +// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. + +// Package elbv2iface provides an interface to enable mocking the Elastic Load Balancing service client +// for testing your code. +// +// It is important to note that this interface will have breaking changes +// when the service model is updated and adds new API operations, paginators, +// and waiters. +package elbv2iface + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/elbv2" +) + +// ELBV2API provides an interface to enable mocking the +// elbv2.ELBV2 service client's API operation, +// paginators, and waiters. This make unit testing your code that calls out +// to the SDK's service client's calls easier. +// +// The best way to use this interface is so the SDK's service client's calls +// can be stubbed out for unit testing your code with the SDK without needing +// to inject custom request handlers into the SDK's request pipeline. +// +// // myFunc uses an SDK service client to make a request to +// // Elastic Load Balancing. +// func myFunc(svc elbv2iface.ELBV2API) bool { +// // Make svc.AddListenerCertificates request +// } +// +// func main() { +// sess := session.New() +// svc := elbv2.New(sess) +// +// myFunc(svc) +// } +// +// In your _test.go file: +// +// // Define a mock struct to be used in your unit tests of myFunc. +// type mockELBV2Client struct { +// elbv2iface.ELBV2API +// } +// func (m *mockELBV2Client) AddListenerCertificates(input *elbv2.AddListenerCertificatesInput) (*elbv2.AddListenerCertificatesOutput, error) { +// // mock response/functionality +// } +// +// func TestMyFunc(t *testing.T) { +// // Setup Test +// mockSvc := &mockELBV2Client{} +// +// myfunc(mockSvc) +// +// // Verify myFunc's functionality +// } +// +// It is important to note that this interface will have breaking changes +// when the service model is updated and adds new API operations, paginators, +// and waiters. Its suggested to use the pattern above for testing, or using +// tooling to generate mocks to satisfy the interfaces. +type ELBV2API interface { + AddListenerCertificates(*elbv2.AddListenerCertificatesInput) (*elbv2.AddListenerCertificatesOutput, error) + AddListenerCertificatesWithContext(aws.Context, *elbv2.AddListenerCertificatesInput, ...request.Option) (*elbv2.AddListenerCertificatesOutput, error) + AddListenerCertificatesRequest(*elbv2.AddListenerCertificatesInput) (*request.Request, *elbv2.AddListenerCertificatesOutput) + + AddTags(*elbv2.AddTagsInput) (*elbv2.AddTagsOutput, error) + AddTagsWithContext(aws.Context, *elbv2.AddTagsInput, ...request.Option) (*elbv2.AddTagsOutput, error) + AddTagsRequest(*elbv2.AddTagsInput) (*request.Request, *elbv2.AddTagsOutput) + + CreateListener(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) + CreateListenerWithContext(aws.Context, *elbv2.CreateListenerInput, ...request.Option) (*elbv2.CreateListenerOutput, error) + CreateListenerRequest(*elbv2.CreateListenerInput) (*request.Request, *elbv2.CreateListenerOutput) + + CreateLoadBalancer(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) + CreateLoadBalancerWithContext(aws.Context, *elbv2.CreateLoadBalancerInput, ...request.Option) (*elbv2.CreateLoadBalancerOutput, error) + CreateLoadBalancerRequest(*elbv2.CreateLoadBalancerInput) (*request.Request, *elbv2.CreateLoadBalancerOutput) + + CreateRule(*elbv2.CreateRuleInput) (*elbv2.CreateRuleOutput, error) + CreateRuleWithContext(aws.Context, *elbv2.CreateRuleInput, ...request.Option) (*elbv2.CreateRuleOutput, error) + CreateRuleRequest(*elbv2.CreateRuleInput) (*request.Request, *elbv2.CreateRuleOutput) + + CreateTargetGroup(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) + CreateTargetGroupWithContext(aws.Context, *elbv2.CreateTargetGroupInput, ...request.Option) (*elbv2.CreateTargetGroupOutput, error) + CreateTargetGroupRequest(*elbv2.CreateTargetGroupInput) (*request.Request, *elbv2.CreateTargetGroupOutput) + + DeleteListener(*elbv2.DeleteListenerInput) (*elbv2.DeleteListenerOutput, error) + DeleteListenerWithContext(aws.Context, *elbv2.DeleteListenerInput, ...request.Option) (*elbv2.DeleteListenerOutput, error) + DeleteListenerRequest(*elbv2.DeleteListenerInput) (*request.Request, *elbv2.DeleteListenerOutput) + + DeleteLoadBalancer(*elbv2.DeleteLoadBalancerInput) (*elbv2.DeleteLoadBalancerOutput, error) + DeleteLoadBalancerWithContext(aws.Context, *elbv2.DeleteLoadBalancerInput, ...request.Option) (*elbv2.DeleteLoadBalancerOutput, error) + DeleteLoadBalancerRequest(*elbv2.DeleteLoadBalancerInput) (*request.Request, *elbv2.DeleteLoadBalancerOutput) + + DeleteRule(*elbv2.DeleteRuleInput) (*elbv2.DeleteRuleOutput, error) + DeleteRuleWithContext(aws.Context, *elbv2.DeleteRuleInput, ...request.Option) (*elbv2.DeleteRuleOutput, error) + DeleteRuleRequest(*elbv2.DeleteRuleInput) (*request.Request, *elbv2.DeleteRuleOutput) + + DeleteTargetGroup(*elbv2.DeleteTargetGroupInput) (*elbv2.DeleteTargetGroupOutput, error) + DeleteTargetGroupWithContext(aws.Context, *elbv2.DeleteTargetGroupInput, ...request.Option) (*elbv2.DeleteTargetGroupOutput, error) + DeleteTargetGroupRequest(*elbv2.DeleteTargetGroupInput) (*request.Request, *elbv2.DeleteTargetGroupOutput) + + DeregisterTargets(*elbv2.DeregisterTargetsInput) (*elbv2.DeregisterTargetsOutput, error) + DeregisterTargetsWithContext(aws.Context, *elbv2.DeregisterTargetsInput, ...request.Option) (*elbv2.DeregisterTargetsOutput, error) + DeregisterTargetsRequest(*elbv2.DeregisterTargetsInput) (*request.Request, *elbv2.DeregisterTargetsOutput) + + DescribeAccountLimits(*elbv2.DescribeAccountLimitsInput) (*elbv2.DescribeAccountLimitsOutput, error) + DescribeAccountLimitsWithContext(aws.Context, *elbv2.DescribeAccountLimitsInput, ...request.Option) (*elbv2.DescribeAccountLimitsOutput, error) + DescribeAccountLimitsRequest(*elbv2.DescribeAccountLimitsInput) (*request.Request, *elbv2.DescribeAccountLimitsOutput) + + DescribeListenerCertificates(*elbv2.DescribeListenerCertificatesInput) (*elbv2.DescribeListenerCertificatesOutput, error) + DescribeListenerCertificatesWithContext(aws.Context, *elbv2.DescribeListenerCertificatesInput, ...request.Option) (*elbv2.DescribeListenerCertificatesOutput, error) + DescribeListenerCertificatesRequest(*elbv2.DescribeListenerCertificatesInput) (*request.Request, *elbv2.DescribeListenerCertificatesOutput) + + DescribeListeners(*elbv2.DescribeListenersInput) (*elbv2.DescribeListenersOutput, error) + DescribeListenersWithContext(aws.Context, *elbv2.DescribeListenersInput, ...request.Option) (*elbv2.DescribeListenersOutput, error) + DescribeListenersRequest(*elbv2.DescribeListenersInput) (*request.Request, *elbv2.DescribeListenersOutput) + + DescribeListenersPages(*elbv2.DescribeListenersInput, func(*elbv2.DescribeListenersOutput, bool) bool) error + DescribeListenersPagesWithContext(aws.Context, *elbv2.DescribeListenersInput, func(*elbv2.DescribeListenersOutput, bool) bool, ...request.Option) error + + DescribeLoadBalancerAttributes(*elbv2.DescribeLoadBalancerAttributesInput) (*elbv2.DescribeLoadBalancerAttributesOutput, error) + DescribeLoadBalancerAttributesWithContext(aws.Context, *elbv2.DescribeLoadBalancerAttributesInput, ...request.Option) (*elbv2.DescribeLoadBalancerAttributesOutput, error) + DescribeLoadBalancerAttributesRequest(*elbv2.DescribeLoadBalancerAttributesInput) (*request.Request, *elbv2.DescribeLoadBalancerAttributesOutput) + + DescribeLoadBalancers(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) + DescribeLoadBalancersWithContext(aws.Context, *elbv2.DescribeLoadBalancersInput, ...request.Option) (*elbv2.DescribeLoadBalancersOutput, error) + DescribeLoadBalancersRequest(*elbv2.DescribeLoadBalancersInput) (*request.Request, *elbv2.DescribeLoadBalancersOutput) + + DescribeLoadBalancersPages(*elbv2.DescribeLoadBalancersInput, func(*elbv2.DescribeLoadBalancersOutput, bool) bool) error + DescribeLoadBalancersPagesWithContext(aws.Context, *elbv2.DescribeLoadBalancersInput, func(*elbv2.DescribeLoadBalancersOutput, bool) bool, ...request.Option) error + + DescribeRules(*elbv2.DescribeRulesInput) (*elbv2.DescribeRulesOutput, error) + DescribeRulesWithContext(aws.Context, *elbv2.DescribeRulesInput, ...request.Option) (*elbv2.DescribeRulesOutput, error) + DescribeRulesRequest(*elbv2.DescribeRulesInput) (*request.Request, *elbv2.DescribeRulesOutput) + + DescribeSSLPolicies(*elbv2.DescribeSSLPoliciesInput) (*elbv2.DescribeSSLPoliciesOutput, error) + DescribeSSLPoliciesWithContext(aws.Context, *elbv2.DescribeSSLPoliciesInput, ...request.Option) (*elbv2.DescribeSSLPoliciesOutput, error) + DescribeSSLPoliciesRequest(*elbv2.DescribeSSLPoliciesInput) (*request.Request, *elbv2.DescribeSSLPoliciesOutput) + + DescribeTags(*elbv2.DescribeTagsInput) (*elbv2.DescribeTagsOutput, error) + DescribeTagsWithContext(aws.Context, *elbv2.DescribeTagsInput, ...request.Option) (*elbv2.DescribeTagsOutput, error) + DescribeTagsRequest(*elbv2.DescribeTagsInput) (*request.Request, *elbv2.DescribeTagsOutput) + + DescribeTargetGroupAttributes(*elbv2.DescribeTargetGroupAttributesInput) (*elbv2.DescribeTargetGroupAttributesOutput, error) + DescribeTargetGroupAttributesWithContext(aws.Context, *elbv2.DescribeTargetGroupAttributesInput, ...request.Option) (*elbv2.DescribeTargetGroupAttributesOutput, error) + DescribeTargetGroupAttributesRequest(*elbv2.DescribeTargetGroupAttributesInput) (*request.Request, *elbv2.DescribeTargetGroupAttributesOutput) + + DescribeTargetGroups(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) + DescribeTargetGroupsWithContext(aws.Context, *elbv2.DescribeTargetGroupsInput, ...request.Option) (*elbv2.DescribeTargetGroupsOutput, error) + DescribeTargetGroupsRequest(*elbv2.DescribeTargetGroupsInput) (*request.Request, *elbv2.DescribeTargetGroupsOutput) + + DescribeTargetGroupsPages(*elbv2.DescribeTargetGroupsInput, func(*elbv2.DescribeTargetGroupsOutput, bool) bool) error + DescribeTargetGroupsPagesWithContext(aws.Context, *elbv2.DescribeTargetGroupsInput, func(*elbv2.DescribeTargetGroupsOutput, bool) bool, ...request.Option) error + + DescribeTargetHealth(*elbv2.DescribeTargetHealthInput) (*elbv2.DescribeTargetHealthOutput, error) + DescribeTargetHealthWithContext(aws.Context, *elbv2.DescribeTargetHealthInput, ...request.Option) (*elbv2.DescribeTargetHealthOutput, error) + DescribeTargetHealthRequest(*elbv2.DescribeTargetHealthInput) (*request.Request, *elbv2.DescribeTargetHealthOutput) + + ModifyListener(*elbv2.ModifyListenerInput) (*elbv2.ModifyListenerOutput, error) + ModifyListenerWithContext(aws.Context, *elbv2.ModifyListenerInput, ...request.Option) (*elbv2.ModifyListenerOutput, error) + ModifyListenerRequest(*elbv2.ModifyListenerInput) (*request.Request, *elbv2.ModifyListenerOutput) + + ModifyLoadBalancerAttributes(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) + ModifyLoadBalancerAttributesWithContext(aws.Context, *elbv2.ModifyLoadBalancerAttributesInput, ...request.Option) (*elbv2.ModifyLoadBalancerAttributesOutput, error) + ModifyLoadBalancerAttributesRequest(*elbv2.ModifyLoadBalancerAttributesInput) (*request.Request, *elbv2.ModifyLoadBalancerAttributesOutput) + + ModifyRule(*elbv2.ModifyRuleInput) (*elbv2.ModifyRuleOutput, error) + ModifyRuleWithContext(aws.Context, *elbv2.ModifyRuleInput, ...request.Option) (*elbv2.ModifyRuleOutput, error) + ModifyRuleRequest(*elbv2.ModifyRuleInput) (*request.Request, *elbv2.ModifyRuleOutput) + + ModifyTargetGroup(*elbv2.ModifyTargetGroupInput) (*elbv2.ModifyTargetGroupOutput, error) + ModifyTargetGroupWithContext(aws.Context, *elbv2.ModifyTargetGroupInput, ...request.Option) (*elbv2.ModifyTargetGroupOutput, error) + ModifyTargetGroupRequest(*elbv2.ModifyTargetGroupInput) (*request.Request, *elbv2.ModifyTargetGroupOutput) + + ModifyTargetGroupAttributes(*elbv2.ModifyTargetGroupAttributesInput) (*elbv2.ModifyTargetGroupAttributesOutput, error) + ModifyTargetGroupAttributesWithContext(aws.Context, *elbv2.ModifyTargetGroupAttributesInput, ...request.Option) (*elbv2.ModifyTargetGroupAttributesOutput, error) + ModifyTargetGroupAttributesRequest(*elbv2.ModifyTargetGroupAttributesInput) (*request.Request, *elbv2.ModifyTargetGroupAttributesOutput) + + RegisterTargets(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) + RegisterTargetsWithContext(aws.Context, *elbv2.RegisterTargetsInput, ...request.Option) (*elbv2.RegisterTargetsOutput, error) + RegisterTargetsRequest(*elbv2.RegisterTargetsInput) (*request.Request, *elbv2.RegisterTargetsOutput) + + RemoveListenerCertificates(*elbv2.RemoveListenerCertificatesInput) (*elbv2.RemoveListenerCertificatesOutput, error) + RemoveListenerCertificatesWithContext(aws.Context, *elbv2.RemoveListenerCertificatesInput, ...request.Option) (*elbv2.RemoveListenerCertificatesOutput, error) + RemoveListenerCertificatesRequest(*elbv2.RemoveListenerCertificatesInput) (*request.Request, *elbv2.RemoveListenerCertificatesOutput) + + RemoveTags(*elbv2.RemoveTagsInput) (*elbv2.RemoveTagsOutput, error) + RemoveTagsWithContext(aws.Context, *elbv2.RemoveTagsInput, ...request.Option) (*elbv2.RemoveTagsOutput, error) + RemoveTagsRequest(*elbv2.RemoveTagsInput) (*request.Request, *elbv2.RemoveTagsOutput) + + SetIpAddressType(*elbv2.SetIpAddressTypeInput) (*elbv2.SetIpAddressTypeOutput, error) + SetIpAddressTypeWithContext(aws.Context, *elbv2.SetIpAddressTypeInput, ...request.Option) (*elbv2.SetIpAddressTypeOutput, error) + SetIpAddressTypeRequest(*elbv2.SetIpAddressTypeInput) (*request.Request, *elbv2.SetIpAddressTypeOutput) + + SetRulePriorities(*elbv2.SetRulePrioritiesInput) (*elbv2.SetRulePrioritiesOutput, error) + SetRulePrioritiesWithContext(aws.Context, *elbv2.SetRulePrioritiesInput, ...request.Option) (*elbv2.SetRulePrioritiesOutput, error) + SetRulePrioritiesRequest(*elbv2.SetRulePrioritiesInput) (*request.Request, *elbv2.SetRulePrioritiesOutput) + + SetSecurityGroups(*elbv2.SetSecurityGroupsInput) (*elbv2.SetSecurityGroupsOutput, error) + SetSecurityGroupsWithContext(aws.Context, *elbv2.SetSecurityGroupsInput, ...request.Option) (*elbv2.SetSecurityGroupsOutput, error) + SetSecurityGroupsRequest(*elbv2.SetSecurityGroupsInput) (*request.Request, *elbv2.SetSecurityGroupsOutput) + + SetSubnets(*elbv2.SetSubnetsInput) (*elbv2.SetSubnetsOutput, error) + SetSubnetsWithContext(aws.Context, *elbv2.SetSubnetsInput, ...request.Option) (*elbv2.SetSubnetsOutput, error) + SetSubnetsRequest(*elbv2.SetSubnetsInput) (*request.Request, *elbv2.SetSubnetsOutput) + + WaitUntilLoadBalancerAvailable(*elbv2.DescribeLoadBalancersInput) error + WaitUntilLoadBalancerAvailableWithContext(aws.Context, *elbv2.DescribeLoadBalancersInput, ...request.WaiterOption) error + + WaitUntilLoadBalancerExists(*elbv2.DescribeLoadBalancersInput) error + WaitUntilLoadBalancerExistsWithContext(aws.Context, *elbv2.DescribeLoadBalancersInput, ...request.WaiterOption) error + + WaitUntilLoadBalancersDeleted(*elbv2.DescribeLoadBalancersInput) error + WaitUntilLoadBalancersDeletedWithContext(aws.Context, *elbv2.DescribeLoadBalancersInput, ...request.WaiterOption) error + + WaitUntilTargetDeregistered(*elbv2.DescribeTargetHealthInput) error + WaitUntilTargetDeregisteredWithContext(aws.Context, *elbv2.DescribeTargetHealthInput, ...request.WaiterOption) error + + WaitUntilTargetInService(*elbv2.DescribeTargetHealthInput) error + WaitUntilTargetInServiceWithContext(aws.Context, *elbv2.DescribeTargetHealthInput, ...request.WaiterOption) error +} + +var _ ELBV2API = (*elbv2.ELBV2)(nil) diff --git a/vendor/github.com/aws/aws-sdk-go/service/route53/route53iface/interface.go b/vendor/github.com/aws/aws-sdk-go/service/route53/route53iface/interface.go new file mode 100644 index 00000000000..940fd981daa --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/route53/route53iface/interface.go @@ -0,0 +1,368 @@ +// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. + +// Package route53iface provides an interface to enable mocking the Amazon Route 53 service client +// for testing your code. +// +// It is important to note that this interface will have breaking changes +// when the service model is updated and adds new API operations, paginators, +// and waiters. +package route53iface + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/route53" +) + +// Route53API provides an interface to enable mocking the +// route53.Route53 service client's API operation, +// paginators, and waiters. This make unit testing your code that calls out +// to the SDK's service client's calls easier. +// +// The best way to use this interface is so the SDK's service client's calls +// can be stubbed out for unit testing your code with the SDK without needing +// to inject custom request handlers into the SDK's request pipeline. +// +// // myFunc uses an SDK service client to make a request to +// // Amazon Route 53. +// func myFunc(svc route53iface.Route53API) bool { +// // Make svc.ActivateKeySigningKey request +// } +// +// func main() { +// sess := session.New() +// svc := route53.New(sess) +// +// myFunc(svc) +// } +// +// In your _test.go file: +// +// // Define a mock struct to be used in your unit tests of myFunc. +// type mockRoute53Client struct { +// route53iface.Route53API +// } +// func (m *mockRoute53Client) ActivateKeySigningKey(input *route53.ActivateKeySigningKeyInput) (*route53.ActivateKeySigningKeyOutput, error) { +// // mock response/functionality +// } +// +// func TestMyFunc(t *testing.T) { +// // Setup Test +// mockSvc := &mockRoute53Client{} +// +// myfunc(mockSvc) +// +// // Verify myFunc's functionality +// } +// +// It is important to note that this interface will have breaking changes +// when the service model is updated and adds new API operations, paginators, +// and waiters. Its suggested to use the pattern above for testing, or using +// tooling to generate mocks to satisfy the interfaces. +type Route53API interface { + ActivateKeySigningKey(*route53.ActivateKeySigningKeyInput) (*route53.ActivateKeySigningKeyOutput, error) + ActivateKeySigningKeyWithContext(aws.Context, *route53.ActivateKeySigningKeyInput, ...request.Option) (*route53.ActivateKeySigningKeyOutput, error) + ActivateKeySigningKeyRequest(*route53.ActivateKeySigningKeyInput) (*request.Request, *route53.ActivateKeySigningKeyOutput) + + AssociateVPCWithHostedZone(*route53.AssociateVPCWithHostedZoneInput) (*route53.AssociateVPCWithHostedZoneOutput, error) + AssociateVPCWithHostedZoneWithContext(aws.Context, *route53.AssociateVPCWithHostedZoneInput, ...request.Option) (*route53.AssociateVPCWithHostedZoneOutput, error) + AssociateVPCWithHostedZoneRequest(*route53.AssociateVPCWithHostedZoneInput) (*request.Request, *route53.AssociateVPCWithHostedZoneOutput) + + ChangeCidrCollection(*route53.ChangeCidrCollectionInput) (*route53.ChangeCidrCollectionOutput, error) + ChangeCidrCollectionWithContext(aws.Context, *route53.ChangeCidrCollectionInput, ...request.Option) (*route53.ChangeCidrCollectionOutput, error) + ChangeCidrCollectionRequest(*route53.ChangeCidrCollectionInput) (*request.Request, *route53.ChangeCidrCollectionOutput) + + ChangeResourceRecordSets(*route53.ChangeResourceRecordSetsInput) (*route53.ChangeResourceRecordSetsOutput, error) + ChangeResourceRecordSetsWithContext(aws.Context, *route53.ChangeResourceRecordSetsInput, ...request.Option) (*route53.ChangeResourceRecordSetsOutput, error) + ChangeResourceRecordSetsRequest(*route53.ChangeResourceRecordSetsInput) (*request.Request, *route53.ChangeResourceRecordSetsOutput) + + ChangeTagsForResource(*route53.ChangeTagsForResourceInput) (*route53.ChangeTagsForResourceOutput, error) + ChangeTagsForResourceWithContext(aws.Context, *route53.ChangeTagsForResourceInput, ...request.Option) (*route53.ChangeTagsForResourceOutput, error) + ChangeTagsForResourceRequest(*route53.ChangeTagsForResourceInput) (*request.Request, *route53.ChangeTagsForResourceOutput) + + CreateCidrCollection(*route53.CreateCidrCollectionInput) (*route53.CreateCidrCollectionOutput, error) + CreateCidrCollectionWithContext(aws.Context, *route53.CreateCidrCollectionInput, ...request.Option) (*route53.CreateCidrCollectionOutput, error) + CreateCidrCollectionRequest(*route53.CreateCidrCollectionInput) (*request.Request, *route53.CreateCidrCollectionOutput) + + CreateHealthCheck(*route53.CreateHealthCheckInput) (*route53.CreateHealthCheckOutput, error) + CreateHealthCheckWithContext(aws.Context, *route53.CreateHealthCheckInput, ...request.Option) (*route53.CreateHealthCheckOutput, error) + CreateHealthCheckRequest(*route53.CreateHealthCheckInput) (*request.Request, *route53.CreateHealthCheckOutput) + + CreateHostedZone(*route53.CreateHostedZoneInput) (*route53.CreateHostedZoneOutput, error) + CreateHostedZoneWithContext(aws.Context, *route53.CreateHostedZoneInput, ...request.Option) (*route53.CreateHostedZoneOutput, error) + CreateHostedZoneRequest(*route53.CreateHostedZoneInput) (*request.Request, *route53.CreateHostedZoneOutput) + + CreateKeySigningKey(*route53.CreateKeySigningKeyInput) (*route53.CreateKeySigningKeyOutput, error) + CreateKeySigningKeyWithContext(aws.Context, *route53.CreateKeySigningKeyInput, ...request.Option) (*route53.CreateKeySigningKeyOutput, error) + CreateKeySigningKeyRequest(*route53.CreateKeySigningKeyInput) (*request.Request, *route53.CreateKeySigningKeyOutput) + + CreateQueryLoggingConfig(*route53.CreateQueryLoggingConfigInput) (*route53.CreateQueryLoggingConfigOutput, error) + CreateQueryLoggingConfigWithContext(aws.Context, *route53.CreateQueryLoggingConfigInput, ...request.Option) (*route53.CreateQueryLoggingConfigOutput, error) + CreateQueryLoggingConfigRequest(*route53.CreateQueryLoggingConfigInput) (*request.Request, *route53.CreateQueryLoggingConfigOutput) + + CreateReusableDelegationSet(*route53.CreateReusableDelegationSetInput) (*route53.CreateReusableDelegationSetOutput, error) + CreateReusableDelegationSetWithContext(aws.Context, *route53.CreateReusableDelegationSetInput, ...request.Option) (*route53.CreateReusableDelegationSetOutput, error) + CreateReusableDelegationSetRequest(*route53.CreateReusableDelegationSetInput) (*request.Request, *route53.CreateReusableDelegationSetOutput) + + CreateTrafficPolicy(*route53.CreateTrafficPolicyInput) (*route53.CreateTrafficPolicyOutput, error) + CreateTrafficPolicyWithContext(aws.Context, *route53.CreateTrafficPolicyInput, ...request.Option) (*route53.CreateTrafficPolicyOutput, error) + CreateTrafficPolicyRequest(*route53.CreateTrafficPolicyInput) (*request.Request, *route53.CreateTrafficPolicyOutput) + + CreateTrafficPolicyInstance(*route53.CreateTrafficPolicyInstanceInput) (*route53.CreateTrafficPolicyInstanceOutput, error) + CreateTrafficPolicyInstanceWithContext(aws.Context, *route53.CreateTrafficPolicyInstanceInput, ...request.Option) (*route53.CreateTrafficPolicyInstanceOutput, error) + CreateTrafficPolicyInstanceRequest(*route53.CreateTrafficPolicyInstanceInput) (*request.Request, *route53.CreateTrafficPolicyInstanceOutput) + + CreateTrafficPolicyVersion(*route53.CreateTrafficPolicyVersionInput) (*route53.CreateTrafficPolicyVersionOutput, error) + CreateTrafficPolicyVersionWithContext(aws.Context, *route53.CreateTrafficPolicyVersionInput, ...request.Option) (*route53.CreateTrafficPolicyVersionOutput, error) + CreateTrafficPolicyVersionRequest(*route53.CreateTrafficPolicyVersionInput) (*request.Request, *route53.CreateTrafficPolicyVersionOutput) + + CreateVPCAssociationAuthorization(*route53.CreateVPCAssociationAuthorizationInput) (*route53.CreateVPCAssociationAuthorizationOutput, error) + CreateVPCAssociationAuthorizationWithContext(aws.Context, *route53.CreateVPCAssociationAuthorizationInput, ...request.Option) (*route53.CreateVPCAssociationAuthorizationOutput, error) + CreateVPCAssociationAuthorizationRequest(*route53.CreateVPCAssociationAuthorizationInput) (*request.Request, *route53.CreateVPCAssociationAuthorizationOutput) + + DeactivateKeySigningKey(*route53.DeactivateKeySigningKeyInput) (*route53.DeactivateKeySigningKeyOutput, error) + DeactivateKeySigningKeyWithContext(aws.Context, *route53.DeactivateKeySigningKeyInput, ...request.Option) (*route53.DeactivateKeySigningKeyOutput, error) + DeactivateKeySigningKeyRequest(*route53.DeactivateKeySigningKeyInput) (*request.Request, *route53.DeactivateKeySigningKeyOutput) + + DeleteCidrCollection(*route53.DeleteCidrCollectionInput) (*route53.DeleteCidrCollectionOutput, error) + DeleteCidrCollectionWithContext(aws.Context, *route53.DeleteCidrCollectionInput, ...request.Option) (*route53.DeleteCidrCollectionOutput, error) + DeleteCidrCollectionRequest(*route53.DeleteCidrCollectionInput) (*request.Request, *route53.DeleteCidrCollectionOutput) + + DeleteHealthCheck(*route53.DeleteHealthCheckInput) (*route53.DeleteHealthCheckOutput, error) + DeleteHealthCheckWithContext(aws.Context, *route53.DeleteHealthCheckInput, ...request.Option) (*route53.DeleteHealthCheckOutput, error) + DeleteHealthCheckRequest(*route53.DeleteHealthCheckInput) (*request.Request, *route53.DeleteHealthCheckOutput) + + DeleteHostedZone(*route53.DeleteHostedZoneInput) (*route53.DeleteHostedZoneOutput, error) + DeleteHostedZoneWithContext(aws.Context, *route53.DeleteHostedZoneInput, ...request.Option) (*route53.DeleteHostedZoneOutput, error) + DeleteHostedZoneRequest(*route53.DeleteHostedZoneInput) (*request.Request, *route53.DeleteHostedZoneOutput) + + DeleteKeySigningKey(*route53.DeleteKeySigningKeyInput) (*route53.DeleteKeySigningKeyOutput, error) + DeleteKeySigningKeyWithContext(aws.Context, *route53.DeleteKeySigningKeyInput, ...request.Option) (*route53.DeleteKeySigningKeyOutput, error) + DeleteKeySigningKeyRequest(*route53.DeleteKeySigningKeyInput) (*request.Request, *route53.DeleteKeySigningKeyOutput) + + DeleteQueryLoggingConfig(*route53.DeleteQueryLoggingConfigInput) (*route53.DeleteQueryLoggingConfigOutput, error) + DeleteQueryLoggingConfigWithContext(aws.Context, *route53.DeleteQueryLoggingConfigInput, ...request.Option) (*route53.DeleteQueryLoggingConfigOutput, error) + DeleteQueryLoggingConfigRequest(*route53.DeleteQueryLoggingConfigInput) (*request.Request, *route53.DeleteQueryLoggingConfigOutput) + + DeleteReusableDelegationSet(*route53.DeleteReusableDelegationSetInput) (*route53.DeleteReusableDelegationSetOutput, error) + DeleteReusableDelegationSetWithContext(aws.Context, *route53.DeleteReusableDelegationSetInput, ...request.Option) (*route53.DeleteReusableDelegationSetOutput, error) + DeleteReusableDelegationSetRequest(*route53.DeleteReusableDelegationSetInput) (*request.Request, *route53.DeleteReusableDelegationSetOutput) + + DeleteTrafficPolicy(*route53.DeleteTrafficPolicyInput) (*route53.DeleteTrafficPolicyOutput, error) + DeleteTrafficPolicyWithContext(aws.Context, *route53.DeleteTrafficPolicyInput, ...request.Option) (*route53.DeleteTrafficPolicyOutput, error) + DeleteTrafficPolicyRequest(*route53.DeleteTrafficPolicyInput) (*request.Request, *route53.DeleteTrafficPolicyOutput) + + DeleteTrafficPolicyInstance(*route53.DeleteTrafficPolicyInstanceInput) (*route53.DeleteTrafficPolicyInstanceOutput, error) + DeleteTrafficPolicyInstanceWithContext(aws.Context, *route53.DeleteTrafficPolicyInstanceInput, ...request.Option) (*route53.DeleteTrafficPolicyInstanceOutput, error) + DeleteTrafficPolicyInstanceRequest(*route53.DeleteTrafficPolicyInstanceInput) (*request.Request, *route53.DeleteTrafficPolicyInstanceOutput) + + DeleteVPCAssociationAuthorization(*route53.DeleteVPCAssociationAuthorizationInput) (*route53.DeleteVPCAssociationAuthorizationOutput, error) + DeleteVPCAssociationAuthorizationWithContext(aws.Context, *route53.DeleteVPCAssociationAuthorizationInput, ...request.Option) (*route53.DeleteVPCAssociationAuthorizationOutput, error) + DeleteVPCAssociationAuthorizationRequest(*route53.DeleteVPCAssociationAuthorizationInput) (*request.Request, *route53.DeleteVPCAssociationAuthorizationOutput) + + DisableHostedZoneDNSSEC(*route53.DisableHostedZoneDNSSECInput) (*route53.DisableHostedZoneDNSSECOutput, error) + DisableHostedZoneDNSSECWithContext(aws.Context, *route53.DisableHostedZoneDNSSECInput, ...request.Option) (*route53.DisableHostedZoneDNSSECOutput, error) + DisableHostedZoneDNSSECRequest(*route53.DisableHostedZoneDNSSECInput) (*request.Request, *route53.DisableHostedZoneDNSSECOutput) + + DisassociateVPCFromHostedZone(*route53.DisassociateVPCFromHostedZoneInput) (*route53.DisassociateVPCFromHostedZoneOutput, error) + DisassociateVPCFromHostedZoneWithContext(aws.Context, *route53.DisassociateVPCFromHostedZoneInput, ...request.Option) (*route53.DisassociateVPCFromHostedZoneOutput, error) + DisassociateVPCFromHostedZoneRequest(*route53.DisassociateVPCFromHostedZoneInput) (*request.Request, *route53.DisassociateVPCFromHostedZoneOutput) + + EnableHostedZoneDNSSEC(*route53.EnableHostedZoneDNSSECInput) (*route53.EnableHostedZoneDNSSECOutput, error) + EnableHostedZoneDNSSECWithContext(aws.Context, *route53.EnableHostedZoneDNSSECInput, ...request.Option) (*route53.EnableHostedZoneDNSSECOutput, error) + EnableHostedZoneDNSSECRequest(*route53.EnableHostedZoneDNSSECInput) (*request.Request, *route53.EnableHostedZoneDNSSECOutput) + + GetAccountLimit(*route53.GetAccountLimitInput) (*route53.GetAccountLimitOutput, error) + GetAccountLimitWithContext(aws.Context, *route53.GetAccountLimitInput, ...request.Option) (*route53.GetAccountLimitOutput, error) + GetAccountLimitRequest(*route53.GetAccountLimitInput) (*request.Request, *route53.GetAccountLimitOutput) + + GetChange(*route53.GetChangeInput) (*route53.GetChangeOutput, error) + GetChangeWithContext(aws.Context, *route53.GetChangeInput, ...request.Option) (*route53.GetChangeOutput, error) + GetChangeRequest(*route53.GetChangeInput) (*request.Request, *route53.GetChangeOutput) + + GetCheckerIpRanges(*route53.GetCheckerIpRangesInput) (*route53.GetCheckerIpRangesOutput, error) + GetCheckerIpRangesWithContext(aws.Context, *route53.GetCheckerIpRangesInput, ...request.Option) (*route53.GetCheckerIpRangesOutput, error) + GetCheckerIpRangesRequest(*route53.GetCheckerIpRangesInput) (*request.Request, *route53.GetCheckerIpRangesOutput) + + GetDNSSEC(*route53.GetDNSSECInput) (*route53.GetDNSSECOutput, error) + GetDNSSECWithContext(aws.Context, *route53.GetDNSSECInput, ...request.Option) (*route53.GetDNSSECOutput, error) + GetDNSSECRequest(*route53.GetDNSSECInput) (*request.Request, *route53.GetDNSSECOutput) + + GetGeoLocation(*route53.GetGeoLocationInput) (*route53.GetGeoLocationOutput, error) + GetGeoLocationWithContext(aws.Context, *route53.GetGeoLocationInput, ...request.Option) (*route53.GetGeoLocationOutput, error) + GetGeoLocationRequest(*route53.GetGeoLocationInput) (*request.Request, *route53.GetGeoLocationOutput) + + GetHealthCheck(*route53.GetHealthCheckInput) (*route53.GetHealthCheckOutput, error) + GetHealthCheckWithContext(aws.Context, *route53.GetHealthCheckInput, ...request.Option) (*route53.GetHealthCheckOutput, error) + GetHealthCheckRequest(*route53.GetHealthCheckInput) (*request.Request, *route53.GetHealthCheckOutput) + + GetHealthCheckCount(*route53.GetHealthCheckCountInput) (*route53.GetHealthCheckCountOutput, error) + GetHealthCheckCountWithContext(aws.Context, *route53.GetHealthCheckCountInput, ...request.Option) (*route53.GetHealthCheckCountOutput, error) + GetHealthCheckCountRequest(*route53.GetHealthCheckCountInput) (*request.Request, *route53.GetHealthCheckCountOutput) + + GetHealthCheckLastFailureReason(*route53.GetHealthCheckLastFailureReasonInput) (*route53.GetHealthCheckLastFailureReasonOutput, error) + GetHealthCheckLastFailureReasonWithContext(aws.Context, *route53.GetHealthCheckLastFailureReasonInput, ...request.Option) (*route53.GetHealthCheckLastFailureReasonOutput, error) + GetHealthCheckLastFailureReasonRequest(*route53.GetHealthCheckLastFailureReasonInput) (*request.Request, *route53.GetHealthCheckLastFailureReasonOutput) + + GetHealthCheckStatus(*route53.GetHealthCheckStatusInput) (*route53.GetHealthCheckStatusOutput, error) + GetHealthCheckStatusWithContext(aws.Context, *route53.GetHealthCheckStatusInput, ...request.Option) (*route53.GetHealthCheckStatusOutput, error) + GetHealthCheckStatusRequest(*route53.GetHealthCheckStatusInput) (*request.Request, *route53.GetHealthCheckStatusOutput) + + GetHostedZone(*route53.GetHostedZoneInput) (*route53.GetHostedZoneOutput, error) + GetHostedZoneWithContext(aws.Context, *route53.GetHostedZoneInput, ...request.Option) (*route53.GetHostedZoneOutput, error) + GetHostedZoneRequest(*route53.GetHostedZoneInput) (*request.Request, *route53.GetHostedZoneOutput) + + GetHostedZoneCount(*route53.GetHostedZoneCountInput) (*route53.GetHostedZoneCountOutput, error) + GetHostedZoneCountWithContext(aws.Context, *route53.GetHostedZoneCountInput, ...request.Option) (*route53.GetHostedZoneCountOutput, error) + GetHostedZoneCountRequest(*route53.GetHostedZoneCountInput) (*request.Request, *route53.GetHostedZoneCountOutput) + + GetHostedZoneLimit(*route53.GetHostedZoneLimitInput) (*route53.GetHostedZoneLimitOutput, error) + GetHostedZoneLimitWithContext(aws.Context, *route53.GetHostedZoneLimitInput, ...request.Option) (*route53.GetHostedZoneLimitOutput, error) + GetHostedZoneLimitRequest(*route53.GetHostedZoneLimitInput) (*request.Request, *route53.GetHostedZoneLimitOutput) + + GetQueryLoggingConfig(*route53.GetQueryLoggingConfigInput) (*route53.GetQueryLoggingConfigOutput, error) + GetQueryLoggingConfigWithContext(aws.Context, *route53.GetQueryLoggingConfigInput, ...request.Option) (*route53.GetQueryLoggingConfigOutput, error) + GetQueryLoggingConfigRequest(*route53.GetQueryLoggingConfigInput) (*request.Request, *route53.GetQueryLoggingConfigOutput) + + GetReusableDelegationSet(*route53.GetReusableDelegationSetInput) (*route53.GetReusableDelegationSetOutput, error) + GetReusableDelegationSetWithContext(aws.Context, *route53.GetReusableDelegationSetInput, ...request.Option) (*route53.GetReusableDelegationSetOutput, error) + GetReusableDelegationSetRequest(*route53.GetReusableDelegationSetInput) (*request.Request, *route53.GetReusableDelegationSetOutput) + + GetReusableDelegationSetLimit(*route53.GetReusableDelegationSetLimitInput) (*route53.GetReusableDelegationSetLimitOutput, error) + GetReusableDelegationSetLimitWithContext(aws.Context, *route53.GetReusableDelegationSetLimitInput, ...request.Option) (*route53.GetReusableDelegationSetLimitOutput, error) + GetReusableDelegationSetLimitRequest(*route53.GetReusableDelegationSetLimitInput) (*request.Request, *route53.GetReusableDelegationSetLimitOutput) + + GetTrafficPolicy(*route53.GetTrafficPolicyInput) (*route53.GetTrafficPolicyOutput, error) + GetTrafficPolicyWithContext(aws.Context, *route53.GetTrafficPolicyInput, ...request.Option) (*route53.GetTrafficPolicyOutput, error) + GetTrafficPolicyRequest(*route53.GetTrafficPolicyInput) (*request.Request, *route53.GetTrafficPolicyOutput) + + GetTrafficPolicyInstance(*route53.GetTrafficPolicyInstanceInput) (*route53.GetTrafficPolicyInstanceOutput, error) + GetTrafficPolicyInstanceWithContext(aws.Context, *route53.GetTrafficPolicyInstanceInput, ...request.Option) (*route53.GetTrafficPolicyInstanceOutput, error) + GetTrafficPolicyInstanceRequest(*route53.GetTrafficPolicyInstanceInput) (*request.Request, *route53.GetTrafficPolicyInstanceOutput) + + GetTrafficPolicyInstanceCount(*route53.GetTrafficPolicyInstanceCountInput) (*route53.GetTrafficPolicyInstanceCountOutput, error) + GetTrafficPolicyInstanceCountWithContext(aws.Context, *route53.GetTrafficPolicyInstanceCountInput, ...request.Option) (*route53.GetTrafficPolicyInstanceCountOutput, error) + GetTrafficPolicyInstanceCountRequest(*route53.GetTrafficPolicyInstanceCountInput) (*request.Request, *route53.GetTrafficPolicyInstanceCountOutput) + + ListCidrBlocks(*route53.ListCidrBlocksInput) (*route53.ListCidrBlocksOutput, error) + ListCidrBlocksWithContext(aws.Context, *route53.ListCidrBlocksInput, ...request.Option) (*route53.ListCidrBlocksOutput, error) + ListCidrBlocksRequest(*route53.ListCidrBlocksInput) (*request.Request, *route53.ListCidrBlocksOutput) + + ListCidrBlocksPages(*route53.ListCidrBlocksInput, func(*route53.ListCidrBlocksOutput, bool) bool) error + ListCidrBlocksPagesWithContext(aws.Context, *route53.ListCidrBlocksInput, func(*route53.ListCidrBlocksOutput, bool) bool, ...request.Option) error + + ListCidrCollections(*route53.ListCidrCollectionsInput) (*route53.ListCidrCollectionsOutput, error) + ListCidrCollectionsWithContext(aws.Context, *route53.ListCidrCollectionsInput, ...request.Option) (*route53.ListCidrCollectionsOutput, error) + ListCidrCollectionsRequest(*route53.ListCidrCollectionsInput) (*request.Request, *route53.ListCidrCollectionsOutput) + + ListCidrCollectionsPages(*route53.ListCidrCollectionsInput, func(*route53.ListCidrCollectionsOutput, bool) bool) error + ListCidrCollectionsPagesWithContext(aws.Context, *route53.ListCidrCollectionsInput, func(*route53.ListCidrCollectionsOutput, bool) bool, ...request.Option) error + + ListCidrLocations(*route53.ListCidrLocationsInput) (*route53.ListCidrLocationsOutput, error) + ListCidrLocationsWithContext(aws.Context, *route53.ListCidrLocationsInput, ...request.Option) (*route53.ListCidrLocationsOutput, error) + ListCidrLocationsRequest(*route53.ListCidrLocationsInput) (*request.Request, *route53.ListCidrLocationsOutput) + + ListCidrLocationsPages(*route53.ListCidrLocationsInput, func(*route53.ListCidrLocationsOutput, bool) bool) error + ListCidrLocationsPagesWithContext(aws.Context, *route53.ListCidrLocationsInput, func(*route53.ListCidrLocationsOutput, bool) bool, ...request.Option) error + + ListGeoLocations(*route53.ListGeoLocationsInput) (*route53.ListGeoLocationsOutput, error) + ListGeoLocationsWithContext(aws.Context, *route53.ListGeoLocationsInput, ...request.Option) (*route53.ListGeoLocationsOutput, error) + ListGeoLocationsRequest(*route53.ListGeoLocationsInput) (*request.Request, *route53.ListGeoLocationsOutput) + + ListHealthChecks(*route53.ListHealthChecksInput) (*route53.ListHealthChecksOutput, error) + ListHealthChecksWithContext(aws.Context, *route53.ListHealthChecksInput, ...request.Option) (*route53.ListHealthChecksOutput, error) + ListHealthChecksRequest(*route53.ListHealthChecksInput) (*request.Request, *route53.ListHealthChecksOutput) + + ListHealthChecksPages(*route53.ListHealthChecksInput, func(*route53.ListHealthChecksOutput, bool) bool) error + ListHealthChecksPagesWithContext(aws.Context, *route53.ListHealthChecksInput, func(*route53.ListHealthChecksOutput, bool) bool, ...request.Option) error + + ListHostedZones(*route53.ListHostedZonesInput) (*route53.ListHostedZonesOutput, error) + ListHostedZonesWithContext(aws.Context, *route53.ListHostedZonesInput, ...request.Option) (*route53.ListHostedZonesOutput, error) + ListHostedZonesRequest(*route53.ListHostedZonesInput) (*request.Request, *route53.ListHostedZonesOutput) + + ListHostedZonesPages(*route53.ListHostedZonesInput, func(*route53.ListHostedZonesOutput, bool) bool) error + ListHostedZonesPagesWithContext(aws.Context, *route53.ListHostedZonesInput, func(*route53.ListHostedZonesOutput, bool) bool, ...request.Option) error + + ListHostedZonesByName(*route53.ListHostedZonesByNameInput) (*route53.ListHostedZonesByNameOutput, error) + ListHostedZonesByNameWithContext(aws.Context, *route53.ListHostedZonesByNameInput, ...request.Option) (*route53.ListHostedZonesByNameOutput, error) + ListHostedZonesByNameRequest(*route53.ListHostedZonesByNameInput) (*request.Request, *route53.ListHostedZonesByNameOutput) + + ListHostedZonesByVPC(*route53.ListHostedZonesByVPCInput) (*route53.ListHostedZonesByVPCOutput, error) + ListHostedZonesByVPCWithContext(aws.Context, *route53.ListHostedZonesByVPCInput, ...request.Option) (*route53.ListHostedZonesByVPCOutput, error) + ListHostedZonesByVPCRequest(*route53.ListHostedZonesByVPCInput) (*request.Request, *route53.ListHostedZonesByVPCOutput) + + ListQueryLoggingConfigs(*route53.ListQueryLoggingConfigsInput) (*route53.ListQueryLoggingConfigsOutput, error) + ListQueryLoggingConfigsWithContext(aws.Context, *route53.ListQueryLoggingConfigsInput, ...request.Option) (*route53.ListQueryLoggingConfigsOutput, error) + ListQueryLoggingConfigsRequest(*route53.ListQueryLoggingConfigsInput) (*request.Request, *route53.ListQueryLoggingConfigsOutput) + + ListQueryLoggingConfigsPages(*route53.ListQueryLoggingConfigsInput, func(*route53.ListQueryLoggingConfigsOutput, bool) bool) error + ListQueryLoggingConfigsPagesWithContext(aws.Context, *route53.ListQueryLoggingConfigsInput, func(*route53.ListQueryLoggingConfigsOutput, bool) bool, ...request.Option) error + + ListResourceRecordSets(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) + ListResourceRecordSetsWithContext(aws.Context, *route53.ListResourceRecordSetsInput, ...request.Option) (*route53.ListResourceRecordSetsOutput, error) + ListResourceRecordSetsRequest(*route53.ListResourceRecordSetsInput) (*request.Request, *route53.ListResourceRecordSetsOutput) + + ListResourceRecordSetsPages(*route53.ListResourceRecordSetsInput, func(*route53.ListResourceRecordSetsOutput, bool) bool) error + ListResourceRecordSetsPagesWithContext(aws.Context, *route53.ListResourceRecordSetsInput, func(*route53.ListResourceRecordSetsOutput, bool) bool, ...request.Option) error + + ListReusableDelegationSets(*route53.ListReusableDelegationSetsInput) (*route53.ListReusableDelegationSetsOutput, error) + ListReusableDelegationSetsWithContext(aws.Context, *route53.ListReusableDelegationSetsInput, ...request.Option) (*route53.ListReusableDelegationSetsOutput, error) + ListReusableDelegationSetsRequest(*route53.ListReusableDelegationSetsInput) (*request.Request, *route53.ListReusableDelegationSetsOutput) + + ListTagsForResource(*route53.ListTagsForResourceInput) (*route53.ListTagsForResourceOutput, error) + ListTagsForResourceWithContext(aws.Context, *route53.ListTagsForResourceInput, ...request.Option) (*route53.ListTagsForResourceOutput, error) + ListTagsForResourceRequest(*route53.ListTagsForResourceInput) (*request.Request, *route53.ListTagsForResourceOutput) + + ListTagsForResources(*route53.ListTagsForResourcesInput) (*route53.ListTagsForResourcesOutput, error) + ListTagsForResourcesWithContext(aws.Context, *route53.ListTagsForResourcesInput, ...request.Option) (*route53.ListTagsForResourcesOutput, error) + ListTagsForResourcesRequest(*route53.ListTagsForResourcesInput) (*request.Request, *route53.ListTagsForResourcesOutput) + + ListTrafficPolicies(*route53.ListTrafficPoliciesInput) (*route53.ListTrafficPoliciesOutput, error) + ListTrafficPoliciesWithContext(aws.Context, *route53.ListTrafficPoliciesInput, ...request.Option) (*route53.ListTrafficPoliciesOutput, error) + ListTrafficPoliciesRequest(*route53.ListTrafficPoliciesInput) (*request.Request, *route53.ListTrafficPoliciesOutput) + + ListTrafficPolicyInstances(*route53.ListTrafficPolicyInstancesInput) (*route53.ListTrafficPolicyInstancesOutput, error) + ListTrafficPolicyInstancesWithContext(aws.Context, *route53.ListTrafficPolicyInstancesInput, ...request.Option) (*route53.ListTrafficPolicyInstancesOutput, error) + ListTrafficPolicyInstancesRequest(*route53.ListTrafficPolicyInstancesInput) (*request.Request, *route53.ListTrafficPolicyInstancesOutput) + + ListTrafficPolicyInstancesByHostedZone(*route53.ListTrafficPolicyInstancesByHostedZoneInput) (*route53.ListTrafficPolicyInstancesByHostedZoneOutput, error) + ListTrafficPolicyInstancesByHostedZoneWithContext(aws.Context, *route53.ListTrafficPolicyInstancesByHostedZoneInput, ...request.Option) (*route53.ListTrafficPolicyInstancesByHostedZoneOutput, error) + ListTrafficPolicyInstancesByHostedZoneRequest(*route53.ListTrafficPolicyInstancesByHostedZoneInput) (*request.Request, *route53.ListTrafficPolicyInstancesByHostedZoneOutput) + + ListTrafficPolicyInstancesByPolicy(*route53.ListTrafficPolicyInstancesByPolicyInput) (*route53.ListTrafficPolicyInstancesByPolicyOutput, error) + ListTrafficPolicyInstancesByPolicyWithContext(aws.Context, *route53.ListTrafficPolicyInstancesByPolicyInput, ...request.Option) (*route53.ListTrafficPolicyInstancesByPolicyOutput, error) + ListTrafficPolicyInstancesByPolicyRequest(*route53.ListTrafficPolicyInstancesByPolicyInput) (*request.Request, *route53.ListTrafficPolicyInstancesByPolicyOutput) + + ListTrafficPolicyVersions(*route53.ListTrafficPolicyVersionsInput) (*route53.ListTrafficPolicyVersionsOutput, error) + ListTrafficPolicyVersionsWithContext(aws.Context, *route53.ListTrafficPolicyVersionsInput, ...request.Option) (*route53.ListTrafficPolicyVersionsOutput, error) + ListTrafficPolicyVersionsRequest(*route53.ListTrafficPolicyVersionsInput) (*request.Request, *route53.ListTrafficPolicyVersionsOutput) + + ListVPCAssociationAuthorizations(*route53.ListVPCAssociationAuthorizationsInput) (*route53.ListVPCAssociationAuthorizationsOutput, error) + ListVPCAssociationAuthorizationsWithContext(aws.Context, *route53.ListVPCAssociationAuthorizationsInput, ...request.Option) (*route53.ListVPCAssociationAuthorizationsOutput, error) + ListVPCAssociationAuthorizationsRequest(*route53.ListVPCAssociationAuthorizationsInput) (*request.Request, *route53.ListVPCAssociationAuthorizationsOutput) + + TestDNSAnswer(*route53.TestDNSAnswerInput) (*route53.TestDNSAnswerOutput, error) + TestDNSAnswerWithContext(aws.Context, *route53.TestDNSAnswerInput, ...request.Option) (*route53.TestDNSAnswerOutput, error) + TestDNSAnswerRequest(*route53.TestDNSAnswerInput) (*request.Request, *route53.TestDNSAnswerOutput) + + UpdateHealthCheck(*route53.UpdateHealthCheckInput) (*route53.UpdateHealthCheckOutput, error) + UpdateHealthCheckWithContext(aws.Context, *route53.UpdateHealthCheckInput, ...request.Option) (*route53.UpdateHealthCheckOutput, error) + UpdateHealthCheckRequest(*route53.UpdateHealthCheckInput) (*request.Request, *route53.UpdateHealthCheckOutput) + + UpdateHostedZoneComment(*route53.UpdateHostedZoneCommentInput) (*route53.UpdateHostedZoneCommentOutput, error) + UpdateHostedZoneCommentWithContext(aws.Context, *route53.UpdateHostedZoneCommentInput, ...request.Option) (*route53.UpdateHostedZoneCommentOutput, error) + UpdateHostedZoneCommentRequest(*route53.UpdateHostedZoneCommentInput) (*request.Request, *route53.UpdateHostedZoneCommentOutput) + + UpdateTrafficPolicyComment(*route53.UpdateTrafficPolicyCommentInput) (*route53.UpdateTrafficPolicyCommentOutput, error) + UpdateTrafficPolicyCommentWithContext(aws.Context, *route53.UpdateTrafficPolicyCommentInput, ...request.Option) (*route53.UpdateTrafficPolicyCommentOutput, error) + UpdateTrafficPolicyCommentRequest(*route53.UpdateTrafficPolicyCommentInput) (*request.Request, *route53.UpdateTrafficPolicyCommentOutput) + + UpdateTrafficPolicyInstance(*route53.UpdateTrafficPolicyInstanceInput) (*route53.UpdateTrafficPolicyInstanceOutput, error) + UpdateTrafficPolicyInstanceWithContext(aws.Context, *route53.UpdateTrafficPolicyInstanceInput, ...request.Option) (*route53.UpdateTrafficPolicyInstanceOutput, error) + UpdateTrafficPolicyInstanceRequest(*route53.UpdateTrafficPolicyInstanceInput) (*request.Request, *route53.UpdateTrafficPolicyInstanceOutput) + + WaitUntilResourceRecordSetsChanged(*route53.GetChangeInput) error + WaitUntilResourceRecordSetsChangedWithContext(aws.Context, *route53.GetChangeInput, ...request.WaiterOption) error +} + +var _ Route53API = (*route53.Route53)(nil) diff --git a/vendor/modules.txt b/vendor/modules.txt index 977809fc7d1..8982604a9db 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -335,13 +335,16 @@ github.com/aws/aws-sdk-go/private/protocol/restjson github.com/aws/aws-sdk-go/private/protocol/restxml github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil github.com/aws/aws-sdk-go/service/ec2 +github.com/aws/aws-sdk-go/service/ec2/ec2iface github.com/aws/aws-sdk-go/service/efs github.com/aws/aws-sdk-go/service/elb github.com/aws/aws-sdk-go/service/elbv2 +github.com/aws/aws-sdk-go/service/elbv2/elbv2iface github.com/aws/aws-sdk-go/service/iam github.com/aws/aws-sdk-go/service/iam/iamiface github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi github.com/aws/aws-sdk-go/service/route53 +github.com/aws/aws-sdk-go/service/route53/route53iface github.com/aws/aws-sdk-go/service/s3 github.com/aws/aws-sdk-go/service/s3/s3iface github.com/aws/aws-sdk-go/service/s3/s3manager From f8a53e254c696b725253e2f437d02f9d804712a6 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Sun, 5 Nov 2023 20:02:50 +0100 Subject: [PATCH 25/33] CORS-2887: infra/aws: preserve bootstrap ignition when specified Bootstrap ignition is not deleted when installconfig.platform.aws.preserveBootstrapIgnition is specified. --- pkg/infrastructure/aws/aws.go | 6 ++-- pkg/infrastructure/aws/bootstrap.go | 7 +++-- pkg/infrastructure/aws/destroy.go | 49 +++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 28d2312e7cb..09140ae7db8 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -326,8 +326,10 @@ func (a InfraProvider) DestroyBootstrap(dir string) error { logger := logrus.StandardLogger() input := &destroyInputOptions{ - infraID: clusterConfig.ClusterID, - region: clusterAWSConfig.Region, + infraID: clusterConfig.ClusterID, + region: clusterAWSConfig.Region, + ignitionBucket: clusterAWSConfig.IgnitionBucket, + preserveIgnition: clusterAWSConfig.PreserveBootstrapIgnition, } err = destroyBootstrapResources(ctx, logger, awsSession, input) if err != nil { diff --git a/pkg/infrastructure/aws/bootstrap.go b/pkg/infrastructure/aws/bootstrap.go index 23a977d37ed..776fad69277 100644 --- a/pkg/infrastructure/aws/bootstrap.go +++ b/pkg/infrastructure/aws/bootstrap.go @@ -17,6 +17,8 @@ import ( "github.com/sirupsen/logrus" ) +const ignitionKey = "bootstrap.ign" + type bootstrapInputOptions struct { instanceInputOptions ignitionBucket string @@ -59,7 +61,6 @@ func ensureIgnition(ctx context.Context, logger logrus.FieldLogger, client s3ifa return err } - const ignitionKey = "bootstrap.ign" // Upload the bootstrap.ign file to the S3 bucket _, err = client.PutObjectWithContext(ctx, &s3.PutObjectInput{ Bucket: aws.String(bucket), @@ -70,7 +71,7 @@ func ensureIgnition(ctx context.Context, logger logrus.FieldLogger, client s3ifa if err != nil { return fmt.Errorf("failed to upload %s to bucket: %w", ignitionKey, err) } - logger.Infoln("Uploaded bootstrap.ign to S3 bucket") + logger.Infof("Uploaded %s to S3 bucket", ignitionKey) // S3 Object tagging supports only up to 10 tags // https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html @@ -89,7 +90,7 @@ func ensureIgnition(ctx context.Context, logger logrus.FieldLogger, client s3ifa if err != nil { return fmt.Errorf("failed to tag ignition object: %w", err) } - logger.Infoln("Tagged bootstrap.ign object") + logger.Infof("Tagged %s object", ignitionKey) return nil } diff --git a/pkg/infrastructure/aws/destroy.go b/pkg/infrastructure/aws/destroy.go index aa3b13585e1..acab494e3f8 100644 --- a/pkg/infrastructure/aws/destroy.go +++ b/pkg/infrastructure/aws/destroy.go @@ -3,14 +3,17 @@ package aws import ( "context" "fmt" + "strings" "time" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" "github.com/sirupsen/logrus" + utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -18,8 +21,10 @@ import ( ) type destroyInputOptions struct { - infraID string - region string + infraID string + region string + ignitionBucket string + preserveIgnition bool } func destroyBootstrapResources(ctx context.Context, logger logrus.FieldLogger, awsSession *session.Session, input *destroyInputOptions) error { @@ -69,6 +74,44 @@ func destroyBootstrapResources(ctx context.Context, logger logrus.FieldLogger, a return fmt.Errorf("failed to collect bootstrap resources to delete: %w", err) } + resourcesToPreserve := sets.New[string]() + if input.preserveIgnition { + logger.Debugln("Preserving ignition resources") + var errs []error + for _, resource := range resourcesToDelete.UnsortedList() { + arn, err := arn.Parse(resource) + if err != nil { + // We don't care if we failed to parse some resource ARNs as + // long as we are able to find the ignition bucket and object + // we are looking for + errs = append(errs, err) + continue + } + if arn.Service != "s3" { + continue + } + bucketName, objectName, objectFound := strings.Cut(arn.Resource, "/") + if bucketName != input.ignitionBucket { + continue + } + if !objectFound || objectName == ignitionKey { + resourcesToPreserve.Insert(resource) + } + } + // Should contain at least bucket + if resourcesToPreserve.Len() < 1 { + errMsg := "failed to find ignition resources to preserve" + if len(errs) > 0 { + return fmt.Errorf("%s: %w", errMsg, utilerrors.NewAggregate(errs)) + } + return fmt.Errorf("%s", errMsg) + } + resourcesToDelete = resourcesToDelete.Difference(resourcesToPreserve) + // Pretend the ignition objects have already been deleted to avoid them + // being added again to the to-delete list + deleted = deleted.Union(resourcesToPreserve) + } + tracker := new(awsdestroy.ErrorTracker) instanceFilters := []awsdestroy.Filter{ { @@ -120,5 +163,7 @@ func destroyBootstrapResources(ctx context.Context, logger logrus.FieldLogger, a return fmt.Errorf("failed to delete bootstrap resources: %w", err) } + logger.Debugf("Preserving the following resources: %v", resourcesToPreserve.UnsortedList()) + return nil } From 914fb2f69d5ba7121a623933a4719f25ddd20ff4 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Sun, 5 Nov 2023 22:38:20 +0100 Subject: [PATCH 26/33] CORS-2880: infra/aws: use user-supplied iam role iam role is correctly attached to control plane node when installconfig.controlPlane.platform.aws.iamRole is specified --- pkg/infrastructure/aws/bootstrap.go | 5 +-- pkg/infrastructure/aws/controlplane.go | 5 +-- pkg/infrastructure/aws/instance.go | 42 ++++++++++++++---------- pkg/infrastructure/aws/provision_test.go | 42 +++++++++++++++++++++--- 4 files changed, 69 insertions(+), 25 deletions(-) diff --git a/pkg/infrastructure/aws/bootstrap.go b/pkg/infrastructure/aws/bootstrap.go index 776fad69277..4af3b478387 100644 --- a/pkg/infrastructure/aws/bootstrap.go +++ b/pkg/infrastructure/aws/bootstrap.go @@ -37,7 +37,7 @@ func createBootstrapResources(ctx context.Context, logger logrus.FieldLogger, ec } profileName := fmt.Sprintf("%s-bootstrap", input.infraID) - instanceProfile, err := createBootstrapInstanceProfile(ctx, logger, iamClient, profileName, input.tags) + instanceProfile, err := createBootstrapInstanceProfile(ctx, logger, iamClient, profileName, input.iamRole, input.tags) if err != nil { return nil, fmt.Errorf("failed to create bootstrap instance profile: %w", err) } @@ -167,7 +167,7 @@ func limitTags(tags map[string]string, size int) map[string]string { return resized } -func createBootstrapInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, tags map[string]string) (*iam.InstanceProfile, error) { +func createBootstrapInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, roleName string, tags map[string]string) (*iam.InstanceProfile, error) { const ( assumeRolePolicy = `{ "Version": "2012-10-17", @@ -206,6 +206,7 @@ func createBootstrapInstanceProfile(ctx context.Context, logger logrus.FieldLogg profileInput := &instanceProfileOptions{ namePrefix: name, + roleName: roleName, assumeRolePolicy: assumeRolePolicy, policyDocument: bootstrapPolicy, tags: tags, diff --git a/pkg/infrastructure/aws/controlplane.go b/pkg/infrastructure/aws/controlplane.go index 183c70fa6f7..48d20eccfea 100644 --- a/pkg/infrastructure/aws/controlplane.go +++ b/pkg/infrastructure/aws/controlplane.go @@ -26,7 +26,7 @@ type controlPlaneOutput struct { func createControlPlaneResources(ctx context.Context, logger logrus.FieldLogger, ec2Client ec2iface.EC2API, iamClient iamiface.IAMAPI, elbClient elbv2iface.ELBV2API, input *controlPlaneInputOptions) (*controlPlaneOutput, error) { profileName := fmt.Sprintf("%s-master", input.infraID) - instanceProfile, err := createControlPlaneInstanceProfile(ctx, logger, iamClient, profileName, input.tags) + instanceProfile, err := createControlPlaneInstanceProfile(ctx, logger, iamClient, profileName, input.iamRole, input.tags) if err != nil { return nil, fmt.Errorf("failed to create control plane instance profile: %w", err) } @@ -51,7 +51,7 @@ func createControlPlaneResources(ctx context.Context, logger logrus.FieldLogger, return &controlPlaneOutput{controlPlaneIPs: instanceIPs}, nil } -func createControlPlaneInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, tags map[string]string) (*iam.InstanceProfile, error) { +func createControlPlaneInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, name string, roleName string, tags map[string]string) (*iam.InstanceProfile, error) { const ( assumeRolePolicy = `{ "Version": "2012-10-17", @@ -119,6 +119,7 @@ func createControlPlaneInstanceProfile(ctx context.Context, logger logrus.FieldL profileInput := &instanceProfileOptions{ namePrefix: name, + roleName: roleName, assumeRolePolicy: assumeRolePolicy, policyDocument: policy, tags: tags, diff --git a/pkg/infrastructure/aws/instance.go b/pkg/infrastructure/aws/instance.go index e12f2bbda59..0c7e7110d7c 100644 --- a/pkg/infrastructure/aws/instance.go +++ b/pkg/infrastructure/aws/instance.go @@ -174,10 +174,16 @@ type instanceProfileOptions struct { } func createInstanceProfile(ctx context.Context, logger logrus.FieldLogger, client iamiface.IAMAPI, input *instanceProfileOptions) (*iam.InstanceProfile, error) { - roleName := fmt.Sprintf("%s-role", input.namePrefix) - _, err := ensureRole(ctx, logger, client, roleName, input.assumeRolePolicy, input.tags) - if err != nil { - return nil, err + useExistingRole := len(input.roleName) > 0 + roleName := input.roleName + if !useExistingRole { + roleName = fmt.Sprintf("%s-role", input.namePrefix) + _, err := ensureRole(ctx, logger, client, roleName, input.assumeRolePolicy, input.tags) + if err != nil { + return nil, err + } + } else { + logger.WithField("name", roleName).Infoln("Using user-supplied role") } profileName := fmt.Sprintf("%s-profile", input.namePrefix) @@ -212,20 +218,22 @@ func createInstanceProfile(ctx context.Context, logger logrus.FieldLogger, clien }).Infoln("Role already added to instance profile") } - rolePolicyName := fmt.Sprintf("%s-policy", profileName) - err = existingRolePolicy(ctx, client, roleName, rolePolicyName) - if err != nil { - if !errors.Is(err, errNotFound) { - return nil, fmt.Errorf("failed to get profile policy: %w", err) + if !useExistingRole { + rolePolicyName := fmt.Sprintf("%s-policy", profileName) + err = existingRolePolicy(ctx, client, roleName, rolePolicyName) + if err != nil { + if !errors.Is(err, errNotFound) { + return nil, fmt.Errorf("failed to get role policy: %w", err) + } + _, err = client.PutRolePolicyWithContext(ctx, &iam.PutRolePolicyInput{ + PolicyName: aws.String(rolePolicyName), + PolicyDocument: aws.String(input.policyDocument), + RoleName: aws.String(roleName), + }) + } + if err != nil { + return nil, fmt.Errorf("failed to create role policy: %w", err) } - _, err = client.PutRolePolicyWithContext(ctx, &iam.PutRolePolicyInput{ - PolicyName: aws.String(rolePolicyName), - PolicyDocument: aws.String(input.policyDocument), - RoleName: aws.String(roleName), - }) - } - if err != nil { - return nil, fmt.Errorf("failed to create profile policy: %w", err) } // We sleep here otherwise got an error when creating the ec2 instance diff --git a/pkg/infrastructure/aws/provision_test.go b/pkg/infrastructure/aws/provision_test.go index eb5ac61a8c7..d628a2e0482 100644 --- a/pkg/infrastructure/aws/provision_test.go +++ b/pkg/infrastructure/aws/provision_test.go @@ -2863,10 +2863,11 @@ func TestEnsureInstanceProfile(t *testing.T) { Roles: []*iam.Role{expectedRole}, } tests := []struct { - name string - mockIAM mockIAMClient - expectedOut *iam.InstanceProfile - expectedErr string + name string + existingRole string + mockIAM mockIAMClient + expectedOut *iam.InstanceProfile + expectedErr string }{ { name: "AWS SDK error when retrieving role", @@ -3108,6 +3109,36 @@ func TestEnsureInstanceProfile(t *testing.T) { }, expectedOut: expectedProfile, }, + { + name: "Use user-supplied role", + existingRole: "existing-role", + mockIAM: mockIAMClient{ + getRole: func(*iam.GetRoleInput) (*iam.GetRoleOutput, error) { + panic("should not be called") + }, + createRole: func(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) { + panic("should not be called") + }, + getProfile: func(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) { + return &iam.GetInstanceProfileOutput{ + InstanceProfile: expectedProfile, + }, nil + }, + createProfile: func(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) { + panic("should not be called") + }, + addRoleToProfile: func(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) { + return &iam.AddRoleToInstanceProfileOutput{}, nil + }, + getRolePolicy: func(*iam.GetRolePolicyInput) (*iam.GetRolePolicyOutput, error) { + panic("should not be called") + }, + putRolePolicy: func(*iam.PutRolePolicyInput) (*iam.PutRolePolicyOutput, error) { + panic("should not be called") + }, + }, + expectedOut: expectedProfile, + }, } logger := logrus.New() @@ -3121,6 +3152,9 @@ func TestEnsureInstanceProfile(t *testing.T) { policyDocument: "policy", tags: map[string]string{"custom-tag": "custom-value"}, } + if len(test.existingRole) > 0 { + input.roleName = test.existingRole + } res, err := createInstanceProfile(context.TODO(), logger, &test.mockIAM, &input) if test.expectedErr == "" { assert.NoError(t, err) From 258d5e5da62e0c20dfa52aead6c1f298049c68db Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Mon, 6 Nov 2023 01:38:33 +0100 Subject: [PATCH 27/33] CORS-2881: infra/aws: support AWS local zones --- pkg/infrastructure/aws/aws.go | 2 + pkg/infrastructure/aws/vpc.go | 159 ++++++++++++++++++++++++++++++---- 2 files changed, 143 insertions(+), 18 deletions(-) diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 09140ae7db8..2e4df85be59 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -128,6 +128,8 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, zones: sets.List(availabilityZones), tags: tags, privateSubnetIDs: clusterAWSConfig.PrivateSubnets, + edgeZones: clusterAWSConfig.EdgeLocalZones, + edgeParentMap: clusterAWSConfig.EdgeZonesGatewayIndex, } if clusterAWSConfig.PublicSubnets != nil { vpcInput.publicSubnetIDs = *clusterAWSConfig.PublicSubnets diff --git a/pkg/infrastructure/aws/vpc.go b/pkg/infrastructure/aws/vpc.go index 8fb2c2252f9..235658add89 100644 --- a/pkg/infrastructure/aws/vpc.go +++ b/pkg/infrastructure/aws/vpc.go @@ -47,8 +47,10 @@ type vpcInputOptions struct { vpcID string cidrV4Block string zones []string + edgeZones []string publicSubnetIDs []string privateSubnetIDs []string + edgeParentMap map[string]int tags map[string]string } @@ -118,21 +120,22 @@ func createVPCResources(ctx context.Context, logger logrus.FieldLogger, ec2Clien endpointRouteTableIDs = append(endpointRouteTableIDs, publicRouteTable.RouteTableId) // Per-zone resources - privateNetwork, publicNetwork, err := splitNetworks(vpcInput.cidrV4Block, len(vpcInput.zones)) + networks, err := splitNetworks(vpcInput.cidrV4Block, len(vpcInput.zones), len(vpcInput.edgeZones)) if err != nil { return nil, err } - publicSubnetIDs, publicSubnetZoneMap, err := state.ensurePublicSubnets(ctx, logger, ec2Client, publicNetwork, publicRouteTable) + publicSubnetIDs, publicSubnetZoneMap, err := state.ensurePublicSubnets(ctx, logger, ec2Client, networks.standard.public, publicRouteTable) if err != nil { return nil, err } - privateSubnetIDs, privateSubnetZoneMap, err := state.ensurePrivateSubnets(ctx, logger, ec2Client, privateNetwork) + privateSubnetIDs, privateSubnetZoneMap, err := state.ensurePrivateSubnets(ctx, logger, ec2Client, networks.standard.private) if err != nil { return nil, err } + privateRouteTables := make([]*ec2.RouteTable, 0, len(vpcInput.zones)) for _, zone := range vpcInput.zones { var natGwID *string if len(publicSubnetZoneMap) > 0 { @@ -148,6 +151,7 @@ func createVPCResources(ctx context.Context, logger logrus.FieldLogger, ec2Clien return nil, fmt.Errorf("failed to create private route table for zone (%s): %w", zone, err) } endpointRouteTableIDs = append(endpointRouteTableIDs, privateRouteTable.RouteTableId) + privateRouteTables = append(privateRouteTables, privateRouteTable) } _, err = state.ensureVPCS3Endpoint(ctx, logger, ec2Client, endpointRouteTableIDs) @@ -155,6 +159,47 @@ func createVPCResources(ctx context.Context, logger logrus.FieldLogger, ec2Clien return nil, fmt.Errorf("failed to create VPC S3 endpoint: %w", err) } + if len(vpcInput.edgeZones) > 0 { + _, _, err := state.ensureEdgePublicSubnets(ctx, logger, ec2Client, networks.edge.public, publicRouteTable) + if err != nil { + return nil, err + } + + _, subnetZoneMap, err := state.ensureEdgePrivateSubnets(ctx, logger, ec2Client, networks.edge.private) + if err != nil { + return nil, err + } + + for _, zone := range vpcInput.edgeZones { + // Lookup the index of the parent zone from a given local zone + // name, getting the index for the route table id for that zone + // (parent). When not found (parent zone's gateway does not exist), + // the first route table will be used. + // Example: edgeParentMap = {"us-east-1-nyc-1a": 0} + tableIdx, found := vpcInput.edgeParentMap[zone] + if !found { + tableIdx = 0 + } + table := privateRouteTables[tableIdx] + subnetID := subnetZoneMap[zone] + createdOrFoundMsg := "Edge subnet already associated with route table" + if !hasAssociatedSubnet(table, subnetID) { + createdOrFoundMsg = "Associated edge subnet with route table" + _, err := ec2Client.AssociateRouteTableWithContext(ctx, &ec2.AssociateRouteTableInput{ + RouteTableId: table.RouteTableId, + SubnetId: subnetID, + }) + if err != nil { + return nil, fmt.Errorf("failed to associate edge subnet (%s) to route table (%s): %w", aws.StringValue(subnetID), aws.StringValue(table.RouteTableId), err) + } + } + logger.WithFields(logrus.Fields{ + "subnet": aws.StringValue(subnetID), + "route table": aws.StringValue(table.RouteTableId), + }).Infoln(createdOrFoundMsg) + } + } + return &vpcOutput{ vpcID: aws.StringValue(state.vpcID), privateSubnetIDs: aws.StringValueSlice(privateSubnetIDs), @@ -582,7 +627,7 @@ func (o *vpcState) ensurePublicSubnets(ctx context.Context, logger logrus.FieldL tagNameSubnetPublicELB: "true", }) - ids, zoneMap, err := o.ensureSubnets(ctx, logger, client, network, "public", tags) + ids, zoneMap, err := o.ensureSubnets(ctx, logger, client, network, "public", o.input.zones, tags) if err != nil { return nil, nil, fmt.Errorf("failed to create public subnets: %w", err) } @@ -602,18 +647,40 @@ func (o *vpcState) ensurePrivateSubnets(ctx context.Context, logger logrus.Field tagNameSubnetInternalELB: "true", }) - ids, zoneMap, err := o.ensureSubnets(ctx, logger, client, network, "private", tags) + ids, zoneMap, err := o.ensureSubnets(ctx, logger, client, network, "private", o.input.zones, tags) if err != nil { return nil, nil, fmt.Errorf("failed to create private subnets: %w", err) } return ids, zoneMap, nil } -func (o *vpcState) ensureSubnets(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, network *net.IPNet, subnetType string, tags map[string]string) ([]*string, map[string]*string, error) { - subnetIDs := make([]*string, 0, len(o.input.zones)) - subnetZoneMap := make(map[string]*string, len(o.input.zones)) - newBits := int(math.Ceil(math.Log2(float64(len(o.input.zones))))) - for i, zone := range o.input.zones { +func (o *vpcState) ensureEdgePublicSubnets(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, network *net.IPNet, publicTable *ec2.RouteTable) ([]*string, map[string]*string, error) { + ids, zoneMap, err := o.ensureSubnets(ctx, logger, client, network, "public", o.input.edgeZones, o.input.tags) + if err != nil { + return nil, nil, fmt.Errorf("failed to create public edge subnets: %w", err) + } + + err = addSubnetsToRouteTable(ctx, client, publicTable, ids) + if err != nil { + return nil, nil, fmt.Errorf("failed to associate public edge subnets with public route table (%s): %w", aws.StringValue(publicTable.RouteTableId), err) + } + + return ids, zoneMap, nil +} + +func (o *vpcState) ensureEdgePrivateSubnets(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, network *net.IPNet) ([]*string, map[string]*string, error) { + ids, zoneMap, err := o.ensureSubnets(ctx, logger, client, network, "private", o.input.edgeZones, o.input.tags) + if err != nil { + return nil, nil, fmt.Errorf("failed to create private edge subnets: %w", err) + } + return ids, zoneMap, nil +} + +func (o *vpcState) ensureSubnets(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, network *net.IPNet, subnetType string, zones []string, tags map[string]string) ([]*string, map[string]*string, error) { + subnetIDs := make([]*string, 0, len(zones)) + subnetZoneMap := make(map[string]*string, len(zones)) + newBits := int(math.Ceil(math.Log2(float64(len(zones))))) + for i, zone := range zones { cidr, err := cidr.Subnet(network, newBits, i) if err != nil { return nil, nil, fmt.Errorf("failed to subnet %s network: %w", subnetType, err) @@ -932,20 +999,59 @@ func existingVPCEndpoint(ctx context.Context, client ec2iface.EC2API, filters [] return nil, errNotFound } -func splitNetworks(cidrBlock string, numZones int) (*net.IPNet, *net.IPNet, error) { +type splitOutput struct { + standard struct { + private *net.IPNet + public *net.IPNet + } + edge struct { + private *net.IPNet + public *net.IPNet + } +} + +func splitNetworks(cidrBlock string, numZones int, numEdgeZones int) (*splitOutput, error) { + output := &splitOutput{} + _, network, err := net.ParseCIDR(cidrBlock) if err != nil { - return nil, nil, fmt.Errorf("failed to parse IPv4 CIDR blocks: %w", err) + return nil, fmt.Errorf("failed to parse IPv4 CIDR blocks: %w", err) } + // CIDR blocks for default IPI installation privateNetwork, err := cidr.Subnet(network, 1, 0) if err != nil { - return nil, nil, fmt.Errorf("failed to determine private subnet: %w", err) + return nil, fmt.Errorf("failed to determine private subnet: %w", err) } - publicNetwork, err := cidr.Subnet(network, 1, 1) if err != nil { - return nil, nil, fmt.Errorf("failed to determine public subnet: %w", err) + return nil, fmt.Errorf("failed to determine public subnet: %w", err) + } + + // CIDR blocks used when creating subnets into edge zones. + var edgePrivateNetwork *net.IPNet + var edgePublicNetwork *net.IPNet + if numEdgeZones > 0 { + // The public CIDR is used to create the CIDR blocks for edge subnets. + sharedPublicNetwork, err := cidr.Subnet(publicNetwork, 1, 0) + if err != nil { + return nil, fmt.Errorf("failed to determine shared public subnet: %w", err) + } + sharedEdgeNetwork, err := cidr.Subnet(publicNetwork, 1, 1) + if err != nil { + return nil, fmt.Errorf("failed to determine shared edge subnet: %w", err) + } + publicNetwork = sharedPublicNetwork + + // CIDR bloks for edge subnets + edgePrivateNetwork, err = cidr.Subnet(sharedEdgeNetwork, 1, 0) + if err != nil { + return nil, fmt.Errorf("failed to determine edge private subnet: %w", err) + } + edgePublicNetwork, err = cidr.Subnet(sharedEdgeNetwork, 1, 1) + if err != nil { + return nil, fmt.Errorf("failed to determine edge public subnet: %w", err) + } } // If a single-zone deployment, the available CIDR block is split into two @@ -953,15 +1059,32 @@ func splitNetworks(cidrBlock string, numZones int) (*net.IPNet, *net.IPNet, erro if numZones == 1 { privateNetwork, err = cidr.Subnet(privateNetwork, 1, 0) if err != nil { - return nil, nil, fmt.Errorf("failed to split private subnet in single-zone deployment: %w", err) + return nil, fmt.Errorf("failed to split private subnet in single-zone deployment: %w", err) } publicNetwork, err = cidr.Subnet(publicNetwork, 1, 0) if err != nil { - return nil, nil, fmt.Errorf("failed to split public subnet in single-zone deployment: %w", err) + return nil, fmt.Errorf("failed to split public subnet in single-zone deployment: %w", err) + } + } + output.standard.private = privateNetwork + output.standard.public = publicNetwork + + // If a single-zone deployment, the available CIDR block is split into two + // to allow for user expansion + if numEdgeZones == 1 { + edgePrivateNetwork, err = cidr.Subnet(edgePrivateNetwork, 1, 0) + if err != nil { + return nil, fmt.Errorf("failed to split private edge subnet in single-zone deployment: %w", err) + } + edgePublicNetwork, err = cidr.Subnet(edgePublicNetwork, 1, 0) + if err != nil { + return nil, fmt.Errorf("failed to split public edge subnet in single-zone deployment: %w", err) } } + output.edge.private = edgePrivateNetwork + output.edge.public = edgePublicNetwork - return privateNetwork, publicNetwork, nil + return output, nil } func addSubnetsToRouteTable(ctx context.Context, client ec2iface.EC2API, table *ec2.RouteTable, subnetIDs []*string) error { From 651082b4959983ac2ee65f5b5dabdf0904de9953 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Mon, 6 Nov 2023 15:18:43 +0100 Subject: [PATCH 28/33] infra/aws: wait for instance to acquire IP address We need to know the instances IP address so we can gather logs in case something goes wrong. Since it might take a while for an instance to acquire an IP address, let's wait until that happens when creating an instance. --- pkg/infrastructure/aws/instance.go | 43 +++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/pkg/infrastructure/aws/instance.go b/pkg/infrastructure/aws/instance.go index 0c7e7110d7c..149e9680ca4 100644 --- a/pkg/infrastructure/aws/instance.go +++ b/pkg/infrastructure/aws/instance.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "errors" "fmt" + "strings" "time" "github.com/aws/aws-sdk-go/aws" @@ -21,6 +22,8 @@ import ( var errInstanceNotCreated = errors.New("instance was not created") +const errInstanceIDNotFound = "InvalidInstanceID.NotFound" + type instanceInputOptions struct { infraID string name string @@ -57,7 +60,45 @@ func ensureInstance(ctx context.Context, logger logrus.FieldLogger, ec2Client ec return nil, err } } - l.WithField("id", aws.StringValue(instance.InstanceId)).Infoln(createdOrFoundMsg) + l = l.WithField("id", aws.StringValue(instance.InstanceId)) + l.Infoln(createdOrFoundMsg) + + // wait for the instance to get an IP address since we need to return it. + err = wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (bool, error) { + l.Debugln("Waiting for instance to be created and acquire IP address") + res, err := ec2Client.DescribeInstancesWithContext(ctx, &ec2.DescribeInstancesInput{ + InstanceIds: []*string{instance.InstanceId}, + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && strings.EqualFold(awsErr.Code(), errInstanceIDNotFound) { + return false, nil + } + return true, err + } + // Should not happen but let's be safe + if len(res.Reservations) == 0 || len(res.Reservations[0].Instances) == 0 { + return false, nil + } + instance = res.Reservations[0].Instances[0] + if instance.PrivateIpAddress == nil { + return false, nil + } + if input.associatePublicIP && instance.PublicIpAddress == nil { + return false, nil + } + return true, nil + }, + ) + if err != nil { + l.WithError(err).Infoln("failed to wait for instance to acquire IP address") + // We dont return an error here since the installation can still + // proceed. However, we might not be able to gather instance logs in + // case of bootstrap failure + } for _, targetGroup := range input.targetGroupARNs { _, err = elbClient.RegisterTargetsWithContext(ctx, &elbv2.RegisterTargetsInput{ From 4183edacbc551b1bd80ea50705783fd46bcf06da Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Mon, 6 Nov 2023 15:47:28 +0100 Subject: [PATCH 29/33] infra/aws: reuse code to associate a subnet with a route table --- pkg/infrastructure/aws/provision_test.go | 2 +- pkg/infrastructure/aws/vpc.go | 97 ++++++++++-------------- 2 files changed, 42 insertions(+), 57 deletions(-) diff --git a/pkg/infrastructure/aws/provision_test.go b/pkg/infrastructure/aws/provision_test.go index d628a2e0482..f9ceea9ee40 100644 --- a/pkg/infrastructure/aws/provision_test.go +++ b/pkg/infrastructure/aws/provision_test.go @@ -1250,7 +1250,7 @@ func TestEnsurePublicSubnets(t *testing.T) { return nil, errAwsSdk }, }, - expectedErr: `^failed to associate public subnets with public route table \(table-1\): failed to associate subnet \(subnet-zone1\) with route table: some AWS SDK error$`, + expectedErr: `^failed to associate public subnet \(subnet-zone1\) with public route table \(table-1\): some AWS SDK error$`, }, { name: "Public subnets created", diff --git a/pkg/infrastructure/aws/vpc.go b/pkg/infrastructure/aws/vpc.go index 235658add89..20cefa78018 100644 --- a/pkg/infrastructure/aws/vpc.go +++ b/pkg/infrastructure/aws/vpc.go @@ -182,21 +182,9 @@ func createVPCResources(ctx context.Context, logger logrus.FieldLogger, ec2Clien } table := privateRouteTables[tableIdx] subnetID := subnetZoneMap[zone] - createdOrFoundMsg := "Edge subnet already associated with route table" - if !hasAssociatedSubnet(table, subnetID) { - createdOrFoundMsg = "Associated edge subnet with route table" - _, err := ec2Client.AssociateRouteTableWithContext(ctx, &ec2.AssociateRouteTableInput{ - RouteTableId: table.RouteTableId, - SubnetId: subnetID, - }) - if err != nil { - return nil, fmt.Errorf("failed to associate edge subnet (%s) to route table (%s): %w", aws.StringValue(subnetID), aws.StringValue(table.RouteTableId), err) - } + if err := addSubnetToRouteTable(ctx, logger, ec2Client, table, subnetID); err != nil { + return nil, fmt.Errorf("failed to associate edge subnet (%s) to route table (%s): %w", aws.StringValue(subnetID), aws.StringValue(table.RouteTableId), err) } - logger.WithFields(logrus.Fields{ - "subnet": aws.StringValue(subnetID), - "route table": aws.StringValue(table.RouteTableId), - }).Infoln(createdOrFoundMsg) } } @@ -490,18 +478,9 @@ func (o *vpcState) ensurePrivateRouteTable(ctx context.Context, logger logrus.Fi } l.WithField("nat gateway", aws.StringValue(natGwID)).Infoln(createdOrFoundMsg) - createdOrFoundMsg = "Subnet already associated with route table" - if !hasAssociatedSubnet(table, subnetID) { - createdOrFoundMsg = "Associated subnet with route table" - _, err := client.AssociateRouteTableWithContext(ctx, &ec2.AssociateRouteTableInput{ - RouteTableId: table.RouteTableId, - SubnetId: subnetID, - }) - if err != nil { - return nil, fmt.Errorf("failed to associate subnet (%s) to route table (%s): %w", aws.StringValue(subnetID), aws.StringValue(table.RouteTableId), err) - } + if err = addSubnetToRouteTable(ctx, l, client, table, subnetID); err != nil { + return nil, fmt.Errorf("failed to associate subnet (%s) to route table (%s): %w", aws.StringValue(subnetID), aws.StringValue(table.RouteTableId), err) } - l.WithField("subnet", aws.StringValue(subnetID)).Infoln(createdOrFoundMsg) return table, nil } @@ -632,9 +611,10 @@ func (o *vpcState) ensurePublicSubnets(ctx context.Context, logger logrus.FieldL return nil, nil, fmt.Errorf("failed to create public subnets: %w", err) } - err = addSubnetsToRouteTable(ctx, client, publicTable, ids) - if err != nil { - return nil, nil, fmt.Errorf("failed to associate public subnets with public route table (%s): %w", aws.StringValue(publicTable.RouteTableId), err) + for _, subnetID := range ids { + if err = addSubnetToRouteTable(ctx, logger, client, publicTable, subnetID); err != nil { + return nil, nil, fmt.Errorf("failed to associate public subnet (%s) with public route table (%s): %w", aws.StringValue(subnetID), aws.StringValue(publicTable.RouteTableId), err) + } } return ids, zoneMap, nil @@ -660,9 +640,10 @@ func (o *vpcState) ensureEdgePublicSubnets(ctx context.Context, logger logrus.Fi return nil, nil, fmt.Errorf("failed to create public edge subnets: %w", err) } - err = addSubnetsToRouteTable(ctx, client, publicTable, ids) - if err != nil { - return nil, nil, fmt.Errorf("failed to associate public edge subnets with public route table (%s): %w", aws.StringValue(publicTable.RouteTableId), err) + for _, subnetID := range ids { + if err = addSubnetToRouteTable(ctx, logger, client, publicTable, subnetID); err != nil { + return nil, nil, fmt.Errorf("failed to associate public edge subnet (%s) with public route table (%s): %w", aws.StringValue(subnetID), aws.StringValue(publicTable.RouteTableId), err) + } } return ids, zoneMap, nil @@ -1087,33 +1068,37 @@ func splitNetworks(cidrBlock string, numZones int, numEdgeZones int) (*splitOutp return output, nil } -func addSubnetsToRouteTable(ctx context.Context, client ec2iface.EC2API, table *ec2.RouteTable, subnetIDs []*string) error { - for _, subnetID := range subnetIDs { - if hasAssociatedSubnet(table, subnetID) { - continue - } - err := wait.ExponentialBackoffWithContext( - ctx, - defaultBackoff, - func(ctx context.Context) (bool, error) { - _, err := client.AssociateRouteTableWithContext(ctx, &ec2.AssociateRouteTableInput{ - RouteTableId: table.RouteTableId, - SubnetId: subnetID, - }) - if err != nil { - var awsErr awserr.Error - if errors.As(err, &awsErr) && strings.EqualFold(awsErr.Code(), errRouteTableIDNotFound) { - return false, nil - } - return false, err +func addSubnetToRouteTable(ctx context.Context, logger logrus.FieldLogger, client ec2iface.EC2API, table *ec2.RouteTable, subnetID *string) error { + l := logger.WithFields(logrus.Fields{ + "subnet id": aws.StringValue(subnetID), + "table id": aws.StringValue(table.RouteTableId), + }) + if hasAssociatedSubnet(table, subnetID) { + l.Infoln("Subnet already associated with route table") + return nil + } + err := wait.ExponentialBackoffWithContext( + ctx, + defaultBackoff, + func(ctx context.Context) (bool, error) { + _, err := client.AssociateRouteTableWithContext(ctx, &ec2.AssociateRouteTableInput{ + RouteTableId: table.RouteTableId, + SubnetId: subnetID, + }) + if err != nil { + var awsErr awserr.Error + if errors.As(err, &awsErr) && strings.EqualFold(awsErr.Code(), errRouteTableIDNotFound) { + return false, nil } - return true, nil - }, - ) - if err != nil { - return fmt.Errorf("failed to associate subnet (%s) with route table: %w", aws.StringValue(subnetID), err) - } + return false, err + } + return true, nil + }, + ) + if err != nil { + return err } + l.Infoln("Associated subnet with route table") return nil } From 53ffdb2c348a52a7d82600777f781ee0a788a52d Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Mon, 6 Nov 2023 16:57:58 +0100 Subject: [PATCH 30/33] CORS-2886: infra/aws: phz and shared VPC support Private hosted zone and cross-account shared vpc works when installconfig.platform.aws.hostedZone is specified. --- pkg/infrastructure/aws/aws.go | 8 +++++++- pkg/infrastructure/aws/dns.go | 22 +++++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 2e4df85be59..7bce2d54cb3 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -156,7 +156,12 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, } logger.Infoln("Creating DNS resources") + r53Config := awssession.GetR53ClientCfg(awsSession, clusterAWSConfig.InternalZoneRole) + if len(clusterAWSConfig.InternalZoneRole) > 0 { + logger.WithField("role", clusterAWSConfig.InternalZoneRole).Debugln("Assuming role for private hosted zone") + } r53Client := route53.New(awsSession) + assumedRoleClient := route53.New(awsSession, r53Config) dnsInput := dnsInputOptions{ infraID: clusterConfig.ClusterID, region: clusterAWSConfig.Region, @@ -169,8 +174,9 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, lbInternalZoneID: lbOutput.internal.zoneID, lbInternalZoneDNS: lbOutput.internal.dnsName, isPrivateCluster: clusterAWSConfig.PublishStrategy != "External", + internalZone: clusterAWSConfig.InternalZone, } - err = createDNSResources(ctx, logger, r53Client, &dnsInput) + err = createDNSResources(ctx, logger, r53Client, assumedRoleClient, &dnsInput) if err != nil { return nil, fmt.Errorf("failed to create DNS rsources: %w", err) } diff --git a/pkg/infrastructure/aws/dns.go b/pkg/infrastructure/aws/dns.go index 139e4ddf80b..acac560870e 100644 --- a/pkg/infrastructure/aws/dns.go +++ b/pkg/infrastructure/aws/dns.go @@ -31,11 +31,12 @@ type dnsInputOptions struct { lbExternalZoneDNS string lbInternalZoneID string lbInternalZoneDNS string + internalZone string isPrivateCluster bool tags map[string]string } -func createDNSResources(ctx context.Context, logger logrus.FieldLogger, route53Client route53iface.Route53API, input *dnsInputOptions) error { +func createDNSResources(ctx context.Context, logger logrus.FieldLogger, route53Client route53iface.Route53API, assumedRoleClient route53iface.Route53API, input *dnsInputOptions) error { apiName := fmt.Sprintf("api.%s", input.clusterDomain) apiIntName := fmt.Sprintf("api-int.%s", input.clusterDomain) useCNAME := cnameRegions.Has(input.region) @@ -59,21 +60,28 @@ func createDNSResources(ctx context.Context, logger logrus.FieldLogger, route53C logger.Infoln("Created api DNS record for public zone") } - privateZone, err := ensurePrivateZone(ctx, logger, route53Client, input) - if err != nil { - return err + privateZoneID := cleanZoneID(aws.String(input.internalZone)) + if len(privateZoneID) == 0 { + privateZone, err := ensurePrivateZone(ctx, logger, route53Client, input) + if err != nil { + return err + } + privateZoneID = cleanZoneID(privateZone.Id) } - privateZoneID := cleanZoneID(privateZone.Id) + + // Note: assumedRoleClient used below is either the standard route53 client + // or a client with a custom role if one was supplied for a phz belonging + // to a different account than the rest of the cluster resources. // Create API record in private zone - _, err = createRecord(ctx, route53Client, privateZoneID, apiName, input.lbInternalZoneDNS, input.lbInternalZoneID, useCNAME) + _, err := createRecord(ctx, assumedRoleClient, privateZoneID, apiName, input.lbInternalZoneDNS, input.lbInternalZoneID, useCNAME) if err != nil { return fmt.Errorf("failed to create api record (%s) in private zone: %w", apiName, err) } logger.Infoln("Created api DNS record for private zone") // Create API-int record in privat zone - _, err = createRecord(ctx, route53Client, privateZoneID, apiIntName, input.lbInternalZoneDNS, input.lbInternalZoneID, useCNAME) + _, err = createRecord(ctx, assumedRoleClient, privateZoneID, apiIntName, input.lbInternalZoneDNS, input.lbInternalZoneID, useCNAME) if err != nil { return fmt.Errorf("failed to create api-int record (%s) in private zone: %w", apiIntName, err) } From b75d9eb57deaf385ba9dba8c48b9e3080d935d4f Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Mon, 6 Nov 2023 17:04:54 +0100 Subject: [PATCH 31/33] infra/aws: use a boolean for public endpoints. It's a bit better than comparing strings all the time. --- pkg/infrastructure/aws/aws.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index 7bce2d54cb3..a69715ecdc2 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -105,6 +105,8 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, clusterOwnedTag(clusterConfig.ClusterID): ownedTagValue, }) + usePublicEndpoints := clusterAWSConfig.PublishStrategy == "External" + logger := logrus.StandardLogger() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) defer cancel() @@ -148,7 +150,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, privateSubnetIDs: vpcOutput.privateSubnetIDs, publicSubnetIDs: vpcOutput.publicSubnetIDs, tags: tags, - isPrivateCluster: clusterAWSConfig.PublishStrategy != "External", + isPrivateCluster: !usePublicEndpoints, } lbOutput, err := createLoadBalancers(ctx, logger, elbClient, &lbInput) if err != nil { @@ -173,7 +175,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, lbExternalZoneDNS: lbOutput.external.dnsName, lbInternalZoneID: lbOutput.internal.zoneID, lbInternalZoneDNS: lbOutput.internal.dnsName, - isPrivateCluster: clusterAWSConfig.PublishStrategy != "External", + isPrivateCluster: !usePublicEndpoints, internalZone: clusterAWSConfig.InternalZone, } err = createDNSResources(ctx, logger, r53Client, assumedRoleClient, &dnsInput) @@ -186,7 +188,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, infraID: clusterConfig.ClusterID, vpcID: vpcOutput.vpcID, cidrV4Blocks: clusterConfig.MachineV4CIDRs, - isPrivateCluster: clusterAWSConfig.PublishStrategy != "External", + isPrivateCluster: !usePublicEndpoints, tags: tags, } sgOutput, err := createSecurityGroups(ctx, logger, ec2Client, &sgInput) @@ -196,7 +198,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, logger.Infoln("Creating bootstrap resources") bootstrapSubnet := vpcOutput.privateSubnetIDs[0] - if clusterAWSConfig.PublishStrategy == "External" { + if usePublicEndpoints { bootstrapSubnet = vpcOutput.publicSubnetIDs[0] } bootstrapInput := bootstrapInputOptions{ @@ -214,7 +216,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, securityGroupIds: []string{sgOutput.bootstrap, sgOutput.controlPlane}, targetGroupARNs: lbOutput.targetGroupArns, subnetID: bootstrapSubnet, - associatePublicIP: clusterAWSConfig.PublishStrategy == "External", + associatePublicIP: usePublicEndpoints, userData: clusterAWSConfig.BootstrapIgnitionStub, tags: tags, }, @@ -268,7 +270,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, } bootstrapIP := bootstrapOut.privateIP - if clusterAWSConfig.PublishStrategy == "External" { + if usePublicEndpoints { bootstrapIP = bootstrapOut.publicIP } out := &output{ From 6ed69821ce8866515f93cf69bb01e84b15bcdc8e Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Wed, 8 Nov 2023 08:00:51 +0100 Subject: [PATCH 32/33] infra/aws: fix public subnets only clusters We must allow control plane VMs to acquire a public IP if we are running with public subnets only (and no nat gateway). --- pkg/infrastructure/aws/aws.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/infrastructure/aws/aws.go b/pkg/infrastructure/aws/aws.go index a69715ecdc2..6d141814d2a 100644 --- a/pkg/infrastructure/aws/aws.go +++ b/pkg/infrastructure/aws/aws.go @@ -245,7 +245,7 @@ func (a InfraProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, metadataAuth: clusterAWSConfig.MasterMetadataAuthentication, securityGroupIds: append(clusterAWSConfig.MasterSecurityGroups, sgOutput.controlPlane), targetGroupARNs: lbOutput.targetGroupArns, - associatePublicIP: false, + associatePublicIP: len(os.Getenv("OPENSHIFT_INSTALL_AWS_PUBLIC_ONLY")) > 0, userData: clusterConfig.IgnitionMaster, tags: tags, }, From 393fc2e5a6e9fa3721cdc55da9bd51e1e94a1990 Mon Sep 17 00:00:00 2001 From: Rafael Fonseca Date: Wed, 8 Nov 2023 08:05:31 +0100 Subject: [PATCH 33/33] infra: enable AWS SDK provider when building altinfra image --- pkg/infrastructure/platform/platform_altinfra.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/infrastructure/platform/platform_altinfra.go b/pkg/infrastructure/platform/platform_altinfra.go index b1b222e0057..427c524bd61 100644 --- a/pkg/infrastructure/platform/platform_altinfra.go +++ b/pkg/infrastructure/platform/platform_altinfra.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/openshift/installer/pkg/infrastructure" + "github.com/openshift/installer/pkg/infrastructure/aws" awstypes "github.com/openshift/installer/pkg/types/aws" azuretypes "github.com/openshift/installer/pkg/types/azure" vspheretypes "github.com/openshift/installer/pkg/types/vsphere" @@ -16,8 +17,7 @@ import ( func ProviderForPlatform(platform string) (infrastructure.Provider, error) { switch platform { case awstypes.Name: - panic("not implemented") - return nil, nil + return aws.InitializeProvider(), nil case azuretypes.Name: panic("not implemented") return nil, nil