Merge pull request #585 from docker/aci_compose_ls

Implement `compose ls` for ACI
This commit is contained in:
Guillaume Tardif 2020-09-07 15:15:09 +02:00 committed by GitHub
commit dc7934d879
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 87 additions and 33 deletions

View File

@ -134,32 +134,14 @@ type aciContainerService struct {
} }
func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers.Container, error) { func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers.Container, error) {
groupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID) containerGroups, err := getContainerGroups(ctx, cs.ctx.SubscriptionID, cs.ctx.ResourceGroup)
if err != nil {
return nil, err
}
var containerGroups []containerinstance.ContainerGroup
result, err := groupsClient.ListByResourceGroup(ctx, cs.ctx.ResourceGroup)
if err != nil { if err != nil {
return []containers.Container{}, err 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 var res []containers.Container
for _, containerGroup := range containerGroups { for _, group := range containerGroups {
group, err := groupsClient.Get(ctx, cs.ctx.ResourceGroup, *containerGroup.Name)
if err != nil {
return []containers.Container{}, err
}
if group.Containers == nil || len(*group.Containers) < 1 { 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 { for _, container := range *group.Containers {
@ -173,6 +155,34 @@ func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers
return res, nil 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 { func getContainerID(group containerinstance.ContainerGroup, container containerinstance.Container) string {
containerID := *group.Name + composeContainerSeparator + *container.Name containerID := *group.Name + composeContainerSeparator + *container.Name
if _, ok := group.Tags[singleContainerTag]; ok { if _, ok := group.Tags[singleContainerTag]; ok {
@ -446,8 +456,36 @@ func (cs *aciComposeService) Ps(ctx context.Context, project string) ([]compose.
} }
return res, nil return res, nil
} }
func (cs *aciComposeService) List(ctx context.Context, project string) ([]compose.Stack, error) { 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 { func (cs *aciComposeService) Logs(ctx context.Context, project string, w io.Writer) error {

View File

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

View File

@ -57,23 +57,24 @@ type ServiceStatus struct {
Publishers []PortPublisher Publishers []PortPublisher
} }
// State of a compose stack
type State string
const ( const (
// STARTING indicates that stack is being deployed // STARTING indicates that stack is being deployed
STARTING State = "starting" STARTING string = "Starting"
// RUNNING indicates that stack is deployed and services are running // 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 indicates that some stack resources are being recreated
UPDATING State = "updating" UPDATING string = "Updating"
// REMOVING indicates that stack is being deleted // 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 // Stack holds the name and state of a compose application/stack
type Stack struct { type Stack struct {
ID string ID string
Name string Name string
Status State Status string
} }

View File

@ -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) { 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 { if err != nil {
return nil, err return nil, err
} }
@ -325,7 +329,7 @@ func (s sdk) ListStacks(ctx context.Context, name string) ([]compose.Stack, erro
Name: aws.StringValue(stack.StackName), Name: aws.StringValue(stack.StackName),
Status: status, Status: status,
}) })
continue break
} }
} }
} }

View File

@ -98,6 +98,17 @@ func TestCompose(t *testing.T) {
url = "http://" + strings.Replace(fields[3], "->80/http", "", 1) 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) { t.Run("nginx GET", func(t *testing.T) {
checkUp := func(t poll.LogT) poll.Result { checkUp := func(t poll.LogT) poll.Result {
r, err := http.Get(url) r, err := http.Get(url)