remove obsolete mutli-orchestrator support

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2022-02-22 13:46:35 +01:00
parent 1d48749c1c
commit 193ede9b12
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
44 changed files with 186 additions and 581 deletions

View File

@ -60,7 +60,6 @@ type Cli interface {
ContentTrustEnabled() bool ContentTrustEnabled() bool
ContextStore() store.Store ContextStore() store.Store
CurrentContext() string CurrentContext() string
StackOrchestrator(flagValue string) (Orchestrator, error)
DockerEndpoint() docker.Endpoint DockerEndpoint() docker.Endpoint
} }
@ -367,25 +366,6 @@ func (cli *DockerCli) CurrentContext() string {
return cli.currentContext return cli.currentContext
} }
// StackOrchestrator resolves which stack orchestrator is in use
func (cli *DockerCli) StackOrchestrator(flagValue string) (Orchestrator, error) {
currentContext := cli.CurrentContext()
ctxRaw, err := cli.ContextStore().GetMetadata(currentContext)
if store.IsErrContextDoesNotExist(err) {
// case where the currentContext has been removed (CLI behavior is to fallback to using DOCKER_HOST based resolution)
return GetStackOrchestrator(flagValue, "", cli.ConfigFile().StackOrchestrator, cli.Err())
}
if err != nil {
return "", err
}
ctxMeta, err := GetDockerContext(ctxRaw)
if err != nil {
return "", err
}
ctxOrchestrator := string(ctxMeta.StackOrchestrator)
return GetStackOrchestrator(flagValue, ctxOrchestrator, cli.ConfigFile().StackOrchestrator, cli.Err())
}
// DockerEndpoint returns the current docker endpoint // DockerEndpoint returns the current docker endpoint
func (cli *DockerCli) DockerEndpoint() docker.Endpoint { func (cli *DockerCli) DockerEndpoint() docker.Endpoint {
return cli.dockerEndpoint return cli.dockerEndpoint

View File

@ -9,9 +9,8 @@ import (
// DockerContext is a typed representation of what we put in Context metadata // DockerContext is a typed representation of what we put in Context metadata
type DockerContext struct { type DockerContext struct {
Description string Description string
StackOrchestrator Orchestrator AdditionalFields map[string]interface{}
AdditionalFields map[string]interface{}
} }
// MarshalJSON implements custom JSON marshalling // MarshalJSON implements custom JSON marshalling
@ -20,9 +19,6 @@ func (dc DockerContext) MarshalJSON() ([]byte, error) {
if dc.Description != "" { if dc.Description != "" {
s["Description"] = dc.Description s["Description"] = dc.Description
} }
if dc.StackOrchestrator != "" {
s["StackOrchestrator"] = dc.StackOrchestrator
}
if dc.AdditionalFields != nil { if dc.AdditionalFields != nil {
for k, v := range dc.AdditionalFields { for k, v := range dc.AdditionalFields {
s[k] = v s[k] = v
@ -41,8 +37,6 @@ func (dc *DockerContext) UnmarshalJSON(payload []byte) error {
switch k { switch k {
case "Description": case "Description":
dc.Description = v.(string) dc.Description = v.(string)
case "StackOrchestrator":
dc.StackOrchestrator = Orchestrator(v.(string))
default: default:
if dc.AdditionalFields == nil { if dc.AdditionalFields == nil {
dc.AdditionalFields = make(map[string]interface{}) dc.AdditionalFields = make(map[string]interface{})

View File

@ -3,7 +3,6 @@ package context
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/sirupsen/logrus"
"text/tabwriter" "text/tabwriter"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
@ -59,10 +58,12 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
"default-stack-orchestrator", "", "default-stack-orchestrator", "",
"Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)") "Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)")
flags.SetAnnotation("default-stack-orchestrator", "deprecated", nil) flags.SetAnnotation("default-stack-orchestrator", "deprecated", nil)
flags.MarkDeprecated("default-stack-orchestrator", "option will be ignored")
flags.StringToStringVar(&opts.Docker, "docker", nil, "set the docker endpoint") flags.StringToStringVar(&opts.Docker, "docker", nil, "set the docker endpoint")
flags.StringToStringVar(&opts.Kubernetes, "kubernetes", nil, "set the kubernetes endpoint") flags.StringToStringVar(&opts.Kubernetes, "kubernetes", nil, "set the kubernetes endpoint")
flags.SetAnnotation("kubernetes", "kubernetes", nil) flags.SetAnnotation("kubernetes", "kubernetes", nil)
flags.SetAnnotation("kubernetes", "deprecated", nil) flags.SetAnnotation("kubernetes", "deprecated", nil)
flags.MarkDeprecated("kubernetes", "option will be ignored")
flags.StringVar(&opts.From, "from", "", "create context from a named context") flags.StringVar(&opts.From, "from", "", "create context from a named context")
return cmd return cmd
} }
@ -70,20 +71,17 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
// RunCreate creates a Docker context // RunCreate creates a Docker context
func RunCreate(cli command.Cli, o *CreateOptions) error { func RunCreate(cli command.Cli, o *CreateOptions) error {
s := cli.ContextStore() s := cli.ContextStore()
if err := checkContextNameForCreation(s, o.Name); err != nil { err := checkContextNameForCreation(s, o.Name)
return err
}
stackOrchestrator, err := command.NormalizeOrchestrator(o.DefaultStackOrchestrator)
if err != nil { if err != nil {
return errors.Wrap(err, "unable to parse default-stack-orchestrator") return err
} }
switch { switch {
case o.From == "" && o.Docker == nil && o.Kubernetes == nil: case o.From == "" && o.Docker == nil && o.Kubernetes == nil:
err = createFromExistingContext(s, cli.CurrentContext(), stackOrchestrator, o) err = createFromExistingContext(s, cli.CurrentContext(), o)
case o.From != "": case o.From != "":
err = createFromExistingContext(s, o.From, stackOrchestrator, o) err = createFromExistingContext(s, o.From, o)
default: default:
err = createNewContext(o, stackOrchestrator, cli, s) err = createNewContext(o, cli, s)
} }
if err == nil { if err == nil {
fmt.Fprintln(cli.Out(), o.Name) fmt.Fprintln(cli.Out(), o.Name)
@ -92,11 +90,11 @@ func RunCreate(cli command.Cli, o *CreateOptions) error {
return err return err
} }
func createNewContext(o *CreateOptions, stackOrchestrator command.Orchestrator, cli command.Cli, s store.Writer) error { func createNewContext(o *CreateOptions, cli command.Cli, s store.Writer) error {
if o.Docker == nil { if o.Docker == nil {
return errors.New("docker endpoint configuration is required") return errors.New("docker endpoint configuration is required")
} }
contextMetadata := newContextMetadata(stackOrchestrator, o) contextMetadata := newContextMetadata(o)
contextTLSData := store.ContextTLSData{ contextTLSData := store.ContextTLSData{
Endpoints: make(map[string]store.EndpointTLSData), Endpoints: make(map[string]store.EndpointTLSData),
} }
@ -108,10 +106,7 @@ func createNewContext(o *CreateOptions, stackOrchestrator command.Orchestrator,
if dockerTLS != nil { if dockerTLS != nil {
contextTLSData.Endpoints[docker.DockerEndpoint] = *dockerTLS contextTLSData.Endpoints[docker.DockerEndpoint] = *dockerTLS
} }
if len(o.Kubernetes) != 0 { if err := validateEndpoints(contextMetadata); err != nil {
logrus.Warn("kubernetes orchestrator is deprecated")
}
if err := validateEndpointsAndOrchestrator(contextMetadata); err != nil {
return err return err
} }
if err := s.CreateOrUpdate(contextMetadata); err != nil { if err := s.CreateOrUpdate(contextMetadata); err != nil {
@ -136,26 +131,24 @@ func checkContextNameForCreation(s store.Reader, name string) error {
return nil return nil
} }
func createFromExistingContext(s store.ReaderWriter, fromContextName string, stackOrchestrator command.Orchestrator, o *CreateOptions) error { func createFromExistingContext(s store.ReaderWriter, fromContextName string, o *CreateOptions) error {
if len(o.Docker) != 0 || len(o.Kubernetes) != 0 { if len(o.Docker) != 0 || len(o.Kubernetes) != 0 {
return errors.New("cannot use --docker or --kubernetes flags when --from is set") return errors.New("cannot use --docker or --kubernetes flags when --from is set")
} }
reader := store.Export(fromContextName, &descriptionAndOrchestratorStoreDecorator{ reader := store.Export(fromContextName, &descriptionDecorator{
Reader: s, Reader: s,
description: o.Description, description: o.Description,
orchestrator: stackOrchestrator,
}) })
defer reader.Close() defer reader.Close()
return store.Import(o.Name, s, reader) return store.Import(o.Name, s, reader)
} }
type descriptionAndOrchestratorStoreDecorator struct { type descriptionDecorator struct {
store.Reader store.Reader
description string description string
orchestrator command.Orchestrator
} }
func (d *descriptionAndOrchestratorStoreDecorator) GetMetadata(name string) (store.Metadata, error) { func (d *descriptionDecorator) GetMetadata(name string) (store.Metadata, error) {
c, err := d.Reader.GetMetadata(name) c, err := d.Reader.GetMetadata(name)
if err != nil { if err != nil {
return c, err return c, err
@ -167,19 +160,15 @@ func (d *descriptionAndOrchestratorStoreDecorator) GetMetadata(name string) (sto
if d.description != "" { if d.description != "" {
typedContext.Description = d.description typedContext.Description = d.description
} }
if d.orchestrator != command.Orchestrator("") {
typedContext.StackOrchestrator = d.orchestrator
}
c.Metadata = typedContext c.Metadata = typedContext
return c, nil return c, nil
} }
func newContextMetadata(stackOrchestrator command.Orchestrator, o *CreateOptions) store.Metadata { func newContextMetadata(o *CreateOptions) store.Metadata {
return store.Metadata{ return store.Metadata{
Endpoints: make(map[string]interface{}), Endpoints: make(map[string]interface{}),
Metadata: command.DockerContext{ Metadata: command.DockerContext{
Description: o.Description, Description: o.Description,
StackOrchestrator: stackOrchestrator,
}, },
Name: o.Name, Name: o.Name,
} }

View File

@ -12,7 +12,6 @@ import (
"github.com/docker/cli/cli/context/store" "github.com/docker/cli/cli/context/store"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
"gotest.tools/v3/env"
) )
func makeFakeCli(t *testing.T, opts ...func(*test.FakeCli)) (*test.FakeCli, func()) { func makeFakeCli(t *testing.T, opts ...func(*test.FakeCli)) (*test.FakeCli, func()) {
@ -33,8 +32,7 @@ func makeFakeCli(t *testing.T, opts ...func(*test.FakeCli)) (*test.FakeCli, func
}, },
}, },
Metadata: command.DockerContext{ Metadata: command.DockerContext{
Description: "", Description: "",
StackOrchestrator: command.OrchestratorSwarm,
}, },
Name: command.DefaultContextName, Name: command.DefaultContextName,
}, },
@ -59,7 +57,7 @@ func withCliConfig(configFile *configfile.ConfigFile) func(*test.FakeCli) {
} }
} }
func TestCreateInvalids(t *testing.T) { func TestCreate(t *testing.T) {
cli, cleanup := makeFakeCli(t) cli, cleanup := makeFakeCli(t)
defer cleanup() defer cleanup()
assert.NilError(t, cli.ContextStore().CreateOrUpdate(store.Metadata{Name: "existing-context"})) assert.NilError(t, cli.ContextStore().CreateOrUpdate(store.Metadata{Name: "existing-context"}))
@ -102,7 +100,7 @@ func TestCreateInvalids(t *testing.T) {
Name: "invalid-orchestrator", Name: "invalid-orchestrator",
DefaultStackOrchestrator: "invalid", DefaultStackOrchestrator: "invalid",
}, },
expecterErr: `specified orchestrator "invalid" is invalid, please use either kubernetes, swarm or all`, expecterErr: "",
}, },
{ {
options: CreateOptions{ options: CreateOptions{
@ -158,37 +156,25 @@ func TestCreateOrchestratorEmpty(t *testing.T) {
func TestCreateFromContext(t *testing.T) { func TestCreateFromContext(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
description string description string
orchestrator string expectedDescription string
expectedDescription string docker map[string]string
docker map[string]string kubernetes map[string]string
kubernetes map[string]string
expectedOrchestrator command.Orchestrator
}{ }{
{ {
name: "no-override", name: "no-override",
expectedDescription: "original description", expectedDescription: "original description",
expectedOrchestrator: command.OrchestratorSwarm,
}, },
{ {
name: "override-description", name: "override-description",
description: "new description", description: "new description",
expectedDescription: "new description", expectedDescription: "new description",
expectedOrchestrator: command.OrchestratorSwarm,
},
{
name: "override-orchestrator",
orchestrator: "kubernetes",
expectedDescription: "original description",
expectedOrchestrator: command.OrchestratorKubernetes,
}, },
} }
cli, cleanup := makeFakeCli(t) cli, cleanup := makeFakeCli(t)
defer cleanup() defer cleanup()
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
defer revert()
cli.ResetOutputBuffers() cli.ResetOutputBuffers()
assert.NilError(t, RunCreate(cli, &CreateOptions{ assert.NilError(t, RunCreate(cli, &CreateOptions{
Name: "original", Name: "original",
@ -196,10 +182,6 @@ func TestCreateFromContext(t *testing.T) {
Docker: map[string]string{ Docker: map[string]string{
keyHost: "tcp://42.42.42.42:2375", keyHost: "tcp://42.42.42.42:2375",
}, },
Kubernetes: map[string]string{
keyFrom: "default",
},
DefaultStackOrchestrator: "swarm",
})) }))
assertContextCreateLogging(t, cli, "original") assertContextCreateLogging(t, cli, "original")
@ -210,10 +192,6 @@ func TestCreateFromContext(t *testing.T) {
Docker: map[string]string{ Docker: map[string]string{
keyHost: "tcp://24.24.24.24:2375", keyHost: "tcp://24.24.24.24:2375",
}, },
Kubernetes: map[string]string{
keyFrom: "default",
},
DefaultStackOrchestrator: "swarm",
})) }))
assertContextCreateLogging(t, cli, "dummy") assertContextCreateLogging(t, cli, "dummy")
@ -224,12 +202,10 @@ func TestCreateFromContext(t *testing.T) {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
cli.ResetOutputBuffers() cli.ResetOutputBuffers()
err := RunCreate(cli, &CreateOptions{ err := RunCreate(cli, &CreateOptions{
From: "original", From: "original",
Name: c.name, Name: c.name,
Description: c.description, Description: c.description,
DefaultStackOrchestrator: c.orchestrator, Docker: c.docker,
Docker: c.docker,
Kubernetes: c.kubernetes,
}) })
assert.NilError(t, err) assert.NilError(t, err)
assertContextCreateLogging(t, cli, c.name) assertContextCreateLogging(t, cli, c.name)
@ -240,7 +216,6 @@ func TestCreateFromContext(t *testing.T) {
dockerEndpoint, err := docker.EndpointFromContext(newContext) dockerEndpoint, err := docker.EndpointFromContext(newContext)
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, newContextTyped.Description, c.expectedDescription) assert.Equal(t, newContextTyped.Description, c.expectedDescription)
assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator)
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375") assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
}) })
} }
@ -248,29 +223,24 @@ func TestCreateFromContext(t *testing.T) {
func TestCreateFromCurrent(t *testing.T) { func TestCreateFromCurrent(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
description string description string
orchestrator string orchestrator string
expectedDescription string expectedDescription string
expectedOrchestrator command.Orchestrator
}{ }{
{ {
name: "no-override", name: "no-override",
expectedDescription: "original description", expectedDescription: "original description",
expectedOrchestrator: command.OrchestratorSwarm,
}, },
{ {
name: "override-description", name: "override-description",
description: "new description", description: "new description",
expectedDescription: "new description", expectedDescription: "new description",
expectedOrchestrator: command.OrchestratorSwarm,
}, },
} }
cli, cleanup := makeFakeCli(t) cli, cleanup := makeFakeCli(t)
defer cleanup() defer cleanup()
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
defer revert()
cli.ResetOutputBuffers() cli.ResetOutputBuffers()
assert.NilError(t, RunCreate(cli, &CreateOptions{ assert.NilError(t, RunCreate(cli, &CreateOptions{
Name: "original", Name: "original",
@ -278,10 +248,6 @@ func TestCreateFromCurrent(t *testing.T) {
Docker: map[string]string{ Docker: map[string]string{
keyHost: "tcp://42.42.42.42:2375", keyHost: "tcp://42.42.42.42:2375",
}, },
Kubernetes: map[string]string{
keyFrom: "default",
},
DefaultStackOrchestrator: "swarm",
})) }))
assertContextCreateLogging(t, cli, "original") assertContextCreateLogging(t, cli, "original")
@ -292,9 +258,8 @@ func TestCreateFromCurrent(t *testing.T) {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
cli.ResetOutputBuffers() cli.ResetOutputBuffers()
err := RunCreate(cli, &CreateOptions{ err := RunCreate(cli, &CreateOptions{
Name: c.name, Name: c.name,
Description: c.description, Description: c.description,
DefaultStackOrchestrator: c.orchestrator,
}) })
assert.NilError(t, err) assert.NilError(t, err)
assertContextCreateLogging(t, cli, c.name) assertContextCreateLogging(t, cli, c.name)
@ -305,7 +270,6 @@ func TestCreateFromCurrent(t *testing.T) {
dockerEndpoint, err := docker.EndpointFromContext(newContext) dockerEndpoint, err := docker.EndpointFromContext(newContext)
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, newContextTyped.Description, c.expectedDescription) assert.Equal(t, newContextTyped.Description, c.expectedDescription)
assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator)
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375") assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
}) })
} }

View File

@ -59,11 +59,10 @@ func runList(dockerCli command.Cli, opts *listOptions) error {
meta.Description = "Current DOCKER_HOST based configuration" meta.Description = "Current DOCKER_HOST based configuration"
} }
desc := formatter.ClientContext{ desc := formatter.ClientContext{
Name: rawMeta.Name, Name: rawMeta.Name,
Current: rawMeta.Name == curContext, Current: rawMeta.Name == curContext,
Description: meta.Description, Description: meta.Description,
StackOrchestrator: string(meta.StackOrchestrator), DockerEndpoint: dockerEndpoint.Host,
DockerEndpoint: dockerEndpoint.Host,
} }
contexts = append(contexts, &desc) contexts = append(contexts, &desc)
} }

View File

@ -2,8 +2,7 @@
{ {
"Name": "current", "Name": "current",
"Metadata": { "Metadata": {
"Description": "description of current", "Description": "description of current"
"StackOrchestrator": "all"
}, },
"Endpoints": { "Endpoints": {
"docker": { "docker": {

View File

@ -1,5 +1,5 @@
NAME DESCRIPTION DOCKER ENDPOINT ORCHESTRATOR NAME DESCRIPTION DOCKER ENDPOINT
current * description of current https://someswarmserver.example.com all current * description of current https://someswarmserver.example.com
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
other description of other https://someswarmserver.example.com all other description of other https://someswarmserver.example.com
unset description of unset https://someswarmserver.example.com unset description of unset https://someswarmserver.example.com

View File

@ -3,7 +3,6 @@ package context
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/sirupsen/logrus"
"text/tabwriter" "text/tabwriter"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
@ -58,10 +57,12 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
"default-stack-orchestrator", "", "default-stack-orchestrator", "",
"Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)") "Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)")
flags.SetAnnotation("default-stack-orchestrator", "deprecated", nil) flags.SetAnnotation("default-stack-orchestrator", "deprecated", nil)
flags.MarkDeprecated("default-stack-orchestrator", "option will be ignored")
flags.StringToStringVar(&opts.Docker, "docker", nil, "set the docker endpoint") flags.StringToStringVar(&opts.Docker, "docker", nil, "set the docker endpoint")
flags.StringToStringVar(&opts.Kubernetes, "kubernetes", nil, "set the kubernetes endpoint") flags.StringToStringVar(&opts.Kubernetes, "kubernetes", nil, "set the kubernetes endpoint")
flags.SetAnnotation("kubernetes", "kubernetes", nil) flags.SetAnnotation("kubernetes", "kubernetes", nil)
flags.SetAnnotation("kubernetes", "deprecated", nil) flags.SetAnnotation("kubernetes", "deprecated", nil)
flags.MarkDeprecated("kubernetes", "option will be ignored")
return cmd return cmd
} }
@ -79,13 +80,6 @@ func RunUpdate(cli command.Cli, o *UpdateOptions) error {
if err != nil { if err != nil {
return err return err
} }
if o.DefaultStackOrchestrator != "" {
stackOrchestrator, err := command.NormalizeOrchestrator(o.DefaultStackOrchestrator)
if err != nil {
return errors.Wrap(err, "unable to parse default-stack-orchestrator")
}
dockerContext.StackOrchestrator = stackOrchestrator
}
if o.Description != "" { if o.Description != "" {
dockerContext.Description = o.Description dockerContext.Description = o.Description
} }
@ -102,10 +96,7 @@ func RunUpdate(cli command.Cli, o *UpdateOptions) error {
c.Endpoints[docker.DockerEndpoint] = dockerEP c.Endpoints[docker.DockerEndpoint] = dockerEP
tlsDataToReset[docker.DockerEndpoint] = dockerTLS tlsDataToReset[docker.DockerEndpoint] = dockerTLS
} }
if len(o.Kubernetes) != 0 { if err := validateEndpoints(c); err != nil {
logrus.Warn("kubernetes orchestrator is deprecated")
}
if err := validateEndpointsAndOrchestrator(c); err != nil {
return err return err
} }
if err := s.CreateOrUpdate(c); err != nil { if err := s.CreateOrUpdate(c); err != nil {
@ -122,7 +113,7 @@ func RunUpdate(cli command.Cli, o *UpdateOptions) error {
return nil return nil
} }
func validateEndpointsAndOrchestrator(c store.Metadata) error { func validateEndpoints(c store.Metadata) error {
_, err := command.GetDockerContext(c) _, err := command.GetDockerContext(c)
return err return err
} }

View File

@ -28,7 +28,6 @@ func TestUpdateDescriptionOnly(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
dc, err := command.GetDockerContext(c) dc, err := command.GetDockerContext(c)
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, dc.StackOrchestrator, command.OrchestratorSwarm)
assert.Equal(t, dc.Description, "description") assert.Equal(t, dc.Description, "description")
assert.Equal(t, "test\n", cli.OutBuffer().String()) assert.Equal(t, "test\n", cli.OutBuffer().String())
@ -49,7 +48,6 @@ func TestUpdateDockerOnly(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
dc, err := command.GetDockerContext(c) dc, err := command.GetDockerContext(c)
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, dc.StackOrchestrator, command.OrchestratorSwarm)
assert.Equal(t, dc.Description, "description of test") assert.Equal(t, dc.Description, "description of test")
assert.Check(t, cmp.Contains(c.Endpoints, docker.DockerEndpoint)) assert.Check(t, cmp.Contains(c.Endpoints, docker.DockerEndpoint))
assert.Equal(t, c.Endpoints[docker.DockerEndpoint].(docker.EndpointMeta).Host, "tcp://some-host") assert.Equal(t, c.Endpoints[docker.DockerEndpoint].(docker.EndpointMeta).Host, "tcp://some-host")

View File

@ -9,19 +9,17 @@ import (
func TestDockerContextMetadataKeepAdditionalFields(t *testing.T) { func TestDockerContextMetadataKeepAdditionalFields(t *testing.T) {
c := DockerContext{ c := DockerContext{
Description: "test", Description: "test",
StackOrchestrator: OrchestratorSwarm,
AdditionalFields: map[string]interface{}{ AdditionalFields: map[string]interface{}{
"foo": "bar", "foo": "bar",
}, },
} }
jsonBytes, err := json.Marshal(c) jsonBytes, err := json.Marshal(c)
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, `{"Description":"test","StackOrchestrator":"swarm","foo":"bar"}`, string(jsonBytes)) assert.Equal(t, `{"Description":"test","foo":"bar"}`, string(jsonBytes))
var c2 DockerContext var c2 DockerContext
assert.NilError(t, json.Unmarshal(jsonBytes, &c2)) assert.NilError(t, json.Unmarshal(jsonBytes, &c2))
assert.Equal(t, c2.AdditionalFields["foo"], "bar") assert.Equal(t, c2.AdditionalFields["foo"], "bar")
assert.Equal(t, c2.StackOrchestrator, OrchestratorSwarm)
assert.Equal(t, c2.Description, "test") assert.Equal(t, c2.Description, "test")
} }

View File

@ -41,23 +41,18 @@ type EndpointDefaultResolver interface {
// the lack of a default (e.g. because the config file which // the lack of a default (e.g. because the config file which
// would contain it is missing). If there is no default then // would contain it is missing). If there is no default then
// returns nil, nil, nil. // returns nil, nil, nil.
ResolveDefault(Orchestrator) (interface{}, *store.EndpointTLSData, error) ResolveDefault() (interface{}, *store.EndpointTLSData, error)
} }
// ResolveDefaultContext creates a Metadata for the current CLI invocation parameters // ResolveDefaultContext creates a Metadata for the current CLI invocation parameters
func ResolveDefaultContext(opts *cliflags.CommonOptions, config *configfile.ConfigFile, storeconfig store.Config, stderr io.Writer) (*DefaultContext, error) { func ResolveDefaultContext(opts *cliflags.CommonOptions, config *configfile.ConfigFile, storeconfig store.Config, stderr io.Writer) (*DefaultContext, error) {
stackOrchestrator, err := GetStackOrchestrator("", "", config.StackOrchestrator, stderr)
if err != nil {
return nil, err
}
contextTLSData := store.ContextTLSData{ contextTLSData := store.ContextTLSData{
Endpoints: make(map[string]store.EndpointTLSData), Endpoints: make(map[string]store.EndpointTLSData),
} }
contextMetadata := store.Metadata{ contextMetadata := store.Metadata{
Endpoints: make(map[string]interface{}), Endpoints: make(map[string]interface{}),
Metadata: DockerContext{ Metadata: DockerContext{
Description: "", Description: "",
StackOrchestrator: stackOrchestrator,
}, },
Name: DefaultContextName, Name: DefaultContextName,
} }
@ -77,7 +72,7 @@ func ResolveDefaultContext(opts *cliflags.CommonOptions, config *configfile.Conf
} }
ep := get() ep := get()
if i, ok := ep.(EndpointDefaultResolver); ok { if i, ok := ep.(EndpointDefaultResolver); ok {
meta, tls, err := i.ResolveDefault(stackOrchestrator) meta, tls, err := i.ResolveDefault()
if err != nil { if err != nil {
return err return err
} }

View File

@ -71,7 +71,6 @@ func TestDefaultContextInitializer(t *testing.T) {
}, cli.ConfigFile(), DefaultContextStoreConfig(), cli.Err()) }, cli.ConfigFile(), DefaultContextStoreConfig(), cli.Err())
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, "default", ctx.Meta.Name) assert.Equal(t, "default", ctx.Meta.Name)
assert.Equal(t, OrchestratorSwarm, ctx.Meta.Metadata.(DockerContext).StackOrchestrator)
assert.DeepEqual(t, "ssh://someswarmserver", ctx.Meta.Endpoints[docker.DockerEndpoint].(docker.EndpointMeta).Host) assert.DeepEqual(t, "ssh://someswarmserver", ctx.Meta.Endpoints[docker.DockerEndpoint].(docker.EndpointMeta).Host)
golden.Assert(t, string(ctx.TLS.Endpoints[docker.DockerEndpoint].Files["ca.pem"]), "ca.pem") golden.Assert(t, string(ctx.TLS.Endpoints[docker.DockerEndpoint].Files["ca.pem"]), "ca.pem")
} }

