Skip to content

Commit d8255ad

Browse files
committed
Add --desired-status to ps commands
1 parent f2f28a7 commit d8255ad

File tree

17 files changed

+164
-73
lines changed

17 files changed

+164
-73
lines changed

ecs-cli/modules/cli/cluster/cluster_app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ func clusterPS(context *cli.Context, rdwr config.ReadWriter) (project.InfoSet, e
496496

497497
ecsContext := &ecscontext.ECSContext{ECSClient: ecsClient, EC2Client: ec2Client}
498498
task := task.NewTask(ecsContext)
499-
return task.Info(false)
499+
return task.Info(false, context.String(flags.DesiredTaskStatus))
500500
}
501501

502502
// validateCluster validates if the cluster exists in ECS and is in "ACTIVE" state.

ecs-cli/modules/cli/compose/compose_app.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ import (
1717
"os"
1818
"strconv"
1919

20-
log "github.com/sirupsen/logrus"
2120
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/cli/compose/container"
2221
composeFactory "github.com/aws/amazon-ecs-cli/ecs-cli/modules/cli/compose/factory"
2322
ecscompose "github.com/aws/amazon-ecs-cli/ecs-cli/modules/cli/compose/project"
23+
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/commands/flags"
2424
"github.com/flynn/go-shlex"
25+
log "github.com/sirupsen/logrus"
2526
"github.com/urfave/cli"
2627
)
2728

