mirror of
https://github.com/docker/compose.git
synced 2025-07-28 16:14:06 +02:00
Merge pull request #1400 from docker/tls_flags
This commit is contained in:
commit
3999eea066
@ -20,9 +20,12 @@ import (
|
|||||||
gocontext "context"
|
gocontext "context"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
cliflags "github.com/docker/cli/cli/flags"
|
||||||
)
|
)
|
||||||
|
|
||||||
type currentContextKey struct{}
|
type currentContextKey struct{}
|
||||||
|
type cliOptionsKey struct{}
|
||||||
|
|
||||||
// WithCurrentContext sets the name of the current docker context
|
// WithCurrentContext sets the name of the current docker context
|
||||||
func WithCurrentContext(ctx gocontext.Context, contextName string) context.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)
|
cc, _ := ctx.Value(currentContextKey{}).(string)
|
||||||
return cc
|
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
|
||||||
|
}
|
||||||
|
@ -36,8 +36,12 @@ func VersionCommand() *cobra.Command {
|
|||||||
Use: "version",
|
Use: "version",
|
||||||
Short: "Show the Docker version information",
|
Short: "Show the Docker version information",
|
||||||
Args: cobra.MaximumNArgs(0),
|
Args: cobra.MaximumNArgs(0),
|
||||||
Run: func(cmd *cobra.Command, _ []string) {
|
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||||
runVersion(cmd)
|
err := runVersion(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return ExitCodeError{ExitCode: 1}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// define flags for backward compatibility with com.docker.cli
|
// define flags for backward compatibility with com.docker.cli
|
||||||
@ -48,34 +52,38 @@ func VersionCommand() *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runVersion(cmd *cobra.Command) {
|
func runVersion(cmd *cobra.Command) error {
|
||||||
var versionString string
|
var versionString string
|
||||||
|
var err error
|
||||||
format := strings.ToLower(strings.ReplaceAll(cmd.Flag(formatOpt).Value.String(), " ", ""))
|
format := strings.ToLower(strings.ReplaceAll(cmd.Flag(formatOpt).Value.String(), " ", ""))
|
||||||
displayedVersion := strings.TrimPrefix(internal.Version, "v")
|
displayedVersion := strings.TrimPrefix(internal.Version, "v")
|
||||||
// Replace is preferred in this case to keep the order.
|
// Replace is preferred in this case to keep the order.
|
||||||
switch format {
|
switch format {
|
||||||
case formatter.PRETTY, "":
|
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)
|
"\n Version:", "\n Cloud integration: "+displayedVersion+"\n Version:", 1)
|
||||||
case formatter.JSON, formatter.TemplateLegacyJSON: // Try to catch full JSON formats
|
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)
|
`"Version":`, fmt.Sprintf(`"CloudIntegration":%q,"Version":`, displayedVersion), 1)
|
||||||
default:
|
default:
|
||||||
versionString = getOutFromMoby(cmd)
|
versionString, err = getOutFromMoby(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print(versionString)
|
fmt.Print(versionString)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOutFromMoby(cmd *cobra.Command, args ...string) string {
|
func getOutFromMoby(cmd *cobra.Command, args ...string) (string, error) {
|
||||||
versionResult, _ := mobycli.ExecSilent(cmd.Context(), args...)
|
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
|
// 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
|
// Still, technically the [] byte versionResult could be nil, just let the original command display what it has to display
|
||||||
if versionResult == nil {
|
if versionResult == nil {
|
||||||
mobycli.Exec(cmd.Root())
|
mobycli.Exec(cmd.Root())
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
return string(versionResult)
|
return string(versionResult), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func fixedPrettyArgs(oArgs []string) []string {
|
func fixedPrettyArgs(oArgs []string) []string {
|
||||||
|
56
cli/main.go
56
cli/main.go
@ -47,6 +47,8 @@ import (
|
|||||||
"github.com/docker/compose-cli/cli/mobycli"
|
"github.com/docker/compose-cli/cli/mobycli"
|
||||||
cliopts "github.com/docker/compose-cli/cli/options"
|
cliopts "github.com/docker/compose-cli/cli/options"
|
||||||
|
|
||||||
|
cliflags "github.com/docker/cli/cli/flags"
|
||||||
|
|
||||||
// Backend registrations
|
// Backend registrations
|
||||||
_ "github.com/docker/compose-cli/aci"
|
_ "github.com/docker/compose-cli/aci"
|
||||||
_ "github.com/docker/compose-cli/ecs"
|
_ "github.com/docker/compose-cli/ecs"
|
||||||
@ -151,10 +153,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
flags := root.Flags()
|
flags := root.Flags()
|
||||||
flags.StringVarP(&opts.LogLevel, "log-level", "l", "info", "Set the logging level (\"debug\"|\"info\"|\"warn\"|\"error\"|\"fatal\")")
|
opts.InstallFlags(flags)
|
||||||
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.AddConfigFlags(flags)
|
opts.AddConfigFlags(flags)
|
||||||
flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")
|
flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")
|
||||||
|
|
||||||
@ -184,18 +183,19 @@ func main() {
|
|||||||
ctx, cancel := newSigContext()
|
ctx, cancel := newSigContext()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// --host and --version should immediately be forwarded to the original cli
|
// --version should immediately be forwarded to the original cli
|
||||||
if opts.Host != "" || opts.Version {
|
if opts.Version {
|
||||||
mobycli.Exec(root)
|
mobycli.Exec(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Config == "" {
|
if opts.Config == "" {
|
||||||
fatal(errors.New("config path cannot be empty"))
|
fatal(errors.New("config path cannot be empty"))
|
||||||
}
|
}
|
||||||
|
|
||||||
configDir := opts.Config
|
configDir := opts.Config
|
||||||
ctx = config.WithDir(ctx, configDir)
|
ctx = config.WithDir(ctx, configDir)
|
||||||
|
|
||||||
currentContext := determineCurrentContext(opts.Context, configDir)
|
currentContext := determineCurrentContext(opts.Context, configDir, opts.Hosts)
|
||||||
|
|
||||||
s, err := store.New(configDir)
|
s, err := store.New(configDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -213,7 +213,21 @@ func main() {
|
|||||||
compose.Command(ctype),
|
compose.Command(ctype),
|
||||||
volume.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 = apicontext.WithCurrentContext(ctx, currentContext)
|
||||||
ctx = store.WithContextStore(ctx, s)
|
ctx = store.WithContextStore(ctx, s)
|
||||||
|
|
||||||
@ -302,15 +316,31 @@ func newSigContext() (context.Context, func()) {
|
|||||||
return ctx, cancel
|
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
|
res := flag
|
||||||
if res == "" {
|
if res == "" {
|
||||||
config, err := config.LoadFile(configDir)
|
// check if DOCKER_CONTEXT env variable was set
|
||||||
if err != nil {
|
if _, present := os.LookupEnv("DOCKER_CONTEXT"); present {
|
||||||
fmt.Fprintln(os.Stderr, errors.Wrap(err, "WARNING"))
|
res = os.Getenv("DOCKER_CONTEXT")
|
||||||
return "default"
|
}
|
||||||
|
|
||||||
|
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 == "" {
|
if res == "" {
|
||||||
res = "default"
|
res = "default"
|
||||||
|
@ -44,20 +44,24 @@ func TestDetermineCurrentContext(t *testing.T) {
|
|||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
// If nothing set, fallback to default
|
// If nothing set, fallback to default
|
||||||
c := determineCurrentContext("", "")
|
c := determineCurrentContext("", "", []string{})
|
||||||
assert.Equal(t, c, "default")
|
assert.Equal(t, c, "default")
|
||||||
|
|
||||||
// If context flag set, use that
|
// If context flag set, use that
|
||||||
c = determineCurrentContext("other-context", "")
|
c = determineCurrentContext("other-context", "", []string{})
|
||||||
assert.Equal(t, c, "other-context")
|
assert.Equal(t, c, "other-context")
|
||||||
|
|
||||||
// If no context flag, use config
|
// If no context flag, use config
|
||||||
c = determineCurrentContext("", d)
|
c = determineCurrentContext("", d, []string{})
|
||||||
assert.Equal(t, c, "some-context")
|
assert.Equal(t, c, "some-context")
|
||||||
|
|
||||||
// Ensure context flag overrides config
|
// Ensure context flag overrides config
|
||||||
c = determineCurrentContext("other-context", d)
|
c = determineCurrentContext("other-context", d, []string{})
|
||||||
assert.Equal(t, "other-context", c)
|
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) {
|
func TestCheckOwnCommand(t *testing.T) {
|
||||||
|
@ -17,16 +17,14 @@
|
|||||||
package options
|
package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
apicontext "github.com/docker/compose-cli/api/context"
|
|
||||||
cliconfig "github.com/docker/compose-cli/cli/config"
|
cliconfig "github.com/docker/compose-cli/cli/config"
|
||||||
|
|
||||||
|
cliflags "github.com/docker/cli/cli/flags"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GlobalOpts contains the global CLI options
|
// GlobalOpts contains the global CLI options
|
||||||
type GlobalOpts struct {
|
type GlobalOpts struct {
|
||||||
apicontext.ContextFlags
|
|
||||||
cliconfig.ConfigFlags
|
cliconfig.ConfigFlags
|
||||||
Debug bool
|
cliflags.CommonOptions
|
||||||
LogLevel string
|
Version bool
|
||||||
Version bool
|
|
||||||
Host string
|
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,20 @@ package local
|
|||||||
import (
|
import (
|
||||||
"context"
|
"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/backend"
|
||||||
"github.com/docker/compose-cli/api/cloud"
|
"github.com/docker/compose-cli/api/cloud"
|
||||||
|
|
||||||
"github.com/docker/compose-cli/api/compose"
|
"github.com/docker/compose-cli/api/compose"
|
||||||
|
apiconfig "github.com/docker/compose-cli/api/config"
|
||||||
"github.com/docker/compose-cli/api/containers"
|
"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/resources"
|
||||||
"github.com/docker/compose-cli/api/secrets"
|
"github.com/docker/compose-cli/api/secrets"
|
||||||
"github.com/docker/compose-cli/api/volumes"
|
"github.com/docker/compose-cli/api/volumes"
|
||||||
local_compose "github.com/docker/compose-cli/local/compose"
|
local_compose "github.com/docker/compose-cli/local/compose"
|
||||||
|
|
||||||
|
cliconfig "github.com/docker/cli/cli/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type local struct {
|
type local struct {
|
||||||
@ -42,7 +46,13 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func service(ctx context.Context) (backend.Service, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -39,10 +39,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type containerService struct {
|
type containerService struct {
|
||||||
apiClient *client.Client
|
apiClient client.APIClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *containerService) Inspect(ctx context.Context, id string) (containers.Container, error) {
|
func (cs *containerService) Inspect(ctx context.Context, id string) (containers.Container, error) {
|
||||||
|
|
||||||
c, err := cs.apiClient.ContainerInspect(ctx, id)
|
c, err := cs.apiClient.ContainerInspect(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return containers.Container{}, err
|
return containers.Container{}, err
|
||||||
|
@ -396,15 +396,14 @@ func TestLegacy(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("host flag", func(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" {
|
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 := c.RunDockerOrExitError("-H", "tcp://nonexistent:123", "version")
|
||||||
res.Assert(t, icmd.Expected{
|
assert.Assert(t, res.ExitCode == 1)
|
||||||
ExitCode: 1,
|
assert.Assert(t, strings.Contains(res.Stdout(), stderr), res.Stdout())
|
||||||
Err: stderr,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("existing contexts delegate", func(t *testing.T) {
|
t.Run("existing contexts delegate", func(t *testing.T) {
|
||||||
|
@ -29,7 +29,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type volumeService struct {
|
type volumeService struct {
|
||||||
apiClient *client.Client
|
apiClient client.APIClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *volumeService) List(ctx context.Context) ([]volumes.Volume, error) {
|
func (vs *volumeService) List(ctx context.Context) ([]volumes.Volume, error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user