1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #13771 from tiborvass/daemon-cli

New `docker daemon` command
This commit is contained in:
Jessie Frazelle 2015-07-23 19:30:39 -07:00
commit 7674f21686
86 changed files with 1126 additions and 709 deletions

View file

@ -8,6 +8,7 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/signal"
) )
@ -16,9 +17,10 @@ import (
// //
// Usage: docker attach [OPTIONS] CONTAINER // Usage: docker attach [OPTIONS] CONTAINER
func (cli *DockerCli) CmdAttach(args ...string) error { func (cli *DockerCli) CmdAttach(args ...string) error {
cmd := cli.Subcmd("attach", []string{"CONTAINER"}, "Attach to a running container", true) cmd := Cli.Subcmd("attach", []string{"CONTAINER"}, "Attach to a running container", true)
noStdin := cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN") noStdin := cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
proxy := cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process") proxy := cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process")
cmd.Require(flag.Exact, 1) cmd.Require(flag.Exact, 1)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)
@ -75,7 +77,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
return err return err
} }
if status != 0 { if status != 0 {
return StatusError{StatusCode: status} return Cli.StatusError{StatusCode: status}
} }
return nil return nil

View file

@ -18,6 +18,7 @@ import (
"strings" "strings"
"github.com/docker/docker/api" "github.com/docker/docker/api"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/graph/tags" "github.com/docker/docker/graph/tags"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
@ -46,7 +47,7 @@ const (
// //
// Usage: docker build [OPTIONS] PATH | URL | - // Usage: docker build [OPTIONS] PATH | URL | -
func (cli *DockerCli) CmdBuild(args ...string) error { func (cli *DockerCli) CmdBuild(args ...string) error {
cmd := cli.Subcmd("build", []string{"PATH | URL | -"}, "Build a new image from the source code at PATH", true) cmd := Cli.Subcmd("build", []string{"PATH | URL | -"}, "Build a new image from the source code at PATH", true)
tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) for the image") tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) for the image")
suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers") suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image") 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 {
flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container") flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
ulimits := make(map[string]*ulimit.Ulimit) ulimits := make(map[string]*ulimit.Ulimit)
flUlimits := opts.NewUlimitOpt(ulimits) flUlimits := opts.NewUlimitOpt(&ulimits)
cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options") cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options")
cmd.Require(flag.Exact, 1) cmd.Require(flag.Exact, 1)
@ -325,7 +326,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
if jerr.Code == 0 { if jerr.Code == 0 {
jerr.Code = 1 jerr.Code = 1
} }
return StatusError{Status: jerr.Message, StatusCode: jerr.Code} return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
} }
return err return err
} }

View file

@ -2,25 +2,28 @@ package client
import ( import (
"crypto/tls" "crypto/tls"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"reflect" "os"
"strings" "strings"
"text/template"
"github.com/docker/docker/cli"
"github.com/docker/docker/cliconfig" "github.com/docker/docker/cliconfig"
flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/opts"
"github.com/docker/docker/pkg/sockets" "github.com/docker/docker/pkg/sockets"
"github.com/docker/docker/pkg/term" "github.com/docker/docker/pkg/term"
"github.com/docker/docker/pkg/tlsconfig"
) )
// DockerCli represents the docker command line client. // DockerCli represents the docker command line client.
// Instances of the client can be returned from NewDockerCli. // Instances of the client can be returned from NewDockerCli.
type DockerCli struct { type DockerCli struct {
// initializing closure
init func() error
// proto holds the client protocol i.e. unix. // proto holds the client protocol i.e. unix.
proto string proto string
// addr holds the client address. // addr holds the client address.
@ -55,116 +58,11 @@ type DockerCli struct {
transport *http.Transport transport *http.Transport
} }
var funcMap = template.FuncMap{ func (cli *DockerCli) Initialize() error {
"json": func(v interface{}) string { if cli.init == nil {
a, _ := json.Marshal(v) return nil
return string(a)
},
}
func (cli *DockerCli) Out() io.Writer {
return cli.out
}
func (cli *DockerCli) Err() io.Writer {
return cli.err
}
func (cli *DockerCli) getMethod(args ...string) (func(...string) error, bool) {
camelArgs := make([]string, len(args))
for i, s := range args {
if len(s) == 0 {
return nil, false
}
camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:])
} }
methodName := "Cmd" + strings.Join(camelArgs, "") return cli.init()
method := reflect.ValueOf(cli).MethodByName(methodName)
if !method.IsValid() {
return nil, false
}
return method.Interface().(func(...string) error), true
}
// Cmd executes the specified command.
func (cli *DockerCli) Cmd(args ...string) error {
if len(args) > 1 {
method, exists := cli.getMethod(args[:2]...)
if exists {
return method(args[2:]...)
}
}
if len(args) > 0 {
method, exists := cli.getMethod(args[0])
if !exists {
return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
}
return method(args[1:]...)
}
return cli.CmdHelp()
}
// Subcmd is a subcommand of the main "docker" command.
// A subcommand represents an action that can be performed
// from the Docker command line client.
//
// Multiple subcommand synopses may be provided with one 'Usage' line being
// printed for each in the following way:
//
// Usage: docker <subcmd-name> [OPTIONS] <synopsis 0>
// docker <subcmd-name> [OPTIONS] <synopsis 1>
// ...
//
// If no undeprecated flags are added to the returned FlagSet, "[OPTIONS]" will
// not be included on the usage synopsis lines. If no synopses are given, only
// one usage synopsis line will be printed with nothing following the
// "[OPTIONS]" section
//
// To see all available subcommands, run "docker --help".
func (cli *DockerCli) Subcmd(name string, synopses []string, description string, exitOnError bool) *flag.FlagSet {
var errorHandling flag.ErrorHandling
if exitOnError {
errorHandling = flag.ExitOnError
} else {
errorHandling = flag.ContinueOnError
}
flags := flag.NewFlagSet(name, errorHandling)
flags.Usage = func() {
flags.ShortUsage()
flags.PrintDefaults()
}
flags.ShortUsage = func() {
options := ""
if flags.FlagCountUndeprecated() > 0 {
options = " [OPTIONS]"
}
if len(synopses) == 0 {
synopses = []string{""}
}
// Allow for multiple command usage synopses.
for i, synopsis := range synopses {
lead := "\t"
if i == 0 {
// First line needs the word 'Usage'.
lead = "Usage:\t"
}
if synopsis != "" {
synopsis = " " + synopsis
}
fmt.Fprintf(flags.Out(), "\n%sdocker %s%s%s", lead, name, options, synopsis)
}
fmt.Fprintf(flags.Out(), "\n\n%s\n", description)
}
return flags
} }
// CheckTtyInput checks if we are trying to attach to a container tty // CheckTtyInput checks if we are trying to attach to a container tty
@ -187,64 +85,78 @@ func (cli *DockerCli) PsFormat() string {
// The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config
// is set the client scheme will be set to https. // is set the client scheme will be set to https.
// The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035).
func NewDockerCli(in io.ReadCloser, out, err io.Writer, keyFile string, proto, addr string, tlsConfig *tls.Config) *DockerCli { func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli {
var ( cli := &DockerCli{
inFd uintptr in: in,
outFd uintptr out: out,
isTerminalIn = false err: err,
isTerminalOut = false keyFile: clientFlags.Common.TrustKey,
scheme = "http"
basePath = ""
)
if tlsConfig != nil {
scheme = "https"
}
if in != nil {
inFd, isTerminalIn = term.GetFdInfo(in)
} }
if out != nil { cli.init = func() error {
outFd, isTerminalOut = term.GetFdInfo(out) clientFlags.PostParse()
hosts := clientFlags.Common.Hosts
switch len(hosts) {
case 0:
defaultHost := os.Getenv("DOCKER_HOST")
if defaultHost == "" {
defaultHost = opts.DefaultHost
}
defaultHost, err := opts.ValidateHost(defaultHost)
if err != nil {
return err
}
hosts = []string{defaultHost}
case 1:
// only accept one host to talk to
default:
return errors.New("Please specify only one -H")
}
protoAddrParts := strings.SplitN(hosts[0], "://", 2)
cli.proto, cli.addr = protoAddrParts[0], protoAddrParts[1]
if cli.proto == "tcp" {
// error is checked in pkg/parsers already
parsed, _ := url.Parse("tcp://" + cli.addr)
cli.addr = parsed.Host
cli.basePath = parsed.Path
}
if clientFlags.Common.TLSOptions != nil {
cli.scheme = "https"
var e error
cli.tlsConfig, e = tlsconfig.Client(*clientFlags.Common.TLSOptions)
if e != nil {
return e
}
} else {
cli.scheme = "http"
}
if cli.in != nil {
cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in)
}
if cli.out != nil {
cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out)
}
// The transport is created here for reuse during the client session.
cli.transport = &http.Transport{
TLSClientConfig: cli.tlsConfig,
}
sockets.ConfigureTCPTransport(cli.transport, cli.proto, cli.addr)
configFile, e := cliconfig.Load(cliconfig.ConfigDir())
if e != nil {
fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e)
}
cli.configFile = configFile
return nil
} }
if err == nil { return cli
err = out
}
// The transport is created here for reuse during the client session.
tr := &http.Transport{
TLSClientConfig: tlsConfig,
}
sockets.ConfigureTCPTransport(tr, proto, addr)
configFile, e := cliconfig.Load(cliconfig.ConfigDir())
if e != nil {
fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e)
}
if proto == "tcp" {
// error is checked in pkg/parsers already
parsed, _ := url.Parse("tcp://" + addr)
addr = parsed.Host
basePath = parsed.Path
}
return &DockerCli{
proto: proto,
addr: addr,
basePath: basePath,
configFile: configFile,
in: in,
out: out,
err: err,
keyFile: keyFile,
inFd: inFd,
outFd: outFd,
isTerminalIn: isTerminalIn,
isTerminalOut: isTerminalOut,
tlsConfig: tlsConfig,
scheme: scheme,
transport: tr,
}
} }

View file

@ -3,15 +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. // 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.
// See https://docs.docker.com/installation/ for instructions on installing Docker. // See https://docs.docker.com/installation/ for instructions on installing Docker.
package client package client
import "fmt"
// An StatusError reports an unsuccessful exit by a command.
type StatusError struct {
Status string
StatusCode int
}
func (e StatusError) Error() string {
return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
}

View file

@ -6,6 +6,7 @@ import (
"net/url" "net/url"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
@ -17,7 +18,7 @@ import (
// //
// Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] // Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
func (cli *DockerCli) CmdCommit(args ...string) error { func (cli *DockerCli) CmdCommit(args ...string) error {
cmd := cli.Subcmd("commit", []string{"CONTAINER [REPOSITORY[:TAG]]"}, "Create a new image from a container's changes", true) cmd := Cli.Subcmd("commit", []string{"CONTAINER [REPOSITORY[:TAG]]"}, "Create a new image from a container's changes", true)
flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit") flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
flComment := cmd.String([]string{"m", "-message"}, "", "Commit message") flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")") flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")

View file

@ -12,6 +12,7 @@ import (
"strings" "strings"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -37,7 +38,7 @@ const (
// docker cp CONTAINER:PATH LOCALPATH|- // docker cp CONTAINER:PATH LOCALPATH|-
// docker cp LOCALPATH|- CONTAINER:PATH // docker cp LOCALPATH|- CONTAINER:PATH
func (cli *DockerCli) CmdCp(args ...string) error { func (cli *DockerCli) CmdCp(args ...string) error {
cmd := cli.Subcmd( cmd := Cli.Subcmd(
"cp", "cp",
[]string{"CONTAINER:PATH LOCALPATH|-", "LOCALPATH|- CONTAINER:PATH"}, []string{"CONTAINER:PATH LOCALPATH|-", "LOCALPATH|- CONTAINER:PATH"},
strings.Join([]string{ strings.Join([]string{

View file

@ -10,6 +10,7 @@ import (
"strings" "strings"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/graph/tags" "github.com/docker/docker/graph/tags"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
@ -137,7 +138,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
// //
// Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...] // Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
func (cli *DockerCli) CmdCreate(args ...string) error { func (cli *DockerCli) CmdCreate(args ...string) error {
cmd := cli.Subcmd("create", []string{"IMAGE [COMMAND] [ARG...]"}, "Create a new container", true) cmd := Cli.Subcmd("create", []string{"IMAGE [COMMAND] [ARG...]"}, "Create a new container", true)
// These are flags not stored in Config/HostConfig // These are flags not stored in Config/HostConfig
var ( var (

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -17,7 +18,7 @@ import (
// //
// Usage: docker diff CONTAINER // Usage: docker diff CONTAINER
func (cli *DockerCli) CmdDiff(args ...string) error { func (cli *DockerCli) CmdDiff(args ...string) error {
cmd := cli.Subcmd("diff", []string{"CONTAINER"}, "Inspect changes on a container's filesystem", true) cmd := Cli.Subcmd("diff", []string{"CONTAINER"}, "Inspect changes on a container's filesystem", true)
cmd.Require(flag.Exact, 1) cmd.Require(flag.Exact, 1)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

View file

@ -4,6 +4,7 @@ import (
"net/url" "net/url"
"time" "time"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers/filters" "github.com/docker/docker/pkg/parsers/filters"
@ -14,7 +15,7 @@ import (
// //
// Usage: docker events [OPTIONS] // Usage: docker events [OPTIONS]
func (cli *DockerCli) CmdEvents(args ...string) error { func (cli *DockerCli) CmdEvents(args ...string) error {
cmd := cli.Subcmd("events", nil, "Get real time events from the server", true) cmd := Cli.Subcmd("events", nil, "Get real time events from the server", true)
since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp") since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp") until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
flFilter := opts.NewListOpts(nil) flFilter := opts.NewListOpts(nil)

View file

@ -7,6 +7,7 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/promise"
"github.com/docker/docker/runconfig" "github.com/docker/docker/runconfig"
) )
@ -15,12 +16,12 @@ import (
// //
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] // Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
func (cli *DockerCli) CmdExec(args ...string) error { func (cli *DockerCli) CmdExec(args ...string) error {
cmd := cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, "Run a command in a running container", true) cmd := Cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, "Run a command in a running container", true)
execConfig, err := runconfig.ParseExec(cmd, args) execConfig, err := runconfig.ParseExec(cmd, args)
// just in case the ParseExec does not exit // just in case the ParseExec does not exit
if execConfig.Container == "" || err != nil { if execConfig.Container == "" || err != nil {
return StatusError{StatusCode: 1} return Cli.StatusError{StatusCode: 1}
} }
serverResp, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, nil) serverResp, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, nil)
@ -126,7 +127,7 @@ func (cli *DockerCli) CmdExec(args ...string) error {
} }
if status != 0 { if status != 0 {
return StatusError{StatusCode: status} return Cli.StatusError{StatusCode: status}
} }
return nil return nil

View file

@ -5,6 +5,7 @@ import (
"io" "io"
"os" "os"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -14,7 +15,7 @@ import (
// //
// Usage: docker export [OPTIONS] CONTAINER // Usage: docker export [OPTIONS] CONTAINER
func (cli *DockerCli) CmdExport(args ...string) error { func (cli *DockerCli) CmdExport(args ...string) error {
cmd := cli.Subcmd("export", []string{"CONTAINER"}, "Export the contents of a container's filesystem as a tar archive", true) cmd := Cli.Subcmd("export", []string{"CONTAINER"}, "Export the contents of a container's filesystem as a tar archive", true)
outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT") outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
cmd.Require(flag.Exact, 1) cmd.Require(flag.Exact, 1)

View file

@ -1,34 +0,0 @@
package client
import (
"fmt"
flag "github.com/docker/docker/pkg/mflag"
)
// CmdHelp displays information on a Docker command.
//
// If more than one command is specified, information is only shown for the first command.
//
// Usage: docker help COMMAND or docker COMMAND --help
func (cli *DockerCli) CmdHelp(args ...string) error {
if len(args) > 1 {
method, exists := cli.getMethod(args[:2]...)
if exists {
method("--help")
return nil
}
}
if len(args) > 0 {
method, exists := cli.getMethod(args[0])
if !exists {
return fmt.Errorf("docker: '%s' is not a docker command. See 'docker --help'.", args[0])
}
method("--help")
return nil
}
flag.Usage()
return nil
}

View file

@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/pkg/stringutils"
@ -17,7 +18,7 @@ import (
// //
// Usage: docker history [OPTIONS] IMAGE // Usage: docker history [OPTIONS] IMAGE
func (cli *DockerCli) CmdHistory(args ...string) error { func (cli *DockerCli) CmdHistory(args ...string) error {
cmd := cli.Subcmd("history", []string{"IMAGE"}, "Show the history of an image", true) cmd := Cli.Subcmd("history", []string{"IMAGE"}, "Show the history of an image", true)
human := cmd.Bool([]string{"H", "-human"}, true, "Print sizes and dates in human readable format") human := cmd.Bool([]string{"H", "-human"}, true, "Print sizes and dates in human readable format")
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs") quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output") noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")

View file

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
@ -21,7 +22,7 @@ import (
// //
// Usage: docker images [OPTIONS] [REPOSITORY] // Usage: docker images [OPTIONS] [REPOSITORY]
func (cli *DockerCli) CmdImages(args ...string) error { func (cli *DockerCli) CmdImages(args ...string) error {
cmd := cli.Subcmd("images", []string{"[REPOSITORY]"}, "List images", true) cmd := Cli.Subcmd("images", []string{"[REPOSITORY]"}, "List images", true)
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs") quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)") all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)")
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output") noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")

View file

@ -6,6 +6,7 @@ import (
"net/url" "net/url"
"os" "os"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
@ -19,7 +20,7 @@ import (
// //
// Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] // Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
func (cli *DockerCli) CmdImport(args ...string) error { func (cli *DockerCli) CmdImport(args ...string) error {
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) 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)
flChanges := opts.NewListOpts(nil) flChanges := opts.NewListOpts(nil)
cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image") cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/pkg/httputils" "github.com/docker/docker/pkg/httputils"
"github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/ioutils"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
@ -15,7 +16,7 @@ import (
// //
// Usage: docker info // Usage: docker info
func (cli *DockerCli) CmdInfo(args ...string) error { func (cli *DockerCli) CmdInfo(args ...string) error {
cmd := cli.Subcmd("info", nil, "Display system-wide information", true) cmd := Cli.Subcmd("info", nil, "Display system-wide information", true)
cmd.Require(flag.Exact, 0) cmd.Require(flag.Exact, 0)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

View file

@ -9,14 +9,22 @@ import (
"text/template" "text/template"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
var funcMap = template.FuncMap{
"json": func(v interface{}) string {
a, _ := json.Marshal(v)
return string(a)
},
}
// CmdInspect displays low-level information on one or more containers or images. // CmdInspect displays low-level information on one or more containers or images.
// //
// Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...] // Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]
func (cli *DockerCli) CmdInspect(args ...string) error { func (cli *DockerCli) CmdInspect(args ...string) error {
cmd := cli.Subcmd("inspect", []string{"CONTAINER|IMAGE [CONTAINER|IMAGE...]"}, "Return low-level information on a container or image", true) cmd := Cli.Subcmd("inspect", []string{"CONTAINER|IMAGE [CONTAINER|IMAGE...]"}, "Return low-level information on a container or image", true)
tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template") tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template")
inspectType := cmd.String([]string{"-type"}, "", "Return JSON for specified type, (e.g image or container)") inspectType := cmd.String([]string{"-type"}, "", "Return JSON for specified type, (e.g image or container)")
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)
@ -29,7 +37,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
if *tmplStr != "" { if *tmplStr != "" {
if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil { if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
return StatusError{StatusCode: 64, return Cli.StatusError{StatusCode: 64,
Status: "Template parsing error: " + err.Error()} Status: "Template parsing error: " + err.Error()}
} }
} }
@ -143,7 +151,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
} }
if status != 0 { if status != 0 {
return StatusError{StatusCode: status} return Cli.StatusError{StatusCode: status}
} }
return nil return nil
} }

View file

@ -3,6 +3,7 @@ package client
import ( import (
"fmt" "fmt"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -10,7 +11,7 @@ import (
// //
// Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...] // Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdKill(args ...string) error { func (cli *DockerCli) CmdKill(args ...string) error {
cmd := cli.Subcmd("kill", []string{"CONTAINER [CONTAINER...]"}, "Kill a running container using SIGKILL or a specified signal", true) cmd := Cli.Subcmd("kill", []string{"CONTAINER [CONTAINER...]"}, "Kill a running container using SIGKILL or a specified signal", true)
signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container") signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)

View file

@ -4,6 +4,7 @@ import (
"io" "io"
"os" "os"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -13,7 +14,7 @@ import (
// //
// Usage: docker load [OPTIONS] // Usage: docker load [OPTIONS]
func (cli *DockerCli) CmdLoad(args ...string) error { func (cli *DockerCli) CmdLoad(args ...string) error {
cmd := cli.Subcmd("load", nil, "Load an image from a tar archive or STDIN", true) cmd := Cli.Subcmd("load", nil, "Load an image from a tar archive or STDIN", true)
infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN") infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
cmd.Require(flag.Exact, 0) cmd.Require(flag.Exact, 0)

View file

@ -9,6 +9,7 @@ import (
"strings" "strings"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/cliconfig" "github.com/docker/docker/cliconfig"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/term" "github.com/docker/docker/pkg/term"
@ -21,7 +22,7 @@ import (
// //
// Usage: docker login SERVER // Usage: docker login SERVER
func (cli *DockerCli) CmdLogin(args ...string) error { func (cli *DockerCli) CmdLogin(args ...string) error {
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) 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)
cmd.Require(flag.Max, 1) cmd.Require(flag.Max, 1)
var username, password, email string var username, password, email string

View file

@ -3,6 +3,7 @@ package client
import ( import (
"fmt" "fmt"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
) )
@ -13,7 +14,7 @@ import (
// //
// Usage: docker logout [SERVER] // Usage: docker logout [SERVER]
func (cli *DockerCli) CmdLogout(args ...string) error { func (cli *DockerCli) CmdLogout(args ...string) error {
cmd := cli.Subcmd("logout", []string{"[SERVER]"}, "Log out from a Docker registry, if no server is\nspecified \""+registry.INDEXSERVER+"\" is the default.", true) cmd := Cli.Subcmd("logout", []string{"[SERVER]"}, "Log out from a Docker registry, if no server is\nspecified \""+registry.INDEXSERVER+"\" is the default.", true)
cmd.Require(flag.Max, 1) cmd.Require(flag.Max, 1)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

View file

@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/timeutils" "github.com/docker/docker/pkg/timeutils"
) )
@ -15,7 +16,7 @@ import (
// //
// docker logs [OPTIONS] CONTAINER // docker logs [OPTIONS] CONTAINER
func (cli *DockerCli) CmdLogs(args ...string) error { func (cli *DockerCli) CmdLogs(args ...string) error {
cmd := cli.Subcmd("logs", []string{"CONTAINER"}, "Fetch the logs of a container", true) cmd := Cli.Subcmd("logs", []string{"CONTAINER"}, "Fetch the logs of a container", true)
follow := cmd.Bool([]string{"f", "-follow"}, false, "Follow log output") follow := cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
since := cmd.String([]string{"-since"}, "", "Show logs since timestamp") since := cmd.String([]string{"-since"}, "", "Show logs since timestamp")
times := cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps") times := cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")

View file

@ -3,6 +3,7 @@ package client
import ( import (
"fmt" "fmt"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -10,7 +11,7 @@ import (
// //
// Usage: docker pause CONTAINER [CONTAINER...] // Usage: docker pause CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdPause(args ...string) error { func (cli *DockerCli) CmdPause(args ...string) error {
cmd := cli.Subcmd("pause", []string{"CONTAINER [CONTAINER...]"}, "Pause all processes within a container", true) cmd := Cli.Subcmd("pause", []string{"CONTAINER [CONTAINER...]"}, "Pause all processes within a container", true)
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"strings" "strings"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat" "github.com/docker/docker/pkg/nat"
) )
@ -14,7 +15,7 @@ import (
// //
// Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]] // Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]]
func (cli *DockerCli) CmdPort(args ...string) error { func (cli *DockerCli) CmdPort(args ...string) error {
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) 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)
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

View file

@ -7,6 +7,7 @@ import (
"github.com/docker/docker/api/client/ps" "github.com/docker/docker/api/client/ps"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers/filters" "github.com/docker/docker/pkg/parsers/filters"
@ -22,7 +23,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
psFilterArgs = filters.Args{} psFilterArgs = filters.Args{}
v = url.Values{} v = url.Values{}
cmd = cli.Subcmd("ps", nil, "List containers", true) cmd = Cli.Subcmd("ps", nil, "List containers", true)
quiet = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs") quiet = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
size = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes") size = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
all = cmd.Bool([]string{"a", "-all"}, false, "Show all containers (default shows just running)") all = cmd.Bool([]string{"a", "-all"}, false, "Show all containers (default shows just running)")

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"net/url" "net/url"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/graph/tags" "github.com/docker/docker/graph/tags"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
@ -15,7 +16,7 @@ import (
// //
// Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST] // Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST]
func (cli *DockerCli) CmdPull(args ...string) error { func (cli *DockerCli) CmdPull(args ...string) error {
cmd := cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, "Pull an image or a repository from a registry", true) cmd := Cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, "Pull an image or a repository from a registry", true)
allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository") allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
cmd.Require(flag.Exact, 1) cmd.Require(flag.Exact, 1)

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"net/url" "net/url"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
@ -13,7 +14,7 @@ import (
// //
// Usage: docker push NAME[:TAG] // Usage: docker push NAME[:TAG]
func (cli *DockerCli) CmdPush(args ...string) error { func (cli *DockerCli) CmdPush(args ...string) error {
cmd := cli.Subcmd("push", []string{"NAME[:TAG]"}, "Push an image or a repository to a registry", true) cmd := Cli.Subcmd("push", []string{"NAME[:TAG]"}, "Push an image or a repository to a registry", true)
cmd.Require(flag.Exact, 1) cmd.Require(flag.Exact, 1)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

View file

@ -3,6 +3,7 @@ package client
import ( import (
"fmt" "fmt"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -10,7 +11,7 @@ import (
// //
// Usage: docker rename OLD_NAME NEW_NAME // Usage: docker rename OLD_NAME NEW_NAME
func (cli *DockerCli) CmdRename(args ...string) error { func (cli *DockerCli) CmdRename(args ...string) error {
cmd := cli.Subcmd("rename", []string{"OLD_NAME NEW_NAME"}, "Rename a container", true) cmd := Cli.Subcmd("rename", []string{"OLD_NAME NEW_NAME"}, "Rename a container", true)
cmd.Require(flag.Exact, 2) cmd.Require(flag.Exact, 2)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

View file

@ -5,6 +5,7 @@ import (
"net/url" "net/url"
"strconv" "strconv"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -12,7 +13,7 @@ import (
// //
// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...] // Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdRestart(args ...string) error { func (cli *DockerCli) CmdRestart(args ...string) error {
cmd := cli.Subcmd("restart", []string{"CONTAINER [CONTAINER...]"}, "Restart a running container", true) cmd := Cli.Subcmd("restart", []string{"CONTAINER [CONTAINER...]"}, "Restart a running container", true)
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container") nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container")
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)

View file

@ -5,6 +5,7 @@ import (
"net/url" "net/url"
"strings" "strings"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -12,7 +13,7 @@ import (
// //
// Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...] // Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdRm(args ...string) error { func (cli *DockerCli) CmdRm(args ...string) error {
cmd := cli.Subcmd("rm", []string{"CONTAINER [CONTAINER...]"}, "Remove one or more containers", true) cmd := Cli.Subcmd("rm", []string{"CONTAINER [CONTAINER...]"}, "Remove one or more containers", true)
v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container") v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link") link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link")
force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)") force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")

View file

@ -6,6 +6,7 @@ import (
"net/url" "net/url"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -13,7 +14,7 @@ import (
// //
// Usage: docker rmi [OPTIONS] IMAGE [IMAGE...] // Usage: docker rmi [OPTIONS] IMAGE [IMAGE...]
func (cli *DockerCli) CmdRmi(args ...string) error { func (cli *DockerCli) CmdRmi(args ...string) error {
cmd := cli.Subcmd("rmi", []string{"IMAGE [IMAGE...]"}, "Remove one or more images", true) cmd := Cli.Subcmd("rmi", []string{"IMAGE [IMAGE...]"}, "Remove one or more images", true)
force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image") force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
noprune := cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents") noprune := cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)

View file

@ -8,6 +8,7 @@ import (
"runtime" "runtime"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
"github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/promise"
"github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/signal"
@ -39,7 +40,7 @@ func (cid *cidFile) Write(id string) error {
// //
// Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] // Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
func (cli *DockerCli) CmdRun(args ...string) error { func (cli *DockerCli) CmdRun(args ...string) error {
cmd := cli.Subcmd("run", []string{"IMAGE [COMMAND] [ARG...]"}, "Run a command in a new container", true) cmd := Cli.Subcmd("run", []string{"IMAGE [COMMAND] [ARG...]"}, "Run a command in a new container", true)
// These are flags not stored in Config/HostConfig // These are flags not stored in Config/HostConfig
var ( var (
@ -249,7 +250,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
} }
} }
if status != 0 { if status != 0 {
return StatusError{StatusCode: status} return Cli.StatusError{StatusCode: status}
} }
return nil return nil
} }

View file

@ -6,6 +6,7 @@ import (
"net/url" "net/url"
"os" "os"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -15,7 +16,7 @@ import (
// //
// Usage: docker save [OPTIONS] IMAGE [IMAGE...] // Usage: docker save [OPTIONS] IMAGE [IMAGE...]
func (cli *DockerCli) CmdSave(args ...string) error { func (cli *DockerCli) CmdSave(args ...string) error {
cmd := cli.Subcmd("save", []string{"IMAGE [IMAGE...]"}, "Save an image(s) to a tar archive (streamed to STDOUT by default)", true) cmd := Cli.Subcmd("save", []string{"IMAGE [IMAGE...]"}, "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT") outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)

View file

@ -8,6 +8,7 @@ import (
"strings" "strings"
"text/tabwriter" "text/tabwriter"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/stringutils" "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 }
// //
// Usage: docker search [OPTIONS] TERM // Usage: docker search [OPTIONS] TERM
func (cli *DockerCli) CmdSearch(args ...string) error { func (cli *DockerCli) CmdSearch(args ...string) error {
cmd := cli.Subcmd("search", []string{"TERM"}, "Search the Docker Hub for images", true) cmd := Cli.Subcmd("search", []string{"TERM"}, "Search the Docker Hub for images", true)
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output") noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds") trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds") automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")

View file

@ -9,6 +9,7 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/promise"
"github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/signal"
@ -44,7 +45,7 @@ func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
// //
// Usage: docker start [OPTIONS] CONTAINER [CONTAINER...] // Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdStart(args ...string) error { func (cli *DockerCli) CmdStart(args ...string) error {
cmd := cli.Subcmd("start", []string{"CONTAINER [CONTAINER...]"}, "Start one or more stopped containers", true) cmd := Cli.Subcmd("start", []string{"CONTAINER [CONTAINER...]"}, "Start one or more stopped containers", true)
attach := cmd.Bool([]string{"a", "-attach"}, false, "Attach STDOUT/STDERR and forward signals") attach := cmd.Bool([]string{"a", "-attach"}, false, "Attach STDOUT/STDERR and forward signals")
openStdin := cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN") openStdin := cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)
@ -162,7 +163,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
return err return err
} }
if status != 0 { if status != 0 {
return StatusError{StatusCode: status} return Cli.StatusError{StatusCode: status}
} }
} }
return nil return nil

View file

@ -12,6 +12,7 @@ import (
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/units" "github.com/docker/docker/pkg/units"
) )
@ -124,7 +125,7 @@ func (s *containerStats) Display(w io.Writer) error {
// //
// Usage: docker stats CONTAINER [CONTAINER...] // Usage: docker stats CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdStats(args ...string) error { func (cli *DockerCli) CmdStats(args ...string) error {
cmd := cli.Subcmd("stats", []string{"CONTAINER [CONTAINER...]"}, "Display a live stream of one or more containers' resource usage statistics", true) cmd := Cli.Subcmd("stats", []string{"CONTAINER [CONTAINER...]"}, "Display a live stream of one or more containers' resource usage statistics", true)
noStream := cmd.Bool([]string{"-no-stream"}, false, "Disable streaming stats and only pull the first result") noStream := cmd.Bool([]string{"-no-stream"}, false, "Disable streaming stats and only pull the first result")
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)

View file

@ -5,6 +5,7 @@ import (
"net/url" "net/url"
"strconv" "strconv"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -14,7 +15,7 @@ import (
// //
// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...] // Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdStop(args ...string) error { func (cli *DockerCli) CmdStop(args ...string) error {
cmd := cli.Subcmd("stop", []string{"CONTAINER [CONTAINER...]"}, "Stop a running container by sending SIGTERM and then SIGKILL after a\ngrace period", true) cmd := Cli.Subcmd("stop", []string{"CONTAINER [CONTAINER...]"}, "Stop a running container by sending SIGTERM and then SIGKILL after a\ngrace period", true)
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing it") nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing it")
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)

View file

@ -3,6 +3,7 @@ package client
import ( import (
"net/url" "net/url"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
@ -12,7 +13,7 @@ import (
// //
// Usage: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG] // Usage: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
func (cli *DockerCli) CmdTag(args ...string) error { func (cli *DockerCli) CmdTag(args ...string) error {
cmd := cli.Subcmd("tag", []string{"IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]"}, "Tag an image into a repository", true) cmd := Cli.Subcmd("tag", []string{"IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]"}, "Tag an image into a repository", true)
force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force") force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
cmd.Require(flag.Exact, 2) cmd.Require(flag.Exact, 2)

View file

@ -8,6 +8,7 @@ import (
"text/tabwriter" "text/tabwriter"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -15,7 +16,7 @@ import (
// //
// Usage: docker top CONTAINER // Usage: docker top CONTAINER
func (cli *DockerCli) CmdTop(args ...string) error { func (cli *DockerCli) CmdTop(args ...string) error {
cmd := cli.Subcmd("top", []string{"CONTAINER [ps OPTIONS]"}, "Display the running processes of a container", true) cmd := Cli.Subcmd("top", []string{"CONTAINER [ps OPTIONS]"}, "Display the running processes of a container", true)
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

View file

@ -3,6 +3,7 @@ package client
import ( import (
"fmt" "fmt"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -10,7 +11,7 @@ import (
// //
// Usage: docker unpause CONTAINER [CONTAINER...] // Usage: docker unpause CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdUnpause(args ...string) error { func (cli *DockerCli) CmdUnpause(args ...string) error {
cmd := cli.Subcmd("unpause", []string{"CONTAINER [CONTAINER...]"}, "Unpause all processes within a container", true) cmd := Cli.Subcmd("unpause", []string{"CONTAINER [CONTAINER...]"}, "Unpause all processes within a container", true)
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

View file

@ -8,6 +8,7 @@ import (
"github.com/docker/docker/api" "github.com/docker/docker/api"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/autogen/dockerversion" "github.com/docker/docker/autogen/dockerversion"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/utils" "github.com/docker/docker/utils"
) )
@ -42,7 +43,7 @@ type VersionData struct {
// //
// Usage: docker version // Usage: docker version
func (cli *DockerCli) CmdVersion(args ...string) (err error) { func (cli *DockerCli) CmdVersion(args ...string) (err error) {
cmd := cli.Subcmd("version", nil, "Show the Docker version information.", true) cmd := Cli.Subcmd("version", nil, "Show the Docker version information.", true)
tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template") tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template")
cmd.Require(flag.Exact, 0) cmd.Require(flag.Exact, 0)
@ -53,7 +54,7 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
var tmpl *template.Template var tmpl *template.Template
if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil { if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
return StatusError{StatusCode: 64, return Cli.StatusError{StatusCode: 64,
Status: "Template parsing error: " + err.Error()} Status: "Template parsing error: " + err.Error()}
} }
@ -85,7 +86,7 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
defer serverResp.body.Close() defer serverResp.body.Close()
if err = json.NewDecoder(serverResp.body).Decode(&vd.Server); err != nil { if err = json.NewDecoder(serverResp.body).Decode(&vd.Server); err != nil {
return StatusError{StatusCode: 1, return Cli.StatusError{StatusCode: 1,
Status: "Error reading remote version: " + err.Error()} Status: "Error reading remote version: " + err.Error()}
} }

View file

@ -3,6 +3,7 @@ package client
import ( import (
"fmt" "fmt"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -12,7 +13,7 @@ import (
// //
// Usage: docker wait CONTAINER [CONTAINER...] // Usage: docker wait CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdWait(args ...string) error { func (cli *DockerCli) CmdWait(args ...string) error {
cmd := cli.Subcmd("wait", []string{"CONTAINER [CONTAINER...]"}, "Block until a container stops, then print its exit code.", true) cmd := Cli.Subcmd("wait", []string{"CONTAINER [CONTAINER...]"}, "Block until a container stops, then print its exit code.", true)
cmd.Require(flag.Min, 1) cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)

200
cli/cli.go Normal file
View file

@ -0,0 +1,200 @@
package cli
import (
"errors"
"fmt"
"io"
"os"
"reflect"
"strings"
flag "github.com/docker/docker/pkg/mflag"
)
// Cli represents a command line interface.
type Cli struct {
Stderr io.Writer
handlers []Handler
Usage func()
}
// Handler holds the different commands Cli will call
// It should have methods with names starting with `Cmd` like:
// func (h myHandler) CmdFoo(args ...string) error
type Handler interface{}
// Initializer can be optionally implemented by a Handler to
// initialize before each call to one of its commands.
type Initializer interface {
Initialize() error
}
// New instantiates a ready-to-use Cli.
func New(handlers ...Handler) *Cli {
// make the generic Cli object the first cli handler
// in order to handle `docker help` appropriately
cli := new(Cli)
cli.handlers = append([]Handler{cli}, handlers...)
return cli
}
// initErr is an error returned upon initialization of a handler implementing Initializer.
type initErr struct{ error }
func (err initErr) Error() string {
return err.Error()
}
func (cli *Cli) command(args ...string) (func(...string) error, error) {
for _, c := range cli.handlers {
if c == nil {
continue
}
camelArgs := make([]string, len(args))
for i, s := range args {
if len(s) == 0 {
return nil, errors.New("empty command")
}
camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:])
}
methodName := "Cmd" + strings.Join(camelArgs, "")
method := reflect.ValueOf(c).MethodByName(methodName)
if method.IsValid() {
if c, ok := c.(Initializer); ok {
if err := c.Initialize(); err != nil {
return nil, initErr{err}
}
}
return method.Interface().(func(...string) error), nil
}
}
return nil, errors.New("command not found")
}
// Run executes the specified command.
func (cli *Cli) Run(args ...string) error {
if len(args) > 1 {
command, err := cli.command(args[:2]...)
switch err := err.(type) {
case nil:
return command(args[2:]...)
case initErr:
return err.error
}
}
if len(args) > 0 {
command, err := cli.command(args[0])
switch err := err.(type) {
case nil:
return command(args[1:]...)
case initErr:
return err.error
}
cli.noSuchCommand(args[0])
}
return cli.CmdHelp()
}
func (cli *Cli) noSuchCommand(command string) {
if cli.Stderr == nil {
cli.Stderr = os.Stderr
}
fmt.Fprintf(cli.Stderr, "docker: '%s' is not a docker command.\nSee 'docker --help'.\n", command)
os.Exit(1)
}
// CmdHelp displays information on a Docker command.
//
// If more than one command is specified, information is only shown for the first command.
//
// Usage: docker help COMMAND or docker COMMAND --help
func (cli *Cli) CmdHelp(args ...string) error {
if len(args) > 1 {
command, err := cli.command(args[:2]...)
switch err := err.(type) {
case nil:
command("--help")
return nil
case initErr:
return err.error
}
}
if len(args) > 0 {
command, err := cli.command(args[0])
switch err := err.(type) {
case nil:
command("--help")
return nil
case initErr:
return err.error
}
cli.noSuchCommand(args[0])
}
if cli.Usage == nil {
flag.Usage()
} else {
cli.Usage()
}
return nil
}
// Subcmd is a subcommand of the main "docker" command.
// A subcommand represents an action that can be performed
// from the Docker command line client.
//
// To see all available subcommands, run "docker --help".
func Subcmd(name string, synopses []string, description string, exitOnError bool) *flag.FlagSet {
var errorHandling flag.ErrorHandling
if exitOnError {
errorHandling = flag.ExitOnError
} else {
errorHandling = flag.ContinueOnError
}
flags := flag.NewFlagSet(name, errorHandling)
flags.Usage = func() {
flags.ShortUsage()
flags.PrintDefaults()
}
flags.ShortUsage = func() {
options := ""
if flags.FlagCountUndeprecated() > 0 {
options = " [OPTIONS]"
}
if len(synopses) == 0 {
synopses = []string{""}
}
// Allow for multiple command usage synopses.
for i, synopsis := range synopses {
lead := "\t"
if i == 0 {
// First line needs the word 'Usage'.
lead = "Usage:\t"
}
if synopsis != "" {
synopsis = " " + synopsis
}
fmt.Fprintf(flags.Out(), "\n%sdocker %s%s%s", lead, name, options, synopsis)
}
fmt.Fprintf(flags.Out(), "\n\n%s\n", description)
}
return flags
}
// An StatusError reports an unsuccessful exit by a command.
type StatusError struct {
Status string
StatusCode int
}
func (e StatusError) Error() string {
return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
}

12
cli/client.go Normal file
View file

@ -0,0 +1,12 @@
package cli
import flag "github.com/docker/docker/pkg/mflag"
// ClientFlags represents flags for the docker client.
type ClientFlags struct {
FlagSet *flag.FlagSet
Common *CommonFlags
PostParse func()
ConfigDir string
}

20
cli/common.go Normal file
View file

@ -0,0 +1,20 @@
package cli
import (
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/tlsconfig"
)
// CommonFlags represents flags that are common to both the client and the daemon.
type CommonFlags struct {
FlagSet *flag.FlagSet
PostParse func()
Debug bool
Hosts []string
LogLevel string
TLS bool
TLSVerify bool
TLSOptions *tlsconfig.Options
TrustKey string
}

View file

@ -41,22 +41,22 @@ type CommonConfig struct {
// the current process. // the current process.
// Subsequent calls to `flag.Parse` will populate config with values parsed // Subsequent calls to `flag.Parse` will populate config with values parsed
// from the command-line. // from the command-line.
func (config *Config) InstallCommonFlags() { func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string) string) {
opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options") cmd.Var(opts.NewListOptsRef(&config.GraphOptions, nil), []string{"-storage-opt"}, usageFn("Set storage driver options"))
opts.ListVar(&config.ExecOptions, []string{"-exec-opt"}, "Set exec driver options") cmd.Var(opts.NewListOptsRef(&config.ExecOptions, nil), []string{"-exec-opt"}, usageFn("Set exec driver options"))
flag.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, "Path to use for daemon PID file") cmd.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, usageFn("Path to use for daemon PID file"))
flag.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, "Root of the Docker runtime") cmd.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, usageFn("Root of the Docker runtime"))
flag.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", "Root of the Docker execdriver") cmd.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", usageFn("Root of the Docker execdriver"))
flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run") cmd.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, usageFn("--restart on the daemon has been deprecated in favor of --restart policies on docker run"))
flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Storage driver to use") cmd.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", usageFn("Storage driver to use"))
flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, "Exec driver to use") cmd.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, usageFn("Exec driver to use"))
flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "Set the containers network MTU") cmd.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, usageFn("Set the containers network MTU"))
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") 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"))
flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API") cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
// FIXME: why the inconsistency between "hosts" and "sockets"? // FIXME: why the inconsistency between "hosts" and "sockets"?
opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use") cmd.Var(opts.NewListOptsRef(&config.Dns, opts.ValidateIPAddress), []string{"#dns", "-dns"}, usageFn("DNS server to use"))
opts.DNSSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "DNS search domains to use") cmd.Var(opts.NewListOptsRef(&config.DnsSearch, opts.ValidateDNSSearch), []string{"-dns-search"}, usageFn("DNS search domains to use"))
opts.LabelListVar(&config.Labels, []string{"-label"}, "Set key=value labels to the daemon") cmd.Var(opts.NewListOptsRef(&config.Labels, opts.ValidateLabel), []string{"-label"}, usageFn("Set key=value labels to the daemon"))
flag.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", "Default driver for container logs") cmd.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", usageFn("Default driver for container logs"))
opts.LogOptsVar(config.LogConfig.Config, []string{"-log-opt"}, "Set log driver options") cmd.Var(opts.NewMapOpts(config.LogConfig.Config, nil), []string{"-log-opt"}, usageFn("Set log driver options"))
} }

View file

@ -4,7 +4,7 @@ package daemon
import flag "github.com/docker/docker/pkg/mflag" import flag "github.com/docker/docker/pkg/mflag"
func (config *Config) attachExperimentalFlags() { func (config *Config) attachExperimentalFlags(cmd *flag.FlagSet, usageFn func(string) string) {
flag.StringVar(&config.DefaultNetwork, []string{"-default-network"}, "", "Set default network") cmd.StringVar(&config.DefaultNetwork, []string{"-default-network"}, "", usageFn("Set default network"))
flag.StringVar(&config.NetworkKVStore, []string{"-kv-store"}, "", "Set KV Store configuration") cmd.StringVar(&config.NetworkKVStore, []string{"-kv-store"}, "", usageFn("Set KV Store configuration"))
} }

View file

@ -49,27 +49,28 @@ type bridgeConfig struct {
// the current process. // the current process.
// Subsequent calls to `flag.Parse` will populate config with values parsed // Subsequent calls to `flag.Parse` will populate config with values parsed
// from the command-line. // from the command-line.
func (config *Config) InstallFlags() { func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
// First handle install flags which are consistent cross-platform // First handle install flags which are consistent cross-platform
config.InstallCommonFlags() config.InstallCommonFlags(cmd, usageFn)
// Then platform-specific install flags // Then platform-specific install flags
flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support") cmd.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, usageFn("Enable selinux support"))
flag.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", "Group for the unix socket") cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", usageFn("Group for the unix socket"))
config.Ulimits = make(map[string]*ulimit.Ulimit) config.Ulimits = make(map[string]*ulimit.Ulimit)
opts.UlimitMapVar(config.Ulimits, []string{"-default-ulimit"}, "Set default ulimits for containers") cmd.Var(opts.NewUlimitOpt(&config.Ulimits), []string{"-default-ulimit"}, usageFn("Set default ulimits for containers"))
flag.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules") cmd.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, usageFn("Enable addition of iptables rules"))
flag.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward") cmd.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, usageFn("Enable net.ipv4.ip_forward"))
flag.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, "Enable IP masquerading") cmd.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, usageFn("Enable IP masquerading"))
flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking") cmd.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, usageFn("Enable IPv6 networking"))
flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP") cmd.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", usageFn("Specify network bridge IP"))
flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge") cmd.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", usageFn("Attach containers to a network bridge"))
flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs") cmd.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", usageFn("IPv4 subnet for fixed IPs"))
flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs") cmd.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", usageFn("IPv6 subnet for fixed IPs"))
opts.IPVar(&config.Bridge.DefaultGatewayIPv4, []string{"-default-gateway"}, "", "Container default gateway IPv4 address") cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultGatewayIPv4, ""), []string{"-default-gateway"}, usageFn("Container default gateway IPv4 address"))
opts.IPVar(&config.Bridge.DefaultGatewayIPv6, []string{"-default-gateway-v6"}, "", "Container default gateway IPv6 address") cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultGatewayIPv6, ""), []string{"-default-gateway-v6"}, usageFn("Container default gateway IPv6 address"))
flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication") cmd.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, usageFn("Enable inter-container communication"))
opts.IPVar(&config.Bridge.DefaultIP, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports") cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultIP, "0.0.0.0"), []string{"#ip", "-ip"}, usageFn("Default IP when binding container ports"))
flag.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, "Use userland proxy for loopback traffic") cmd.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
config.attachExperimentalFlags()
config.attachExperimentalFlags(cmd, usageFn)
} }

View file

@ -2,5 +2,7 @@
package daemon package daemon
func (config *Config) attachExperimentalFlags() { import flag "github.com/docker/docker/pkg/mflag"
func (config *Config) attachExperimentalFlags(cmd *flag.FlagSet, usageFn func(string) string) {
} }

View file

@ -32,9 +32,9 @@ type Config struct {
// the current process. // the current process.
// Subsequent calls to `flag.Parse` will populate config with values parsed // Subsequent calls to `flag.Parse` will populate config with values parsed
// from the command-line. // from the command-line.
func (config *Config) InstallFlags() { func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
// First handle install flags which are consistent cross-platform // First handle install flags which are consistent cross-platform
config.InstallCommonFlags() config.InstallCommonFlags(cmd, usageFn)
// Then platform-specific install flags. // Then platform-specific install flags.
flag.StringVar(&config.Bridge.VirtualSwitchName, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch") flag.StringVar(&config.Bridge.VirtualSwitchName, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch")

View file

@ -1,11 +1,28 @@
// +build !daemon
package main package main
import ( import (
"log" // see gh#8745, client needs to use go log pkg "path/filepath"
"github.com/docker/docker/cli"
"github.com/docker/docker/cliconfig"
flag "github.com/docker/docker/pkg/mflag"
) )
func mainDaemon() { var clientFlags = &cli.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags}
log.Fatal("This is a client-only binary - running the Docker daemon is not supported.")
func init() {
client := clientFlags.FlagSet
client.StringVar(&clientFlags.ConfigDir, []string{"-config"}, cliconfig.ConfigDir(), "Location of client config files")
clientFlags.PostParse = func() {
clientFlags.Common.PostParse()
if clientFlags.ConfigDir != "" {
cliconfig.SetConfigDir(clientFlags.ConfigDir)
}
if clientFlags.Common.TrustKey == "" {
clientFlags.Common.TrustKey = filepath.Join(cliconfig.ConfigDir(), defaultTrustKeyFile)
}
}
} }

101
docker/common.go Normal file
View file

@ -0,0 +1,101 @@
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/cli"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/tlsconfig"
)
const (
defaultTrustKeyFile = "key.json"
defaultCaFile = "ca.pem"
defaultKeyFile = "key.pem"
defaultCertFile = "cert.pem"
)
var (
daemonFlags *flag.FlagSet
commonFlags = &cli.CommonFlags{FlagSet: new(flag.FlagSet)}
dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
dockerTLSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
)
func init() {
if dockerCertPath == "" {
dockerCertPath = cliconfig.ConfigDir()
}
commonFlags.PostParse = postParseCommon
cmd := commonFlags.FlagSet
cmd.BoolVar(&commonFlags.Debug, []string{"D", "-debug"}, false, "Enable debug mode")
cmd.StringVar(&commonFlags.LogLevel, []string{"l", "-log-level"}, "info", "Set the logging level")
cmd.BoolVar(&commonFlags.TLS, []string{"-tls"}, false, "Use TLS; implied by --tlsverify")
cmd.BoolVar(&commonFlags.TLSVerify, []string{"-tlsverify"}, dockerTLSVerify, "Use TLS and verify the remote")
// TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file")
var tlsOptions tlsconfig.Options
commonFlags.TLSOptions = &tlsOptions
cmd.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA")
cmd.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file")
cmd.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file")
cmd.Var(opts.NewListOptsRef(&commonFlags.Hosts, opts.ValidateHost), []string{"H", "-host"}, "Daemon socket(s) to connect to")
}
func postParseCommon() {
cmd := commonFlags.FlagSet
if commonFlags.LogLevel != "" {
lvl, err := logrus.ParseLevel(commonFlags.LogLevel)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", commonFlags.LogLevel)
os.Exit(1)
}
logrus.SetLevel(lvl)
} else {
logrus.SetLevel(logrus.InfoLevel)
}
if commonFlags.Debug {
os.Setenv("DEBUG", "1")
logrus.SetLevel(logrus.DebugLevel)
}
// Regardless of whether the user sets it to true or false, if they
// specify --tlsverify at all then we need to turn on tls
// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need to check that here as well
if cmd.IsSet("-tlsverify") || commonFlags.TLSVerify {
commonFlags.TLS = true
}
if !commonFlags.TLS {
commonFlags.TLSOptions = nil
} else {
tlsOptions := commonFlags.TLSOptions
tlsOptions.InsecureSkipVerify = !commonFlags.TLSVerify
// Reset CertFile and KeyFile to empty string if the user did not specify
// the respective flags and the respective default files were not found.
if !cmd.IsSet("-tlscert") {
if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
tlsOptions.CertFile = ""
}
}
if !cmd.IsSet("-tlskey") {
if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
tlsOptions.KeyFile = ""
}
}
}
}

View file

@ -8,14 +8,18 @@ import (
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"strings"
"time" "time"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
apiserver "github.com/docker/docker/api/server" apiserver "github.com/docker/docker/api/server"
"github.com/docker/docker/autogen/dockerversion" "github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/cli"
"github.com/docker/docker/cliconfig" "github.com/docker/docker/cliconfig"
"github.com/docker/docker/daemon" "github.com/docker/docker/daemon"
"github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/logger"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/pidfile" "github.com/docker/docker/pkg/pidfile"
"github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/signal"
@ -26,17 +30,63 @@ import (
"github.com/docker/docker/utils" "github.com/docker/docker/utils"
) )
const daemonUsage = " docker daemon [ --help | ... ]\n"
var ( var (
daemonCfg = &daemon.Config{} flDaemon = flag.Bool([]string{"#d", "#-daemon"}, false, "Enable daemon mode (deprecated; use docker daemon)")
registryCfg = &registry.Options{} daemonCli cli.Handler = NewDaemonCli()
) )
func init() { // TODO: remove once `-d` is retired
if daemonCfg.LogConfig.Config == nil { func handleGlobalDaemonFlag() {
daemonCfg.LogConfig.Config = make(map[string]string) // This block makes sure that if the deprecated daemon flag `--daemon` is absent,
// then all daemon-specific flags are absent as well.
if !*flDaemon && daemonFlags != nil {
flag.CommandLine.Visit(func(fl *flag.Flag) {
for _, name := range fl.Names {
name := strings.TrimPrefix(name, "#")
if daemonFlags.Lookup(name) != nil {
// daemon flag was NOT specified, but daemon-specific flags were
// so let's error out
fmt.Fprintf(os.Stderr, "docker: the daemon flag '-%s' must follow the 'docker daemon' command.\n", name)
os.Exit(1)
}
}
})
}
if *flDaemon {
if *flHelp {
// We do not show the help output here, instead, we tell the user about the new daemon command,
// because the help output is so long they would not see the warning anyway.
fmt.Fprintln(os.Stderr, "Please use 'docker daemon --help' instead.")
os.Exit(0)
}
daemonCli.(*DaemonCli).CmdDaemon(flag.Args()...)
os.Exit(0)
}
}
func presentInHelp(usage string) string { return usage }
func absentFromHelp(string) string { return "" }
// NewDaemonCli returns a pre-configured daemon CLI
func NewDaemonCli() *DaemonCli {
daemonFlags = cli.Subcmd("daemon", nil, "Enable daemon mode", true)
// TODO(tiborvass): remove InstallFlags?
daemonConfig := new(daemon.Config)
daemonConfig.InstallFlags(daemonFlags, presentInHelp)
daemonConfig.InstallFlags(flag.CommandLine, absentFromHelp)
registryOptions := new(registry.Options)
registryOptions.InstallFlags(daemonFlags, presentInHelp)
registryOptions.InstallFlags(flag.CommandLine, absentFromHelp)
daemonFlags.Require(flag.Exact, 0)
return &DaemonCli{
Config: daemonConfig,
registryOptions: registryOptions,
} }
daemonCfg.InstallFlags()
registryCfg.InstallFlags()
} }
func migrateKey() (err error) { func migrateKey() (err error) {
@ -79,14 +129,56 @@ func migrateKey() (err error) {
return nil return nil
} }
func mainDaemon() { // DaemonCli represents the daemon CLI.
if utils.ExperimentalBuild() { type DaemonCli struct {
logrus.Warn("Running experimental build") *daemon.Config
registryOptions *registry.Options
}
func getGlobalFlag() (globalFlag *flag.Flag) {
defer func() {
if x := recover(); x != nil {
switch f := x.(type) {
case *flag.Flag:
globalFlag = f
default:
panic(x)
}
}
}()
visitor := func(f *flag.Flag) { panic(f) }
commonFlags.FlagSet.Visit(visitor)
clientFlags.FlagSet.Visit(visitor)
return
}
// CmdDaemon is the daemon command, called the raw arguments after `docker daemon`.
func (cli *DaemonCli) CmdDaemon(args ...string) error {
if *flDaemon {
// allow legacy forms `docker -D -d` and `docker -d -D`
logrus.Warn("please use 'docker daemon' instead.")
} else if !commonFlags.FlagSet.IsEmpty() || !clientFlags.FlagSet.IsEmpty() {
// deny `docker -D daemon`
illegalFlag := getGlobalFlag()
fmt.Fprintf(os.Stderr, "invalid flag '-%s'.\nSee 'docker daemon --help'.\n", illegalFlag.Names[0])
os.Exit(1)
} else {
// allow new form `docker daemon -D`
flag.Merge(daemonFlags, commonFlags.FlagSet)
} }
if flag.NArg() != 0 { daemonFlags.ParseFlags(args, true)
flag.Usage() commonFlags.PostParse()
return
if len(commonFlags.Hosts) == 0 {
commonFlags.Hosts = []string{opts.DefaultHost}
}
if commonFlags.TrustKey == "" {
commonFlags.TrustKey = filepath.Join(getDaemonConfDir(), defaultTrustKeyFile)
}
if utils.ExperimentalBuild() {
logrus.Warn("Running experimental build")
} }
logrus.SetFormatter(&logrus.TextFormatter{TimestampFormat: timeutils.RFC3339NanoFixed}) logrus.SetFormatter(&logrus.TextFormatter{TimestampFormat: timeutils.RFC3339NanoFixed})
@ -95,15 +187,15 @@ func mainDaemon() {
logrus.Fatalf("Failed to set umask: %v", err) logrus.Fatalf("Failed to set umask: %v", err)
} }
if len(daemonCfg.LogConfig.Config) > 0 { if len(cli.LogConfig.Config) > 0 {
if err := logger.ValidateLogOpts(daemonCfg.LogConfig.Type, daemonCfg.LogConfig.Config); err != nil { if err := logger.ValidateLogOpts(cli.LogConfig.Type, cli.LogConfig.Config); err != nil {
logrus.Fatalf("Failed to set log opts: %v", err) logrus.Fatalf("Failed to set log opts: %v", err)
} }
} }
var pfile *pidfile.PidFile var pfile *pidfile.PidFile
if daemonCfg.Pidfile != "" { if cli.Pidfile != "" {
pf, err := pidfile.New(daemonCfg.Pidfile) pf, err := pidfile.New(cli.Pidfile)
if err != nil { if err != nil {
logrus.Fatalf("Error starting daemon: %v", err) logrus.Fatalf("Error starting daemon: %v", err)
} }
@ -115,21 +207,26 @@ func mainDaemon() {
}() }()
} }
if cli.LogConfig.Config == nil {
cli.LogConfig.Config = make(map[string]string)
}
serverConfig := &apiserver.ServerConfig{ serverConfig := &apiserver.ServerConfig{
Logging: true, Logging: true,
EnableCors: daemonCfg.EnableCors, EnableCors: cli.EnableCors,
CorsHeaders: daemonCfg.CorsHeaders, CorsHeaders: cli.CorsHeaders,
Version: dockerversion.VERSION, Version: dockerversion.VERSION,
} }
serverConfig = setPlatformServerConfig(serverConfig, daemonCfg) serverConfig = setPlatformServerConfig(serverConfig, cli.Config)
if *flTLS { if commonFlags.TLSOptions != nil {
if *flTLSVerify { if !commonFlags.TLSOptions.InsecureSkipVerify {
tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert // server requires and verifies client's certificate
commonFlags.TLSOptions.ClientAuth = tls.RequireAndVerifyClientCert
} }
tlsConfig, err := tlsconfig.Server(tlsOptions) tlsConfig, err := tlsconfig.Server(*commonFlags.TLSOptions)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatalf("foobar: %v", err)
} }
serverConfig.TLSConfig = tlsConfig serverConfig.TLSConfig = tlsConfig
} }
@ -141,7 +238,7 @@ func mainDaemon() {
// daemon doesn't exit // daemon doesn't exit
serveAPIWait := make(chan error) serveAPIWait := make(chan error)
go func() { go func() {
if err := api.ServeApi(flHosts); err != nil { if err := api.ServeApi(commonFlags.Hosts); err != nil {
logrus.Errorf("ServeAPI error: %v", err) logrus.Errorf("ServeAPI error: %v", err)
serveAPIWait <- err serveAPIWait <- err
return return
@ -152,10 +249,10 @@ func mainDaemon() {
if err := migrateKey(); err != nil { if err := migrateKey(); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
daemonCfg.TrustKeyPath = *flTrustKey cli.TrustKeyPath = commonFlags.TrustKey
registryService := registry.NewService(registryCfg) registryService := registry.NewService(cli.registryOptions)
d, err := daemon.NewDaemon(daemonCfg, registryService) d, err := daemon.NewDaemon(cli.Config, registryService)
if err != nil { if err != nil {
if pfile != nil { if pfile != nil {
if err := pfile.Remove(); err != nil { if err := pfile.Remove(); err != nil {
@ -201,6 +298,7 @@ func mainDaemon() {
} }
logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI) logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)
} }
return nil
} }
// shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
@ -219,3 +317,11 @@ func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) {
logrus.Error("Force shutdown daemon") logrus.Error("Force shutdown daemon")
} }
} }
func getDaemonConfDir() string {
// TODO: update for Windows daemon
if runtime.GOOS == "windows" {
return cliconfig.ConfigDir()
}
return "/etc/docker"
}

12
docker/daemon_none.go Normal file
View file

@ -0,0 +1,12 @@
// +build !daemon
package main
import "github.com/docker/docker/cli"
const daemonUsage = ""
var daemonCli cli.Handler
// TODO: remove once `-d` is retired
func handleGlobalDaemonFlag() {}

View file

@ -1,31 +1,20 @@
package main package main
import ( import (
"crypto/tls"
"fmt" "fmt"
"os" "os"
"runtime" "sort"
"strings"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/api/client" "github.com/docker/docker/api/client"
"github.com/docker/docker/autogen/dockerversion" "github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/cliconfig" "github.com/docker/docker/cli"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/reexec" "github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/term" "github.com/docker/docker/pkg/term"
"github.com/docker/docker/pkg/tlsconfig"
"github.com/docker/docker/utils" "github.com/docker/docker/utils"
) )
const (
defaultTrustKeyFile = "key.json"
defaultCaFile = "ca.pem"
defaultKeyFile = "key.pem"
defaultCertFile = "cert.pem"
)
func main() { func main() {
if reexec.Init() { if reexec.Init() {
return return
@ -34,116 +23,58 @@ func main() {
// Set terminal emulation based on platform as required. // Set terminal emulation based on platform as required.
stdin, stdout, stderr := term.StdStreams() stdin, stdout, stderr := term.StdStreams()
initLogging(stderr) logrus.SetOutput(stderr)
flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet)
flag.Usage = func() {
fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n"+daemonUsage+" docker [ -h | --help | -v | --version ]\n\n")
fmt.Fprint(os.Stdout, "A self-sufficient runtime for containers.\n\nOptions:\n")
flag.CommandLine.SetOutput(os.Stdout)
flag.PrintDefaults()
help := "\nCommands:\n"
// TODO(tiborvass): no need to sort if we ensure dockerCommands is sorted
sort.Sort(byName(dockerCommands))
for _, cmd := range dockerCommands {
help += fmt.Sprintf(" %-10.10s%s\n", cmd.name, cmd.description)
}
help += "\nRun 'docker COMMAND --help' for more information on a command."
fmt.Fprintf(os.Stdout, "%s\n", help)
}
flag.Parse() flag.Parse()
// FIXME: validate daemon flags here
if *flVersion { if *flVersion {
showVersion() showVersion()
return return
} }
if *flConfigDir != "" { clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags)
cliconfig.SetConfigDir(*flConfigDir) // TODO: remove once `-d` is retired
} handleGlobalDaemonFlag()
if *flLogLevel != "" { if *flHelp {
lvl, err := logrus.ParseLevel(*flLogLevel) // if global flag --help is present, regardless of what other options and commands there are,
if err != nil { // just print the usage.
fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", *flLogLevel) flag.Usage()
os.Exit(1)
}
setLogLevel(lvl)
} else {
setLogLevel(logrus.InfoLevel)
}
if *flDebug {
os.Setenv("DEBUG", "1")
setLogLevel(logrus.DebugLevel)
}
if len(flHosts) == 0 {
defaultHost := os.Getenv("DOCKER_HOST")
if defaultHost == "" || *flDaemon {
if runtime.GOOS != "windows" {
// If we do not have a host, default to unix socket
defaultHost = fmt.Sprintf("unix://%s", opts.DefaultUnixSocket)
} else {
// If we do not have a host, default to TCP socket on Windows
defaultHost = fmt.Sprintf("tcp://%s:%d", opts.DefaultHTTPHost, opts.DefaultHTTPPort)
}
}
defaultHost, err := opts.ValidateHost(defaultHost)
if err != nil {
if *flDaemon {
logrus.Fatal(err)
} else {
fmt.Fprint(os.Stderr, err)
}
os.Exit(1)
}
flHosts = append(flHosts, defaultHost)
}
setDefaultConfFlag(flTrustKey, defaultTrustKeyFile)
// Regardless of whether the user sets it to true or false, if they
// specify --tlsverify at all then we need to turn on tls
// *flTlsVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need to check that here as well
if flag.IsSet("-tlsverify") || *flTLSVerify {
*flTLS = true
}
if *flDaemon {
if *flHelp {
flag.Usage()
return
}
mainDaemon()
return return
} }
// From here on, we assume we're a client, not a server. c := cli.New(clientCli, daemonCli)
if err := c.Run(flag.Args()...); err != nil {
if len(flHosts) > 1 { if sterr, ok := err.(cli.StatusError); ok {
fmt.Fprintf(os.Stderr, "Please specify only one -H")
os.Exit(0)
}
protoAddrParts := strings.SplitN(flHosts[0], "://", 2)
var tlsConfig *tls.Config
if *flTLS {
tlsOptions.InsecureSkipVerify = !*flTLSVerify
if !flag.IsSet("-tlscert") {
if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
tlsOptions.CertFile = ""
}
}
if !flag.IsSet("-tlskey") {
if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
tlsOptions.KeyFile = ""
}
}
var err error
tlsConfig, err = tlsconfig.Client(tlsOptions)
if err != nil {
fmt.Fprintln(stderr, err)
os.Exit(1)
}
}
cli := client.NewDockerCli(stdin, stdout, stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], tlsConfig)
if err := cli.Cmd(flag.Args()...); err != nil {
if sterr, ok := err.(client.StatusError); ok {
if sterr.Status != "" { if sterr.Status != "" {
fmt.Fprintln(cli.Err(), sterr.Status) fmt.Fprintln(os.Stderr, sterr.Status)
os.Exit(1) os.Exit(1)
} }
os.Exit(sterr.StatusCode) os.Exit(sterr.StatusCode)
} }
fmt.Fprintln(cli.Err(), err) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
} }
} }

View file

@ -1,16 +1,10 @@
package main package main
import ( import flag "github.com/docker/docker/pkg/mflag"
"fmt"
"os"
"path/filepath"
"runtime"
"sort"
"github.com/docker/docker/cliconfig" var (
"github.com/docker/docker/opts" flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage")
flag "github.com/docker/docker/pkg/mflag" flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
"github.com/docker/docker/pkg/tlsconfig"
) )
type command struct { type command struct {
@ -24,118 +18,46 @@ func (a byName) Len() int { return len(a) }
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].name < a[j].name } func (a byName) Less(i, j int) bool { return a[i].name < a[j].name }
var ( // TODO(tiborvass): do not show 'daemon' on client-only binaries
dockerCertPath = os.Getenv("DOCKER_CERT_PATH") // and deduplicate description in dockerCommands and cli subcommands
dockerTlSVerify = os.Getenv("DOCKER_TLS_VERIFY") != "" var dockerCommands = []command{
{"attach", "Attach to a running container"},
dockerCommands = []command{ {"build", "Build an image from a Dockerfile"},
{"attach", "Attach to a running container"}, {"commit", "Create a new image from a container's changes"},
{"build", "Build an image from a Dockerfile"}, {"cp", "Copy files/folders from a container to a HOSTDIR or to STDOUT"},
{"commit", "Create a new image from a container's changes"}, {"create", "Create a new container"},
{"cp", "Copy files/folders from a container to a HOSTDIR or to STDOUT"}, {"diff", "Inspect changes on a container's filesystem"},
{"create", "Create a new container"}, {"events", "Get real time events from the server"},
{"diff", "Inspect changes on a container's filesystem"}, {"exec", "Run a command in a running container"},
{"events", "Get real time events from the server"}, {"export", "Export a container's filesystem as a tar archive"},
{"exec", "Run a command in a running container"}, {"history", "Show the history of an image"},
{"export", "Export a container's filesystem as a tar archive"}, {"images", "List images"},
{"history", "Show the history of an image"}, {"import", "Import the contents from a tarball to create a filesystem image"},
{"images", "List images"}, {"info", "Display system-wide information"},
{"import", "Import the contents from a tarball to create a filesystem image"}, {"inspect", "Return low-level information on a container or image"},
{"info", "Display system-wide information"}, {"kill", "Kill a running container"},
{"inspect", "Return low-level information on a container or image"}, {"load", "Load an image from a tar archive or STDIN"},
{"kill", "Kill a running container"}, {"login", "Register or log in to a Docker registry"},
{"load", "Load an image from a tar archive or STDIN"}, {"logout", "Log out from a Docker registry"},
{"login", "Register or log in to a Docker registry"}, {"logs", "Fetch the logs of a container"},
{"logout", "Log out from a Docker registry"}, {"port", "List port mappings or a specific mapping for the CONTAINER"},
{"logs", "Fetch the logs of a container"}, {"pause", "Pause all processes within a container"},
{"port", "List port mappings or a specific mapping for the CONTAINER"}, {"ps", "List containers"},
{"pause", "Pause all processes within a container"}, {"pull", "Pull an image or a repository from a registry"},
{"ps", "List containers"}, {"push", "Push an image or a repository to a registry"},
{"pull", "Pull an image or a repository from a registry"}, {"rename", "Rename a container"},
{"push", "Push an image or a repository to a registry"}, {"restart", "Restart a running container"},
{"rename", "Rename a container"}, {"rm", "Remove one or more containers"},
{"restart", "Restart a running container"}, {"rmi", "Remove one or more images"},
{"rm", "Remove one or more containers"}, {"run", "Run a command in a new container"},
{"rmi", "Remove one or more images"}, {"save", "Save an image(s) to a tar archive"},
{"run", "Run a command in a new container"}, {"search", "Search the Docker Hub for images"},
{"save", "Save an image(s) to a tar archive"}, {"start", "Start one or more stopped containers"},
{"search", "Search the Docker Hub for images"}, {"stats", "Display a live stream of container(s) resource usage statistics"},
{"start", "Start one or more stopped containers"}, {"stop", "Stop a running container"},
{"stats", "Display a live stream of container(s) resource usage statistics"}, {"tag", "Tag an image into a repository"},
{"stop", "Stop a running container"}, {"top", "Display the running processes of a container"},
{"tag", "Tag an image into a repository"}, {"unpause", "Unpause all processes within a container"},
{"top", "Display the running processes of a container"}, {"version", "Show the Docker version information"},
{"unpause", "Unpause all processes within a container"}, {"wait", "Block until a container stops, then print its exit code"},
{"version", "Show the Docker version information"},
{"wait", "Block until a container stops, then print its exit code"},
}
)
func init() {
if dockerCertPath == "" {
dockerCertPath = cliconfig.ConfigDir()
}
}
func getDaemonConfDir() string {
// TODO: update for Windows daemon
if runtime.GOOS == "windows" {
return cliconfig.ConfigDir()
}
return "/etc/docker"
}
var (
flConfigDir = flag.String([]string{"-config"}, cliconfig.ConfigDir(), "Location of client config files")
flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level")
flTLS = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by --tlsverify")
flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage")
flTLSVerify = flag.Bool([]string{"-tlsverify"}, dockerTlSVerify, "Use TLS and verify the remote")
// these are initialized in init() below since their default values depend on dockerCertPath which isn't fully initialized until init() runs
tlsOptions tlsconfig.Options
flTrustKey *string
flHosts []string
)
func setDefaultConfFlag(flag *string, def string) {
if *flag == "" {
if *flDaemon {
*flag = filepath.Join(getDaemonConfDir(), def)
} else {
*flag = filepath.Join(cliconfig.ConfigDir(), def)
}
}
}
func init() {
var placeholderTrustKey string
// TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file")
flTrustKey = &placeholderTrustKey
flag.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA")
flag.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file")
flag.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file")
opts.HostListVar(&flHosts, []string{"H", "-host"}, "Daemon socket(s) to connect to")
flag.Usage = func() {
fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for containers.\n\nOptions:\n")
flag.CommandLine.SetOutput(os.Stdout)
flag.PrintDefaults()
help := "\nCommands:\n"
sort.Sort(byName(dockerCommands))
for _, cmd := range dockerCommands {
help += fmt.Sprintf(" %-10.10s%s\n", cmd.name, cmd.description)
}
help += "\nRun 'docker COMMAND --help' for more information on a command."
fmt.Fprintf(os.Stdout, "%s\n", help)
}
} }

View file

@ -1,14 +0,0 @@
package main
import (
"github.com/Sirupsen/logrus"
"io"
)
func setLogLevel(lvl logrus.Level) {
logrus.SetLevel(lvl)
}
func initLogging(stderr io.Writer) {
logrus.SetOutput(stderr)
}

View file

@ -103,7 +103,7 @@ when no `-H` was passed in.
Run Docker in daemon mode: Run Docker in daemon mode:
$ sudo <path to>/docker -H 0.0.0.0:5555 -d & $ sudo <path to>/docker daemon -H 0.0.0.0:5555 &
Download an `ubuntu` image: Download an `ubuntu` image:
@ -113,7 +113,7 @@ You can use multiple `-H`, for example, if you want to listen on both
TCP and a Unix socket TCP and a Unix socket
# Run docker in daemon mode # Run docker in daemon mode
$ sudo <path to>/docker -H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock -d & $ sudo <path to>/docker daemon -H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock &
# Download an ubuntu image, use default Unix socket # Download an ubuntu image, use default Unix socket
$ docker pull ubuntu $ docker pull ubuntu
# OR use the TCP port # OR use the TCP port

View file

@ -24,7 +24,7 @@ or `systemd` to manage the `docker` daemon's start and stop.
The `docker` daemon can be run directly using the `-d` option. By default it listens on The `docker` daemon can be run directly using the `-d` option. By default it listens on
the Unix socket `unix:///var/run/docker.sock` the Unix socket `unix:///var/run/docker.sock`
$ docker -d $ docker daemon
INFO[0000] +job init_networkdriver() INFO[0000] +job init_networkdriver()
INFO[0000] +job serveapi(unix:///var/run/docker.sock) INFO[0000] +job serveapi(unix:///var/run/docker.sock)
@ -34,10 +34,9 @@ the Unix socket `unix:///var/run/docker.sock`
### Configuring the docker daemon directly ### Configuring the docker daemon directly
If you're running the `docker` daemon directly by running `docker -d` instead If you're running the `docker` daemon directly by running `docker daemon` instead
of using a process manager, you can append the configuration options to the `docker` run of using a process manager, you can append the configuration options to the `docker` run
command directly. Just like the `-d` option, other options can be passed to the `docker` command directly. Other options can be passed to the `docker` daemon to configure it.
daemon to configure it.
Some of the daemon's options are: Some of the daemon's options are:
@ -50,7 +49,7 @@ Some of the daemon's options are:
Here is a an example of running the `docker` daemon with configuration options: Here is a an example of running the `docker` daemon with configuration options:
$ docker -d -D --tls=true --tlscert=/var/docker/server.pem --tlskey=/var/docker/serverkey.pem -H tcp://192.168.59.3:2376 $ docker daemon -D --tls=true --tlscert=/var/docker/server.pem --tlskey=/var/docker/serverkey.pem -H tcp://192.168.59.3:2376
These options : These options :

View file

@ -136,7 +136,7 @@ prevent accidental damage:
Now you can make the Docker daemon only accept connections from clients Now you can make the Docker daemon only accept connections from clients
providing a certificate trusted by our CA: providing a certificate trusted by our CA:
$ docker -d --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem \ $ docker daemon --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem \
-H=0.0.0.0:2376 -H=0.0.0.0:2376
To be able to connect to Docker and validate its certificate, you now To be able to connect to Docker and validate its certificate, you now

View file

@ -503,7 +503,7 @@ To assign globally routable IPv6 addresses to your containers you have to
specify an IPv6 subnet to pick the addresses from. Set the IPv6 subnet via the specify an IPv6 subnet to pick the addresses from. Set the IPv6 subnet via the
`--fixed-cidr-v6` parameter when starting Docker daemon: `--fixed-cidr-v6` parameter when starting Docker daemon:
docker -d --ipv6 --fixed-cidr-v6="2001:db8:1::/64" docker daemon --ipv6 --fixed-cidr-v6="2001:db8:1::/64"
The subnet for Docker containers should at least have a size of `/80`. This way The subnet for Docker containers should at least have a size of `/80`. This way
an IPv6 address can end with the container's MAC address and you prevent NDP an IPv6 address can end with the container's MAC address and you prevent NDP
@ -589,7 +589,7 @@ Let's split up the configurable address range into two subnets
`2001:db8::c000/125` and `2001:db8::c008/125`. The first one can be used by the `2001:db8::c000/125` and `2001:db8::c008/125`. The first one can be used by the
host itself, the latter by Docker: host itself, the latter by Docker:
docker -d --ipv6 --fixed-cidr-v6 2001:db8::c008/125 docker daemon --ipv6 --fixed-cidr-v6 2001:db8::c008/125
You notice the Docker subnet is within the subnet managed by your router that You notice the Docker subnet is within the subnet managed by your router that
is connected to `eth0`. This means all devices (containers) with the addresses is connected to `eth0`. This means all devices (containers) with the addresses

View file

@ -36,11 +36,11 @@ There are two steps to set up and use a local registry mirror.
You will need to pass the `--registry-mirror` option to your Docker daemon on You will need to pass the `--registry-mirror` option to your Docker daemon on
startup: startup:
docker --registry-mirror=http://<my-docker-mirror-host> -d docker daemon --registry-mirror=http://<my-docker-mirror-host>
For example, if your mirror is serving on `http://10.0.0.2:5000`, you would run: For example, if your mirror is serving on `http://10.0.0.2:5000`, you would run:
docker --registry-mirror=http://10.0.0.2:5000 -d docker daemon --registry-mirror=http://10.0.0.2:5000
**NOTE:** **NOTE:**
Depending on your local host setup, you may be able to add the Depending on your local host setup, you may be able to add the

View file

@ -70,7 +70,7 @@ In this example, we'll assume that your `docker.service` file looks something li
[Service] [Service]
Type=notify Type=notify
EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker
ExecStart=/usr/bin/docker -d -H fd:// $OPTIONS ExecStart=/usr/bin/docker daemon -H fd:// $OPTIONS
LimitNOFILE=1048576 LimitNOFILE=1048576
LimitNPROC=1048576 LimitNPROC=1048576

View file

@ -174,7 +174,7 @@ For example:
## Run the Docker daemon ## Run the Docker daemon
# start the docker in daemon mode from the directory you unpacked # start the docker in daemon mode from the directory you unpacked
$ sudo ./docker -d & $ sudo ./docker daemon &
## Giving non-root access ## Giving non-root access

View file

@ -185,7 +185,7 @@ To create the `docker` group and add your user:
If this fails with a message similar to this: If this fails with a message similar to this:
Cannot connect to the Docker daemon. Is 'docker -d' running on this host? Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?
Check that the `DOCKER_HOST` environment variable is not set for your shell. Check that the `DOCKER_HOST` environment variable is not set for your shell.
If it is, unset it. If it is, unset it.

View file

@ -285,7 +285,7 @@ with the `make.sh` script.
8. Start a `docker` daemon running inside your container. 8. Start a `docker` daemon running inside your container.
root@5f8630b873fe:/go/src/github.com/docker/docker# docker -dD root@5f8630b873fe:/go/src/github.com/docker/docker# docker daemon -D
The `-dD` flag starts the daemon in debug mode. You'll find this useful The `-dD` flag starts the daemon in debug mode. You'll find this useful
when debugging your code. when debugging your code.
@ -411,7 +411,7 @@ onto the `/go` directory inside the container.
* copy the binary inside the development container using * copy the binary inside the development container using
`cp bundles/1.5.0-dev/binary/docker /usr/bin` `cp bundles/1.5.0-dev/binary/docker /usr/bin`
* start `docker -dD` to launch the Docker daemon inside the container * start `docker daemon -D` to launch the Docker daemon inside the container
* run `docker ps` on local host to get the development container's name * run `docker ps` on local host to get the development container's name
* connect to your running container `docker exec -it container_name bash` * connect to your running container `docker exec -it container_name bash`
* use the `docker run hello-world` command to create and run a container * use the `docker run hello-world` command to create and run a container

View file

@ -120,7 +120,7 @@ Run the entire test suite on your current repository:
PASS PASS
coverage: 70.8% of statements coverage: 70.8% of statements
---> Making bundle: test-docker-py (in bundles/1.5.0-dev/test-docker-py) ---> Making bundle: test-docker-py (in bundles/1.5.0-dev/test-docker-py)
+++ exec docker --daemon --debug --host unix:///go/src/github.com/docker/docker/bundles/1.5.0-dev/test-docker-py/docker.sock --storage-driver vfs --exec-driver native --pidfile /go/src/github.com/docker/docker/bundles/1.5.0-dev/test-docker-py/docker.pid +++ exec docker daemon --debug --host unix:///go/src/github.com/docker/docker/bundles/1.5.0-dev/test-docker-py/docker.sock --storage-driver vfs --exec-driver native --pidfile /go/src/github.com/docker/docker/bundles/1.5.0-dev/test-docker-py/docker.pid
................................................................. .................................................................
---------------------------------------------------------------------- ----------------------------------------------------------------------
Ran 65 tests in 89.266s Ran 65 tests in 89.266s

View file

@ -2269,4 +2269,4 @@ To set cross origin requests to the remote api please give values to
`--api-cors-header` when running Docker in daemon mode. Set * (asterisk) allows all, `--api-cors-header` when running Docker in daemon mode. Set * (asterisk) allows all,
default or blank means CORS disabled default or blank means CORS disabled
$ docker -d -H="192.168.1.9:2375" --api-cors-header="http://foo.bar" $ docker daemon -H="192.168.1.9:2375" --api-cors-header="http://foo.bar"

View file

@ -19,6 +19,9 @@ or execute `docker help`:
$ docker $ docker
Usage: docker [OPTIONS] COMMAND [arg...] Usage: docker [OPTIONS] COMMAND [arg...]
docker daemon [ --help | ... ]
docker [ -h | --help | -v | --version ]
-H, --host=[]: The socket(s) to bind to in daemon mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd. -H, --host=[]: The socket(s) to bind to in daemon mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.
A self-sufficient runtime for Linux containers. A self-sufficient runtime for Linux containers.

View file

@ -10,7 +10,7 @@ parent = "smn_cli"
# daemon # daemon
Usage: docker [OPTIONS] COMMAND [arg...] Usage: docker daemon [OPTIONS]
A self-sufficient runtime for linux containers. A self-sufficient runtime for linux containers.
@ -18,9 +18,7 @@ parent = "smn_cli"
--api-cors-header="" Set CORS headers in the remote API --api-cors-header="" Set CORS headers in the remote API
-b, --bridge="" Attach containers to a network bridge -b, --bridge="" Attach containers to a network bridge
--bip="" Specify network bridge IP --bip="" Specify network bridge IP
--config=~/.docker Location of client config files
-D, --debug=false Enable debug mode -D, --debug=false Enable debug mode
-d, --daemon=false Enable daemon mode
--default-gateway="" Container default gateway IPv4 address --default-gateway="" Container default gateway IPv4 address
--default-gateway-v6="" Container default gateway IPv6 address --default-gateway-v6="" Container default gateway IPv6 address
--dns=[] DNS server to use --dns=[] DNS server to use
@ -58,15 +56,14 @@ parent = "smn_cli"
--tlskey="~/.docker/key.pem" Path to TLS key file --tlskey="~/.docker/key.pem" Path to TLS key file
--tlsverify=false Use TLS and verify the remote --tlsverify=false Use TLS and verify the remote
--userland-proxy=true Use userland proxy for loopback traffic --userland-proxy=true Use userland proxy for loopback traffic
-v, --version=false Print version information and quit
Options with [] may be specified multiple times. Options with [] may be specified multiple times.
The Docker daemon is the persistent process that manages containers. Docker The Docker daemon is the persistent process that manages containers. Docker
uses the same binary for both the daemon and client. To run the daemon you uses the same binary for both the daemon and client. To run the daemon you
provide the `-d` flag. type `docker daemon`.
To run the daemon with debug output, use `docker -d -D`. To run the daemon with debug output, use `docker daemon -D`.
## Daemon socket option ## Daemon socket option
@ -94,8 +91,8 @@ communication with the daemon.
On Systemd based systems, you can communicate with the daemon via On Systemd based systems, you can communicate with the daemon via
[Systemd socket activation](http://0pointer.de/blog/projects/socket-activation.html), [Systemd socket activation](http://0pointer.de/blog/projects/socket-activation.html),
use `docker -d -H fd://`. Using `fd://` will work perfectly for most setups but use `docker daemon -H fd://`. Using `fd://` will work perfectly for most setups but
you can also specify individual sockets: `docker -d -H fd://3`. If the you can also specify individual sockets: `docker daemon -H fd://3`. If the
specified socket activated files aren't found, then Docker will exit. You can specified socket activated files aren't found, then Docker will exit. You can
find examples of using Systemd socket activation with Docker and Systemd in the find examples of using Systemd socket activation with Docker and Systemd in the
[Docker source tree](https://github.com/docker/docker/tree/master/contrib/init/systemd/). [Docker source tree](https://github.com/docker/docker/tree/master/contrib/init/systemd/).
@ -104,7 +101,7 @@ You can configure the Docker daemon to listen to multiple sockets at the same
time using multiple `-H` options: time using multiple `-H` options:
# listen using the default unix socket, and on 2 specific IP addresses on this host. # listen using the default unix socket, and on 2 specific IP addresses on this host.
docker -d -H unix:///var/run/docker.sock -H tcp://192.168.59.106 -H tcp://10.10.10.2 docker daemon -H unix:///var/run/docker.sock -H tcp://192.168.59.106 -H tcp://10.10.10.2
The Docker client will honor the `DOCKER_HOST` environment variable to set the The Docker client will honor the `DOCKER_HOST` environment variable to set the
`-H` flag for the client. `-H` flag for the client.
@ -152,16 +149,16 @@ article explains how to tune your existing setup without the use of options.
The `btrfs` driver is very fast for `docker build` - but like `devicemapper` The `btrfs` driver is very fast for `docker build` - but like `devicemapper`
does not share executable memory between devices. Use does not share executable memory between devices. Use
`docker -d -s btrfs -g /mnt/btrfs_partition`. `docker daemon -s btrfs -g /mnt/btrfs_partition`.
The `zfs` driver is probably not fast as `btrfs` but has a longer track record The `zfs` driver is probably not fast as `btrfs` but has a longer track record
on stability. Thanks to `Single Copy ARC` shared blocks between clones will be on stability. Thanks to `Single Copy ARC` shared blocks between clones will be
cached only once. Use `docker -d -s zfs`. To select a different zfs filesystem cached only once. Use `docker daemon -s zfs`. To select a different zfs filesystem
set `zfs.fsname` option as described in [Storage driver options](#storage-driver-options). set `zfs.fsname` option as described in [Storage driver options](#storage-driver-options).
The `overlay` is a very fast union filesystem. It is now merged in the main The `overlay` is a very fast union filesystem. It is now merged in the main
Linux kernel as of [3.18.0](https://lkml.org/lkml/2014/10/26/137). Call Linux kernel as of [3.18.0](https://lkml.org/lkml/2014/10/26/137). Call
`docker -d -s overlay` to use it. `docker daemon -s overlay` to use it.
> **Note:** > **Note:**
> As promising as `overlay` is, the feature is still quite young and should not > As promising as `overlay` is, the feature is still quite young and should not
@ -196,7 +193,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
docker -d --storage-opt dm.thinpooldev=/dev/mapper/thin-pool docker daemon --storage-opt dm.thinpooldev=/dev/mapper/thin-pool
* `dm.basesize` * `dm.basesize`
@ -216,7 +213,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt dm.basesize=20G $ docker daemon --storage-opt dm.basesize=20G
* `dm.loopdatasize` * `dm.loopdatasize`
@ -229,7 +226,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt dm.loopdatasize=200G $ docker daemon --storage-opt dm.loopdatasize=200G
* `dm.loopmetadatasize` * `dm.loopmetadatasize`
@ -242,7 +239,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt dm.loopmetadatasize=4G $ docker daemon --storage-opt dm.loopmetadatasize=4G
* `dm.fs` * `dm.fs`
@ -251,7 +248,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt dm.fs=xfs $ docker daemon --storage-opt dm.fs=xfs
* `dm.mkfsarg` * `dm.mkfsarg`
@ -259,7 +256,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt "dm.mkfsarg=-O ^has_journal" $ docker daemon --storage-opt "dm.mkfsarg=-O ^has_journal"
* `dm.mountopt` * `dm.mountopt`
@ -267,7 +264,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt dm.mountopt=nodiscard $ docker daemon --storage-opt dm.mountopt=nodiscard
* `dm.datadev` * `dm.datadev`
@ -281,7 +278,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt dm.datadev=/dev/sdb1 --storage-opt dm.metadatadev=/dev/sdc1 $ docker daemon --storage-opt dm.datadev=/dev/sdb1 --storage-opt dm.metadatadev=/dev/sdc1
* `dm.metadatadev` * `dm.metadatadev`
@ -299,7 +296,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt dm.datadev=/dev/sdb1 --storage-opt dm.metadatadev=/dev/sdc1 $ docker daemon --storage-opt dm.datadev=/dev/sdb1 --storage-opt dm.metadatadev=/dev/sdc1
* `dm.blocksize` * `dm.blocksize`
@ -308,7 +305,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt dm.blocksize=512K $ docker daemon --storage-opt dm.blocksize=512K
* `dm.blkdiscard` * `dm.blkdiscard`
@ -322,7 +319,7 @@ options for `zfs` start with `zfs`.
Example use: Example use:
$ docker -d --storage-opt dm.blkdiscard=false $ docker daemon --storage-opt dm.blkdiscard=false
* `dm.override_udev_sync_check` * `dm.override_udev_sync_check`
@ -348,7 +345,7 @@ options for `zfs` start with `zfs`.
To allow the `docker` daemon to start, regardless of `udev` sync not being To allow the `docker` daemon to start, regardless of `udev` sync not being
supported, set `dm.override_udev_sync_check` to true: supported, set `dm.override_udev_sync_check` to true:
$ docker -d --storage-opt dm.override_udev_sync_check=true $ docker daemon --storage-opt dm.override_udev_sync_check=true
When this value is `true`, the `devicemapper` continues and simply warns When this value is `true`, the `devicemapper` continues and simply warns
you the errors are happening. you the errors are happening.
@ -373,7 +370,7 @@ Currently supported options of `zfs`:
Example use: Example use:
$ docker -d -s zfs --storage-opt zfs.fsname=zroot/docker $ docker daemon -s zfs --storage-opt zfs.fsname=zroot/docker
## Docker execdriver option ## Docker execdriver option
@ -397,17 +394,17 @@ it is not available, the system uses `cgroupfs`. By default, if no option is
specified, the execdriver first tries `systemd` and falls back to `cgroupfs`. specified, the execdriver first tries `systemd` and falls back to `cgroupfs`.
This example sets the execdriver to `cgroupfs`: This example sets the execdriver to `cgroupfs`:
$ sudo docker -d --exec-opt native.cgroupdriver=cgroupfs $ sudo docker daemon --exec-opt native.cgroupdriver=cgroupfs
Setting this option applies to all containers the daemon launches. Setting this option applies to all containers the daemon launches.
## Daemon DNS options ## Daemon DNS options
To set the DNS server for all Docker containers, use To set the DNS server for all Docker containers, use
`docker -d --dns 8.8.8.8`. `docker daemon --dns 8.8.8.8`.
To set the DNS search domain for all Docker containers, use To set the DNS search domain for all Docker containers, use
`docker -d --dns-search example.com`. `docker daemon --dns-search example.com`.
## Insecure registries ## Insecure registries
@ -456,7 +453,7 @@ need to be added to your Docker host's configuration:
1. Install the `ca-certificates` package for your distribution 1. Install the `ca-certificates` package for your distribution
2. Ask your network admin for the proxy's CA certificate and append them to 2. Ask your network admin for the proxy's CA certificate and append them to
`/etc/pki/tls/certs/ca-bundle.crt` `/etc/pki/tls/certs/ca-bundle.crt`
3. Then start your Docker daemon with `HTTPS_PROXY=http://username:password@proxy:port/ docker -d`. 3. Then start your Docker daemon with `HTTPS_PROXY=http://username:password@proxy:port/ docker daemon`.
The `username:` and `password@` are optional - and are only needed if your The `username:` and `password@` are optional - and are only needed if your
proxy is set up to require authentication. proxy is set up to require authentication.
@ -486,9 +483,9 @@ Docker supports softlinks for the Docker data directory (`/var/lib/docker`) and
for `/var/lib/docker/tmp`. The `DOCKER_TMPDIR` and the data directory can be for `/var/lib/docker/tmp`. The `DOCKER_TMPDIR` and the data directory can be
set like this: set like this:
DOCKER_TMPDIR=/mnt/disk2/tmp /usr/local/bin/docker -d -D -g /var/lib/docker -H unix:// > /var/lib/boot2docker/docker.log 2>&1 DOCKER_TMPDIR=/mnt/disk2/tmp /usr/local/bin/docker daemon -D -g /var/lib/docker -H unix:// > /var/lib/boot2docker/docker.log 2>&1
# or # or
export DOCKER_TMPDIR=/mnt/disk2/tmp export DOCKER_TMPDIR=/mnt/disk2/tmp
/usr/local/bin/docker -d -D -g /var/lib/docker -H unix:// > /var/lib/boot2docker/docker.log 2>&1 /usr/local/bin/docker daemon -D -g /var/lib/docker -H unix:// > /var/lib/boot2docker/docker.log 2>&1

View file

@ -164,7 +164,7 @@ List all images with `vendor` `ACME`:
## Daemon labels ## Daemon labels
docker -d \ docker daemon \
--dns 8.8.8.8 \ --dns 8.8.8.8 \
--dns 8.8.4.4 \ --dns 8.8.4.4 \
-H unix:///var/run/docker.sock \ -H unix:///var/run/docker.sock \

View file

@ -79,7 +79,7 @@ func (s *DockerSuite) TestBuildShCmdJSONEntrypoint(c *check.C) {
out, _ := dockerCmd(c, "run", "--rm", name) out, _ := dockerCmd(c, "run", "--rm", name)
if strings.TrimSpace(out) != "/bin/sh -c echo test" { if strings.TrimSpace(out) != "/bin/sh -c echo test" {
c.Fatal("CMD did not contain /bin/sh -c") c.Fatalf("CMD did not contain /bin/sh -c : %s", out)
} }
} }

View file

@ -324,6 +324,100 @@ func (s *DockerDaemonSuite) TestDaemonLogLevelWrong(c *check.C) {
c.Assert(s.d.Start("--log-level=bogus"), check.NotNil, check.Commentf("Daemon shouldn't start with wrong log level")) c.Assert(s.d.Start("--log-level=bogus"), check.NotNil, check.Commentf("Daemon shouldn't start with wrong log level"))
} }
func (s *DockerSuite) TestDaemonStartWithBackwardCompatibility(c *check.C) {
var validCommandArgs = [][]string{
{"--selinux-enabled", "-l", "info"},
{"--insecure-registry", "daemon"},
}
var invalidCommandArgs = [][]string{
{"--selinux-enabled", "--storage-opt"},
{"-D", "-b"},
{"--config", "/tmp"},
}
for _, args := range validCommandArgs {
d := NewDaemon(c)
d.Command = "--daemon"
if err := d.Start(args...); err != nil {
c.Fatalf("Daemon should have started successfully with --daemon %v: %v", args, err)
}
d.Stop()
}
for _, args := range invalidCommandArgs {
d := NewDaemon(c)
if err := d.Start(args...); err == nil {
d.Stop()
c.Fatalf("Daemon should have failed to start with %v", args)
}
}
}
func (s *DockerSuite) TestDaemonStartWithDaemonCommand(c *check.C) {
type kind int
const (
common kind = iota
daemon
)
var flags = []map[kind][]string{
{common: {"-l", "info"}, daemon: {"--selinux-enabled"}},
{common: {"-D"}, daemon: {"--selinux-enabled", "-r"}},
{common: {"-D"}, daemon: {"--restart"}},
{common: {"--debug"}, daemon: {"--log-driver=json-file", "--log-opt=max-size=1k"}},
}
var invalidGlobalFlags = [][]string{
//Invalid because you cannot pass daemon flags as global flags.
{"--selinux-enabled", "-l", "info"},
{"-D", "-r"},
{"--config", "/tmp"},
}
// `docker daemon -l info --selinux-enabled`
// should NOT error out
for _, f := range flags {
d := NewDaemon(c)
args := append(f[common], f[daemon]...)
if err := d.Start(args...); err != nil {
c.Fatalf("Daemon should have started successfully with %v: %v", args, err)
}
d.Stop()
}
// `docker -l info daemon --selinux-enabled`
// should error out
for _, f := range flags {
d := NewDaemon(c)
d.GlobalFlags = f[common]
if err := d.Start(f[daemon]...); err == nil {
d.Stop()
c.Fatalf("Daemon should have failed to start with docker %v daemon %v", d.GlobalFlags, f[daemon])
}
}
for _, f := range invalidGlobalFlags {
cmd := exec.Command(dockerBinary, append(f, "daemon")...)
errch := make(chan error)
var err error
go func() {
errch <- cmd.Run()
}()
select {
case <-time.After(time.Second):
cmd.Process.Kill()
case err = <-errch:
}
if err == nil {
c.Fatalf("Daemon should have failed to start with docker %v daemon", f)
}
}
}
func (s *DockerDaemonSuite) TestDaemonLogLevelDebug(c *check.C) { func (s *DockerDaemonSuite) TestDaemonLogLevelDebug(c *check.C) {
if err := s.d.Start("--log-level=debug"); err != nil { if err := s.d.Start("--log-level=debug"); err != nil {
c.Fatal(err) c.Fatal(err)
@ -382,7 +476,7 @@ func (s *DockerDaemonSuite) TestDaemonAllocatesListeningPort(c *check.C) {
{"localhost", "127.0.0.1", "1235"}, {"localhost", "127.0.0.1", "1235"},
} }
cmdArgs := []string{} cmdArgs := make([]string, 0, len(listeningPorts)*2)
for _, hostDirective := range listeningPorts { for _, hostDirective := range listeningPorts {
cmdArgs = append(cmdArgs, "--host", fmt.Sprintf("tcp://%s:%s", hostDirective[0], hostDirective[2])) cmdArgs = append(cmdArgs, "--host", fmt.Sprintf("tcp://%s:%s", hostDirective[0], hostDirective[2]))
} }
@ -798,8 +892,7 @@ func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *che
c.Assert(err, check.IsNil, check.Commentf(out)) c.Assert(err, check.IsNil, check.Commentf(out))
defer deleteInterface(c, bridgeName) defer deleteInterface(c, bridgeName)
args := []string{"--bridge", bridgeName, "--icc=false"} err = s.d.StartWithBusybox("--bridge", bridgeName, "--icc=false")
err = s.d.StartWithBusybox(args...)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
defer s.d.Restart() defer s.d.Restart()
@ -1210,7 +1303,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartKillWait(c *check.C) {
// TestHttpsInfo connects via two-way authenticated HTTPS to the info endpoint // TestHttpsInfo connects via two-way authenticated HTTPS to the info endpoint
func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) { func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) {
const ( const (
testDaemonHTTPSAddr = "localhost:4271" testDaemonHTTPSAddr = "tcp://localhost:4271"
) )
if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-cert.pem", if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-cert.pem",
@ -1218,9 +1311,7 @@ func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) {
c.Fatalf("Could not start daemon with busybox: %v", err) c.Fatalf("Could not start daemon with busybox: %v", err)
} }
//force tcp protocol daemonArgs := []string{"--host", testDaemonHTTPSAddr, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-cert.pem", "--tlskey", "fixtures/https/client-key.pem"}
host := fmt.Sprintf("tcp://%s", testDaemonHTTPSAddr)
daemonArgs := []string{"--host", host, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-cert.pem", "--tlskey", "fixtures/https/client-key.pem"}
out, err := s.d.CmdWithArgs(daemonArgs, "info") out, err := s.d.CmdWithArgs(daemonArgs, "info")
if err != nil { if err != nil {
c.Fatalf("Error Occurred: %s and output: %s", err, out) c.Fatalf("Error Occurred: %s and output: %s", err, out)
@ -1232,16 +1323,15 @@ func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) {
func (s *DockerDaemonSuite) TestHttpsInfoRogueCert(c *check.C) { func (s *DockerDaemonSuite) TestHttpsInfoRogueCert(c *check.C) {
const ( const (
errBadCertificate = "remote error: bad certificate" errBadCertificate = "remote error: bad certificate"
testDaemonHTTPSAddr = "localhost:4271" testDaemonHTTPSAddr = "tcp://localhost:4271"
) )
if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-cert.pem", if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-cert.pem",
"--tlskey", "fixtures/https/server-key.pem", "-H", testDaemonHTTPSAddr); err != nil { "--tlskey", "fixtures/https/server-key.pem", "-H", testDaemonHTTPSAddr); err != nil {
c.Fatalf("Could not start daemon with busybox: %v", err) c.Fatalf("Could not start daemon with busybox: %v", err)
} }
//force tcp protocol daemonArgs := []string{"--host", testDaemonHTTPSAddr, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"}
host := fmt.Sprintf("tcp://%s", testDaemonHTTPSAddr)
daemonArgs := []string{"--host", host, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"}
out, err := s.d.CmdWithArgs(daemonArgs, "info") out, err := s.d.CmdWithArgs(daemonArgs, "info")
if err == nil || !strings.Contains(out, errBadCertificate) { if err == nil || !strings.Contains(out, errBadCertificate) {
c.Fatalf("Expected err: %s, got instead: %s and output: %s", errBadCertificate, err, out) c.Fatalf("Expected err: %s, got instead: %s and output: %s", errBadCertificate, err, out)
@ -1253,16 +1343,14 @@ func (s *DockerDaemonSuite) TestHttpsInfoRogueCert(c *check.C) {
func (s *DockerDaemonSuite) TestHttpsInfoRogueServerCert(c *check.C) { func (s *DockerDaemonSuite) TestHttpsInfoRogueServerCert(c *check.C) {
const ( const (
errCaUnknown = "x509: certificate signed by unknown authority" errCaUnknown = "x509: certificate signed by unknown authority"
testDaemonRogueHTTPSAddr = "localhost:4272" testDaemonRogueHTTPSAddr = "tcp://localhost:4272"
) )
if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-rogue-cert.pem", if err := s.d.Start("--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/server-rogue-cert.pem",
"--tlskey", "fixtures/https/server-rogue-key.pem", "-H", testDaemonRogueHTTPSAddr); err != nil { "--tlskey", "fixtures/https/server-rogue-key.pem", "-H", testDaemonRogueHTTPSAddr); err != nil {
c.Fatalf("Could not start daemon with busybox: %v", err) c.Fatalf("Could not start daemon with busybox: %v", err)
} }
//force tcp protocol daemonArgs := []string{"--host", testDaemonRogueHTTPSAddr, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"}
host := fmt.Sprintf("tcp://%s", testDaemonRogueHTTPSAddr)
daemonArgs := []string{"--host", host, "--tlsverify", "--tlscacert", "fixtures/https/ca.pem", "--tlscert", "fixtures/https/client-rogue-cert.pem", "--tlskey", "fixtures/https/client-rogue-key.pem"}
out, err := s.d.CmdWithArgs(daemonArgs, "info") out, err := s.d.CmdWithArgs(daemonArgs, "info")
if err == nil || !strings.Contains(out, errCaUnknown) { if err == nil || !strings.Contains(out, errCaUnknown) {
c.Fatalf("Expected err: %s, got instead: %s and output: %s", errCaUnknown, err, out) c.Fatalf("Expected err: %s, got instead: %s and output: %s", errCaUnknown, err, out)

View file

@ -89,10 +89,18 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
c.Fatalf("Missing 'Commands:' in:\n%s", out) c.Fatalf("Missing 'Commands:' in:\n%s", out)
} }
// Grab all chars starting at "Commands:"
// Skip first line, its "Commands:"
cmds := []string{} cmds := []string{}
for _, cmd := range strings.Split(out[i:], "\n")[1:] { // Grab all chars starting at "Commands:"
helpOut := strings.Split(out[i:], "\n")
// First line is just "Commands:"
if isLocalDaemon {
// Replace first line with "daemon" command since it's not part of the list of commands.
helpOut[0] = " daemon"
} else {
// Skip first line
helpOut = helpOut[1:]
}
for _, cmd := range helpOut {
var stderr string var stderr string
// Stop on blank line or non-idented line // Stop on blank line or non-idented line
@ -192,9 +200,10 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
// lead to incorrect test result (like false negative). // lead to incorrect test result (like false negative).
// Whatever the reason, skip trying to run w/o args and // Whatever the reason, skip trying to run w/o args and
// jump to trying with a bogus arg. // jump to trying with a bogus arg.
skipNoArgs := map[string]string{ skipNoArgs := map[string]struct{}{
"events": "", "daemon": {},
"load": "", "events": {},
"load": {},
} }
ec = 0 ec = 0
@ -230,6 +239,9 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
} }
expected := 39 expected := 39
if isLocalDaemon {
expected++ // for the daemon command
}
if len(cmds) != expected { if len(cmds) != expected {
c.Fatalf("Wrong # of cmds(%d), it should be: %d\nThe list:\n%q", c.Fatalf("Wrong # of cmds(%d), it should be: %d\nThe list:\n%q",
len(cmds), expected, cmds) len(cmds), expected, cmds)
@ -246,7 +258,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
cmd := exec.Command(dockerBinary) cmd := exec.Command(dockerBinary)
stdout, stderr, ec, err := runCommandWithStdoutStderr(cmd) stdout, stderr, ec, err := runCommandWithStdoutStderr(cmd)
if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil {
c.Fatalf("Bad results from 'docker'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) c.Fatalf("Bad results from 'docker'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err)
} }
// Be really pick // Be really pick
if strings.HasSuffix(stdout, "\n\n") { if strings.HasSuffix(stdout, "\n\n") {
@ -257,7 +269,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
cmd = exec.Command(dockerBinary, "help") cmd = exec.Command(dockerBinary, "help")
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil {
c.Fatalf("Bad results from 'docker help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) c.Fatalf("Bad results from 'docker help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err)
} }
// Be really pick // Be really pick
if strings.HasSuffix(stdout, "\n\n") { if strings.HasSuffix(stdout, "\n\n") {
@ -268,7 +280,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
cmd = exec.Command(dockerBinary, "--help") cmd = exec.Command(dockerBinary, "--help")
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil {
c.Fatalf("Bad results from 'docker --help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) c.Fatalf("Bad results from 'docker --help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err)
} }
// Be really pick // Be really pick
if strings.HasSuffix(stdout, "\n\n") { if strings.HasSuffix(stdout, "\n\n") {
@ -280,7 +292,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
cmd = exec.Command(dockerBinary, "inspect", "busybox") cmd = exec.Command(dockerBinary, "inspect", "busybox")
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil {
c.Fatalf("Bad results from 'docker inspect busybox'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) c.Fatalf("Bad results from 'docker inspect busybox'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err)
} }
// Be really pick // Be really pick
if strings.HasSuffix(stdout, "\n\n") { if strings.HasSuffix(stdout, "\n\n") {
@ -292,7 +304,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
cmd = exec.Command(dockerBinary, "rm") cmd = exec.Command(dockerBinary, "rm")
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil {
c.Fatalf("Bad results from 'docker rm'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) c.Fatalf("Bad results from 'docker rm'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err)
} }
// Should not contain full help text but should contain info about // Should not contain full help text but should contain info about
// # of args and Usage line // # of args and Usage line
@ -305,7 +317,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
cmd = exec.Command(dockerBinary, "rm", "NoSuchContainer") cmd = exec.Command(dockerBinary, "rm", "NoSuchContainer")
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil {
c.Fatalf("Bad results from 'docker rm NoSuchContainer'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) c.Fatalf("Bad results from 'docker rm NoSuchContainer'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err)
} }
// Be really picky // Be really picky
if strings.HasSuffix(stderr, "\n\n") { if strings.HasSuffix(stderr, "\n\n") {
@ -316,7 +328,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
cmd = exec.Command(dockerBinary, "BadCmd") cmd = exec.Command(dockerBinary, "BadCmd")
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil {
c.Fatalf("Bad results from 'docker BadCmd'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) c.Fatalf("Bad results from 'docker BadCmd'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err)
} }
if stderr != "docker: 'BadCmd' is not a docker command.\nSee 'docker --help'.\n" { if stderr != "docker: 'BadCmd' is not a docker command.\nSee 'docker --help'.\n" {
c.Fatalf("Unexcepted output for 'docker badCmd'\nstderr:%s", stderr) c.Fatalf("Unexcepted output for 'docker badCmd'\nstderr:%s", stderr)

View file

@ -217,6 +217,17 @@ func (s *DockerSuite) TestRunLinksContainerWithContainerId(c *check.C) {
} }
} }
// Issue 9677.
func (s *DockerSuite) TestRunWithDaemonFlags(c *check.C) {
out, _, err := dockerCmdWithError(c, "--selinux-enabled", "run", "-i", "-t", "busybox", "true")
if err != nil {
if !strings.Contains(out, "must follow the 'docker daemon' command") && // daemon
!strings.Contains(out, "flag provided but not defined: --selinux-enabled") { // no daemon (client-only)
c.Fatal(err, out)
}
}
}
// Regression test for #4979 // Regression test for #4979
func (s *DockerSuite) TestRunWithVolumesFromExited(c *check.C) { func (s *DockerSuite) TestRunWithVolumesFromExited(c *check.C) {
out, exitCode := dockerCmd(c, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file") out, exitCode := dockerCmd(c, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file")

View file

@ -29,6 +29,12 @@ import (
// Daemon represents a Docker daemon for the testing framework. // Daemon represents a Docker daemon for the testing framework.
type Daemon struct { type Daemon struct {
// Defaults to "daemon"
// Useful to set to --daemon or -d for checking backwards compatability
Command string
GlobalFlags []string
id string
c *check.C c *check.C
logFile *os.File logFile *os.File
folder string folder string
@ -59,7 +65,8 @@ func NewDaemon(c *check.C) *Daemon {
c.Fatal("Please set the DEST environment variable") c.Fatal("Please set the DEST environment variable")
} }
dir := filepath.Join(dest, fmt.Sprintf("d%d", time.Now().UnixNano()%100000000)) id := fmt.Sprintf("d%d", time.Now().UnixNano()%100000000)
dir := filepath.Join(dest, id)
daemonFolder, err := filepath.Abs(dir) daemonFolder, err := filepath.Abs(dir)
if err != nil { if err != nil {
c.Fatalf("Could not make %q an absolute path: %v", dir, err) c.Fatalf("Could not make %q an absolute path: %v", dir, err)
@ -77,6 +84,8 @@ func NewDaemon(c *check.C) *Daemon {
} }
return &Daemon{ return &Daemon{
Command: "daemon",
id: id,
c: c, c: c,
folder: daemonFolder, folder: daemonFolder,
storageDriver: os.Getenv("DOCKER_GRAPHDRIVER"), storageDriver: os.Getenv("DOCKER_GRAPHDRIVER"),
@ -90,22 +99,22 @@ func NewDaemon(c *check.C) *Daemon {
func (d *Daemon) Start(arg ...string) error { func (d *Daemon) Start(arg ...string) error {
dockerBinary, err := exec.LookPath(dockerBinary) dockerBinary, err := exec.LookPath(dockerBinary)
if err != nil { if err != nil {
d.c.Fatalf("could not find docker binary in $PATH: %v", err) d.c.Fatalf("[%s] could not find docker binary in $PATH: %v", d.id, err)
} }
args := []string{ args := append(d.GlobalFlags,
d.Command,
"--host", d.sock(), "--host", d.sock(),
"--daemon",
"--graph", fmt.Sprintf("%s/graph", d.folder), "--graph", fmt.Sprintf("%s/graph", d.folder),
"--pidfile", fmt.Sprintf("%s/docker.pid", d.folder), "--pidfile", fmt.Sprintf("%s/docker.pid", d.folder),
fmt.Sprintf("--userland-proxy=%t", d.userlandProxy), fmt.Sprintf("--userland-proxy=%t", d.userlandProxy),
} )
// If we don't explicitly set the log-level or debug flag(-D) then // If we don't explicitly set the log-level or debug flag(-D) then
// turn on debug mode // turn on debug mode
foundIt := false foundIt := false
for _, a := range arg { for _, a := range arg {
if strings.Contains(a, "--log-level") || strings.Contains(a, "-D") { if strings.Contains(a, "--log-level") || strings.Contains(a, "-D") || strings.Contains(a, "--debug") {
foundIt = true foundIt = true
} }
} }
@ -125,21 +134,21 @@ func (d *Daemon) Start(arg ...string) error {
d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
if err != nil { if err != nil {
d.c.Fatalf("Could not create %s/docker.log: %v", d.folder, err) d.c.Fatalf("[%s] Could not create %s/docker.log: %v", d.id, d.folder, err)
} }
d.cmd.Stdout = d.logFile d.cmd.Stdout = d.logFile
d.cmd.Stderr = d.logFile d.cmd.Stderr = d.logFile
if err := d.cmd.Start(); err != nil { if err := d.cmd.Start(); err != nil {
return fmt.Errorf("could not start daemon container: %v", err) return fmt.Errorf("[%s] could not start daemon container: %v", d.id, err)
} }
wait := make(chan error) wait := make(chan error)
go func() { go func() {
wait <- d.cmd.Wait() wait <- d.cmd.Wait()
d.c.Log("exiting daemon") d.c.Logf("[%s] exiting daemon", d.id)
close(wait) close(wait)
}() }()
@ -149,14 +158,14 @@ func (d *Daemon) Start(arg ...string) error {
// make sure daemon is ready to receive requests // make sure daemon is ready to receive requests
startTime := time.Now().Unix() startTime := time.Now().Unix()
for { for {
d.c.Log("waiting for daemon to start") d.c.Logf("[%s] waiting for daemon to start", d.id)
if time.Now().Unix()-startTime > 5 { if time.Now().Unix()-startTime > 5 {
// After 5 seconds, give up // After 5 seconds, give up
return errors.New("Daemon exited and never started") return fmt.Errorf("[%s] Daemon exited and never started", d.id)
} }
select { select {
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
return errors.New("timeout: daemon does not respond") return fmt.Errorf("[%s] timeout: daemon does not respond", d.id)
case <-tick: case <-tick:
c, err := net.Dial("unix", filepath.Join(d.folder, "docker.sock")) c, err := net.Dial("unix", filepath.Join(d.folder, "docker.sock"))
if err != nil { if err != nil {
@ -168,7 +177,7 @@ func (d *Daemon) Start(arg ...string) error {
req, err := http.NewRequest("GET", "/_ping", nil) req, err := http.NewRequest("GET", "/_ping", nil)
if err != nil { if err != nil {
d.c.Fatalf("could not create new request: %v", err) d.c.Fatalf("[%s] could not create new request: %v", d.id, err)
} }
resp, err := client.Do(req) resp, err := client.Do(req)
@ -176,10 +185,10 @@ func (d *Daemon) Start(arg ...string) error {
continue continue
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
d.c.Logf("received status != 200 OK: %s", resp.Status) d.c.Logf("[%s] received status != 200 OK: %s", d.id, resp.Status)
} }
d.c.Log("daemon started") d.c.Logf("[%s] daemon started", d.id)
return nil return nil
} }
} }

7
opts/hosts_unix.go Normal file
View file

@ -0,0 +1,7 @@
// +build !windows
package opts
import "fmt"
var DefaultHost = fmt.Sprintf("unix://%s", DefaultUnixSocket)

7
opts/hosts_windows.go Normal file
View file

@ -0,0 +1,7 @@
// +build windows
package opts
import "fmt"
var DefaultHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)

View file

@ -32,37 +32,37 @@ var (
// ListVar Defines a flag with the specified names and usage, and put the value // ListVar Defines a flag with the specified names and usage, and put the value
// list into ListOpts that will hold the values. // list into ListOpts that will hold the values.
func ListVar(values *[]string, names []string, usage string) { func ListVar(values *[]string, names []string, usage string) {
flag.Var(newListOptsRef(values, nil), names, usage) flag.Var(NewListOptsRef(values, nil), names, usage)
} }
// MapVar Defines a flag with the specified names and usage, and put the value // MapVar Defines a flag with the specified names and usage, and put the value
// map into MapOpt that will hold the values (key,value). // map into MapOpt that will hold the values (key,value).
func MapVar(values map[string]string, names []string, usage string) { func MapVar(values map[string]string, names []string, usage string) {
flag.Var(newMapOpt(values, nil), names, usage) flag.Var(NewMapOpts(values, nil), names, usage)
} }
// LogOptsVar Defines a flag with the specified names and usage for --log-opts, // LogOptsVar Defines a flag with the specified names and usage for --log-opts,
// and put the value map into MapOpt that will hold the values (key,value). // and put the value map into MapOpt that will hold the values (key,value).
func LogOptsVar(values map[string]string, names []string, usage string) { func LogOptsVar(values map[string]string, names []string, usage string) {
flag.Var(newMapOpt(values, nil), names, usage) flag.Var(NewMapOpts(values, nil), names, usage)
} }
// HostListVar Defines a flag with the specified names and usage and put the // HostListVar Defines a flag with the specified names and usage and put the
// value into a ListOpts that will hold the values, validating the Host format. // value into a ListOpts that will hold the values, validating the Host format.
func HostListVar(values *[]string, names []string, usage string) { func HostListVar(values *[]string, names []string, usage string) {
flag.Var(newListOptsRef(values, ValidateHost), names, usage) flag.Var(NewListOptsRef(values, ValidateHost), names, usage)
} }
// IPListVar Defines a flag with the specified names and usage and put the // IPListVar Defines a flag with the specified names and usage and put the
// value into a ListOpts that will hold the values, validating the IP format. // value into a ListOpts that will hold the values, validating the IP format.
func IPListVar(values *[]string, names []string, usage string) { func IPListVar(values *[]string, names []string, usage string) {
flag.Var(newListOptsRef(values, ValidateIPAddress), names, usage) flag.Var(NewListOptsRef(values, ValidateIPAddress), names, usage)
} }
// DNSSearchListVar Defines a flag with the specified names and usage and put the // DNSSearchListVar Defines a flag with the specified names and usage and put the
// value into a ListOpts that will hold the values, validating the DNS search format. // value into a ListOpts that will hold the values, validating the DNS search format.
func DNSSearchListVar(values *[]string, names []string, usage string) { func DNSSearchListVar(values *[]string, names []string, usage string) {
flag.Var(newListOptsRef(values, ValidateDNSSearch), names, usage) flag.Var(NewListOptsRef(values, ValidateDNSSearch), names, usage)
} }
// IPVar Defines a flag with the specified names and usage for IP and will use // 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) {
// LabelListVar Defines a flag with the specified names and usage and put the // LabelListVar Defines a flag with the specified names and usage and put the
// value into a ListOpts that will hold the values, validating the label format. // value into a ListOpts that will hold the values, validating the label format.
func LabelListVar(values *[]string, names []string, usage string) { func LabelListVar(values *[]string, names []string, usage string) {
flag.Var(newListOptsRef(values, ValidateLabel), names, usage) flag.Var(NewListOptsRef(values, ValidateLabel), names, usage)
} }
// UlimitMapVar Defines a flag with the specified names and usage for --ulimit, // UlimitMapVar Defines a flag with the specified names and usage for --ulimit,
// and put the value map into a UlimitOpt that will hold the values. // and put the value map into a UlimitOpt that will hold the values.
func UlimitMapVar(values map[string]*ulimit.Ulimit, names []string, usage string) { func UlimitMapVar(values *map[string]*ulimit.Ulimit, names []string, usage string) {
flag.Var(NewUlimitOpt(values), names, usage) flag.Var(NewUlimitOpt(values), names, usage)
} }
@ -92,10 +92,10 @@ type ListOpts struct {
// NewListOpts Create a new ListOpts with the specified validator. // NewListOpts Create a new ListOpts with the specified validator.
func NewListOpts(validator ValidatorFctType) ListOpts { func NewListOpts(validator ValidatorFctType) ListOpts {
var values []string var values []string
return *newListOptsRef(&values, validator) return *NewListOptsRef(&values, validator)
} }
func newListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts { func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
return &ListOpts{ return &ListOpts{
values: values, values: values,
validator: validator, validator: validator,
@ -191,7 +191,10 @@ func (opts *MapOpts) String() string {
return fmt.Sprintf("%v", map[string]string((opts.values))) return fmt.Sprintf("%v", map[string]string((opts.values)))
} }
func newMapOpt(values map[string]string, validator ValidatorFctType) *MapOpts { func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
if values == nil {
values = make(map[string]string)
}
return &MapOpts{ return &MapOpts{
values: values, values: values,
validator: validator, validator: validator,

View file

@ -32,7 +32,7 @@ func TestValidateIPAddress(t *testing.T) {
func TestMapOpts(t *testing.T) { func TestMapOpts(t *testing.T) {
tmpMap := make(map[string]string) tmpMap := make(map[string]string)
o := newMapOpt(tmpMap, logOptsValidator) o := NewMapOpts(tmpMap, logOptsValidator)
o.Set("max-size=1") o.Set("max-size=1")
if o.String() != "map[max-size:1]" { if o.String() != "map[max-size:1]" {
t.Errorf("%s != [map[max-size:1]", o.String()) t.Errorf("%s != [map[max-size:1]", o.String())

View file

@ -7,10 +7,13 @@ import (
) )
type UlimitOpt struct { type UlimitOpt struct {
values map[string]*ulimit.Ulimit values *map[string]*ulimit.Ulimit
} }
func NewUlimitOpt(ref map[string]*ulimit.Ulimit) *UlimitOpt { func NewUlimitOpt(ref *map[string]*ulimit.Ulimit) *UlimitOpt {
if ref == nil {
ref = &map[string]*ulimit.Ulimit{}
}
return &UlimitOpt{ref} return &UlimitOpt{ref}
} }
@ -20,14 +23,14 @@ func (o *UlimitOpt) Set(val string) error {
return err return err
} }
o.values[l.Name] = l (*o.values)[l.Name] = l
return nil return nil
} }
func (o *UlimitOpt) String() string { func (o *UlimitOpt) String() string {
var out []string var out []string
for _, v := range o.values { for _, v := range *o.values {
out = append(out, v.String()) out = append(out, v.String())
} }
@ -36,7 +39,7 @@ func (o *UlimitOpt) String() string {
func (o *UlimitOpt) GetList() []*ulimit.Ulimit { func (o *UlimitOpt) GetList() []*ulimit.Ulimit {
var ulimits []*ulimit.Ulimit var ulimits []*ulimit.Ulimit
for _, v := range o.values { for _, v := range *o.values {
ulimits = append(ulimits, v) ulimits = append(ulimits, v)
} }

View file

@ -11,7 +11,7 @@ func TestUlimitOpt(t *testing.T) {
"nofile": {"nofile", 1024, 512}, "nofile": {"nofile", 1024, 512},
} }
ulimitOpt := NewUlimitOpt(ulimitMap) ulimitOpt := NewUlimitOpt(&ulimitMap)
expected := "[nofile=512:1024]" expected := "[nofile=512:1024]"
if ulimitOpt.String() != expected { if ulimitOpt.String() != expected {

View file

@ -526,7 +526,7 @@ func (f *FlagSet) PrintDefaults() {
names = append(names, name) names = append(names, name)
} }
} }
if len(names) > 0 { if len(names) > 0 && len(flag.Usage) > 0 {
val := flag.DefValue val := flag.DefValue
if home != "" && strings.HasPrefix(val, home) { if home != "" && strings.HasPrefix(val, home) {
@ -1143,3 +1143,53 @@ func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
f.name = name f.name = name
f.errorHandling = errorHandling f.errorHandling = errorHandling
} }
type mergeVal struct {
Value
key string
fset *FlagSet
}
func (v mergeVal) Set(s string) error {
return v.fset.Set(v.key, s)
}
func (v mergeVal) IsBoolFlag() bool {
if b, ok := v.Value.(boolFlag); ok {
return b.IsBoolFlag()
}
return false
}
func Merge(dest *FlagSet, flagsets ...*FlagSet) error {
for _, fset := range flagsets {
for k, f := range fset.formal {
if _, ok := dest.formal[k]; ok {
var err error
if fset.name == "" {
err = fmt.Errorf("flag redefined: %s", k)
} else {
err = fmt.Errorf("%s flag redefined: %s", fset.name, k)
}
fmt.Fprintln(fset.Out(), err.Error())
// Happens only if flags are declared with identical names
switch dest.errorHandling {
case ContinueOnError:
return err
case ExitOnError:
os.Exit(2)
case PanicOnError:
panic(err)
}
}
newF := *f
newF.Value = mergeVal{f.Value, k, fset}
dest.formal[k] = &newF
}
}
return nil
}
func (f *FlagSet) IsEmpty() bool {
return len(f.actual) == 0
}

View file

@ -17,11 +17,18 @@ import (
// Options represents the information needed to create client and server TLS configurations. // Options represents the information needed to create client and server TLS configurations.
type Options struct { type Options struct {
CAFile string
// If either CertFile or KeyFile is empty, Client() will not load them
// preventing the client from authenticating to the server.
// However, Server() requires them and will error out if they are empty.
CertFile string
KeyFile string
// client-only option
InsecureSkipVerify bool InsecureSkipVerify bool
ClientAuth tls.ClientAuthType // server-only option
CAFile string ClientAuth tls.ClientAuthType
CertFile string
KeyFile string
} }
// Extra (server-side) accepted CBC cipher suites - will phase out in the future // Extra (server-side) accepted CBC cipher suites - will phase out in the future

View file

@ -43,11 +43,11 @@ var (
// InstallFlags adds command-line options to the top-level flag parser for // InstallFlags adds command-line options to the top-level flag parser for
// the current process. // the current process.
func (options *Options) InstallFlags() { func (options *Options) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
options.Mirrors = opts.NewListOpts(ValidateMirror) options.Mirrors = opts.NewListOpts(ValidateMirror)
flag.Var(&options.Mirrors, []string{"-registry-mirror"}, "Preferred Docker registry mirror") cmd.Var(&options.Mirrors, []string{"-registry-mirror"}, usageFn("Preferred Docker registry mirror"))
options.InsecureRegistries = opts.NewListOpts(ValidateIndexName) options.InsecureRegistries = opts.NewListOpts(ValidateIndexName)
flag.Var(&options.InsecureRegistries, []string{"-insecure-registry"}, "Enable insecure registry communication") cmd.Var(&options.InsecureRegistries, []string{"-insecure-registry"}, usageFn("Enable insecure registry communication"))
} }
type netIPNet net.IPNet type netIPNet net.IPNet

View file

@ -9,7 +9,6 @@ import (
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat" "github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/ulimit"
"github.com/docker/docker/pkg/units" "github.com/docker/docker/pkg/units"
) )
@ -48,8 +47,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
flLabels = opts.NewListOpts(opts.ValidateEnv) flLabels = opts.NewListOpts(opts.ValidateEnv)
flDevices = opts.NewListOpts(opts.ValidateDevice) flDevices = opts.NewListOpts(opts.ValidateDevice)
ulimits = make(map[string]*ulimit.Ulimit) flUlimits = opts.NewUlimitOpt(nil)
flUlimits = opts.NewUlimitOpt(ulimits)
flPublish = opts.NewListOpts(nil) flPublish = opts.NewListOpts(nil)
flExpose = opts.NewListOpts(nil) flExpose = opts.NewListOpts(nil)