`ps` shows LoadBalancer URL

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-07-03 11:07:08 +02:00
parent 324443deb6
commit f892ee1004
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
5 changed files with 71 additions and 31 deletions

View File

@ -14,7 +14,31 @@ func (b *Backend) Ps(ctx context.Context, project *types.Project) ([]compose.Ser
cluster = project.Name cluster = project.Name
} }
status, err := b.api.DescribeServices(ctx, cluster, project.Name) resources, err := b.api.ListStackResources(ctx, project.Name)
if err != nil {
return nil, err
}
var loadBalancer string
if lb, ok := project.Extensions[compose.ExtensionLB]; ok {
loadBalancer = lb.(string)
}
servicesARN := []string{}
for _, r := range resources {
switch r.Type {
case "AWS::ECS::Service":
servicesARN = append(servicesARN, r.ARN)
case "AWS::ElasticLoadBalancingV2::LoadBalancer":
loadBalancer = r.ARN
}
}
status, err := b.api.DescribeServices(ctx, cluster, servicesARN)
if err != nil {
return nil, err
}
url, err := b.api.GetLoadBalancerURL(ctx, loadBalancer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -26,7 +50,7 @@ func (b *Backend) Ps(ctx context.Context, project *types.Project) ([]compose.Ser
} }
ports := []string{} ports := []string{}
for _, p := range s.Ports { for _, p := range s.Ports {
ports = append(ports, fmt.Sprintf("*:%d->%d/%s", p.Published, p.Target, p.Protocol)) ports = append(ports, fmt.Sprintf("%s:%d->%d/%s", url, p.Published, p.Target, p.Protocol))
} }
state.Ports = ports state.Ports = ports
status[i] = state status[i] = state

View File

@ -105,7 +105,6 @@ func (b Backend) GetLoadBalancer(ctx context.Context, project *types.Project) (s
if !ok { if !ok {
return "", fmt.Errorf("Load Balancer does not exist: %s", lb) return "", fmt.Errorf("Load Balancer does not exist: %s", lb)
} }
return b.api.GetLoadBalancerARN(ctx, lbName)
} }
return "", nil return "", nil
} }

View File

