Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions cli/flags/options.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package flags

import (
"errors"
"fmt"
"os"
"path/filepath"

"github.com/docker/cli/cli/config"
"github.com/docker/cli/opts"
"github.com/docker/docker/client"
"github.com/docker/go-connections/tlsconfig"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -54,6 +54,39 @@ var (
dockerTLS = os.Getenv(EnvEnableTLS) != ""
)

// hostVar is used for the '--host' / '-H' flag to set [ClientOptions.Hosts].
// The [ClientOptions.Hosts] field is a slice because it was originally shared
// with the daemon config. However, the CLI only allows for a single host to
// be specified.
//
// hostVar presents itself as a "string", but stores the value in a string
// slice. It produces an error when trying to set multiple values, matching
// the check in [getServerHost].
//
// [getServerHost]: https://github.com/docker/cli/blob/7eab668982645def1cd46fe1b60894cba6fd17a4/cli/command/cli.go#L542-L551
type hostVar struct {
dst *[]string
set bool
}

func (h *hostVar) String() string {
if h.dst == nil || len(*h.dst) == 0 {
return ""
}
return (*h.dst)[0]
}

func (h *hostVar) Set(s string) error {
if h.set {
return errors.New("specify only one -H")
}
*h.dst = []string{s}
h.set = true
return nil
}

func (*hostVar) Type() string { return "string" }

// ClientOptions are the options used to configure the client cli.
type ClientOptions struct {
Debug bool
Expand Down Expand Up @@ -94,9 +127,9 @@ func (o *ClientOptions) InstallFlags(flags *pflag.FlagSet) {
flags.Var(&quotedString{&tlsOptions.CertFile}, "tlscert", "Path to TLS certificate file")
flags.Var(&quotedString{&tlsOptions.KeyFile}, "tlskey", "Path to TLS key file")

// opts.ValidateHost is not used here, so as to allow connection helpers
hostOpt := opts.NewNamedListOptsRef("hosts", &o.Hosts, nil)
flags.VarP(hostOpt, "host", "H", "Daemon socket to connect to")
// TODO(thaJeztah): show the default host.
// TODO(thaJeztah): this should be a string, not an "array" as we only allow a single host.
flags.VarP(&hostVar{dst: &o.Hosts}, "host", "H", "Daemon socket to connect to")
flags.StringVarP(&o.Context, "context", "c", "",
`Name of the context to use to connect to the daemon (overrides `+client.EnvOverrideHost+` env var and default context set with "docker context use")`)
}
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/commandline/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ The base command for the Docker CLI.
| `--config` | `string` | `/root/.docker` | Location of client config files |
| `-c`, `--context` | `string` | | Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with `docker context use`) |
| `-D`, `--debug` | `bool` | | Enable debug mode |
| [`-H`](#host), [`--host`](#host) | `list` | | Daemon socket to connect to |
| [`-H`](#host), [`--host`](#host) | `string` | | Daemon socket to connect to |
| `-l`, `--log-level` | `string` | `info` | Set the logging level (`debug`, `info`, `warn`, `error`, `fatal`) |
| `--tls` | `bool` | | Use TLS; implied by --tlsverify |
| `--tlscacert` | `string` | `/root/.docker/ca.pem` | Trust certs signed only by this CA |
Expand Down
5 changes: 3 additions & 2 deletions e2e/cli-plugins/flags_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cliplugins

import (
"fmt"
"os"
"testing"

Expand Down Expand Up @@ -91,9 +92,9 @@ func TestGlobalArgsOnlyParsedOnce(t *testing.T) {
// This is checking the precondition wrt -H mentioned in the function comment
name: "fails-if-H-used-twice",
args: []string{"-H", dh, "-H", dh, "version", "-f", "{{.Client.Version}}"},
expectedExitCode: 1,
expectedExitCode: 125,
expectedOut: icmd.None,
expectedErr: "Specify only one -H",
expectedErr: fmt.Sprintf(`invalid argument %q for "-H, --host" flag: specify only one -H`, dh),
},
{
name: "builtin",
Expand Down
Loading