Pārlūkot izejas kodu

Merge pull request #1400 from docker/tls_flags

Nicolas De loof 4 gadi atpakaļ
vecāks
revīzija
3999eea066

+ 14 - 0
api/context/context.go

@@ -20,9 +20,12 @@ import (
 	gocontext "context"
 
 	"golang.org/x/net/context"
+
+	cliflags "github.com/docker/cli/cli/flags"
 )
 
 type currentContextKey struct{}
+type cliOptionsKey struct{}
 
 // WithCurrentContext sets the name of the current docker context
 func WithCurrentContext(ctx gocontext.Context, contextName string) context.Context {
@@ -34,3 +37,14 @@ 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 common cli options
+func CliOptions(ctx context.Context) cliflags.CommonOptions {
+	cc, _ := ctx.Value(cliOptionsKey{}).(cliflags.CommonOptions)
+	return cc
+}

+ 18 - 10
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 {

+ 43 - 13
cli/main.go

@@ -47,6 +47,8 @@ import (
 	"github.com/docker/compose-cli/cli/mobycli"
 	cliopts "github.com/docker/compose-cli/cli/options"
 
+	cliflags "github.com/docker/cli/cli/flags"
+
 	// Backend registrations
 	_ "github.com/docker/compose-cli/aci"
 	_ "github.com/docker/compose-cli/ecs"
@@ -151,10 +153,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,18 +183,19 @@ 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)
 	}
 
 	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,7 +213,21 @@ func main() {
 		compose.Command(ctype),
 		volume.Command(ctype),
 	)
+	if ctype == store.DefaultContextType || ctype == store.LocalContextType {
+		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
+		}
+		ctx = apicontext.WithCliOptions(ctx, cnxOptions)
+	}
 	ctx = apicontext.WithCurrentContext(ctx, currentContext)
 	ctx = store.WithContextStore(ctx, s)
 
@@ -302,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"

+ 8 - 4
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) {

+ 4 - 6
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
 }

+ 13 - 3
local/backend.go

@@ -19,16 +19,20 @@ 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"
+	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 {
@@ -42,7 +46,13 @@ func init() {
 }
 
 func service(ctx context.Context) (backend.Service, error) {
-	apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
+	options := apicontext.CliOptions(ctx)
+	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
 	}

+ 2 - 1
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

+ 6 - 7
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 := "Cannot connect to the Docker daemon at tcp://localhost:123"
+		stderr := "dial tcp: lookup nonexistent"
 		if runtime.GOOS == "windows" {
-			stderr = "error during connect: Get http://localhost:123"
+			stderr = "dial tcp: lookup nonexistent: no such host"
 		}
-		res := c.RunDockerOrExitError("-H", "tcp://localhost:123", "version")
-		res.Assert(t, icmd.Expected{
-			ExitCode: 1,
-			Err:      stderr,
-		})
+		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) {

+ 1 - 1
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) {