View File

@ -2,11 +2,10 @@ package formatter
const ( const (
// ClientContextTableFormat is the default client context format // ClientContextTableFormat is the default client context format
ClientContextTableFormat = "table {{.Name}}{{if .Current}} *{{end}}\t{{.Description}}\t{{.DockerEndpoint}}\t{{.StackOrchestrator}}" ClientContextTableFormat = "table {{.Name}}{{if .Current}} *{{end}}\t{{.Description}}\t{{.DockerEndpoint}}"
dockerEndpointHeader = "DOCKER ENDPOINT" dockerEndpointHeader = "DOCKER ENDPOINT"
stackOrchestrastorHeader = "ORCHESTRATOR" quietContextFormat = "{{.Name}}"
quietContextFormat = "{{.Name}}"
) )
// NewClientContextFormat returns a Format for rendering using a Context // NewClientContextFormat returns a Format for rendering using a Context
@ -22,11 +21,10 @@ func NewClientContextFormat(source string, quiet bool) Format {
// ClientContext is a context for display // ClientContext is a context for display
type ClientContext struct { type ClientContext struct {
Name string Name string
Description string Description string
DockerEndpoint string DockerEndpoint string
StackOrchestrator string Current bool
Current bool
} }
// ClientContextWrite writes formatted contexts using the Context // ClientContextWrite writes formatted contexts using the Context
@ -50,10 +48,9 @@ type clientContextContext struct {
func newClientContextContext() *clientContextContext { func newClientContextContext() *clientContextContext {
ctx := clientContextContext{} ctx := clientContextContext{}
ctx.Header = SubHeaderContext{ ctx.Header = SubHeaderContext{
"Name": NameHeader, "Name": NameHeader,
"Description": DescriptionHeader, "Description": DescriptionHeader,
"DockerEndpoint": dockerEndpointHeader, "DockerEndpoint": dockerEndpointHeader,
"StackOrchestrator": stackOrchestrastorHeader,
} }
return &ctx return &ctx
} }
@ -81,7 +78,3 @@ func (c *clientContextContext) DockerEndpoint() string {
func (c *clientContextContext) KubernetesEndpoint() string { func (c *clientContextContext) KubernetesEndpoint() string {
return "" return ""
} }
func (c *clientContextContext) StackOrchestrator() string {
return c.c.StackOrchestrator
}

View File

@ -1,85 +0,0 @@
package command
import (
"fmt"
"io"
"os"
)
// Orchestrator type acts as an enum describing supported orchestrators.
type Orchestrator string
const (
// OrchestratorKubernetes orchestrator
OrchestratorKubernetes = Orchestrator("kubernetes")
// OrchestratorSwarm orchestrator
OrchestratorSwarm = Orchestrator("swarm")
// OrchestratorAll orchestrator
OrchestratorAll = Orchestrator("all")
orchestratorUnset = Orchestrator("")
defaultOrchestrator = OrchestratorSwarm
envVarDockerStackOrchestrator = "DOCKER_STACK_ORCHESTRATOR"
envVarDockerOrchestrator = "DOCKER_ORCHESTRATOR"
)
// HasKubernetes returns true if defined orchestrator has Kubernetes capabilities.
// Deprecated: support for kubernetes as orchestrator was removed.
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":
return OrchestratorKubernetes, nil
case "swarm":
return OrchestratorSwarm, nil
case "", "unset": // unset is the old value for orchestratorUnset. Keep accepting this for backward compat
return orchestratorUnset, nil
case "all":
return OrchestratorAll, nil
default:
return defaultOrchestrator, fmt.Errorf("specified orchestrator %q is invalid, please use either kubernetes, swarm or all", value)
}
}
// NormalizeOrchestrator parses an orchestrator value and checks if it is valid
func NormalizeOrchestrator(value string) (Orchestrator, error) {
return normalize(value)
}
// GetStackOrchestrator checks DOCKER_STACK_ORCHESTRATOR environment variable and configuration file
// orchestrator value and returns user defined Orchestrator.
func GetStackOrchestrator(flagValue, contextValue, globalDefault string, stderr io.Writer) (Orchestrator, error) {
// Check flag
if o, err := normalize(flagValue); o != orchestratorUnset {
return o, err
}
// Check environment variable
env := os.Getenv(envVarDockerStackOrchestrator)
if env == "" && os.Getenv(envVarDockerOrchestrator) != "" {
fmt.Fprintf(stderr, "WARNING: experimental environment variable %s is set. Please use %s instead\n", envVarDockerOrchestrator, envVarDockerStackOrchestrator)
}
if o, err := normalize(env); o != orchestratorUnset {
return o, err
}
if o, err := normalize(contextValue); o != orchestratorUnset {
return o, err
}
if o, err := normalize(globalDefault); o != orchestratorUnset {
return o, err
}
// Nothing set, use default orchestrator
return defaultOrchestrator, nil
}

View File

@ -1,67 +0,0 @@
package command
import (
"io/ioutil"
"testing"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/env"
)
func TestOrchestratorSwitch(t *testing.T) {
var testcases = []struct {
doc string
globalOrchestrator string
envOrchestrator string
flagOrchestrator string
contextOrchestrator string
expectedOrchestrator string
expectedSwarm bool
}{
{
doc: "default",
expectedOrchestrator: "swarm",
expectedSwarm: true,
},
{
doc: "allOrchestratorFlag",
flagOrchestrator: "all",
expectedOrchestrator: "all",
expectedSwarm: true,
},
{
doc: "contextOverridesConfigFile",
globalOrchestrator: "kubernetes",
contextOrchestrator: "swarm",
expectedOrchestrator: "swarm",
expectedSwarm: true,
},
{
doc: "envOverridesConfigFile",
globalOrchestrator: "kubernetes",
envOrchestrator: "swarm",
expectedOrchestrator: "swarm",
expectedSwarm: true,
},
{
doc: "flagOverridesEnv",
envOrchestrator: "kubernetes",
flagOrchestrator: "swarm",
expectedOrchestrator: "swarm",
expectedSwarm: true,
},
}
for _, testcase := range testcases {
t.Run(testcase.doc, func(t *testing.T) {
if testcase.envOrchestrator != "" {
defer env.Patch(t, "DOCKER_STACK_ORCHESTRATOR", testcase.envOrchestrator)()
}
orchestrator, err := GetStackOrchestrator(testcase.flagOrchestrator, testcase.contextOrchestrator, testcase.globalOrchestrator, ioutil.Discard)
assert.NilError(t, err)
assert.Check(t, is.Equal(testcase.expectedSwarm, orchestrator.HasSwarm()))
assert.Check(t, is.Equal(testcase.expectedOrchestrator, string(orchestrator)))
})
}
}

View File

@ -1,45 +1,20 @@
package stack package stack
import ( import (
"errors"
"fmt" "fmt"
"strings"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag"
) )
type commonOptions struct {
orchestrator command.Orchestrator
}
func (o *commonOptions) Orchestrator() command.Orchestrator {
if o == nil {
return command.OrchestratorSwarm
}
return o.orchestrator
}
// NewStackCommand returns a cobra command for `stack` subcommands // NewStackCommand returns a cobra command for `stack` subcommands
func NewStackCommand(dockerCli command.Cli) *cobra.Command { func NewStackCommand(dockerCli command.Cli) *cobra.Command {
var opts commonOptions
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "stack [OPTIONS]", Use: "stack [OPTIONS]",
Short: "Manage Docker stacks", Short: "Manage Docker stacks",
Args: cli.NoArgs, Args: cli.NoArgs,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { RunE: command.ShowHelp(dockerCli.Err()),
orchestrator, err := getOrchestrator(dockerCli, cmd)
if err != nil {
return err
}
opts.orchestrator = orchestrator
hideOrchestrationFlags(cmd, orchestrator)
return checkSupportedFlag(cmd, orchestrator)
},
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{ Annotations: map[string]string{
"version": "1.25", "version": "1.25",
}, },
@ -50,62 +25,18 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Err(), err) fmt.Fprintln(dockerCli.Err(), err)
return return
} }
if err := cmd.PersistentPreRunE(c, args); err != nil {
fmt.Fprintln(dockerCli.Err(), err)
return
}
hideOrchestrationFlags(c, opts.orchestrator)
defaultHelpFunc(c, args) defaultHelpFunc(c, args)
}) })
cmd.AddCommand( cmd.AddCommand(
newDeployCommand(dockerCli, &opts), newDeployCommand(dockerCli),
newListCommand(dockerCli, &opts), newListCommand(dockerCli),
newPsCommand(dockerCli, &opts), newPsCommand(dockerCli),
newRemoveCommand(dockerCli, &opts), newRemoveCommand(dockerCli),
newServicesCommand(dockerCli, &opts), newServicesCommand(dockerCli),
) )
flags := cmd.PersistentFlags() flags := cmd.PersistentFlags()
flags.String("orchestrator", "", "Orchestrator to use (swarm|all)") flags.String("orchestrator", "", "Orchestrator to use (swarm|all)")
flags.SetAnnotation("orchestrator", "deprecated", nil) flags.SetAnnotation("orchestrator", "deprecated", nil)
flags.MarkDeprecated("orchestrator", "option will be ignored")
return cmd return cmd
} }
func getOrchestrator(dockerCli command.Cli, cmd *cobra.Command) (command.Orchestrator, error) {
var orchestratorFlag string
if o, err := cmd.Flags().GetString("orchestrator"); err == nil {
orchestratorFlag = o
}
return dockerCli.StackOrchestrator(orchestratorFlag)
}
func hideOrchestrationFlags(cmd *cobra.Command, orchestrator command.Orchestrator) {
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if _, ok := f.Annotations["swarm"]; ok && !orchestrator.HasSwarm() {
f.Hidden = true
}
})
for _, subcmd := range cmd.Commands() {
hideOrchestrationFlags(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["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

@ -11,7 +11,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
func newDeployCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command { func newDeployCommand(dockerCli command.Cli) *cobra.Command {
var opts options.Deploy var opts options.Deploy
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -28,7 +28,7 @@ func newDeployCommand(dockerCli command.Cli, common *commonOptions) *cobra.Comma
if err != nil { if err != nil {
return err return err
} }
return RunDeploy(dockerCli, cmd.Flags(), config, common.Orchestrator(), opts) return RunDeploy(dockerCli, cmd.Flags(), config, opts)
}, },
} }
@ -47,7 +47,7 @@ func newDeployCommand(dockerCli command.Cli, common *commonOptions) *cobra.Comma
return cmd return cmd
} }
// RunDeploy performs a stack deploy against the specified orchestrator // RunDeploy performs a stack deploy against the specified swarm cluster
func RunDeploy(dockerCli command.Cli, flags *pflag.FlagSet, config *composetypes.Config, commonOrchestrator command.Orchestrator, opts options.Deploy) error { func RunDeploy(dockerCli command.Cli, flags *pflag.FlagSet, config *composetypes.Config, opts options.Deploy) error {
return swarm.RunDeploy(dockerCli, opts, config) return swarm.RunDeploy(dockerCli, opts, config)
} }

View File

@ -9,7 +9,7 @@ import (
) )
func TestDeployWithEmptyName(t *testing.T) { func TestDeployWithEmptyName(t *testing.T) {
cmd := newDeployCommand(test.NewFakeCli(&fakeClient{}), nil) cmd := newDeployCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetArgs([]string{"' '"}) cmd.SetArgs([]string{"' '"})
cmd.SetOut(ioutil.Discard) cmd.SetOut(ioutil.Discard)

View File

@ -8,10 +8,9 @@ import (
const ( const (
// SwarmStackTableFormat is the default Swarm stack format // SwarmStackTableFormat is the default Swarm stack format
SwarmStackTableFormat formatter.Format = "table {{.Name}}\t{{.Services}}\t{{.Orchestrator}}" SwarmStackTableFormat formatter.Format = "table {{.Name}}\t{{.Services}}"
stackServicesHeader = "SERVICES" stackServicesHeader = "SERVICES"
stackOrchestrastorHeader = "ORCHESTRATOR"
// TableFormatKey is an alias for formatter.TableFormatKey // TableFormatKey is an alias for formatter.TableFormatKey
TableFormatKey = formatter.TableFormatKey TableFormatKey = formatter.TableFormatKey
@ -29,8 +28,6 @@ type Stack struct {
Name string Name string
// Services is the number of the services // Services is the number of the services
Services int Services int
// Orchestrator is the platform where the stack is deployed
Orchestrator string
} }
// StackWrite writes formatted stacks using the Context // StackWrite writes formatted stacks using the Context
@ -54,9 +51,8 @@ type stackContext struct {
func newStackContext() *stackContext { func newStackContext() *stackContext {
stackCtx := stackContext{} stackCtx := stackContext{}
stackCtx.Header = formatter.SubHeaderContext{ stackCtx.Header = formatter.SubHeaderContext{
"Name": formatter.NameHeader, "Name": formatter.NameHeader,
"Services": stackServicesHeader, "Services": stackServicesHeader,
"Orchestrator": stackOrchestrastorHeader,
} }
return &stackCtx return &stackCtx
} }
@ -72,7 +68,3 @@ func (s *stackContext) Name() string {
func (s *stackContext) Services() string { func (s *stackContext) Services() string {
return strconv.Itoa(s.s.Services) return strconv.Itoa(s.s.Services)
} }
func (s *stackContext) Orchestrator() string {
return s.s.Orchestrator
}

View File

@ -27,9 +27,9 @@ func TestStackContextWrite(t *testing.T) {
// Table format // Table format
{ {
formatter.Context{Format: SwarmStackTableFormat}, formatter.Context{Format: SwarmStackTableFormat},
`NAME SERVICES ORCHESTRATOR `NAME SERVICES
baz 2 orchestrator1 baz 2
bar 1 orchestrator2 bar 1
`, `,
}, },
{ {
@ -49,8 +49,8 @@ bar
} }
stacks := []*Stack{ stacks := []*Stack{
{Name: "baz", Services: 2, Orchestrator: "orchestrator1"}, {Name: "baz", Services: 2},
{Name: "bar", Services: 1, Orchestrator: "orchestrator2"}, {Name: "bar", Services: 1},
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc tc := tc

View File

@ -12,7 +12,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newListCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command { func newListCommand(dockerCli command.Cli) *cobra.Command {
opts := options.List{} opts := options.List{}
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -21,7 +21,7 @@ func newListCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command
Short: "List stacks", Short: "List stacks",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return RunList(cmd, dockerCli, opts, common.orchestrator) return RunList(cmd, dockerCli, opts)
}, },
} }
@ -30,16 +30,14 @@ func newListCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command
return cmd return cmd
} }
// RunList performs a stack list against the specified orchestrator // RunList performs a stack list against the specified swarm cluster
func RunList(cmd *cobra.Command, dockerCli command.Cli, opts options.List, orchestrator command.Orchestrator) error { func RunList(cmd *cobra.Command, dockerCli command.Cli, opts options.List) error {
stacks := []*formatter.Stack{} stacks := []*formatter.Stack{}
if orchestrator.HasSwarm() { ss, err := swarm.GetStacks(dockerCli)
ss, err := swarm.GetStacks(dockerCli) if err != nil {
if err != nil { return err
return err
}
stacks = append(stacks, ss...)
} }
stacks = append(stacks, ss...)
return format(dockerCli, opts, stacks) return format(dockerCli, opts, stacks)
} }

View File

@ -4,7 +4,6 @@ import (
"io/ioutil" "io/ioutil"
"testing" "testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
. "github.com/docker/cli/internal/test/builders" // Import builders to get the builder function as package function . "github.com/docker/cli/internal/test/builders" // Import builders to get the builder function as package function
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@ -14,10 +13,6 @@ import (
"gotest.tools/v3/golden" "gotest.tools/v3/golden"
) )
var (
orchestrator = commonOptions{orchestrator: command.OrchestratorSwarm}
)
func TestListErrors(t *testing.T) { func TestListErrors(t *testing.T) {
testCases := []struct { testCases := []struct {
args []string args []string
@ -52,7 +47,7 @@ func TestListErrors(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
cmd := newListCommand(test.NewFakeCli(&fakeClient{ cmd := newListCommand(test.NewFakeCli(&fakeClient{
serviceListFunc: tc.serviceListFunc, serviceListFunc: tc.serviceListFunc,
}), &orchestrator) }))
cmd.SetArgs(tc.args) cmd.SetArgs(tc.args)
cmd.SetOut(ioutil.Discard) cmd.SetOut(ioutil.Discard)
for key, value := range tc.flags { for key, value := range tc.flags {
@ -118,7 +113,7 @@ func TestStackList(t *testing.T) {
return services, nil return services, nil
}, },
}) })
cmd := newListCommand(cli, &orchestrator) cmd := newListCommand(cli)
for key, value := range tc.flags { for key, value := range tc.flags {
cmd.Flags().Set(key, value) cmd.Flags().Set(key, value)
} }

View File

@ -10,7 +10,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
func newPsCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command { func newPsCommand(dockerCli command.Cli) *cobra.Command {
opts := options.PS{Filter: cliopts.NewFilterOpt()} opts := options.PS{Filter: cliopts.NewFilterOpt()}
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -22,7 +22,7 @@ func newPsCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command {
if err := validateStackName(opts.Namespace); err != nil { if err := validateStackName(opts.Namespace); err != nil {
return err return err
} }
return RunPs(dockerCli, cmd.Flags(), common.Orchestrator(), opts) return RunPs(dockerCli, cmd.Flags(), opts)
}, },
} }
flags := cmd.Flags() flags := cmd.Flags()
@ -34,7 +34,7 @@ func newPsCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command {
return cmd return cmd
} }
// RunPs performs a stack ps against the specified orchestrator // RunPs performs a stack ps against the specified swarm cluster
func RunPs(dockerCli command.Cli, flags *pflag.FlagSet, commonOrchestrator command.Orchestrator, opts options.PS) error { func RunPs(dockerCli command.Cli, flags *pflag.FlagSet, opts options.PS) error {
return swarm.RunPS(dockerCli, opts) return swarm.RunPS(dockerCli, opts)
} }

View File

@ -43,7 +43,7 @@ func TestStackPsErrors(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
cmd := newPsCommand(test.NewFakeCli(&fakeClient{ cmd := newPsCommand(test.NewFakeCli(&fakeClient{
taskListFunc: tc.taskListFunc, taskListFunc: tc.taskListFunc,
}), &orchestrator) }))
cmd.SetArgs(tc.args) cmd.SetArgs(tc.args)
cmd.SetOut(ioutil.Discard) cmd.SetOut(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError) assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
@ -164,7 +164,7 @@ func TestStackPs(t *testing.T) {
}) })
cli.SetConfigFile(&tc.config) cli.SetConfigFile(&tc.config)
cmd := newPsCommand(cli, &orchestrator) cmd := newPsCommand(cli)
cmd.SetArgs(tc.args) cmd.SetArgs(tc.args)
for key, value := range tc.flags { for key, value := range tc.flags {
cmd.Flags().Set(key, value) cmd.Flags().Set(key, value)

View File

@ -9,7 +9,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
func newRemoveCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command { func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
var opts options.Remove var opts options.Remove
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -22,13 +22,13 @@ func newRemoveCommand(dockerCli command.Cli, common *commonOptions) *cobra.Comma
if err := validateStackNames(opts.Namespaces); err != nil { if err := validateStackNames(opts.Namespaces); err != nil {
return err return err
} }
return RunRemove(dockerCli, cmd.Flags(), common.Orchestrator(), opts) return RunRemove(dockerCli, cmd.Flags(), opts)
}, },
} }
return cmd return cmd
} }
// RunRemove performs a stack remove against the specified orchestrator // RunRemove performs a stack remove against the specified swarm cluster
func RunRemove(dockerCli command.Cli, flags *pflag.FlagSet, commonOrchestrator command.Orchestrator, opts options.Remove) error { func RunRemove(dockerCli command.Cli, flags *pflag.FlagSet, opts options.Remove) error {
return swarm.RunRemove(dockerCli, opts) return swarm.RunRemove(dockerCli, opts)
} }

