mirror of https://github.com/docker/compose.git
`Ps` return ContainerSummary, not Services
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
15040f8473
commit
1d859dc807
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/docker/compose-cli/api/compose"
|
||||
"github.com/docker/compose-cli/context/store"
|
||||
"github.com/docker/compose-cli/errdefs"
|
||||
"github.com/docker/compose-cli/utils/formatter"
|
||||
)
|
||||
|
||||
type aciComposeService struct {
|
||||
|
@ -119,7 +120,7 @@ func (cs *aciComposeService) Down(ctx context.Context, project string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Ps(ctx context.Context, project string) ([]compose.ServiceStatus, error) {
|
||||
func (cs *aciComposeService) Ps(ctx context.Context, project string) ([]compose.ContainerSummary, error) {
|
||||
groupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -134,12 +135,29 @@ func (cs *aciComposeService) Ps(ctx context.Context, project string) ([]compose.
|
|||
return nil, fmt.Errorf("no containers found in ACI container group %s", project)
|
||||
}
|
||||
|
||||
res := []compose.ServiceStatus{}
|
||||
res := []compose.ContainerSummary{}
|
||||
for _, container := range *group.Containers {
|
||||
if isContainerVisible(container, group, false) {
|
||||
continue
|
||||
}
|
||||
res = append(res, convert.ContainerGroupToServiceStatus(getContainerID(group, container), group, container, cs.ctx.Location))
|
||||
var publishers []compose.PortPublisher
|
||||
urls := formatter.PortsToStrings(convert.ToPorts(group.IPAddress, *container.Ports), convert.FQDN(group, cs.ctx.Location))
|
||||
for i, p := range *container.Ports {
|
||||
publishers = append(publishers, compose.PortPublisher{
|
||||
URL: urls[i],
|
||||
TargetPort: int(*p.Port),
|
||||
PublishedPort: int(*p.Port),
|
||||
Protocol: string(p.Protocol),
|
||||
})
|
||||
}
|
||||
res = append(res, compose.ContainerSummary{
|
||||
ID: *container.Name,
|
||||
Name: *container.Name,
|
||||
Project: project,
|
||||
Service: *container.Name,
|
||||
State: convert.GetStatus(container, group),
|
||||
Publishers: publishers,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
|
|
@ -314,13 +314,14 @@ func ContainerGroupToServiceStatus(containerID string, group containerinstance.C
|
|||
return compose.ServiceStatus{
|
||||
ID: containerID,
|
||||
Name: *container.Name,
|
||||
Ports: formatter.PortsToStrings(ToPorts(group.IPAddress, *container.Ports), fqdn(group, region)),
|
||||
Ports: formatter.PortsToStrings(ToPorts(group.IPAddress, *container.Ports), FQDN(group, region)),
|
||||
Replicas: replicas,
|
||||
Desired: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func fqdn(group containerinstance.ContainerGroup, region string) string {
|
||||
// FQDN retrieve the fully qualified domain name for a ContainerGroup
|
||||
func FQDN(group containerinstance.ContainerGroup, region string) string {
|
||||
fqdn := ""
|
||||
if group.IPAddress != nil && group.IPAddress.DNSNameLabel != nil && *group.IPAddress.DNSNameLabel != "" {
|
||||
fqdn = *group.IPAddress.DNSNameLabel + "." + region + ".azurecontainer.io"
|
||||
|
@ -348,7 +349,7 @@ func ContainerGroupToContainer(containerID string, cg containerinstance.Containe
|
|||
|
||||
hostConfig := ToHostConfig(cc, cg)
|
||||
config := &containers.RuntimeConfig{
|
||||
FQDN: fqdn(cg, region),
|
||||
FQDN: FQDN(cg, region),
|
||||
Env: envVars,
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ func (c *composeService) Logs(context.Context, string, compose.LogConsumer) erro
|
|||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (c *composeService) Ps(context.Context, string) ([]compose.ServiceStatus, error) {
|
||||
func (c *composeService) Ps(context.Context, string) ([]compose.ContainerSummary, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ type Service interface {
|
|||
// Logs executes the equivalent to a `compose logs`
|
||||
Logs(ctx context.Context, projectName string, consumer LogConsumer) error
|
||||
// Ps executes the equivalent to a `compose ps`
|
||||
Ps(ctx context.Context, projectName string) ([]ServiceStatus, error)
|
||||
Ps(ctx context.Context, projectName string) ([]ContainerSummary, error)
|
||||
// List executes the equivalent to a `docker stack ls`
|
||||
List(ctx context.Context, projectName string) ([]Stack, error)
|
||||
// Convert translate compose model into backend's native format
|
||||
|
@ -56,6 +56,16 @@ type PortPublisher struct {
|
|||
Protocol string
|
||||
}
|
||||
|
||||
// ContainerSummary hold high-level description of a container
|
||||
type ContainerSummary struct {
|
||||
ID string
|
||||
Name string
|
||||
Project string
|
||||
Service string
|
||||
State string
|
||||
Publishers []PortPublisher
|
||||
}
|
||||
|
||||
// ServiceStatus hold status about a service
|
||||
type ServiceStatus struct {
|
||||
ID string
|
||||
|
|
|
@ -21,12 +21,12 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/api/client"
|
||||
"github.com/docker/compose-cli/api/compose"
|
||||
"github.com/docker/compose-cli/formatter"
|
||||
)
|
||||
|
||||
|
@ -54,44 +54,34 @@ func runPs(ctx context.Context, opts composeOptions) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serviceList, err := c.ComposeService().Ps(ctx, projectName)
|
||||
containers, err := c.ComposeService().Ps(ctx, projectName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if opts.Quiet {
|
||||
for _, s := range serviceList {
|
||||
for _, s := range containers {
|
||||
fmt.Println(s.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
view := viewFromServiceStatusList(serviceList)
|
||||
return formatter.Print(view, opts.Format, os.Stdout,
|
||||
|
||||
sort.Slice(containers, func(i, j int) bool {
|
||||
return containers[i].Name < containers[j].Name
|
||||
})
|
||||
|
||||
return formatter.Print(containers, opts.Format, os.Stdout,
|
||||
func(w io.Writer) {
|
||||
for _, service := range view {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%d/%d\t%s\n", service.ID, service.Name, service.Replicas, service.Desired, strings.Join(service.Ports, ", "))
|
||||
for _, container := range containers {
|
||||
var ports []string
|
||||
for _, p := range container.Publishers {
|
||||
if p.URL == "" {
|
||||
ports = append(ports, fmt.Sprintf("%d/%s", p.TargetPort, p.Protocol))
|
||||
} else {
|
||||
ports = append(ports, fmt.Sprintf("%s->%d/%s", p.URL, p.TargetPort, p.Protocol))
|
||||
}
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\n", container.Name, container.State, strings.Join(ports, ", "))
|
||||
}
|
||||
},
|
||||
"ID", "NAME", "REPLICAS", "PORTS")
|
||||
}
|
||||
|
||||
type serviceStatusView struct {
|
||||
ID string
|
||||
Name string
|
||||
Replicas int
|
||||
Desired int
|
||||
Ports []string
|
||||
}
|
||||
|
||||
func viewFromServiceStatusList(serviceStatusList []compose.ServiceStatus) []serviceStatusView {
|
||||
retList := make([]serviceStatusView, len(serviceStatusList))
|
||||
for i, s := range serviceStatusList {
|
||||
retList[i] = serviceStatusView{
|
||||
ID: s.ID,
|
||||
Name: s.Name,
|
||||
Replicas: s.Replicas,
|
||||
Desired: s.Desired,
|
||||
Ports: s.Ports,
|
||||
}
|
||||
}
|
||||
return retList
|
||||
"NAME", "STATE", "PORTS")
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ type API interface {
|
|||
DeleteSecret(ctx context.Context, id string, recover bool) error
|
||||
GetLogs(ctx context.Context, name string, consumer func(service, container, message string)) error
|
||||
DescribeService(ctx context.Context, cluster string, arn string) (compose.ServiceStatus, error)
|
||||
DescribeServiceTasks(ctx context.Context, cluster string, project string, service string) ([]compose.ContainerSummary, error)
|
||||
getURLWithPortMapping(ctx context.Context, targetGroupArns []string) ([]compose.PortPublisher, error)
|
||||
ListTasks(ctx context.Context, cluster string, family string) ([]string, error)
|
||||
GetPublicIPs(ctx context.Context, interfaces ...string) (map[string]string, error)
|
||||
|
|
|
@ -224,6 +224,21 @@ func (mr *MockAPIMockRecorder) DescribeService(arg0, arg1, arg2 interface{}) *go
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeService", reflect.TypeOf((*MockAPI)(nil).DescribeService), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// DescribeServiceTasks mocks base method
|
||||
func (m *MockAPI) DescribeServiceTasks(arg0 context.Context, arg1, arg2, arg3 string) ([]compose.ContainerSummary, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DescribeServiceTasks", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].([]compose.ContainerSummary)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DescribeServiceTasks indicates an expected call of DescribeServiceTasks
|
||||
func (mr *MockAPIMockRecorder) DescribeServiceTasks(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeServiceTasks", reflect.TypeOf((*MockAPI)(nil).DescribeServiceTasks), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// DescribeStackEvents mocks base method
|
||||
func (m *MockAPI) DescribeStackEvents(arg0 context.Context, arg1 string) ([]*cloudformation.StackEvent, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
|
@ -207,7 +207,7 @@ func (e ecsLocalSimulation) Logs(ctx context.Context, projectName string, consum
|
|||
return cmd.Run()
|
||||
}
|
||||
|
||||
func (e ecsLocalSimulation) Ps(ctx context.Context, projectName string) ([]compose.ServiceStatus, error) {
|
||||
func (e ecsLocalSimulation) Ps(ctx context.Context, projectName string) ([]compose.ContainerSummary, error) {
|
||||
return nil, errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose ps")
|
||||
}
|
||||
func (e ecsLocalSimulation) List(ctx context.Context, projectName string) ([]compose.Stack, error) {
|
||||
|
|
30
ecs/ps.go
30
ecs/ps.go
|
@ -18,13 +18,11 @@ package ecs
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/api/compose"
|
||||
)
|
||||
|
||||
func (b *ecsAPIService) Ps(ctx context.Context, project string) ([]compose.ServiceStatus, error) {
|
||||
func (b *ecsAPIService) Ps(ctx context.Context, project string) ([]compose.ContainerSummary, error) {
|
||||
cluster, err := b.aws.GetStackClusterID(ctx, project)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -38,23 +36,23 @@ func (b *ecsAPIService) Ps(ctx context.Context, project string) ([]compose.Servi
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
status := []compose.ServiceStatus{}
|
||||
summary := []compose.ContainerSummary{}
|
||||
for _, arn := range servicesARN {
|
||||
state, err := b.aws.DescribeService(ctx, cluster, arn)
|
||||
service, err := b.aws.DescribeService(ctx, cluster, arn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ports := []string{}
|
||||
for _, lb := range state.Publishers {
|
||||
ports = append(ports, fmt.Sprintf(
|
||||
"%s:%d->%d/%s",
|
||||
lb.URL,
|
||||
lb.PublishedPort,
|
||||
lb.TargetPort,
|
||||
strings.ToLower(lb.Protocol)))
|
||||
|
||||
tasks, err := b.aws.DescribeServiceTasks(ctx, cluster, project, service.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state.Ports = ports
|
||||
status = append(status, state)
|
||||
|
||||
for i, t := range tasks {
|
||||
t.Publishers = service.Publishers
|
||||
tasks[i] = t
|
||||
}
|
||||
summary = append(summary, tasks...)
|
||||
}
|
||||
return status, nil
|
||||
return summary, nil
|
||||
}
|
||||
|
|
67
ecs/sdk.go
67
ecs/sdk.go
|
@ -819,6 +819,69 @@ func (s sdk) DescribeService(ctx context.Context, cluster string, arn string) (c
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (s sdk) DescribeServiceTasks(ctx context.Context, cluster string, project string, service string) ([]compose.ContainerSummary, error) {
|
||||
var summary []compose.ContainerSummary
|
||||
familly := fmt.Sprintf("%s-%s", project, service)
|
||||
var token *string
|
||||
for {
|
||||
list, err := s.ECS.ListTasks(&ecs.ListTasksInput{
|
||||
Cluster: aws.String(cluster),
|
||||
Family: aws.String(familly),
|
||||
LaunchType: nil,
|
||||
MaxResults: nil,
|
||||
NextToken: token,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(list.TaskArns) == 0 {
|
||||
break
|
||||
}
|
||||
tasks, err := s.ECS.DescribeTasksWithContext(ctx, &ecs.DescribeTasksInput{
|
||||
Cluster: aws.String(cluster),
|
||||
Include: aws.StringSlice([]string{"TAGS"}),
|
||||
Tasks: list.TaskArns,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, t := range tasks.Tasks {
|
||||
var project string
|
||||
var service string
|
||||
for _, tag := range t.Tags {
|
||||
switch aws.StringValue(tag.Key) {
|
||||
case compose.ProjectTag:
|
||||
project = aws.StringValue(tag.Value)
|
||||
case compose.ServiceTag:
|
||||
service = aws.StringValue(tag.Value)
|
||||
}
|
||||
}
|
||||
|
||||
id, err := arn.Parse(aws.StringValue(t.TaskArn))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
summary = append(summary, compose.ContainerSummary{
|
||||
ID: id.String(),
|
||||
Name: id.Resource,
|
||||
Project: project,
|
||||
Service: service,
|
||||
State: aws.StringValue(t.LastStatus),
|
||||
})
|
||||
}
|
||||
|
||||
if list.NextToken == token {
|
||||
break
|
||||
}
|
||||
token = list.NextToken
|
||||
}
|
||||
|
||||
return summary, nil
|
||||
}
|
||||
|
||||
func (s sdk) getURLWithPortMapping(ctx context.Context, targetGroupArns []string) ([]compose.PortPublisher, error) {
|
||||
if len(targetGroupArns) == 0 {
|
||||
return nil, nil
|
||||
|
@ -861,10 +924,10 @@ func (s sdk) getURLWithPortMapping(ctx context.Context, targetGroupArns []string
|
|||
continue
|
||||
}
|
||||
loadBalancers = append(loadBalancers, compose.PortPublisher{
|
||||
URL: aws.StringValue(lb.DNSName),
|
||||
URL: fmt.Sprintf("%s:%d", aws.StringValue(lb.DNSName), aws.Int64Value(tg.Port)),
|
||||
TargetPort: int(aws.Int64Value(tg.Port)),
|
||||
PublishedPort: int(aws.Int64Value(tg.Port)),
|
||||
Protocol: aws.StringValue(tg.Protocol),
|
||||
Protocol: strings.ToLower(aws.StringValue(tg.Protocol)),
|
||||
})
|
||||
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ func (cs *composeService) Down(ctx context.Context, project string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (cs *composeService) Ps(ctx context.Context, project string) ([]compose.ServiceStatus, error) {
|
||||
func (cs *composeService) Ps(ctx context.Context, projectName string) ([]compose.ContainerSummary, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
func (cs *composeService) List(ctx context.Context, project string) ([]compose.Stack, error) {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
package compose
|
|
@ -0,0 +1 @@
|
|||
package compose
|
|
@ -28,8 +28,8 @@ import (
|
|||
"github.com/docker/docker/api/types/filters"
|
||||
)
|
||||
|
||||
func (s *composeService) Ps(ctx context.Context, projectName string) ([]compose.ServiceStatus, error) {
|
||||
list, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{
|
||||
func (s *composeService) Ps(ctx context.Context, projectName string) ([]compose.ContainerSummary, error) {
|
||||
containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{
|
||||
Filters: filters.NewArgs(
|
||||
projectFilter(projectName),
|
||||
),
|
||||
|
@ -37,7 +37,33 @@ func (s *composeService) Ps(ctx context.Context, projectName string) ([]compose.
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return containersToServiceStatus(list)
|
||||
|
||||
var summary []compose.ContainerSummary
|
||||
for _, c := range containers {
|
||||
var publishers []compose.PortPublisher
|
||||
for _, p := range c.Ports {
|
||||
var url string
|
||||
if p.PublicPort != 0 {
|
||||
url = fmt.Sprintf("%s:%d", p.IP, p.PublicPort)
|
||||
}
|
||||
publishers = append(publishers, compose.PortPublisher{
|
||||
URL: url,
|
||||
TargetPort: int(p.PrivatePort),
|
||||
PublishedPort: int(p.PublicPort),
|
||||
Protocol: p.Type,
|
||||
})
|
||||
}
|
||||
|
||||
summary = append(summary, compose.ContainerSummary{
|
||||
ID: c.ID,
|
||||
Name: getContainerName(c),
|
||||
Project: c.Labels[projectLabel],
|
||||
Service: c.Labels[serviceLabel],
|
||||
State: c.State,
|
||||
Publishers: publishers,
|
||||
})
|
||||
}
|
||||
return summary, nil
|
||||
}
|
||||
|
||||
func containersToServiceStatus(containers []moby.Container) ([]compose.ServiceStatus, error) {
|
||||
|
|
|
@ -54,11 +54,12 @@ func (p *proxy) Services(ctx context.Context, request *composev1.ComposeServices
|
|||
}
|
||||
projectName = project.Name
|
||||
}
|
||||
services, err := Client(ctx).ComposeService().Ps(ctx, projectName)
|
||||
response := []*composev1.Service{}
|
||||
_, err := Client(ctx).ComposeService().Ps(ctx, projectName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response := []*composev1.Service{}
|
||||
/* FIXME need to create `docker service ls` command to re-introduce this feature
|
||||
for _, service := range services {
|
||||
response = append(response, &composev1.Service{
|
||||
Id: service.ID,
|
||||
|
@ -67,7 +68,7 @@ func (p *proxy) Services(ctx context.Context, request *composev1.ComposeServices
|
|||
Desired: uint32(service.Desired),
|
||||
Ports: service.Ports,
|
||||
})
|
||||
}
|
||||
}*/
|
||||
return &composev1.ComposeServicesResponse{Services: response}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -692,7 +692,7 @@ func TestUpUpdate(t *testing.T) {
|
|||
for _, l := range out {
|
||||
if strings.Contains(l, serverContainer) {
|
||||
webRunning = true
|
||||
strings.Contains(l, ":80->80/tcp")
|
||||
assert.Check(t, strings.Contains(l, ":80->80/tcp"))
|
||||
}
|
||||
}
|
||||
assert.Assert(t, webRunning, "web container not running ; ps:\n"+res.Stdout())
|
||||
|
@ -738,10 +738,10 @@ func TestUpUpdate(t *testing.T) {
|
|||
switch containerID {
|
||||
case wordsContainer:
|
||||
wordsDisplayed = true
|
||||
assert.DeepEqual(t, fields, []string{containerID, "words", "1/1"})
|
||||
assert.DeepEqual(t, fields, []string{containerID, "words", "Running"})
|
||||
case dbContainer:
|
||||
dbDisplayed = true
|
||||
assert.DeepEqual(t, fields, []string{containerID, "db", "1/1"})
|
||||
assert.DeepEqual(t, fields, []string{containerID, "db", "Running"})
|
||||
case serverContainer:
|
||||
webDisplayed = true
|
||||
assert.Equal(t, fields[1], "web")
|
||||
|
|
Loading…
Reference in New Issue