From 3194cc9b1617224e3d486cda02a27d2682c59951 Mon Sep 17 00:00:00 2001 From: aiordache Date: Thu, 4 Jun 2020 16:28:11 +0200 Subject: [PATCH] allow user defined LB Signed-off-by: aiordache Signed-off-by: Nicolas De Loof --- ecs/pkg/amazon/cloudformation.go | 41 +++++++++++++++++++++++--------- ecs/pkg/amazon/sdk.go | 22 +++++++++++++++++ ecs/pkg/amazon/up.go | 33 +++++++++++++++++++++---- ecs/pkg/amazon/x.go | 1 + 4 files changed, 82 insertions(+), 15 deletions(-) diff --git a/ecs/pkg/amazon/cloudformation.go b/ecs/pkg/amazon/cloudformation.go index 35d2e123e..68f6b3443 100644 --- a/ecs/pkg/amazon/cloudformation.go +++ b/ecs/pkg/amazon/cloudformation.go @@ -25,10 +25,11 @@ import ( ) const ( - ParameterClusterName = "ParameterClusterName" - ParameterVPCId = "ParameterVPCId" - ParameterSubnet1Id = "ParameterSubnet1Id" - ParameterSubnet2Id = "ParameterSubnet2Id" + ParameterClusterName = "ParameterClusterName" + ParameterVPCId = "ParameterVPCId" + ParameterSubnet1Id = "ParameterSubnet1Id" + ParameterSubnet2Id = "ParameterSubnet2Id" + ParameterLoadBalancerARN = "ParameterLoadBalancerARN" ) // Convert a compose project into a CloudFormation template @@ -66,6 +67,11 @@ func (c client) Convert(project *compose.Project) (*cloudformation.Template, err Description: "SubnetId, for Availability Zone 2 in the region in your VPC", } + template.Parameters[ParameterLoadBalancerARN] = cloudformation.Parameter{ + Type: "String", + Description: "Name of the LoadBalancer to connect to (optional)", + } + // Create Cluster is `ParameterClusterName` parameter is not set template.Conditions["CreateCluster"] = cloudformation.Equals("", cloudformation.Ref(ParameterClusterName)) @@ -172,10 +178,19 @@ func (c client) Convert(project *compose.Project) (*cloudformation.Template, err } func (c client) createLoadBalancer(project *compose.Project, template *cloudformation.Template) string { - loadBalancerName := fmt.Sprintf("%sLoadBalancer", strings.Title(project.Name)) - template.Resources[loadBalancerName] = &elasticloadbalancingv2.LoadBalancer{ + + loadBalancerType := "network" + loadBalancerName := fmt.Sprintf( + "%s%sLB", + strings.Title(project.Name), + strings.ToUpper(loadBalancerType[0:1]), + ) + // Create LoadBalancer if `ParameterLoadBalancerName` is not set + template.Conditions["CreateLoadBalancer"] = cloudformation.Equals("", cloudformation.Ref(ParameterLoadBalancerARN)) + + loadBalancer := &elasticloadbalancingv2.LoadBalancer{ Name: loadBalancerName, - Scheme: elbv2.LoadBalancerSchemeEnumInternetFacing, + Scheme: "internet-facing", Subnets: []string{ cloudformation.Ref(ParameterSubnet1Id), cloudformation.Ref(ParameterSubnet2Id), @@ -186,12 +201,16 @@ func (c client) createLoadBalancer(project *compose.Project, template *cloudform Value: project.Name, }, }, - Type: elbv2.LoadBalancerTypeEnumNetwork, + Type: loadBalancerType, + AWSCloudFormationCondition: "CreateLoadBalancer", } - return loadBalancerName + template.Resources[loadBalancerName] = loadBalancer + loadBalancerRef := cloudformation.If("CreateLoadBalancer", cloudformation.Ref(loadBalancerName), cloudformation.Ref(ParameterLoadBalancerARN)) + + return loadBalancerRef } -func (c client) createListener(service types.ServiceConfig, port types.ServicePortConfig, template *cloudformation.Template, targetGroupName string, loadBalancerName string, protocol string) string { +func (c client) createListener(service types.ServiceConfig, port types.ServicePortConfig, template *cloudformation.Template, targetGroupName string, loadBalancerARN string, protocol string) string { listenerName := fmt.Sprintf( "%s%s%dListener", normalizeResourceName(service.Name), @@ -213,7 +232,7 @@ func (c client) createListener(service types.ServiceConfig, port types.ServicePo Type: elbv2.ActionTypeEnumForward, }, }, - LoadBalancerArn: cloudformation.Ref(loadBalancerName), + LoadBalancerArn: loadBalancerARN, Protocol: protocol, Port: int(port.Published), } diff --git a/ecs/pkg/amazon/sdk.go b/ecs/pkg/amazon/sdk.go index 6bc85381b..e074fb11d 100644 --- a/ecs/pkg/amazon/sdk.go +++ b/ecs/pkg/amazon/sdk.go @@ -400,3 +400,25 @@ func (s sdk) GetPublicIPs(ctx context.Context, interfaces ...string) (map[string } return publicIPs, nil } + +func (s sdk) LoadBalancerExists(ctx context.Context, name string) (bool, error) { + logrus.Debug("Check if cluster was already created: ", name) + lbs, err := s.ELB.DescribeLoadBalancersWithContext(ctx, &elbv2.DescribeLoadBalancersInput{ + Names: []*string{aws.String(name)}, + }) + if err != nil { + return false, err + } + return len(lbs.LoadBalancers) > 0, nil +} + +func (s sdk) GetLoadBalancerARN(ctx context.Context, name string) (string, error) { + logrus.Debug("Check if cluster was already created: ", name) + lbs, err := s.ELB.DescribeLoadBalancersWithContext(ctx, &elbv2.DescribeLoadBalancersInput{ + Names: []*string{aws.String(name)}, + }) + if err != nil { + return "", err + } + return *lbs.LoadBalancers[0].LoadBalancerArn, nil +} diff --git a/ecs/pkg/amazon/up.go b/ecs/pkg/amazon/up.go index 21500c381..3c9477247 100644 --- a/ecs/pkg/amazon/up.go +++ b/ecs/pkg/amazon/up.go @@ -42,11 +42,17 @@ func (c *client) ComposeUp(ctx context.Context, project *compose.Project) error return err } + lb, err := c.GetLoadBalancer(ctx, project) + if err != nil { + return err + } + parameters := map[string]string{ - ParameterClusterName: c.Cluster, - ParameterVPCId: vpc, - ParameterSubnet1Id: subNets[0], - ParameterSubnet2Id: subNets[1], + ParameterClusterName: c.Cluster, + ParameterVPCId: vpc, + ParameterSubnet1Id: subNets[0], + ParameterSubnet2Id: subNets[1], + ParameterLoadBalancerARN: lb, } err = c.api.CreateStack(ctx, project.Name, template, parameters) @@ -77,6 +83,22 @@ func (c client) GetVPC(ctx context.Context, project *compose.Project) (string, e return defaultVPC, nil } +func (c client) GetLoadBalancer(ctx context.Context, project *compose.Project) (string, error) { + //check compose file for custom VPC selected + if lb, ok := project.Extras[ExtensionLB]; ok { + lbName := lb.(string) + ok, err := c.api.LoadBalancerExists(ctx, lbName) + if err != nil { + return "", err + } + if !ok { + return "", fmt.Errorf("Load Balancer does not exist: %s", lb) + } + return c.api.GetLoadBalancerARN(ctx, lbName) + } + return "", nil +} + type upAPI interface { waitAPI GetDefaultVPC(ctx context.Context) (string, error) @@ -86,4 +108,7 @@ type upAPI interface { ClusterExists(ctx context.Context, name string) (bool, error) StackExists(ctx context.Context, name string) (bool, error) CreateStack(ctx context.Context, name string, template *cloudformation.Template, parameters map[string]string) error + + LoadBalancerExists(ctx context.Context, name string) (bool, error) + GetLoadBalancerARN(ctx context.Context, name string) (string, error) } diff --git a/ecs/pkg/amazon/x.go b/ecs/pkg/amazon/x.go index 0b022bac2..b16c3d253 100644 --- a/ecs/pkg/amazon/x.go +++ b/ecs/pkg/amazon/x.go @@ -4,4 +4,5 @@ const ( ExtensionSecurityGroup = "x-aws-securitygroup" ExtensionVPC = "x-aws-vpc" ExtensionPullCredentials = "x-aws-pull_credentials" + ExtensionLB = "x-aws-lb" )