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:
commit
7674f21686
86 changed files with 1126 additions and 709 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
)
|
||||
|
@ -16,9 +17,10 @@ import (
|
|||
//
|
||||
// Usage: docker attach [OPTIONS] CONTAINER
|
||||
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")
|
||||
proxy := cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
@ -75,7 +77,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
|
|||
return err
|
||||
}
|
||||
if status != 0 {
|
||||
return StatusError{StatusCode: status}
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/graph/tags"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
|
@ -46,7 +47,7 @@ const (
|
|||
//
|
||||
// Usage: docker build [OPTIONS] PATH | URL | -
|
||||
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")
|
||||
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")
|
||||
|
@ -64,7 +65,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||
flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
|
||||
|
||||
ulimits := make(map[string]*ulimit.Ulimit)
|
||||
flUlimits := opts.NewUlimitOpt(ulimits)
|
||||
flUlimits := opts.NewUlimitOpt(&ulimits)
|
||||
cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
@ -325,7 +326,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||
if jerr.Code == 0 {
|
||||
jerr.Code = 1
|
||||
}
|
||||
return StatusError{Status: jerr.Message, StatusCode: jerr.Code}
|
||||
return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -2,25 +2,28 @@ package client
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/docker/docker/cli"
|
||||
"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/term"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
)
|
||||
|
||||
// DockerCli represents the docker command line client.
|
||||
// Instances of the client can be returned from NewDockerCli.
|
||||
type DockerCli struct {
|
||||
// initializing closure
|
||||
init func() error
|
||||
|
||||
// proto holds the client protocol i.e. unix.
|
||||
proto string
|
||||
// addr holds the client address.
|
||||
|
@ -55,116 +58,11 @@ type DockerCli struct {
|
|||
transport *http.Transport
|
||||
}
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"json": func(v interface{}) string {
|
||||
a, _ := json.Marshal(v)
|
||||
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:])
|
||||
func (cli *DockerCli) Initialize() error {
|
||||
if cli.init == nil {
|
||||
return nil
|
||||
}
|
||||
methodName := "Cmd" + strings.Join(camelArgs, "")
|
||||
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
|
||||
return cli.init()
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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).
|
||||
func NewDockerCli(in io.ReadCloser, out, err io.Writer, keyFile string, proto, addr string, tlsConfig *tls.Config) *DockerCli {
|
||||
var (
|
||||
inFd uintptr
|
||||
outFd uintptr
|
||||
isTerminalIn = false
|
||||
isTerminalOut = false
|
||||
scheme = "http"
|
||||
basePath = ""
|
||||
)
|
||||
|
||||
if tlsConfig != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
if in != nil {
|
||||
inFd, isTerminalIn = term.GetFdInfo(in)
|
||||
func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli {
|
||||
cli := &DockerCli{
|
||||
in: in,
|
||||
out: out,
|
||||
err: err,
|
||||
keyFile: clientFlags.Common.TrustKey,
|
||||
}
|
||||
|
||||
if out != nil {
|
||||
outFd, isTerminalOut = term.GetFdInfo(out)
|
||||
cli.init = func() error {
|
||||
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 {
|
||||
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,
|
||||
}
|
||||
return cli
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
// See https://docs.docker.com/installation/ for instructions on installing Docker.
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/url"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
|
@ -17,7 +18,7 @@ import (
|
|||
//
|
||||
// Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
|
||||
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")
|
||||
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>\")")
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
@ -37,7 +38,7 @@ const (
|
|||
// docker cp CONTAINER:PATH LOCALPATH|-
|
||||
// docker cp LOCALPATH|- CONTAINER:PATH
|
||||
func (cli *DockerCli) CmdCp(args ...string) error {
|
||||
cmd := cli.Subcmd(
|
||||
cmd := Cli.Subcmd(
|
||||
"cp",
|
||||
[]string{"CONTAINER:PATH LOCALPATH|-", "LOCALPATH|- CONTAINER:PATH"},
|
||||
strings.Join([]string{
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/graph/tags"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"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...]
|
||||
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
|
||||
var (
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
@ -17,7 +18,7 @@ import (
|
|||
//
|
||||
// Usage: docker diff CONTAINER
|
||||
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.ParseFlags(args, true)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"net/url"
|
||||
"time"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/parsers/filters"
|
||||
|
@ -14,7 +15,7 @@ import (
|
|||
//
|
||||
// Usage: docker events [OPTIONS]
|
||||
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")
|
||||
until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
|
||||
flFilter := opts.NewListOpts(nil)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/pkg/promise"
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
@ -15,12 +16,12 @@ import (
|
|||
//
|
||||
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
|
||||
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)
|
||||
// just in case the ParseExec does not exit
|
||||
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)
|
||||
|
@ -126,7 +127,7 @@ func (cli *DockerCli) CmdExec(args ...string) error {
|
|||
}
|
||||
|
||||
if status != 0 {
|
||||
return StatusError{StatusCode: status}
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -14,7 +15,7 @@ import (
|
|||
//
|
||||
// Usage: docker export [OPTIONS] CONTAINER
|
||||
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")
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
|
@ -17,7 +18,7 @@ import (
|
|||
//
|
||||
// Usage: docker history [OPTIONS] IMAGE
|
||||
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")
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
|
||||
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
|
@ -21,7 +22,7 @@ import (
|
|||
//
|
||||
// Usage: docker images [OPTIONS] [REPOSITORY]
|
||||
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")
|
||||
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")
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
|
@ -19,7 +20,7 @@ import (
|
|||
//
|
||||
// Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
|
||||
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)
|
||||
cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/pkg/httputils"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
|
@ -15,7 +16,7 @@ import (
|
|||
//
|
||||
// Usage: docker info
|
||||
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.ParseFlags(args, true)
|
||||
|
|
|
@ -9,14 +9,22 @@ import (
|
|||
"text/template"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
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.
|
||||
//
|
||||
// Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]
|
||||
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")
|
||||
inspectType := cmd.String([]string{"-type"}, "", "Return JSON for specified type, (e.g image or container)")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
@ -29,7 +37,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
|
|||
|
||||
if *tmplStr != "" {
|
||||
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()}
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +151,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
|
|||
}
|
||||
|
||||
if status != 0 {
|
||||
return StatusError{StatusCode: status}
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package client
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -10,7 +11,7 @@ import (
|
|||
//
|
||||
// Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
|
||||
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")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -13,7 +14,7 @@ import (
|
|||
//
|
||||
// Usage: docker load [OPTIONS]
|
||||
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")
|
||||
cmd.Require(flag.Exact, 0)
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
|
@ -21,7 +22,7 @@ import (
|
|||
//
|
||||
// Usage: docker login SERVER
|
||||
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)
|
||||
|
||||
var username, password, email string
|
||||
|
|
|
@ -3,6 +3,7 @@ package client
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/registry"
|
||||
)
|
||||
|
@ -13,7 +14,7 @@ import (
|
|||
//
|
||||
// Usage: docker logout [SERVER]
|
||||
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.ParseFlags(args, true)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/timeutils"
|
||||
)
|
||||
|
@ -15,7 +16,7 @@ import (
|
|||
//
|
||||
// docker logs [OPTIONS] CONTAINER
|
||||
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")
|
||||
since := cmd.String([]string{"-since"}, "", "Show logs since timestamp")
|
||||
times := cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
|
||||
|
|
|
@ -3,6 +3,7 @@ package client
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -10,7 +11,7 @@ import (
|
|||
//
|
||||
// Usage: docker pause CONTAINER [CONTAINER...]
|
||||
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.ParseFlags(args, true)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/nat"
|
||||
)
|
||||
|
@ -14,7 +15,7 @@ import (
|
|||
//
|
||||
// Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]]
|
||||
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.ParseFlags(args, true)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/docker/docker/api/client/ps"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/parsers/filters"
|
||||
|
@ -22,7 +23,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
|||
psFilterArgs = filters.Args{}
|
||||
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")
|
||||
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)")
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"net/url"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/graph/tags"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
|
@ -15,7 +16,7 @@ import (
|
|||
//
|
||||
// Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST]
|
||||
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")
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"net/url"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/registry"
|
||||
|
@ -13,7 +14,7 @@ import (
|
|||
//
|
||||
// Usage: docker push NAME[:TAG]
|
||||
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.ParseFlags(args, true)
|
||||
|
|
|
@ -3,6 +3,7 @@ package client
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -10,7 +11,7 @@ import (
|
|||
//
|
||||
// Usage: docker rename OLD_NAME NEW_NAME
|
||||
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.ParseFlags(args, true)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/url"
|
||||
"strconv"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -12,7 +13,7 @@ import (
|
|||
//
|
||||
// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
|
||||
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")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -12,7 +13,7 @@ import (
|
|||
//
|
||||
// Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
|
||||
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")
|
||||
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)")
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/url"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -13,7 +14,7 @@ import (
|
|||
//
|
||||
// Usage: docker rmi [OPTIONS] IMAGE [IMAGE...]
|
||||
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")
|
||||
noprune := cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"runtime"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/promise"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
|
@ -39,7 +40,7 @@ func (cid *cidFile) Write(id string) error {
|
|||
//
|
||||
// Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
|
||||
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
|
||||
var (
|
||||
|
@ -249,7 +250,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||
}
|
||||
}
|
||||
if status != 0 {
|
||||
return StatusError{StatusCode: status}
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -15,7 +16,7 @@ import (
|
|||
//
|
||||
// Usage: docker save [OPTIONS] IMAGE [IMAGE...]
|
||||
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")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"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
|
||||
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")
|
||||
trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
|
||||
automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/promise"
|
||||
"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...]
|
||||
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")
|
||||
openStdin := cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
@ -162,7 +163,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
|
|||
return err
|
||||
}
|
||||
if status != 0 {
|
||||
return StatusError{StatusCode: status}
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/units"
|
||||
)
|
||||
|
@ -124,7 +125,7 @@ func (s *containerStats) Display(w io.Writer) error {
|
|||
//
|
||||
// Usage: docker stats CONTAINER [CONTAINER...]
|
||||
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")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/url"
|
||||
"strconv"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -14,7 +15,7 @@ import (
|
|||
//
|
||||
// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
|
||||
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")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package client
|
|||
import (
|
||||
"net/url"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/registry"
|
||||
|
@ -12,7 +13,7 @@ import (
|
|||
//
|
||||
// Usage: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
|
||||
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")
|
||||
cmd.Require(flag.Exact, 2)
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"text/tabwriter"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -15,7 +16,7 @@ import (
|
|||
//
|
||||
// Usage: docker top CONTAINER
|
||||
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.ParseFlags(args, true)
|
||||
|
|
|
@ -3,6 +3,7 @@ package client
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -10,7 +11,7 @@ import (
|
|||
//
|
||||
// Usage: docker unpause CONTAINER [CONTAINER...]
|
||||
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.ParseFlags(args, true)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/autogen/dockerversion"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
|
@ -42,7 +43,7 @@ type VersionData struct {
|
|||
//
|
||||
// Usage: docker version
|
||||
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")
|
||||
cmd.Require(flag.Exact, 0)
|
||||
|
||||
|
@ -53,7 +54,7 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
|
|||
|
||||
var tmpl *template.Template
|
||||
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()}
|
||||
}
|
||||
|
||||
|
@ -85,7 +86,7 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
|
|||
defer serverResp.body.Close()
|
||||
|
||||
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()}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package client
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
)
|
||||
|
||||
|
@ -12,7 +13,7 @@ import (
|
|||
//
|
||||
// Usage: docker wait CONTAINER [CONTAINER...]
|
||||
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.ParseFlags(args, true)
|
||||
|
|
200
cli/cli.go
Normal file
200
cli/cli.go
Normal 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
12
cli/client.go
Normal 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
20
cli/common.go
Normal 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
|
||||
}
|
|
@ -41,22 +41,22 @@ type CommonConfig struct {
|
|||
// the current process.
|
||||
// Subsequent calls to `flag.Parse` will populate config with values parsed
|
||||
// from the command-line.
|
||||
func (config *Config) InstallCommonFlags() {
|
||||
opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options")
|
||||
opts.ListVar(&config.ExecOptions, []string{"-exec-opt"}, "Set exec driver options")
|
||||
flag.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, "Path to use for daemon PID file")
|
||||
flag.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, "Root of the Docker runtime")
|
||||
flag.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", "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")
|
||||
flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Storage driver to use")
|
||||
flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, "Exec driver to use")
|
||||
flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "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")
|
||||
flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API")
|
||||
func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string) string) {
|
||||
cmd.Var(opts.NewListOptsRef(&config.GraphOptions, nil), []string{"-storage-opt"}, usageFn("Set storage driver options"))
|
||||
cmd.Var(opts.NewListOptsRef(&config.ExecOptions, nil), []string{"-exec-opt"}, usageFn("Set exec driver options"))
|
||||
cmd.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, usageFn("Path to use for daemon PID file"))
|
||||
cmd.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, usageFn("Root of the Docker runtime"))
|
||||
cmd.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", usageFn("Root of the Docker execdriver"))
|
||||
cmd.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, usageFn("--restart on the daemon has been deprecated in favor of --restart policies on docker run"))
|
||||
cmd.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", usageFn("Storage driver to use"))
|
||||
cmd.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, usageFn("Exec driver to use"))
|
||||
cmd.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, usageFn("Set the containers network MTU"))
|
||||
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"))
|
||||
cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
|
||||
// FIXME: why the inconsistency between "hosts" and "sockets"?
|
||||
opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use")
|
||||
opts.DNSSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "DNS search domains to use")
|
||||
opts.LabelListVar(&config.Labels, []string{"-label"}, "Set key=value labels to the daemon")
|
||||
flag.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", "Default driver for container logs")
|
||||
opts.LogOptsVar(config.LogConfig.Config, []string{"-log-opt"}, "Set log driver options")
|
||||
cmd.Var(opts.NewListOptsRef(&config.Dns, opts.ValidateIPAddress), []string{"#dns", "-dns"}, usageFn("DNS server to use"))
|
||||
cmd.Var(opts.NewListOptsRef(&config.DnsSearch, opts.ValidateDNSSearch), []string{"-dns-search"}, usageFn("DNS search domains to use"))
|
||||
cmd.Var(opts.NewListOptsRef(&config.Labels, opts.ValidateLabel), []string{"-label"}, usageFn("Set key=value labels to the daemon"))
|
||||
cmd.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", usageFn("Default driver for container logs"))
|
||||
cmd.Var(opts.NewMapOpts(config.LogConfig.Config, nil), []string{"-log-opt"}, usageFn("Set log driver options"))
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ package daemon
|
|||
|
||||
import flag "github.com/docker/docker/pkg/mflag"
|
||||
|
||||
func (config *Config) attachExperimentalFlags() {
|
||||
flag.StringVar(&config.DefaultNetwork, []string{"-default-network"}, "", "Set default network")
|
||||
flag.StringVar(&config.NetworkKVStore, []string{"-kv-store"}, "", "Set KV Store configuration")
|
||||
func (config *Config) attachExperimentalFlags(cmd *flag.FlagSet, usageFn func(string) string) {
|
||||
cmd.StringVar(&config.DefaultNetwork, []string{"-default-network"}, "", usageFn("Set default network"))
|
||||
cmd.StringVar(&config.NetworkKVStore, []string{"-kv-store"}, "", usageFn("Set KV Store configuration"))
|
||||
}
|
||||
|
|
|
@ -49,27 +49,28 @@ type bridgeConfig struct {
|
|||
// the current process.
|
||||
// Subsequent calls to `flag.Parse` will populate config with values parsed
|
||||
// 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
|
||||
config.InstallCommonFlags()
|
||||
config.InstallCommonFlags(cmd, usageFn)
|
||||
|
||||
// Then platform-specific install flags
|
||||
flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support")
|
||||
flag.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", "Group for the unix socket")
|
||||
cmd.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, usageFn("Enable selinux support"))
|
||||
cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", usageFn("Group for the unix socket"))
|
||||
config.Ulimits = make(map[string]*ulimit.Ulimit)
|
||||
opts.UlimitMapVar(config.Ulimits, []string{"-default-ulimit"}, "Set default ulimits for containers")
|
||||
flag.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
|
||||
flag.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
|
||||
flag.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
|
||||
flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking")
|
||||
flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP")
|
||||
flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
|
||||
flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs")
|
||||
flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs")
|
||||
opts.IPVar(&config.Bridge.DefaultGatewayIPv4, []string{"-default-gateway"}, "", "Container default gateway IPv4 address")
|
||||
opts.IPVar(&config.Bridge.DefaultGatewayIPv6, []string{"-default-gateway-v6"}, "", "Container default gateway IPv6 address")
|
||||
flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
|
||||
opts.IPVar(&config.Bridge.DefaultIP, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
|
||||
flag.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, "Use userland proxy for loopback traffic")
|
||||
config.attachExperimentalFlags()
|
||||
cmd.Var(opts.NewUlimitOpt(&config.Ulimits), []string{"-default-ulimit"}, usageFn("Set default ulimits for containers"))
|
||||
cmd.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, usageFn("Enable addition of iptables rules"))
|
||||
cmd.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, usageFn("Enable net.ipv4.ip_forward"))
|
||||
cmd.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, usageFn("Enable IP masquerading"))
|
||||
cmd.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, usageFn("Enable IPv6 networking"))
|
||||
cmd.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", usageFn("Specify network bridge IP"))
|
||||
cmd.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", usageFn("Attach containers to a network bridge"))
|
||||
cmd.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", usageFn("IPv4 subnet for fixed IPs"))
|
||||
cmd.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", usageFn("IPv6 subnet for fixed IPs"))
|
||||
cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultGatewayIPv4, ""), []string{"-default-gateway"}, usageFn("Container default gateway IPv4 address"))
|
||||
cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultGatewayIPv6, ""), []string{"-default-gateway-v6"}, usageFn("Container default gateway IPv6 address"))
|
||||
cmd.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, usageFn("Enable inter-container communication"))
|
||||
cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultIP, "0.0.0.0"), []string{"#ip", "-ip"}, usageFn("Default IP when binding container ports"))
|
||||
cmd.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
|
||||
|
||||
config.attachExperimentalFlags(cmd, usageFn)
|
||||
}
|
||||
|
|
|
@ -2,5 +2,7 @@
|
|||
|
||||
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) {
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@ type Config struct {
|
|||
// the current process.
|
||||
// Subsequent calls to `flag.Parse` will populate config with values parsed
|
||||
// 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
|
||||
config.InstallCommonFlags()
|
||||
config.InstallCommonFlags(cmd, usageFn)
|
||||
|
||||
// Then platform-specific install flags.
|
||||
flag.StringVar(&config.Bridge.VirtualSwitchName, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch")
|
||||
|
|
|
@ -1,11 +1,28 @@
|
|||
// +build !daemon
|
||||
|
||||
package main
|
||||
|
||||
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() {
|
||||
log.Fatal("This is a client-only binary - running the Docker daemon is not supported.")
|
||||
var clientFlags = &cli.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags}
|
||||
|
||||
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
101
docker/common.go
Normal 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 = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
164
docker/daemon.go
164
docker/daemon.go
|
@ -8,14 +8,18 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
apiserver "github.com/docker/docker/api/server"
|
||||
"github.com/docker/docker/autogen/dockerversion"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/daemon/logger"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/pidfile"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
|
@ -26,17 +30,63 @@ import (
|
|||
"github.com/docker/docker/utils"
|
||||
)
|
||||
|
||||
const daemonUsage = " docker daemon [ --help | ... ]\n"
|
||||
|
||||
var (
|
||||
daemonCfg = &daemon.Config{}
|
||||
registryCfg = ®istry.Options{}
|
||||
flDaemon = flag.Bool([]string{"#d", "#-daemon"}, false, "Enable daemon mode (deprecated; use docker daemon)")
|
||||
daemonCli cli.Handler = NewDaemonCli()
|
||||
)
|
||||
|
||||
func init() {
|
||||
if daemonCfg.LogConfig.Config == nil {
|
||||
daemonCfg.LogConfig.Config = make(map[string]string)
|
||||
// TODO: remove once `-d` is retired
|
||||
func handleGlobalDaemonFlag() {
|
||||
// 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) {
|
||||
|
@ -79,14 +129,56 @@ func migrateKey() (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func mainDaemon() {
|
||||
if utils.ExperimentalBuild() {
|
||||
logrus.Warn("Running experimental build")
|
||||
// DaemonCli represents the daemon CLI.
|
||||
type DaemonCli struct {
|
||||
*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 {
|
||||
flag.Usage()
|
||||
return
|
||||
daemonFlags.ParseFlags(args, true)
|
||||
commonFlags.PostParse()
|
||||
|
||||
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})
|
||||
|
@ -95,15 +187,15 @@ func mainDaemon() {
|
|||
logrus.Fatalf("Failed to set umask: %v", err)
|
||||
}
|
||||
|
||||
if len(daemonCfg.LogConfig.Config) > 0 {
|
||||
if err := logger.ValidateLogOpts(daemonCfg.LogConfig.Type, daemonCfg.LogConfig.Config); err != nil {
|
||||
if len(cli.LogConfig.Config) > 0 {
|
||||
if err := logger.ValidateLogOpts(cli.LogConfig.Type, cli.LogConfig.Config); err != nil {
|
||||
logrus.Fatalf("Failed to set log opts: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var pfile *pidfile.PidFile
|
||||
if daemonCfg.Pidfile != "" {
|
||||
pf, err := pidfile.New(daemonCfg.Pidfile)
|
||||
if cli.Pidfile != "" {
|
||||
pf, err := pidfile.New(cli.Pidfile)
|
||||
if err != nil {
|
||||
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{
|
||||
Logging: true,
|
||||
EnableCors: daemonCfg.EnableCors,
|
||||
CorsHeaders: daemonCfg.CorsHeaders,
|
||||
EnableCors: cli.EnableCors,
|
||||
CorsHeaders: cli.CorsHeaders,
|
||||
Version: dockerversion.VERSION,
|
||||
}
|
||||
serverConfig = setPlatformServerConfig(serverConfig, daemonCfg)
|
||||
serverConfig = setPlatformServerConfig(serverConfig, cli.Config)
|
||||
|
||||
if *flTLS {
|
||||
if *flTLSVerify {
|
||||
tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
if commonFlags.TLSOptions != nil {
|
||||
if !commonFlags.TLSOptions.InsecureSkipVerify {
|
||||
// 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 {
|
||||
logrus.Fatal(err)
|
||||
logrus.Fatalf("foobar: %v", err)
|
||||
}
|
||||
serverConfig.TLSConfig = tlsConfig
|
||||
}
|
||||
|
@ -141,7 +238,7 @@ func mainDaemon() {
|
|||
// daemon doesn't exit
|
||||
serveAPIWait := make(chan error)
|
||||
go func() {
|
||||
if err := api.ServeApi(flHosts); err != nil {
|
||||
if err := api.ServeApi(commonFlags.Hosts); err != nil {
|
||||
logrus.Errorf("ServeAPI error: %v", err)
|
||||
serveAPIWait <- err
|
||||
return
|
||||
|
@ -152,10 +249,10 @@ func mainDaemon() {
|
|||
if err := migrateKey(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
daemonCfg.TrustKeyPath = *flTrustKey
|
||||
cli.TrustKeyPath = commonFlags.TrustKey
|
||||
|
||||
registryService := registry.NewService(registryCfg)
|
||||
d, err := daemon.NewDaemon(daemonCfg, registryService)
|
||||
registryService := registry.NewService(cli.registryOptions)
|
||||
d, err := daemon.NewDaemon(cli.Config, registryService)
|
||||
if err != nil {
|
||||
if pfile != nil {
|
||||
if err := pfile.Remove(); err != nil {
|
||||
|
@ -201,6 +298,7 @@ func mainDaemon() {
|
|||
}
|
||||
logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
||||
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
12
docker/daemon_none.go
Normal 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() {}
|
143
docker/docker.go
143
docker/docker.go
|
@ -1,31 +1,20 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sort"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/client"
|
||||
"github.com/docker/docker/autogen/dockerversion"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTrustKeyFile = "key.json"
|
||||
defaultCaFile = "ca.pem"
|
||||
defaultKeyFile = "key.pem"
|
||||
defaultCertFile = "cert.pem"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if reexec.Init() {
|
||||
return
|
||||
|
@ -34,116 +23,58 @@ func main() {
|
|||
// Set terminal emulation based on platform as required.
|
||||
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()
|
||||
// FIXME: validate daemon flags here
|
||||
|
||||
if *flVersion {
|
||||
showVersion()
|
||||
return
|
||||
}
|
||||
|
||||
if *flConfigDir != "" {
|
||||
cliconfig.SetConfigDir(*flConfigDir)
|
||||
}
|
||||
clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags)
|
||||
// TODO: remove once `-d` is retired
|
||||
handleGlobalDaemonFlag()
|
||||
|
||||
if *flLogLevel != "" {
|
||||
lvl, err := logrus.ParseLevel(*flLogLevel)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", *flLogLevel)
|
||||
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()
|
||||
if *flHelp {
|
||||
// if global flag --help is present, regardless of what other options and commands there are,
|
||||
// just print the usage.
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
// From here on, we assume we're a client, not a server.
|
||||
|
||||
if len(flHosts) > 1 {
|
||||
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 {
|
||||
c := cli.New(clientCli, daemonCli)
|
||||
if err := c.Run(flag.Args()...); err != nil {
|
||||
if sterr, ok := err.(cli.StatusError); ok {
|
||||
if sterr.Status != "" {
|
||||
fmt.Fprintln(cli.Err(), sterr.Status)
|
||||
fmt.Fprintln(os.Stderr, sterr.Status)
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(sterr.StatusCode)
|
||||
}
|
||||
fmt.Fprintln(cli.Err(), err)
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
170
docker/flags.go
170
docker/flags.go
|
@ -1,16 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
import flag "github.com/docker/docker/pkg/mflag"
|
||||
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
var (
|
||||
flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage")
|
||||
flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
|
||||
)
|
||||
|
||||
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) Less(i, j int) bool { return a[i].name < a[j].name }
|
||||
|
||||
var (
|
||||
dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
|
||||
dockerTlSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
|
||||
|
||||
dockerCommands = []command{
|
||||
{"attach", "Attach to a running container"},
|
||||
{"build", "Build an image from a Dockerfile"},
|
||||
{"commit", "Create a new image from a container's changes"},
|
||||
{"cp", "Copy files/folders from a container to a HOSTDIR or to STDOUT"},
|
||||
{"create", "Create a new container"},
|
||||
{"diff", "Inspect changes on a container's filesystem"},
|
||||
{"events", "Get real time events from the server"},
|
||||
{"exec", "Run a command in a running container"},
|
||||
{"export", "Export a container's filesystem as a tar archive"},
|
||||
{"history", "Show the history of an image"},
|
||||
{"images", "List images"},
|
||||
{"import", "Import the contents from a tarball to create a filesystem image"},
|
||||
{"info", "Display system-wide information"},
|
||||
{"inspect", "Return low-level information on a container or image"},
|
||||
{"kill", "Kill a running container"},
|
||||
{"load", "Load an image from a tar archive or STDIN"},
|
||||
{"login", "Register or log in to a Docker registry"},
|
||||
{"logout", "Log out from a Docker registry"},
|
||||
{"logs", "Fetch the logs of a container"},
|
||||
{"port", "List port mappings or a specific mapping for the CONTAINER"},
|
||||
{"pause", "Pause all processes within a container"},
|
||||
{"ps", "List containers"},
|
||||
{"pull", "Pull an image or a repository from a registry"},
|
||||
{"push", "Push an image or a repository to a registry"},
|
||||
{"rename", "Rename a container"},
|
||||
{"restart", "Restart a running container"},
|
||||
{"rm", "Remove one or more containers"},
|
||||
{"rmi", "Remove one or more images"},
|
||||
{"run", "Run a command in a new container"},
|
||||
{"save", "Save an image(s) to a tar archive"},
|
||||
{"search", "Search the Docker Hub for images"},
|
||||
{"start", "Start one or more stopped containers"},
|
||||
{"stats", "Display a live stream of container(s) resource usage statistics"},
|
||||
{"stop", "Stop a running container"},
|
||||
{"tag", "Tag an image into a repository"},
|
||||
{"top", "Display the running processes of a container"},
|
||||
{"unpause", "Unpause all processes within a container"},
|
||||
{"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)
|
||||
}
|
||||
// TODO(tiborvass): do not show 'daemon' on client-only binaries
|
||||
// and deduplicate description in dockerCommands and cli subcommands
|
||||
var dockerCommands = []command{
|
||||
{"attach", "Attach to a running container"},
|
||||
{"build", "Build an image from a Dockerfile"},
|
||||
{"commit", "Create a new image from a container's changes"},
|
||||
{"cp", "Copy files/folders from a container to a HOSTDIR or to STDOUT"},
|
||||
{"create", "Create a new container"},
|
||||
{"diff", "Inspect changes on a container's filesystem"},
|
||||
{"events", "Get real time events from the server"},
|
||||
{"exec", "Run a command in a running container"},
|
||||
{"export", "Export a container's filesystem as a tar archive"},
|
||||
{"history", "Show the history of an image"},
|
||||
{"images", "List images"},
|
||||
{"import", "Import the contents from a tarball to create a filesystem image"},
|
||||
{"info", "Display system-wide information"},
|
||||
{"inspect", "Return low-level information on a container or image"},
|
||||
{"kill", "Kill a running container"},
|
||||
{"load", "Load an image from a tar archive or STDIN"},
|
||||
{"login", "Register or log in to a Docker registry"},
|
||||
{"logout", "Log out from a Docker registry"},
|
||||
{"logs", "Fetch the logs of a container"},
|
||||
{"port", "List port mappings or a specific mapping for the CONTAINER"},
|
||||
{"pause", "Pause all processes within a container"},
|
||||
{"ps", "List containers"},
|
||||
{"pull", "Pull an image or a repository from a registry"},
|
||||
{"push", "Push an image or a repository to a registry"},
|
||||
{"rename", "Rename a container"},
|
||||
{"restart", "Restart a running container"},
|
||||
{"rm", "Remove one or more containers"},
|
||||
{"rmi", "Remove one or more images"},
|
||||
{"run", "Run a command in a new container"},
|
||||
{"save", "Save an image(s) to a tar archive"},
|
||||
{"search", "Search the Docker Hub for images"},
|
||||
{"start", "Start one or more stopped containers"},
|
||||
{"stats", "Display a live stream of container(s) resource usage statistics"},
|
||||
{"stop", "Stop a running container"},
|
||||
{"tag", "Tag an image into a repository"},
|
||||
{"top", "Display the running processes of a container"},
|
||||
{"unpause", "Unpause all processes within a container"},
|
||||
{"version", "Show the Docker version information"},
|
||||
{"wait", "Block until a container stops, then print its exit code"},
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -103,7 +103,7 @@ when no `-H` was passed in.
|
|||
|
||||
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:
|
||||
|
||||
|
@ -113,7 +113,7 @@ You can use multiple `-H`, for example, if you want to listen on both
|
|||
TCP and a Unix socket
|
||||
|
||||
# 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
|
||||
$ docker pull ubuntu
|
||||
# OR use the TCP port
|
||||
|
|
|
@ -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 Unix socket `unix:///var/run/docker.sock`
|
||||
|
||||
$ docker -d
|
||||
$ docker daemon
|
||||
|
||||
INFO[0000] +job init_networkdriver()
|
||||
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
|
||||
|
||||
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
|
||||
command directly. Just like the `-d` option, other options can be passed to the `docker`
|
||||
daemon to configure it.
|
||||
command directly. Other options can be passed to the `docker` daemon to configure it.
|
||||
|
||||
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:
|
||||
|
||||
$ 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 :
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ prevent accidental damage:
|
|||
Now you can make the Docker daemon only accept connections from clients
|
||||
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
|
||||
|
||||
To be able to connect to Docker and validate its certificate, you now
|
||||
|
|
|
@ -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
|
||||
`--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
|
||||
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
|
||||
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
|
||||
is connected to `eth0`. This means all devices (containers) with the addresses
|
||||
|
|
|
@ -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
|
||||
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:
|
||||
|
||||
docker --registry-mirror=http://10.0.0.2:5000 -d
|
||||
docker daemon --registry-mirror=http://10.0.0.2:5000
|
||||
|
||||
**NOTE:**
|
||||
Depending on your local host setup, you may be able to add the
|
||||
|
|
|
@ -70,7 +70,7 @@ In this example, we'll assume that your `docker.service` file looks something li
|
|||
[Service]
|
||||
Type=notify
|
||||
EnvironmentFile=-/etc/sysconfig/docker
|
||||
ExecStart=/usr/bin/docker -d -H fd:// $OPTIONS
|
||||
ExecStart=/usr/bin/docker daemon -H fd:// $OPTIONS
|
||||
LimitNOFILE=1048576
|
||||
LimitNPROC=1048576
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ For example:
|
|||
## Run the Docker daemon
|
||||
|
||||
# start the docker in daemon mode from the directory you unpacked
|
||||
$ sudo ./docker -d &
|
||||
$ sudo ./docker daemon &
|
||||
|
||||
## Giving non-root access
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ To create the `docker` group and add your user:
|
|||
|
||||
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.
|
||||
If it is, unset it.
|
||||
|
|
|
@ -285,7 +285,7 @@ with the `make.sh` script.
|
|||
|
||||
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
|
||||
when debugging your code.
|
||||
|
@ -411,7 +411,7 @@ onto the `/go` directory inside the container.
|
|||
|
||||
* copy the binary inside the development container using
|
||||
`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
|
||||
* connect to your running container `docker exec -it container_name bash`
|
||||
* use the `docker run hello-world` command to create and run a container
|
||||
|
|
|
@ -120,7 +120,7 @@ Run the entire test suite on your current repository:
|
|||
PASS
|
||||
coverage: 70.8% of statements
|
||||
---> 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
|
||||
|
|
|
@ -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,
|
||||
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"
|
||||
|
|
|
@ -19,6 +19,9 @@ or execute `docker help`:
|
|||
|
||||
$ docker
|
||||
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.
|
||||
|
||||
A self-sufficient runtime for Linux containers.
|
||||
|
|
|
@ -10,7 +10,7 @@ parent = "smn_cli"
|
|||
|
||||
# daemon
|
||||
|
||||
Usage: docker [OPTIONS] COMMAND [arg...]
|
||||
Usage: docker daemon [OPTIONS]
|
||||
|
||||
A self-sufficient runtime for linux containers.
|
||||
|
||||
|
@ -18,9 +18,7 @@ parent = "smn_cli"
|
|||
--api-cors-header="" Set CORS headers in the remote API
|
||||
-b, --bridge="" Attach containers to a network bridge
|
||||
--bip="" Specify network bridge IP
|
||||
--config=~/.docker Location of client config files
|
||||
-D, --debug=false Enable debug mode
|
||||
-d, --daemon=false Enable daemon mode
|
||||
--default-gateway="" Container default gateway IPv4 address
|
||||
--default-gateway-v6="" Container default gateway IPv6 address
|
||||
--dns=[] DNS server to use
|
||||
|
@ -58,15 +56,14 @@ parent = "smn_cli"
|
|||
--tlskey="~/.docker/key.pem" Path to TLS key file
|
||||
--tlsverify=false Use TLS and verify the remote
|
||||
--userland-proxy=true Use userland proxy for loopback traffic
|
||||
-v, --version=false Print version information and quit
|
||||
|
||||
Options with [] may be specified multiple times.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -94,8 +91,8 @@ communication with the daemon.
|
|||
|
||||
On Systemd based systems, you can communicate with the daemon via
|
||||
[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
|
||||
you can also specify individual sockets: `docker -d -H fd://3`. If the
|
||||
use `docker daemon -H fd://`. Using `fd://` will work perfectly for most setups but
|
||||
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
|
||||
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/).
|
||||
|
@ -104,7 +101,7 @@ You can configure the Docker daemon to listen to multiple sockets at the same
|
|||
time using multiple `-H` options:
|
||||
|
||||
# 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
|
||||
`-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`
|
||||
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
|
||||
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).
|
||||
|
||||
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
|
||||
`docker -d -s overlay` to use it.
|
||||
`docker daemon -s overlay` to use it.
|
||||
|
||||
> **Note:**
|
||||
> 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:
|
||||
|
||||
docker -d --storage-opt dm.thinpooldev=/dev/mapper/thin-pool
|
||||
docker daemon --storage-opt dm.thinpooldev=/dev/mapper/thin-pool
|
||||
|
||||
* `dm.basesize`
|
||||
|
||||
|
@ -216,7 +213,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
Example use:
|
||||
|
||||
$ docker -d --storage-opt dm.basesize=20G
|
||||
$ docker daemon --storage-opt dm.basesize=20G
|
||||
|
||||
* `dm.loopdatasize`
|
||||
|
||||
|
@ -229,7 +226,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
Example use:
|
||||
|
||||
$ docker -d --storage-opt dm.loopdatasize=200G
|
||||
$ docker daemon --storage-opt dm.loopdatasize=200G
|
||||
|
||||
* `dm.loopmetadatasize`
|
||||
|
||||
|
@ -242,7 +239,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
Example use:
|
||||
|
||||
$ docker -d --storage-opt dm.loopmetadatasize=4G
|
||||
$ docker daemon --storage-opt dm.loopmetadatasize=4G
|
||||
|
||||
* `dm.fs`
|
||||
|
||||
|
@ -251,7 +248,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
Example use:
|
||||
|
||||
$ docker -d --storage-opt dm.fs=xfs
|
||||
$ docker daemon --storage-opt dm.fs=xfs
|
||||
|
||||
* `dm.mkfsarg`
|
||||
|
||||
|
@ -259,7 +256,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
Example use:
|
||||
|
||||
$ docker -d --storage-opt "dm.mkfsarg=-O ^has_journal"
|
||||
$ docker daemon --storage-opt "dm.mkfsarg=-O ^has_journal"
|
||||
|
||||
* `dm.mountopt`
|
||||
|
||||
|
@ -267,7 +264,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
Example use:
|
||||
|
||||
$ docker -d --storage-opt dm.mountopt=nodiscard
|
||||
$ docker daemon --storage-opt dm.mountopt=nodiscard
|
||||
|
||||
* `dm.datadev`
|
||||
|
||||
|
@ -281,7 +278,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
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`
|
||||
|
||||
|
@ -299,7 +296,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
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`
|
||||
|
||||
|
@ -308,7 +305,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
Example use:
|
||||
|
||||
$ docker -d --storage-opt dm.blocksize=512K
|
||||
$ docker daemon --storage-opt dm.blocksize=512K
|
||||
|
||||
* `dm.blkdiscard`
|
||||
|
||||
|
@ -322,7 +319,7 @@ options for `zfs` start with `zfs`.
|
|||
|
||||
Example use:
|
||||
|
||||
$ docker -d --storage-opt dm.blkdiscard=false
|
||||
$ docker daemon --storage-opt dm.blkdiscard=false
|
||||
|
||||
* `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
|
||||
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
|
||||
you the errors are happening.
|
||||
|
@ -373,7 +370,7 @@ Currently supported options of `zfs`:
|
|||
|
||||
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
|
||||
|
||||
|
@ -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`.
|
||||
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.
|
||||
|
||||
## Daemon DNS options
|
||||
|
||||
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
|
||||
`docker -d --dns-search example.com`.
|
||||
`docker daemon --dns-search example.com`.
|
||||
|
||||
## 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
|
||||
2. Ask your network admin for the proxy's CA certificate and append them to
|
||||
`/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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ List all images with `vendor` `ACME`:
|
|||
## Daemon labels
|
||||
|
||||
|
||||
docker -d \
|
||||
docker daemon \
|
||||
--dns 8.8.8.8 \
|
||||
--dns 8.8.4.4 \
|
||||
-H unix:///var/run/docker.sock \
|
||||
|
|
|
@ -79,7 +79,7 @@ func (s *DockerSuite) TestBuildShCmdJSONEntrypoint(c *check.C) {
|
|||
out, _ := dockerCmd(c, "run", "--rm", name)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
|
||||
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) {
|
||||
if err := s.d.Start("--log-level=debug"); err != nil {
|
||||
c.Fatal(err)
|
||||
|
@ -382,7 +476,7 @@ func (s *DockerDaemonSuite) TestDaemonAllocatesListeningPort(c *check.C) {
|
|||
{"localhost", "127.0.0.1", "1235"},
|
||||
}
|
||||
|
||||
cmdArgs := []string{}
|
||||
cmdArgs := make([]string, 0, len(listeningPorts)*2)
|
||||
for _, hostDirective := range listeningPorts {
|
||||
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))
|
||||
defer deleteInterface(c, bridgeName)
|
||||
|
||||
args := []string{"--bridge", bridgeName, "--icc=false"}
|
||||
err = s.d.StartWithBusybox(args...)
|
||||
err = s.d.StartWithBusybox("--bridge", bridgeName, "--icc=false")
|
||||
c.Assert(err, check.IsNil)
|
||||
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
|
||||
func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) {
|
||||
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",
|
||||
|
@ -1218,9 +1311,7 @@ func (s *DockerDaemonSuite) TestHttpsInfo(c *check.C) {
|
|||
c.Fatalf("Could not start daemon with busybox: %v", err)
|
||||
}
|
||||
|
||||
//force tcp protocol
|
||||
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"}
|
||||
daemonArgs := []string{"--host", testDaemonHTTPSAddr, "--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")
|
||||
if err != nil {
|
||||
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) {
|
||||
const (
|
||||
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",
|
||||
"--tlskey", "fixtures/https/server-key.pem", "-H", testDaemonHTTPSAddr); err != nil {
|
||||
c.Fatalf("Could not start daemon with busybox: %v", err)
|
||||
}
|
||||
|
||||
//force tcp protocol
|
||||
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"}
|
||||
daemonArgs := []string{"--host", testDaemonHTTPSAddr, "--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")
|
||||
if err == nil || !strings.Contains(out, errBadCertificate) {
|
||||
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) {
|
||||
const (
|
||||
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",
|
||||
"--tlskey", "fixtures/https/server-rogue-key.pem", "-H", testDaemonRogueHTTPSAddr); err != nil {
|
||||
c.Fatalf("Could not start daemon with busybox: %v", err)
|
||||
}
|
||||
|
||||
//force tcp protocol
|
||||
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"}
|
||||
daemonArgs := []string{"--host", testDaemonRogueHTTPSAddr, "--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")
|
||||
if err == nil || !strings.Contains(out, errCaUnknown) {
|
||||
c.Fatalf("Expected err: %s, got instead: %s and output: %s", errCaUnknown, err, out)
|
||||
|
|
|
@ -89,10 +89,18 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
|
|||
c.Fatalf("Missing 'Commands:' in:\n%s", out)
|
||||
}
|
||||
|
||||
// Grab all chars starting at "Commands:"
|
||||
// Skip first line, its "Commands:"
|
||||
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
|
||||
|
||||
// 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).
|
||||
// Whatever the reason, skip trying to run w/o args and
|
||||
// jump to trying with a bogus arg.
|
||||
skipNoArgs := map[string]string{
|
||||
"events": "",
|
||||
"load": "",
|
||||
skipNoArgs := map[string]struct{}{
|
||||
"daemon": {},
|
||||
"events": {},
|
||||
"load": {},
|
||||
}
|
||||
|
||||
ec = 0
|
||||
|
@ -230,6 +239,9 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
|
|||
}
|
||||
|
||||
expected := 39
|
||||
if isLocalDaemon {
|
||||
expected++ // for the daemon command
|
||||
}
|
||||
if len(cmds) != expected {
|
||||
c.Fatalf("Wrong # of cmds(%d), it should be: %d\nThe list:\n%q",
|
||||
len(cmds), expected, cmds)
|
||||
|
@ -246,7 +258,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
|
|||
cmd := exec.Command(dockerBinary)
|
||||
stdout, stderr, ec, err := runCommandWithStdoutStderr(cmd)
|
||||
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
|
||||
if strings.HasSuffix(stdout, "\n\n") {
|
||||
|
@ -257,7 +269,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
|
|||
cmd = exec.Command(dockerBinary, "help")
|
||||
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
|
||||
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
|
||||
if strings.HasSuffix(stdout, "\n\n") {
|
||||
|
@ -268,7 +280,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
|
|||
cmd = exec.Command(dockerBinary, "--help")
|
||||
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
|
||||
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
|
||||
if strings.HasSuffix(stdout, "\n\n") {
|
||||
|
@ -280,7 +292,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
|
|||
cmd = exec.Command(dockerBinary, "inspect", "busybox")
|
||||
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
|
||||
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
|
||||
if strings.HasSuffix(stdout, "\n\n") {
|
||||
|
@ -292,7 +304,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
|
|||
cmd = exec.Command(dockerBinary, "rm")
|
||||
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
|
||||
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
|
||||
// # of args and Usage line
|
||||
|
@ -305,7 +317,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
|
|||
cmd = exec.Command(dockerBinary, "rm", "NoSuchContainer")
|
||||
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
|
||||
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
|
||||
if strings.HasSuffix(stderr, "\n\n") {
|
||||
|
@ -316,7 +328,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
|
|||
cmd = exec.Command(dockerBinary, "BadCmd")
|
||||
stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd)
|
||||
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" {
|
||||
c.Fatalf("Unexcepted output for 'docker badCmd'\nstderr:%s", stderr)
|
||||
|
|
|
@ -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
|
||||
func (s *DockerSuite) TestRunWithVolumesFromExited(c *check.C) {
|
||||
out, exitCode := dockerCmd(c, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file")
|
||||
|
|
|
@ -29,6 +29,12 @@ import (
|
|||
|
||||
// Daemon represents a Docker daemon for the testing framework.
|
||||
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
|
||||
logFile *os.File
|
||||
folder string
|
||||
|
@ -59,7 +65,8 @@ func NewDaemon(c *check.C) *Daemon {
|
|||
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)
|
||||
if err != nil {
|
||||
c.Fatalf("Could not make %q an absolute path: %v", dir, err)
|
||||
|
@ -77,6 +84,8 @@ func NewDaemon(c *check.C) *Daemon {
|
|||
}
|
||||
|
||||
return &Daemon{
|
||||
Command: "daemon",
|
||||
id: id,
|
||||
c: c,
|
||||
folder: daemonFolder,
|
||||
storageDriver: os.Getenv("DOCKER_GRAPHDRIVER"),
|
||||
|
@ -90,22 +99,22 @@ func NewDaemon(c *check.C) *Daemon {
|
|||
func (d *Daemon) Start(arg ...string) error {
|
||||
dockerBinary, err := exec.LookPath(dockerBinary)
|
||||
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(),
|
||||
"--daemon",
|
||||
"--graph", fmt.Sprintf("%s/graph", d.folder),
|
||||
"--pidfile", fmt.Sprintf("%s/docker.pid", d.folder),
|
||||
fmt.Sprintf("--userland-proxy=%t", d.userlandProxy),
|
||||
}
|
||||
)
|
||||
|
||||
// If we don't explicitly set the log-level or debug flag(-D) then
|
||||
// turn on debug mode
|
||||
foundIt := false
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
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.Stderr = d.logFile
|
||||
|
||||
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)
|
||||
|
||||
go func() {
|
||||
wait <- d.cmd.Wait()
|
||||
d.c.Log("exiting daemon")
|
||||
d.c.Logf("[%s] exiting daemon", d.id)
|
||||
close(wait)
|
||||
}()
|
||||
|
||||
|
@ -149,14 +158,14 @@ func (d *Daemon) Start(arg ...string) error {
|
|||
// make sure daemon is ready to receive requests
|
||||
startTime := time.Now().Unix()
|
||||
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 {
|
||||
// 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 {
|
||||
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:
|
||||
c, err := net.Dial("unix", filepath.Join(d.folder, "docker.sock"))
|
||||
if err != nil {
|
||||
|
@ -168,7 +177,7 @@ func (d *Daemon) Start(arg ...string) error {
|
|||
|
||||
req, err := http.NewRequest("GET", "/_ping", 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)
|
||||
|
@ -176,10 +185,10 @@ func (d *Daemon) Start(arg ...string) error {
|
|||
continue
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
7
opts/hosts_unix.go
Normal file
7
opts/hosts_unix.go
Normal 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
7
opts/hosts_windows.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
// +build windows
|
||||
|
||||
package opts
|
||||
|
||||
import "fmt"
|
||||
|
||||
var DefaultHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
|
25
opts/opts.go
25
opts/opts.go
|
@ -32,37 +32,37 @@ var (
|
|||
// ListVar Defines a flag with the specified names and usage, and put the value
|
||||
// list into ListOpts that will hold the values.
|
||||
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
|
||||
// map into MapOpt that will hold the values (key,value).
|
||||
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,
|
||||
// and put the value map into MapOpt that will hold the values (key,value).
|
||||
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
|
||||
// value into a ListOpts that will hold the values, validating the Host format.
|
||||
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
|
||||
// value into a ListOpts that will hold the values, validating the IP format.
|
||||
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
|
||||
// value into a ListOpts that will hold the values, validating the DNS search format.
|
||||
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
|
||||
|
@ -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
|
||||
// value into a ListOpts that will hold the values, validating the label format.
|
||||
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,
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
@ -92,10 +92,10 @@ type ListOpts struct {
|
|||
// NewListOpts Create a new ListOpts with the specified validator.
|
||||
func NewListOpts(validator ValidatorFctType) ListOpts {
|
||||
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{
|
||||
values: values,
|
||||
validator: validator,
|
||||
|
@ -191,7 +191,10 @@ func (opts *MapOpts) String() string {
|
|||
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{
|
||||
values: values,
|
||||
validator: validator,
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestValidateIPAddress(t *testing.T) {
|
|||
|
||||
func TestMapOpts(t *testing.T) {
|
||||
tmpMap := make(map[string]string)
|
||||
o := newMapOpt(tmpMap, logOptsValidator)
|
||||
o := NewMapOpts(tmpMap, logOptsValidator)
|
||||
o.Set("max-size=1")
|
||||
if o.String() != "map[max-size:1]" {
|
||||
t.Errorf("%s != [map[max-size:1]", o.String())
|
||||
|
|
|
@ -7,10 +7,13 @@ import (
|
|||
)
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
|
@ -20,14 +23,14 @@ func (o *UlimitOpt) Set(val string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
o.values[l.Name] = l
|
||||
(*o.values)[l.Name] = l
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *UlimitOpt) String() string {
|
||||
var out []string
|
||||
for _, v := range o.values {
|
||||
for _, v := range *o.values {
|
||||
out = append(out, v.String())
|
||||
}
|
||||
|
||||
|
@ -36,7 +39,7 @@ func (o *UlimitOpt) String() string {
|
|||
|
||||
func (o *UlimitOpt) GetList() []*ulimit.Ulimit {
|
||||
var ulimits []*ulimit.Ulimit
|
||||
for _, v := range o.values {
|
||||
for _, v := range *o.values {
|
||||
ulimits = append(ulimits, v)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ func TestUlimitOpt(t *testing.T) {
|
|||
"nofile": {"nofile", 1024, 512},
|
||||
}
|
||||
|
||||
ulimitOpt := NewUlimitOpt(ulimitMap)
|
||||
ulimitOpt := NewUlimitOpt(&ulimitMap)
|
||||
|
||||
expected := "[nofile=512:1024]"
|
||||
if ulimitOpt.String() != expected {
|
||||
|
|
|
@ -526,7 +526,7 @@ func (f *FlagSet) PrintDefaults() {
|
|||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
if len(names) > 0 {
|
||||
if len(names) > 0 && len(flag.Usage) > 0 {
|
||||
val := flag.DefValue
|
||||
|
||||
if home != "" && strings.HasPrefix(val, home) {
|
||||
|
@ -1143,3 +1143,53 @@ func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
|
|||
f.name = name
|
||||
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
|
||||
}
|
||||
|
|
|
@ -17,11 +17,18 @@ import (
|
|||
|
||||
// Options represents the information needed to create client and server TLS configurations.
|
||||
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
|
||||
ClientAuth tls.ClientAuthType
|
||||
CAFile string
|
||||
CertFile string
|
||||
KeyFile string
|
||||
// server-only option
|
||||
ClientAuth tls.ClientAuthType
|
||||
}
|
||||
|
||||
// Extra (server-side) accepted CBC cipher suites - will phase out in the future
|
||||
|
|
|
@ -43,11 +43,11 @@ var (
|
|||
|
||||
// InstallFlags adds command-line options to the top-level flag parser for
|
||||
// the current process.
|
||||
func (options *Options) InstallFlags() {
|
||||
func (options *Options) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
|
||||
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)
|
||||
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
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/nat"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/ulimit"
|
||||
"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)
|
||||
flDevices = opts.NewListOpts(opts.ValidateDevice)
|
||||
|
||||
ulimits = make(map[string]*ulimit.Ulimit)
|
||||
flUlimits = opts.NewUlimitOpt(ulimits)
|
||||
flUlimits = opts.NewUlimitOpt(nil)
|
||||
|
||||
flPublish = opts.NewListOpts(nil)
|
||||
flExpose = opts.NewListOpts(nil)
|
||||
|
|
Loading…
Reference in a new issue