From d26783c3226e694ab412291e022e5785801cec88 Mon Sep 17 00:00:00 2001 From: aiordache Date: Tue, 2 Mar 2021 15:21:54 +0100 Subject: [PATCH 1/9] Add connection flags to root command Signed-off-by: aiordache --- api/context/context.go | 27 +++++++++++++++++++++++++++ cli/main.go | 34 ++++++++++++++++++++++++++++------ cli/options/options.go | 10 ++++------ local/backend.go | 9 ++++++--- local/containers.go | 3 ++- local/volumes.go | 2 +- 6 files changed, 68 insertions(+), 17 deletions(-) diff --git a/api/context/context.go b/api/context/context.go index b1138c31f..6d03e159c 100644 --- a/api/context/context.go +++ b/api/context/context.go @@ -20,9 +20,14 @@ import ( gocontext "context" "golang.org/x/net/context" + + configfile "github.com/docker/cli/cli/config/configfile" + cliflags "github.com/docker/cli/cli/flags" ) type currentContextKey struct{} +type cliOptionsKey struct{} +type configKey struct{} // WithCurrentContext sets the name of the current docker context func WithCurrentContext(ctx gocontext.Context, contextName string) context.Context { @@ -34,3 +39,25 @@ func CurrentContext(ctx context.Context) string { cc, _ := ctx.Value(currentContextKey{}).(string) return cc } + +// WithCliOptions sets CLI options +func WithCliOptions(ctx gocontext.Context, options cliflags.CommonOptions) context.Context { + return context.WithValue(ctx, cliOptionsKey{}, options) +} + +// CliOptions returns the current context name +func CliOptions(ctx context.Context) cliflags.CommonOptions { + cc, _ := ctx.Value(cliOptionsKey{}).(cliflags.CommonOptions) + return cc +} + +// WithConfig sets docker config +func WithConfig(ctx gocontext.Context, config configfile.ConfigFile) context.Context { + return context.WithValue(ctx, configKey{}, config) +} + +// Config returns the docker config +func Config(ctx context.Context) configfile.ConfigFile { + cc, _ := ctx.Value(cliOptionsKey{}).(configfile.ConfigFile) + return cc +} diff --git a/cli/main.go b/cli/main.go index eb59c0056..f4c52b2dc 100644 --- a/cli/main.go +++ b/cli/main.go @@ -47,6 +47,9 @@ import ( "github.com/docker/compose-cli/cli/mobycli" cliopts "github.com/docker/compose-cli/cli/options" + cliconfig "github.com/docker/cli/cli/config" + cliflags "github.com/docker/cli/cli/flags" + // Backend registrations _ "github.com/docker/compose-cli/aci" _ "github.com/docker/compose-cli/ecs" @@ -151,10 +154,7 @@ func main() { }) flags := root.Flags() - flags.StringVarP(&opts.LogLevel, "log-level", "l", "info", "Set the logging level (\"debug\"|\"info\"|\"warn\"|\"error\"|\"fatal\")") - flags.BoolVarP(&opts.Debug, "debug", "D", false, "Enable debug output in the logs") - flags.StringVarP(&opts.Host, "host", "H", "", "Daemon socket(s) to connect to") - opts.AddContextFlags(flags) + opts.InstallFlags(flags) opts.AddConfigFlags(flags) flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit") @@ -184,8 +184,8 @@ func main() { ctx, cancel := newSigContext() defer cancel() - // --host and --version should immediately be forwarded to the original cli - if opts.Host != "" || opts.Version { + // --version should immediately be forwarded to the original cli + if opts.Version { mobycli.Exec(root) } @@ -214,7 +214,29 @@ func main() { volume.Command(ctype), ) + configFile, err := cliconfig.Load(opts.Config) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to load docker config: %s\n", opts.Config) + os.Exit(1) + } + ctx = apicontext.WithConfig(ctx, *configFile) ctx = apicontext.WithCurrentContext(ctx, currentContext) + + cnxOptions := cliflags.CommonOptions{ + Context: opts.Context, + Debug: opts.Debug, + Hosts: opts.Hosts, + LogLevel: opts.LogLevel, + TLS: opts.TLS, + TLSVerify: opts.TLSVerify, + } + if len(opts.Hosts) == 0 { + cnxOptions.Context = currentContext + } + if opts.TLSVerify { + cnxOptions.TLSOptions = opts.TLSOptions + } + ctx = apicontext.WithCliOptions(ctx, cnxOptions) ctx = store.WithContextStore(ctx, s) if err = root.ExecuteContext(ctx); err != nil { diff --git a/cli/options/options.go b/cli/options/options.go index 764c9cb57..c65e62aed 100644 --- a/cli/options/options.go +++ b/cli/options/options.go @@ -17,16 +17,14 @@ package options import ( - apicontext "github.com/docker/compose-cli/api/context" cliconfig "github.com/docker/compose-cli/cli/config" + + cliflags "github.com/docker/cli/cli/flags" ) // GlobalOpts contains the global CLI options type GlobalOpts struct { - apicontext.ContextFlags cliconfig.ConfigFlags - Debug bool - LogLevel string - Version bool - Host string + cliflags.CommonOptions + Version bool } diff --git a/local/backend.go b/local/backend.go index 0e5ea277e..5e2f042f0 100644 --- a/local/backend.go +++ b/local/backend.go @@ -19,12 +19,12 @@ package local import ( "context" - "github.com/docker/docker/client" - + "github.com/docker/cli/cli/command" "github.com/docker/compose-cli/api/backend" "github.com/docker/compose-cli/api/cloud" "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/containers" + apicontext "github.com/docker/compose-cli/api/context" "github.com/docker/compose-cli/api/resources" "github.com/docker/compose-cli/api/secrets" "github.com/docker/compose-cli/api/volumes" @@ -42,7 +42,10 @@ func init() { } func service(ctx context.Context) (backend.Service, error) { - apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + options := apicontext.CliOptions(ctx) + config := apicontext.Config(ctx) + + apiClient, err := command.NewAPIClientFromFlags(&options, &config) if err != nil { return nil, err } diff --git a/local/containers.go b/local/containers.go index e3e72d25c..f2b28738a 100644 --- a/local/containers.go +++ b/local/containers.go @@ -39,10 +39,11 @@ import ( ) type containerService struct { - apiClient *client.Client + apiClient client.APIClient } func (cs *containerService) Inspect(ctx context.Context, id string) (containers.Container, error) { + c, err := cs.apiClient.ContainerInspect(ctx, id) if err != nil { return containers.Container{}, err diff --git a/local/volumes.go b/local/volumes.go index 2fbf08b77..9b49aaf42 100644 --- a/local/volumes.go +++ b/local/volumes.go @@ -29,7 +29,7 @@ import ( ) type volumeService struct { - apiClient *client.Client + apiClient client.APIClient } func (vs *volumeService) List(ctx context.Context) ([]volumes.Volume, error) { From 6f1d88e3bc3d5c6858e68a4376382fbc3a7cef6f Mon Sep 17 00:00:00 2001 From: aiordache Date: Thu, 4 Mar 2021 17:59:09 +0100 Subject: [PATCH 2/9] Fix test and load dockerconfig in the backend Signed-off-by: aiordache --- cli/main.go | 7 ------- local/backend.go | 13 ++++++++++--- local/e2e/cli-only/e2e_test.go | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cli/main.go b/cli/main.go index f4c52b2dc..0153823ae 100644 --- a/cli/main.go +++ b/cli/main.go @@ -47,7 +47,6 @@ import ( "github.com/docker/compose-cli/cli/mobycli" cliopts "github.com/docker/compose-cli/cli/options" - cliconfig "github.com/docker/cli/cli/config" cliflags "github.com/docker/cli/cli/flags" // Backend registrations @@ -214,12 +213,6 @@ func main() { volume.Command(ctype), ) - configFile, err := cliconfig.Load(opts.Config) - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to load docker config: %s\n", opts.Config) - os.Exit(1) - } - ctx = apicontext.WithConfig(ctx, *configFile) ctx = apicontext.WithCurrentContext(ctx, currentContext) cnxOptions := cliflags.CommonOptions{ diff --git a/local/backend.go b/local/backend.go index 5e2f042f0..fa79f1ebf 100644 --- a/local/backend.go +++ b/local/backend.go @@ -22,13 +22,17 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/compose-cli/api/backend" "github.com/docker/compose-cli/api/cloud" + "github.com/docker/compose-cli/api/compose" + apiconfig "github.com/docker/compose-cli/api/config" "github.com/docker/compose-cli/api/containers" apicontext "github.com/docker/compose-cli/api/context" "github.com/docker/compose-cli/api/resources" "github.com/docker/compose-cli/api/secrets" "github.com/docker/compose-cli/api/volumes" local_compose "github.com/docker/compose-cli/local/compose" + + cliconfig "github.com/docker/cli/cli/config" ) type local struct { @@ -43,9 +47,12 @@ func init() { func service(ctx context.Context) (backend.Service, error) { options := apicontext.CliOptions(ctx) - config := apicontext.Config(ctx) - - apiClient, err := command.NewAPIClientFromFlags(&options, &config) + config := apiconfig.Dir(ctx) + configFile, err := cliconfig.Load(config) + if err != nil { + return nil, err + } + apiClient, err := command.NewAPIClientFromFlags(&options, configFile) if err != nil { return nil, err } diff --git a/local/e2e/cli-only/e2e_test.go b/local/e2e/cli-only/e2e_test.go index 40faf6f93..8b8f1b75a 100644 --- a/local/e2e/cli-only/e2e_test.go +++ b/local/e2e/cli-only/e2e_test.go @@ -396,11 +396,11 @@ func TestLegacy(t *testing.T) { }) t.Run("host flag", func(t *testing.T) { - stderr := "Cannot connect to the Docker daemon at tcp://localhost:123" + stderr := "nonexistent: Name or service not known" if runtime.GOOS == "windows" { - stderr = "error during connect: Get http://localhost:123" + stderr = "error during connect: Get http://nonexitent:123" } - res := c.RunDockerOrExitError("-H", "tcp://localhost:123", "version") + res := c.RunDockerOrExitError("-H", "tcp://nonexistent:123", "version") res.Assert(t, icmd.Expected{ ExitCode: 1, Err: stderr, From f0fd18eec9d85e6b818a296c85f06dbc9af2b080 Mon Sep 17 00:00:00 2001 From: aiordache Date: Thu, 4 Mar 2021 18:38:09 +0100 Subject: [PATCH 3/9] set current context to default when -H flag is set Signed-off-by: aiordache --- cli/main.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cli/main.go b/cli/main.go index 0153823ae..6812661df 100644 --- a/cli/main.go +++ b/cli/main.go @@ -195,6 +195,10 @@ func main() { ctx = config.WithDir(ctx, configDir) currentContext := determineCurrentContext(opts.Context, configDir) + if len(opts.Hosts) > 0 { + opts.Context = "" + currentContext = "default" + } s, err := store.New(configDir) if err != nil { @@ -213,8 +217,6 @@ func main() { volume.Command(ctype), ) - ctx = apicontext.WithCurrentContext(ctx, currentContext) - cnxOptions := cliflags.CommonOptions{ Context: opts.Context, Debug: opts.Debug, @@ -223,13 +225,12 @@ func main() { TLS: opts.TLS, TLSVerify: opts.TLSVerify, } - if len(opts.Hosts) == 0 { - cnxOptions.Context = currentContext - } + if opts.TLSVerify { cnxOptions.TLSOptions = opts.TLSOptions } ctx = apicontext.WithCliOptions(ctx, cnxOptions) + ctx = apicontext.WithCurrentContext(ctx, currentContext) ctx = store.WithContextStore(ctx, s) if err = root.ExecuteContext(ctx); err != nil { From 6458b97089faf97cf6c637a00a0fa52b68c05076 Mon Sep 17 00:00:00 2001 From: aiordache Date: Fri, 5 Mar 2021 14:29:42 +0100 Subject: [PATCH 4/9] test fix Signed-off-by: aiordache --- api/context/context.go | 13 ------------- cli/main.go | 32 +++++++++++++++++--------------- local/e2e/cli-only/e2e_test.go | 4 ++-- 3 files changed, 19 insertions(+), 30 deletions(-) diff --git a/api/context/context.go b/api/context/context.go index 6d03e159c..b0c1f64e9 100644 --- a/api/context/context.go +++ b/api/context/context.go @@ -21,13 +21,11 @@ import ( "golang.org/x/net/context" - configfile "github.com/docker/cli/cli/config/configfile" cliflags "github.com/docker/cli/cli/flags" ) type currentContextKey struct{} type cliOptionsKey struct{} -type configKey struct{} // WithCurrentContext sets the name of the current docker context func WithCurrentContext(ctx gocontext.Context, contextName string) context.Context { @@ -50,14 +48,3 @@ func CliOptions(ctx context.Context) cliflags.CommonOptions { cc, _ := ctx.Value(cliOptionsKey{}).(cliflags.CommonOptions) return cc } - -// WithConfig sets docker config -func WithConfig(ctx gocontext.Context, config configfile.ConfigFile) context.Context { - return context.WithValue(ctx, configKey{}, config) -} - -// Config returns the docker config -func Config(ctx context.Context) configfile.ConfigFile { - cc, _ := ctx.Value(cliOptionsKey{}).(configfile.ConfigFile) - return cc -} diff --git a/cli/main.go b/cli/main.go index 6812661df..3ce8b3d10 100644 --- a/cli/main.go +++ b/cli/main.go @@ -195,10 +195,6 @@ func main() { ctx = config.WithDir(ctx, configDir) currentContext := determineCurrentContext(opts.Context, configDir) - if len(opts.Hosts) > 0 { - opts.Context = "" - currentContext = "default" - } s, err := store.New(configDir) if err != nil { @@ -216,20 +212,26 @@ func main() { compose.Command(ctype), volume.Command(ctype), ) + if ctype == store.LocalContextType { + if len(opts.Hosts) > 0 { + opts.Context = "" + currentContext = "default" + } - cnxOptions := cliflags.CommonOptions{ - Context: opts.Context, - Debug: opts.Debug, - Hosts: opts.Hosts, - LogLevel: opts.LogLevel, - TLS: opts.TLS, - TLSVerify: opts.TLSVerify, - } + cnxOptions := cliflags.CommonOptions{ + Context: opts.Context, + Debug: opts.Debug, + Hosts: opts.Hosts, + LogLevel: opts.LogLevel, + TLS: opts.TLS, + TLSVerify: opts.TLSVerify, + } - if opts.TLSVerify { - cnxOptions.TLSOptions = opts.TLSOptions + if opts.TLSVerify { + cnxOptions.TLSOptions = opts.TLSOptions + } + ctx = apicontext.WithCliOptions(ctx, cnxOptions) } - ctx = apicontext.WithCliOptions(ctx, cnxOptions) ctx = apicontext.WithCurrentContext(ctx, currentContext) ctx = store.WithContextStore(ctx, s) diff --git a/local/e2e/cli-only/e2e_test.go b/local/e2e/cli-only/e2e_test.go index 8b8f1b75a..3d2b002e9 100644 --- a/local/e2e/cli-only/e2e_test.go +++ b/local/e2e/cli-only/e2e_test.go @@ -396,15 +396,15 @@ func TestLegacy(t *testing.T) { }) t.Run("host flag", func(t *testing.T) { - stderr := "nonexistent: Name or service not known" + stderr := "dial tcp: lookup nonexistent" if runtime.GOOS == "windows" { stderr = "error during connect: Get http://nonexitent:123" } res := c.RunDockerOrExitError("-H", "tcp://nonexistent:123", "version") res.Assert(t, icmd.Expected{ ExitCode: 1, - Err: stderr, }) + assert.Assert(t, strings.Contains(res.Stderr(), stderr), res.Stderr()) }) t.Run("existing contexts delegate", func(t *testing.T) { From 34df3caaaf2d40e34120cf4921eff6999ea8ef46 Mon Sep 17 00:00:00 2001 From: aiordache Date: Fri, 5 Mar 2021 15:44:01 +0100 Subject: [PATCH 5/9] Update error message for Windows Signed-off-by: aiordache --- local/e2e/cli-only/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local/e2e/cli-only/e2e_test.go b/local/e2e/cli-only/e2e_test.go index 3d2b002e9..09aac2031 100644 --- a/local/e2e/cli-only/e2e_test.go +++ b/local/e2e/cli-only/e2e_test.go @@ -398,7 +398,7 @@ func TestLegacy(t *testing.T) { t.Run("host flag", func(t *testing.T) { stderr := "dial tcp: lookup nonexistent" if runtime.GOOS == "windows" { - stderr = "error during connect: Get http://nonexitent:123" + stderr = "dial tcp: lookup nonexistent: no such host" } res := c.RunDockerOrExitError("-H", "tcp://nonexistent:123", "version") res.Assert(t, icmd.Expected{ From fef479ad1f11a76fdd0094499bad8dbacffee46f Mon Sep 17 00:00:00 2001 From: aiordache Date: Fri, 5 Mar 2021 16:30:52 +0100 Subject: [PATCH 6/9] update test Signed-off-by: aiordache --- cli/main.go | 2 +- local/e2e/cli-only/e2e_test.go | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/cli/main.go b/cli/main.go index 3ce8b3d10..02e15ec41 100644 --- a/cli/main.go +++ b/cli/main.go @@ -212,7 +212,7 @@ func main() { compose.Command(ctype), volume.Command(ctype), ) - if ctype == store.LocalContextType { + if ctype == store.DefaultContextType || ctype == store.LocalContextType { if len(opts.Hosts) > 0 { opts.Context = "" currentContext = "default" diff --git a/local/e2e/cli-only/e2e_test.go b/local/e2e/cli-only/e2e_test.go index 09aac2031..d02338267 100644 --- a/local/e2e/cli-only/e2e_test.go +++ b/local/e2e/cli-only/e2e_test.go @@ -396,15 +396,14 @@ func TestLegacy(t *testing.T) { }) t.Run("host flag", func(t *testing.T) { - stderr := "dial tcp: lookup nonexistent" - if runtime.GOOS == "windows" { - stderr = "dial tcp: lookup nonexistent: no such host" - } + stderr := []string{"dial tcp: lookup nonexistent", "no such host"} res := c.RunDockerOrExitError("-H", "tcp://nonexistent:123", "version") res.Assert(t, icmd.Expected{ ExitCode: 1, }) - assert.Assert(t, strings.Contains(res.Stderr(), stderr), res.Stderr()) + for _, s := range stderr { + assert.Assert(t, strings.Contains(res.Stderr(), s), res.Stderr()) + } }) t.Run("existing contexts delegate", func(t *testing.T) { From 29cc59cf42eb5fd7e04b3415b4ef2bca18ccdf05 Mon Sep 17 00:00:00 2001 From: aiordache Date: Fri, 5 Mar 2021 17:45:04 +0100 Subject: [PATCH 7/9] Return exit code 1 if engine error on version query Signed-off-by: aiordache --- api/context/context.go | 2 +- cli/cmd/version.go | 28 ++++++++++++++++++---------- local/e2e/cli-only/e2e_test.go | 14 +++++++------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/api/context/context.go b/api/context/context.go index b0c1f64e9..27ac5e36f 100644 --- a/api/context/context.go +++ b/api/context/context.go @@ -43,7 +43,7 @@ func WithCliOptions(ctx gocontext.Context, options cliflags.CommonOptions) conte return context.WithValue(ctx, cliOptionsKey{}, options) } -// CliOptions returns the current context name +// CliOptions returns common cli options func CliOptions(ctx context.Context) cliflags.CommonOptions { cc, _ := ctx.Value(cliOptionsKey{}).(cliflags.CommonOptions) return cc diff --git a/cli/cmd/version.go b/cli/cmd/version.go index 89ea64770..878d0b1e5 100644 --- a/cli/cmd/version.go +++ b/cli/cmd/version.go @@ -36,8 +36,12 @@ func VersionCommand() *cobra.Command { Use: "version", Short: "Show the Docker version information", Args: cobra.MaximumNArgs(0), - Run: func(cmd *cobra.Command, _ []string) { - runVersion(cmd) + RunE: func(cmd *cobra.Command, _ []string) error { + err := runVersion(cmd) + if err != nil { + return ExitCodeError{ExitCode: 1} + } + return nil }, } // define flags for backward compatibility with com.docker.cli @@ -48,34 +52,38 @@ func VersionCommand() *cobra.Command { return cmd } -func runVersion(cmd *cobra.Command) { +func runVersion(cmd *cobra.Command) error { var versionString string + var err error format := strings.ToLower(strings.ReplaceAll(cmd.Flag(formatOpt).Value.String(), " ", "")) displayedVersion := strings.TrimPrefix(internal.Version, "v") // Replace is preferred in this case to keep the order. switch format { case formatter.PRETTY, "": - versionString = strings.Replace(getOutFromMoby(cmd, fixedPrettyArgs(os.Args[1:])...), + versionString, err = getOutFromMoby(cmd, fixedPrettyArgs(os.Args[1:])...) + versionString = strings.Replace(versionString, "\n Version:", "\n Cloud integration: "+displayedVersion+"\n Version:", 1) case formatter.JSON, formatter.TemplateLegacyJSON: // Try to catch full JSON formats - versionString = strings.Replace(getOutFromMoby(cmd, fixedJSONArgs(os.Args[1:])...), + versionString, err = getOutFromMoby(cmd, fixedJSONArgs(os.Args[1:])...) + versionString = strings.Replace(versionString, `"Version":`, fmt.Sprintf(`"CloudIntegration":%q,"Version":`, displayedVersion), 1) default: - versionString = getOutFromMoby(cmd) + versionString, err = getOutFromMoby(cmd) } fmt.Print(versionString) + return err } -func getOutFromMoby(cmd *cobra.Command, args ...string) string { - versionResult, _ := mobycli.ExecSilent(cmd.Context(), args...) +func getOutFromMoby(cmd *cobra.Command, args ...string) (string, error) { + versionResult, err := mobycli.ExecSilent(cmd.Context(), args...) // we don't want to fail on error, there is an error if the engine is not available but it displays client version info // Still, technically the [] byte versionResult could be nil, just let the original command display what it has to display if versionResult == nil { mobycli.Exec(cmd.Root()) - return "" + return "", nil } - return string(versionResult) + return string(versionResult), err } func fixedPrettyArgs(oArgs []string) []string { diff --git a/local/e2e/cli-only/e2e_test.go b/local/e2e/cli-only/e2e_test.go index d02338267..689cc56ba 100644 --- a/local/e2e/cli-only/e2e_test.go +++ b/local/e2e/cli-only/e2e_test.go @@ -396,14 +396,14 @@ func TestLegacy(t *testing.T) { }) t.Run("host flag", func(t *testing.T) { - stderr := []string{"dial tcp: lookup nonexistent", "no such host"} - res := c.RunDockerOrExitError("-H", "tcp://nonexistent:123", "version") - res.Assert(t, icmd.Expected{ - ExitCode: 1, - }) - for _, s := range stderr { - assert.Assert(t, strings.Contains(res.Stderr(), s), res.Stderr()) + stderr := "dial tcp: lookup nonexistent" + if runtime.GOOS == "windows" { + stderr = "dial tcp: lookup nonexistent: no such host" } + res := c.RunDockerOrExitError("-H", "tcp://nonexistent:123", "version") + assert.Assert(t, res.ExitCode == 1) + assert.Assert(t, strings.Contains(res.Stdout(), stderr), res.Stdout()) + }) t.Run("existing contexts delegate", func(t *testing.T) { From f1f4ca483330bae0d7e0518e34546be3fd927ad6 Mon Sep 17 00:00:00 2001 From: aiordache Date: Mon, 8 Mar 2021 19:28:16 +0100 Subject: [PATCH 8/9] Check -H flags and DOCKER_HOST/DOCKER_CONTEXT vars when determining current context Signed-off-by: aiordache --- cli/main.go | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/cli/main.go b/cli/main.go index 02e15ec41..2500cf228 100644 --- a/cli/main.go +++ b/cli/main.go @@ -191,10 +191,11 @@ func main() { if opts.Config == "" { fatal(errors.New("config path cannot be empty")) } + configDir := opts.Config ctx = config.WithDir(ctx, configDir) - currentContext := determineCurrentContext(opts.Context, configDir) + currentContext := determineCurrentContext(opts.Context, configDir, opts.Hosts) s, err := store.New(configDir) if err != nil { @@ -213,11 +214,6 @@ func main() { volume.Command(ctype), ) if ctype == store.DefaultContextType || ctype == store.LocalContextType { - if len(opts.Hosts) > 0 { - opts.Context = "" - currentContext = "default" - } - cnxOptions := cliflags.CommonOptions{ Context: opts.Context, Debug: opts.Debug, @@ -320,15 +316,31 @@ func newSigContext() (context.Context, func()) { return ctx, cancel } -func determineCurrentContext(flag string, configDir string) string { +func determineCurrentContext(flag string, configDir string, hosts []string) string { + // host and context flags cannot be both set at the same time -- the local backend enforces this when resolving hostname + // -H flag disables context --> set default as current + if len(hosts) > 0 { + return "default" + } + // DOCKER_HOST disables context --> set default as current + if _, present := os.LookupEnv("DOCKER_HOST"); present { + return "default" + } res := flag if res == "" { - config, err := config.LoadFile(configDir) - if err != nil { - fmt.Fprintln(os.Stderr, errors.Wrap(err, "WARNING")) - return "default" + // check if DOCKER_CONTEXT env variable was set + if _, present := os.LookupEnv("DOCKER_CONTEXT"); present { + res = os.Getenv("DOCKER_CONTEXT") + } + + if res == "" { + config, err := config.LoadFile(configDir) + if err != nil { + fmt.Fprintln(os.Stderr, errors.Wrap(err, "WARNING")) + return "default" + } + res = config.CurrentContext } - res = config.CurrentContext } if res == "" { res = "default" From bc0611ad5210e8a194ea684dd85e401137dd7e2c Mon Sep 17 00:00:00 2001 From: aiordache Date: Tue, 9 Mar 2021 09:52:07 +0100 Subject: [PATCH 9/9] Update tests for determining current context Signed-off-by: aiordache --- cli/main_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cli/main_test.go b/cli/main_test.go index bb62ee04a..3a0ee145c 100644 --- a/cli/main_test.go +++ b/cli/main_test.go @@ -44,20 +44,24 @@ func TestDetermineCurrentContext(t *testing.T) { assert.NilError(t, err) // If nothing set, fallback to default - c := determineCurrentContext("", "") + c := determineCurrentContext("", "", []string{}) assert.Equal(t, c, "default") // If context flag set, use that - c = determineCurrentContext("other-context", "") + c = determineCurrentContext("other-context", "", []string{}) assert.Equal(t, c, "other-context") // If no context flag, use config - c = determineCurrentContext("", d) + c = determineCurrentContext("", d, []string{}) assert.Equal(t, c, "some-context") // Ensure context flag overrides config - c = determineCurrentContext("other-context", d) + c = determineCurrentContext("other-context", d, []string{}) assert.Equal(t, "other-context", c) + + // Ensure host flag overrides context + c = determineCurrentContext("other-context", d, []string{"hostname"}) + assert.Equal(t, "default", c) } func TestCheckOwnCommand(t *testing.T) {