Skip to content

Commit a63db0e

Browse files
committed
cli/command/service: remove AppendServiceStatus (API <v1.41)
This function was added in 7405ac5 as a fallback for API < v1.41, which did not include the service status in the response. Current API versions return this information, so there's no need to fetch it manually. It was not gated by API version for some tests (which didn't set API version), but should not be needed for non-test situations. Signed-off-by: Sebastiaan van Stijn <[email protected]>
1 parent a51c3be commit a63db0e

File tree

4 files changed

+6
-195
lines changed

4 files changed

+6
-195
lines changed

cli/command/image/opts.go

Lines changed: 0 additions & 17 deletions
This file was deleted.

cli/command/service/list.go

Lines changed: 3 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"github.com/docker/cli/cli/command/formatter"
99
flagsHelper "github.com/docker/cli/cli/flags"
1010
"github.com/docker/cli/opts"
11-
"github.com/moby/moby/api/types/swarm"
1211
"github.com/moby/moby/client"
1312
"github.com/spf13/cobra"
1413
)
@@ -43,44 +42,19 @@ func newListCommand(dockerCLI command.Cli) *cobra.Command {
4342
}
4443

4544
func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) error {
46-
var (
47-
apiClient = dockerCLI.Client()
48-
err error
49-
)
50-
51-
listOpts := client.ServiceListOptions{
45+
apiClient := dockerCLI.Client()
46+
services, err := apiClient.ServiceList(ctx, client.ServiceListOptions{
5247
Filters: options.filter.Value(),
5348
// When not running "quiet", also get service status (number of running
5449
// and desired tasks). Note that this is only supported on API v1.41 and
5550
// up; older API versions ignore this option, and we will have to collect
5651
// the information manually below.
5752
Status: !options.quiet,
58-
}
59-
60-
services, err := apiClient.ServiceList(ctx, listOpts)
53+
})
6154
if err != nil {
6255
return err
6356
}
6457

65-
if listOpts.Status {
66-
// Now that a request was made, we know what API version was used (either
67-
// through configuration, or after client and daemon negotiated a version).
68-
// If API version v1.41 or up was used; the daemon should already have done
69-
// the legwork for us, and we don't have to calculate the number of desired
70-
// and running tasks. On older API versions, we need to do some extra requests
71-
// to get that information.
72-
//
73-
// So theoretically, this step can be skipped based on API version, however,
74-
// some of our unit tests don't set the API version, and there may be other
75-
// situations where the client uses the "default" version. To account for
76-
// these situations, we do a quick check for services that do not have
77-
// a ServiceStatus set, and perform a lookup for those.
78-
services, err = AppendServiceStatus(ctx, apiClient, services)
79-
if err != nil {
80-
return err
81-
}
82-
}
83-
8458
format := options.format
8559
if len(format) == 0 {
8660
if len(dockerCLI.ConfigFile().ServicesFormat) > 0 && !options.quiet {
@@ -96,94 +70,3 @@ func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) er
9670
}
9771
return ListFormatWrite(servicesCtx, services)
9872
}
99-
100-
// AppendServiceStatus propagates the ServiceStatus field for "services".
101-
//
102-
// If API version v1.41 or up is used, this information is already set by the
103-
// daemon. On older API versions, we need to do some extra requests to get
104-
// that information. Theoretically, this function can be skipped based on API
105-
// version, however, some of our unit tests don't set the API version, and
106-
// there may be other situations where the client uses the "default" version.
107-
// To take these situations into account, we do a quick check for services
108-
// that don't have ServiceStatus set, and perform a lookup for those.
109-
func AppendServiceStatus(ctx context.Context, c client.APIClient, services []swarm.Service) ([]swarm.Service, error) {
110-
status := map[string]*swarm.ServiceStatus{}
111-
taskFilter := make(client.Filters)
112-
for i, s := range services {
113-
// there is no need in this switch to check for job modes. jobs are not
114-
// supported until after ServiceStatus was introduced.
115-
switch {
116-
case s.ServiceStatus != nil:
117-
// Server already returned service-status, so we don't
118-
// have to look-up tasks for this service.
119-
continue
120-
case s.Spec.Mode.Replicated != nil:
121-
// For replicated services, set the desired number of tasks;
122-
// that way we can present this information in case we're unable
123-
// to get a list of tasks from the server.
124-
services[i].ServiceStatus = &swarm.ServiceStatus{DesiredTasks: *s.Spec.Mode.Replicated.Replicas}
125-
status[s.ID] = &swarm.ServiceStatus{}
126-
taskFilter.Add("service", s.ID)
127-
case s.Spec.Mode.Global != nil:
128-
// No such thing as number of desired tasks for global services
129-
services[i].ServiceStatus = &swarm.ServiceStatus{}
130-
status[s.ID] = &swarm.ServiceStatus{}
131-
taskFilter.Add("service", s.ID)
132-
default:
133-
// Unknown task type
134-
}
135-
}
136-
if len(status) == 0 {
137-
// All services have their ServiceStatus set, so we're done
138-
return services, nil
139-
}
140-
141-
tasks, err := c.TaskList(ctx, client.TaskListOptions{Filters: taskFilter})
142-
if err != nil {
143-
return nil, err
144-
}
145-
if len(tasks) == 0 {
146-
return services, nil
147-
}
148-
activeNodes, err := getActiveNodes(ctx, c)
149-
if err != nil {
150-
return nil, err
151-
}
152-
153-
for _, task := range tasks {
154-
if status[task.ServiceID] == nil {
155-
// This should not happen in practice; either all services have
156-
// a ServiceStatus set, or none of them.
157-
continue
158-
}
159-
// TODO: this should only be needed for "global" services. Replicated
160-
// services have `Spec.Mode.Replicated.Replicas`, which should give this value.
161-
if task.DesiredState != swarm.TaskStateShutdown {
162-
status[task.ServiceID].DesiredTasks++
163-
}
164-
if _, nodeActive := activeNodes[task.NodeID]; nodeActive && task.Status.State == swarm.TaskStateRunning {
165-
status[task.ServiceID].RunningTasks++
166-
}
167-
}
168-
169-
for i, service := range services {
170-
if s := status[service.ID]; s != nil {
171-
services[i].ServiceStatus = s
172-
}
173-
}
174-
return services, nil
175-
}
176-
177-
func getActiveNodes(ctx context.Context, c client.NodeAPIClient) (map[string]struct{}, error) {
178-
nodes, err := c.NodeList(ctx, client.NodeListOptions{})
179-
if err != nil {
180-
return nil, err
181-
}
182-
activeNodes := make(map[string]struct{})
183-
for _, n := range nodes {
184-
if n.Status.State != swarm.NodeStateDown {
185-
activeNodes[n.ID] = struct{}{}
186-
}
187-
}
188-
return activeNodes, nil
189-
}

