cli: new daemon command and new cli package
This patch creates a new cli package that allows to combine both client and daemon commands (there is only one daemon command: docker daemon). The `-d` and `--daemon` top-level flags are deprecated and a special message is added to prompt the user to use `docker daemon`. Providing top-level daemon-specific flags for client commands result in an error message prompting the user to use `docker daemon`. This patch does not break any old but correct usages. This also makes `-d` and `--daemon` flags, as well as the `daemon` command illegal in client-only binaries. Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
parent
490e78a642
commit
96ce3a194a
67 changed files with 913 additions and 614 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)
|
||||
}
|
|
@ -43,7 +43,8 @@ func (s *DockerDaemonSuite) TestCliProxyProxyTCPSock(c *check.C) {
|
|||
c.Fatal("could not find ip to connect to")
|
||||
}
|
||||
|
||||
if err := s.d.Start("-H", "tcp://"+ip+":2375"); err != nil {
|
||||
s.d.GlobalFlags = []string{"-H", "tcp://" + ip + ":2375"}
|
||||
if err := s.d.Start(); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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