Skip to content

Commit 67be0c7

Browse files
rumplthaJeztah
authored andcommitted
Refactor the stack services command to be uniform
Running `docker stack services <STACK> --orchestrator swarm would yield the message "Noting found in stack: asdf" with an exit code 0. The same command with kubernetes orchestrator would yield "nothing found in stack: adsf" (note the lower-case "nothing") and a non-zero exit code. This change makes the `stack services` command uniform for both orchestrators. The logic of getting and printing services is split to reuse the same formatting code. Signed-off-by: Djordje Lukic <djordje.lukic@docker.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 4ab76b0 commit 67be0c7

3 files changed

Lines changed: 70 additions & 55 deletions

File tree

cli/command/stack/kubernetes/services.go

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import (
44
"fmt"
55
"strings"
66

7-
"github.com/docker/cli/cli/command/service"
8-
"github.com/docker/cli/cli/command/stack/formatter"
97
"github.com/docker/cli/cli/command/stack/options"
108
"github.com/docker/compose-on-kubernetes/api/labels"
119
"github.com/docker/docker/api/types/filters"
@@ -79,56 +77,43 @@ func getResourcesForServiceList(dockerCli *KubeCli, filters filters.Args, labelS
7977
return replicas, daemons, services, nil
8078
}
8179

82-
// RunServices is the kubernetes implementation of docker stack services
83-
func RunServices(dockerCli *KubeCli, opts options.Services) error {
80+
// GetServices is the kubernetes implementation of listing stack services
81+
func GetServices(dockerCli *KubeCli, opts options.Services) ([]swarm.Service, error) {
8482
filters := opts.Filter.Value()
8583
if err := filters.Validate(supportedServicesFilters); err != nil {
86-
return err
84+
return nil, err
8785
}
8886
client, err := dockerCli.composeClient()
8987
if err != nil {
90-
return nil
88+
return nil, err
9189
}
9290
stacks, err := client.Stacks(false)
9391
if err != nil {
94-
return nil
92+
return nil, err
9593
}
9694
stackName := opts.Namespace
9795
_, err = stacks.Get(stackName)
9896
if apierrs.IsNotFound(err) {
99-
return fmt.Errorf("nothing found in stack: %s", stackName)
97+
return []swarm.Service{}, nil
10098
}
10199
if err != nil {
102-
return err
100+
return nil, err
103101
}
104102

105103
labelSelector := generateLabelSelector(filters, stackName)
106104
replicasList, daemonsList, servicesList, err := getResourcesForServiceList(dockerCli, filters, labelSelector)
107105
if err != nil {
108-
return err
106+
return nil, err
109107
}
110108

111109
// Convert Replicas sets and kubernetes services to swarm services and formatter information
112110
services, err := convertToServices(replicasList, daemonsList, servicesList)
113111
if err != nil {
114-
return err
112+
return nil, err
115113
}
116114
services = filterServicesByName(services, filters.Get("name"), stackName)
117115

118-
format := opts.Format
119-
if len(format) == 0 {
120-
if len(dockerCli.ConfigFile().ServicesFormat) > 0 && !opts.Quiet {
121-
format = dockerCli.ConfigFile().ServicesFormat
122-
} else {
123-
format = formatter.TableFormatKey
124-
}
125-
}
126-
127-
servicesCtx := formatter.Context{
128-
Output: dockerCli.Out(),
129-
Format: service.NewListFormat(format, opts.Quiet),
130-
}
131-
return service.ListFormatWrite(servicesCtx, services)
116+
return services, nil
132117
}
133118

134119
func filterServicesByName(services []swarm.Service, names []string, stackName string) []swarm.Service {

cli/command/stack/services.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
package stack
22

33
import (
4+
"fmt"
5+
"sort"
6+
47
"github.com/docker/cli/cli"
58
"github.com/docker/cli/cli/command"
9+
"github.com/docker/cli/cli/command/service"
10+
"github.com/docker/cli/cli/command/stack/formatter"
611
"github.com/docker/cli/cli/command/stack/kubernetes"
712
"github.com/docker/cli/cli/command/stack/options"
813
"github.com/docker/cli/cli/command/stack/swarm"
914
cliopts "github.com/docker/cli/opts"
15+
swarmtypes "github.com/docker/docker/api/types/swarm"
1016
"github.com/spf13/cobra"
1117
"github.com/spf13/pflag"
18+
"vbom.ml/util/sortorder"
1219
)
1320

1421
func newServicesCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command {
@@ -36,7 +43,51 @@ func newServicesCommand(dockerCli command.Cli, common *commonOptions) *cobra.Com
3643

3744
// RunServices performs a stack services against the specified orchestrator
3845
func RunServices(dockerCli command.Cli, flags *pflag.FlagSet, commonOrchestrator command.Orchestrator, opts options.Services) error {
39-
return runOrchestratedCommand(dockerCli, flags, commonOrchestrator,
40-
func() error { return swarm.RunServices(dockerCli, opts) },
41-
func(kli *kubernetes.KubeCli) error { return kubernetes.RunServices(kli, opts) })
46+
services, err := GetServices(dockerCli, flags, commonOrchestrator, opts)
47+
if err != nil {
48+
return err
49+
}
50+
return formatWrite(dockerCli, services, opts)
51+
}
52+
53+
// GetServices returns the services for the specified orchestrator
54+
func GetServices(dockerCli command.Cli, flags *pflag.FlagSet, commonOrchestrator command.Orchestrator, opts options.Services) ([]swarmtypes.Service, error) {
55+
switch {
56+
case commonOrchestrator.HasAll():
57+
return nil, errUnsupportedAllOrchestrator
58+
case commonOrchestrator.HasKubernetes():
59+
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(flags, commonOrchestrator))
60+
if err != nil {
61+
return nil, err
62+
}
63+
return kubernetes.GetServices(kli, opts)
64+
default:
65+
return swarm.GetServices(dockerCli, opts)
66+
}
67+
}
68+
69+
func formatWrite(dockerCli command.Cli, services []swarmtypes.Service, opts options.Services) error {
70+
// if no services in the stack, print message and exit 0
71+
if len(services) == 0 {
72+
_, _ = fmt.Fprintf(dockerCli.Err(), "Nothing found in stack: %s\n", opts.Namespace)
73+
return nil
74+
}
75+
sort.Slice(services, func(i, j int) bool {
76+
return sortorder.NaturalLess(services[i].Spec.Name, services[j].Spec.Name)
77+
})
78+
79+
format := opts.Format
80+
if len(format) == 0 {
81+
if len(dockerCli.ConfigFile().ServicesFormat) > 0 && !opts.Quiet {
82+
format = dockerCli.ConfigFile().ServicesFormat
83+
} else {
84+
format = formatter.TableFormatKey
85+
}
86+
}
87+
88+
servicesCtx := formatter.Context{
89+
Output: dockerCli.Out(),
90+
Format: service.NewListFormat(format, opts.Quiet),
91+
}
92+
return service.ListFormatWrite(servicesCtx, services)
4293
}

cli/command/stack/swarm/services.go

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@ package swarm
22

33
import (
44
"context"
5-
"fmt"
65

76
"github.com/docker/cli/cli/command"
87
"github.com/docker/cli/cli/command/service"
9-
"github.com/docker/cli/cli/command/stack/formatter"
108
"github.com/docker/cli/cli/command/stack/options"
119
"github.com/docker/docker/api/types"
10+
"github.com/docker/docker/api/types/swarm"
1211
)
1312

14-
// RunServices is the swarm implementation of docker stack services
15-
func RunServices(dockerCli command.Cli, opts options.Services) error {
13+
// GetServices is the swarm implementation of listing stack services
14+
func GetServices(dockerCli command.Cli, opts options.Services) ([]swarm.Service, error) {
1615
var (
1716
err error
1817
ctx = context.Background()
@@ -30,13 +29,7 @@ func RunServices(dockerCli command.Cli, opts options.Services) error {
3029

3130
services, err := client.ServiceList(ctx, listOpts)
3231
if err != nil {
33-
return err
34-
}
35-
36-
// if no services in this stack, print message and exit 0
37-
if len(services) == 0 {
38-
_, _ = fmt.Fprintf(dockerCli.Err(), "Nothing found in stack: %s\n", opts.Namespace)
39-
return nil
32+
return nil, err
4033
}
4134

4235
if listOpts.Status {
@@ -54,22 +47,8 @@ func RunServices(dockerCli command.Cli, opts options.Services) error {
5447
// a ServiceStatus set, and perform a lookup for those.
5548
services, err = service.AppendServiceStatus(ctx, client, services)
5649
if err != nil {
57-
return err
50+
return nil, err
5851
}
5952
}
60-
61-
format := opts.Format
62-
if len(format) == 0 {
63-
if len(dockerCli.ConfigFile().ServicesFormat) > 0 && !opts.Quiet {
64-
format = dockerCli.ConfigFile().ServicesFormat
65-
} else {
66-
format = formatter.TableFormatKey
67-
}
68-
}
69-
70-
servicesCtx := formatter.Context{
71-
Output: dockerCli.Out(),
72-
Format: service.NewListFormat(format, opts.Quiet),
73-
}
74-
return service.ListFormatWrite(servicesCtx, services)
53+
return services, nil
7554
}

0 commit comments

Comments
 (0)