cli/command/stack/services_test.go

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ func TestStackServicesErrors(t *testing.T) {
2121
args []string
2222
flags map[string]string
2323
serviceListFunc func(options client.ServiceListOptions) ([]swarm.Service, error)
24-
nodeListFunc func(options client.NodeListOptions) ([]swarm.Node, error)
25-
taskListFunc func(options client.TaskListOptions) ([]swarm.Task, error)
2624
expectedError string
2725
}{
2826
{
@@ -32,29 +30,6 @@ func TestStackServicesErrors(t *testing.T) {
3230
},
3331
expectedError: "error getting services",
3432
},
35-
{
36-
args: []string{"foo"},
37-
serviceListFunc: func(options client.ServiceListOptions) ([]swarm.Service, error) {
38-
return []swarm.Service{*builders.Service(builders.GlobalService())}, nil
39-
},
40-
nodeListFunc: func(options client.NodeListOptions) ([]swarm.Node, error) {
41-
return nil, errors.New("error getting nodes")
42-
},
43-
taskListFunc: func(options client.TaskListOptions) ([]swarm.Task, error) {
44-
return []swarm.Task{*builders.Task()}, nil
45-
},
46-
expectedError: "error getting nodes",
47-
},
48-
{
49-
args: []string{"foo"},
50-
serviceListFunc: func(options client.ServiceListOptions) ([]swarm.Service, error) {
51-
return []swarm.Service{*builders.Service(builders.GlobalService())}, nil
52-
},
53-
taskListFunc: func(options client.TaskListOptions) ([]swarm.Task, error) {
54-
return nil, errors.New("error getting tasks")
55-
},
56-
expectedError: "error getting tasks",
57-
},
5833
{
5934
args: []string{"foo"},
6035
flags: map[string]string{
@@ -71,8 +46,6 @@ func TestStackServicesErrors(t *testing.T) {
7146
t.Run(tc.expectedError, func(t *testing.T) {
7247
cli := test.NewFakeCli(&fakeClient{
7348
serviceListFunc: tc.serviceListFunc,
74-
nodeListFunc: tc.nodeListFunc,
75-
taskListFunc: tc.taskListFunc,
7649
})
7750
cmd := newServicesCommand(cli)
7851
cmd.SetArgs(tc.args)

cli/command/stack/services_utils.go

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,16 @@ package stack
33
import (
44
"context"
55

6-
"github.com/docker/cli/cli/command/service"
76
"github.com/moby/moby/api/types/swarm"
87
"github.com/moby/moby/client"
98
)
109

1110
// getServices is the swarm implementation of listing stack services
1211
func getServices(ctx context.Context, apiClient client.APIClient, opts serviceListOptions) ([]swarm.Service, error) {
13-
listOpts := client.ServiceListOptions{
12+
return apiClient.ServiceList(ctx, client.ServiceListOptions{
1413
Filters: getStackFilterFromOpt(opts.namespace, opts.filter),
1514
// When not running "quiet", also get service status (number of running
16-
// and desired tasks). Note that this is only supported on API v1.41 and
17-
// up; older API versions ignore this option, and we will have to collect
18-
// the information manually below.
15+
// and desired tasks).
1916
Status: !opts.quiet,
20-
}
21-
22-
services, err := apiClient.ServiceList(ctx, listOpts)
23-
if err != nil {
24-
return nil, err
25-
}
26-
27-
if listOpts.Status {
28-
// Now that a request was made, we know what API version was used (either
29-
// through configuration, or after client and daemon negotiated a version).
30-
// If API version v1.41 or up was used; the daemon should already have done
31-
// the legwork for us, and we don't have to calculate the number of desired
32-
// and running tasks. On older API versions, we need to do some extra requests
33-
// to get that information.
34-
//
35-
// So theoretically, this step can be skipped based on API version, however,
36-
// some of our unit tests don't set the API version, and there may be other
37-
// situations where the client uses the "default" version. To account for
38-
// these situations, we do a quick check for services that do not have
39-
// a ServiceStatus set, and perform a lookup for those.
40-
services, err = service.AppendServiceStatus(ctx, apiClient, services)
41-
if err != nil {
42-
return nil, err
43-
}
44-
}
45-
return services, nil
17+
})
4618
}

0 commit comments

Comments
 (0)