mirror of https://github.com/docker/cli.git
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>
This commit is contained in:
parent
b3cde356f6
commit
568ea3a329
|
@ -4,8 +4,6 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command/service"
|
||||
"github.com/docker/cli/cli/command/stack/formatter"
|
||||
"github.com/docker/cli/cli/command/stack/options"
|
||||
"github.com/docker/compose-on-kubernetes/api/labels"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
@ -79,56 +77,43 @@ func getResourcesForServiceList(dockerCli *KubeCli, filters filters.Args, labelS
|
|||
return replicas, daemons, services, nil
|
||||
}
|
||||
|
||||
// RunServices is the kubernetes implementation of docker stack services
|
||||
func RunServices(dockerCli *KubeCli, opts options.Services) error {
|
||||
// GetServices is the kubernetes implementation of listing stack services
|
||||
func GetServices(dockerCli *KubeCli, opts options.Services) ([]swarm.Service, error) {
|
||||
filters := opts.Filter.Value()
|
||||
if err := filters.Validate(supportedServicesFilters); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
client, err := dockerCli.composeClient()
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, err
|
||||
}
|
||||
stacks, err := client.Stacks(false)
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, err
|
||||
}
|
||||
stackName := opts.Namespace
|
||||
_, err = stacks.Get(stackName)
|
||||
if apierrs.IsNotFound(err) {
|
||||
return fmt.Errorf("nothing found in stack: %s", stackName)
|
||||
return []swarm.Service{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labelSelector := generateLabelSelector(filters, stackName)
|
||||
replicasList, daemonsList, servicesList, err := getResourcesForServiceList(dockerCli, filters, labelSelector)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert Replicas sets and kubernetes services to swarm services and formatter information
|
||||
services, err := convertToServices(replicasList, daemonsList, servicesList)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
services = filterServicesByName(services, filters.Get("name"), stackName)
|
||||
|
||||
format := opts.Format
|
||||
if len(format) == 0 {
|
||||
if len(dockerCli.ConfigFile().ServicesFormat) > 0 && !opts.Quiet {
|
||||
format = dockerCli.ConfigFile().ServicesFormat
|
||||
} else {
|
||||
format = formatter.TableFormatKey
|
||||
}
|
||||
}
|
||||
|
||||
servicesCtx := formatter.Context{
|
||||
Output: dockerCli.Out(),
|
||||
Format: service.NewListFormat(format, opts.Quiet),
|
||||
}
|
||||
return service.ListFormatWrite(servicesCtx, services)
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func filterServicesByName(services []swarm.Service, names []string, stackName string) []swarm.Service {
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
package stack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/service"
|
||||
"github.com/docker/cli/cli/command/stack/formatter"
|
||||
"github.com/docker/cli/cli/command/stack/kubernetes"
|
||||
"github.com/docker/cli/cli/command/stack/options"
|
||||
"github.com/docker/cli/cli/command/stack/swarm"
|
||||
cliopts "github.com/docker/cli/opts"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"vbom.ml/util/sortorder"
|
||||
)
|
||||
|
||||
func newServicesCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command {
|
||||
|
@ -36,7 +43,51 @@ func newServicesCommand(dockerCli command.Cli, common *commonOptions) *cobra.Com
|
|||
|
||||
// RunServices performs a stack services against the specified orchestrator
|
||||
func RunServices(dockerCli command.Cli, flags *pflag.FlagSet, commonOrchestrator command.Orchestrator, opts options.Services) error {
|
||||
return runOrchestratedCommand(dockerCli, flags, commonOrchestrator,
|
||||
func() error { return swarm.RunServices(dockerCli, opts) },
|
||||
func(kli *kubernetes.KubeCli) error { return kubernetes.RunServices(kli, opts) })
|
||||
services, err := GetServices(dockerCli, flags, commonOrchestrator, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return formatWrite(dockerCli, services, opts)
|
||||
}
|
||||
|
||||
// GetServices returns the services for the specified orchestrator
|
||||
func GetServices(dockerCli command.Cli, flags *pflag.FlagSet, commonOrchestrator command.Orchestrator, opts options.Services) ([]swarmtypes.Service, error) {
|
||||
switch {
|
||||
case commonOrchestrator.HasAll():
|
||||
return nil, errUnsupportedAllOrchestrator
|
||||
case commonOrchestrator.HasKubernetes():
|
||||
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(flags, commonOrchestrator))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kubernetes.GetServices(kli, opts)
|
||||
default:
|
||||
return swarm.GetServices(dockerCli, opts)
|
||||
}
|
||||
}
|
||||
|
||||
func formatWrite(dockerCli command.Cli, services []swarmtypes.Service, opts options.Services) error {
|
||||
// if no services in the stack, print message and exit 0
|
||||
if len(services) == 0 {
|
||||
_, _ = fmt.Fprintf(dockerCli.Err(), "Nothing found in stack: %s\n", opts.Namespace)
|
||||
return nil
|
||||
}
|
||||
sort.Slice(services, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(services[i].Spec.Name, services[j].Spec.Name)
|
||||
})
|
||||
|
||||
format := opts.Format
|
||||
if len(format) == 0 {
|
||||
if len(dockerCli.ConfigFile().ServicesFormat) > 0 && !opts.Quiet {
|
||||
format = dockerCli.ConfigFile().ServicesFormat
|
||||
} else {
|
||||
format = formatter.TableFormatKey
|
||||
}
|
||||
}
|
||||
|
||||
servicesCtx := formatter.Context{
|
||||
Output: dockerCli.Out(),
|
||||
Format: service.NewListFormat(format, opts.Quiet),
|
||||
}
|
||||
return service.ListFormatWrite(servicesCtx, services)
|
||||
}
|
||||
|
|
|
@ -2,17 +2,16 @@ package swarm
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/service"
|
||||
"github.com/docker/cli/cli/command/stack/formatter"
|
||||
"github.com/docker/cli/cli/command/stack/options"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
)
|
||||
|
||||
// RunServices is the swarm implementation of docker stack services
|
||||
func RunServices(dockerCli command.Cli, opts options.Services) error {
|
||||
// GetServices is the swarm implementation of listing stack services
|
||||
func GetServices(dockerCli command.Cli, opts options.Services) ([]swarm.Service, error) {
|
||||
var (
|
||||
err error
|
||||
ctx = context.Background()
|
||||
|
@ -30,13 +29,7 @@ func RunServices(dockerCli command.Cli, opts options.Services) error {
|
|||
|
||||
services, err := client.ServiceList(ctx, listOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if no services in this stack, print message and exit 0
|
||||
if len(services) == 0 {
|
||||
_, _ = fmt.Fprintf(dockerCli.Err(), "Nothing found in stack: %s\n", opts.Namespace)
|
||||
return nil
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if listOpts.Status {
|
||||
|
@ -54,22 +47,8 @@ func RunServices(dockerCli command.Cli, opts options.Services) error {
|
|||
// a ServiceStatus set, and perform a lookup for those.
|
||||
services, err = service.AppendServiceStatus(ctx, client, services)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
format := opts.Format
|
||||
if len(format) == 0 {
|
||||
if len(dockerCli.ConfigFile().ServicesFormat) > 0 && !opts.Quiet {
|
||||
format = dockerCli.ConfigFile().ServicesFormat
|
||||
} else {
|
||||
format = formatter.TableFormatKey
|
||||
}
|
||||
}
|
||||
|
||||
servicesCtx := formatter.Context{
|
||||
Output: dockerCli.Out(),
|
||||
Format: service.NewListFormat(format, opts.Quiet),
|
||||
}
|
||||
return service.ListFormatWrite(servicesCtx, services)
|
||||
return services, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue