This patch creates a new cli package that allows to combine both client
and daemon commands (there is only one daemon command: docker daemon).
The `-d` and `--daemon` top-level flags are deprecated and a special
message is added to prompt the user to use `docker daemon`.
Providing top-level daemon-specific flags for client commands result
in an error message prompting the user to use `docker daemon`.
This patch does not break any old but correct usages.
This also makes `-d` and `--daemon` flags, as well as the `daemon`
command illegal in client-only binaries.
Signed-off-by: Tibor Vass <tibor@docker.com>
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
|
| 9 | 9 |
"github.com/Sirupsen/logrus" |
| 10 | 10 |
"github.com/docker/docker/api/types" |
| 11 |
+ Cli "github.com/docker/docker/cli" |
|
| 11 | 12 |
flag "github.com/docker/docker/pkg/mflag" |
| 12 | 13 |
"github.com/docker/docker/pkg/signal" |
| 13 | 14 |
) |
| ... | ... |
@@ -16,9 +17,10 @@ import ( |
| 16 | 16 |
// |
| 17 | 17 |
// Usage: docker attach [OPTIONS] CONTAINER |
| 18 | 18 |
func (cli *DockerCli) CmdAttach(args ...string) error {
|
| 19 |
- cmd := cli.Subcmd("attach", []string{"CONTAINER"}, "Attach to a running container", true)
|
|
| 19 |
+ cmd := Cli.Subcmd("attach", []string{"CONTAINER"}, "Attach to a running container", true)
|
|
| 20 | 20 |
noStdin := cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
|
| 21 | 21 |
proxy := cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process")
|
| 22 |
+ |
|
| 22 | 23 |
cmd.Require(flag.Exact, 1) |
| 23 | 24 |
|
| 24 | 25 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -75,7 +77,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
|
| 75 | 75 |
return err |
| 76 | 76 |
} |
| 77 | 77 |
if status != 0 {
|
| 78 |
- return StatusError{StatusCode: status}
|
|
| 78 |
+ return Cli.StatusError{StatusCode: status}
|
|
| 79 | 79 |
} |
| 80 | 80 |
|
| 81 | 81 |
return nil |
| ... | ... |
@@ -18,6 +18,7 @@ import ( |
| 18 | 18 |
"strings" |
| 19 | 19 |
|
| 20 | 20 |
"github.com/docker/docker/api" |
| 21 |
+ Cli "github.com/docker/docker/cli" |
|
| 21 | 22 |
"github.com/docker/docker/graph/tags" |
| 22 | 23 |
"github.com/docker/docker/opts" |
| 23 | 24 |
"github.com/docker/docker/pkg/archive" |
| ... | ... |
@@ -46,7 +47,7 @@ const ( |
| 46 | 46 |
// |
| 47 | 47 |
// Usage: docker build [OPTIONS] PATH | URL | - |
| 48 | 48 |
func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 49 |
- cmd := cli.Subcmd("build", []string{"PATH | URL | -"}, "Build a new image from the source code at PATH", true)
|
|
| 49 |
+ cmd := Cli.Subcmd("build", []string{"PATH | URL | -"}, "Build a new image from the source code at PATH", true)
|
|
| 50 | 50 |
tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) for the image")
|
| 51 | 51 |
suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
|
| 52 | 52 |
noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
|
| ... | ... |
@@ -64,7 +65,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 64 | 64 |
flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
|
| 65 | 65 |
|
| 66 | 66 |
ulimits := make(map[string]*ulimit.Ulimit) |
| 67 |
- flUlimits := opts.NewUlimitOpt(ulimits) |
|
| 67 |
+ flUlimits := opts.NewUlimitOpt(&ulimits) |
|
| 68 | 68 |
cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options")
|
| 69 | 69 |
|
| 70 | 70 |
cmd.Require(flag.Exact, 1) |
| ... | ... |
@@ -325,7 +326,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 325 | 325 |
if jerr.Code == 0 {
|
| 326 | 326 |
jerr.Code = 1 |
| 327 | 327 |
} |
| 328 |
- return StatusError{Status: jerr.Message, StatusCode: jerr.Code}
|
|
| 328 |
+ return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
|
|
| 329 | 329 |
} |
| 330 | 330 |
return err |
| 331 | 331 |
} |
| ... | ... |
@@ -2,25 +2,28 @@ package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"crypto/tls" |
| 5 |
- "encoding/json" |
|
| 6 | 5 |
"errors" |
| 7 | 6 |
"fmt" |
| 8 | 7 |
"io" |
| 9 | 8 |
"net/http" |
| 10 | 9 |
"net/url" |
| 11 |
- "reflect" |
|
| 10 |
+ "os" |
|
| 12 | 11 |
"strings" |
| 13 |
- "text/template" |
|
| 14 | 12 |
|
| 13 |
+ "github.com/docker/docker/cli" |
|
| 15 | 14 |
"github.com/docker/docker/cliconfig" |
| 16 |
- flag "github.com/docker/docker/pkg/mflag" |
|
| 15 |
+ "github.com/docker/docker/opts" |
|
| 17 | 16 |
"github.com/docker/docker/pkg/sockets" |
| 18 | 17 |
"github.com/docker/docker/pkg/term" |
| 18 |
+ "github.com/docker/docker/pkg/tlsconfig" |
|
| 19 | 19 |
) |
| 20 | 20 |
|
| 21 | 21 |
// DockerCli represents the docker command line client. |
| 22 | 22 |
// Instances of the client can be returned from NewDockerCli. |
| 23 | 23 |
type DockerCli struct {
|
| 24 |
+ // initializing closure |
|
| 25 |
+ init func() error |
|
| 26 |
+ |
|
| 24 | 27 |
// proto holds the client protocol i.e. unix. |
| 25 | 28 |
proto string |
| 26 | 29 |
// addr holds the client address. |
| ... | ... |
@@ -55,116 +58,11 @@ type DockerCli struct {
|
| 55 | 55 |
transport *http.Transport |
| 56 | 56 |
} |
| 57 | 57 |
|
| 58 |
-var funcMap = template.FuncMap{
|
|
| 59 |
- "json": func(v interface{}) string {
|
|
| 60 |
- a, _ := json.Marshal(v) |
|
| 61 |
- return string(a) |
|
| 62 |
- }, |
|
| 63 |
-} |
|
| 64 |
- |
|
| 65 |
-func (cli *DockerCli) Out() io.Writer {
|
|
| 66 |
- return cli.out |
|
| 67 |
-} |
|
| 68 |
- |
|
| 69 |
-func (cli *DockerCli) Err() io.Writer {
|
|
| 70 |
- return cli.err |
|
| 71 |
-} |
|
| 72 |
- |
|
| 73 |
-func (cli *DockerCli) getMethod(args ...string) (func(...string) error, bool) {
|
|
| 74 |
- camelArgs := make([]string, len(args)) |
|
| 75 |
- for i, s := range args {
|
|
| 76 |
- if len(s) == 0 {
|
|
| 77 |
- return nil, false |
|
| 78 |
- } |
|
| 79 |
- camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:]) |
|
| 80 |
- } |
|
| 81 |
- methodName := "Cmd" + strings.Join(camelArgs, "") |
|
| 82 |
- method := reflect.ValueOf(cli).MethodByName(methodName) |
|
| 83 |
- if !method.IsValid() {
|
|
| 84 |
- return nil, false |
|
| 85 |
- } |
|
| 86 |
- return method.Interface().(func(...string) error), true |
|
| 87 |
-} |
|
| 88 |
- |
|
| 89 |
-// Cmd executes the specified command. |
|
| 90 |
-func (cli *DockerCli) Cmd(args ...string) error {
|
|
| 91 |
- if len(args) > 1 {
|
|
| 92 |
- method, exists := cli.getMethod(args[:2]...) |
|
| 93 |
- if exists {
|
|
| 94 |
- return method(args[2:]...) |
|
| 95 |
- } |
|
| 96 |
- } |
|
| 97 |
- if len(args) > 0 {
|
|
| 98 |
- method, exists := cli.getMethod(args[0]) |
|
| 99 |
- if !exists {
|
|
| 100 |
- return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
|
|
| 101 |
- } |
|
| 102 |
- return method(args[1:]...) |
|
| 58 |
+func (cli *DockerCli) Initialize() error {
|
|
| 59 |
+ if cli.init == nil {
|
|
| 60 |
+ return nil |
|
| 103 | 61 |
} |
| 104 |
- return cli.CmdHelp() |
|
| 105 |
-} |
|
| 106 |
- |
|
| 107 |
-// Subcmd is a subcommand of the main "docker" command. |
|
| 108 |
-// A subcommand represents an action that can be performed |
|
| 109 |
-// from the Docker command line client. |
|
| 110 |
-// |
|
| 111 |
-// Multiple subcommand synopses may be provided with one 'Usage' line being |
|
| 112 |
-// printed for each in the following way: |
|
| 113 |
-// |
|
| 114 |
-// Usage: docker <subcmd-name> [OPTIONS] <synopsis 0> |
|
| 115 |
-// docker <subcmd-name> [OPTIONS] <synopsis 1> |
|
| 116 |
-// ... |
|
| 117 |
-// |
|
| 118 |
-// If no undeprecated flags are added to the returned FlagSet, "[OPTIONS]" will |
|
| 119 |
-// not be included on the usage synopsis lines. If no synopses are given, only |
|
| 120 |
-// one usage synopsis line will be printed with nothing following the |
|
| 121 |
-// "[OPTIONS]" section |
|
| 122 |
-// |
|
| 123 |
-// To see all available subcommands, run "docker --help". |
|
| 124 |
-func (cli *DockerCli) Subcmd(name string, synopses []string, description string, exitOnError bool) *flag.FlagSet {
|
|
| 125 |
- var errorHandling flag.ErrorHandling |
|
| 126 |
- if exitOnError {
|
|
| 127 |
- errorHandling = flag.ExitOnError |
|
| 128 |
- } else {
|
|
| 129 |
- errorHandling = flag.ContinueOnError |
|
| 130 |
- } |
|
| 131 |
- |
|
| 132 |
- flags := flag.NewFlagSet(name, errorHandling) |
|
| 133 |
- |
|
| 134 |
- flags.Usage = func() {
|
|
| 135 |
- flags.ShortUsage() |
|
| 136 |
- flags.PrintDefaults() |
|
| 137 |
- } |
|
| 138 |
- |
|
| 139 |
- flags.ShortUsage = func() {
|
|
| 140 |
- options := "" |
|
| 141 |
- if flags.FlagCountUndeprecated() > 0 {
|
|
| 142 |
- options = " [OPTIONS]" |
|
| 143 |
- } |
|
| 144 |
- |
|
| 145 |
- if len(synopses) == 0 {
|
|
| 146 |
- synopses = []string{""}
|
|
| 147 |
- } |
|
| 148 |
- |
|
| 149 |
- // Allow for multiple command usage synopses. |
|
| 150 |
- for i, synopsis := range synopses {
|
|
| 151 |
- lead := "\t" |
|
| 152 |
- if i == 0 {
|
|
| 153 |
- // First line needs the word 'Usage'. |
|
| 154 |
- lead = "Usage:\t" |
|
| 155 |
- } |
|
| 156 |
- |
|
| 157 |
- if synopsis != "" {
|
|
| 158 |
- synopsis = " " + synopsis |
|
| 159 |
- } |
|
| 160 |
- |
|
| 161 |
- fmt.Fprintf(flags.Out(), "\n%sdocker %s%s%s", lead, name, options, synopsis) |
|
| 162 |
- } |
|
| 163 |
- |
|
| 164 |
- fmt.Fprintf(flags.Out(), "\n\n%s\n", description) |
|
| 165 |
- } |
|
| 166 |
- |
|
| 167 |
- return flags |
|
| 62 |
+ return cli.init() |
|
| 168 | 63 |
} |
| 169 | 64 |
|
| 170 | 65 |
// CheckTtyInput checks if we are trying to attach to a container tty |
| ... | ... |
@@ -187,64 +85,78 @@ func (cli *DockerCli) PsFormat() string {
|
| 187 | 187 |
// The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config |
| 188 | 188 |
// is set the client scheme will be set to https. |
| 189 | 189 |
// The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). |
| 190 |
-func NewDockerCli(in io.ReadCloser, out, err io.Writer, keyFile string, proto, addr string, tlsConfig *tls.Config) *DockerCli {
|
|
| 191 |
- var ( |
|
| 192 |
- inFd uintptr |
|
| 193 |
- outFd uintptr |
|
| 194 |
- isTerminalIn = false |
|
| 195 |
- isTerminalOut = false |
|
| 196 |
- scheme = "http" |
|
| 197 |
- basePath = "" |
|
| 198 |
- ) |
|
| 199 |
- |
|
| 200 |
- if tlsConfig != nil {
|
|
| 201 |
- scheme = "https" |
|
| 202 |
- } |
|
| 203 |
- if in != nil {
|
|
| 204 |
- inFd, isTerminalIn = term.GetFdInfo(in) |
|
| 190 |
+func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli {
|
|
| 191 |
+ cli := &DockerCli{
|
|
| 192 |
+ in: in, |
|
| 193 |
+ out: out, |
|
| 194 |
+ err: err, |
|
| 195 |
+ keyFile: clientFlags.Common.TrustKey, |
|
| 205 | 196 |
} |
| 206 | 197 |
|
| 207 |
- if out != nil {
|
|
| 208 |
- outFd, isTerminalOut = term.GetFdInfo(out) |
|
| 209 |
- } |
|
| 198 |
+ cli.init = func() error {
|
|
| 199 |
+ clientFlags.PostParse() |
|
| 210 | 200 |
|
| 211 |
- if err == nil {
|
|
| 212 |
- err = out |
|
| 213 |
- } |
|
| 201 |
+ hosts := clientFlags.Common.Hosts |
|
| 214 | 202 |
|
| 215 |
- // The transport is created here for reuse during the client session. |
|
| 216 |
- tr := &http.Transport{
|
|
| 217 |
- TLSClientConfig: tlsConfig, |
|
| 218 |
- } |
|
| 219 |
- sockets.ConfigureTCPTransport(tr, proto, addr) |
|
| 203 |
+ switch len(hosts) {
|
|
| 204 |
+ case 0: |
|
| 205 |
+ defaultHost := os.Getenv("DOCKER_HOST")
|
|
| 206 |
+ if defaultHost == "" {
|
|
| 207 |
+ defaultHost = opts.DefaultHost |
|
| 208 |
+ } |
|
| 209 |
+ defaultHost, err := opts.ValidateHost(defaultHost) |
|
| 210 |
+ if err != nil {
|
|
| 211 |
+ return err |
|
| 212 |
+ } |
|
| 213 |
+ hosts = []string{defaultHost}
|
|
| 214 |
+ case 1: |
|
| 215 |
+ // only accept one host to talk to |
|
| 216 |
+ default: |
|
| 217 |
+ return errors.New("Please specify only one -H")
|
|
| 218 |
+ } |
|
| 220 | 219 |
|
| 221 |
- configFile, e := cliconfig.Load(cliconfig.ConfigDir()) |
|
| 222 |
- if e != nil {
|
|
| 223 |
- fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e) |
|
| 224 |
- } |
|
| 220 |
+ protoAddrParts := strings.SplitN(hosts[0], "://", 2) |
|
| 221 |
+ cli.proto, cli.addr = protoAddrParts[0], protoAddrParts[1] |
|
| 225 | 222 |
|
| 226 |
- if proto == "tcp" {
|
|
| 227 |
- // error is checked in pkg/parsers already |
|
| 228 |
- parsed, _ := url.Parse("tcp://" + addr)
|
|
| 229 |
- addr = parsed.Host |
|
| 230 |
- basePath = parsed.Path |
|
| 231 |
- } |
|
| 223 |
+ if cli.proto == "tcp" {
|
|
| 224 |
+ // error is checked in pkg/parsers already |
|
| 225 |
+ parsed, _ := url.Parse("tcp://" + cli.addr)
|
|
| 226 |
+ cli.addr = parsed.Host |
|
| 227 |
+ cli.basePath = parsed.Path |
|
| 228 |
+ } |
|
| 232 | 229 |
|
| 233 |
- return &DockerCli{
|
|
| 234 |
- proto: proto, |
|
| 235 |
- addr: addr, |
|
| 236 |
- basePath: basePath, |
|
| 237 |
- configFile: configFile, |
|
| 238 |
- in: in, |
|
| 239 |
- out: out, |
|
| 240 |
- err: err, |
|
| 241 |
- keyFile: keyFile, |
|
| 242 |
- inFd: inFd, |
|
| 243 |
- outFd: outFd, |
|
| 244 |
- isTerminalIn: isTerminalIn, |
|
| 245 |
- isTerminalOut: isTerminalOut, |
|
| 246 |
- tlsConfig: tlsConfig, |
|
| 247 |
- scheme: scheme, |
|
| 248 |
- transport: tr, |
|
| 230 |
+ if clientFlags.Common.TLSOptions != nil {
|
|
| 231 |
+ cli.scheme = "https" |
|
| 232 |
+ var e error |
|
| 233 |
+ cli.tlsConfig, e = tlsconfig.Client(*clientFlags.Common.TLSOptions) |
|
| 234 |
+ if e != nil {
|
|
| 235 |
+ return e |
|
| 236 |
+ } |
|
| 237 |
+ } else {
|
|
| 238 |
+ cli.scheme = "http" |
|
| 239 |
+ } |
|
| 240 |
+ |
|
| 241 |
+ if cli.in != nil {
|
|
| 242 |
+ cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in) |
|
| 243 |
+ } |
|
| 244 |
+ if cli.out != nil {
|
|
| 245 |
+ cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out) |
|
| 246 |
+ } |
|
| 247 |
+ |
|
| 248 |
+ // The transport is created here for reuse during the client session. |
|
| 249 |
+ cli.transport = &http.Transport{
|
|
| 250 |
+ TLSClientConfig: cli.tlsConfig, |
|
| 251 |
+ } |
|
| 252 |
+ sockets.ConfigureTCPTransport(cli.transport, cli.proto, cli.addr) |
|
| 253 |
+ |
|
| 254 |
+ configFile, e := cliconfig.Load(cliconfig.ConfigDir()) |
|
| 255 |
+ if e != nil {
|
|
| 256 |
+ fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e) |
|
| 257 |
+ } |
|
| 258 |
+ cli.configFile = configFile |
|
| 259 |
+ |
|
| 260 |
+ return nil |
|
| 249 | 261 |
} |
| 262 |
+ |
|
| 263 |
+ return cli |
|
| 250 | 264 |
} |
| ... | ... |
@@ -3,15 +3,3 @@ |
| 3 | 3 |
// Run "docker help SUBCOMMAND" or "docker SUBCOMMAND --help" to see more information on any Docker subcommand, including the full list of options supported for the subcommand. |
| 4 | 4 |
// See https://docs.docker.com/installation/ for instructions on installing Docker. |
| 5 | 5 |
package client |
| 6 |
- |
|
| 7 |
-import "fmt" |
|
| 8 |
- |
|
| 9 |
-// An StatusError reports an unsuccessful exit by a command. |
|
| 10 |
-type StatusError struct {
|
|
| 11 |
- Status string |
|
| 12 |
- StatusCode int |
|
| 13 |
-} |
|
| 14 |
- |
|
| 15 |
-func (e StatusError) Error() string {
|
|
| 16 |
- return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
|
|
| 17 |
-} |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"net/url" |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/api/types" |
| 9 |
+ Cli "github.com/docker/docker/cli" |
|
| 9 | 10 |
"github.com/docker/docker/opts" |
| 10 | 11 |
flag "github.com/docker/docker/pkg/mflag" |
| 11 | 12 |
"github.com/docker/docker/pkg/parsers" |
| ... | ... |
@@ -17,7 +18,7 @@ import ( |
| 17 | 17 |
// |
| 18 | 18 |
// Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] |
| 19 | 19 |
func (cli *DockerCli) CmdCommit(args ...string) error {
|
| 20 |
- cmd := cli.Subcmd("commit", []string{"CONTAINER [REPOSITORY[:TAG]]"}, "Create a new image from a container's changes", true)
|
|
| 20 |
+ cmd := Cli.Subcmd("commit", []string{"CONTAINER [REPOSITORY[:TAG]]"}, "Create a new image from a container's changes", true)
|
|
| 21 | 21 |
flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
|
| 22 | 22 |
flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
|
| 23 | 23 |
flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
|
| ... | ... |
@@ -12,6 +12,7 @@ import ( |
| 12 | 12 |
"strings" |
| 13 | 13 |
|
| 14 | 14 |
"github.com/docker/docker/api/types" |
| 15 |
+ Cli "github.com/docker/docker/cli" |
|
| 15 | 16 |
"github.com/docker/docker/pkg/archive" |
| 16 | 17 |
flag "github.com/docker/docker/pkg/mflag" |
| 17 | 18 |
) |
| ... | ... |
@@ -37,7 +38,7 @@ const ( |
| 37 | 37 |
// docker cp CONTAINER:PATH LOCALPATH|- |
| 38 | 38 |
// docker cp LOCALPATH|- CONTAINER:PATH |
| 39 | 39 |
func (cli *DockerCli) CmdCp(args ...string) error {
|
| 40 |
- cmd := cli.Subcmd( |
|
| 40 |
+ cmd := Cli.Subcmd( |
|
| 41 | 41 |
"cp", |
| 42 | 42 |
[]string{"CONTAINER:PATH LOCALPATH|-", "LOCALPATH|- CONTAINER:PATH"},
|
| 43 | 43 |
strings.Join([]string{
|
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
"strings" |
| 11 | 11 |
|
| 12 | 12 |
"github.com/docker/docker/api/types" |
| 13 |
+ Cli "github.com/docker/docker/cli" |
|
| 13 | 14 |
"github.com/docker/docker/graph/tags" |
| 14 | 15 |
"github.com/docker/docker/pkg/parsers" |
| 15 | 16 |
"github.com/docker/docker/registry" |
| ... | ... |
@@ -137,7 +138,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc |
| 137 | 137 |
// |
| 138 | 138 |
// Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...] |
| 139 | 139 |
func (cli *DockerCli) CmdCreate(args ...string) error {
|
| 140 |
- cmd := cli.Subcmd("create", []string{"IMAGE [COMMAND] [ARG...]"}, "Create a new container", true)
|
|
| 140 |
+ cmd := Cli.Subcmd("create", []string{"IMAGE [COMMAND] [ARG...]"}, "Create a new container", true)
|
|
| 141 | 141 |
|
| 142 | 142 |
// These are flags not stored in Config/HostConfig |
| 143 | 143 |
var ( |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"fmt" |
| 6 | 6 |
|
| 7 | 7 |
"github.com/docker/docker/api/types" |
| 8 |
+ Cli "github.com/docker/docker/cli" |
|
| 8 | 9 |
"github.com/docker/docker/pkg/archive" |
| 9 | 10 |
flag "github.com/docker/docker/pkg/mflag" |
| 10 | 11 |
) |
| ... | ... |
@@ -17,7 +18,7 @@ import ( |
| 17 | 17 |
// |
| 18 | 18 |
// Usage: docker diff CONTAINER |
| 19 | 19 |
func (cli *DockerCli) CmdDiff(args ...string) error {
|
| 20 |
- cmd := cli.Subcmd("diff", []string{"CONTAINER"}, "Inspect changes on a container's filesystem", true)
|
|
| 20 |
+ cmd := Cli.Subcmd("diff", []string{"CONTAINER"}, "Inspect changes on a container's filesystem", true)
|
|
| 21 | 21 |
cmd.Require(flag.Exact, 1) |
| 22 | 22 |
|
| 23 | 23 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"net/url" |
| 5 | 5 |
"time" |
| 6 | 6 |
|
| 7 |
+ Cli "github.com/docker/docker/cli" |
|
| 7 | 8 |
"github.com/docker/docker/opts" |
| 8 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 10 |
"github.com/docker/docker/pkg/parsers/filters" |
| ... | ... |
@@ -14,7 +15,7 @@ import ( |
| 14 | 14 |
// |
| 15 | 15 |
// Usage: docker events [OPTIONS] |
| 16 | 16 |
func (cli *DockerCli) CmdEvents(args ...string) error {
|
| 17 |
- cmd := cli.Subcmd("events", nil, "Get real time events from the server", true)
|
|
| 17 |
+ cmd := Cli.Subcmd("events", nil, "Get real time events from the server", true)
|
|
| 18 | 18 |
since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
|
| 19 | 19 |
until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
|
| 20 | 20 |
flFilter := opts.NewListOpts(nil) |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/Sirupsen/logrus" |
| 9 | 9 |
"github.com/docker/docker/api/types" |
| 10 |
+ Cli "github.com/docker/docker/cli" |
|
| 10 | 11 |
"github.com/docker/docker/pkg/promise" |
| 11 | 12 |
"github.com/docker/docker/runconfig" |
| 12 | 13 |
) |
| ... | ... |
@@ -15,12 +16,12 @@ import ( |
| 15 | 15 |
// |
| 16 | 16 |
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] |
| 17 | 17 |
func (cli *DockerCli) CmdExec(args ...string) error {
|
| 18 |
- cmd := cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, "Run a command in a running container", true)
|
|
| 18 |
+ cmd := Cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, "Run a command in a running container", true)
|
|
| 19 | 19 |
|
| 20 | 20 |
execConfig, err := runconfig.ParseExec(cmd, args) |
| 21 | 21 |
// just in case the ParseExec does not exit |
| 22 | 22 |
if execConfig.Container == "" || err != nil {
|
| 23 |
- return StatusError{StatusCode: 1}
|
|
| 23 |
+ return Cli.StatusError{StatusCode: 1}
|
|
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 | 26 |
serverResp, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, nil)
|
| ... | ... |
@@ -126,7 +127,7 @@ func (cli *DockerCli) CmdExec(args ...string) error {
|
| 126 | 126 |
} |
| 127 | 127 |
|
| 128 | 128 |
if status != 0 {
|
| 129 |
- return StatusError{StatusCode: status}
|
|
| 129 |
+ return Cli.StatusError{StatusCode: status}
|
|
| 130 | 130 |
} |
| 131 | 131 |
|
| 132 | 132 |
return nil |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"io" |
| 6 | 6 |
"os" |
| 7 | 7 |
|
| 8 |
+ Cli "github.com/docker/docker/cli" |
|
| 8 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 10 |
) |
| 10 | 11 |
|
| ... | ... |
@@ -14,7 +15,7 @@ import ( |
| 14 | 14 |
// |
| 15 | 15 |
// Usage: docker export [OPTIONS] CONTAINER |
| 16 | 16 |
func (cli *DockerCli) CmdExport(args ...string) error {
|
| 17 |
- cmd := cli.Subcmd("export", []string{"CONTAINER"}, "Export the contents of a container's filesystem as a tar archive", true)
|
|
| 17 |
+ cmd := Cli.Subcmd("export", []string{"CONTAINER"}, "Export the contents of a container's filesystem as a tar archive", true)
|
|
| 18 | 18 |
outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
|
| 19 | 19 |
cmd.Require(flag.Exact, 1) |
| 20 | 20 |
|
| 21 | 21 |
deleted file mode 100644 |
| ... | ... |
@@ -1,34 +0,0 @@ |
| 1 |
-package client |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- |
|
| 6 |
- flag "github.com/docker/docker/pkg/mflag" |
|
| 7 |
-) |
|
| 8 |
- |
|
| 9 |
-// CmdHelp displays information on a Docker command. |
|
| 10 |
-// |
|
| 11 |
-// If more than one command is specified, information is only shown for the first command. |
|
| 12 |
-// |
|
| 13 |
-// Usage: docker help COMMAND or docker COMMAND --help |
|
| 14 |
-func (cli *DockerCli) CmdHelp(args ...string) error {
|
|
| 15 |
- if len(args) > 1 {
|
|
| 16 |
- method, exists := cli.getMethod(args[:2]...) |
|
| 17 |
- if exists {
|
|
| 18 |
- method("--help")
|
|
| 19 |
- return nil |
|
| 20 |
- } |
|
| 21 |
- } |
|
| 22 |
- if len(args) > 0 {
|
|
| 23 |
- method, exists := cli.getMethod(args[0]) |
|
| 24 |
- if !exists {
|
|
| 25 |
- return fmt.Errorf("docker: '%s' is not a docker command. See 'docker --help'.", args[0])
|
|
| 26 |
- } |
|
| 27 |
- method("--help")
|
|
| 28 |
- return nil |
|
| 29 |
- } |
|
| 30 |
- |
|
| 31 |
- flag.Usage() |
|
| 32 |
- |
|
| 33 |
- return nil |
|
| 34 |
-} |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"time" |
| 8 | 8 |
|
| 9 | 9 |
"github.com/docker/docker/api/types" |
| 10 |
+ Cli "github.com/docker/docker/cli" |
|
| 10 | 11 |
flag "github.com/docker/docker/pkg/mflag" |
| 11 | 12 |
"github.com/docker/docker/pkg/stringid" |
| 12 | 13 |
"github.com/docker/docker/pkg/stringutils" |
| ... | ... |
@@ -17,7 +18,7 @@ import ( |
| 17 | 17 |
// |
| 18 | 18 |
// Usage: docker history [OPTIONS] IMAGE |
| 19 | 19 |
func (cli *DockerCli) CmdHistory(args ...string) error {
|
| 20 |
- cmd := cli.Subcmd("history", []string{"IMAGE"}, "Show the history of an image", true)
|
|
| 20 |
+ cmd := Cli.Subcmd("history", []string{"IMAGE"}, "Show the history of an image", true)
|
|
| 21 | 21 |
human := cmd.Bool([]string{"H", "-human"}, true, "Print sizes and dates in human readable format")
|
| 22 | 22 |
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
|
| 23 | 23 |
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"time" |
| 9 | 9 |
|
| 10 | 10 |
"github.com/docker/docker/api/types" |
| 11 |
+ Cli "github.com/docker/docker/cli" |
|
| 11 | 12 |
"github.com/docker/docker/opts" |
| 12 | 13 |
flag "github.com/docker/docker/pkg/mflag" |
| 13 | 14 |
"github.com/docker/docker/pkg/parsers" |
| ... | ... |
@@ -21,7 +22,7 @@ import ( |
| 21 | 21 |
// |
| 22 | 22 |
// Usage: docker images [OPTIONS] [REPOSITORY] |
| 23 | 23 |
func (cli *DockerCli) CmdImages(args ...string) error {
|
| 24 |
- cmd := cli.Subcmd("images", []string{"[REPOSITORY]"}, "List images", true)
|
|
| 24 |
+ cmd := Cli.Subcmd("images", []string{"[REPOSITORY]"}, "List images", true)
|
|
| 25 | 25 |
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
|
| 26 | 26 |
all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)")
|
| 27 | 27 |
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"net/url" |
| 7 | 7 |
"os" |
| 8 | 8 |
|
| 9 |
+ Cli "github.com/docker/docker/cli" |
|
| 9 | 10 |
"github.com/docker/docker/opts" |
| 10 | 11 |
flag "github.com/docker/docker/pkg/mflag" |
| 11 | 12 |
"github.com/docker/docker/pkg/parsers" |
| ... | ... |
@@ -19,7 +20,7 @@ import ( |
| 19 | 19 |
// |
| 20 | 20 |
// Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] |
| 21 | 21 |
func (cli *DockerCli) CmdImport(args ...string) error {
|
| 22 |
- cmd := cli.Subcmd("import", []string{"file|URL|- [REPOSITORY[:TAG]]"}, "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true)
|
|
| 22 |
+ cmd := Cli.Subcmd("import", []string{"file|URL|- [REPOSITORY[:TAG]]"}, "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true)
|
|
| 23 | 23 |
flChanges := opts.NewListOpts(nil) |
| 24 | 24 |
cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
|
| 25 | 25 |
cmd.Require(flag.Min, 1) |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"fmt" |
| 6 | 6 |
|
| 7 | 7 |
"github.com/docker/docker/api/types" |
| 8 |
+ Cli "github.com/docker/docker/cli" |
|
| 8 | 9 |
"github.com/docker/docker/pkg/httputils" |
| 9 | 10 |
"github.com/docker/docker/pkg/ioutils" |
| 10 | 11 |
flag "github.com/docker/docker/pkg/mflag" |
| ... | ... |
@@ -15,7 +16,7 @@ import ( |
| 15 | 15 |
// |
| 16 | 16 |
// Usage: docker info |
| 17 | 17 |
func (cli *DockerCli) CmdInfo(args ...string) error {
|
| 18 |
- cmd := cli.Subcmd("info", nil, "Display system-wide information", true)
|
|
| 18 |
+ cmd := Cli.Subcmd("info", nil, "Display system-wide information", true)
|
|
| 19 | 19 |
cmd.Require(flag.Exact, 0) |
| 20 | 20 |
|
| 21 | 21 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -9,14 +9,22 @@ import ( |
| 9 | 9 |
"text/template" |
| 10 | 10 |
|
| 11 | 11 |
"github.com/docker/docker/api/types" |
| 12 |
+ Cli "github.com/docker/docker/cli" |
|
| 12 | 13 |
flag "github.com/docker/docker/pkg/mflag" |
| 13 | 14 |
) |
| 14 | 15 |
|
| 16 |
+var funcMap = template.FuncMap{
|
|
| 17 |
+ "json": func(v interface{}) string {
|
|
| 18 |
+ a, _ := json.Marshal(v) |
|
| 19 |
+ return string(a) |
|
| 20 |
+ }, |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 15 | 23 |
// CmdInspect displays low-level information on one or more containers or images. |
| 16 | 24 |
// |
| 17 | 25 |
// Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...] |
| 18 | 26 |
func (cli *DockerCli) CmdInspect(args ...string) error {
|
| 19 |
- cmd := cli.Subcmd("inspect", []string{"CONTAINER|IMAGE [CONTAINER|IMAGE...]"}, "Return low-level information on a container or image", true)
|
|
| 27 |
+ cmd := Cli.Subcmd("inspect", []string{"CONTAINER|IMAGE [CONTAINER|IMAGE...]"}, "Return low-level information on a container or image", true)
|
|
| 20 | 28 |
tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template")
|
| 21 | 29 |
inspectType := cmd.String([]string{"-type"}, "", "Return JSON for specified type, (e.g image or container)")
|
| 22 | 30 |
cmd.Require(flag.Min, 1) |
| ... | ... |
@@ -29,7 +37,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
|
| 29 | 29 |
|
| 30 | 30 |
if *tmplStr != "" {
|
| 31 | 31 |
if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
|
| 32 |
- return StatusError{StatusCode: 64,
|
|
| 32 |
+ return Cli.StatusError{StatusCode: 64,
|
|
| 33 | 33 |
Status: "Template parsing error: " + err.Error()} |
| 34 | 34 |
} |
| 35 | 35 |
} |
| ... | ... |
@@ -143,7 +151,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
|
| 143 | 143 |
} |
| 144 | 144 |
|
| 145 | 145 |
if status != 0 {
|
| 146 |
- return StatusError{StatusCode: status}
|
|
| 146 |
+ return Cli.StatusError{StatusCode: status}
|
|
| 147 | 147 |
} |
| 148 | 148 |
return nil |
| 149 | 149 |
} |
| ... | ... |
@@ -3,6 +3,7 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
|
| 6 |
+ Cli "github.com/docker/docker/cli" |
|
| 6 | 7 |
flag "github.com/docker/docker/pkg/mflag" |
| 7 | 8 |
) |
| 8 | 9 |
|
| ... | ... |
@@ -10,7 +11,7 @@ import ( |
| 10 | 10 |
// |
| 11 | 11 |
// Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...] |
| 12 | 12 |
func (cli *DockerCli) CmdKill(args ...string) error {
|
| 13 |
- cmd := cli.Subcmd("kill", []string{"CONTAINER [CONTAINER...]"}, "Kill a running container using SIGKILL or a specified signal", true)
|
|
| 13 |
+ cmd := Cli.Subcmd("kill", []string{"CONTAINER [CONTAINER...]"}, "Kill a running container using SIGKILL or a specified signal", true)
|
|
| 14 | 14 |
signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
|
| 15 | 15 |
cmd.Require(flag.Min, 1) |
| 16 | 16 |
|
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
"os" |
| 6 | 6 |
|
| 7 |
+ Cli "github.com/docker/docker/cli" |
|
| 7 | 8 |
flag "github.com/docker/docker/pkg/mflag" |
| 8 | 9 |
) |
| 9 | 10 |
|
| ... | ... |
@@ -13,7 +14,7 @@ import ( |
| 13 | 13 |
// |
| 14 | 14 |
// Usage: docker load [OPTIONS] |
| 15 | 15 |
func (cli *DockerCli) CmdLoad(args ...string) error {
|
| 16 |
- cmd := cli.Subcmd("load", nil, "Load an image from a tar archive or STDIN", true)
|
|
| 16 |
+ cmd := Cli.Subcmd("load", nil, "Load an image from a tar archive or STDIN", true)
|
|
| 17 | 17 |
infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
|
| 18 | 18 |
cmd.Require(flag.Exact, 0) |
| 19 | 19 |
|
| ... | ... |
@@ -9,6 +9,7 @@ import ( |
| 9 | 9 |
"strings" |
| 10 | 10 |
|
| 11 | 11 |
"github.com/docker/docker/api/types" |
| 12 |
+ Cli "github.com/docker/docker/cli" |
|
| 12 | 13 |
"github.com/docker/docker/cliconfig" |
| 13 | 14 |
flag "github.com/docker/docker/pkg/mflag" |
| 14 | 15 |
"github.com/docker/docker/pkg/term" |
| ... | ... |
@@ -21,7 +22,7 @@ import ( |
| 21 | 21 |
// |
| 22 | 22 |
// Usage: docker login SERVER |
| 23 | 23 |
func (cli *DockerCli) CmdLogin(args ...string) error {
|
| 24 |
- cmd := cli.Subcmd("login", []string{"[SERVER]"}, "Register or log in to a Docker registry server, if no server is\nspecified \""+registry.INDEXSERVER+"\" is the default.", true)
|
|
| 24 |
+ cmd := Cli.Subcmd("login", []string{"[SERVER]"}, "Register or log in to a Docker registry server, if no server is\nspecified \""+registry.INDEXSERVER+"\" is the default.", true)
|
|
| 25 | 25 |
cmd.Require(flag.Max, 1) |
| 26 | 26 |
|
| 27 | 27 |
var username, password, email string |
| ... | ... |
@@ -3,6 +3,7 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
|
| 6 |
+ Cli "github.com/docker/docker/cli" |
|
| 6 | 7 |
flag "github.com/docker/docker/pkg/mflag" |
| 7 | 8 |
"github.com/docker/docker/registry" |
| 8 | 9 |
) |
| ... | ... |
@@ -13,7 +14,7 @@ import ( |
| 13 | 13 |
// |
| 14 | 14 |
// Usage: docker logout [SERVER] |
| 15 | 15 |
func (cli *DockerCli) CmdLogout(args ...string) error {
|
| 16 |
- cmd := cli.Subcmd("logout", []string{"[SERVER]"}, "Log out from a Docker registry, if no server is\nspecified \""+registry.INDEXSERVER+"\" is the default.", true)
|
|
| 16 |
+ cmd := Cli.Subcmd("logout", []string{"[SERVER]"}, "Log out from a Docker registry, if no server is\nspecified \""+registry.INDEXSERVER+"\" is the default.", true)
|
|
| 17 | 17 |
cmd.Require(flag.Max, 1) |
| 18 | 18 |
|
| 19 | 19 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"time" |
| 8 | 8 |
|
| 9 | 9 |
"github.com/docker/docker/api/types" |
| 10 |
+ Cli "github.com/docker/docker/cli" |
|
| 10 | 11 |
flag "github.com/docker/docker/pkg/mflag" |
| 11 | 12 |
"github.com/docker/docker/pkg/timeutils" |
| 12 | 13 |
) |
| ... | ... |
@@ -15,7 +16,7 @@ import ( |
| 15 | 15 |
// |
| 16 | 16 |
// docker logs [OPTIONS] CONTAINER |
| 17 | 17 |
func (cli *DockerCli) CmdLogs(args ...string) error {
|
| 18 |
- cmd := cli.Subcmd("logs", []string{"CONTAINER"}, "Fetch the logs of a container", true)
|
|
| 18 |
+ cmd := Cli.Subcmd("logs", []string{"CONTAINER"}, "Fetch the logs of a container", true)
|
|
| 19 | 19 |
follow := cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
|
| 20 | 20 |
since := cmd.String([]string{"-since"}, "", "Show logs since timestamp")
|
| 21 | 21 |
times := cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
|
| ... | ... |
@@ -3,6 +3,7 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
|
| 6 |
+ Cli "github.com/docker/docker/cli" |
|
| 6 | 7 |
flag "github.com/docker/docker/pkg/mflag" |
| 7 | 8 |
) |
| 8 | 9 |
|
| ... | ... |
@@ -10,7 +11,7 @@ import ( |
| 10 | 10 |
// |
| 11 | 11 |
// Usage: docker pause CONTAINER [CONTAINER...] |
| 12 | 12 |
func (cli *DockerCli) CmdPause(args ...string) error {
|
| 13 |
- cmd := cli.Subcmd("pause", []string{"CONTAINER [CONTAINER...]"}, "Pause all processes within a container", true)
|
|
| 13 |
+ cmd := Cli.Subcmd("pause", []string{"CONTAINER [CONTAINER...]"}, "Pause all processes within a container", true)
|
|
| 14 | 14 |
cmd.Require(flag.Min, 1) |
| 15 | 15 |
|
| 16 | 16 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"strings" |
| 7 | 7 |
|
| 8 |
+ Cli "github.com/docker/docker/cli" |
|
| 8 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 10 |
"github.com/docker/docker/pkg/nat" |
| 10 | 11 |
) |
| ... | ... |
@@ -14,7 +15,7 @@ import ( |
| 14 | 14 |
// |
| 15 | 15 |
// Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]] |
| 16 | 16 |
func (cli *DockerCli) CmdPort(args ...string) error {
|
| 17 |
- cmd := cli.Subcmd("port", []string{"CONTAINER [PRIVATE_PORT[/PROTO]]"}, "List port mappings for the CONTAINER, or lookup the public-facing port that\nis NAT-ed to the PRIVATE_PORT", true)
|
|
| 17 |
+ cmd := Cli.Subcmd("port", []string{"CONTAINER [PRIVATE_PORT[/PROTO]]"}, "List port mappings for the CONTAINER, or lookup the public-facing port that\nis NAT-ed to the PRIVATE_PORT", true)
|
|
| 18 | 18 |
cmd.Require(flag.Min, 1) |
| 19 | 19 |
|
| 20 | 20 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/api/client/ps" |
| 9 | 9 |
"github.com/docker/docker/api/types" |
| 10 |
+ Cli "github.com/docker/docker/cli" |
|
| 10 | 11 |
"github.com/docker/docker/opts" |
| 11 | 12 |
flag "github.com/docker/docker/pkg/mflag" |
| 12 | 13 |
"github.com/docker/docker/pkg/parsers/filters" |
| ... | ... |
@@ -22,7 +23,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
| 22 | 22 |
psFilterArgs = filters.Args{}
|
| 23 | 23 |
v = url.Values{}
|
| 24 | 24 |
|
| 25 |
- cmd = cli.Subcmd("ps", nil, "List containers", true)
|
|
| 25 |
+ cmd = Cli.Subcmd("ps", nil, "List containers", true)
|
|
| 26 | 26 |
quiet = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
|
| 27 | 27 |
size = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
|
| 28 | 28 |
all = cmd.Bool([]string{"a", "-all"}, false, "Show all containers (default shows just running)")
|
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"net/url" |
| 6 | 6 |
|
| 7 |
+ Cli "github.com/docker/docker/cli" |
|
| 7 | 8 |
"github.com/docker/docker/graph/tags" |
| 8 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 10 |
"github.com/docker/docker/pkg/parsers" |
| ... | ... |
@@ -15,7 +16,7 @@ import ( |
| 15 | 15 |
// |
| 16 | 16 |
// Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST] |
| 17 | 17 |
func (cli *DockerCli) CmdPull(args ...string) error {
|
| 18 |
- cmd := cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, "Pull an image or a repository from a registry", true)
|
|
| 18 |
+ cmd := Cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, "Pull an image or a repository from a registry", true)
|
|
| 19 | 19 |
allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
|
| 20 | 20 |
cmd.Require(flag.Exact, 1) |
| 21 | 21 |
|
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"net/url" |
| 6 | 6 |
|
| 7 |
+ Cli "github.com/docker/docker/cli" |
|
| 7 | 8 |
flag "github.com/docker/docker/pkg/mflag" |
| 8 | 9 |
"github.com/docker/docker/pkg/parsers" |
| 9 | 10 |
"github.com/docker/docker/registry" |
| ... | ... |
@@ -13,7 +14,7 @@ import ( |
| 13 | 13 |
// |
| 14 | 14 |
// Usage: docker push NAME[:TAG] |
| 15 | 15 |
func (cli *DockerCli) CmdPush(args ...string) error {
|
| 16 |
- cmd := cli.Subcmd("push", []string{"NAME[:TAG]"}, "Push an image or a repository to a registry", true)
|
|
| 16 |
+ cmd := Cli.Subcmd("push", []string{"NAME[:TAG]"}, "Push an image or a repository to a registry", true)
|
|
| 17 | 17 |
cmd.Require(flag.Exact, 1) |
| 18 | 18 |
|
| 19 | 19 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -3,6 +3,7 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
|
| 6 |
+ Cli "github.com/docker/docker/cli" |
|
| 6 | 7 |
flag "github.com/docker/docker/pkg/mflag" |
| 7 | 8 |
) |
| 8 | 9 |
|
| ... | ... |
@@ -10,7 +11,7 @@ import ( |
| 10 | 10 |
// |
| 11 | 11 |
// Usage: docker rename OLD_NAME NEW_NAME |
| 12 | 12 |
func (cli *DockerCli) CmdRename(args ...string) error {
|
| 13 |
- cmd := cli.Subcmd("rename", []string{"OLD_NAME NEW_NAME"}, "Rename a container", true)
|
|
| 13 |
+ cmd := Cli.Subcmd("rename", []string{"OLD_NAME NEW_NAME"}, "Rename a container", true)
|
|
| 14 | 14 |
cmd.Require(flag.Exact, 2) |
| 15 | 15 |
|
| 16 | 16 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"net/url" |
| 6 | 6 |
"strconv" |
| 7 | 7 |
|
| 8 |
+ Cli "github.com/docker/docker/cli" |
|
| 8 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 10 |
) |
| 10 | 11 |
|
| ... | ... |
@@ -12,7 +13,7 @@ import ( |
| 12 | 12 |
// |
| 13 | 13 |
// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...] |
| 14 | 14 |
func (cli *DockerCli) CmdRestart(args ...string) error {
|
| 15 |
- cmd := cli.Subcmd("restart", []string{"CONTAINER [CONTAINER...]"}, "Restart a running container", true)
|
|
| 15 |
+ cmd := Cli.Subcmd("restart", []string{"CONTAINER [CONTAINER...]"}, "Restart a running container", true)
|
|
| 16 | 16 |
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container")
|
| 17 | 17 |
cmd.Require(flag.Min, 1) |
| 18 | 18 |
|
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"net/url" |
| 6 | 6 |
"strings" |
| 7 | 7 |
|
| 8 |
+ Cli "github.com/docker/docker/cli" |
|
| 8 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 10 |
) |
| 10 | 11 |
|
| ... | ... |
@@ -12,7 +13,7 @@ import ( |
| 12 | 12 |
// |
| 13 | 13 |
// Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...] |
| 14 | 14 |
func (cli *DockerCli) CmdRm(args ...string) error {
|
| 15 |
- cmd := cli.Subcmd("rm", []string{"CONTAINER [CONTAINER...]"}, "Remove one or more containers", true)
|
|
| 15 |
+ cmd := Cli.Subcmd("rm", []string{"CONTAINER [CONTAINER...]"}, "Remove one or more containers", true)
|
|
| 16 | 16 |
v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
|
| 17 | 17 |
link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link")
|
| 18 | 18 |
force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
|
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"net/url" |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/api/types" |
| 9 |
+ Cli "github.com/docker/docker/cli" |
|
| 9 | 10 |
flag "github.com/docker/docker/pkg/mflag" |
| 10 | 11 |
) |
| 11 | 12 |
|
| ... | ... |
@@ -13,7 +14,7 @@ import ( |
| 13 | 13 |
// |
| 14 | 14 |
// Usage: docker rmi [OPTIONS] IMAGE [IMAGE...] |
| 15 | 15 |
func (cli *DockerCli) CmdRmi(args ...string) error {
|
| 16 |
- cmd := cli.Subcmd("rmi", []string{"IMAGE [IMAGE...]"}, "Remove one or more images", true)
|
|
| 16 |
+ cmd := Cli.Subcmd("rmi", []string{"IMAGE [IMAGE...]"}, "Remove one or more images", true)
|
|
| 17 | 17 |
force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
|
| 18 | 18 |
noprune := cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
|
| 19 | 19 |
cmd.Require(flag.Min, 1) |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"runtime" |
| 9 | 9 |
|
| 10 | 10 |
"github.com/Sirupsen/logrus" |
| 11 |
+ Cli "github.com/docker/docker/cli" |
|
| 11 | 12 |
"github.com/docker/docker/opts" |
| 12 | 13 |
"github.com/docker/docker/pkg/promise" |
| 13 | 14 |
"github.com/docker/docker/pkg/signal" |
| ... | ... |
@@ -39,7 +40,7 @@ func (cid *cidFile) Write(id string) error {
|
| 39 | 39 |
// |
| 40 | 40 |
// Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] |
| 41 | 41 |
func (cli *DockerCli) CmdRun(args ...string) error {
|
| 42 |
- cmd := cli.Subcmd("run", []string{"IMAGE [COMMAND] [ARG...]"}, "Run a command in a new container", true)
|
|
| 42 |
+ cmd := Cli.Subcmd("run", []string{"IMAGE [COMMAND] [ARG...]"}, "Run a command in a new container", true)
|
|
| 43 | 43 |
|
| 44 | 44 |
// These are flags not stored in Config/HostConfig |
| 45 | 45 |
var ( |
| ... | ... |
@@ -249,7 +250,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
| 249 | 249 |
} |
| 250 | 250 |
} |
| 251 | 251 |
if status != 0 {
|
| 252 |
- return StatusError{StatusCode: status}
|
|
| 252 |
+ return Cli.StatusError{StatusCode: status}
|
|
| 253 | 253 |
} |
| 254 | 254 |
return nil |
| 255 | 255 |
} |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"net/url" |
| 7 | 7 |
"os" |
| 8 | 8 |
|
| 9 |
+ Cli "github.com/docker/docker/cli" |
|
| 9 | 10 |
flag "github.com/docker/docker/pkg/mflag" |
| 10 | 11 |
) |
| 11 | 12 |
|
| ... | ... |
@@ -15,7 +16,7 @@ import ( |
| 15 | 15 |
// |
| 16 | 16 |
// Usage: docker save [OPTIONS] IMAGE [IMAGE...] |
| 17 | 17 |
func (cli *DockerCli) CmdSave(args ...string) error {
|
| 18 |
- cmd := cli.Subcmd("save", []string{"IMAGE [IMAGE...]"}, "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
|
|
| 18 |
+ cmd := Cli.Subcmd("save", []string{"IMAGE [IMAGE...]"}, "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
|
|
| 19 | 19 |
outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
|
| 20 | 20 |
cmd.Require(flag.Min, 1) |
| 21 | 21 |
|
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"strings" |
| 9 | 9 |
"text/tabwriter" |
| 10 | 10 |
|
| 11 |
+ Cli "github.com/docker/docker/cli" |
|
| 11 | 12 |
flag "github.com/docker/docker/pkg/mflag" |
| 12 | 13 |
"github.com/docker/docker/pkg/parsers" |
| 13 | 14 |
"github.com/docker/docker/pkg/stringutils" |
| ... | ... |
@@ -25,7 +26,7 @@ func (r ByStars) Less(i, j int) bool { return r[i].StarCount < r[j].StarCount }
|
| 25 | 25 |
// |
| 26 | 26 |
// Usage: docker search [OPTIONS] TERM |
| 27 | 27 |
func (cli *DockerCli) CmdSearch(args ...string) error {
|
| 28 |
- cmd := cli.Subcmd("search", []string{"TERM"}, "Search the Docker Hub for images", true)
|
|
| 28 |
+ cmd := Cli.Subcmd("search", []string{"TERM"}, "Search the Docker Hub for images", true)
|
|
| 29 | 29 |
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
| 30 | 30 |
trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
|
| 31 | 31 |
automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
|
| ... | ... |
@@ -9,6 +9,7 @@ import ( |
| 9 | 9 |
|
| 10 | 10 |
"github.com/Sirupsen/logrus" |
| 11 | 11 |
"github.com/docker/docker/api/types" |
| 12 |
+ Cli "github.com/docker/docker/cli" |
|
| 12 | 13 |
flag "github.com/docker/docker/pkg/mflag" |
| 13 | 14 |
"github.com/docker/docker/pkg/promise" |
| 14 | 15 |
"github.com/docker/docker/pkg/signal" |
| ... | ... |
@@ -44,7 +45,7 @@ func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
|
| 44 | 44 |
// |
| 45 | 45 |
// Usage: docker start [OPTIONS] CONTAINER [CONTAINER...] |
| 46 | 46 |
func (cli *DockerCli) CmdStart(args ...string) error {
|
| 47 |
- cmd := cli.Subcmd("start", []string{"CONTAINER [CONTAINER...]"}, "Start one or more stopped containers", true)
|
|
| 47 |
+ cmd := Cli.Subcmd("start", []string{"CONTAINER [CONTAINER...]"}, "Start one or more stopped containers", true)
|
|
| 48 | 48 |
attach := cmd.Bool([]string{"a", "-attach"}, false, "Attach STDOUT/STDERR and forward signals")
|
| 49 | 49 |
openStdin := cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
|
| 50 | 50 |
cmd.Require(flag.Min, 1) |
| ... | ... |
@@ -162,7 +163,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
|
| 162 | 162 |
return err |
| 163 | 163 |
} |
| 164 | 164 |
if status != 0 {
|
| 165 |
- return StatusError{StatusCode: status}
|
|
| 165 |
+ return Cli.StatusError{StatusCode: status}
|
|
| 166 | 166 |
} |
| 167 | 167 |
} |
| 168 | 168 |
return nil |
| ... | ... |
@@ -12,6 +12,7 @@ import ( |
| 12 | 12 |
"time" |
| 13 | 13 |
|
| 14 | 14 |
"github.com/docker/docker/api/types" |
| 15 |
+ Cli "github.com/docker/docker/cli" |
|
| 15 | 16 |
flag "github.com/docker/docker/pkg/mflag" |
| 16 | 17 |
"github.com/docker/docker/pkg/units" |
| 17 | 18 |
) |
| ... | ... |
@@ -124,7 +125,7 @@ func (s *containerStats) Display(w io.Writer) error {
|
| 124 | 124 |
// |
| 125 | 125 |
// Usage: docker stats CONTAINER [CONTAINER...] |
| 126 | 126 |
func (cli *DockerCli) CmdStats(args ...string) error {
|
| 127 |
- cmd := cli.Subcmd("stats", []string{"CONTAINER [CONTAINER...]"}, "Display a live stream of one or more containers' resource usage statistics", true)
|
|
| 127 |
+ cmd := Cli.Subcmd("stats", []string{"CONTAINER [CONTAINER...]"}, "Display a live stream of one or more containers' resource usage statistics", true)
|
|
| 128 | 128 |
noStream := cmd.Bool([]string{"-no-stream"}, false, "Disable streaming stats and only pull the first result")
|
| 129 | 129 |
cmd.Require(flag.Min, 1) |
| 130 | 130 |
|
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"net/url" |
| 6 | 6 |
"strconv" |
| 7 | 7 |
|
| 8 |
+ Cli "github.com/docker/docker/cli" |
|
| 8 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 10 |
) |
| 10 | 11 |
|
| ... | ... |
@@ -14,7 +15,7 @@ import ( |
| 14 | 14 |
// |
| 15 | 15 |
// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...] |
| 16 | 16 |
func (cli *DockerCli) CmdStop(args ...string) error {
|
| 17 |
- cmd := cli.Subcmd("stop", []string{"CONTAINER [CONTAINER...]"}, "Stop a running container by sending SIGTERM and then SIGKILL after a\ngrace period", true)
|
|
| 17 |
+ cmd := Cli.Subcmd("stop", []string{"CONTAINER [CONTAINER...]"}, "Stop a running container by sending SIGTERM and then SIGKILL after a\ngrace period", true)
|
|
| 18 | 18 |
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing it")
|
| 19 | 19 |
cmd.Require(flag.Min, 1) |
| 20 | 20 |
|
| ... | ... |
@@ -3,6 +3,7 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"net/url" |
| 5 | 5 |
|
| 6 |
+ Cli "github.com/docker/docker/cli" |
|
| 6 | 7 |
flag "github.com/docker/docker/pkg/mflag" |
| 7 | 8 |
"github.com/docker/docker/pkg/parsers" |
| 8 | 9 |
"github.com/docker/docker/registry" |
| ... | ... |
@@ -12,7 +13,7 @@ import ( |
| 12 | 12 |
// |
| 13 | 13 |
// Usage: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG] |
| 14 | 14 |
func (cli *DockerCli) CmdTag(args ...string) error {
|
| 15 |
- cmd := cli.Subcmd("tag", []string{"IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]"}, "Tag an image into a repository", true)
|
|
| 15 |
+ cmd := Cli.Subcmd("tag", []string{"IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]"}, "Tag an image into a repository", true)
|
|
| 16 | 16 |
force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
|
| 17 | 17 |
cmd.Require(flag.Exact, 2) |
| 18 | 18 |
|
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"text/tabwriter" |
| 9 | 9 |
|
| 10 | 10 |
"github.com/docker/docker/api/types" |
| 11 |
+ Cli "github.com/docker/docker/cli" |
|
| 11 | 12 |
flag "github.com/docker/docker/pkg/mflag" |
| 12 | 13 |
) |
| 13 | 14 |
|
| ... | ... |
@@ -15,7 +16,7 @@ import ( |
| 15 | 15 |
// |
| 16 | 16 |
// Usage: docker top CONTAINER |
| 17 | 17 |
func (cli *DockerCli) CmdTop(args ...string) error {
|
| 18 |
- cmd := cli.Subcmd("top", []string{"CONTAINER [ps OPTIONS]"}, "Display the running processes of a container", true)
|
|
| 18 |
+ cmd := Cli.Subcmd("top", []string{"CONTAINER [ps OPTIONS]"}, "Display the running processes of a container", true)
|
|
| 19 | 19 |
cmd.Require(flag.Min, 1) |
| 20 | 20 |
|
| 21 | 21 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -3,6 +3,7 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
|
| 6 |
+ Cli "github.com/docker/docker/cli" |
|
| 6 | 7 |
flag "github.com/docker/docker/pkg/mflag" |
| 7 | 8 |
) |
| 8 | 9 |
|
| ... | ... |
@@ -10,7 +11,7 @@ import ( |
| 10 | 10 |
// |
| 11 | 11 |
// Usage: docker unpause CONTAINER [CONTAINER...] |
| 12 | 12 |
func (cli *DockerCli) CmdUnpause(args ...string) error {
|
| 13 |
- cmd := cli.Subcmd("unpause", []string{"CONTAINER [CONTAINER...]"}, "Unpause all processes within a container", true)
|
|
| 13 |
+ cmd := Cli.Subcmd("unpause", []string{"CONTAINER [CONTAINER...]"}, "Unpause all processes within a container", true)
|
|
| 14 | 14 |
cmd.Require(flag.Min, 1) |
| 15 | 15 |
|
| 16 | 16 |
cmd.ParseFlags(args, true) |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"github.com/docker/docker/api" |
| 9 | 9 |
"github.com/docker/docker/api/types" |
| 10 | 10 |
"github.com/docker/docker/autogen/dockerversion" |
| 11 |
+ Cli "github.com/docker/docker/cli" |
|
| 11 | 12 |
flag "github.com/docker/docker/pkg/mflag" |
| 12 | 13 |
"github.com/docker/docker/utils" |
| 13 | 14 |
) |
| ... | ... |
@@ -42,7 +43,7 @@ type VersionData struct {
|
| 42 | 42 |
// |
| 43 | 43 |
// Usage: docker version |
| 44 | 44 |
func (cli *DockerCli) CmdVersion(args ...string) (err error) {
|
| 45 |
- cmd := cli.Subcmd("version", nil, "Show the Docker version information.", true)
|
|
| 45 |
+ cmd := Cli.Subcmd("version", nil, "Show the Docker version information.", true)
|
|
| 46 | 46 |
tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template")
|
| 47 | 47 |
cmd.Require(flag.Exact, 0) |
| 48 | 48 |
|
| ... | ... |
@@ -53,7 +54,7 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
|
| 53 | 53 |
|
| 54 | 54 |
var tmpl *template.Template |
| 55 | 55 |
if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
|
| 56 |
- return StatusError{StatusCode: 64,
|
|
| 56 |
+ return Cli.StatusError{StatusCode: 64,
|
|
| 57 | 57 |
Status: "Template parsing error: " + err.Error()} |
| 58 | 58 |
} |
| 59 | 59 |
|
| ... | ... |
@@ -85,7 +86,7 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
|
| 85 | 85 |
defer serverResp.body.Close() |
| 86 | 86 |
|
| 87 | 87 |
if err = json.NewDecoder(serverResp.body).Decode(&vd.Server); err != nil {
|
| 88 |
- return StatusError{StatusCode: 1,
|
|
| 88 |
+ return Cli.StatusError{StatusCode: 1,
|
|
| 89 | 89 |
Status: "Error reading remote version: " + err.Error()} |
| 90 | 90 |
} |
| 91 | 91 |
|
| ... | ... |
@@ -3,6 +3,7 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
|
| 6 |
+ Cli "github.com/docker/docker/cli" |
|
| 6 | 7 |
flag "github.com/docker/docker/pkg/mflag" |
| 7 | 8 |
) |
| 8 | 9 |
|
| ... | ... |
@@ -12,7 +13,7 @@ import ( |
| 12 | 12 |
// |
| 13 | 13 |
// Usage: docker wait CONTAINER [CONTAINER...] |
| 14 | 14 |
func (cli *DockerCli) CmdWait(args ...string) error {
|
| 15 |
- cmd := cli.Subcmd("wait", []string{"CONTAINER [CONTAINER...]"}, "Block until a container stops, then print its exit code.", true)
|
|
| 15 |
+ cmd := Cli.Subcmd("wait", []string{"CONTAINER [CONTAINER...]"}, "Block until a container stops, then print its exit code.", true)
|
|
| 16 | 16 |
cmd.Require(flag.Min, 1) |
| 17 | 17 |
|
| 18 | 18 |
cmd.ParseFlags(args, true) |
| 19 | 19 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,200 @@ |
| 0 |
+package cli |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "errors" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "io" |
|
| 6 |
+ "os" |
|
| 7 |
+ "reflect" |
|
| 8 |
+ "strings" |
|
| 9 |
+ |
|
| 10 |
+ flag "github.com/docker/docker/pkg/mflag" |
|
| 11 |
+) |
|
| 12 |
+ |
|
| 13 |
+// Cli represents a command line interface. |
|
| 14 |
+type Cli struct {
|
|
| 15 |
+ Stderr io.Writer |
|
| 16 |
+ handlers []Handler |
|
| 17 |
+ Usage func() |
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+// Handler holds the different commands Cli will call |
|
| 21 |
+// It should have methods with names starting with `Cmd` like: |
|
| 22 |
+// func (h myHandler) CmdFoo(args ...string) error |
|
| 23 |
+type Handler interface{}
|
|
| 24 |
+ |
|
| 25 |
+// Initializer can be optionally implemented by a Handler to |
|
| 26 |
+// initialize before each call to one of its commands. |
|
| 27 |
+type Initializer interface {
|
|
| 28 |
+ Initialize() error |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+// New instantiates a ready-to-use Cli. |
|
| 32 |
+func New(handlers ...Handler) *Cli {
|
|
| 33 |
+ // make the generic Cli object the first cli handler |
|
| 34 |
+ // in order to handle `docker help` appropriately |
|
| 35 |
+ cli := new(Cli) |
|
| 36 |
+ cli.handlers = append([]Handler{cli}, handlers...)
|
|
| 37 |
+ return cli |
|
| 38 |
+} |
|
| 39 |
+ |
|
| 40 |
+// initErr is an error returned upon initialization of a handler implementing Initializer. |
|
| 41 |
+type initErr struct{ error }
|
|
| 42 |
+ |
|
| 43 |
+func (err initErr) Error() string {
|
|
| 44 |
+ return err.Error() |
|
| 45 |
+} |
|
| 46 |
+ |
|
| 47 |
+func (cli *Cli) command(args ...string) (func(...string) error, error) {
|
|
| 48 |
+ for _, c := range cli.handlers {
|
|
| 49 |
+ if c == nil {
|
|
| 50 |
+ continue |
|
| 51 |
+ } |
|
| 52 |
+ camelArgs := make([]string, len(args)) |
|
| 53 |
+ for i, s := range args {
|
|
| 54 |
+ if len(s) == 0 {
|
|
| 55 |
+ return nil, errors.New("empty command")
|
|
| 56 |
+ } |
|
| 57 |
+ camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:]) |
|
| 58 |
+ } |
|
| 59 |
+ methodName := "Cmd" + strings.Join(camelArgs, "") |
|
| 60 |
+ method := reflect.ValueOf(c).MethodByName(methodName) |
|
| 61 |
+ if method.IsValid() {
|
|
| 62 |
+ if c, ok := c.(Initializer); ok {
|
|
| 63 |
+ if err := c.Initialize(); err != nil {
|
|
| 64 |
+ return nil, initErr{err}
|
|
| 65 |
+ } |
|
| 66 |
+ } |
|
| 67 |
+ return method.Interface().(func(...string) error), nil |
|
| 68 |
+ } |
|
| 69 |
+ } |
|
| 70 |
+ return nil, errors.New("command not found")
|
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+// Run executes the specified command. |
|
| 74 |
+func (cli *Cli) Run(args ...string) error {
|
|
| 75 |
+ if len(args) > 1 {
|
|
| 76 |
+ command, err := cli.command(args[:2]...) |
|
| 77 |
+ switch err := err.(type) {
|
|
| 78 |
+ case nil: |
|
| 79 |
+ return command(args[2:]...) |
|
| 80 |
+ case initErr: |
|
| 81 |
+ return err.error |
|
| 82 |
+ } |
|
| 83 |
+ } |
|
| 84 |
+ if len(args) > 0 {
|
|
| 85 |
+ command, err := cli.command(args[0]) |
|
| 86 |
+ switch err := err.(type) {
|
|
| 87 |
+ case nil: |
|
| 88 |
+ return command(args[1:]...) |
|
| 89 |
+ case initErr: |
|
| 90 |
+ return err.error |
|
| 91 |
+ } |
|
| 92 |
+ cli.noSuchCommand(args[0]) |
|
| 93 |
+ } |
|
| 94 |
+ return cli.CmdHelp() |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+func (cli *Cli) noSuchCommand(command string) {
|
|
| 98 |
+ if cli.Stderr == nil {
|
|
| 99 |
+ cli.Stderr = os.Stderr |
|
| 100 |
+ } |
|
| 101 |
+ fmt.Fprintf(cli.Stderr, "docker: '%s' is not a docker command.\nSee 'docker --help'.\n", command) |
|
| 102 |
+ os.Exit(1) |
|
| 103 |
+} |
|
| 104 |
+ |
|
| 105 |
+// CmdHelp displays information on a Docker command. |
|
| 106 |
+// |
|
| 107 |
+// If more than one command is specified, information is only shown for the first command. |
|
| 108 |
+// |
|
| 109 |
+// Usage: docker help COMMAND or docker COMMAND --help |
|
| 110 |
+func (cli *Cli) CmdHelp(args ...string) error {
|
|
| 111 |
+ if len(args) > 1 {
|
|
| 112 |
+ command, err := cli.command(args[:2]...) |
|
| 113 |
+ switch err := err.(type) {
|
|
| 114 |
+ case nil: |
|
| 115 |
+ command("--help")
|
|
| 116 |
+ return nil |
|
| 117 |
+ case initErr: |
|
| 118 |
+ return err.error |
|
| 119 |
+ } |
|
| 120 |
+ } |
|
| 121 |
+ if len(args) > 0 {
|
|
| 122 |
+ command, err := cli.command(args[0]) |
|
| 123 |
+ switch err := err.(type) {
|
|
| 124 |
+ case nil: |
|
| 125 |
+ command("--help")
|
|
| 126 |
+ return nil |
|
| 127 |
+ case initErr: |
|
| 128 |
+ return err.error |
|
| 129 |
+ } |
|
| 130 |
+ cli.noSuchCommand(args[0]) |
|
| 131 |
+ } |
|
| 132 |
+ |
|
| 133 |
+ if cli.Usage == nil {
|
|
| 134 |
+ flag.Usage() |
|
| 135 |
+ } else {
|
|
| 136 |
+ cli.Usage() |
|
| 137 |
+ } |
|
| 138 |
+ |
|
| 139 |
+ return nil |
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+// Subcmd is a subcommand of the main "docker" command. |
|
| 143 |
+// A subcommand represents an action that can be performed |
|
| 144 |
+// from the Docker command line client. |
|
| 145 |
+// |
|
| 146 |
+// To see all available subcommands, run "docker --help". |
|
| 147 |
+func Subcmd(name string, synopses []string, description string, exitOnError bool) *flag.FlagSet {
|
|
| 148 |
+ var errorHandling flag.ErrorHandling |
|
| 149 |
+ if exitOnError {
|
|
| 150 |
+ errorHandling = flag.ExitOnError |
|
| 151 |
+ } else {
|
|
| 152 |
+ errorHandling = flag.ContinueOnError |
|
| 153 |
+ } |
|
| 154 |
+ flags := flag.NewFlagSet(name, errorHandling) |
|
| 155 |
+ flags.Usage = func() {
|
|
| 156 |
+ flags.ShortUsage() |
|
| 157 |
+ flags.PrintDefaults() |
|
| 158 |
+ } |
|
| 159 |
+ |
|
| 160 |
+ flags.ShortUsage = func() {
|
|
| 161 |
+ options := "" |
|
| 162 |
+ if flags.FlagCountUndeprecated() > 0 {
|
|
| 163 |
+ options = " [OPTIONS]" |
|
| 164 |
+ } |
|
| 165 |
+ |
|
| 166 |
+ if len(synopses) == 0 {
|
|
| 167 |
+ synopses = []string{""}
|
|
| 168 |
+ } |
|
| 169 |
+ |
|
| 170 |
+ // Allow for multiple command usage synopses. |
|
| 171 |
+ for i, synopsis := range synopses {
|
|
| 172 |
+ lead := "\t" |
|
| 173 |
+ if i == 0 {
|
|
| 174 |
+ // First line needs the word 'Usage'. |
|
| 175 |
+ lead = "Usage:\t" |
|
| 176 |
+ } |
|
| 177 |
+ |
|
| 178 |
+ if synopsis != "" {
|
|
| 179 |
+ synopsis = " " + synopsis |
|
| 180 |
+ } |
|
| 181 |
+ |
|
| 182 |
+ fmt.Fprintf(flags.Out(), "\n%sdocker %s%s%s", lead, name, options, synopsis) |
|
| 183 |
+ } |
|
| 184 |
+ |
|
| 185 |
+ fmt.Fprintf(flags.Out(), "\n\n%s\n", description) |
|
| 186 |
+ } |
|
| 187 |
+ |
|
| 188 |
+ return flags |
|
| 189 |
+} |
|
| 190 |
+ |
|
| 191 |
+// An StatusError reports an unsuccessful exit by a command. |
|
| 192 |
+type StatusError struct {
|
|
| 193 |
+ Status string |
|
| 194 |
+ StatusCode int |
|
| 195 |
+} |
|
| 196 |
+ |
|
| 197 |
+func (e StatusError) Error() string {
|
|
| 198 |
+ return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
|
|
| 199 |
+} |
| 0 | 200 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,12 @@ |
| 0 |
+package cli |
|
| 1 |
+ |
|
| 2 |
+import flag "github.com/docker/docker/pkg/mflag" |
|
| 3 |
+ |
|
| 4 |
+// ClientFlags represents flags for the docker client. |
|
| 5 |
+type ClientFlags struct {
|
|
| 6 |
+ FlagSet *flag.FlagSet |
|
| 7 |
+ Common *CommonFlags |
|
| 8 |
+ PostParse func() |
|
| 9 |
+ |
|
| 10 |
+ ConfigDir string |
|
| 11 |
+} |
| 0 | 12 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,20 @@ |
| 0 |
+package cli |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ flag "github.com/docker/docker/pkg/mflag" |
|
| 4 |
+ "github.com/docker/docker/pkg/tlsconfig" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// CommonFlags represents flags that are common to both the client and the daemon. |
|
| 8 |
+type CommonFlags struct {
|
|
| 9 |
+ FlagSet *flag.FlagSet |
|
| 10 |
+ PostParse func() |
|
| 11 |
+ |
|
| 12 |
+ Debug bool |
|
| 13 |
+ Hosts []string |
|
| 14 |
+ LogLevel string |
|
| 15 |
+ TLS bool |
|
| 16 |
+ TLSVerify bool |
|
| 17 |
+ TLSOptions *tlsconfig.Options |
|
| 18 |
+ TrustKey string |
|
| 19 |
+} |
| ... | ... |
@@ -41,22 +41,22 @@ type CommonConfig struct {
|
| 41 | 41 |
// the current process. |
| 42 | 42 |
// Subsequent calls to `flag.Parse` will populate config with values parsed |
| 43 | 43 |
// from the command-line. |
| 44 |
-func (config *Config) InstallCommonFlags() {
|
|
| 45 |
- opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options")
|
|
| 46 |
- opts.ListVar(&config.ExecOptions, []string{"-exec-opt"}, "Set exec driver options")
|
|
| 47 |
- flag.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, "Path to use for daemon PID file")
|
|
| 48 |
- flag.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, "Root of the Docker runtime")
|
|
| 49 |
- flag.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", "Root of the Docker execdriver")
|
|
| 50 |
- flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run")
|
|
| 51 |
- flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Storage driver to use")
|
|
| 52 |
- flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, "Exec driver to use")
|
|
| 53 |
- flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "Set the containers network MTU")
|
|
| 54 |
- flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header")
|
|
| 55 |
- flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API")
|
|
| 44 |
+func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string) string) {
|
|
| 45 |
+ cmd.Var(opts.NewListOptsRef(&config.GraphOptions, nil), []string{"-storage-opt"}, usageFn("Set storage driver options"))
|
|
| 46 |
+ cmd.Var(opts.NewListOptsRef(&config.ExecOptions, nil), []string{"-exec-opt"}, usageFn("Set exec driver options"))
|
|
| 47 |
+ cmd.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, usageFn("Path to use for daemon PID file"))
|
|
| 48 |
+ cmd.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, usageFn("Root of the Docker runtime"))
|
|
| 49 |
+ cmd.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", usageFn("Root of the Docker execdriver"))
|
|
| 50 |
+ cmd.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, usageFn("--restart on the daemon has been deprecated in favor of --restart policies on docker run"))
|
|
| 51 |
+ cmd.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", usageFn("Storage driver to use"))
|
|
| 52 |
+ cmd.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, usageFn("Exec driver to use"))
|
|
| 53 |
+ cmd.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, usageFn("Set the containers network MTU"))
|
|
| 54 |
+ cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header"))
|
|
| 55 |
+ cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
|
|
| 56 | 56 |
// FIXME: why the inconsistency between "hosts" and "sockets"? |
| 57 |
- opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use")
|
|
| 58 |
- opts.DNSSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "DNS search domains to use")
|
|
| 59 |
- opts.LabelListVar(&config.Labels, []string{"-label"}, "Set key=value labels to the daemon")
|
|
| 60 |
- flag.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", "Default driver for container logs")
|
|
| 61 |
- opts.LogOptsVar(config.LogConfig.Config, []string{"-log-opt"}, "Set log driver options")
|
|
| 57 |
+ cmd.Var(opts.NewListOptsRef(&config.Dns, opts.ValidateIPAddress), []string{"#dns", "-dns"}, usageFn("DNS server to use"))
|
|
| 58 |
+ cmd.Var(opts.NewListOptsRef(&config.DnsSearch, opts.ValidateDNSSearch), []string{"-dns-search"}, usageFn("DNS search domains to use"))
|
|
| 59 |
+ cmd.Var(opts.NewListOptsRef(&config.Labels, opts.ValidateLabel), []string{"-label"}, usageFn("Set key=value labels to the daemon"))
|
|
| 60 |
+ cmd.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", usageFn("Default driver for container logs"))
|
|
| 61 |
+ cmd.Var(opts.NewMapOpts(config.LogConfig.Config, nil), []string{"-log-opt"}, usageFn("Set log driver options"))
|
|
| 62 | 62 |
} |
| ... | ... |
@@ -4,7 +4,7 @@ package daemon |
| 4 | 4 |
|
| 5 | 5 |
import flag "github.com/docker/docker/pkg/mflag" |
| 6 | 6 |
|
| 7 |
-func (config *Config) attachExperimentalFlags() {
|
|
| 8 |
- flag.StringVar(&config.DefaultNetwork, []string{"-default-network"}, "", "Set default network")
|
|
| 9 |
- flag.StringVar(&config.NetworkKVStore, []string{"-kv-store"}, "", "Set KV Store configuration")
|
|
| 7 |
+func (config *Config) attachExperimentalFlags(cmd *flag.FlagSet, usageFn func(string) string) {
|
|
| 8 |
+ cmd.StringVar(&config.DefaultNetwork, []string{"-default-network"}, "", usageFn("Set default network"))
|
|
| 9 |
+ cmd.StringVar(&config.NetworkKVStore, []string{"-kv-store"}, "", usageFn("Set KV Store configuration"))
|
|
| 10 | 10 |
} |
| ... | ... |
@@ -49,27 +49,28 @@ type bridgeConfig struct {
|
| 49 | 49 |
// the current process. |
| 50 | 50 |
// Subsequent calls to `flag.Parse` will populate config with values parsed |
| 51 | 51 |
// from the command-line. |
| 52 |
-func (config *Config) InstallFlags() {
|
|
| 52 |
+func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
|
|
| 53 | 53 |
// First handle install flags which are consistent cross-platform |
| 54 |
- config.InstallCommonFlags() |
|
| 54 |
+ config.InstallCommonFlags(cmd, usageFn) |
|
| 55 | 55 |
|
| 56 | 56 |
// Then platform-specific install flags |
| 57 |
- flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support")
|
|
| 58 |
- flag.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", "Group for the unix socket")
|
|
| 57 |
+ cmd.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, usageFn("Enable selinux support"))
|
|
| 58 |
+ cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", usageFn("Group for the unix socket"))
|
|
| 59 | 59 |
config.Ulimits = make(map[string]*ulimit.Ulimit) |
| 60 |
- opts.UlimitMapVar(config.Ulimits, []string{"-default-ulimit"}, "Set default ulimits for containers")
|
|
| 61 |
- flag.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
|
|
| 62 |
- flag.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
|
|
| 63 |
- flag.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
|
|
| 64 |
- flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking")
|
|
| 65 |
- flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP")
|
|
| 66 |
- flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
|
|
| 67 |
- flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs")
|
|
| 68 |
- flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs")
|
|
| 69 |
- opts.IPVar(&config.Bridge.DefaultGatewayIPv4, []string{"-default-gateway"}, "", "Container default gateway IPv4 address")
|
|
| 70 |
- opts.IPVar(&config.Bridge.DefaultGatewayIPv6, []string{"-default-gateway-v6"}, "", "Container default gateway IPv6 address")
|
|
| 71 |
- flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
|
|
| 72 |
- opts.IPVar(&config.Bridge.DefaultIP, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
|
|
| 73 |
- flag.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, "Use userland proxy for loopback traffic")
|
|
| 74 |
- config.attachExperimentalFlags() |
|
| 60 |
+ cmd.Var(opts.NewUlimitOpt(&config.Ulimits), []string{"-default-ulimit"}, usageFn("Set default ulimits for containers"))
|
|
| 61 |
+ cmd.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, usageFn("Enable addition of iptables rules"))
|
|
| 62 |
+ cmd.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, usageFn("Enable net.ipv4.ip_forward"))
|
|
| 63 |
+ cmd.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, usageFn("Enable IP masquerading"))
|
|
| 64 |
+ cmd.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, usageFn("Enable IPv6 networking"))
|
|
| 65 |
+ cmd.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", usageFn("Specify network bridge IP"))
|
|
| 66 |
+ cmd.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", usageFn("Attach containers to a network bridge"))
|
|
| 67 |
+ cmd.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", usageFn("IPv4 subnet for fixed IPs"))
|
|
| 68 |
+ cmd.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", usageFn("IPv6 subnet for fixed IPs"))
|
|
| 69 |
+ cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultGatewayIPv4, ""), []string{"-default-gateway"}, usageFn("Container default gateway IPv4 address"))
|
|
| 70 |
+ cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultGatewayIPv6, ""), []string{"-default-gateway-v6"}, usageFn("Container default gateway IPv6 address"))
|
|
| 71 |
+ cmd.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, usageFn("Enable inter-container communication"))
|
|
| 72 |
+ cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultIP, "0.0.0.0"), []string{"#ip", "-ip"}, usageFn("Default IP when binding container ports"))
|
|
| 73 |
+ cmd.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
|
|
| 74 |
+ |
|
| 75 |
+ config.attachExperimentalFlags(cmd, usageFn) |
|
| 75 | 76 |
} |
| ... | ... |
@@ -32,9 +32,9 @@ type Config struct {
|
| 32 | 32 |
// the current process. |
| 33 | 33 |
// Subsequent calls to `flag.Parse` will populate config with values parsed |
| 34 | 34 |
// from the command-line. |
| 35 |
-func (config *Config) InstallFlags() {
|
|
| 35 |
+func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
|
|
| 36 | 36 |
// First handle install flags which are consistent cross-platform |
| 37 |
- config.InstallCommonFlags() |
|
| 37 |
+ config.InstallCommonFlags(cmd, usageFn) |
|
| 38 | 38 |
|
| 39 | 39 |
// Then platform-specific install flags. |
| 40 | 40 |
flag.StringVar(&config.Bridge.VirtualSwitchName, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch")
|
| ... | ... |
@@ -1,11 +1,28 @@ |
| 1 |
-// +build !daemon |
|
| 2 |
- |
|
| 3 | 1 |
package main |
| 4 | 2 |
|
| 5 | 3 |
import ( |
| 6 |
- "log" // see gh#8745, client needs to use go log pkg |
|
| 4 |
+ "path/filepath" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/docker/docker/cli" |
|
| 7 |
+ "github.com/docker/docker/cliconfig" |
|
| 8 |
+ flag "github.com/docker/docker/pkg/mflag" |
|
| 7 | 9 |
) |
| 8 | 10 |
|
| 9 |
-func mainDaemon() {
|
|
| 10 |
- log.Fatal("This is a client-only binary - running the Docker daemon is not supported.")
|
|
| 11 |
+var clientFlags = &cli.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags}
|
|
| 12 |
+ |
|
| 13 |
+func init() {
|
|
| 14 |
+ client := clientFlags.FlagSet |
|
| 15 |
+ client.StringVar(&clientFlags.ConfigDir, []string{"-config"}, cliconfig.ConfigDir(), "Location of client config files")
|
|
| 16 |
+ |
|
| 17 |
+ clientFlags.PostParse = func() {
|
|
| 18 |
+ clientFlags.Common.PostParse() |
|
| 19 |
+ |
|
| 20 |
+ if clientFlags.ConfigDir != "" {
|
|
| 21 |
+ cliconfig.SetConfigDir(clientFlags.ConfigDir) |
|
| 22 |
+ } |
|
| 23 |
+ |
|
| 24 |
+ if clientFlags.Common.TrustKey == "" {
|
|
| 25 |
+ clientFlags.Common.TrustKey = filepath.Join(cliconfig.ConfigDir(), defaultTrustKeyFile) |
|
| 26 |
+ } |
|
| 27 |
+ } |
|
| 11 | 28 |
} |
| 12 | 29 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,101 @@ |
| 0 |
+package main |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "os" |
|
| 5 |
+ "path/filepath" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/Sirupsen/logrus" |
|
| 8 |
+ "github.com/docker/docker/cli" |
|
| 9 |
+ "github.com/docker/docker/cliconfig" |
|
| 10 |
+ "github.com/docker/docker/opts" |
|
| 11 |
+ flag "github.com/docker/docker/pkg/mflag" |
|
| 12 |
+ "github.com/docker/docker/pkg/tlsconfig" |
|
| 13 |
+) |
|
| 14 |
+ |
|
| 15 |
+const ( |
|
| 16 |
+ defaultTrustKeyFile = "key.json" |
|
| 17 |
+ defaultCaFile = "ca.pem" |
|
| 18 |
+ defaultKeyFile = "key.pem" |
|
| 19 |
+ defaultCertFile = "cert.pem" |
|
| 20 |
+) |
|
| 21 |
+ |
|
| 22 |
+var ( |
|
| 23 |
+ daemonFlags *flag.FlagSet |
|
| 24 |
+ commonFlags = &cli.CommonFlags{FlagSet: new(flag.FlagSet)}
|
|
| 25 |
+ |
|
| 26 |
+ dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
|
|
| 27 |
+ dockerTLSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
|
|
| 28 |
+) |
|
| 29 |
+ |
|
| 30 |
+func init() {
|
|
| 31 |
+ if dockerCertPath == "" {
|
|
| 32 |
+ dockerCertPath = cliconfig.ConfigDir() |
|
| 33 |
+ } |
|
| 34 |
+ |
|
| 35 |
+ commonFlags.PostParse = postParseCommon |
|
| 36 |
+ |
|
| 37 |
+ cmd := commonFlags.FlagSet |
|
| 38 |
+ |
|
| 39 |
+ cmd.BoolVar(&commonFlags.Debug, []string{"D", "-debug"}, false, "Enable debug mode")
|
|
| 40 |
+ cmd.StringVar(&commonFlags.LogLevel, []string{"l", "-log-level"}, "info", "Set the logging level")
|
|
| 41 |
+ cmd.BoolVar(&commonFlags.TLS, []string{"-tls"}, false, "Use TLS; implied by --tlsverify")
|
|
| 42 |
+ cmd.BoolVar(&commonFlags.TLSVerify, []string{"-tlsverify"}, dockerTLSVerify, "Use TLS and verify the remote")
|
|
| 43 |
+ |
|
| 44 |
+ // TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file")
|
|
| 45 |
+ |
|
| 46 |
+ var tlsOptions tlsconfig.Options |
|
| 47 |
+ commonFlags.TLSOptions = &tlsOptions |
|
| 48 |
+ cmd.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA")
|
|
| 49 |
+ cmd.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file")
|
|
| 50 |
+ cmd.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file")
|
|
| 51 |
+ |
|
| 52 |
+ cmd.Var(opts.NewListOptsRef(&commonFlags.Hosts, opts.ValidateHost), []string{"H", "-host"}, "Daemon socket(s) to connect to")
|
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+func postParseCommon() {
|
|
| 56 |
+ cmd := commonFlags.FlagSet |
|
| 57 |
+ |
|
| 58 |
+ if commonFlags.LogLevel != "" {
|
|
| 59 |
+ lvl, err := logrus.ParseLevel(commonFlags.LogLevel) |
|
| 60 |
+ if err != nil {
|
|
| 61 |
+ fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", commonFlags.LogLevel) |
|
| 62 |
+ os.Exit(1) |
|
| 63 |
+ } |
|
| 64 |
+ logrus.SetLevel(lvl) |
|
| 65 |
+ } else {
|
|
| 66 |
+ logrus.SetLevel(logrus.InfoLevel) |
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ if commonFlags.Debug {
|
|
| 70 |
+ os.Setenv("DEBUG", "1")
|
|
| 71 |
+ logrus.SetLevel(logrus.DebugLevel) |
|
| 72 |
+ } |
|
| 73 |
+ |
|
| 74 |
+ // Regardless of whether the user sets it to true or false, if they |
|
| 75 |
+ // specify --tlsverify at all then we need to turn on tls |
|
| 76 |
+ // TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need to check that here as well |
|
| 77 |
+ if cmd.IsSet("-tlsverify") || commonFlags.TLSVerify {
|
|
| 78 |
+ commonFlags.TLS = true |
|
| 79 |
+ } |
|
| 80 |
+ |
|
| 81 |
+ if !commonFlags.TLS {
|
|
| 82 |
+ commonFlags.TLSOptions = nil |
|
| 83 |
+ } else {
|
|
| 84 |
+ tlsOptions := commonFlags.TLSOptions |
|
| 85 |
+ tlsOptions.InsecureSkipVerify = !commonFlags.TLSVerify |
|
| 86 |
+ |
|
| 87 |
+ // Reset CertFile and KeyFile to empty string if the user did not specify |
|
| 88 |
+ // the respective flags and the respective default files were not found. |
|
| 89 |
+ if !cmd.IsSet("-tlscert") {
|
|
| 90 |
+ if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
|
|
| 91 |
+ tlsOptions.CertFile = "" |
|
| 92 |
+ } |
|
| 93 |
+ } |
|
| 94 |
+ if !cmd.IsSet("-tlskey") {
|
|
| 95 |
+ if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
|
|
| 96 |
+ tlsOptions.KeyFile = "" |
|
| 97 |
+ } |
|
| 98 |
+ } |
|
| 99 |
+ } |
|
| 100 |
+} |
| ... | ... |
@@ -8,14 +8,18 @@ import ( |
| 8 | 8 |
"io" |
| 9 | 9 |
"os" |
| 10 | 10 |
"path/filepath" |
| 11 |
+ "runtime" |
|
| 12 |
+ "strings" |
|
| 11 | 13 |
"time" |
| 12 | 14 |
|
| 13 | 15 |
"github.com/Sirupsen/logrus" |
| 14 | 16 |
apiserver "github.com/docker/docker/api/server" |
| 15 | 17 |
"github.com/docker/docker/autogen/dockerversion" |
| 18 |
+ "github.com/docker/docker/cli" |
|
| 16 | 19 |
"github.com/docker/docker/cliconfig" |
| 17 | 20 |
"github.com/docker/docker/daemon" |
| 18 | 21 |
"github.com/docker/docker/daemon/logger" |
| 22 |
+ "github.com/docker/docker/opts" |
|
| 19 | 23 |
flag "github.com/docker/docker/pkg/mflag" |
| 20 | 24 |
"github.com/docker/docker/pkg/pidfile" |
| 21 | 25 |
"github.com/docker/docker/pkg/signal" |
| ... | ... |
@@ -26,17 +30,63 @@ import ( |
| 26 | 26 |
"github.com/docker/docker/utils" |
| 27 | 27 |
) |
| 28 | 28 |
|
| 29 |
+const daemonUsage = " docker daemon [ --help | ... ]\n" |
|
| 30 |
+ |
|
| 29 | 31 |
var ( |
| 30 |
- daemonCfg = &daemon.Config{}
|
|
| 31 |
- registryCfg = ®istry.Options{}
|
|
| 32 |
+ flDaemon = flag.Bool([]string{"#d", "#-daemon"}, false, "Enable daemon mode (deprecated; use docker daemon)")
|
|
| 33 |
+ daemonCli cli.Handler = NewDaemonCli() |
|
| 32 | 34 |
) |
| 33 | 35 |
|
| 34 |
-func init() {
|
|
| 35 |
- if daemonCfg.LogConfig.Config == nil {
|
|
| 36 |
- daemonCfg.LogConfig.Config = make(map[string]string) |
|
| 36 |
+// TODO: remove once `-d` is retired |
|
| 37 |
+func handleGlobalDaemonFlag() {
|
|
| 38 |
+ // This block makes sure that if the deprecated daemon flag `--daemon` is absent, |
|
| 39 |
+ // then all daemon-specific flags are absent as well. |
|
| 40 |
+ if !*flDaemon && daemonFlags != nil {
|
|
| 41 |
+ flag.CommandLine.Visit(func(fl *flag.Flag) {
|
|
| 42 |
+ for _, name := range fl.Names {
|
|
| 43 |
+ name := strings.TrimPrefix(name, "#") |
|
| 44 |
+ if daemonFlags.Lookup(name) != nil {
|
|
| 45 |
+ // daemon flag was NOT specified, but daemon-specific flags were |
|
| 46 |
+ // so let's error out |
|
| 47 |
+ fmt.Fprintf(os.Stderr, "docker: the daemon flag '-%s' must follow the 'docker daemon' command.\n", name) |
|
| 48 |
+ os.Exit(1) |
|
| 49 |
+ } |
|
| 50 |
+ } |
|
| 51 |
+ }) |
|
| 52 |
+ } |
|
| 53 |
+ |
|
| 54 |
+ if *flDaemon {
|
|
| 55 |
+ if *flHelp {
|
|
| 56 |
+ // We do not show the help output here, instead, we tell the user about the new daemon command, |
|
| 57 |
+ // because the help output is so long they would not see the warning anyway. |
|
| 58 |
+ fmt.Fprintln(os.Stderr, "Please use 'docker daemon --help' instead.") |
|
| 59 |
+ os.Exit(0) |
|
| 60 |
+ } |
|
| 61 |
+ daemonCli.(*DaemonCli).CmdDaemon(flag.Args()...) |
|
| 62 |
+ os.Exit(0) |
|
| 63 |
+ } |
|
| 64 |
+} |
|
| 65 |
+ |
|
| 66 |
+func presentInHelp(usage string) string { return usage }
|
|
| 67 |
+func absentFromHelp(string) string { return "" }
|
|
| 68 |
+ |
|
| 69 |
+// NewDaemonCli returns a pre-configured daemon CLI |
|
| 70 |
+func NewDaemonCli() *DaemonCli {
|
|
| 71 |
+ daemonFlags = cli.Subcmd("daemon", nil, "Enable daemon mode", true)
|
|
| 72 |
+ |
|
| 73 |
+ // TODO(tiborvass): remove InstallFlags? |
|
| 74 |
+ daemonConfig := new(daemon.Config) |
|
| 75 |
+ daemonConfig.InstallFlags(daemonFlags, presentInHelp) |
|
| 76 |
+ daemonConfig.InstallFlags(flag.CommandLine, absentFromHelp) |
|
| 77 |
+ registryOptions := new(registry.Options) |
|
| 78 |
+ registryOptions.InstallFlags(daemonFlags, presentInHelp) |
|
| 79 |
+ registryOptions.InstallFlags(flag.CommandLine, absentFromHelp) |
|
| 80 |
+ daemonFlags.Require(flag.Exact, 0) |
|
| 81 |
+ |
|
| 82 |
+ return &DaemonCli{
|
|
| 83 |
+ Config: daemonConfig, |
|
| 84 |
+ registryOptions: registryOptions, |
|
| 37 | 85 |
} |
| 38 |
- daemonCfg.InstallFlags() |
|
| 39 |
- registryCfg.InstallFlags() |
|
| 40 | 86 |
} |
| 41 | 87 |
|
| 42 | 88 |
func migrateKey() (err error) {
|
| ... | ... |
@@ -79,14 +129,56 @@ func migrateKey() (err error) {
|
| 79 | 79 |
return nil |
| 80 | 80 |
} |
| 81 | 81 |
|
| 82 |
-func mainDaemon() {
|
|
| 83 |
- if utils.ExperimentalBuild() {
|
|
| 84 |
- logrus.Warn("Running experimental build")
|
|
| 82 |
+// DaemonCli represents the daemon CLI. |
|
| 83 |
+type DaemonCli struct {
|
|
| 84 |
+ *daemon.Config |
|
| 85 |
+ registryOptions *registry.Options |
|
| 86 |
+} |
|
| 87 |
+ |
|
| 88 |
+func getGlobalFlag() (globalFlag *flag.Flag) {
|
|
| 89 |
+ defer func() {
|
|
| 90 |
+ if x := recover(); x != nil {
|
|
| 91 |
+ switch f := x.(type) {
|
|
| 92 |
+ case *flag.Flag: |
|
| 93 |
+ globalFlag = f |
|
| 94 |
+ default: |
|
| 95 |
+ panic(x) |
|
| 96 |
+ } |
|
| 97 |
+ } |
|
| 98 |
+ }() |
|
| 99 |
+ visitor := func(f *flag.Flag) { panic(f) }
|
|
| 100 |
+ commonFlags.FlagSet.Visit(visitor) |
|
| 101 |
+ clientFlags.FlagSet.Visit(visitor) |
|
| 102 |
+ return |
|
| 103 |
+} |
|
| 104 |
+ |
|
| 105 |
+// CmdDaemon is the daemon command, called the raw arguments after `docker daemon`. |
|
| 106 |
+func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
|
| 107 |
+ if *flDaemon {
|
|
| 108 |
+ // allow legacy forms `docker -D -d` and `docker -d -D` |
|
| 109 |
+ logrus.Warn("please use 'docker daemon' instead.")
|
|
| 110 |
+ } else if !commonFlags.FlagSet.IsEmpty() || !clientFlags.FlagSet.IsEmpty() {
|
|
| 111 |
+ // deny `docker -D daemon` |
|
| 112 |
+ illegalFlag := getGlobalFlag() |
|
| 113 |
+ fmt.Fprintf(os.Stderr, "invalid flag '-%s'.\nSee 'docker daemon --help'.\n", illegalFlag.Names[0]) |
|
| 114 |
+ os.Exit(1) |
|
| 115 |
+ } else {
|
|
| 116 |
+ // allow new form `docker daemon -D` |
|
| 117 |
+ flag.Merge(daemonFlags, commonFlags.FlagSet) |
|
| 118 |
+ } |
|
| 119 |
+ |
|
| 120 |
+ daemonFlags.ParseFlags(args, true) |
|
| 121 |
+ commonFlags.PostParse() |
|
| 122 |
+ |
|
| 123 |
+ if len(commonFlags.Hosts) == 0 {
|
|
| 124 |
+ commonFlags.Hosts = []string{opts.DefaultHost}
|
|
| 125 |
+ } |
|
| 126 |
+ if commonFlags.TrustKey == "" {
|
|
| 127 |
+ commonFlags.TrustKey = filepath.Join(getDaemonConfDir(), defaultTrustKeyFile) |
|
| 85 | 128 |
} |
| 86 | 129 |
|
| 87 |
- if flag.NArg() != 0 {
|
|
| 88 |
- flag.Usage() |
|
| 89 |
- return |
|
| 130 |
+ if utils.ExperimentalBuild() {
|
|
| 131 |
+ logrus.Warn("Running experimental build")
|
|
| 90 | 132 |
} |
| 91 | 133 |
|
| 92 | 134 |
logrus.SetFormatter(&logrus.TextFormatter{TimestampFormat: timeutils.RFC3339NanoFixed})
|
| ... | ... |
@@ -95,15 +187,15 @@ func mainDaemon() {
|
| 95 | 95 |
logrus.Fatalf("Failed to set umask: %v", err)
|
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 |
- if len(daemonCfg.LogConfig.Config) > 0 {
|
|
| 99 |
- if err := logger.ValidateLogOpts(daemonCfg.LogConfig.Type, daemonCfg.LogConfig.Config); err != nil {
|
|
| 98 |
+ if len(cli.LogConfig.Config) > 0 {
|
|
| 99 |
+ if err := logger.ValidateLogOpts(cli.LogConfig.Type, cli.LogConfig.Config); err != nil {
|
|
| 100 | 100 |
logrus.Fatalf("Failed to set log opts: %v", err)
|
| 101 | 101 |
} |
| 102 | 102 |
} |
| 103 | 103 |
|
| 104 | 104 |
var pfile *pidfile.PidFile |
| 105 |
- if daemonCfg.Pidfile != "" {
|
|
| 106 |
- pf, err := pidfile.New(daemonCfg.Pidfile) |
|
| 105 |
+ if cli.Pidfile != "" {
|
|
| 106 |
+ pf, err := pidfile.New(cli.Pidfile) |
|
| 107 | 107 |
if err != nil {
|
| 108 | 108 |
logrus.Fatalf("Error starting daemon: %v", err)
|
| 109 | 109 |
} |
| ... | ... |
@@ -115,21 +207,26 @@ func mainDaemon() {
|
| 115 | 115 |
}() |
| 116 | 116 |
} |
| 117 | 117 |
|
| 118 |
+ if cli.LogConfig.Config == nil {
|
|
| 119 |
+ cli.LogConfig.Config = make(map[string]string) |
|
| 120 |
+ } |
|
| 121 |
+ |
|
| 118 | 122 |
serverConfig := &apiserver.ServerConfig{
|
| 119 | 123 |
Logging: true, |
| 120 |
- EnableCors: daemonCfg.EnableCors, |
|
| 121 |
- CorsHeaders: daemonCfg.CorsHeaders, |
|
| 124 |
+ EnableCors: cli.EnableCors, |
|
| 125 |
+ CorsHeaders: cli.CorsHeaders, |
|
| 122 | 126 |
Version: dockerversion.VERSION, |
| 123 | 127 |
} |
| 124 |
- serverConfig = setPlatformServerConfig(serverConfig, daemonCfg) |
|
| 128 |
+ serverConfig = setPlatformServerConfig(serverConfig, cli.Config) |
|
| 125 | 129 |
|
| 126 |
- if *flTLS {
|
|
| 127 |
- if *flTLSVerify {
|
|
| 128 |
- tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert |
|
| 130 |
+ if commonFlags.TLSOptions != nil {
|
|
| 131 |
+ if !commonFlags.TLSOptions.InsecureSkipVerify {
|
|
| 132 |
+ // server requires and verifies client's certificate |
|
| 133 |
+ commonFlags.TLSOptions.ClientAuth = tls.RequireAndVerifyClientCert |
|
| 129 | 134 |
} |
| 130 |
- tlsConfig, err := tlsconfig.Server(tlsOptions) |
|
| 135 |
+ tlsConfig, err := tlsconfig.Server(*commonFlags.TLSOptions) |
|
| 131 | 136 |
if err != nil {
|
| 132 |
- logrus.Fatal(err) |
|
| 137 |
+ logrus.Fatalf("foobar: %v", err)
|
|
| 133 | 138 |
} |
| 134 | 139 |
serverConfig.TLSConfig = tlsConfig |
| 135 | 140 |
} |
| ... | ... |
@@ -141,7 +238,7 @@ func mainDaemon() {
|
| 141 | 141 |
// daemon doesn't exit |
| 142 | 142 |
serveAPIWait := make(chan error) |
| 143 | 143 |
go func() {
|
| 144 |
- if err := api.ServeApi(flHosts); err != nil {
|
|
| 144 |
+ if err := api.ServeApi(commonFlags.Hosts); err != nil {
|
|
| 145 | 145 |
logrus.Errorf("ServeAPI error: %v", err)
|
| 146 | 146 |
serveAPIWait <- err |
| 147 | 147 |
return |
| ... | ... |
@@ -152,10 +249,10 @@ func mainDaemon() {
|
| 152 | 152 |
if err := migrateKey(); err != nil {
|
| 153 | 153 |
logrus.Fatal(err) |
| 154 | 154 |
} |
| 155 |
- daemonCfg.TrustKeyPath = *flTrustKey |
|
| 155 |
+ cli.TrustKeyPath = commonFlags.TrustKey |
|
| 156 | 156 |
|
| 157 |
- registryService := registry.NewService(registryCfg) |
|
| 158 |
- d, err := daemon.NewDaemon(daemonCfg, registryService) |
|
| 157 |
+ registryService := registry.NewService(cli.registryOptions) |
|
| 158 |
+ d, err := daemon.NewDaemon(cli.Config, registryService) |
|
| 159 | 159 |
if err != nil {
|
| 160 | 160 |
if pfile != nil {
|
| 161 | 161 |
if err := pfile.Remove(); err != nil {
|
| ... | ... |
@@ -201,6 +298,7 @@ func mainDaemon() {
|
| 201 | 201 |
} |
| 202 | 202 |
logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)
|
| 203 | 203 |
} |
| 204 |
+ return nil |
|
| 204 | 205 |
} |
| 205 | 206 |
|
| 206 | 207 |
// shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case |
| ... | ... |
@@ -219,3 +317,11 @@ func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) {
|
| 219 | 219 |
logrus.Error("Force shutdown daemon")
|
| 220 | 220 |
} |
| 221 | 221 |
} |
| 222 |
+ |
|
| 223 |
+func getDaemonConfDir() string {
|
|
| 224 |
+ // TODO: update for Windows daemon |
|
| 225 |
+ if runtime.GOOS == "windows" {
|
|
| 226 |
+ return cliconfig.ConfigDir() |
|
| 227 |
+ } |
|
| 228 |
+ return "/etc/docker" |
|
| 229 |
+} |
| ... | ... |
@@ -1,31 +1,20 @@ |
| 1 | 1 |
package main |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "crypto/tls" |
|
| 5 | 4 |
"fmt" |
| 6 | 5 |
"os" |
| 7 |
- "runtime" |
|
| 8 |
- "strings" |
|
| 6 |
+ "sort" |
|
| 9 | 7 |
|
| 10 | 8 |
"github.com/Sirupsen/logrus" |
| 11 | 9 |
"github.com/docker/docker/api/client" |
| 12 | 10 |
"github.com/docker/docker/autogen/dockerversion" |
| 13 |
- "github.com/docker/docker/cliconfig" |
|
| 14 |
- "github.com/docker/docker/opts" |
|
| 11 |
+ "github.com/docker/docker/cli" |
|
| 15 | 12 |
flag "github.com/docker/docker/pkg/mflag" |
| 16 | 13 |
"github.com/docker/docker/pkg/reexec" |
| 17 | 14 |
"github.com/docker/docker/pkg/term" |
| 18 |
- "github.com/docker/docker/pkg/tlsconfig" |
|
| 19 | 15 |
"github.com/docker/docker/utils" |
| 20 | 16 |
) |
| 21 | 17 |
|
| 22 |
-const ( |
|
| 23 |
- defaultTrustKeyFile = "key.json" |
|
| 24 |
- defaultCaFile = "ca.pem" |
|
| 25 |
- defaultKeyFile = "key.pem" |
|
| 26 |
- defaultCertFile = "cert.pem" |
|
| 27 |
-) |
|
| 28 |
- |
|
| 29 | 18 |
func main() {
|
| 30 | 19 |
if reexec.Init() {
|
| 31 | 20 |
return |
| ... | ... |
@@ -34,116 +23,58 @@ func main() {
|
| 34 | 34 |
// Set terminal emulation based on platform as required. |
| 35 | 35 |
stdin, stdout, stderr := term.StdStreams() |
| 36 | 36 |
|
| 37 |
- initLogging(stderr) |
|
| 37 |
+ logrus.SetOutput(stderr) |
|
| 38 | 38 |
|
| 39 |
- flag.Parse() |
|
| 40 |
- // FIXME: validate daemon flags here |
|
| 39 |
+ flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet) |
|
| 41 | 40 |
|
| 42 |
- if *flVersion {
|
|
| 43 |
- showVersion() |
|
| 44 |
- return |
|
| 45 |
- } |
|
| 41 |
+ flag.Usage = func() {
|
|
| 42 |
+ fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n"+daemonUsage+" docker [ -h | --help | -v | --version ]\n\n") |
|
| 43 |
+ fmt.Fprint(os.Stdout, "A self-sufficient runtime for containers.\n\nOptions:\n") |
|
| 46 | 44 |
|
| 47 |
- if *flConfigDir != "" {
|
|
| 48 |
- cliconfig.SetConfigDir(*flConfigDir) |
|
| 49 |
- } |
|
| 45 |
+ flag.CommandLine.SetOutput(os.Stdout) |
|
| 46 |
+ flag.PrintDefaults() |
|
| 50 | 47 |
|
| 51 |
- if *flLogLevel != "" {
|
|
| 52 |
- lvl, err := logrus.ParseLevel(*flLogLevel) |
|
| 53 |
- if err != nil {
|
|
| 54 |
- fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", *flLogLevel) |
|
| 55 |
- os.Exit(1) |
|
| 56 |
- } |
|
| 57 |
- setLogLevel(lvl) |
|
| 58 |
- } else {
|
|
| 59 |
- setLogLevel(logrus.InfoLevel) |
|
| 60 |
- } |
|
| 48 |
+ help := "\nCommands:\n" |
|
| 61 | 49 |
|
| 62 |
- if *flDebug {
|
|
| 63 |
- os.Setenv("DEBUG", "1")
|
|
| 64 |
- setLogLevel(logrus.DebugLevel) |
|
| 65 |
- } |
|
| 50 |
+ // TODO(tiborvass): no need to sort if we ensure dockerCommands is sorted |
|
| 51 |
+ sort.Sort(byName(dockerCommands)) |
|
| 66 | 52 |
|
| 67 |
- if len(flHosts) == 0 {
|
|
| 68 |
- defaultHost := os.Getenv("DOCKER_HOST")
|
|
| 69 |
- if defaultHost == "" || *flDaemon {
|
|
| 70 |
- if runtime.GOOS != "windows" {
|
|
| 71 |
- // If we do not have a host, default to unix socket |
|
| 72 |
- defaultHost = fmt.Sprintf("unix://%s", opts.DefaultUnixSocket)
|
|
| 73 |
- } else {
|
|
| 74 |
- // If we do not have a host, default to TCP socket on Windows |
|
| 75 |
- defaultHost = fmt.Sprintf("tcp://%s:%d", opts.DefaultHTTPHost, opts.DefaultHTTPPort)
|
|
| 76 |
- } |
|
| 77 |
- } |
|
| 78 |
- defaultHost, err := opts.ValidateHost(defaultHost) |
|
| 79 |
- if err != nil {
|
|
| 80 |
- if *flDaemon {
|
|
| 81 |
- logrus.Fatal(err) |
|
| 82 |
- } else {
|
|
| 83 |
- fmt.Fprint(os.Stderr, err) |
|
| 84 |
- } |
|
| 85 |
- os.Exit(1) |
|
| 53 |
+ for _, cmd := range dockerCommands {
|
|
| 54 |
+ help += fmt.Sprintf(" %-10.10s%s\n", cmd.name, cmd.description)
|
|
| 86 | 55 |
} |
| 87 |
- flHosts = append(flHosts, defaultHost) |
|
| 88 |
- } |
|
| 89 |
- |
|
| 90 |
- setDefaultConfFlag(flTrustKey, defaultTrustKeyFile) |
|
| 91 | 56 |
|
| 92 |
- // Regardless of whether the user sets it to true or false, if they |
|
| 93 |
- // specify --tlsverify at all then we need to turn on tls |
|
| 94 |
- // *flTlsVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need to check that here as well |
|
| 95 |
- if flag.IsSet("-tlsverify") || *flTLSVerify {
|
|
| 96 |
- *flTLS = true |
|
| 57 |
+ help += "\nRun 'docker COMMAND --help' for more information on a command." |
|
| 58 |
+ fmt.Fprintf(os.Stdout, "%s\n", help) |
|
| 97 | 59 |
} |
| 98 | 60 |
|
| 99 |
- if *flDaemon {
|
|
| 100 |
- if *flHelp {
|
|
| 101 |
- flag.Usage() |
|
| 102 |
- return |
|
| 103 |
- } |
|
| 104 |
- mainDaemon() |
|
| 61 |
+ flag.Parse() |
|
| 62 |
+ |
|
| 63 |
+ if *flVersion {
|
|
| 64 |
+ showVersion() |
|
| 105 | 65 |
return |
| 106 | 66 |
} |
| 107 | 67 |
|
| 108 |
- // From here on, we assume we're a client, not a server. |
|
| 68 |
+ clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags) |
|
| 69 |
+ // TODO: remove once `-d` is retired |
|
| 70 |
+ handleGlobalDaemonFlag() |
|
| 109 | 71 |
|
| 110 |
- if len(flHosts) > 1 {
|
|
| 111 |
- fmt.Fprintf(os.Stderr, "Please specify only one -H") |
|
| 112 |
- os.Exit(0) |
|
| 113 |
- } |
|
| 114 |
- protoAddrParts := strings.SplitN(flHosts[0], "://", 2) |
|
| 115 |
- |
|
| 116 |
- var tlsConfig *tls.Config |
|
| 117 |
- if *flTLS {
|
|
| 118 |
- tlsOptions.InsecureSkipVerify = !*flTLSVerify |
|
| 119 |
- if !flag.IsSet("-tlscert") {
|
|
| 120 |
- if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
|
|
| 121 |
- tlsOptions.CertFile = "" |
|
| 122 |
- } |
|
| 123 |
- } |
|
| 124 |
- if !flag.IsSet("-tlskey") {
|
|
| 125 |
- if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
|
|
| 126 |
- tlsOptions.KeyFile = "" |
|
| 127 |
- } |
|
| 128 |
- } |
|
| 129 |
- var err error |
|
| 130 |
- tlsConfig, err = tlsconfig.Client(tlsOptions) |
|
| 131 |
- if err != nil {
|
|
| 132 |
- fmt.Fprintln(stderr, err) |
|
| 133 |
- os.Exit(1) |
|
| 134 |
- } |
|
| 72 |
+ if *flHelp {
|
|
| 73 |
+ // if global flag --help is present, regardless of what other options and commands there are, |
|
| 74 |
+ // just print the usage. |
|
| 75 |
+ flag.Usage() |
|
| 76 |
+ return |
|
| 135 | 77 |
} |
| 136 |
- cli := client.NewDockerCli(stdin, stdout, stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], tlsConfig) |
|
| 137 | 78 |
|
| 138 |
- if err := cli.Cmd(flag.Args()...); err != nil {
|
|
| 139 |
- if sterr, ok := err.(client.StatusError); ok {
|
|
| 79 |
+ c := cli.New(clientCli, daemonCli) |
|
| 80 |
+ if err := c.Run(flag.Args()...); err != nil {
|
|
| 81 |
+ if sterr, ok := err.(cli.StatusError); ok {
|
|
| 140 | 82 |
if sterr.Status != "" {
|
| 141 |
- fmt.Fprintln(cli.Err(), sterr.Status) |
|
| 83 |
+ fmt.Fprintln(os.Stderr, sterr.Status) |
|
| 142 | 84 |
os.Exit(1) |
| 143 | 85 |
} |
| 144 | 86 |
os.Exit(sterr.StatusCode) |
| 145 | 87 |
} |
| 146 |
- fmt.Fprintln(cli.Err(), err) |
|
| 88 |
+ fmt.Fprintln(os.Stderr, err) |
|
| 147 | 89 |
os.Exit(1) |
| 148 | 90 |
} |
| 149 | 91 |
} |
| ... | ... |
@@ -1,16 +1,10 @@ |
| 1 | 1 |
package main |
| 2 | 2 |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- "os" |
|
| 6 |
- "path/filepath" |
|
| 7 |
- "runtime" |
|
| 8 |
- "sort" |
|
| 3 |
+import flag "github.com/docker/docker/pkg/mflag" |
|
| 9 | 4 |
|
| 10 |
- "github.com/docker/docker/cliconfig" |
|
| 11 |
- "github.com/docker/docker/opts" |
|
| 12 |
- flag "github.com/docker/docker/pkg/mflag" |
|
| 13 |
- "github.com/docker/docker/pkg/tlsconfig" |
|
| 5 |
+var ( |
|
| 6 |
+ flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage")
|
|
| 7 |
+ flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
|
|
| 14 | 8 |
) |
| 15 | 9 |
|
| 16 | 10 |
type command struct {
|
| ... | ... |
@@ -24,118 +18,46 @@ func (a byName) Len() int { return len(a) }
|
| 24 | 24 |
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
| 25 | 25 |
func (a byName) Less(i, j int) bool { return a[i].name < a[j].name }
|
| 26 | 26 |
|
| 27 |
-var ( |
|
| 28 |
- dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
|
|
| 29 |
- dockerTlSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
|
|
| 30 |
- |
|
| 31 |
- dockerCommands = []command{
|
|
| 32 |
- {"attach", "Attach to a running container"},
|
|
| 33 |
- {"build", "Build an image from a Dockerfile"},
|
|
| 34 |
- {"commit", "Create a new image from a container's changes"},
|
|
| 35 |
- {"cp", "Copy files/folders from a container to a HOSTDIR or to STDOUT"},
|
|
| 36 |
- {"create", "Create a new container"},
|
|
| 37 |
- {"diff", "Inspect changes on a container's filesystem"},
|
|
| 38 |
- {"events", "Get real time events from the server"},
|
|
| 39 |
- {"exec", "Run a command in a running container"},
|
|
| 40 |
- {"export", "Export a container's filesystem as a tar archive"},
|
|
| 41 |
- {"history", "Show the history of an image"},
|
|
| 42 |
- {"images", "List images"},
|
|
| 43 |
- {"import", "Import the contents from a tarball to create a filesystem image"},
|
|
| 44 |
- {"info", "Display system-wide information"},
|
|
| 45 |
- {"inspect", "Return low-level information on a container or image"},
|
|
| 46 |
- {"kill", "Kill a running container"},
|
|
| 47 |
- {"load", "Load an image from a tar archive or STDIN"},
|
|
| 48 |
- {"login", "Register or log in to a Docker registry"},
|
|
| 49 |
- {"logout", "Log out from a Docker registry"},
|
|
| 50 |
- {"logs", "Fetch the logs of a container"},
|
|
| 51 |
- {"port", "List port mappings or a specific mapping for the CONTAINER"},
|
|
| 52 |
- {"pause", "Pause all processes within a container"},
|
|
| 53 |
- {"ps", "List containers"},
|
|
| 54 |
- {"pull", "Pull an image or a repository from a registry"},
|
|
| 55 |
- {"push", "Push an image or a repository to a registry"},
|
|
| 56 |
- {"rename", "Rename a container"},
|
|
| 57 |
- {"restart", "Restart a running container"},
|
|
| 58 |
- {"rm", "Remove one or more containers"},
|
|
| 59 |
- {"rmi", "Remove one or more images"},
|
|
| 60 |
- {"run", "Run a command in a new container"},
|
|
| 61 |
- {"save", "Save an image(s) to a tar archive"},
|
|
| 62 |
- {"search", "Search the Docker Hub for images"},
|
|
| 63 |
- {"start", "Start one or more stopped containers"},
|
|
| 64 |
- {"stats", "Display a live stream of container(s) resource usage statistics"},
|
|
| 65 |
- {"stop", "Stop a running container"},
|
|
| 66 |
- {"tag", "Tag an image into a repository"},
|
|
| 67 |
- {"top", "Display the running processes of a container"},
|
|
| 68 |
- {"unpause", "Unpause all processes within a container"},
|
|
| 69 |
- {"version", "Show the Docker version information"},
|
|
| 70 |
- {"wait", "Block until a container stops, then print its exit code"},
|
|
| 71 |
- } |
|
| 72 |
-) |
|
| 73 |
- |
|
| 74 |
-func init() {
|
|
| 75 |
- if dockerCertPath == "" {
|
|
| 76 |
- dockerCertPath = cliconfig.ConfigDir() |
|
| 77 |
- } |
|
| 78 |
-} |
|
| 79 |
- |
|
| 80 |
-func getDaemonConfDir() string {
|
|
| 81 |
- // TODO: update for Windows daemon |
|
| 82 |
- if runtime.GOOS == "windows" {
|
|
| 83 |
- return cliconfig.ConfigDir() |
|
| 84 |
- } |
|
| 85 |
- return "/etc/docker" |
|
| 86 |
-} |
|
| 87 |
- |
|
| 88 |
-var ( |
|
| 89 |
- flConfigDir = flag.String([]string{"-config"}, cliconfig.ConfigDir(), "Location of client config files")
|
|
| 90 |
- flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
|
|
| 91 |
- flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
|
|
| 92 |
- flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
|
|
| 93 |
- flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level")
|
|
| 94 |
- flTLS = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by --tlsverify")
|
|
| 95 |
- flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage")
|
|
| 96 |
- flTLSVerify = flag.Bool([]string{"-tlsverify"}, dockerTlSVerify, "Use TLS and verify the remote")
|
|
| 97 |
- |
|
| 98 |
- // these are initialized in init() below since their default values depend on dockerCertPath which isn't fully initialized until init() runs |
|
| 99 |
- tlsOptions tlsconfig.Options |
|
| 100 |
- flTrustKey *string |
|
| 101 |
- flHosts []string |
|
| 102 |
-) |
|
| 103 |
- |
|
| 104 |
-func setDefaultConfFlag(flag *string, def string) {
|
|
| 105 |
- if *flag == "" {
|
|
| 106 |
- if *flDaemon {
|
|
| 107 |
- *flag = filepath.Join(getDaemonConfDir(), def) |
|
| 108 |
- } else {
|
|
| 109 |
- *flag = filepath.Join(cliconfig.ConfigDir(), def) |
|
| 110 |
- } |
|
| 111 |
- } |
|
| 112 |
-} |
|
| 113 |
- |
|
| 114 |
-func init() {
|
|
| 115 |
- var placeholderTrustKey string |
|
| 116 |
- // TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file")
|
|
| 117 |
- flTrustKey = &placeholderTrustKey |
|
| 118 |
- |
|
| 119 |
- flag.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA")
|
|
| 120 |
- flag.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file")
|
|
| 121 |
- flag.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file")
|
|
| 122 |
- opts.HostListVar(&flHosts, []string{"H", "-host"}, "Daemon socket(s) to connect to")
|
|
| 123 |
- |
|
| 124 |
- flag.Usage = func() {
|
|
| 125 |
- fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for containers.\n\nOptions:\n") |
|
| 126 |
- |
|
| 127 |
- flag.CommandLine.SetOutput(os.Stdout) |
|
| 128 |
- flag.PrintDefaults() |
|
| 129 |
- |
|
| 130 |
- help := "\nCommands:\n" |
|
| 131 |
- |
|
| 132 |
- sort.Sort(byName(dockerCommands)) |
|
| 133 |
- |
|
| 134 |
- for _, cmd := range dockerCommands {
|
|
| 135 |
- help += fmt.Sprintf(" %-10.10s%s\n", cmd.name, cmd.description)
|
|
| 136 |
- } |
|
| 137 |
- |
|
| 138 |
- help += "\nRun 'docker COMMAND --help' for more information on a command." |
|
| 139 |
- fmt.Fprintf(os.Stdout, "%s\n", help) |
|
| 140 |
- } |
|
| 27 |
+// TODO(tiborvass): do not show 'daemon' on client-only binaries |
|
| 28 |
+// and deduplicate description in dockerCommands and cli subcommands |
|
| 29 |
+var dockerCommands = []command{
|
|
| 30 |
+ {"attach", "Attach to a running container"},
|
|
| 31 |
+ {"build", "Build an image from a Dockerfile"},
|
|
| 32 |
+ {"commit", "Create a new image from a container's changes"},
|
|
| 33 |
+ {"cp", "Copy files/folders from a container to a HOSTDIR or to STDOUT"},
|
|
| 34 |
+ {"create", "Create a new container"},
|
|
| 35 |
+ {"diff", "Inspect changes on a container's filesystem"},
|
|
| 36 |
+ {"events", "Get real time events from the server"},
|
|
| 37 |
+ {"exec", "Run a command in a running container"},
|
|
| 38 |
+ {"export", "Export a container's filesystem as a tar archive"},
|
|
| 39 |
+ {"history", "Show the history of an image"},
|
|
| 40 |
+ {"images", "List images"},
|
|
| 41 |
+ {"import", "Import the contents from a tarball to create a filesystem image"},
|
|
| 42 |
+ {"info", "Display system-wide information"},
|
|
| 43 |
+ {"inspect", "Return low-level information on a container or image"},
|
|
| 44 |
+ {"kill", "Kill a running container"},
|
|
| 45 |
+ {"load", "Load an image from a tar archive or STDIN"},
|
|
| 46 |
+ {"login", "Register or log in to a Docker registry"},
|
|
| 47 |
+ {"logout", "Log out from a Docker registry"},
|
|
| 48 |
+ {"logs", "Fetch the logs of a container"},
|
|
| 49 |
+ {"port", "List port mappings or a specific mapping for the CONTAINER"},
|
|
| 50 |
+ {"pause", "Pause all processes within a container"},
|
|
| 51 |
+ {"ps", "List containers"},
|
|
| 52 |
+ {"pull", "Pull an image or a repository from a registry"},
|
|
| 53 |
+ {"push", "Push an image or a repository to a registry"},
|
|
| 54 |
+ {"rename", "Rename a container"},
|
|
| 55 |
+ {"restart", "Restart a running container"},
|
|
| 56 |
+ {"rm", "Remove one or more containers"},
|
|
| 57 |
+ {"rmi", "Remove one or more images"},
|
|
| 58 |
+ {"run", "Run a command in a new container"},
|
|
| 59 |
+ {"save", "Save an image(s) to a tar archive"},
|
|
| 60 |
+ {"search", "Search the Docker Hub for images"},
|
|
| 61 |
+ {"start", "Start one or more stopped containers"},
|
|
| 62 |
+ {"stats", "Display a live stream of container(s) resource usage statistics"},
|
|
| 63 |
+ {"stop", "Stop a running container"},
|
|
| 64 |
+ {"tag", "Tag an image into a repository"},
|
|
| 65 |
+ {"top", "Display the running processes of a container"},
|
|
| 66 |
+ {"unpause", "Unpause all processes within a container"},
|
|
| 67 |
+ {"version", "Show the Docker version information"},
|
|
| 68 |
+ {"wait", "Block until a container stops, then print its exit code"},
|
|
| 141 | 69 |
} |
| ... | ... |
@@ -43,7 +43,8 @@ func (s *DockerDaemonSuite) TestCliProxyProxyTCPSock(c *check.C) {
|
| 43 | 43 |
c.Fatal("could not find ip to connect to")
|
| 44 | 44 |
} |
| 45 | 45 |
|
| 46 |
- if err := s.d.Start("-H", "tcp://"+ip+":2375"); err != nil {
|
|
| 46 |
+ s.d.GlobalFlags = []string{"-H", "tcp://" + ip + ":2375"}
|
|
| 47 |
+ if err := s.d.Start(); err != nil {
|
|
| 47 | 48 |
c.Fatal(err) |
| 48 | 49 |
} |
| 49 | 50 |
|
| ... | ... |
@@ -32,37 +32,37 @@ var ( |
| 32 | 32 |
// ListVar Defines a flag with the specified names and usage, and put the value |
| 33 | 33 |
// list into ListOpts that will hold the values. |
| 34 | 34 |
func ListVar(values *[]string, names []string, usage string) {
|
| 35 |
- flag.Var(newListOptsRef(values, nil), names, usage) |
|
| 35 |
+ flag.Var(NewListOptsRef(values, nil), names, usage) |
|
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 | 38 |
// MapVar Defines a flag with the specified names and usage, and put the value |
| 39 | 39 |
// map into MapOpt that will hold the values (key,value). |
| 40 | 40 |
func MapVar(values map[string]string, names []string, usage string) {
|
| 41 |
- flag.Var(newMapOpt(values, nil), names, usage) |
|
| 41 |
+ flag.Var(NewMapOpts(values, nil), names, usage) |
|
| 42 | 42 |
} |
| 43 | 43 |
|
| 44 | 44 |
// LogOptsVar Defines a flag with the specified names and usage for --log-opts, |
| 45 | 45 |
// and put the value map into MapOpt that will hold the values (key,value). |
| 46 | 46 |
func LogOptsVar(values map[string]string, names []string, usage string) {
|
| 47 |
- flag.Var(newMapOpt(values, nil), names, usage) |
|
| 47 |
+ flag.Var(NewMapOpts(values, nil), names, usage) |
|
| 48 | 48 |
} |
| 49 | 49 |
|
| 50 | 50 |
// HostListVar Defines a flag with the specified names and usage and put the |
| 51 | 51 |
// value into a ListOpts that will hold the values, validating the Host format. |
| 52 | 52 |
func HostListVar(values *[]string, names []string, usage string) {
|
| 53 |
- flag.Var(newListOptsRef(values, ValidateHost), names, usage) |
|
| 53 |
+ flag.Var(NewListOptsRef(values, ValidateHost), names, usage) |
|
| 54 | 54 |
} |
| 55 | 55 |
|
| 56 | 56 |
// IPListVar Defines a flag with the specified names and usage and put the |
| 57 | 57 |
// value into a ListOpts that will hold the values, validating the IP format. |
| 58 | 58 |
func IPListVar(values *[]string, names []string, usage string) {
|
| 59 |
- flag.Var(newListOptsRef(values, ValidateIPAddress), names, usage) |
|
| 59 |
+ flag.Var(NewListOptsRef(values, ValidateIPAddress), names, usage) |
|
| 60 | 60 |
} |
| 61 | 61 |
|
| 62 | 62 |
// DNSSearchListVar Defines a flag with the specified names and usage and put the |
| 63 | 63 |
// value into a ListOpts that will hold the values, validating the DNS search format. |
| 64 | 64 |
func DNSSearchListVar(values *[]string, names []string, usage string) {
|
| 65 |
- flag.Var(newListOptsRef(values, ValidateDNSSearch), names, usage) |
|
| 65 |
+ flag.Var(NewListOptsRef(values, ValidateDNSSearch), names, usage) |
|
| 66 | 66 |
} |
| 67 | 67 |
|
| 68 | 68 |
// IPVar Defines a flag with the specified names and usage for IP and will use |
| ... | ... |
@@ -74,12 +74,12 @@ func IPVar(value *net.IP, names []string, defaultValue, usage string) {
|
| 74 | 74 |
// LabelListVar Defines a flag with the specified names and usage and put the |
| 75 | 75 |
// value into a ListOpts that will hold the values, validating the label format. |
| 76 | 76 |
func LabelListVar(values *[]string, names []string, usage string) {
|
| 77 |
- flag.Var(newListOptsRef(values, ValidateLabel), names, usage) |
|
| 77 |
+ flag.Var(NewListOptsRef(values, ValidateLabel), names, usage) |
|
| 78 | 78 |
} |
| 79 | 79 |
|
| 80 | 80 |
// UlimitMapVar Defines a flag with the specified names and usage for --ulimit, |
| 81 | 81 |
// and put the value map into a UlimitOpt that will hold the values. |
| 82 |
-func UlimitMapVar(values map[string]*ulimit.Ulimit, names []string, usage string) {
|
|
| 82 |
+func UlimitMapVar(values *map[string]*ulimit.Ulimit, names []string, usage string) {
|
|
| 83 | 83 |
flag.Var(NewUlimitOpt(values), names, usage) |
| 84 | 84 |
} |
| 85 | 85 |
|
| ... | ... |
@@ -92,10 +92,10 @@ type ListOpts struct {
|
| 92 | 92 |
// NewListOpts Create a new ListOpts with the specified validator. |
| 93 | 93 |
func NewListOpts(validator ValidatorFctType) ListOpts {
|
| 94 | 94 |
var values []string |
| 95 |
- return *newListOptsRef(&values, validator) |
|
| 95 |
+ return *NewListOptsRef(&values, validator) |
|
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 |
-func newListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
|
|
| 98 |
+func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
|
|
| 99 | 99 |
return &ListOpts{
|
| 100 | 100 |
values: values, |
| 101 | 101 |
validator: validator, |
| ... | ... |
@@ -191,7 +191,10 @@ func (opts *MapOpts) String() string {
|
| 191 | 191 |
return fmt.Sprintf("%v", map[string]string((opts.values)))
|
| 192 | 192 |
} |
| 193 | 193 |
|
| 194 |
-func newMapOpt(values map[string]string, validator ValidatorFctType) *MapOpts {
|
|
| 194 |
+func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
|
|
| 195 |
+ if values == nil {
|
|
| 196 |
+ values = make(map[string]string) |
|
| 197 |
+ } |
|
| 195 | 198 |
return &MapOpts{
|
| 196 | 199 |
values: values, |
| 197 | 200 |
validator: validator, |
| ... | ... |
@@ -32,7 +32,7 @@ func TestValidateIPAddress(t *testing.T) {
|
| 32 | 32 |
|
| 33 | 33 |
func TestMapOpts(t *testing.T) {
|
| 34 | 34 |
tmpMap := make(map[string]string) |
| 35 |
- o := newMapOpt(tmpMap, logOptsValidator) |
|
| 35 |
+ o := NewMapOpts(tmpMap, logOptsValidator) |
|
| 36 | 36 |
o.Set("max-size=1")
|
| 37 | 37 |
if o.String() != "map[max-size:1]" {
|
| 38 | 38 |
t.Errorf("%s != [map[max-size:1]", o.String())
|
| ... | ... |
@@ -7,10 +7,13 @@ import ( |
| 7 | 7 |
) |
| 8 | 8 |
|
| 9 | 9 |
type UlimitOpt struct {
|
| 10 |
- values map[string]*ulimit.Ulimit |
|
| 10 |
+ values *map[string]*ulimit.Ulimit |
|
| 11 | 11 |
} |
| 12 | 12 |
|
| 13 |
-func NewUlimitOpt(ref map[string]*ulimit.Ulimit) *UlimitOpt {
|
|
| 13 |
+func NewUlimitOpt(ref *map[string]*ulimit.Ulimit) *UlimitOpt {
|
|
| 14 |
+ if ref == nil {
|
|
| 15 |
+ ref = &map[string]*ulimit.Ulimit{}
|
|
| 16 |
+ } |
|
| 14 | 17 |
return &UlimitOpt{ref}
|
| 15 | 18 |
} |
| 16 | 19 |
|
| ... | ... |
@@ -20,14 +23,14 @@ func (o *UlimitOpt) Set(val string) error {
|
| 20 | 20 |
return err |
| 21 | 21 |
} |
| 22 | 22 |
|
| 23 |
- o.values[l.Name] = l |
|
| 23 |
+ (*o.values)[l.Name] = l |
|
| 24 | 24 |
|
| 25 | 25 |
return nil |
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 | 28 |
func (o *UlimitOpt) String() string {
|
| 29 | 29 |
var out []string |
| 30 |
- for _, v := range o.values {
|
|
| 30 |
+ for _, v := range *o.values {
|
|
| 31 | 31 |
out = append(out, v.String()) |
| 32 | 32 |
} |
| 33 | 33 |
|
| ... | ... |
@@ -36,7 +39,7 @@ func (o *UlimitOpt) String() string {
|
| 36 | 36 |
|
| 37 | 37 |
func (o *UlimitOpt) GetList() []*ulimit.Ulimit {
|
| 38 | 38 |
var ulimits []*ulimit.Ulimit |
| 39 |
- for _, v := range o.values {
|
|
| 39 |
+ for _, v := range *o.values {
|
|
| 40 | 40 |
ulimits = append(ulimits, v) |
| 41 | 41 |
} |
| 42 | 42 |
|
| ... | ... |
@@ -526,7 +526,7 @@ func (f *FlagSet) PrintDefaults() {
|
| 526 | 526 |
names = append(names, name) |
| 527 | 527 |
} |
| 528 | 528 |
} |
| 529 |
- if len(names) > 0 {
|
|
| 529 |
+ if len(names) > 0 && len(flag.Usage) > 0 {
|
|
| 530 | 530 |
val := flag.DefValue |
| 531 | 531 |
|
| 532 | 532 |
if home != "" && strings.HasPrefix(val, home) {
|
| ... | ... |
@@ -1143,3 +1143,53 @@ func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
|
| 1143 | 1143 |
f.name = name |
| 1144 | 1144 |
f.errorHandling = errorHandling |
| 1145 | 1145 |
} |
| 1146 |
+ |
|
| 1147 |
+type mergeVal struct {
|
|
| 1148 |
+ Value |
|
| 1149 |
+ key string |
|
| 1150 |
+ fset *FlagSet |
|
| 1151 |
+} |
|
| 1152 |
+ |
|
| 1153 |
+func (v mergeVal) Set(s string) error {
|
|
| 1154 |
+ return v.fset.Set(v.key, s) |
|
| 1155 |
+} |
|
| 1156 |
+ |
|
| 1157 |
+func (v mergeVal) IsBoolFlag() bool {
|
|
| 1158 |
+ if b, ok := v.Value.(boolFlag); ok {
|
|
| 1159 |
+ return b.IsBoolFlag() |
|
| 1160 |
+ } |
|
| 1161 |
+ return false |
|
| 1162 |
+} |
|
| 1163 |
+ |
|
| 1164 |
+func Merge(dest *FlagSet, flagsets ...*FlagSet) error {
|
|
| 1165 |
+ for _, fset := range flagsets {
|
|
| 1166 |
+ for k, f := range fset.formal {
|
|
| 1167 |
+ if _, ok := dest.formal[k]; ok {
|
|
| 1168 |
+ var err error |
|
| 1169 |
+ if fset.name == "" {
|
|
| 1170 |
+ err = fmt.Errorf("flag redefined: %s", k)
|
|
| 1171 |
+ } else {
|
|
| 1172 |
+ err = fmt.Errorf("%s flag redefined: %s", fset.name, k)
|
|
| 1173 |
+ } |
|
| 1174 |
+ fmt.Fprintln(fset.Out(), err.Error()) |
|
| 1175 |
+ // Happens only if flags are declared with identical names |
|
| 1176 |
+ switch dest.errorHandling {
|
|
| 1177 |
+ case ContinueOnError: |
|
| 1178 |
+ return err |
|
| 1179 |
+ case ExitOnError: |
|
| 1180 |
+ os.Exit(2) |
|
| 1181 |
+ case PanicOnError: |
|
| 1182 |
+ panic(err) |
|
| 1183 |
+ } |
|
| 1184 |
+ } |
|
| 1185 |
+ newF := *f |
|
| 1186 |
+ newF.Value = mergeVal{f.Value, k, fset}
|
|
| 1187 |
+ dest.formal[k] = &newF |
|
| 1188 |
+ } |
|
| 1189 |
+ } |
|
| 1190 |
+ return nil |
|
| 1191 |
+} |
|
| 1192 |
+ |
|
| 1193 |
+func (f *FlagSet) IsEmpty() bool {
|
|
| 1194 |
+ return len(f.actual) == 0 |
|
| 1195 |
+} |
| ... | ... |
@@ -17,11 +17,18 @@ import ( |
| 17 | 17 |
|
| 18 | 18 |
// Options represents the information needed to create client and server TLS configurations. |
| 19 | 19 |
type Options struct {
|
| 20 |
+ CAFile string |
|
| 21 |
+ |
|
| 22 |
+ // If either CertFile or KeyFile is empty, Client() will not load them |
|
| 23 |
+ // preventing the client from authenticating to the server. |
|
| 24 |
+ // However, Server() requires them and will error out if they are empty. |
|
| 25 |
+ CertFile string |
|
| 26 |
+ KeyFile string |
|
| 27 |
+ |
|
| 28 |
+ // client-only option |
|
| 20 | 29 |
InsecureSkipVerify bool |
| 21 |
- ClientAuth tls.ClientAuthType |
|
| 22 |
- CAFile string |
|
| 23 |
- CertFile string |
|
| 24 |
- KeyFile string |
|
| 30 |
+ // server-only option |
|
| 31 |
+ ClientAuth tls.ClientAuthType |
|
| 25 | 32 |
} |
| 26 | 33 |
|
| 27 | 34 |
// Extra (server-side) accepted CBC cipher suites - will phase out in the future |
| ... | ... |
@@ -43,11 +43,11 @@ var ( |
| 43 | 43 |
|
| 44 | 44 |
// InstallFlags adds command-line options to the top-level flag parser for |
| 45 | 45 |
// the current process. |
| 46 |
-func (options *Options) InstallFlags() {
|
|
| 46 |
+func (options *Options) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
|
|
| 47 | 47 |
options.Mirrors = opts.NewListOpts(ValidateMirror) |
| 48 |
- flag.Var(&options.Mirrors, []string{"-registry-mirror"}, "Preferred Docker registry mirror")
|
|
| 48 |
+ cmd.Var(&options.Mirrors, []string{"-registry-mirror"}, usageFn("Preferred Docker registry mirror"))
|
|
| 49 | 49 |
options.InsecureRegistries = opts.NewListOpts(ValidateIndexName) |
| 50 |
- flag.Var(&options.InsecureRegistries, []string{"-insecure-registry"}, "Enable insecure registry communication")
|
|
| 50 |
+ cmd.Var(&options.InsecureRegistries, []string{"-insecure-registry"}, usageFn("Enable insecure registry communication"))
|
|
| 51 | 51 |
} |
| 52 | 52 |
|
| 53 | 53 |
type netIPNet net.IPNet |
| ... | ... |
@@ -9,7 +9,6 @@ import ( |
| 9 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 10 | 10 |
"github.com/docker/docker/pkg/nat" |
| 11 | 11 |
"github.com/docker/docker/pkg/parsers" |
| 12 |
- "github.com/docker/docker/pkg/ulimit" |
|
| 13 | 12 |
"github.com/docker/docker/pkg/units" |
| 14 | 13 |
) |
| 15 | 14 |
|
| ... | ... |
@@ -48,8 +47,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe |
| 48 | 48 |
flLabels = opts.NewListOpts(opts.ValidateEnv) |
| 49 | 49 |
flDevices = opts.NewListOpts(opts.ValidateDevice) |
| 50 | 50 |
|
| 51 |
- ulimits = make(map[string]*ulimit.Ulimit) |
|
| 52 |
- flUlimits = opts.NewUlimitOpt(ulimits) |
|
| 51 |
+ flUlimits = opts.NewUlimitOpt(nil) |
|
| 53 | 52 |
|
| 54 | 53 |
flPublish = opts.NewListOpts(nil) |
| 55 | 54 |
flExpose = opts.NewListOpts(nil) |