diff --git a/Gopkg.lock b/Gopkg.lock index b3f3d02de3781..7257e04b1004c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -120,6 +120,7 @@ "aws/credentials/ec2rolecreds", "aws/credentials/endpointcreds", "aws/credentials/stscreds", + "aws/csm", "aws/defaults", "aws/ec2metadata", "aws/endpoints", @@ -128,9 +129,12 @@ "aws/signer/v4", "internal/sdkio", "internal/sdkrand", + "internal/sdkuri", "internal/shareddefaults", "private/protocol", "private/protocol/ec2query", + "private/protocol/eventstream", + "private/protocol/eventstream/eventstreamapi", "private/protocol/json/jsonutil", "private/protocol/jsonrpc", "private/protocol/query", @@ -147,6 +151,7 @@ "service/elb", "service/elb/elbiface", "service/elbv2", + "service/elbv2/elbv2iface", "service/iam", "service/iam/iamiface", "service/kms", @@ -155,9 +160,8 @@ "service/s3", "service/sts", ] - pruneopts = "UT" - revision = "5197757a58a794d49d2d0c50a932997157734100" - version = "v1.13.60" + revision = "1825bc12edc3cd682594909d6386f7fcb957c99c" + version = "v1.14.30" [[projects]] digest = "1:ea54f769068039601b42373c98d6d07793dfdffc5baa52f1aaae3d6c86c71007" @@ -2100,6 +2104,7 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 + inputs-digest = "beec19a74f2c84d0145bc939f8ba818026636435f1407cfac67dcda528df9f96" input-imports = [ "cloud.google.com/go/compute/metadata", "github.com/MakeNowJust/heredoc", diff --git a/cloudmock/aws/mockelbv2/BUILD.bazel b/cloudmock/aws/mockelbv2/BUILD.bazel new file mode 100644 index 0000000000000..958a407281aa3 --- /dev/null +++ b/cloudmock/aws/mockelbv2/BUILD.bazel @@ -0,0 +1,14 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["api.go"], + importpath = "k8s.io/kops/cloudmock/aws/mockelbv2", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/aws/aws-sdk-go/aws:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/service/elbv2:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + ], +) diff --git a/cloudmock/aws/mockelbv2/api.go b/cloudmock/aws/mockelbv2/api.go new file mode 100644 index 0000000000000..eb6ecc8c9d794 --- /dev/null +++ b/cloudmock/aws/mockelbv2/api.go @@ -0,0 +1,142 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package mockelbv2 + +import ( + "sync" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/golang/glog" +) + +type MockELBV2 struct { + elbv2iface.ELBV2API + + mutex sync.Mutex + + LoadBalancers map[string]*loadBalancer + TargetGroups map[string]*targetGroup +} + +type loadBalancer struct { + description elbv2.LoadBalancer + tags map[string]string +} + +type targetGroup struct { + description elbv2.TargetGroup + tags map[string]string +} + +func (m *MockELBV2) DescribeLoadBalancers(request *elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + glog.V(2).Infof("DescribeLoadBalancers v2 %v", request) + + if request.PageSize != nil { + glog.Warningf("PageSize not implemented") + } + if request.Marker != nil { + glog.Fatalf("Marker not implemented") + } + + var elbs []*elbv2.LoadBalancer + for _, elb := range m.LoadBalancers { + match := false + + if len(request.LoadBalancerArns) > 0 { + for _, name := range request.LoadBalancerArns { + if aws.StringValue(elb.description.LoadBalancerArn) == aws.StringValue(name) { + match = true + } + } + } else { + match = true + } + + if match { + elbs = append(elbs, &elb.description) + } + } + + return &elbv2.DescribeLoadBalancersOutput{ + LoadBalancers: elbs, + }, nil +} + +func (m *MockELBV2) DescribeLoadBalancersPages(request *elbv2.DescribeLoadBalancersInput, callback func(p *elbv2.DescribeLoadBalancersOutput, lastPage bool) (shouldContinue bool)) error { + // For the mock, we just send everything in one page + page, err := m.DescribeLoadBalancers(request) + if err != nil { + return err + } + + callback(page, false) + + return nil +} + +func (m *MockELBV2) DescribeTargetGroups(request *elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + glog.V(2).Infof("DescribeTargetGroups %v", request) + + if request.PageSize != nil { + glog.Warningf("PageSize not implemented") + } + if request.Marker != nil { + glog.Fatalf("Marker not implemented") + } + + var tgs []*elbv2.TargetGroup + for _, tg := range m.TargetGroups { + match := false + + if len(request.TargetGroupArns) > 0 { + for _, name := range request.TargetGroupArns { + if aws.StringValue(tg.description.TargetGroupArn) == aws.StringValue(name) { + match = true + } + } + } else { + match = true + } + + if match { + tgs = append(tgs, &tg.description) + } + } + + return &elbv2.DescribeTargetGroupsOutput{ + TargetGroups: tgs, + }, nil +} + +func (m *MockELBV2) DescribeTargetGroupsPages(request *elbv2.DescribeTargetGroupsInput, callback func(p *elbv2.DescribeTargetGroupsOutput, lastPage bool) (shouldContinue bool)) error { + page, err := m.DescribeTargetGroups(request) + if err != nil { + return err + } + + callback(page, false) + + return nil +} diff --git a/hack/.packages b/hack/.packages index 11ee757b25c46..220e9ceab2175 100644 --- a/hack/.packages +++ b/hack/.packages @@ -6,6 +6,7 @@ k8s.io/kops/channels/pkg/cmd k8s.io/kops/cloudmock/aws/mockautoscaling k8s.io/kops/cloudmock/aws/mockec2 k8s.io/kops/cloudmock/aws/mockelb +k8s.io/kops/cloudmock/aws/mockelbv2 k8s.io/kops/cloudmock/aws/mockiam k8s.io/kops/cloudmock/aws/mockroute53 k8s.io/kops/cmd/kops diff --git a/pkg/resources/aws/BUILD.bazel b/pkg/resources/aws/BUILD.bazel index 279edd1a68b91..c334ac80f263c 100644 --- a/pkg/resources/aws/BUILD.bazel +++ b/pkg/resources/aws/BUILD.bazel @@ -26,6 +26,7 @@ go_library( "//vendor/github.com/aws/aws-sdk-go/service/cloudformation:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/elb:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/service/elbv2:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/iam:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/route53:go_default_library", "//vendor/github.com/golang/glog:go_default_library", diff --git a/pkg/resources/aws/aws.go b/pkg/resources/aws/aws.go index 4a7e4aeb451bd..4820afcb6ae81 100644 --- a/pkg/resources/aws/aws.go +++ b/pkg/resources/aws/aws.go @@ -28,6 +28,7 @@ import ( "github.com/aws/aws-sdk-go/service/cloudformation" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/elb" + "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/golang/glog" @@ -43,6 +44,7 @@ const ( TypeNatGateway = "nat-gateway" TypeElasticIp = "elastic-ip" TypeLoadBalancer = "load-balancer" + TypeTargetGroup = "target-group" ) type listFn func(fi.Cloud, string) ([]*resources.Resource, error) @@ -70,6 +72,8 @@ func ListResourcesAWS(cloud awsup.AWSCloud, clusterName string) (map[string]*res ListVPCs, // ELBs ListELBs, + ListELBV2s, + ListTargetGroups, // ASG ListAutoScalingGroups, @@ -277,6 +281,24 @@ func matchesElbTags(tags map[string]string, actual []*elb.Tag) bool { return true } +func matchesElbV2Tags(tags map[string]string, actual []*elbv2.Tag) bool { + for k, v := range tags { + found := false + for _, a := range actual { + if aws.StringValue(a.Key) == k { + if aws.StringValue(a.Value) == v { + found = true + break + } + } + } + if !found { + return false + } + } + return true +} + //type DeletableResource interface { // Delete(cloud fi.Cloud) error //} @@ -1351,6 +1373,42 @@ func DeleteELB(cloud fi.Cloud, r *resources.Resource) error { return nil } +func DeleteELBV2(cloud fi.Cloud, r *resources.Resource) error { + c := cloud.(awsup.AWSCloud) + id := r.ID + + glog.V(2).Infof("Deleting ELBV2 %q", id) + request := &elbv2.DeleteLoadBalancerInput{ + LoadBalancerArn: aws.String(id), + } + _, err := c.ELBV2().DeleteLoadBalancer(request) + if err != nil { + if IsDependencyViolation(err) { + return err + } + return fmt.Errorf("error deleting V2 LoadBalancer %q: %v", id, err) + } + return nil +} + +func DeleteTargetGroup(cloud fi.Cloud, r *resources.Resource) error { + c := cloud.(awsup.AWSCloud) + id := r.ID + + glog.V(2).Infof("Deleting TargetGroup %q", id) + request := &elbv2.DeleteTargetGroupInput{ + TargetGroupArn: aws.String(id), + } + _, err := c.ELBV2().DeleteTargetGroup(request) + if err != nil { + if IsDependencyViolation(err) { + return err + } + return fmt.Errorf("error deleting TargetGroup %q: %v", id, err) + } + return nil +} + func DumpELB(op *resources.DumpOperation, r *resources.Resource) error { data := make(map[string]interface{}) data["id"] = r.ID @@ -1442,6 +1500,7 @@ func DescribeELBs(cloud fi.Cloud) ([]*elb.LoadBalancerDescription, map[string][] elb := nameToELB[elbName] elbs = append(elbs, elb) } + return true }) if err != nil { @@ -1450,10 +1509,183 @@ func DescribeELBs(cloud fi.Cloud) ([]*elb.LoadBalancerDescription, map[string][] if innerError != nil { return nil, nil, fmt.Errorf("error describing LoadBalancers: %v", innerError) } - return elbs, elbTags, nil } +// For NLBs and ALBs +func ListELBV2s(cloud fi.Cloud, clusterName string) ([]*resources.Resource, error) { + elbv2s, _, err := DescribeELBV2s(cloud) + if err != nil { + return nil, err + } + + var resourceTrackers []*resources.Resource + for _, elb := range elbv2s { + id := aws.StringValue(elb.LoadBalancerName) + resourceTracker := &resources.Resource{ + Name: id, + ID: string(*elb.LoadBalancerArn), + Type: TypeLoadBalancer, + Deleter: DeleteELBV2, + Dumper: DumpELB, + Obj: elb, + } + + var blocks []string + for _, sg := range elb.SecurityGroups { + blocks = append(blocks, "security-group:"+aws.StringValue(sg)) + } + + blocks = append(blocks, "vpc:"+aws.StringValue(elb.VpcId)) + + resourceTracker.Blocks = blocks + + resourceTrackers = append(resourceTrackers, resourceTracker) + } + + return resourceTrackers, nil +} + +func DescribeELBV2s(cloud fi.Cloud) ([]*elbv2.LoadBalancer, map[string][]*elbv2.Tag, error) { + c := cloud.(awsup.AWSCloud) + tags := c.Tags() + + glog.V(2).Infof("Listing all NLBs and ALBs") + + request := &elbv2.DescribeLoadBalancersInput{} + // ELBV2 DescribeTags has a limit of 20 names, so we set the page size here to 20 also + request.PageSize = aws.Int64(20) + + var elbv2s []*elbv2.LoadBalancer + elbv2Tags := make(map[string][]*elbv2.Tag) + + var innerError error + err := c.ELBV2().DescribeLoadBalancersPages(request, func(p *elbv2.DescribeLoadBalancersOutput, lastPage bool) bool { + if len(p.LoadBalancers) == 0 { + return true + } + + tagRequest := &elbv2.DescribeTagsInput{} + + nameToELB := make(map[string]*elbv2.LoadBalancer) + for _, elb := range p.LoadBalancers { + name := aws.StringValue(elb.LoadBalancerArn) + nameToELB[name] = elb + + tagRequest.ResourceArns = append(tagRequest.ResourceArns, elb.LoadBalancerArn) + } + + tagResponse, err := c.ELBV2().DescribeTags(tagRequest) + if err != nil { + innerError = fmt.Errorf("error listing elb Tags: %v", err) + return false + } + + for _, t := range tagResponse.TagDescriptions { + + elbARN := aws.StringValue(t.ResourceArn) + if !matchesElbV2Tags(tags, t.Tags) { + continue + } + + elbv2Tags[elbARN] = t.Tags + elb := nameToELB[elbARN] + elbv2s = append(elbv2s, elb) + } + + return true + }) + if err != nil { + return nil, nil, fmt.Errorf("error describing LoadBalancers: %v", err) + } + if innerError != nil { + return nil, nil, fmt.Errorf("error describing LoadBalancers: %v", innerError) + } + + return elbv2s, elbv2Tags, nil +} + +func ListTargetGroups(cloud fi.Cloud, clusterName string) ([]*resources.Resource, error) { + targetgroups, _, err := DescribeTargetGroups(cloud) + if err != nil { + return nil, err + } + + var resourceTrackers []*resources.Resource + for _, tg := range targetgroups { + id := aws.StringValue(tg.TargetGroupName) + resourceTracker := &resources.Resource{ + Name: id, + ID: string(*tg.TargetGroupArn), + Type: TypeTargetGroup, + Deleter: DeleteTargetGroup, + Dumper: DumpELB, + Obj: tg, + } + + resourceTrackers = append(resourceTrackers, resourceTracker) + } + return resourceTrackers, nil +} + +func DescribeTargetGroups(cloud fi.Cloud) ([]*elbv2.TargetGroup, map[string][]*elbv2.Tag, error) { + c := cloud.(awsup.AWSCloud) + tags := c.Tags() + + glog.V(2).Infof("Listing all TargetGroups") + + request := &elbv2.DescribeTargetGroupsInput{} + // DescribeTags has a limit of 20 names, so we set the page size here to 20 also + request.PageSize = aws.Int64(20) + + var targetgroups []*elbv2.TargetGroup + targetgroupTags := make(map[string][]*elbv2.Tag) + + var innerError error + err := c.ELBV2().DescribeTargetGroupsPages(request, func(p *elbv2.DescribeTargetGroupsOutput, lastPage bool) bool { + if len(p.TargetGroups) == 0 { + return true + } + + tagRequest := &elbv2.DescribeTagsInput{} + + nameToTargetGroup := make(map[string]*elbv2.TargetGroup) + for _, tg := range p.TargetGroups { + name := aws.StringValue(tg.TargetGroupArn) + nameToTargetGroup[name] = tg + + tagRequest.ResourceArns = append(tagRequest.ResourceArns, tg.TargetGroupArn) + } + + tagResponse, err := c.ELBV2().DescribeTags(tagRequest) + if err != nil { + innerError = fmt.Errorf("error listing TargetGroup Tags: %v", err) + return false + } + + for _, t := range tagResponse.TagDescriptions { + tgARN := aws.StringValue(t.ResourceArn) + if !matchesElbV2Tags(tags, t.Tags) { + continue + } + targetgroupTags[tgARN] = t.Tags + + tg := nameToTargetGroup[tgARN] + targetgroups = append(targetgroups, tg) + } + + return true + }) + if err != nil { + return nil, nil, fmt.Errorf("error describing TargetGroups: %v", err) + } + if innerError != nil { + return nil, nil, fmt.Errorf("error describing TargetGroups: %v", innerError) + } + + return targetgroups, targetgroupTags, nil +} + func DeleteElasticIP(cloud fi.Cloud, t *resources.Resource) error { c := cloud.(awsup.AWSCloud) @@ -1811,6 +2043,13 @@ func FindELBName(tags []*elb.Tag) string { return "" } +func FindELBV2Name(tags []*elbv2.Tag) string { + if name, found := awsup.FindELBV2Tag(tags, "Name"); found { + return name + } + return "" +} + // HasSharedTag looks for the shared tag indicating that the cluster does not own the resource func HasSharedTag(description string, tags []*ec2.Tag, clusterName string) bool { tagKey := "kubernetes.io/cluster/" + clusterName diff --git a/pkg/testutils/BUILD.bazel b/pkg/testutils/BUILD.bazel index b4ac5944b4bc1..0d6d1f03fe5cc 100644 --- a/pkg/testutils/BUILD.bazel +++ b/pkg/testutils/BUILD.bazel @@ -10,6 +10,7 @@ go_library( "//cloudmock/aws/mockautoscaling:go_default_library", "//cloudmock/aws/mockec2:go_default_library", "//cloudmock/aws/mockelb:go_default_library", + "//cloudmock/aws/mockelbv2:go_default_library", "//cloudmock/aws/mockiam:go_default_library", "//cloudmock/aws/mockroute53:go_default_library", "//pkg/apis/kops:go_default_library", diff --git a/pkg/testutils/integrationtestharness.go b/pkg/testutils/integrationtestharness.go index d019661b70447..6963ac4c13aca 100644 --- a/pkg/testutils/integrationtestharness.go +++ b/pkg/testutils/integrationtestharness.go @@ -31,6 +31,7 @@ import ( "k8s.io/kops/cloudmock/aws/mockautoscaling" "k8s.io/kops/cloudmock/aws/mockec2" "k8s.io/kops/cloudmock/aws/mockelb" + "k8s.io/kops/cloudmock/aws/mockelbv2" "k8s.io/kops/cloudmock/aws/mockiam" "k8s.io/kops/cloudmock/aws/mockroute53" "k8s.io/kops/pkg/apis/kops" @@ -105,6 +106,8 @@ func (h *IntegrationTestHarness) SetupMockAWS() *awsup.MockAWSCloud { cloud.MockRoute53 = mockRoute53 mockELB := &mockelb.MockELB{} cloud.MockELB = mockELB + mockELBV2 := &mockelbv2.MockELBV2{} + cloud.MockELBV2 = mockELBV2 mockIAM := &mockiam.MockIAM{} cloud.MockIAM = mockIAM mockAutoscaling := &mockautoscaling.MockAutoscaling{} diff --git a/upup/pkg/fi/cloudup/awsup/BUILD.bazel b/upup/pkg/fi/cloudup/awsup/BUILD.bazel index 26aa193f511b6..01e9c8881c675 100644 --- a/upup/pkg/fi/cloudup/awsup/BUILD.bazel +++ b/upup/pkg/fi/cloudup/awsup/BUILD.bazel @@ -36,6 +36,8 @@ go_library( "//vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/elb:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/elb/elbiface:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/service/elbv2:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/iam:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/iam/iamiface:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/route53:go_default_library", diff --git a/upup/pkg/fi/cloudup/awsup/aws_cloud.go b/upup/pkg/fi/cloudup/awsup/aws_cloud.go index 330ea746c1bb1..6749f8e6c0459 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/aws_cloud.go @@ -33,6 +33,8 @@ import ( "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/aws/aws-sdk-go/service/elb" "github.com/aws/aws-sdk-go/service/elb/elbiface" + "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" @@ -96,6 +98,7 @@ type AWSCloud interface { EC2() ec2iface.EC2API IAM() iamiface.IAMAPI ELB() elbiface.ELBAPI + ELBV2() elbv2iface.ELBV2API Autoscaling() autoscalingiface.AutoScalingAPI Route53() route53iface.Route53API @@ -150,6 +153,7 @@ type awsCloudImplementation struct { ec2 *ec2.EC2 iam *iam.IAM elb *elb.ELB + elbv2 *elbv2.ELBV2 autoscaling *autoscaling.AutoScaling route53 *route53.Route53 @@ -236,6 +240,14 @@ func NewAWSCloud(region string, tags map[string]string) (AWSCloud, error) { c.elb.Handlers.Send.PushFront(requestLogger) c.addHandlers(region, &c.elb.Handlers) + sess, err = session.NewSession(config) + if err != nil { + return c, err + } + c.elbv2 = elbv2.New(sess, config) + c.elbv2.Handlers.Send.PushFront(requestLogger) + c.addHandlers(region, &c.elbv2.Handlers) + sess, err = session.NewSession(config) if err != nil { return c, err @@ -806,6 +818,68 @@ func createELBTags(c AWSCloud, loadBalancerName string, tags map[string]string) } } +func (c *awsCloudImplementation) GetELBV2Tags(ResourceArn string) (map[string]string, error) { + return getELBV2Tags(c, ResourceArn) +} + +func getELBV2Tags(c AWSCloud, ResourceArn string) (map[string]string, error) { + tags := map[string]string{} + + request := &elbv2.DescribeTagsInput{ + ResourceArns: []*string{&ResourceArn}, + } + + attempt := 0 + for { + attempt++ + + response, err := c.ELBV2().DescribeTags(request) + if err != nil { + return nil, fmt.Errorf("error listing tags on %v: %v", ResourceArn, err) + } + + for _, tagset := range response.TagDescriptions { + for _, tag := range tagset.Tags { + tags[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) + } + } + + return tags, nil + } +} + +func (c *awsCloudImplementation) CreateELBV2Tags(ResourceArn string, tags map[string]string) error { + return createELBV2Tags(c, ResourceArn, tags) +} + +func createELBV2Tags(c AWSCloud, ResourceArn string, tags map[string]string) error { + if len(tags) == 0 { + return nil + } + + elbv2Tags := []*elbv2.Tag{} + for k, v := range tags { + elbv2Tags = append(elbv2Tags, &elbv2.Tag{Key: aws.String(k), Value: aws.String(v)}) + } + + attempt := 0 + for { + attempt++ + + request := &elbv2.AddTagsInput{ + Tags: elbv2Tags, + ResourceArns: []*string{&ResourceArn}, + } + + _, err := c.ELBV2().AddTags(request) + if err != nil { + return fmt.Errorf("error creating tags on %v: %v", ResourceArn, err) + } + + return nil + } +} + func (c *awsCloudImplementation) BuildTags(name *string) map[string]string { return buildTags(c.tags, name) } @@ -1053,6 +1127,10 @@ func (c *awsCloudImplementation) ELB() elbiface.ELBAPI { return c.elb } +func (c *awsCloudImplementation) ELBV2() elbv2iface.ELBV2API { + return c.elbv2 +} + func (c *awsCloudImplementation) Autoscaling() autoscalingiface.AutoScalingAPI { return c.autoscaling } diff --git a/upup/pkg/fi/cloudup/awsup/aws_utils.go b/upup/pkg/fi/cloudup/awsup/aws_utils.go index aa3cf9670c202..af0e1ddef8097 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_utils.go +++ b/upup/pkg/fi/cloudup/awsup/aws_utils.go @@ -28,6 +28,7 @@ import ( "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/elb" + elbv2 "github.com/aws/aws-sdk-go/service/elbv2" "github.com/golang/glog" "k8s.io/kops/pkg/apis/kops" ) @@ -152,6 +153,16 @@ func FindELBTag(tags []*elb.Tag, key string) (string, bool) { return "", false } +// FindELBV2Tag find the value of the tag with the specified key +func FindELBV2Tag(tags []*elbv2.Tag, key string) (string, bool) { + for _, tag := range tags { + if key == aws.StringValue(tag.Key) { + return aws.StringValue(tag.Value), true + } + } + return "", false +} + // AWSErrorCode returns the aws error code, if it is an awserr.Error, otherwise "" func AWSErrorCode(err error) string { if awsError, ok := err.(awserr.Error); ok { diff --git a/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go b/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go index acdfdb404ad5b..c16efdf39dcff 100644 --- a/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go @@ -25,6 +25,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/aws/aws-sdk-go/service/elb/elbiface" + "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" "github.com/aws/aws-sdk-go/service/iam/iamiface" "github.com/aws/aws-sdk-go/service/route53/route53iface" "github.com/golang/glog" @@ -76,6 +77,7 @@ type MockCloud struct { MockIAM iamiface.IAMAPI MockRoute53 route53iface.Route53API MockELB elbiface.ELBAPI + MockELBV2 elbv2iface.ELBV2API } func (c *MockAWSCloud) DeleteGroup(g *cloudinstances.CloudInstanceGroup) error { @@ -158,6 +160,14 @@ func (c *MockAWSCloud) CreateELBTags(loadBalancerName string, tags map[string]st return createELBTags(c, loadBalancerName, tags) } +func (c *MockAWSCloud) GetELBV2Tags(ResourceArn string) (map[string]string, error) { + return getELBV2Tags(c, ResourceArn) +} + +func (c *MockAWSCloud) CreateELBV2Tags(ResourceArn string, tags map[string]string) error { + return createELBV2Tags(c, ResourceArn, tags) +} + func (c *MockAWSCloud) DescribeInstance(instanceID string) (*ec2.Instance, error) { return nil, fmt.Errorf("MockAWSCloud DescribeInstance not implemented") } @@ -205,6 +215,13 @@ func (c *MockAWSCloud) ELB() elbiface.ELBAPI { return c.MockELB } +func (c *MockAWSCloud) ELBV2() elbv2iface.ELBV2API { + if c.MockELBV2 == nil { + glog.Fatalf("MockAWSCloud MockELBV2 not set") + } + return c.MockELBV2 +} + func (c *MockAWSCloud) Autoscaling() autoscalingiface.AutoScalingAPI { if c.MockAutoscaling == nil { glog.Fatalf("MockAWSCloud Autoscaling not set") diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/BUILD.bazel b/vendor/github.com/aws/aws-sdk-go/private/protocol/BUILD.bazel index f0f5e37ef4f2f..62fcdc8e9f3ac 100644 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/BUILD.bazel +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/BUILD.bazel @@ -5,6 +5,7 @@ go_library( srcs = [ "idempotency.go", "jsonvalue.go", + "payload.go", "unmarshal.go", ], importmap = "vendor/github.com/aws/aws-sdk-go/private/protocol", @@ -12,6 +13,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//vendor/github.com/aws/aws-sdk-go/aws:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/aws/client/metadata:go_default_library", "//vendor/github.com/aws/aws-sdk-go/aws/request:go_default_library", ], ) diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/BUILD.bazel b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/BUILD.bazel new file mode 100644 index 0000000000000..07ff77dbf0e1b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/BUILD.bazel @@ -0,0 +1,18 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "debug.go", + "decode.go", + "encode.go", + "error.go", + "header.go", + "header_value.go", + "message.go", + ], + importmap = "vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream", + importpath = "github.com/aws/aws-sdk-go/private/protocol/eventstream", + visibility = ["//visibility:public"], + deps = ["//vendor/github.com/aws/aws-sdk-go/aws:go_default_library"], +) diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/debug.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/debug.go new file mode 100644 index 0000000000000..ecc7bf82fa20c --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/debug.go @@ -0,0 +1,144 @@ +package eventstream + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "strconv" +) + +type decodedMessage struct { + rawMessage + Headers decodedHeaders `json:"headers"` +} +type jsonMessage struct { + Length json.Number `json:"total_length"` + HeadersLen json.Number `json:"headers_length"` + PreludeCRC json.Number `json:"prelude_crc"` + Headers decodedHeaders `json:"headers"` + Payload []byte `json:"payload"` + CRC json.Number `json:"message_crc"` +} + +func (d *decodedMessage) UnmarshalJSON(b []byte) (err error) { + var jsonMsg jsonMessage + if err = json.Unmarshal(b, &jsonMsg); err != nil { + return err + } + + d.Length, err = numAsUint32(jsonMsg.Length) + if err != nil { + return err + } + d.HeadersLen, err = numAsUint32(jsonMsg.HeadersLen) + if err != nil { + return err + } + d.PreludeCRC, err = numAsUint32(jsonMsg.PreludeCRC) + if err != nil { + return err + } + d.Headers = jsonMsg.Headers + d.Payload = jsonMsg.Payload + d.CRC, err = numAsUint32(jsonMsg.CRC) + if err != nil { + return err + } + + return nil +} + +func (d *decodedMessage) MarshalJSON() ([]byte, error) { + jsonMsg := jsonMessage{ + Length: json.Number(strconv.Itoa(int(d.Length))), + HeadersLen: json.Number(strconv.Itoa(int(d.HeadersLen))), + PreludeCRC: json.Number(strconv.Itoa(int(d.PreludeCRC))), + Headers: d.Headers, + Payload: d.Payload, + CRC: json.Number(strconv.Itoa(int(d.CRC))), + } + + return json.Marshal(jsonMsg) +} + +func numAsUint32(n json.Number) (uint32, error) { + v, err := n.Int64() + if err != nil { + return 0, fmt.Errorf("failed to get int64 json number, %v", err) + } + + return uint32(v), nil +} + +func (d decodedMessage) Message() Message { + return Message{ + Headers: Headers(d.Headers), + Payload: d.Payload, + } +} + +type decodedHeaders Headers + +func (hs *decodedHeaders) UnmarshalJSON(b []byte) error { + var jsonHeaders []struct { + Name string `json:"name"` + Type valueType `json:"type"` + Value interface{} `json:"value"` + } + + decoder := json.NewDecoder(bytes.NewReader(b)) + decoder.UseNumber() + if err := decoder.Decode(&jsonHeaders); err != nil { + return err + } + + var headers Headers + for _, h := range jsonHeaders { + value, err := valueFromType(h.Type, h.Value) + if err != nil { + return err + } + headers.Set(h.Name, value) + } + (*hs) = decodedHeaders(headers) + + return nil +} + +func valueFromType(typ valueType, val interface{}) (Value, error) { + switch typ { + case trueValueType: + return BoolValue(true), nil + case falseValueType: + return BoolValue(false), nil + case int8ValueType: + v, err := val.(json.Number).Int64() + return Int8Value(int8(v)), err + case int16ValueType: + v, err := val.(json.Number).Int64() + return Int16Value(int16(v)), err + case int32ValueType: + v, err := val.(json.Number).Int64() + return Int32Value(int32(v)), err + case int64ValueType: + v, err := val.(json.Number).Int64() + return Int64Value(v), err + case bytesValueType: + v, err := base64.StdEncoding.DecodeString(val.(string)) + return BytesValue(v), err + case stringValueType: + v, err := base64.StdEncoding.DecodeString(val.(string)) + return StringValue(string(v)), err + case timestampValueType: + v, err := val.(json.Number).Int64() + return TimestampValue(timeFromEpochMilli(v)), err + case uuidValueType: + v, err := base64.StdEncoding.DecodeString(val.(string)) + var tv UUIDValue + copy(tv[:], v) + return tv, err + default: + panic(fmt.Sprintf("unknown type, %s, %T", typ.String(), val)) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go new file mode 100644 index 0000000000000..4b972b2d6664c --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/decode.go @@ -0,0 +1,199 @@ +package eventstream + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "encoding/json" + "fmt" + "hash" + "hash/crc32" + "io" + + "github.com/aws/aws-sdk-go/aws" +) + +// Decoder provides decoding of an Event Stream messages. +type Decoder struct { + r io.Reader + logger aws.Logger +} + +// NewDecoder initializes and returns a Decoder for decoding event +// stream messages from the reader provided. +func NewDecoder(r io.Reader) *Decoder { + return &Decoder{ + r: r, + } +} + +// Decode attempts to decode a single message from the event stream reader. +// Will return the event stream message, or error if Decode fails to read +// the message from the stream. +func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) { + reader := d.r + if d.logger != nil { + debugMsgBuf := bytes.NewBuffer(nil) + reader = io.TeeReader(reader, debugMsgBuf) + defer func() { + logMessageDecode(d.logger, debugMsgBuf, m, err) + }() + } + + crc := crc32.New(crc32IEEETable) + hashReader := io.TeeReader(reader, crc) + + prelude, err := decodePrelude(hashReader, crc) + if err != nil { + return Message{}, err + } + + if prelude.HeadersLen > 0 { + lr := io.LimitReader(hashReader, int64(prelude.HeadersLen)) + m.Headers, err = decodeHeaders(lr) + if err != nil { + return Message{}, err + } + } + + if payloadLen := prelude.PayloadLen(); payloadLen > 0 { + buf, err := decodePayload(payloadBuf, io.LimitReader(hashReader, int64(payloadLen))) + if err != nil { + return Message{}, err + } + m.Payload = buf + } + + msgCRC := crc.Sum32() + if err := validateCRC(reader, msgCRC); err != nil { + return Message{}, err + } + + return m, nil +} + +// UseLogger specifies the Logger that that the decoder should use to log the +// message decode to. +func (d *Decoder) UseLogger(logger aws.Logger) { + d.logger = logger +} + +func logMessageDecode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) { + w := bytes.NewBuffer(nil) + defer func() { logger.Log(w.String()) }() + + fmt.Fprintf(w, "Raw message:\n%s\n", + hex.Dump(msgBuf.Bytes())) + + if decodeErr != nil { + fmt.Fprintf(w, "Decode error: %v\n", decodeErr) + return + } + + rawMsg, err := msg.rawMessage() + if err != nil { + fmt.Fprintf(w, "failed to create raw message, %v\n", err) + return + } + + decodedMsg := decodedMessage{ + rawMessage: rawMsg, + Headers: decodedHeaders(msg.Headers), + } + + fmt.Fprintf(w, "Decoded message:\n") + encoder := json.NewEncoder(w) + if err := encoder.Encode(decodedMsg); err != nil { + fmt.Fprintf(w, "failed to generate decoded message, %v\n", err) + } +} + +func decodePrelude(r io.Reader, crc hash.Hash32) (messagePrelude, error) { + var p messagePrelude + + var err error + p.Length, err = decodeUint32(r) + if err != nil { + return messagePrelude{}, err + } + + p.HeadersLen, err = decodeUint32(r) + if err != nil { + return messagePrelude{}, err + } + + if err := p.ValidateLens(); err != nil { + return messagePrelude{}, err + } + + preludeCRC := crc.Sum32() + if err := validateCRC(r, preludeCRC); err != nil { + return messagePrelude{}, err + } + + p.PreludeCRC = preludeCRC + + return p, nil +} + +func decodePayload(buf []byte, r io.Reader) ([]byte, error) { + w := bytes.NewBuffer(buf[0:0]) + + _, err := io.Copy(w, r) + return w.Bytes(), err +} + +func decodeUint8(r io.Reader) (uint8, error) { + type byteReader interface { + ReadByte() (byte, error) + } + + if br, ok := r.(byteReader); ok { + v, err := br.ReadByte() + return uint8(v), err + } + + var b [1]byte + _, err := io.ReadFull(r, b[:]) + return uint8(b[0]), err +} +func decodeUint16(r io.Reader) (uint16, error) { + var b [2]byte + bs := b[:] + _, err := io.ReadFull(r, bs) + if err != nil { + return 0, err + } + return binary.BigEndian.Uint16(bs), nil +} +func decodeUint32(r io.Reader) (uint32, error) { + var b [4]byte + bs := b[:] + _, err := io.ReadFull(r, bs) + if err != nil { + return 0, err + } + return binary.BigEndian.Uint32(bs), nil +} +func decodeUint64(r io.Reader) (uint64, error) { + var b [8]byte + bs := b[:] + _, err := io.ReadFull(r, bs) + if err != nil { + return 0, err + } + return binary.BigEndian.Uint64(bs), nil +} + +func validateCRC(r io.Reader, expect uint32) error { + msgCRC, err := decodeUint32(r) + if err != nil { + return err + } + + if msgCRC != expect { + return ChecksumError{} + } + + return nil +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go new file mode 100644 index 0000000000000..150a60981d83b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/encode.go @@ -0,0 +1,114 @@ +package eventstream + +import ( + "bytes" + "encoding/binary" + "hash" + "hash/crc32" + "io" +) + +// Encoder provides EventStream message encoding. +type Encoder struct { + w io.Writer + + headersBuf *bytes.Buffer +} + +// NewEncoder initializes and returns an Encoder to encode Event Stream +// messages to an io.Writer. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{ + w: w, + headersBuf: bytes.NewBuffer(nil), + } +} + +// Encode encodes a single EventStream message to the io.Writer the Encoder +// was created with. An error is returned if writing the message fails. +func (e *Encoder) Encode(msg Message) error { + e.headersBuf.Reset() + + err := encodeHeaders(e.headersBuf, msg.Headers) + if err != nil { + return err + } + + crc := crc32.New(crc32IEEETable) + hashWriter := io.MultiWriter(e.w, crc) + + headersLen := uint32(e.headersBuf.Len()) + payloadLen := uint32(len(msg.Payload)) + + if err := encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil { + return err + } + + if headersLen > 0 { + if _, err := io.Copy(hashWriter, e.headersBuf); err != nil { + return err + } + } + + if payloadLen > 0 { + if _, err := hashWriter.Write(msg.Payload); err != nil { + return err + } + } + + msgCRC := crc.Sum32() + return binary.Write(e.w, binary.BigEndian, msgCRC) +} + +func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error { + p := messagePrelude{ + Length: minMsgLen + headersLen + payloadLen, + HeadersLen: headersLen, + } + if err := p.ValidateLens(); err != nil { + return err + } + + err := binaryWriteFields(w, binary.BigEndian, + p.Length, + p.HeadersLen, + ) + if err != nil { + return err + } + + p.PreludeCRC = crc.Sum32() + err = binary.Write(w, binary.BigEndian, p.PreludeCRC) + if err != nil { + return err + } + + return nil +} + +func encodeHeaders(w io.Writer, headers Headers) error { + for _, h := range headers { + hn := headerName{ + Len: uint8(len(h.Name)), + } + copy(hn.Name[:hn.Len], h.Name) + if err := hn.encode(w); err != nil { + return err + } + + if err := h.Value.encode(w); err != nil { + return err + } + } + + return nil +} + +func binaryWriteFields(w io.Writer, order binary.ByteOrder, vs ...interface{}) error { + for _, v := range vs { + if err := binary.Write(w, order, v); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/error.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/error.go new file mode 100644 index 0000000000000..5481ef30796d7 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/error.go @@ -0,0 +1,23 @@ +package eventstream + +import "fmt" + +// LengthError provides the error for items being larger than a maximum length. +type LengthError struct { + Part string + Want int + Have int + Value interface{} +} + +func (e LengthError) Error() string { + return fmt.Sprintf("%s length invalid, %d/%d, %v", + e.Part, e.Want, e.Have, e.Value) +} + +// ChecksumError provides the error for message checksum invalidation errors. +type ChecksumError struct{} + +func (e ChecksumError) Error() string { + return "message checksum mismatch" +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/BUILD.bazel b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/BUILD.bazel new file mode 100644 index 0000000000000..3ef9ed0a3e7f0 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/BUILD.bazel @@ -0,0 +1,17 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "api.go", + "error.go", + ], + importmap = "vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi", + importpath = "github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/aws/aws-sdk-go/aws:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/private/protocol:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream:go_default_library", + ], +) diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/api.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/api.go new file mode 100644 index 0000000000000..97937c8e5980b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/api.go @@ -0,0 +1,196 @@ +package eventstreamapi + +import ( + "fmt" + "io" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/private/protocol" + "github.com/aws/aws-sdk-go/private/protocol/eventstream" +) + +// Unmarshaler provides the interface for unmarshaling a EventStream +// message into a SDK type. +type Unmarshaler interface { + UnmarshalEvent(protocol.PayloadUnmarshaler, eventstream.Message) error +} + +// EventStream headers with specific meaning to async API functionality. +const ( + MessageTypeHeader = `:message-type` // Identifies type of message. + EventMessageType = `event` + ErrorMessageType = `error` + ExceptionMessageType = `exception` + + // Message Events + EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats". + + // Message Error + ErrorCodeHeader = `:error-code` + ErrorMessageHeader = `:error-message` + + // Message Exception + ExceptionTypeHeader = `:exception-type` +) + +// EventReader provides reading from the EventStream of an reader. +type EventReader struct { + reader io.ReadCloser + decoder *eventstream.Decoder + + unmarshalerForEventType func(string) (Unmarshaler, error) + payloadUnmarshaler protocol.PayloadUnmarshaler + + payloadBuf []byte +} + +// NewEventReader returns a EventReader built from the reader and unmarshaler +// provided. Use ReadStream method to start reading from the EventStream. +func NewEventReader( + reader io.ReadCloser, + payloadUnmarshaler protocol.PayloadUnmarshaler, + unmarshalerForEventType func(string) (Unmarshaler, error), +) *EventReader { + return &EventReader{ + reader: reader, + decoder: eventstream.NewDecoder(reader), + payloadUnmarshaler: payloadUnmarshaler, + unmarshalerForEventType: unmarshalerForEventType, + payloadBuf: make([]byte, 10*1024), + } +} + +// UseLogger instructs the EventReader to use the logger and log level +// specified. +func (r *EventReader) UseLogger(logger aws.Logger, logLevel aws.LogLevelType) { + if logger != nil && logLevel.Matches(aws.LogDebugWithEventStreamBody) { + r.decoder.UseLogger(logger) + } +} + +// ReadEvent attempts to read a message from the EventStream and return the +// unmarshaled event value that the message is for. +// +// For EventStream API errors check if the returned error satisfies the +// awserr.Error interface to get the error's Code and Message components. +// +// EventUnmarshalers called with EventStream messages must take copies of the +// message's Payload. The payload will is reused between events read. +func (r *EventReader) ReadEvent() (event interface{}, err error) { + msg, err := r.decoder.Decode(r.payloadBuf) + if err != nil { + return nil, err + } + defer func() { + // Reclaim payload buffer for next message read. + r.payloadBuf = msg.Payload[0:0] + }() + + typ, err := GetHeaderString(msg, MessageTypeHeader) + if err != nil { + return nil, err + } + + switch typ { + case EventMessageType: + return r.unmarshalEventMessage(msg) + case ExceptionMessageType: + err = r.unmarshalEventException(msg) + return nil, err + case ErrorMessageType: + return nil, r.unmarshalErrorMessage(msg) + default: + return nil, fmt.Errorf("unknown eventstream message type, %v", typ) + } +} + +func (r *EventReader) unmarshalEventMessage( + msg eventstream.Message, +) (event interface{}, err error) { + eventType, err := GetHeaderString(msg, EventTypeHeader) + if err != nil { + return nil, err + } + + ev, err := r.unmarshalerForEventType(eventType) + if err != nil { + return nil, err + } + + err = ev.UnmarshalEvent(r.payloadUnmarshaler, msg) + if err != nil { + return nil, err + } + + return ev, nil +} + +func (r *EventReader) unmarshalEventException( + msg eventstream.Message, +) (err error) { + eventType, err := GetHeaderString(msg, ExceptionTypeHeader) + if err != nil { + return err + } + + ev, err := r.unmarshalerForEventType(eventType) + if err != nil { + return err + } + + err = ev.UnmarshalEvent(r.payloadUnmarshaler, msg) + if err != nil { + return err + } + + var ok bool + err, ok = ev.(error) + if !ok { + err = messageError{ + code: "SerializationError", + msg: fmt.Sprintf( + "event stream exception %s mapped to non-error %T, %v", + eventType, ev, ev, + ), + } + } + + return err +} + +func (r *EventReader) unmarshalErrorMessage(msg eventstream.Message) (err error) { + var msgErr messageError + + msgErr.code, err = GetHeaderString(msg, ErrorCodeHeader) + if err != nil { + return err + } + + msgErr.msg, err = GetHeaderString(msg, ErrorMessageHeader) + if err != nil { + return err + } + + return msgErr +} + +// Close closes the EventReader's EventStream reader. +func (r *EventReader) Close() error { + return r.reader.Close() +} + +// GetHeaderString returns the value of the header as a string. If the header +// is not set or the value is not a string an error will be returned. +func GetHeaderString(msg eventstream.Message, headerName string) (string, error) { + headerVal := msg.Headers.Get(headerName) + if headerVal == nil { + return "", fmt.Errorf("error header %s not present", headerName) + } + + v, ok := headerVal.Get().(string) + if !ok { + return "", fmt.Errorf("error header value is not a string, %T", headerVal) + } + + return v, nil +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go new file mode 100644 index 0000000000000..5ea5a988b63e4 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go @@ -0,0 +1,24 @@ +package eventstreamapi + +import "fmt" + +type messageError struct { + code string + msg string +} + +func (e messageError) Code() string { + return e.code +} + +func (e messageError) Message() string { + return e.msg +} + +func (e messageError) Error() string { + return fmt.Sprintf("%s: %s", e.code, e.msg) +} + +func (e messageError) OrigErr() error { + return nil +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header.go new file mode 100644 index 0000000000000..3b44dde2f3230 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header.go @@ -0,0 +1,166 @@ +package eventstream + +import ( + "encoding/binary" + "fmt" + "io" +) + +// Headers are a collection of EventStream header values. +type Headers []Header + +// Header is a single EventStream Key Value header pair. +type Header struct { + Name string + Value Value +} + +// Set associates the name with a value. If the header name already exists in +// the Headers the value will be replaced with the new one. +func (hs *Headers) Set(name string, value Value) { + var i int + for ; i < len(*hs); i++ { + if (*hs)[i].Name == name { + (*hs)[i].Value = value + return + } + } + + *hs = append(*hs, Header{ + Name: name, Value: value, + }) +} + +// Get returns the Value associated with the header. Nil is returned if the +// value does not exist. +func (hs Headers) Get(name string) Value { + for i := 0; i < len(hs); i++ { + if h := hs[i]; h.Name == name { + return h.Value + } + } + return nil +} + +// Del deletes the value in the Headers if it exists. +func (hs *Headers) Del(name string) { + for i := 0; i < len(*hs); i++ { + if (*hs)[i].Name == name { + copy((*hs)[i:], (*hs)[i+1:]) + (*hs) = (*hs)[:len(*hs)-1] + } + } +} + +func decodeHeaders(r io.Reader) (Headers, error) { + hs := Headers{} + + for { + name, err := decodeHeaderName(r) + if err != nil { + if err == io.EOF { + // EOF while getting header name means no more headers + break + } + return nil, err + } + + value, err := decodeHeaderValue(r) + if err != nil { + return nil, err + } + + hs.Set(name, value) + } + + return hs, nil +} + +func decodeHeaderName(r io.Reader) (string, error) { + var n headerName + + var err error + n.Len, err = decodeUint8(r) + if err != nil { + return "", err + } + + name := n.Name[:n.Len] + if _, err := io.ReadFull(r, name); err != nil { + return "", err + } + + return string(name), nil +} + +func decodeHeaderValue(r io.Reader) (Value, error) { + var raw rawValue + + typ, err := decodeUint8(r) + if err != nil { + return nil, err + } + raw.Type = valueType(typ) + + var v Value + + switch raw.Type { + case trueValueType: + v = BoolValue(true) + case falseValueType: + v = BoolValue(false) + case int8ValueType: + var tv Int8Value + err = tv.decode(r) + v = tv + case int16ValueType: + var tv Int16Value + err = tv.decode(r) + v = tv + case int32ValueType: + var tv Int32Value + err = tv.decode(r) + v = tv + case int64ValueType: + var tv Int64Value + err = tv.decode(r) + v = tv + case bytesValueType: + var tv BytesValue + err = tv.decode(r) + v = tv + case stringValueType: + var tv StringValue + err = tv.decode(r) + v = tv + case timestampValueType: + var tv TimestampValue + err = tv.decode(r) + v = tv + case uuidValueType: + var tv UUIDValue + err = tv.decode(r) + v = tv + default: + panic(fmt.Sprintf("unknown value type %d", raw.Type)) + } + + // Error could be EOF, let caller deal with it + return v, err +} + +const maxHeaderNameLen = 255 + +type headerName struct { + Len uint8 + Name [maxHeaderNameLen]byte +} + +func (v headerName) encode(w io.Writer) error { + if err := binary.Write(w, binary.BigEndian, v.Len); err != nil { + return err + } + + _, err := w.Write(v.Name[:v.Len]) + return err +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go new file mode 100644 index 0000000000000..e3fc0766a9ed2 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header_value.go @@ -0,0 +1,501 @@ +package eventstream + +import ( + "encoding/base64" + "encoding/binary" + "fmt" + "io" + "strconv" + "time" +) + +const maxHeaderValueLen = 1<<15 - 1 // 2^15-1 or 32KB - 1 + +// valueType is the EventStream header value type. +type valueType uint8 + +// Header value types +const ( + trueValueType valueType = iota + falseValueType + int8ValueType // Byte + int16ValueType // Short + int32ValueType // Integer + int64ValueType // Long + bytesValueType + stringValueType + timestampValueType + uuidValueType +) + +func (t valueType) String() string { + switch t { + case trueValueType: + return "bool" + case falseValueType: + return "bool" + case int8ValueType: + return "int8" + case int16ValueType: + return "int16" + case int32ValueType: + return "int32" + case int64ValueType: + return "int64" + case bytesValueType: + return "byte_array" + case stringValueType: + return "string" + case timestampValueType: + return "timestamp" + case uuidValueType: + return "uuid" + default: + return fmt.Sprintf("unknown value type %d", uint8(t)) + } +} + +type rawValue struct { + Type valueType + Len uint16 // Only set for variable length slices + Value []byte // byte representation of value, BigEndian encoding. +} + +func (r rawValue) encodeScalar(w io.Writer, v interface{}) error { + return binaryWriteFields(w, binary.BigEndian, + r.Type, + v, + ) +} + +func (r rawValue) encodeFixedSlice(w io.Writer, v []byte) error { + binary.Write(w, binary.BigEndian, r.Type) + + _, err := w.Write(v) + return err +} + +func (r rawValue) encodeBytes(w io.Writer, v []byte) error { + if len(v) > maxHeaderValueLen { + return LengthError{ + Part: "header value", + Want: maxHeaderValueLen, Have: len(v), + Value: v, + } + } + r.Len = uint16(len(v)) + + err := binaryWriteFields(w, binary.BigEndian, + r.Type, + r.Len, + ) + if err != nil { + return err + } + + _, err = w.Write(v) + return err +} + +func (r rawValue) encodeString(w io.Writer, v string) error { + if len(v) > maxHeaderValueLen { + return LengthError{ + Part: "header value", + Want: maxHeaderValueLen, Have: len(v), + Value: v, + } + } + r.Len = uint16(len(v)) + + type stringWriter interface { + WriteString(string) (int, error) + } + + err := binaryWriteFields(w, binary.BigEndian, + r.Type, + r.Len, + ) + if err != nil { + return err + } + + if sw, ok := w.(stringWriter); ok { + _, err = sw.WriteString(v) + } else { + _, err = w.Write([]byte(v)) + } + + return err +} + +func decodeFixedBytesValue(r io.Reader, buf []byte) error { + _, err := io.ReadFull(r, buf) + return err +} + +func decodeBytesValue(r io.Reader) ([]byte, error) { + var raw rawValue + var err error + raw.Len, err = decodeUint16(r) + if err != nil { + return nil, err + } + + buf := make([]byte, raw.Len) + _, err = io.ReadFull(r, buf) + if err != nil { + return nil, err + } + + return buf, nil +} + +func decodeStringValue(r io.Reader) (string, error) { + v, err := decodeBytesValue(r) + return string(v), err +} + +// Value represents the abstract header value. +type Value interface { + Get() interface{} + String() string + valueType() valueType + encode(io.Writer) error +} + +// An BoolValue provides eventstream encoding, and representation +// of a Go bool value. +type BoolValue bool + +// Get returns the underlying type +func (v BoolValue) Get() interface{} { + return bool(v) +} + +// valueType returns the EventStream header value type value. +func (v BoolValue) valueType() valueType { + if v { + return trueValueType + } + return falseValueType +} + +func (v BoolValue) String() string { + return strconv.FormatBool(bool(v)) +} + +// encode encodes the BoolValue into an eventstream binary value +// representation. +func (v BoolValue) encode(w io.Writer) error { + return binary.Write(w, binary.BigEndian, v.valueType()) +} + +// An Int8Value provides eventstream encoding, and representation of a Go +// int8 value. +type Int8Value int8 + +// Get returns the underlying value. +func (v Int8Value) Get() interface{} { + return int8(v) +} + +// valueType returns the EventStream header value type value. +func (Int8Value) valueType() valueType { + return int8ValueType +} + +func (v Int8Value) String() string { + return fmt.Sprintf("0x%02x", int8(v)) +} + +// encode encodes the Int8Value into an eventstream binary value +// representation. +func (v Int8Value) encode(w io.Writer) error { + raw := rawValue{ + Type: v.valueType(), + } + + return raw.encodeScalar(w, v) +} + +func (v *Int8Value) decode(r io.Reader) error { + n, err := decodeUint8(r) + if err != nil { + return err + } + + *v = Int8Value(n) + return nil +} + +// An Int16Value provides eventstream encoding, and representation of a Go +// int16 value. +type Int16Value int16 + +// Get returns the underlying value. +func (v Int16Value) Get() interface{} { + return int16(v) +} + +// valueType returns the EventStream header value type value. +func (Int16Value) valueType() valueType { + return int16ValueType +} + +func (v Int16Value) String() string { + return fmt.Sprintf("0x%04x", int16(v)) +} + +// encode encodes the Int16Value into an eventstream binary value +// representation. +func (v Int16Value) encode(w io.Writer) error { + raw := rawValue{ + Type: v.valueType(), + } + return raw.encodeScalar(w, v) +} + +func (v *Int16Value) decode(r io.Reader) error { + n, err := decodeUint16(r) + if err != nil { + return err + } + + *v = Int16Value(n) + return nil +} + +// An Int32Value provides eventstream encoding, and representation of a Go +// int32 value. +type Int32Value int32 + +// Get returns the underlying value. +func (v Int32Value) Get() interface{} { + return int32(v) +} + +// valueType returns the EventStream header value type value. +func (Int32Value) valueType() valueType { + return int32ValueType +} + +func (v Int32Value) String() string { + return fmt.Sprintf("0x%08x", int32(v)) +} + +// encode encodes the Int32Value into an eventstream binary value +// representation. +func (v Int32Value) encode(w io.Writer) error { + raw := rawValue{ + Type: v.valueType(), + } + return raw.encodeScalar(w, v) +} + +func (v *Int32Value) decode(r io.Reader) error { + n, err := decodeUint32(r) + if err != nil { + return err + } + + *v = Int32Value(n) + return nil +} + +// An Int64Value provides eventstream encoding, and representation of a Go +// int64 value. +type Int64Value int64 + +// Get returns the underlying value. +func (v Int64Value) Get() interface{} { + return int64(v) +} + +// valueType returns the EventStream header value type value. +func (Int64Value) valueType() valueType { + return int64ValueType +} + +func (v Int64Value) String() string { + return fmt.Sprintf("0x%016x", int64(v)) +} + +// encode encodes the Int64Value into an eventstream binary value +// representation. +func (v Int64Value) encode(w io.Writer) error { + raw := rawValue{ + Type: v.valueType(), + } + return raw.encodeScalar(w, v) +} + +func (v *Int64Value) decode(r io.Reader) error { + n, err := decodeUint64(r) + if err != nil { + return err + } + + *v = Int64Value(n) + return nil +} + +// An BytesValue provides eventstream encoding, and representation of a Go +// byte slice. +type BytesValue []byte + +// Get returns the underlying value. +func (v BytesValue) Get() interface{} { + return []byte(v) +} + +// valueType returns the EventStream header value type value. +func (BytesValue) valueType() valueType { + return bytesValueType +} + +func (v BytesValue) String() string { + return base64.StdEncoding.EncodeToString([]byte(v)) +} + +// encode encodes the BytesValue into an eventstream binary value +// representation. +func (v BytesValue) encode(w io.Writer) error { + raw := rawValue{ + Type: v.valueType(), + } + + return raw.encodeBytes(w, []byte(v)) +} + +func (v *BytesValue) decode(r io.Reader) error { + buf, err := decodeBytesValue(r) + if err != nil { + return err + } + + *v = BytesValue(buf) + return nil +} + +// An StringValue provides eventstream encoding, and representation of a Go +// string. +type StringValue string + +// Get returns the underlying value. +func (v StringValue) Get() interface{} { + return string(v) +} + +// valueType returns the EventStream header value type value. +func (StringValue) valueType() valueType { + return stringValueType +} + +func (v StringValue) String() string { + return string(v) +} + +// encode encodes the StringValue into an eventstream binary value +// representation. +func (v StringValue) encode(w io.Writer) error { + raw := rawValue{ + Type: v.valueType(), + } + + return raw.encodeString(w, string(v)) +} + +func (v *StringValue) decode(r io.Reader) error { + s, err := decodeStringValue(r) + if err != nil { + return err + } + + *v = StringValue(s) + return nil +} + +// An TimestampValue provides eventstream encoding, and representation of a Go +// timestamp. +type TimestampValue time.Time + +// Get returns the underlying value. +func (v TimestampValue) Get() interface{} { + return time.Time(v) +} + +// valueType returns the EventStream header value type value. +func (TimestampValue) valueType() valueType { + return timestampValueType +} + +func (v TimestampValue) epochMilli() int64 { + nano := time.Time(v).UnixNano() + msec := nano / int64(time.Millisecond) + return msec +} + +func (v TimestampValue) String() string { + msec := v.epochMilli() + return strconv.FormatInt(msec, 10) +} + +// encode encodes the TimestampValue into an eventstream binary value +// representation. +func (v TimestampValue) encode(w io.Writer) error { + raw := rawValue{ + Type: v.valueType(), + } + + msec := v.epochMilli() + return raw.encodeScalar(w, msec) +} + +func (v *TimestampValue) decode(r io.Reader) error { + n, err := decodeUint64(r) + if err != nil { + return err + } + + *v = TimestampValue(timeFromEpochMilli(int64(n))) + return nil +} + +func timeFromEpochMilli(t int64) time.Time { + secs := t / 1e3 + msec := t % 1e3 + return time.Unix(secs, msec*int64(time.Millisecond)).UTC() +} + +// An UUIDValue provides eventstream encoding, and representation of a UUID +// value. +type UUIDValue [16]byte + +// Get returns the underlying value. +func (v UUIDValue) Get() interface{} { + return v[:] +} + +// valueType returns the EventStream header value type value. +func (UUIDValue) valueType() valueType { + return uuidValueType +} + +func (v UUIDValue) String() string { + return fmt.Sprintf(`%X-%X-%X-%X-%X`, v[0:4], v[4:6], v[6:8], v[8:10], v[10:]) +} + +// encode encodes the UUIDValue into an eventstream binary value +// representation. +func (v UUIDValue) encode(w io.Writer) error { + raw := rawValue{ + Type: v.valueType(), + } + + return raw.encodeFixedSlice(w, v[:]) +} + +func (v *UUIDValue) decode(r io.Reader) error { + tv := (*v)[:] + return decodeFixedBytesValue(r, tv) +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go new file mode 100644 index 0000000000000..2dc012a66e29f --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/message.go @@ -0,0 +1,103 @@ +package eventstream + +import ( + "bytes" + "encoding/binary" + "hash/crc32" +) + +const preludeLen = 8 +const preludeCRCLen = 4 +const msgCRCLen = 4 +const minMsgLen = preludeLen + preludeCRCLen + msgCRCLen +const maxPayloadLen = 1024 * 1024 * 16 // 16MB +const maxHeadersLen = 1024 * 128 // 128KB +const maxMsgLen = minMsgLen + maxHeadersLen + maxPayloadLen + +var crc32IEEETable = crc32.MakeTable(crc32.IEEE) + +// A Message provides the eventstream message representation. +type Message struct { + Headers Headers + Payload []byte +} + +func (m *Message) rawMessage() (rawMessage, error) { + var raw rawMessage + + if len(m.Headers) > 0 { + var headers bytes.Buffer + if err := encodeHeaders(&headers, m.Headers); err != nil { + return rawMessage{}, err + } + raw.Headers = headers.Bytes() + raw.HeadersLen = uint32(len(raw.Headers)) + } + + raw.Length = raw.HeadersLen + uint32(len(m.Payload)) + minMsgLen + + hash := crc32.New(crc32IEEETable) + binaryWriteFields(hash, binary.BigEndian, raw.Length, raw.HeadersLen) + raw.PreludeCRC = hash.Sum32() + + binaryWriteFields(hash, binary.BigEndian, raw.PreludeCRC) + + if raw.HeadersLen > 0 { + hash.Write(raw.Headers) + } + + // Read payload bytes and update hash for it as well. + if len(m.Payload) > 0 { + raw.Payload = m.Payload + hash.Write(raw.Payload) + } + + raw.CRC = hash.Sum32() + + return raw, nil +} + +type messagePrelude struct { + Length uint32 + HeadersLen uint32 + PreludeCRC uint32 +} + +func (p messagePrelude) PayloadLen() uint32 { + return p.Length - p.HeadersLen - minMsgLen +} + +func (p messagePrelude) ValidateLens() error { + if p.Length == 0 || p.Length > maxMsgLen { + return LengthError{ + Part: "message prelude", + Want: maxMsgLen, + Have: int(p.Length), + } + } + if p.HeadersLen > maxHeadersLen { + return LengthError{ + Part: "message headers", + Want: maxHeadersLen, + Have: int(p.HeadersLen), + } + } + if payloadLen := p.PayloadLen(); payloadLen > maxPayloadLen { + return LengthError{ + Part: "message payload", + Want: maxPayloadLen, + Have: int(payloadLen), + } + } + + return nil +} + +type rawMessage struct { + messagePrelude + + Headers []byte + Payload []byte + + CRC uint32 +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/payload.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/payload.go new file mode 100644 index 0000000000000..e21614a125011 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/payload.go @@ -0,0 +1,81 @@ +package protocol + +import ( + "io" + "io/ioutil" + "net/http" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" +) + +// PayloadUnmarshaler provides the interface for unmarshaling a payload's +// reader into a SDK shape. +type PayloadUnmarshaler interface { + UnmarshalPayload(io.Reader, interface{}) error +} + +// HandlerPayloadUnmarshal implements the PayloadUnmarshaler from a +// HandlerList. This provides the support for unmarshaling a payload reader to +// a shape without needing a SDK request first. +type HandlerPayloadUnmarshal struct { + Unmarshalers request.HandlerList +} + +// UnmarshalPayload unmarshals the io.Reader payload into the SDK shape using +// the Unmarshalers HandlerList provided. Returns an error if unable +// unmarshaling fails. +func (h HandlerPayloadUnmarshal) UnmarshalPayload(r io.Reader, v interface{}) error { + req := &request.Request{ + HTTPRequest: &http.Request{}, + HTTPResponse: &http.Response{ + StatusCode: 200, + Header: http.Header{}, + Body: ioutil.NopCloser(r), + }, + Data: v, + } + + h.Unmarshalers.Run(req) + + return req.Error +} + +// PayloadMarshaler provides the interface for marshaling a SDK shape into and +// io.Writer. +type PayloadMarshaler interface { + MarshalPayload(io.Writer, interface{}) error +} + +// HandlerPayloadMarshal implements the PayloadMarshaler from a HandlerList. +// This provides support for marshaling a SDK shape into an io.Writer without +// needing a SDK request first. +type HandlerPayloadMarshal struct { + Marshalers request.HandlerList +} + +// MarshalPayload marshals the SDK shape into the io.Writer using the +// Marshalers HandlerList provided. Returns an error if unable if marshal +// fails. +func (h HandlerPayloadMarshal) MarshalPayload(w io.Writer, v interface{}) error { + req := request.New( + aws.Config{}, + metadata.ClientInfo{}, + request.Handlers{}, + nil, + &request.Operation{HTTPMethod: "GET"}, + v, + nil, + ) + + h.Marshalers.Run(req) + + if req.Error != nil { + return req.Error + } + + io.Copy(w, req.GetBody()) + + return nil +} diff --git a/vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface/BUILD.bazel b/vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface/BUILD.bazel new file mode 100644 index 0000000000000..dc63a7507604b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface/BUILD.bazel @@ -0,0 +1,14 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["interface.go"], + importmap = "vendor/github.com/aws/aws-sdk-go/service/elbv2/elbv2iface", + importpath = "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/aws/aws-sdk-go/aws:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/aws/request:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/service/elbv2:go_default_library", + ], +) 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 0000000000000..825c875d185fd --- /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)