Merge pull request #1137 from silvin-lubecki/stack-orchestrator

Fix broken swarm commands with Kubernetes defined as orchestrator
This commit is contained in:
Andrew Hsu 2018-06-22 13:56:42 -07:00 committed by GitHub
commit 151990de62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 368 additions and 317 deletions

View File

@ -102,7 +102,7 @@ func managementSubCommands(cmd *cobra.Command) []*cobra.Command {
var usageTemplate = `Usage:
{{- if not .HasSubCommands}} {{.UseLine}}{{end}}
{{- if .HasSubCommands}} {{ .CommandPath}} COMMAND{{end}}
{{- if .HasSubCommands}} {{ .CommandPath}}{{- if .HasAvailableFlags}} [OPTIONS]{{end}} COMMAND{{end}}
{{ .Short | trim }}

View File

@ -166,14 +166,9 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error {
if err != nil {
return errors.Wrap(err, "Experimental field")
}
orchestrator, err := GetOrchestrator(opts.Common.Orchestrator, cli.configFile.Orchestrator)
if err != nil {
return err
}
cli.clientInfo = ClientInfo{
DefaultVersion: cli.client.ClientVersion(),
HasExperimental: hasExperimental,
Orchestrator: orchestrator,
}
cli.initializeFromClient()
return nil
@ -239,22 +234,6 @@ type ServerInfo struct {
type ClientInfo struct {
HasExperimental bool
DefaultVersion string
Orchestrator Orchestrator
}
// HasKubernetes checks if kubernetes orchestrator is enabled
func (c ClientInfo) HasKubernetes() bool {
return c.Orchestrator == OrchestratorKubernetes || c.Orchestrator == OrchestratorAll
}
// HasSwarm checks if swarm orchestrator is enabled
func (c ClientInfo) HasSwarm() bool {
return c.Orchestrator == OrchestratorSwarm || c.Orchestrator == OrchestratorAll
}
// HasAll checks if all orchestrator is enabled
func (c ClientInfo) HasAll() bool {
return c.Orchestrator == OrchestratorAll
}
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err.

View File

@ -161,110 +161,6 @@ func TestExperimentalCLI(t *testing.T) {
}
}
func TestOrchestratorSwitch(t *testing.T) {
defaultVersion := "v0.00"
var testcases = []struct {
doc string
configfile string
envOrchestrator string
flagOrchestrator string
expectedOrchestrator string
expectedKubernetes bool
expectedSwarm bool
}{
{
doc: "default",
configfile: `{
}`,
expectedOrchestrator: "swarm",
expectedKubernetes: false,
expectedSwarm: true,
},
{
doc: "kubernetesConfigFile",
configfile: `{
"orchestrator": "kubernetes"
}`,
expectedOrchestrator: "kubernetes",
expectedKubernetes: true,
expectedSwarm: false,
},
{
doc: "kubernetesEnv",
configfile: `{
}`,
envOrchestrator: "kubernetes",
expectedOrchestrator: "kubernetes",
expectedKubernetes: true,
expectedSwarm: false,
},
{
doc: "kubernetesFlag",
configfile: `{
}`,
flagOrchestrator: "kubernetes",
expectedOrchestrator: "kubernetes",
expectedKubernetes: true,
expectedSwarm: false,
},
{
doc: "allOrchestratorFlag",
configfile: `{
}`,
flagOrchestrator: "all",
expectedOrchestrator: "all",
expectedKubernetes: true,
expectedSwarm: true,
},
{
doc: "envOverridesConfigFile",
configfile: `{
"orchestrator": "kubernetes"
}`,
envOrchestrator: "swarm",
expectedOrchestrator: "swarm",
expectedKubernetes: false,
expectedSwarm: true,
},
{
doc: "flagOverridesEnv",
configfile: `{
}`,
envOrchestrator: "kubernetes",
flagOrchestrator: "swarm",
expectedOrchestrator: "swarm",
expectedKubernetes: false,
expectedSwarm: true,
},
}
for _, testcase := range testcases {
t.Run(testcase.doc, func(t *testing.T) {
dir := fs.NewDir(t, testcase.doc, fs.WithFile("config.json", testcase.configfile))
defer dir.Remove()
apiclient := &fakeClient{
version: defaultVersion,
}
if testcase.envOrchestrator != "" {
defer env.Patch(t, "DOCKER_ORCHESTRATOR", testcase.envOrchestrator)()
}
cli := &DockerCli{client: apiclient, err: os.Stderr}
cliconfig.SetDir(dir.Path())
options := flags.NewClientOptions()
if testcase.flagOrchestrator != "" {
options.Common.Orchestrator = testcase.flagOrchestrator
}
err := cli.Initialize(options)
assert.NilError(t, err)
assert.Check(t, is.Equal(testcase.expectedKubernetes, cli.ClientInfo().HasKubernetes()))
assert.Check(t, is.Equal(testcase.expectedSwarm, cli.ClientInfo().HasSwarm()))
assert.Check(t, is.Equal(testcase.expectedOrchestrator, string(cli.ClientInfo().Orchestrator)))
})
}
}
func TestGetClientWithPassword(t *testing.T) {
expected := "password"

View File

@ -17,10 +17,25 @@ const (
OrchestratorAll = Orchestrator("all")
orchestratorUnset = Orchestrator("unset")
defaultOrchestrator = OrchestratorSwarm
envVarDockerOrchestrator = "DOCKER_ORCHESTRATOR"
defaultOrchestrator = OrchestratorSwarm
envVarDockerStackOrchestrator = "DOCKER_STACK_ORCHESTRATOR"
)
// HasKubernetes returns true if defined orchestrator has Kubernetes capabilities.
func (o Orchestrator) HasKubernetes() bool {
return o == OrchestratorKubernetes || o == OrchestratorAll
}
// HasSwarm returns true if defined orchestrator has Swarm capabilities.
func (o Orchestrator) HasSwarm() bool {
return o == OrchestratorSwarm || o == OrchestratorAll
}
// HasAll returns true if defined orchestrator has both Swarm and Kubernetes capabilities.
func (o Orchestrator) HasAll() bool {
return o == OrchestratorAll
}
func normalize(value string) (Orchestrator, error) {
switch value {
case "kubernetes":
@ -36,15 +51,15 @@ func normalize(value string) (Orchestrator, error) {
}
}
// GetOrchestrator checks DOCKER_ORCHESTRATOR environment variable and configuration file
// GetStackOrchestrator checks DOCKER_STACK_ORCHESTRATOR environment variable and configuration file
// orchestrator value and returns user defined Orchestrator.
func GetOrchestrator(flagValue, value string) (Orchestrator, error) {
func GetStackOrchestrator(flagValue, value string) (Orchestrator, error) {
// Check flag
if o, err := normalize(flagValue); o != orchestratorUnset {
return o, err
}
// Check environment variable
env := os.Getenv(envVarDockerOrchestrator)
env := os.Getenv(envVarDockerStackOrchestrator)
if o, err := normalize(env); o != orchestratorUnset {
return o, err
}

View File

@ -0,0 +1,117 @@
package command
import (
"os"
"testing"
cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/flags"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
"gotest.tools/env"
"gotest.tools/fs"
)
func TestOrchestratorSwitch(t *testing.T) {
defaultVersion := "v0.00"
var testcases = []struct {
doc string
configfile string
envOrchestrator string
flagOrchestrator string
expectedOrchestrator string
expectedKubernetes bool
expectedSwarm bool
}{
{
doc: "default",
configfile: `{
}`,
expectedOrchestrator: "swarm",
expectedKubernetes: false,
expectedSwarm: true,
},
{
doc: "kubernetesConfigFile",
configfile: `{
"stackOrchestrator": "kubernetes"
}`,
expectedOrchestrator: "kubernetes",
expectedKubernetes: true,
expectedSwarm: false,
},
{
doc: "kubernetesEnv",
configfile: `{
}`,
envOrchestrator: "kubernetes",
expectedOrchestrator: "kubernetes",
expectedKubernetes: true,
expectedSwarm: false,
},
{
doc: "kubernetesFlag",
configfile: `{
}`,
flagOrchestrator: "kubernetes",
expectedOrchestrator: "kubernetes",
expectedKubernetes: true,
expectedSwarm: false,
},
{
doc: "allOrchestratorFlag",
configfile: `{
}`,
flagOrchestrator: "all",
expectedOrchestrator: "all",
expectedKubernetes: true,
expectedSwarm: true,
},
{
doc: "envOverridesConfigFile",
configfile: `{
"stackOrchestrator": "kubernetes"
}`,
envOrchestrator: "swarm",
expectedOrchestrator: "swarm",
expectedKubernetes: false,
expectedSwarm: true,
},
{
doc: "flagOverridesEnv",
configfile: `{
}`,
envOrchestrator: "kubernetes",
flagOrchestrator: "swarm",
expectedOrchestrator: "swarm",
expectedKubernetes: false,
expectedSwarm: true,
},
}
for _, testcase := range testcases {
t.Run(testcase.doc, func(t *testing.T) {
dir := fs.NewDir(t, testcase.doc, fs.WithFile("config.json", testcase.configfile))
defer dir.Remove()
apiclient := &fakeClient{
version: defaultVersion,
}
if testcase.envOrchestrator != "" {
defer env.Patch(t, "DOCKER_STACK_ORCHESTRATOR", testcase.envOrchestrator)()
}
cli := &DockerCli{client: apiclient, err: os.Stderr}
cliconfig.SetDir(dir.Path())
options := flags.NewClientOptions()
err := cli.Initialize(options)
assert.NilError(t, err)
orchestrator, err := GetStackOrchestrator(testcase.flagOrchestrator, cli.ConfigFile().StackOrchestrator)
assert.NilError(t, err)
assert.Check(t, is.Equal(testcase.expectedKubernetes, orchestrator.HasKubernetes()))
assert.Check(t, is.Equal(testcase.expectedSwarm, orchestrator.HasSwarm()))
assert.Check(t, is.Equal(testcase.expectedOrchestrator, string(orchestrator)))
})
}
}

View File

@ -1,50 +1,125 @@
package stack
import (
"errors"
"fmt"
"strings"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
var errUnsupportedAllOrchestrator = fmt.Errorf(`no orchestrator specified: use either "kubernetes" or "swarm"`)
type commonOptions struct {
orchestrator command.Orchestrator
}
// NewStackCommand returns a cobra command for `stack` subcommands
func NewStackCommand(dockerCli command.Cli) *cobra.Command {
var opts commonOptions
cmd := &cobra.Command{
Use: "stack",
Use: "stack [OPTIONS]",
Short: "Manage Docker stacks",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
orchestrator, err := getOrchestrator(dockerCli.ConfigFile(), cmd)
if err != nil {
return err
}
opts.orchestrator = orchestrator
hideFlag(cmd, orchestrator)
return checkSupportedFlag(cmd, orchestrator)
},
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{
"kubernetes": "",
"swarm": "",
"version": "1.25",
"version": "1.25",
},
}
defaultHelpFunc := cmd.HelpFunc()
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
config := cliconfig.LoadDefaultConfigFile(dockerCli.Err()) // dockerCli is not yet initialized, but we only need config file here
o, err := getOrchestrator(config, cmd)
if err != nil {
fmt.Fprint(dockerCli.Err(), err)
return
}
hideFlag(cmd, o)
defaultHelpFunc(cmd, args)
})
cmd.AddCommand(
newDeployCommand(dockerCli),
newListCommand(dockerCli),
newPsCommand(dockerCli),
newRemoveCommand(dockerCli),
newServicesCommand(dockerCli),
newDeployCommand(dockerCli, &opts),
newListCommand(dockerCli, &opts),
newPsCommand(dockerCli, &opts),
newRemoveCommand(dockerCli, &opts),
newServicesCommand(dockerCli, &opts),
)
flags := cmd.PersistentFlags()
flags.String("kubeconfig", "", "Kubernetes config file")
flags.SetAnnotation("kubeconfig", "kubernetes", nil)
flags.String("orchestrator", "", "Orchestrator to use (swarm|kubernetes|all)")
return cmd
}
// NewTopLevelDeployCommand returns a command for `docker deploy`
func NewTopLevelDeployCommand(dockerCli command.Cli) *cobra.Command {
cmd := newDeployCommand(dockerCli)
cmd := newDeployCommand(dockerCli, nil)
// Remove the aliases at the top level
cmd.Aliases = []string{}
cmd.Annotations = map[string]string{
"experimental": "",
"swarm": "",
"version": "1.25",
}
return cmd
}
func getOrchestrator(config *configfile.ConfigFile, cmd *cobra.Command) (command.Orchestrator, error) {
var orchestratorFlag string
if o, err := cmd.Flags().GetString("orchestrator"); err == nil {
orchestratorFlag = o
}
return command.GetStackOrchestrator(orchestratorFlag, config.StackOrchestrator)
}
func hideFlag(cmd *cobra.Command, orchestrator command.Orchestrator) {
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if _, ok := f.Annotations["kubernetes"]; ok && !orchestrator.HasKubernetes() {
f.Hidden = true
}
if _, ok := f.Annotations["swarm"]; ok && !orchestrator.HasSwarm() {
f.Hidden = true
}
})
for _, subcmd := range cmd.Commands() {
hideFlag(subcmd, orchestrator)
}
}
func checkSupportedFlag(cmd *cobra.Command, orchestrator command.Orchestrator) error {
errs := []string{}
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if !f.Changed {
return
}
if _, ok := f.Annotations["kubernetes"]; ok && !orchestrator.HasKubernetes() {
errs = append(errs, fmt.Sprintf(`"--%s" is only supported on a Docker cli with kubernetes features enabled`, f.Name))
}
if _, ok := f.Annotations["swarm"]; ok && !orchestrator.HasSwarm() {
errs = append(errs, fmt.Sprintf(`"--%s" is only supported on a Docker cli with swarm features enabled`, f.Name))
}
})
for _, subcmd := range cmd.Commands() {
if err := checkSupportedFlag(subcmd, orchestrator); err != nil {
errs = append(errs, err.Error())
}
}
if len(errs) > 0 {
return errors.New(strings.Join(errs, "\n"))
}
return nil
}

View File

@ -9,7 +9,7 @@ import (
"github.com/spf13/cobra"
)
func newDeployCommand(dockerCli command.Cli) *cobra.Command {
func newDeployCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command {
var opts options.Deploy
cmd := &cobra.Command{
@ -20,10 +20,12 @@ func newDeployCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
opts.Namespace = args[0]
switch {
case dockerCli.ClientInfo().HasAll():
case common == nil: // Top level deploy commad
return swarm.RunDeploy(dockerCli, opts)
case common.orchestrator.HasAll():
return errUnsupportedAllOrchestrator
case dockerCli.ClientInfo().HasKubernetes():
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags()))
case common.orchestrator.HasKubernetes():
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags(), common.orchestrator))
if err != nil {
return err
}

View File

@ -23,13 +23,16 @@ type KubeCli struct {
// Options contains resolved parameters to initialize kubernetes clients
type Options struct {
Namespace string
Config string
Namespace string
Config string
Orchestrator command.Orchestrator
}
// NewOptions returns an Options initialized with command line flags
func NewOptions(flags *flag.FlagSet) Options {
var opts Options
func NewOptions(flags *flag.FlagSet, orchestrator command.Orchestrator) Options {
opts := Options{
Orchestrator: orchestrator,
}
if namespace, err := flags.GetString("namespace"); err == nil {
opts.Namespace = namespace
}
@ -73,7 +76,7 @@ func WrapCli(dockerCli command.Cli, opts Options) (*KubeCli, error) {
}
cli.clientSet = clientSet
if dockerCli.ClientInfo().HasAll() {
if opts.Orchestrator.HasAll() {
if err := cli.checkHostsMatch(); err != nil {
return nil, err
}

View File

@ -13,16 +13,16 @@ import (
"vbom.ml/util/sortorder"
)
func newListCommand(dockerCli command.Cli) *cobra.Command {
func newListCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command {
opts := options.List{}
cmd := &cobra.Command{
Use: "ls",
Use: "ls [OPTIONS]",
Aliases: []string{"list"},
Short: "List stacks",
Args: cli.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return runList(cmd, dockerCli, opts)
return runList(cmd, dockerCli, opts, common.orchestrator)
},
}
@ -35,17 +35,17 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runList(cmd *cobra.Command, dockerCli command.Cli, opts options.List) error {
func runList(cmd *cobra.Command, dockerCli command.Cli, opts options.List, orchestrator command.Orchestrator) error {
stacks := []*formatter.Stack{}
if dockerCli.ClientInfo().HasSwarm() {
if orchestrator.HasSwarm() {
ss, err := swarm.GetStacks(dockerCli)
if err != nil {
return err
}
stacks = append(stacks, ss...)
}
if dockerCli.ClientInfo().HasKubernetes() {
kubeCli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags()))
if orchestrator.HasKubernetes() {
kubeCli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags(), orchestrator))
if err != nil {
return err
}
@ -55,14 +55,14 @@ func runList(cmd *cobra.Command, dockerCli command.Cli, opts options.List) error
}
stacks = append(stacks, ss...)
}
return format(dockerCli, opts, stacks)
return format(dockerCli, opts, orchestrator, stacks)
}
func format(dockerCli command.Cli, opts options.List, stacks []*formatter.Stack) error {
func format(dockerCli command.Cli, opts options.List, orchestrator command.Orchestrator, stacks []*formatter.Stack) error {
format := opts.Format
if format == "" || format == formatter.TableFormatKey {
format = formatter.SwarmStackTableFormat
if dockerCli.ClientInfo().HasKubernetes() {
if orchestrator.HasKubernetes() {
format = formatter.KubernetesStackTableFormat
}
}

View File

@ -4,6 +4,7 @@ import (
"io/ioutil"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
@ -14,6 +15,10 @@ import (
"gotest.tools/golden"
)
var (
orchestrator = commonOptions{orchestrator: command.OrchestratorSwarm}
)
func TestListErrors(t *testing.T) {
testCases := []struct {
args []string
@ -48,7 +53,7 @@ func TestListErrors(t *testing.T) {
for _, tc := range testCases {
cmd := newListCommand(test.NewFakeCli(&fakeClient{
serviceListFunc: tc.serviceListFunc,
}, test.OrchestratorSwarm))
}), &orchestrator)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
for key, value := range tc.flags {
@ -69,8 +74,8 @@ func TestListWithFormat(t *testing.T) {
}),
)}, nil
},
}, test.OrchestratorSwarm)
cmd := newListCommand(cli)
})
cmd := newListCommand(cli, &orchestrator)
cmd.Flags().Set("format", "{{ .Name }}")
assert.NilError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "stack-list-with-format.golden")
@ -86,8 +91,8 @@ func TestListWithoutFormat(t *testing.T) {
}),
)}, nil
},
}, test.OrchestratorSwarm)
cmd := newListCommand(cli)
})
cmd := newListCommand(cli, &orchestrator)
assert.NilError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "stack-list-without-format.golden")
}
@ -139,8 +144,8 @@ func TestListOrder(t *testing.T) {
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return uc.swarmServices, nil
},
}, test.OrchestratorSwarm)
cmd := newListCommand(cli)
})
cmd := newListCommand(cli, &orchestrator)
assert.NilError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), uc.golden)
}

View File

@ -10,7 +10,7 @@ import (
"github.com/spf13/cobra"
)
func newPsCommand(dockerCli command.Cli) *cobra.Command {
func newPsCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command {
opts := options.PS{Filter: cliopts.NewFilterOpt()}
cmd := &cobra.Command{
@ -20,10 +20,10 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
opts.Namespace = args[0]
switch {
case dockerCli.ClientInfo().HasAll():
case common.orchestrator.HasAll():
return errUnsupportedAllOrchestrator
case dockerCli.ClientInfo().HasKubernetes():
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags()))
case common.orchestrator.HasKubernetes():
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags(), common.orchestrator))
if err != nil {
return err
}

View File

@ -44,7 +44,7 @@ func TestStackPsErrors(t *testing.T) {
for _, tc := range testCases {
cmd := newPsCommand(test.NewFakeCli(&fakeClient{
taskListFunc: tc.taskListFunc,
}))
}), &orchestrator)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
@ -57,7 +57,7 @@ func TestStackPsEmptyStack(t *testing.T) {
return []swarm.Task{}, nil
},
})
cmd := newPsCommand(fakeCli)
cmd := newPsCommand(fakeCli, &orchestrator)
cmd.SetArgs([]string{"foo"})
cmd.SetOutput(ioutil.Discard)
@ -71,7 +71,7 @@ func TestStackPsWithQuietOption(t *testing.T) {
return []swarm.Task{*Task(TaskID("id-foo"))}, nil
},
})
cmd := newPsCommand(cli)
cmd := newPsCommand(cli, &orchestrator)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("quiet", "true")
assert.NilError(t, cmd.Execute())
@ -85,7 +85,7 @@ func TestStackPsWithNoTruncOption(t *testing.T) {
return []swarm.Task{*Task(TaskID("xn4cypcov06f2w8gsbaf2lst3"))}, nil
},
})
cmd := newPsCommand(cli)
cmd := newPsCommand(cli, &orchestrator)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("no-trunc", "true")
cmd.Flags().Set("format", "{{ .ID }}")
@ -104,7 +104,7 @@ func TestStackPsWithNoResolveOption(t *testing.T) {
return *Node(NodeName("node-name-bar")), nil, nil
},
})
cmd := newPsCommand(cli)
cmd := newPsCommand(cli, &orchestrator)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("no-resolve", "true")
cmd.Flags().Set("format", "{{ .Node }}")
@ -118,7 +118,7 @@ func TestStackPsWithFormat(t *testing.T) {
return []swarm.Task{*Task(TaskServiceID("service-id-foo"))}, nil
},
})
cmd := newPsCommand(cli)
cmd := newPsCommand(cli, &orchestrator)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("format", "{{ .Name }}")
assert.NilError(t, cmd.Execute())
@ -134,7 +134,7 @@ func TestStackPsWithConfigFormat(t *testing.T) {
cli.SetConfigFile(&configfile.ConfigFile{
TasksFormat: "{{ .Name }}",
})
cmd := newPsCommand(cli)
cmd := newPsCommand(cli, &orchestrator)
cmd.SetArgs([]string{"foo"})
assert.NilError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "stack-ps-with-config-format.golden")
@ -156,7 +156,7 @@ func TestStackPsWithoutFormat(t *testing.T) {
return *Node(NodeName("node-name-bar")), nil, nil
},
})
cmd := newPsCommand(cli)
cmd := newPsCommand(cli, &orchestrator)
cmd.SetArgs([]string{"foo"})
assert.NilError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "stack-ps-without-format.golden")

View File

@ -9,21 +9,21 @@ import (
"github.com/spf13/cobra"
)
func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
func newRemoveCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command {
var opts options.Remove
cmd := &cobra.Command{
Use: "rm STACK [STACK...]",
Use: "rm [OPTIONS] STACK [STACK...]",
Aliases: []string{"remove", "down"},
Short: "Remove one or more stacks",
Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.Namespaces = args
switch {
case dockerCli.ClientInfo().HasAll():
case common.orchestrator.HasAll():
return errUnsupportedAllOrchestrator
case dockerCli.ClientInfo().HasKubernetes():
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags()))
case common.orchestrator.HasKubernetes():
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags(), common.orchestrator))
if err != nil {
return err
}

View File

@ -43,7 +43,7 @@ func fakeClientForRemoveStackTest(version string) *fakeClient {
func TestRemoveStackVersion124DoesNotRemoveConfigsOrSecrets(t *testing.T) {
client := fakeClientForRemoveStackTest("1.24")
cmd := newRemoveCommand(test.NewFakeCli(client))
cmd := newRemoveCommand(test.NewFakeCli(client), &orchestrator)
cmd.SetArgs([]string{"foo", "bar"})
assert.NilError(t, cmd.Execute())
@ -55,7 +55,7 @@ func TestRemoveStackVersion124DoesNotRemoveConfigsOrSecrets(t *testing.T) {
func TestRemoveStackVersion125DoesNotRemoveConfigs(t *testing.T) {
client := fakeClientForRemoveStackTest("1.25")
cmd := newRemoveCommand(test.NewFakeCli(client))
cmd := newRemoveCommand(test.NewFakeCli(client), &orchestrator)
cmd.SetArgs([]string{"foo", "bar"})
assert.NilError(t, cmd.Execute())
@ -67,7 +67,7 @@ func TestRemoveStackVersion125DoesNotRemoveConfigs(t *testing.T) {
func TestRemoveStackVersion130RemovesEverything(t *testing.T) {
client := fakeClientForRemoveStackTest("1.30")
cmd := newRemoveCommand(test.NewFakeCli(client))
cmd := newRemoveCommand(test.NewFakeCli(client), &orchestrator)
cmd.SetArgs([]string{"foo", "bar"})
assert.NilError(t, cmd.Execute())
@ -98,7 +98,7 @@ func TestRemoveStackSkipEmpty(t *testing.T) {
configs: allConfigs,
}
fakeCli := test.NewFakeCli(fakeClient)
cmd := newRemoveCommand(fakeCli)
cmd := newRemoveCommand(fakeCli, &orchestrator)
cmd.SetArgs([]string{"foo", "bar"})
assert.NilError(t, cmd.Execute())
@ -146,7 +146,7 @@ func TestRemoveContinueAfterError(t *testing.T) {
return nil
},
}
cmd := newRemoveCommand(test.NewFakeCli(cli))
cmd := newRemoveCommand(test.NewFakeCli(cli), &orchestrator)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs([]string{"foo", "bar"})

View File

@ -10,7 +10,7 @@ import (
"github.com/spf13/cobra"
)
func newServicesCommand(dockerCli command.Cli) *cobra.Command {
func newServicesCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command {
opts := options.Services{Filter: cliopts.NewFilterOpt()}
cmd := &cobra.Command{
@ -20,10 +20,10 @@ func newServicesCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
opts.Namespace = args[0]
switch {
case dockerCli.ClientInfo().HasAll():
case common.orchestrator.HasAll():
return errUnsupportedAllOrchestrator
case dockerCli.ClientInfo().HasKubernetes():
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags()))
case common.orchestrator.HasKubernetes():
kli, err := kubernetes.WrapCli(dockerCli, kubernetes.NewOptions(cmd.Flags(), common.orchestrator))
if err != nil {
return err
}

View File

@ -70,7 +70,7 @@ func TestStackServicesErrors(t *testing.T) {
nodeListFunc: tc.nodeListFunc,
taskListFunc: tc.taskListFunc,
})
cmd := newServicesCommand(cli)
cmd := newServicesCommand(cli, &orchestrator)
cmd.SetArgs(tc.args)
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
@ -86,7 +86,7 @@ func TestStackServicesEmptyServiceList(t *testing.T) {
return []swarm.Service{}, nil
},
})
cmd := newServicesCommand(fakeCli)
cmd := newServicesCommand(fakeCli, &orchestrator)
cmd.SetArgs([]string{"foo"})
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("", fakeCli.OutBuffer().String()))
@ -99,7 +99,7 @@ func TestStackServicesWithQuietOption(t *testing.T) {
return []swarm.Service{*Service(ServiceID("id-foo"))}, nil
},
})
cmd := newServicesCommand(cli)
cmd := newServicesCommand(cli, &orchestrator)
cmd.Flags().Set("quiet", "true")
cmd.SetArgs([]string{"foo"})
assert.NilError(t, cmd.Execute())
@ -114,7 +114,7 @@ func TestStackServicesWithFormat(t *testing.T) {
}, nil
},
})
cmd := newServicesCommand(cli)
cmd := newServicesCommand(cli, &orchestrator)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("format", "{{ .Name }}")
assert.NilError(t, cmd.Execute())
@ -132,7 +132,7 @@ func TestStackServicesWithConfigFormat(t *testing.T) {
cli.SetConfigFile(&configfile.ConfigFile{
ServicesFormat: "{{ .Name }}",
})
cmd := newServicesCommand(cli)
cmd := newServicesCommand(cli, &orchestrator)
cmd.SetArgs([]string{"foo"})
assert.NilError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "stack-services-with-config-format.golden")
@ -155,7 +155,7 @@ func TestStackServicesWithoutFormat(t *testing.T) {
)}, nil
},
})
cmd := newServicesCommand(cli)
cmd := newServicesCommand(cli, &orchestrator)
cmd.SetArgs([]string{"foo"})
assert.NilError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "stack-services-without-format.golden")

View File

@ -6,4 +6,3 @@ Client:
Built: Wed May 30 22:21:05 2018
OS/Arch: linux/amd64
Experimental: true
Orchestrator: swarm

View File

@ -29,7 +29,6 @@ Client:{{if ne .Platform.Name ""}} {{.Platform.Name}}{{end}}
Built: {{.BuildTime}}
OS/Arch: {{.Os}}/{{.Arch}}
Experimental: {{.Experimental}}
Orchestrator: {{.Orchestrator}}
{{- end}}
{{- if .ServerOK}}{{with .Server}}
@ -78,7 +77,6 @@ type clientVersion struct {
Arch string
BuildTime string `json:",omitempty"`
Experimental bool
Orchestrator string `json:",omitempty"`
}
type kubernetesVersion struct {
@ -107,7 +105,7 @@ func NewVersionCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
flags.StringVarP(&opts.kubeConfig, "kubeconfig", "k", "", "Kubernetes config file")
flags.StringVar(&opts.kubeConfig, "kubeconfig", "", "Kubernetes config file")
flags.SetAnnotation("kubeconfig", "kubernetes", nil)
return cmd
@ -128,6 +126,11 @@ func runVersion(dockerCli command.Cli, opts *versionOptions) error {
return cli.StatusError{StatusCode: 64, Status: err.Error()}
}
orchestrator, err := command.GetStackOrchestrator("", dockerCli.ConfigFile().StackOrchestrator)
if err != nil {
return cli.StatusError{StatusCode: 64, Status: err.Error()}
}
vd := versionInfo{
Client: clientVersion{
Platform: struct{ Name string }{cli.PlatformName},
@ -140,14 +143,16 @@ func runVersion(dockerCli command.Cli, opts *versionOptions) error {
Os: runtime.GOOS,
Arch: runtime.GOARCH,
Experimental: dockerCli.ClientInfo().HasExperimental,
Orchestrator: string(dockerCli.ClientInfo().Orchestrator),
},
}
sv, err := dockerCli.Client().ServerVersion(context.Background())
if err == nil {
vd.Server = &sv
kubeVersion := getKubernetesVersion(dockerCli, opts.kubeConfig)
var kubeVersion *kubernetesVersion
if orchestrator.HasKubernetes() {
kubeVersion = getKubernetesVersion(opts.kubeConfig)
}
foundEngine := false
foundKubernetes := false
for _, component := range sv.Components {
@ -225,11 +230,7 @@ func getDetailsOrder(v types.ComponentVersion) []string {
return out
}
func getKubernetesVersion(dockerCli command.Cli, kubeConfig string) *kubernetesVersion {
if !dockerCli.ClientInfo().HasKubernetes() {
return nil
}
func getKubernetesVersion(kubeConfig string) *kubernetesVersion {
version := kubernetesVersion{
Kubernetes: "Unknown",
StackAPI: "Unknown",

View File

@ -11,7 +11,6 @@ import (
"gotest.tools/golden"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
)
@ -31,20 +30,6 @@ func TestVersionWithoutServer(t *testing.T) {
assert.Assert(t, !strings.Contains(out, "Server:"), "actual: %s", out)
}
func fakeServerVersion(_ context.Context) (types.Version, error) {
return types.Version{
Version: "docker-dev",
APIVersion: api.DefaultVersion,
}, nil
}
func TestVersionWithOrchestrator(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{serverVersion: fakeServerVersion}, test.OrchestratorSwarm)
cmd := NewVersionCommand(cli)
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Contains(cleanTabs(cli.OutBuffer().String()), "Orchestrator: swarm"))
}
func TestVersionAlign(t *testing.T) {
vi := versionInfo{
Client: clientVersion{
@ -57,7 +42,6 @@ func TestVersionAlign(t *testing.T) {
Arch: "amd64",
BuildTime: "Wed May 30 22:21:05 2018",
Experimental: true,
Orchestrator: "swarm",
},
}
@ -68,7 +52,3 @@ func TestVersionAlign(t *testing.T) {
assert.Check(t, golden.String(cli.OutBuffer().String(), "docker-client-version.golden"))
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
}
func cleanTabs(line string) string {
return strings.Join(strings.Fields(line), " ")
}

View File

@ -46,7 +46,7 @@ type ConfigFile struct {
PruneFilters []string `json:"pruneFilters,omitempty"`
Proxies map[string]ProxyConfig `json:"proxies,omitempty"`
Experimental string `json:"experimental,omitempty"`
Orchestrator string `json:"orchestrator,omitempty"`
StackOrchestrator string `json:"stackOrchestrator,omitempty"`
Kubernetes *KubernetesConfig `json:"kubernetes,omitempty"`
}

View File

@ -31,13 +31,12 @@ var (
// CommonOptions are options common to both the client and the daemon.
type CommonOptions struct {
Debug bool
Hosts []string
Orchestrator string
LogLevel string
TLS bool
TLSVerify bool
TLSOptions *tlsconfig.Options
Debug bool
Hosts []string
LogLevel string
TLS bool
TLSVerify bool
TLSOptions *tlsconfig.Options
}
// NewCommonOptions returns a new CommonOptions

View File

@ -51,11 +51,6 @@ func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
flags.StringVar(&opts.ConfigDir, "config", cliconfig.Dir(), "Location of client config files")
opts.Common.InstallFlags(flags)
// Install persistent flags
persistentFlags := cmd.PersistentFlags()
persistentFlags.StringVar(&opts.Common.Orchestrator, "orchestrator", "", "Orchestrator to use (swarm|kubernetes|all)")
persistentFlags.SetAnnotation("orchestrator", "top-level", []string{"version", "stack"})
setFlagErrorFunc(dockerCli, cmd, flags, opts)
setHelpFunc(dockerCli, cmd, flags, opts)
@ -244,13 +239,10 @@ func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) {
osType := details.ServerInfo().OSType
hasExperimental := details.ServerInfo().HasExperimental
hasExperimentalCLI := details.ClientInfo().HasExperimental
hasKubernetes := details.ClientInfo().HasKubernetes()
cmd.Flags().VisitAll(func(f *pflag.Flag) {
hideFeatureFlag(f, hasExperimental, "experimental")
hideFeatureFlag(f, hasExperimentalCLI, "experimentalCLI")
hideFeatureFlag(f, hasKubernetes, "kubernetes")
hideFeatureFlag(f, !hasKubernetes, "swarm")
// hide flags not supported by the server
if !isOSTypeSupported(f, osType) || !isVersionSupported(f, clientVersion) {
f.Hidden = true
@ -266,8 +258,6 @@ func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) {
for _, subcmd := range cmd.Commands() {
hideFeatureSubCommand(subcmd, hasExperimental, "experimental")
hideFeatureSubCommand(subcmd, hasExperimentalCLI, "experimentalCLI")
hideFeatureSubCommand(subcmd, hasKubernetes, "kubernetes")
hideFeatureSubCommand(subcmd, !hasKubernetes, "swarm")
// hide subcommands not supported by the server
if subcmdVersion, ok := subcmd.Annotations["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
subcmd.Hidden = true
@ -302,7 +292,6 @@ func areFlagsSupported(cmd *cobra.Command, details versionDetails) error {
clientVersion := details.Client().ClientVersion()
osType := details.ServerInfo().OSType
hasExperimental := details.ServerInfo().HasExperimental
hasKubernetes := details.ClientInfo().HasKubernetes()
hasExperimentalCLI := details.ClientInfo().HasExperimental
errs := []string{}
@ -323,14 +312,6 @@ func areFlagsSupported(cmd *cobra.Command, details versionDetails) error {
if _, ok := f.Annotations["experimentalCLI"]; ok && !hasExperimentalCLI {
errs = append(errs, fmt.Sprintf("\"--%s\" is on a Docker cli with experimental cli features enabled", f.Name))
}
_, isKubernetesAnnotated := f.Annotations["kubernetes"]
_, isSwarmAnnotated := f.Annotations["swarm"]
if isKubernetesAnnotated && !isSwarmAnnotated && !hasKubernetes {
errs = append(errs, fmt.Sprintf("\"--%s\" is only supported on a Docker cli with kubernetes features enabled", f.Name))
}
if isSwarmAnnotated && !isKubernetesAnnotated && hasKubernetes {
errs = append(errs, fmt.Sprintf("\"--%s\" is only supported on a Docker cli with swarm features enabled", f.Name))
}
}
})
if len(errs) > 0 {
@ -345,7 +326,6 @@ func areSubcommandsSupported(cmd *cobra.Command, details versionDetails) error {
osType := details.ServerInfo().OSType
hasExperimental := details.ServerInfo().HasExperimental
hasExperimentalCLI := details.ClientInfo().HasExperimental
hasKubernetes := details.ClientInfo().HasKubernetes()
// Check recursively so that, e.g., `docker stack ls` returns the same output as `docker stack`
for curr := cmd; curr != nil; curr = curr.Parent() {
@ -361,15 +341,6 @@ func areSubcommandsSupported(cmd *cobra.Command, details versionDetails) error {
if _, ok := curr.Annotations["experimentalCLI"]; ok && !hasExperimentalCLI {
return fmt.Errorf("%s is only supported on a Docker cli with experimental cli features enabled", cmd.CommandPath())
}
_, isKubernetesAnnotated := curr.Annotations["kubernetes"]
_, isSwarmAnnotated := curr.Annotations["swarm"]
if isKubernetesAnnotated && !isSwarmAnnotated && !hasKubernetes {
return fmt.Errorf("%s is only supported on a Docker cli with kubernetes features enabled", cmd.CommandPath())
}
if isSwarmAnnotated && !isKubernetesAnnotated && hasKubernetes {
return fmt.Errorf("%s is only supported on a Docker cli with swarm features enabled", cmd.CommandPath())
}
}
return nil
}

View File

@ -66,6 +66,7 @@ by the `docker` command line:
* `DOCKER_NOWARN_KERNEL_VERSION` Prevent warnings that your Linux kernel is
unsuitable for Docker.
* `DOCKER_RAMDISK` If set this will disable 'pivot_root'.
* `DOCKER_STACK_ORCHESTRATOR` Configure the default orchestrator to use when using `docker stack` management commands.
* `DOCKER_TLS` When set Docker uses TLS.
* `DOCKER_TLS_VERIFY` When set Docker uses TLS and verifies the remote.
* `DOCKER_CONTENT_TRUST` When set Docker uses notary to sign and verify images.
@ -196,6 +197,11 @@ credentials for specific registries. If this property is set, the binary
for a specific registry. For more information, see the
[**Credential helpers** section in the `docker login` documentation](login.md#credential-helpers)
The property `stackOrchestrator` specifies the default orchestrator to use when
running `docker stack` management commands. Valid values are `"swarm"`,
`"kubernetes"`, and `"all"`. This property can be overridden with the
`DOCKER_STACK_ORCHESTRATOR` environment variable, or the `--orchestrator` flag.
Once attached to a container, users detach from it and leave it running using
the using `CTRL-p CTRL-q` key sequence. This detach key sequence is customizable
using the `detachKeys` property. Specify a `<sequence>` value for the
@ -236,7 +242,8 @@ Following is a sample `config.json` file:
"credHelpers": {
"awesomereg.example.org": "hip-star",
"unicorn.example.com": "vcbait"
}
},
"stackOrchestrator": "kubernetes"
}
{% endraw %}
```

View File

@ -16,18 +16,20 @@ keywords: "stack"
# stack
```markdown
Usage: docker stack COMMAND
Usage: docker stack [OPTIONS] COMMAND
Manage Docker stacks
Options:
--help Print usage
--help Print usage
--kubeconfig string Kubernetes config file
--orchestrator string Orchestrator to use (swarm|kubernetes|all)
Commands:
deploy Deploy a new stack or update an existing stack
ls List stacks
ps List the tasks in the stack
rm Remove the stack
rm Remove one or more stacks
services List the services in the stack
Run 'docker stack COMMAND --help' for more information on a command.

View File

@ -27,6 +27,9 @@ Options:
--bundle-file string Path to a Distributed Application Bundle file
-c, --compose-file strings Path to a Compose file
--help Print usage
--kubeconfig string Kubernetes config file
--namespace string Kubernetes namespace to use
--orchestrator string Orchestrator to use (swarm|kubernetes|all)
--prune Prune services that are no longer referenced
--resolve-image string Query the registry to resolve image digest and supported platforms
("always"|"changed"|"never") (default "always")

View File

@ -16,7 +16,7 @@ keywords: "stack, ls"
# stack ls
```markdown
Usage: docker stack ls
Usage: docker stack ls [OPTIONS]
List stacks
@ -24,8 +24,11 @@ Aliases:
ls, list
Options:
--help Print usage
--format string Pretty-print stacks using a Go template
--help Print usage
--format string Pretty-print stacks using a Go template
--kubeconfig string Kubernetes config file
--namespace string Kubernetes namespace to use
--orchestrator string Orchestrator to use (swarm|kubernetes|all)
```
## Description

View File

@ -21,12 +21,15 @@ Usage: docker stack ps [OPTIONS] STACK
List the tasks in the stack
Options:
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print tasks using a Go template
--help Print usage
--no-resolve Do not map IDs to Names
--no-trunc Do not truncate output
-q, --quiet Only display task IDs
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print tasks using a Go template
--help Print usage
--kubeconfig string Kubernetes config file
--namespace string Kubernetes namespace to use
--no-resolve Do not map IDs to Names
--no-trunc Do not truncate output
--orchestrator string Orchestrator to use (swarm|kubernetes|all)
-q, --quiet Only display task IDs
```
## Description

View File

@ -16,7 +16,7 @@ keywords: "stack, rm, remove, down"
# stack rm
```markdown
Usage: docker stack rm STACK [STACK...]
Usage: docker stack rm [OPTIONS] STACK [STACK...]
Remove one or more stacks
@ -24,7 +24,10 @@ Aliases:
rm, remove, down
Options:
--help Print usage
--help Print usage
--kubeconfig string Kubernetes config file
--namespace string Kubernetes namespace to use
--orchestrator string Orchestrator to use (swarm|kubernetes|all)
```
## Description

View File

@ -2,7 +2,6 @@
title: "stack services"
description: "The stack services command description and usage"
keywords: "stack, services"
advisory: "experimental"
---
<!-- This file is maintained within the docker/cli GitHub
@ -14,7 +13,7 @@ advisory: "experimental"
will be rejected.
-->
# stack services (experimental)
# stack services
```markdown
Usage: docker stack services [OPTIONS] STACK
@ -22,10 +21,13 @@ Usage: docker stack services [OPTIONS] STACK
List the services in the stack
Options:
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print services using a Go template
--help Print usage
-q, --quiet Only display IDs
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print services using a Go template
--help Print usage
--kubeconfig string Kubernetes config file
--namespace string Kubernetes namespace to use
--orchestrator string Orchestrator to use (swarm|kubernetes|all)
-q, --quiet Only display IDs
```
## Description

View File

@ -21,8 +21,9 @@ Usage: docker version [OPTIONS]
Show the Docker version information
Options:
-f, --format string Format the output using the given Go template
--help Print usage
-f, --format string Format the output using the given Go template
--help Print usage
--kubeconfig string Kubernetes config file
```
## Description

View File

@ -30,10 +30,10 @@ func testDeployWithNamedResources(t *testing.T, orchestrator string) {
stackname := fmt.Sprintf("test-stack-deploy-with-names-%s", orchestrator)
composefile := golden.Path("stack-with-named-resources.yml")
result := icmd.RunCommand("docker", "--orchestrator", orchestrator,
"stack", "deploy", "-c", composefile, stackname)
defer icmd.RunCommand("docker", "--orchestrator", orchestrator,
"stack", "rm", stackname)
result := icmd.RunCommand("docker", "stack", "deploy",
"-c", composefile, stackname, "--orchestrator", orchestrator)
defer icmd.RunCommand("docker", "stack", "rm",
"--orchestrator", orchestrator, stackname)
result.Assert(t, icmd.Success)
stdout := strings.Split(result.Stdout(), "\n")

View File

@ -29,8 +29,8 @@ func testRemove(t *testing.T, orchestrator string) {
stackname := "test-stack-remove-" + orchestrator
deployFullStack(t, orchestrator, stackname)
defer cleanupFullStack(t, orchestrator, stackname)
result := icmd.RunCommand("docker", "--orchestrator", orchestrator,
"stack", "rm", stackname)
result := icmd.RunCommand("docker", "stack", "rm",
stackname, "--orchestrator", orchestrator)
result.Assert(t, icmd.Expected{Err: icmd.None})
golden.Assert(t, result.Stdout(),
fmt.Sprintf("stack-remove-%s-success.golden", orchestrator))
@ -38,8 +38,8 @@ func testRemove(t *testing.T, orchestrator string) {
func deployFullStack(t *testing.T, orchestrator, stackname string) {
// TODO: this stack should have full options not minimal options
result := icmd.RunCommand("docker", "--orchestrator", orchestrator,
"stack", "deploy", "--compose-file=./testdata/full-stack.yml", stackname)
result := icmd.RunCommand("docker", "stack", "deploy",
"--compose-file=./testdata/full-stack.yml", stackname, "--orchestrator", orchestrator)
result.Assert(t, icmd.Success)
poll.WaitOn(t, taskCount(orchestrator, stackname, 2), pollSettings)
@ -53,7 +53,7 @@ func cleanupFullStack(t *testing.T, orchestrator, stackname string) {
func stackRm(orchestrator, stackname string) func(t poll.LogT) poll.Result {
return func(poll.LogT) poll.Result {
result := icmd.RunCommand("docker", "--orchestrator", orchestrator, "stack", "rm", stackname)
result := icmd.RunCommand("docker", "stack", "rm", stackname, "--orchestrator", orchestrator)
if result.Error != nil {
if strings.Contains(result.Stderr(), "not found") {
return poll.Success()
@ -66,7 +66,7 @@ func stackRm(orchestrator, stackname string) func(t poll.LogT) poll.Result {
func taskCount(orchestrator, stackname string, expected int) func(t poll.LogT) poll.Result {
return func(poll.LogT) poll.Result {
args := []string{"--orchestrator", orchestrator, "stack", "ps", stackname}
args := []string{"stack", "ps", stackname, "--orchestrator", orchestrator}
// FIXME(chris-crone): remove when we support filtering by desired-state on kubernetes
if orchestrator == "swarm" {
args = append(args, "-f=desired-state=running")

View File

@ -167,18 +167,3 @@ func (c *FakeCli) ContentTrustEnabled() bool {
func EnableContentTrust(c *FakeCli) {
c.contentTrust = true
}
// OrchestratorSwarm sets a command.ClientInfo with Swarm orchestrator
func OrchestratorSwarm(c *FakeCli) {
c.SetClientInfo(func() command.ClientInfo { return command.ClientInfo{Orchestrator: "swarm"} })
}
// OrchestratorKubernetes sets a command.ClientInfo with Kubernetes orchestrator
func OrchestratorKubernetes(c *FakeCli) {
c.SetClientInfo(func() command.ClientInfo { return command.ClientInfo{Orchestrator: "kubernetes"} })
}
// OrchestratorAll sets a command.ClientInfo with all orchestrator
func OrchestratorAll(c *FakeCli) {
c.SetClientInfo(func() command.ClientInfo { return command.ClientInfo{Orchestrator: "all"} })
}