Browse Source

Merge pull request #585 from docker/aci_compose_ls

Implement `compose ls` for ACI
Guillaume Tardif 5 years ago
parent
commit
dc7934d879
5 changed files with 87 additions and 33 deletions
  1. 60 22
      aci/backend.go
  2. 1 1
      aci/convert/convert.go
  3. 9 8
      api/compose/api.go
  4. 6 2
      ecs/sdk.go
  5. 11 0
      tests/ecs-e2e/e2e-ecs_test.go

+ 60 - 22
aci/backend.go

@@ -134,32 +134,14 @@ type aciContainerService struct {
 }
 
 func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers.Container, error) {
-	groupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID)
-	if err != nil {
-		return nil, err
-	}
-	var containerGroups []containerinstance.ContainerGroup
-	result, err := groupsClient.ListByResourceGroup(ctx, cs.ctx.ResourceGroup)
+	containerGroups, err := getContainerGroups(ctx, cs.ctx.SubscriptionID, cs.ctx.ResourceGroup)
 	if err != nil {
 		return []containers.Container{}, err
 	}
-
-	for result.NotDone() {
-		containerGroups = append(containerGroups, result.Values()...)
-		if err := result.NextWithContext(ctx); err != nil {
-			return []containers.Container{}, err
-		}
-	}
-
 	var res []containers.Container
-	for _, containerGroup := range containerGroups {
-		group, err := groupsClient.Get(ctx, cs.ctx.ResourceGroup, *containerGroup.Name)
-		if err != nil {
-			return []containers.Container{}, err
-		}
-
+	for _, group := range containerGroups {
 		if group.Containers == nil || len(*group.Containers) < 1 {
-			return []containers.Container{}, fmt.Errorf("no containers found in ACI container group %s", *containerGroup.Name)
+			return []containers.Container{}, fmt.Errorf("no containers found in ACI container group %s", *group.Name)
 		}
 
 		for _, container := range *group.Containers {
@@ -173,6 +155,34 @@ func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers
 	return res, nil
 }
 
+func getContainerGroups(ctx context.Context, subscriptionID string, resourceGroup string) ([]containerinstance.ContainerGroup, error) {
+	groupsClient, err := login.NewContainerGroupsClient(subscriptionID)
+	if err != nil {
+		return nil, err
+	}
+	var containerGroups []containerinstance.ContainerGroup
+	result, err := groupsClient.ListByResourceGroup(ctx, resourceGroup)
+	if err != nil {
+		return []containerinstance.ContainerGroup{}, err
+	}
+
+	for result.NotDone() {
+		containerGroups = append(containerGroups, result.Values()...)
+		if err := result.NextWithContext(ctx); err != nil {
+			return []containerinstance.ContainerGroup{}, err
+		}
+	}
+	var groups []containerinstance.ContainerGroup
+	for _, group := range containerGroups {
+		group, err := groupsClient.Get(ctx, resourceGroup, *group.Name)
+		if err != nil {
+			return []containerinstance.ContainerGroup{}, err
+		}
+		groups = append(groups, group)
+	}
+	return groups, nil
+}
+
 func getContainerID(group containerinstance.ContainerGroup, container containerinstance.Container) string {
 	containerID := *group.Name + composeContainerSeparator + *container.Name
 	if _, ok := group.Tags[singleContainerTag]; ok {
@@ -446,8 +456,36 @@ func (cs *aciComposeService) Ps(ctx context.Context, project string) ([]compose.
 	}
 	return res, nil
 }
+
 func (cs *aciComposeService) List(ctx context.Context, project string) ([]compose.Stack, error) {
-	return nil, errdefs.ErrNotImplemented
+	containerGroups, err := getContainerGroups(ctx, cs.ctx.SubscriptionID, cs.ctx.ResourceGroup)
+	if err != nil {
+		return []compose.Stack{}, err
+	}
+
+	stacks := []compose.Stack{}
+	for _, group := range containerGroups {
+		if _, found := group.Tags[composeContainerTag]; !found {
+			continue
+		}
+		if project != "" && *group.Name != project {
+			continue
+		}
+		state := compose.RUNNING
+		for _, container := range *group.ContainerGroupProperties.Containers {
+			containerState := convert.GetStatus(container, group)
+			if containerState != compose.RUNNING {
+				state = containerState
+				break
+			}
+		}
+		stacks = append(stacks, compose.Stack{
+			ID:     *group.ID,
+			Name:   *group.Name,
+			Status: state,
+		})
+	}
+	return stacks, nil
 }
 
 func (cs *aciComposeService) Logs(ctx context.Context, project string, w io.Writer) error {

+ 1 - 1
aci/convert/convert.go

@@ -451,7 +451,7 @@ func ContainerGroupToContainer(containerID string, cg containerinstance.Containe
 
 // GetStatus returns status for the specified container
 func GetStatus(container containerinstance.Container, group containerinstance.ContainerGroup) string {
-	status := "Unknown"
+	status := compose.UNKNOWN
 	if group.InstanceView != nil && group.InstanceView.State != nil {
 		status = "Node " + *group.InstanceView.State
 	}

+ 9 - 8
api/compose/api.go

@@ -57,23 +57,24 @@ type ServiceStatus struct {
 	Publishers []PortPublisher
 }
 
-// State of a compose stack
-type State string
-
 const (
 	// STARTING indicates that stack is being deployed
-	STARTING State = "starting"
+	STARTING string = "Starting"
 	// RUNNING indicates that stack is deployed and services are running
-	RUNNING State = "running"
+	RUNNING string = "Running"
 	// UPDATING indicates that some stack resources are being recreated
-	UPDATING State = "updating"
+	UPDATING string = "Updating"
 	// REMOVING indicates that stack is being deleted
-	REMOVING State = "removing"
+	REMOVING string = "Removing"
+	// UNKNOWN indicates unknown stack state
+	UNKNOWN string = "Unknown"
+	// FAILED indicates that stack deployment failed
+	FAILED string = "Failed"
 )
 
 // Stack holds the name and state of a compose application/stack
 type Stack struct {
 	ID     string
 	Name   string
-	Status State
+	Status string
 }

+ 6 - 2
ecs/sdk.go

@@ -303,7 +303,11 @@ func (s sdk) GetStackID(ctx context.Context, name string) (string, error) {
 }
 
 func (s sdk) ListStacks(ctx context.Context, name string) ([]compose.Stack, error) {
-	cfStacks, err := s.CF.DescribeStacksWithContext(ctx, &cloudformation.DescribeStacksInput{})
+	params := cloudformation.DescribeStacksInput{}
+	if name != "" {
+		params.StackName = &name
+	}
+	cfStacks, err := s.CF.DescribeStacksWithContext(ctx, &params)
 	if err != nil {
 		return nil, err
 	}
@@ -325,7 +329,7 @@ func (s sdk) ListStacks(ctx context.Context, name string) ([]compose.Stack, erro
 					Name:   aws.StringValue(stack.StackName),
 					Status: status,
 				})
-				continue
+				break
 			}
 		}
 	}

+ 11 - 0
tests/ecs-e2e/e2e-ecs_test.go

@@ -98,6 +98,17 @@ func TestCompose(t *testing.T) {
 		url = "http://" + strings.Replace(fields[3], "->80/http", "", 1)
 	})
 
+	t.Run("compose ls", func(t *testing.T) {
+		res := c.RunDockerCmd("compose", "ls", "--project-name", stack)
+		lines := strings.Split(res.Stdout(), "\n")
+
+		assert.Equal(t, 2, len(lines))
+		fields := strings.Fields(lines[1])
+		assert.Equal(t, 2, len(fields))
+		assert.Equal(t, fields[0], stack)
+		assert.Equal(t, "Running", fields[1])
+	})
+
 	t.Run("nginx GET", func(t *testing.T) {
 		checkUp := func(t poll.LogT) poll.Result {
 			r, err := http.Get(url)