mirror of https://github.com/docker/compose.git
`ps` do list services, not containers
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
cb74f7924e
commit
a1eba59a46
|
@ -101,15 +101,15 @@ func PsCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Co
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tasks, err := backend.Ps(context.Background(), project)
|
||||
status, err := backend.Ps(context.Background(), project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printSection(os.Stdout, len(tasks), func(w io.Writer) {
|
||||
for _, task := range tasks {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\n", task.Name, task.State, strings.Join(task.Ports, " "))
|
||||
printSection(os.Stdout, len(status), func(w io.Writer) {
|
||||
for _, service := range status {
|
||||
fmt.Fprintf(w, "%s\t%s\t%d/%d\t%s\n", service.ID, service.Name, service.Replicas, service.Desired, strings.Join(service.Ports, " "))
|
||||
}
|
||||
}, "NAME", "STATE", "PORTS")
|
||||
}, "ID", "NAME", "REPLICAS", "PORTS")
|
||||
return nil
|
||||
}),
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import (
|
|||
"github.com/awslabs/goformation/v4/cloudformation/tags"
|
||||
"github.com/compose-spec/compose-go/compatibility"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
sdk "github.com/docker/ecs-plugin/pkg/amazon/sdk"
|
||||
"github.com/docker/ecs-plugin/pkg/compose"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -120,7 +119,7 @@ func (b Backend) Convert(project *types.Project) (*cloudformation.Template, erro
|
|||
|
||||
for _, service := range project.Services {
|
||||
|
||||
definition, err := sdk.Convert(project, service)
|
||||
definition, err := Convert(project, service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package sdk
|
||||
package backend
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -3,61 +3,29 @@ package backend
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/ecs-plugin/pkg/compose"
|
||||
)
|
||||
|
||||
func (b *Backend) Ps(ctx context.Context, project *types.Project) ([]compose.TaskStatus, error) {
|
||||
func (b *Backend) Ps(ctx context.Context, project *types.Project) ([]compose.ServiceStatus, error) {
|
||||
cluster := b.Cluster
|
||||
if cluster == "" {
|
||||
cluster = project.Name
|
||||
}
|
||||
arns := []string{}
|
||||
|
||||
status := []compose.ServiceStatus{}
|
||||
for _, service := range project.Services {
|
||||
tasks, err := b.api.ListTasks(ctx, cluster, service.Name)
|
||||
desc, err := b.api.DescribeService(ctx, cluster, service.Name)
|
||||
if err != nil {
|
||||
return []compose.TaskStatus{}, err
|
||||
return nil, err
|
||||
}
|
||||
arns = append(arns, tasks...)
|
||||
}
|
||||
if len(arns) == 0 {
|
||||
return []compose.TaskStatus{}, nil
|
||||
}
|
||||
|
||||
tasks, err := b.api.DescribeTasks(ctx, cluster, arns...)
|
||||
if err != nil {
|
||||
return []compose.TaskStatus{}, err
|
||||
}
|
||||
|
||||
networkInterfaces := []string{}
|
||||
for _, t := range tasks {
|
||||
if t.NetworkInterface != "" {
|
||||
networkInterfaces = append(networkInterfaces, t.NetworkInterface)
|
||||
}
|
||||
}
|
||||
publicIps, err := b.api.GetPublicIPs(ctx, networkInterfaces...)
|
||||
if err != nil {
|
||||
return []compose.TaskStatus{}, err
|
||||
}
|
||||
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return strings.Compare(tasks[i].Service, tasks[j].Service) < 0
|
||||
})
|
||||
|
||||
for i, task := range tasks {
|
||||
ports := []string{}
|
||||
s, err := project.GetService(task.Service)
|
||||
if err != nil {
|
||||
return []compose.TaskStatus{}, err
|
||||
for _, p := range service.Ports {
|
||||
ports = append(ports, fmt.Sprintf("*:%d->%d/%s", p.Published, p.Target, p.Protocol))
|
||||
}
|
||||
for _, p := range s.Ports {
|
||||
ports = append(ports, fmt.Sprintf("%s:%d->%d/%s", publicIps[task.NetworkInterface], p.Published, p.Target, p.Protocol))
|
||||
}
|
||||
tasks[i].Name = s.Name
|
||||
tasks[i].Ports = ports
|
||||
desc.Ports = ports
|
||||
status = append(status, desc)
|
||||
}
|
||||
return tasks, nil
|
||||
return status, nil
|
||||
}
|
||||
|
|
|
@ -104,7 +104,6 @@
|
|||
}
|
||||
},
|
||||
"SchedulingStrategy": "REPLICA",
|
||||
"ServiceName": "simple",
|
||||
"ServiceRegistries": [
|
||||
{
|
||||
"RegistryArn": {
|
||||
|
|
|
@ -104,7 +104,6 @@
|
|||
}
|
||||
},
|
||||
"SchedulingStrategy": "REPLICA",
|
||||
"ServiceName": "simple",
|
||||
"ServiceRegistries": [
|
||||
{
|
||||
"RegistryArn": {
|
||||
|
|
|
@ -49,9 +49,7 @@ type secretsAPI interface {
|
|||
}
|
||||
|
||||
type listAPI interface {
|
||||
ListTasks(ctx context.Context, cluster string, name string) ([]string, error)
|
||||
DescribeTasks(ctx context.Context, cluster string, arns ...string) ([]compose.TaskStatus, error)
|
||||
GetPublicIPs(ctx context.Context, interfaces ...string) (map[string]string, error)
|
||||
DescribeService(ctx context.Context, cluster string, name string) (compose.ServiceStatus, error)
|
||||
}
|
||||
|
||||
type waitAPI interface {
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/docker/ecs-plugin/pkg/amazon (interfaces: API)
|
||||
// Source: github.com/docker/ecs-plugin/pkg/amazon/sdk (interfaces: API)
|
||||
|
||||
// Package amazon is a generated GoMock package.
|
||||
// Package sdk is a generated GoMock package.
|
||||
package sdk
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
"github.com/docker/ecs-plugin/pkg/compose"
|
||||
|
||||
cloudformation "github.com/aws/aws-sdk-go/service/cloudformation"
|
||||
cloudformation0 "github.com/awslabs/goformation/v4/cloudformation"
|
||||
compose "github.com/docker/ecs-plugin/pkg/compose"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockAPI is a mock of API interface
|
||||
|
@ -124,6 +122,21 @@ func (mr *MockAPIMockRecorder) DeleteStack(arg0, arg1 interface{}) *gomock.Call
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStack", reflect.TypeOf((*MockAPI)(nil).DeleteStack), arg0, arg1)
|
||||
}
|
||||
|
||||
// DescribeService mocks base method
|
||||
func (m *MockAPI) DescribeService(arg0 context.Context, arg1, arg2 string) (compose.ServiceStatus, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DescribeService", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(compose.ServiceStatus)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DescribeService indicates an expected call of DescribeService
|
||||
func (mr *MockAPIMockRecorder) DescribeService(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeService", reflect.TypeOf((*MockAPI)(nil).DescribeService), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// DescribeStackEvents mocks base method
|
||||
func (m *MockAPI) DescribeStackEvents(arg0 context.Context, arg1 string) ([]*cloudformation.StackEvent, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -139,26 +152,6 @@ func (mr *MockAPIMockRecorder) DescribeStackEvents(arg0, arg1 interface{}) *gomo
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackEvents", reflect.TypeOf((*MockAPI)(nil).DescribeStackEvents), arg0, arg1)
|
||||
}
|
||||
|
||||
// DescribeTasks mocks base method
|
||||
func (m *MockAPI) DescribeTasks(arg0 context.Context, arg1 string, arg2 ...string) ([]compose.TaskStatus, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "DescribeTasks", varargs...)
|
||||
ret0, _ := ret[0].([]compose.TaskStatus)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DescribeTasks indicates an expected call of DescribeTasks
|
||||
func (mr *MockAPIMockRecorder) DescribeTasks(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeTasks", reflect.TypeOf((*MockAPI)(nil).DescribeTasks), varargs...)
|
||||
}
|
||||
|
||||
// GetDefaultVPC mocks base method
|
||||
func (m *MockAPI) GetDefaultVPC(arg0 context.Context) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -174,6 +167,21 @@ func (mr *MockAPIMockRecorder) GetDefaultVPC(arg0 interface{}) *gomock.Call {
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultVPC", reflect.TypeOf((*MockAPI)(nil).GetDefaultVPC), arg0)
|
||||
}
|
||||
|
||||
// GetLoadBalancerARN mocks base method
|
||||
func (m *MockAPI) GetLoadBalancerARN(arg0 context.Context, arg1 string) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetLoadBalancerARN", arg0, arg1)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetLoadBalancerARN indicates an expected call of GetLoadBalancerARN
|
||||
func (mr *MockAPIMockRecorder) GetLoadBalancerARN(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLoadBalancerARN", reflect.TypeOf((*MockAPI)(nil).GetLoadBalancerARN), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetLogs mocks base method
|
||||
func (m *MockAPI) GetLogs(arg0 context.Context, arg1 string, arg2 compose.LogConsumer) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -188,26 +196,6 @@ func (mr *MockAPIMockRecorder) GetLogs(arg0, arg1, arg2 interface{}) *gomock.Cal
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockAPI)(nil).GetLogs), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// GetPublicIPs mocks base method
|
||||
func (m *MockAPI) GetPublicIPs(arg0 context.Context, arg1 ...string) (map[string]string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "GetPublicIPs", varargs...)
|
||||
ret0, _ := ret[0].(map[string]string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetPublicIPs indicates an expected call of GetPublicIPs
|
||||
func (mr *MockAPIMockRecorder) GetPublicIPs(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublicIPs", reflect.TypeOf((*MockAPI)(nil).GetPublicIPs), varargs...)
|
||||
}
|
||||
|
||||
// GetStackID mocks base method
|
||||
func (m *MockAPI) GetStackID(arg0 context.Context, arg1 string) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -268,19 +256,19 @@ func (mr *MockAPIMockRecorder) ListSecrets(arg0 interface{}) *gomock.Call {
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSecrets", reflect.TypeOf((*MockAPI)(nil).ListSecrets), arg0)
|
||||
}
|
||||
|
||||
// ListTasks mocks base method
|
||||
func (m *MockAPI) ListTasks(arg0 context.Context, arg1, arg2 string) ([]string, error) {
|
||||
// LoadBalancerExists mocks base method
|
||||
func (m *MockAPI) LoadBalancerExists(arg0 context.Context, arg1 string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListTasks", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].([]string)
|
||||
ret := m.ctrl.Call(m, "LoadBalancerExists", arg0, arg1)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListTasks indicates an expected call of ListTasks
|
||||
func (mr *MockAPIMockRecorder) ListTasks(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
// LoadBalancerExists indicates an expected call of LoadBalancerExists
|
||||
func (mr *MockAPIMockRecorder) LoadBalancerExists(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTasks", reflect.TypeOf((*MockAPI)(nil).ListTasks), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadBalancerExists", reflect.TypeOf((*MockAPI)(nil).LoadBalancerExists), arg0, arg1)
|
||||
}
|
||||
|
||||
// StackExists mocks base method
|
||||
|
@ -326,27 +314,3 @@ func (mr *MockAPIMockRecorder) WaitStackComplete(arg0, arg1, arg2 interface{}) *
|
|||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitStackComplete", reflect.TypeOf((*MockAPI)(nil).WaitStackComplete), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// LoadBalancerExists mocks base method
|
||||
func (m *MockAPI) LoadBalancerExists(arg0 context.Context, arg1 string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LoadBalancerExists", arg0, arg1)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// LoadBalancerExists indicates an expected call of VpcExists
|
||||
func (mr *MockAPIMockRecorder) LoadBalancerExists(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadBalancerExists", reflect.TypeOf((*MockAPI)(nil).LoadBalancerExists), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetLoadBalancerARN mocks base method
|
||||
func (m *MockAPI) GetLoadBalancerARN(arg0 context.Context, arg1 string) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetLoadBalancerARN", arg0)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
|
|
@ -341,10 +341,26 @@ func (s sdk) GetLogs(ctx context.Context, name string, consumer compose.LogConsu
|
|||
}
|
||||
}
|
||||
|
||||
func (s sdk) ListTasks(ctx context.Context, cluster string, service string) ([]string, error) {
|
||||
func (s sdk) DescribeService(ctx context.Context, cluster string, name string) (compose.ServiceStatus, error) {
|
||||
services, err := s.ECS.DescribeServicesWithContext(ctx, &ecs.DescribeServicesInput{
|
||||
Cluster: aws.String(cluster),
|
||||
Services: aws.StringSlice([]string{name}),
|
||||
})
|
||||
if err != nil {
|
||||
return compose.ServiceStatus{}, err
|
||||
}
|
||||
return compose.ServiceStatus{
|
||||
ID: *services.Services[0].ServiceName,
|
||||
Name: name,
|
||||
Replicas: int(*services.Services[0].RunningCount),
|
||||
Desired: int(*services.Services[0].DesiredCount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s sdk) ListTasks(ctx context.Context, cluster string, family string) ([]string, error) {
|
||||
tasks, err := s.ECS.ListTasksWithContext(ctx, &ecs.ListTasksInput{
|
||||
Cluster: aws.String(cluster),
|
||||
ServiceName: aws.String(service),
|
||||
Cluster: aws.String(cluster),
|
||||
Family: aws.String(family),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -356,35 +372,6 @@ func (s sdk) ListTasks(ctx context.Context, cluster string, service string) ([]s
|
|||
return arns, nil
|
||||
}
|
||||
|
||||
func (s sdk) DescribeTasks(ctx context.Context, cluster string, arns ...string) ([]compose.TaskStatus, error) {
|
||||
tasks, err := s.ECS.DescribeTasksWithContext(ctx, &ecs.DescribeTasksInput{
|
||||
Cluster: aws.String(cluster),
|
||||
Tasks: aws.StringSlice(arns),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := []compose.TaskStatus{}
|
||||
for _, task := range tasks.Tasks {
|
||||
var networkInterface string
|
||||
for _, attachement := range task.Attachments {
|
||||
if *attachement.Type == "ElasticNetworkInterface" {
|
||||
for _, pair := range attachement.Details {
|
||||
if *pair.Name == "networkInterfaceId" {
|
||||
networkInterface = *pair.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = append(result, compose.TaskStatus{
|
||||
State: *task.LastStatus,
|
||||
Service: strings.Replace(*task.Group, "service:", "", 1),
|
||||
NetworkInterface: networkInterface,
|
||||
})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s sdk) GetPublicIPs(ctx context.Context, interfaces ...string) (map[string]string, error) {
|
||||
desc, err := s.EC2.DescribeNetworkInterfaces(&ec2.DescribeNetworkInterfacesInput{
|
||||
NetworkInterfaceIds: aws.StringSlice(interfaces),
|
||||
|
|
|
@ -14,7 +14,7 @@ type API interface {
|
|||
|
||||
Convert(project *types.Project) (*cloudformation.Template, error)
|
||||
Logs(ctx context.Context, projectName string) error
|
||||
Ps(background context.Context, project *types.Project) ([]TaskStatus, error)
|
||||
Ps(background context.Context, project *types.Project) ([]ServiceStatus, error)
|
||||
|
||||
CreateSecret(ctx context.Context, secret Secret) (string, error)
|
||||
InspectSecret(ctx context.Context, id string) (Secret, error)
|
||||
|
|
|
@ -2,13 +2,12 @@ package compose
|
|||
|
||||
import "encoding/json"
|
||||
|
||||
type TaskStatus struct {
|
||||
Name string
|
||||
State string
|
||||
Service string
|
||||
NetworkInterface string
|
||||
PublicIP string
|
||||
Ports []string
|
||||
type ServiceStatus struct {
|
||||
ID string
|
||||
Name string
|
||||
Replicas int
|
||||
Desired int
|
||||
Ports []string
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
@ -6,9 +6,10 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/ecs-plugin/pkg/amazon/sdk"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/docker/ecs-plugin/pkg/amazon"
|
||||
"github.com/docker/ecs-plugin/pkg/docker"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/fs"
|
||||
|
@ -47,11 +48,11 @@ func composeUpSimpleService(t *testing.T, cmd icmd.Cmd, awsContext docker.AwsCon
|
|||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
sdk := amazon.NewAPI(session)
|
||||
arns, err := sdk.ListTasks(bgContext, t.Name(), t.Name())
|
||||
api := sdk.NewAPI(session)
|
||||
arns, err := api.ListTasks(bgContext, t.Name(), t.Name())
|
||||
assert.NilError(t, err)
|
||||
tasks, err := sdk.DescribeTasks(bgContext, t.Name(), arns...)
|
||||
publicIps, err := sdk.GetPublicIPs(context.Background(), tasks[0].NetworkInterface)
|
||||
tasks, err := api.DescribeTasks(bgContext, t.Name(), arns...)
|
||||
publicIps, err := api.GetPublicIPs(context.Background(), tasks[0].NetworkInterface)
|
||||
assert.NilError(t, err)
|
||||
for _, ip := range publicIps {
|
||||
icmd.RunCommand("curl", "-I", "http://"+ip).Assert(t, icmd.Success)
|
||||
|
|
Loading…
Reference in New Issue