@@ -81,7 +82,7 @@ func ProjectUp(p ecscompose.Project, c *cli.Context) {
8182

8283
// ProjectPs lists the containers.
8384
func ProjectPs(p ecscompose.Project, c *cli.Context) {
84-
allInfo, err := p.Info()
85+
allInfo, err := p.Info(c.String(flags.DesiredTaskStatus))
8586
if err != nil {
8687
log.Fatal(err)
8788
}

ecs-cli/modules/cli/compose/entity/entity.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type ProjectEntity interface {
2828
Create() error
2929
Start() error
3030
Up() error
31-
Info(filterComposeTasks bool) (project.InfoSet, error)
31+
Info(filterComposeTasks bool, desiredStatus string) (project.InfoSet, error)
3232
Run(commandOverrides map[string][]string) error
3333
Scale(count int) error
3434
Stop() error

ecs-cli/modules/cli/compose/entity/entity_helper.go

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -144,18 +144,28 @@ func createRegisterTaskDefinitionRequest(taskDefinition *ecs.TaskDefinition) *ec
144144

145145
// Info returns a formatted list of containers (running and stopped) in the current cluster
146146
// filtered by this project if filterLocal is set to true
147-
func Info(entity ProjectEntity, filterLocal bool) (project.InfoSet, error) {
148-
containers, err := collectContainers(entity, filterLocal)
147+
func Info(entity ProjectEntity, filterLocal bool, desiredStatus string) (project.InfoSet, error) {
148+
if err := validateDesiredStatus(desiredStatus); err != nil {
149+
return nil, err
150+
}
151+
containers, err := collectContainers(entity, filterLocal, desiredStatus)
149152
if err != nil {
150153
return nil, err
151154
}
152155
return composecontainer.ConvertContainersToInfoSet(containers), nil
153156
}
154157

158+
func validateDesiredStatus(desiredStatus string) error {
159+
if desiredStatus != "" && desiredStatus != ecs.DesiredStatusRunning && desiredStatus != ecs.DesiredStatusStopped {
160+
return fmt.Errorf("%s is not a valid value for desired status. Please use %s or %s.", desiredStatus, ecs.DesiredStatusRunning, ecs.DesiredStatusStopped)
161+
}
162+
return nil
163+
}
164+
155165
// collectContainers gets all the desiredStatus=RUNNING and STOPPED tasks with EC2 IP Addresses
156166
// if filterLocal is set to true, it filters tasks created by this project
157-
func collectContainers(entity ProjectEntity, filterLocal bool) ([]composecontainer.Container, error) {
158-
ecsTasks, err := collectTasks(entity, filterLocal)
167+
func collectContainers(entity ProjectEntity, filterLocal bool, desiredStatus string) ([]composecontainer.Container, error) {
168+
ecsTasks, err := collectTasks(entity, filterLocal, desiredStatus)
159169
if err != nil {
160170
return nil, err
161171
}
@@ -168,20 +178,25 @@ func collectContainers(entity ProjectEntity, filterLocal bool) ([]composecontain
168178

169179
// collectTasks gets all the desiredStatus=RUNNING and STOPPED tasks
170180
// if filterLocal is set to true, it filters tasks created by this project
171-
func collectTasks(entity ProjectEntity, filterLocal bool) ([]*ecs.Task, error) {
181+
func collectTasks(entity ProjectEntity, filterLocal bool, desiredStatus string) ([]*ecs.Task, error) {
172182
// TODO, parallelize, perhaps using channels
173183
result := []*ecs.Task{}
174-
ecsTasks, err := CollectTasksWithStatus(entity, ecs.DesiredStatusRunning, filterLocal)
175-
if err != nil {
176-
return nil, err
184+
if desiredStatus == "" || desiredStatus == ecs.DesiredStatusRunning {
185+
ecsTasks, err := CollectTasksWithStatus(entity, ecs.DesiredStatusRunning, filterLocal)
186+
if err != nil {
187+
return nil, err
188+
}
189+
result = append(result, ecsTasks...)
177190
}
178-
result = append(result, ecsTasks...)
179191

180-
ecsTasks, err = CollectTasksWithStatus(entity, ecs.DesiredStatusStopped, filterLocal)
181-
if err != nil {
182-
return nil, err
192+
if desiredStatus == "" || desiredStatus == ecs.DesiredStatusStopped {
193+
ecsTasks, err := CollectTasksWithStatus(entity, ecs.DesiredStatusStopped, filterLocal)
194+
if err != nil {
195+
return nil, err
196+
}
197+
result = append(result, ecsTasks...)
183198
}
184-
result = append(result, ecsTasks...)
199+
185200
return result, nil
186201
}
187202

@@ -212,8 +227,10 @@ func CollectTasksWithStatus(entity ProjectEntity, status string, filterLocal boo
212227

213228
// constructListPagesRequest constructs the request based on the entity type and function parameters
214229
func constructListPagesRequest(entity ProjectEntity, status string, filterLocal bool) *ecs.ListTasksInput {
215-
request := &ecs.ListTasksInput{
216-
DesiredStatus: aws.String(status),
230+
request := &ecs.ListTasksInput{}
231+
232+
if status != "" {
233+
request.DesiredStatus = aws.String(status)
217234
}
218235

219236
// if service set ServiceName to the request, else set Task definition family to filter out (provided filterLocal is true)

ecs-cli/modules/cli/compose/entity/entity_helper_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ func TestValidateFargateParams_WrongNetworkMode(t *testing.T) {
109109
assert.Error(t, err, "Launch Type FARGATE requires network mode to be 'awsvpc'. Set network mode using an ECS Params file.")
110110
}
111111

112+
func TestInfoInvalidStatus(t *testing.T) {
113+
_, err := Info(nil, true, "Not a valid status")
114+
assert.Error(t, err, "Expected error when status was invalid")
115+
}
116+
112117
// NOTE: ValidateFargateParams should technically also check for the presence
113118
// of subnets, but this check already exists in
114119
// utils#ConvertToECSNetworkConfiguration, since it also applies to non-Fargate

ecs-cli/modules/cli/compose/entity/entity_test_helper.go

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@ import (
2727
"github.com/aws/aws-sdk-go/service/ecs"
2828
"github.com/docker/libcompose/project"
2929
"github.com/golang/mock/gomock"
30+
"github.com/sirupsen/logrus"
3031
"github.com/stretchr/testify/assert"
3132
)
3233

3334
type validateListTasksInput func(*ecs.ListTasksInput, string, *testing.T)
3435
type setupEntityForTestInfo func(*context.ECSContext) ProjectEntity
3536

3637
// TestInfo tests ps commands
37-
func TestInfo(setupEntity setupEntityForTestInfo, validateFunc validateListTasksInput, t *testing.T, filterLocal bool) {
38+
func TestInfo(setupEntity setupEntityForTestInfo, validateFunc validateListTasksInput, t *testing.T, filterLocal bool, desiredStatus string) {
3839
projectName := "project"
3940
containerInstance := "containerInstance"
4041
ec2InstanceID := "ec2InstanceID"
@@ -96,33 +97,54 @@ func TestInfo(setupEntity setupEntityForTestInfo, validateFunc validateListTasks
9697
mockEcs := mock_ecs.NewMockECSClient(ctrl)
9798
mockEc2 := mock_ec2.NewMockEC2Client(ctrl)
9899

99-
gomock.InOrder(
100+
var expectedCalls []*gomock.Call
101+
102+
logrus.Info("desiredStatus in TestInfo: " + desiredStatus)
103+
104+
if desiredStatus == "" || desiredStatus == ecs.DesiredStatusRunning {
105+
expectedCalls = append(expectedCalls,
106+
mockEcs.EXPECT().GetTasksPages(gomock.Any(), gomock.Any()).Do(func(x, y interface{}) {
107+
logrus.Info("Running tasks call")
108+
// verify input fields
109+
req := x.(*ecs.ListTasksInput)
110+
validateFunc(req, projectName, t)
111+
assert.Equal(t, ecs.DesiredStatusRunning, aws.StringValue(req.DesiredStatus), "Expected DesiredStatus to be RUNNING")
112+
113+
// execute the function passed as input
114+
funct := y.(ecsClient.ProcessTasksAction)
115+
funct(runningTasks)
116+
}).Return(nil),
117+
)
118+
}
119+
120+
if desiredStatus == "" || desiredStatus == ecs.DesiredStatusStopped {
121+
expectedCalls = append(expectedCalls,
122+
mockEcs.EXPECT().GetTasksPages(gomock.Any(), gomock.Any()).Do(func(x, y interface{}) {
123+
logrus.Info("Stopped tasks call")
124+
// verify input fields
125+
req := x.(*ecs.ListTasksInput)
126+
validateFunc(req, projectName, t)
127+
assert.Equal(t, ecs.DesiredStatusStopped, aws.StringValue(req.DesiredStatus), "Expected DesiredStatus to be STOPPED")
128+
129+
// execute the function passed as input
130+
funct := y.(ecsClient.ProcessTasksAction)
131+
funct(stoppedTasks)
132+
}).Return(nil),
133+
)
134+
}
135+
136+
logrus.Infof("Len of expected list calls: %d", len(expectedCalls))
100137

101-
mockEcs.EXPECT().GetTasksPages(gomock.Any(), gomock.Any()).Do(func(x, y interface{}) {
102-
// verify input fields
103-
req := x.(*ecs.ListTasksInput)
104-
validateFunc(req, projectName, t)
105-
assert.Equal(t, ecs.DesiredStatusRunning, aws.StringValue(req.DesiredStatus), "Expected DesiredStatus to match")
106-
107-
// execute the function passed as input
108-
funct := y.(ecsClient.ProcessTasksAction)
109-
funct(runningTasks)
110-
}).Return(nil),
111-
mockEcs.EXPECT().GetTasksPages(gomock.Any(), gomock.Any()).Do(func(x, y interface{}) {
112-
// verify input fields
113-
req := x.(*ecs.ListTasksInput)
114-
validateFunc(req, projectName, t)
115-
assert.Equal(t, ecs.DesiredStatusStopped, aws.StringValue(req.DesiredStatus), "Expected DesiredStatus to match")
116-
117-
// execute the function passed as input
118-
funct := y.(ecsClient.ProcessTasksAction)
119-
funct(stoppedTasks)
120-
}).Return(nil),
138+
expectedCalls = append(expectedCalls,
121139
mockEcs.EXPECT().DescribeTaskDefinition(taskDefArn).Return(taskDef, nil),
122140
mockEcs.EXPECT().GetEC2InstanceIDs([]*string{&containerInstance}).Return(instanceIdsMap, nil),
123141
mockEc2.EXPECT().DescribeInstances([]*string{&ec2InstanceID}).Return(ec2InstancesMap, nil),
124142
)
125143

144+
gomock.InOrder(
145+
expectedCalls...,
146+
)
147+
126148
context := &context.ECSContext{
127149
ECSClient: mockEcs,
128150
EC2Client: mockEc2,
@@ -132,9 +154,16 @@ func TestInfo(setupEntity setupEntityForTestInfo, validateFunc validateListTasks
132154
},
133155
}
134156
entity := setupEntity(context)
135-
infoSet, err := entity.Info(filterLocal)
157+
infoSet, err := entity.Info(filterLocal, desiredStatus)
136158
assert.NoError(t, err, "Unexpected error when getting info")
137159

138-
expectedCountOfContainers := len(runningTasks) + len(stoppedTasks)
160+
var expectedCountOfContainers int
161+
if desiredStatus == ecs.DesiredStatusRunning {
162+
expectedCountOfContainers = len(runningTasks)
163+
} else if desiredStatus == ecs.DesiredStatusStopped {
164+
expectedCountOfContainers = len(stoppedTasks)
165+
} else if desiredStatus == "" {
166+
expectedCountOfContainers = len(runningTasks) + len(stoppedTasks)
167+
}
139168
assert.Len(t, infoSet, expectedCountOfContainers, "Expected containers count to match")
140169
}

ecs-cli/modules/cli/compose/entity/mock/entity.go

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ecs-cli/modules/cli/compose/entity/service/service.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,11 +355,11 @@ func (s *Service) updateService(ecsService *ecs.Service, newTaskDefinition *ecs.
355355
}
356356

357357
// Info returns a formatted list of containers (running and stopped) started by this service
358-
func (s *Service) Info(filterProjectTasks bool) (project.InfoSet, error) {
358+
func (s *Service) Info(filterProjectTasks bool, desiredStatus string) (project.InfoSet, error) {
359359
// filterProjectTasks is not honored for services, because ECS Services have their
360360
// own custom Group field, overriding that with startedBy=project will result in no tasks
361361
// We should instead filter by ServiceName=service
362-
return entity.Info(s, false)
362+
return entity.Info(s, false, desiredStatus)
363363
}
364364

365365
// Scale the service desired count to be the specified count

ecs-cli/modules/cli/compose/entity/service/service_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ func TestServiceInfo(t *testing.T) {
762762
}, func(req *ecs.ListTasksInput, projectName string, t *testing.T) {
763763
assert.Contains(t, aws.StringValue(req.ServiceName), projectName, "ServiceName should contain ProjectName")
764764
assert.Nil(t, req.StartedBy, "StartedBy should be nil")
765-
}, t, true)
765+
}, t, true, "")
766766
}
767767

768768
////////////////

ecs-cli/modules/cli/compose/entity/task/task.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ func (t *Task) Up() error {
106106

107107
// Info returns a formatted list of containers (running and stopped) in the current cluster
108108
// filtered by this project if filterLocal is set to true
109-
func (t *Task) Info(filterLocal bool) (project.InfoSet, error) {
110-
return entity.Info(t, filterLocal)
109+
func (t *Task) Info(filterLocal bool, desiredStatus string) (project.InfoSet, error) {
110+
return entity.Info(t, filterLocal, desiredStatus)
111111
}
112112

113113
// Scale finds out the current count of running tasks for this project and scales to the desired count.

ecs-cli/modules/cli/compose/entity/task/task_test.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ func TestTaskCreate(t *testing.T) {
5151
cliContext := cli.NewContext(nil, flagSet, nil)
5252

5353
context := &context.ECSContext{
54-
ECSClient: mockEcs,
55-
CommandConfig: &config.CommandConfig{},
56-
CLIContext: cliContext,
54+
ECSClient: mockEcs,
55+
CommandConfig: &config.CommandConfig{},
56+
CLIContext: cliContext,
5757
}
5858
task := NewTask(context)
5959
task.SetTaskDefinition(&taskDefinition)
@@ -68,7 +68,7 @@ func TestTaskInfoFilterLocal(t *testing.T) {
6868
return NewTask(context)
6969
}, func(req *ecs.ListTasksInput, projectName string, t *testing.T) {
7070
assert.Equal(t, projectName, aws.StringValue(req.Family), "Expected Task Definition Family to be project name")
71-
}, t, true)
71+
}, t, true, "")
7272
}
7373

7474
func TestTaskInfoAll(t *testing.T) {
@@ -78,7 +78,29 @@ func TestTaskInfoAll(t *testing.T) {
7878
assert.Nil(t, req.StartedBy, "Unexpected filter on StartedBy")
7979
assert.Nil(t, req.Family, "Unexpected filter on Task Definition family")
8080
assert.Nil(t, req.ServiceName, "Unexpected filter on Service Name")
81-
}, t, false)
81+
}, t, false, "")
82+
}
83+
84+
func TestTaskInfoRunning(t *testing.T) {
85+
entity.TestInfo(func(context *context.ECSContext) entity.ProjectEntity {
86+
return NewTask(context)
87+
}, func(req *ecs.ListTasksInput, projectName string, t *testing.T) {
88+
assert.Nil(t, req.StartedBy, "Unexpected filter on StartedBy")
89+
assert.Nil(t, req.Family, "Unexpected filter on Task Definition family")
90+
assert.Nil(t, req.ServiceName, "Unexpected filter on Service Name")
91+
assert.Equal(t, ecs.DesiredStatusRunning, aws.StringValue(req.DesiredStatus), "Expected Desired status to match")
92+
}, t, false, ecs.DesiredStatusRunning)
93+
}
94+
95+
func TestTaskInfoStopped(t *testing.T) {
96+
entity.TestInfo(func(context *context.ECSContext) entity.ProjectEntity {
97+
return NewTask(context)
98+
}, func(req *ecs.ListTasksInput, projectName string, t *testing.T) {
99+
assert.Nil(t, req.StartedBy, "Unexpected filter on StartedBy")
100+
assert.Nil(t, req.Family, "Unexpected filter on Task Definition family")
101+
assert.Nil(t, req.ServiceName, "Unexpected filter on Service Name")
102+
assert.Equal(t, ecs.DesiredStatusStopped, aws.StringValue(req.DesiredStatus), "Expected Desired status to match")
103+
}, t, false, ecs.DesiredStatusStopped)
82104
}
83105

84106
// TODO: Test UP
@@ -95,7 +117,7 @@ func TestConvertToECSTaskOverride(t *testing.T) {
95117
expected := &ecs.TaskOverride{
96118
ContainerOverrides: []*ecs.ContainerOverride{
97119
{
98-
Name: aws.String(container),
120+
Name: aws.String(container),
99121
Command: aws.StringSlice(command),
100122
},
101123
},
@@ -131,8 +153,8 @@ func TestBuildRuntaskInput(t *testing.T) {
131153
context := &context.ECSContext{
132154
ECSClient: mockEcs,
133155
CLIContext: cliContext,
134-
CommandConfig: &config.CommandConfig{
135-
Cluster: cluster,
156+
CommandConfig: &config.CommandConfig{
157+
Cluster: cluster,
136158
LaunchType: launchType,
137159
},
138160
}
@@ -170,8 +192,8 @@ func TestBuildRuntaskInput_WithOverride(t *testing.T) {
170192
context := &context.ECSContext{
171193
ECSClient: mockEcs,
172194
CLIContext: cliContext,
173-
CommandConfig: &config.CommandConfig{
174-
Cluster: cluster,
195+
CommandConfig: &config.CommandConfig{
196+
Cluster: cluster,
175197
LaunchType: launchType,
176198
},
177199
}
@@ -183,7 +205,7 @@ func TestBuildRuntaskInput_WithOverride(t *testing.T) {
183205
expectedOverride := &ecs.TaskOverride{
184206
ContainerOverrides: []*ecs.ContainerOverride{
185207
{
186-
Name: aws.String("railsapp"),
208+
Name: aws.String("railsapp"),
187209
Command: aws.StringSlice(command),
188210
},
189211
},

0 commit comments

Comments
 (0)