View File

@ -42,7 +42,7 @@ func fakeClientForRemoveStackTest(version string) *fakeClient {
} }
func TestRemoveWithEmptyName(t *testing.T) { func TestRemoveWithEmptyName(t *testing.T) {
cmd := newRemoveCommand(test.NewFakeCli(&fakeClient{}), &orchestrator) cmd := newRemoveCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetArgs([]string{"good", "' '", "alsogood"}) cmd.SetArgs([]string{"good", "' '", "alsogood"})
cmd.SetOut(ioutil.Discard) cmd.SetOut(ioutil.Discard)
@ -51,7 +51,7 @@ func TestRemoveWithEmptyName(t *testing.T) {
func TestRemoveStackVersion124DoesNotRemoveConfigsOrSecrets(t *testing.T) { func TestRemoveStackVersion124DoesNotRemoveConfigsOrSecrets(t *testing.T) {
client := fakeClientForRemoveStackTest("1.24") client := fakeClientForRemoveStackTest("1.24")
cmd := newRemoveCommand(test.NewFakeCli(client), &orchestrator) cmd := newRemoveCommand(test.NewFakeCli(client))
cmd.SetArgs([]string{"foo", "bar"}) cmd.SetArgs([]string{"foo", "bar"})
assert.NilError(t, cmd.Execute()) assert.NilError(t, cmd.Execute())
@ -63,7 +63,7 @@ func TestRemoveStackVersion124DoesNotRemoveConfigsOrSecrets(t *testing.T) {
func TestRemoveStackVersion125DoesNotRemoveConfigs(t *testing.T) { func TestRemoveStackVersion125DoesNotRemoveConfigs(t *testing.T) {
client := fakeClientForRemoveStackTest("1.25") client := fakeClientForRemoveStackTest("1.25")
cmd := newRemoveCommand(test.NewFakeCli(client), &orchestrator) cmd := newRemoveCommand(test.NewFakeCli(client))
cmd.SetArgs([]string{"foo", "bar"}) cmd.SetArgs([]string{"foo", "bar"})
assert.NilError(t, cmd.Execute()) assert.NilError(t, cmd.Execute())
@ -75,7 +75,7 @@ func TestRemoveStackVersion125DoesNotRemoveConfigs(t *testing.T) {
func TestRemoveStackVersion130RemovesEverything(t *testing.T) { func TestRemoveStackVersion130RemovesEverything(t *testing.T) {
client := fakeClientForRemoveStackTest("1.30") client := fakeClientForRemoveStackTest("1.30")
cmd := newRemoveCommand(test.NewFakeCli(client), &orchestrator) cmd := newRemoveCommand(test.NewFakeCli(client))
cmd.SetArgs([]string{"foo", "bar"}) cmd.SetArgs([]string{"foo", "bar"})
assert.NilError(t, cmd.Execute()) assert.NilError(t, cmd.Execute())
@ -106,7 +106,7 @@ func TestRemoveStackSkipEmpty(t *testing.T) {
configs: allConfigs, configs: allConfigs,
} }
fakeCli := test.NewFakeCli(fakeClient) fakeCli := test.NewFakeCli(fakeClient)
cmd := newRemoveCommand(fakeCli, &orchestrator) cmd := newRemoveCommand(fakeCli)
cmd.SetArgs([]string{"foo", "bar"}) cmd.SetArgs([]string{"foo", "bar"})
assert.NilError(t, cmd.Execute()) assert.NilError(t, cmd.Execute())
@ -154,7 +154,7 @@ func TestRemoveContinueAfterError(t *testing.T) {
return nil return nil
}, },
} }
cmd := newRemoveCommand(test.NewFakeCli(cli), &orchestrator) cmd := newRemoveCommand(test.NewFakeCli(cli))
cmd.SetOut(ioutil.Discard) cmd.SetOut(ioutil.Discard)
cmd.SetArgs([]string{"foo", "bar"}) cmd.SetArgs([]string{"foo", "bar"})

View File

@ -17,7 +17,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
func newServicesCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command { func newServicesCommand(dockerCli command.Cli) *cobra.Command {
opts := options.Services{Filter: cliopts.NewFilterOpt()} opts := options.Services{Filter: cliopts.NewFilterOpt()}
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -29,7 +29,7 @@ func newServicesCommand(dockerCli command.Cli, common *commonOptions) *cobra.Com
if err := validateStackName(opts.Namespace); err != nil { if err := validateStackName(opts.Namespace); err != nil {
return err return err
} }
return RunServices(dockerCli, cmd.Flags(), common.Orchestrator(), opts) return RunServices(dockerCli, cmd.Flags(), opts)
}, },
} }
flags := cmd.Flags() flags := cmd.Flags()
@ -39,17 +39,17 @@ func newServicesCommand(dockerCli command.Cli, common *commonOptions) *cobra.Com
return cmd return cmd
} }
// RunServices performs a stack services against the specified orchestrator // RunServices performs a stack services against the specified swarm cluster
func RunServices(dockerCli command.Cli, flags *pflag.FlagSet, commonOrchestrator command.Orchestrator, opts options.Services) error { func RunServices(dockerCli command.Cli, flags *pflag.FlagSet, opts options.Services) error {
services, err := GetServices(dockerCli, flags, commonOrchestrator, opts) services, err := GetServices(dockerCli, flags, opts)
if err != nil { if err != nil {
return err return err
} }
return formatWrite(dockerCli, services, opts) return formatWrite(dockerCli, services, opts)
} }
// GetServices returns the services for the specified orchestrator // GetServices returns the services for the specified swarm cluster
func GetServices(dockerCli command.Cli, flags *pflag.FlagSet, commonOrchestrator command.Orchestrator, opts options.Services) ([]swarmtypes.Service, error) { func GetServices(dockerCli command.Cli, flags *pflag.FlagSet, opts options.Services) ([]swarmtypes.Service, error) {
return swarm.GetServices(dockerCli, opts) return swarm.GetServices(dockerCli, opts)
} }

View File

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

View File

@ -29,9 +29,8 @@ func GetStacks(dockerCli command.Cli) ([]*formatter.Stack, error) {
ztack, ok := m[name] ztack, ok := m[name]
if !ok { if !ok {
m[name] = &formatter.Stack{ m[name] = &formatter.Stack{
Name: name, Name: name,
Services: 1, Services: 1,
Orchestrator: "Swarm",
} }
} else { } else {
ztack.Services++ ztack.Services++

View File

@ -1,4 +1,4 @@
NAME SERVICES ORCHESTRATOR NAME SERVICES
service-name-1-foo 1 Swarm service-name-1-foo 1
service-name-2-foo 1 Swarm service-name-2-foo 1
service-name-10-foo 1 Swarm service-name-10-foo 1

View File

@ -1,3 +1,3 @@
NAME SERVICES ORCHESTRATOR NAME SERVICES
service-name-bar 1 Swarm service-name-bar 1
service-name-foo 1 Swarm service-name-foo 1

View File

@ -1,2 +1,2 @@
NAME SERVICES ORCHESTRATOR NAME SERVICES
service-name-foo 1 Swarm service-name-foo 1

View File

@ -44,7 +44,7 @@ func (s *tlsStore) getData(contextID contextdir, endpointName, filename string)
return data, nil return data, nil
} }
func (s *tlsStore) remove(contextID contextdir, endpointName, filename string) error { func (s *tlsStore) remove(contextID contextdir, endpointName, filename string) error { // nolint:unused
err := os.Remove(s.filePath(contextID, endpointName, filename)) err := os.Remove(s.filePath(contextID, endpointName, filename))
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil return nil

View File

@ -1,3 +1,3 @@
NAME DESCRIPTION DOCKER ENDPOINT ORCHESTRATOR NAME DESCRIPTION DOCKER ENDPOINT
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
remote my remote cluster ssh://someserver kubernetes remote my remote cluster ssh://someserver

View File

@ -1,3 +1,3 @@
NAME DESCRIPTION DOCKER ENDPOINT ORCHESTRATOR NAME DESCRIPTION DOCKER ENDPOINT
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
test unix:///var/run/docker.sock swarm test unix:///var/run/docker.sock

View File

@ -1,3 +1,3 @@
NAME DESCRIPTION DOCKER ENDPOINT ORCHESTRATOR NAME DESCRIPTION DOCKER ENDPOINT
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
remote my remote cluster ssh://someserver kubernetes remote my remote cluster ssh://someserver

View File

@ -1,7 +1,6 @@
package stack package stack
import ( import (
"fmt"
"sort" "sort"
"strings" "strings"
"testing" "testing"
@ -12,23 +11,16 @@ import (
) )
func TestDeployWithNamedResources(t *testing.T) { func TestDeployWithNamedResources(t *testing.T) {
t.Run("Swarm", func(t *testing.T) { stackname := "test-stack-deploy-with-names"
testDeployWithNamedResources(t, "swarm")
})
}
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") composefile := golden.Path("stack-with-named-resources.yml")
result := icmd.RunCommand("docker", "stack", "deploy", result := icmd.RunCommand("docker", "stack", "deploy",
"-c", composefile, stackname, "--orchestrator", orchestrator) "-c", composefile, stackname)
defer icmd.RunCommand("docker", "stack", "rm", defer icmd.RunCommand("docker", "stack", "rm", stackname)
"--orchestrator", orchestrator, stackname)
result.Assert(t, icmd.Success) result.Assert(t, icmd.Success)
stdout := strings.Split(result.Stdout(), "\n") stdout := strings.Split(result.Stdout(), "\n")
expected := strings.Split(string(golden.Get(t, fmt.Sprintf("stack-deploy-with-names-%s.golden", orchestrator))), "\n") expected := strings.Split(string(golden.Get(t, "stack-deploy-with-names.golden")), "\n")
sort.Strings(stdout) sort.Strings(stdout)
sort.Strings(expected) sort.Strings(expected)
assert.DeepEqual(t, stdout, expected) assert.DeepEqual(t, stdout, expected)

View File

@ -1,7 +1,6 @@
package stack package stack
import ( import (
"fmt"
"testing" "testing"
"gotest.tools/v3/golden" "gotest.tools/v3/golden"
@ -9,13 +8,7 @@ import (
) )
func TestStackDeployHelp(t *testing.T) { func TestStackDeployHelp(t *testing.T) {
t.Run("Swarm", func(t *testing.T) { result := icmd.RunCommand("docker", "stack", "deploy", "--help")
testStackDeployHelp(t, "swarm")
})
}
func testStackDeployHelp(t *testing.T, orchestrator string) {
result := icmd.RunCommand("docker", "stack", "deploy", "--orchestrator", orchestrator, "--help")
result.Assert(t, icmd.Success) result.Assert(t, icmd.Success)
golden.Assert(t, result.Stdout(), fmt.Sprintf("stack-deploy-help-%s.golden", orchestrator)) golden.Assert(t, result.Stdout(), "stack-deploy-help.golden")
} }

View File

@ -1,7 +1,6 @@
package stack package stack
import ( import (
"fmt"
"strings" "strings"
"testing" "testing"
@ -14,40 +13,32 @@ import (
var pollSettings = environment.DefaultPollSettings var pollSettings = environment.DefaultPollSettings
func TestRemove(t *testing.T) { func TestRemove(t *testing.T) {
t.Run("Swarm", func(t *testing.T) { stackname := "test-stack-remove"
testRemove(t, "swarm") deployFullStack(t, stackname)
}) defer cleanupFullStack(t, stackname)
} result := icmd.RunCommand("docker", "stack", "rm", stackname)
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", "stack", "rm",
stackname, "--orchestrator", orchestrator)
result.Assert(t, icmd.Expected{Err: icmd.None}) result.Assert(t, icmd.Expected{Err: icmd.None})
golden.Assert(t, result.Stdout(), golden.Assert(t, result.Stdout(), "stack-remove-success.golden")
fmt.Sprintf("stack-remove-%s-success.golden", orchestrator))
} }
func deployFullStack(t *testing.T, orchestrator, stackname string) { func deployFullStack(t *testing.T, stackname string) {
// TODO: this stack should have full options not minimal options // TODO: this stack should have full options not minimal options
result := icmd.RunCommand("docker", "stack", "deploy", result := icmd.RunCommand("docker", "stack", "deploy",
"--compose-file=./testdata/full-stack.yml", stackname, "--orchestrator", orchestrator) "--compose-file=./testdata/full-stack.yml", stackname)
result.Assert(t, icmd.Success) result.Assert(t, icmd.Success)
poll.WaitOn(t, taskCount(orchestrator, stackname, 2), pollSettings) poll.WaitOn(t, taskCount(stackname, 2), pollSettings)
} }
func cleanupFullStack(t *testing.T, orchestrator, stackname string) { func cleanupFullStack(t *testing.T, stackname string) {
// FIXME(vdemeester) we shouldn't have to do that. it is hiding a race on docker stack rm // FIXME(vdemeester) we shouldn't have to do that. it is hiding a race on docker stack rm
poll.WaitOn(t, stackRm(orchestrator, stackname), pollSettings) poll.WaitOn(t, stackRm(stackname), pollSettings)
poll.WaitOn(t, taskCount(orchestrator, stackname, 0), pollSettings) poll.WaitOn(t, taskCount(stackname, 0), pollSettings)
} }
func stackRm(orchestrator, stackname string) func(t poll.LogT) poll.Result { func stackRm(stackname string) func(t poll.LogT) poll.Result {
return func(poll.LogT) poll.Result { return func(poll.LogT) poll.Result {
result := icmd.RunCommand("docker", "stack", "rm", stackname, "--orchestrator", orchestrator) result := icmd.RunCommand("docker", "stack", "rm", stackname)
if result.Error != nil { if result.Error != nil {
if strings.Contains(result.Stderr(), "not found") { if strings.Contains(result.Stderr(), "not found") {
return poll.Success() return poll.Success()
@ -58,14 +49,9 @@ func stackRm(orchestrator, stackname string) func(t poll.LogT) poll.Result {
} }
} }
func taskCount(orchestrator, stackname string, expected int) func(t poll.LogT) poll.Result { func taskCount(stackname string, expected int) func(t poll.LogT) poll.Result {
return func(poll.LogT) poll.Result { return func(poll.LogT) poll.Result {
args := []string{"stack", "ps", stackname, "--orchestrator", orchestrator} result := icmd.RunCommand("docker", "stack", "ps", stackname, "-f=desired-state=running")
// FIXME(chris-crone): remove when we support filtering by desired-state on kubernetes
if orchestrator == "swarm" {
args = append(args, "-f=desired-state=running")
}
result := icmd.RunCommand("docker", args...)
count := lines(result.Stdout()) - 1 count := lines(result.Stdout()) - 1
if count == expected { if count == expected {
return poll.Success() return poll.Success()

View File

@ -9,7 +9,6 @@ Aliases:
Options: Options:
-c, --compose-file strings Path to a Compose file, or "-" to read -c, --compose-file strings Path to a Compose file, or "-" to read
from stdin from stdin
--orchestrator string Orchestrator to use (swarm|all)
--prune Prune services that are no longer referenced --prune Prune services that are no longer referenced
--resolve-image string Query the registry to resolve image digest --resolve-image string Query the registry to resolve image digest
and supported platforms and supported platforms

View File

@ -1,7 +0,0 @@
Creating network test-stack-deploy-with-names-swarm_network2
Creating network named-network
Creating secret named-secret
Creating secret test-stack-deploy-with-names-swarm_secret2
Creating config test-stack-deploy-with-names-swarm_config2
Creating config named-config
Creating service test-stack-deploy-with-names-swarm_web

View File

@ -0,0 +1,3 @@
Removing service test-stack-remove_one
Removing service test-stack-remove_two
Removing network test-stack-remove_default

View File

@ -1,3 +0,0 @@
Removing service test-stack-remove-swarm_one
Removing service test-stack-remove-swarm_two
Removing network test-stack-remove-swarm_default

View File

@ -55,7 +55,8 @@ func NewFakeCli(client client.APIClient, opts ...func(*FakeCli)) *FakeCli {
in: streams.NewIn(ioutil.NopCloser(strings.NewReader(""))), in: streams.NewIn(ioutil.NopCloser(strings.NewReader(""))),
// Use an empty string for filename so that tests don't create configfiles // Use an empty string for filename so that tests don't create configfiles
// Set cli.ConfigFile().Filename to a tempfile to support Save. // Set cli.ConfigFile().Filename to a tempfile to support Save.
configfile: configfile.New(""), configfile: configfile.New(""),
currentContext: command.DefaultContextName,
} }
for _, opt := range opts { for _, opt := range opts {
opt(c) opt(c)
@ -214,24 +215,3 @@ func (c *FakeCli) ContentTrustEnabled() bool {
func EnableContentTrust(c *FakeCli) { func EnableContentTrust(c *FakeCli) {
c.contentTrust = true c.contentTrust = true
} }
// StackOrchestrator return the selected stack orchestrator
func (c *FakeCli) StackOrchestrator(flagValue string) (command.Orchestrator, error) {
configOrchestrator := ""
if c.configfile != nil {
configOrchestrator = c.configfile.StackOrchestrator
}
ctxOrchestrator := ""
if c.currentContext != "" && c.contextStore != nil {
meta, err := c.contextStore.GetMetadata(c.currentContext)
if err != nil {
return "", err
}
context, err := command.GetDockerContext(meta)
if err != nil {
return "", err
}
ctxOrchestrator = string(context.StackOrchestrator)
}
return command.GetStackOrchestrator(flagValue, ctxOrchestrator, configOrchestrator, c.err)
}