@ -16,13 +16,15 @@ type API interface {
StackExists(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 CreateStack(ctx context.Context, name string, template *cloudformation.Template, parameters map[string]string) error
DeleteStack(ctx context.Context, name string) error DeleteStack(ctx context.Context, name string) error
DescribeServices(ctx context.Context, cluster string, project string) ([]compose.ServiceStatus, error) ListStackResources(ctx context.Context, name string) ([]compose.StackResource, error)
GetStackID(ctx context.Context, name string) (string, error) GetStackID(ctx context.Context, name string) (string, error)
WaitStackComplete(ctx context.Context, name string, operation int) error WaitStackComplete(ctx context.Context, name string, operation int) error
DescribeStackEvents(ctx context.Context, stackID string) ([]*cf.StackEvent, error) DescribeStackEvents(ctx context.Context, stackID string) ([]*cf.StackEvent, error)
LoadBalancerExists(ctx context.Context, name string) (bool, error) DescribeServices(ctx context.Context, cluster string, arns []string) ([]compose.ServiceStatus, error)
GetLoadBalancerARN(ctx context.Context, name string) (string, error)
LoadBalancerExists(ctx context.Context, arn string) (bool, error)
GetLoadBalancerURL(ctx context.Context, arn string) (string, error)
ClusterExists(ctx context.Context, name string) (bool, error) ClusterExists(ctx context.Context, name string) (bool, error)

View File

@ -222,6 +222,27 @@ func (s sdk) DescribeStackEvents(ctx context.Context, stackID string) ([]*cloudf
} }
} }
func (s sdk) ListStackResources(ctx context.Context, name string) ([]compose.StackResource, error) {
// FIXME handle pagination
res, err := s.CF.ListStackResourcesWithContext(ctx, &cloudformation.ListStackResourcesInput{
StackName: aws.String(name),
})
if err != nil {
return nil, err
}
resources := []compose.StackResource{}
for _, r := range res.StackResourceSummaries {
resources = append(resources, compose.StackResource{
LogicalID: *r.LogicalResourceId,
Type: *r.ResourceType,
ARN: *r.PhysicalResourceId,
Status: *r.ResourceStatus,
})
}
return resources, nil
}
func (s sdk) DeleteStack(ctx context.Context, name string) error { func (s sdk) DeleteStack(ctx context.Context, name string) error {
logrus.Debug("Delete CloudFormation stack") logrus.Debug("Delete CloudFormation stack")
_, err := s.CF.DeleteStackWithContext(ctx, &cloudformation.DeleteStackInput{ _, err := s.CF.DeleteStackWithContext(ctx, &cloudformation.DeleteStackInput{
@ -270,7 +291,6 @@ func (s sdk) InspectSecret(ctx context.Context, id string) (compose.Secret, erro
} }
func (s sdk) ListSecrets(ctx context.Context) ([]compose.Secret, error) { func (s sdk) ListSecrets(ctx context.Context) ([]compose.Secret, error) {
logrus.Debug("List secrets ...") logrus.Debug("List secrets ...")
response, err := s.SM.ListSecrets(&secretsmanager.ListSecretsInput{}) response, err := s.SM.ListSecrets(&secretsmanager.ListSecretsInput{})
if err != nil { if err != nil {
@ -336,18 +356,10 @@ func (s sdk) GetLogs(ctx context.Context, name string, consumer compose.LogConsu
} }
} }
func (s sdk) DescribeServices(ctx context.Context, cluster string, project string) ([]compose.ServiceStatus, error) { func (s sdk) DescribeServices(ctx context.Context, cluster string, arns []string) ([]compose.ServiceStatus, error) {
// TODO handle pagination
list, err := s.ECS.ListServicesWithContext(ctx, &ecs.ListServicesInput{
Cluster: aws.String(cluster),
})
if err != nil {
return nil, err
}
services, err := s.ECS.DescribeServicesWithContext(ctx, &ecs.DescribeServicesInput{ services, err := s.ECS.DescribeServicesWithContext(ctx, &ecs.DescribeServicesInput{
Cluster: aws.String(cluster), Cluster: aws.String(cluster),
Services: list.ServiceArns, Services: aws.StringSlice(arns),
Include: aws.StringSlice([]string{"TAGS"}), Include: aws.StringSlice([]string{"TAGS"}),
}) })
if err != nil { if err != nil {
@ -356,17 +368,13 @@ func (s sdk) DescribeServices(ctx context.Context, cluster string, project strin
status := []compose.ServiceStatus{} status := []compose.ServiceStatus{}
for _, service := range services.Services { for _, service := range services.Services {
var name string var name string
var stack string
for _, t := range service.Tags { for _, t := range service.Tags {
switch *t.Key { if *t.Key == compose.ServiceTag {
case compose.ProjectTag:
stack = *t.Value
case compose.ServiceTag:
name = *t.Value name = *t.Value
} }
} }
if stack != project { if name == "" {
continue return nil, fmt.Errorf("service %s doesn't have a %s tag", *service.ServiceArn, compose.ServiceTag)
} }
status = append(status, compose.ServiceStatus{ status = append(status, compose.ServiceStatus{
ID: *service.ServiceName, ID: *service.ServiceName,
@ -410,10 +418,10 @@ func (s sdk) GetPublicIPs(ctx context.Context, interfaces ...string) (map[string
return publicIPs, nil return publicIPs, nil
} }
func (s sdk) LoadBalancerExists(ctx context.Context, name string) (bool, error) { func (s sdk) LoadBalancerExists(ctx context.Context, arn string) (bool, error) {
logrus.Debug("Check if cluster was already created: ", name) logrus.Debug("Check if LoadBalancer exists: ", arn)
lbs, err := s.ELB.DescribeLoadBalancersWithContext(ctx, &elbv2.DescribeLoadBalancersInput{ lbs, err := s.ELB.DescribeLoadBalancersWithContext(ctx, &elbv2.DescribeLoadBalancersInput{
Names: []*string{aws.String(name)}, LoadBalancerArns: []*string{aws.String(arn)},
}) })
if err != nil { if err != nil {
return false, err return false, err
@ -421,13 +429,13 @@ func (s sdk) LoadBalancerExists(ctx context.Context, name string) (bool, error)
return len(lbs.LoadBalancers) > 0, nil return len(lbs.LoadBalancers) > 0, nil
} }
func (s sdk) GetLoadBalancerARN(ctx context.Context, name string) (string, error) { func (s sdk) GetLoadBalancerURL(ctx context.Context, arn string) (string, error) {
logrus.Debug("Check if cluster was already created: ", name) logrus.Debug("Retrieve load balancer URL: ", arn)
lbs, err := s.ELB.DescribeLoadBalancersWithContext(ctx, &elbv2.DescribeLoadBalancersInput{ lbs, err := s.ELB.DescribeLoadBalancersWithContext(ctx, &elbv2.DescribeLoadBalancersInput{
Names: []*string{aws.String(name)}, LoadBalancerArns: []*string{aws.String(arn)},
}) })
if err != nil { if err != nil {
return "", err return "", err
} }
return *lbs.LoadBalancers[0].LoadBalancerArn, nil return *lbs.LoadBalancers[0].DNSName, nil
} }

View File

@ -2,6 +2,13 @@ package compose
import "encoding/json" import "encoding/json"
type StackResource struct {
LogicalID string
Type string
ARN string
Status string
}
type ServiceStatus struct { type ServiceStatus struct {
ID string ID string
Name string Name string