This exposes the already existing "create container" operation. It is
very similar to "docker run -d" except it doesn't actually start the
container, but just prepares it. It can then be manually started using
"docker start" at any point.
Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
Conflicts:
api/client/commands.go
runconfig/parse.go
server/container.go
Docker-DCO-1.1-Signed-off-by: Tibor Vass <teabee89@gmail.com> (github: tiborvass)
| ... | ... |
@@ -1965,91 +1965,181 @@ func (cli *DockerCli) pullImage(image string) error {
|
| 1965 | 1965 |
return nil |
| 1966 | 1966 |
} |
| 1967 | 1967 |
|
| 1968 |
-func (cli *DockerCli) CmdRun(args ...string) error {
|
|
| 1969 |
- // FIXME: just use runconfig.Parse already |
|
| 1970 |
- config, hostConfig, cmd, err := runconfig.ParseSubcommand(cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container"), args, nil)
|
|
| 1971 |
- if err != nil {
|
|
| 1972 |
- return err |
|
| 1968 |
+type cidFile struct {
|
|
| 1969 |
+ path string |
|
| 1970 |
+ file *os.File |
|
| 1971 |
+ written bool |
|
| 1972 |
+} |
|
| 1973 |
+ |
|
| 1974 |
+func newCIDFile(path string) (*cidFile, error) {
|
|
| 1975 |
+ if _, err := os.Stat(path); err == nil {
|
|
| 1976 |
+ return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
|
|
| 1973 | 1977 |
} |
| 1974 |
- if config.Image == "" {
|
|
| 1975 |
- cmd.Usage() |
|
| 1976 |
- return nil |
|
| 1978 |
+ f, err := os.Create(path) |
|
| 1979 |
+ if err != nil {
|
|
| 1980 |
+ return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
|
|
| 1977 | 1981 |
} |
| 1978 | 1982 |
|
| 1979 |
- // Retrieve relevant client-side config |
|
| 1980 |
- var ( |
|
| 1981 |
- flName = cmd.Lookup("name")
|
|
| 1982 |
- flRm = cmd.Lookup("rm")
|
|
| 1983 |
- flSigProxy = cmd.Lookup("sig-proxy")
|
|
| 1984 |
- autoRemove, _ = strconv.ParseBool(flRm.Value.String()) |
|
| 1985 |
- sigProxy, _ = strconv.ParseBool(flSigProxy.Value.String()) |
|
| 1986 |
- ) |
|
| 1983 |
+ return &cidFile{path: path, file: f}, nil
|
|
| 1984 |
+} |
|
| 1987 | 1985 |
|
| 1988 |
- // Disable sigProxy in case on TTY |
|
| 1989 |
- if config.Tty {
|
|
| 1990 |
- sigProxy = false |
|
| 1991 |
- } |
|
| 1986 |
+func (cid *cidFile) Close() error {
|
|
| 1987 |
+ cid.file.Close() |
|
| 1992 | 1988 |
|
| 1993 |
- var containerIDFile io.WriteCloser |
|
| 1994 |
- if len(hostConfig.ContainerIDFile) > 0 {
|
|
| 1995 |
- if _, err := os.Stat(hostConfig.ContainerIDFile); err == nil {
|
|
| 1996 |
- return fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", hostConfig.ContainerIDFile)
|
|
| 1997 |
- } |
|
| 1998 |
- if containerIDFile, err = os.Create(hostConfig.ContainerIDFile); err != nil {
|
|
| 1999 |
- return fmt.Errorf("Failed to create the container ID file: %s", err)
|
|
| 1989 |
+ if !cid.written {
|
|
| 1990 |
+ if err := os.Remove(cid.path); err != nil {
|
|
| 1991 |
+ return fmt.Errorf("failed to remove CID file '%s': %s \n", cid.path, err)
|
|
| 2000 | 1992 |
} |
| 2001 |
- defer func() {
|
|
| 2002 |
- containerIDFile.Close() |
|
| 2003 |
- var ( |
|
| 2004 |
- cidFileInfo os.FileInfo |
|
| 2005 |
- err error |
|
| 2006 |
- ) |
|
| 2007 |
- if cidFileInfo, err = os.Stat(hostConfig.ContainerIDFile); err != nil {
|
|
| 2008 |
- return |
|
| 2009 |
- } |
|
| 2010 |
- if cidFileInfo.Size() == 0 {
|
|
| 2011 |
- if err := os.Remove(hostConfig.ContainerIDFile); err != nil {
|
|
| 2012 |
- fmt.Printf("failed to remove Container ID file '%s': %s \n", hostConfig.ContainerIDFile, err)
|
|
| 2013 |
- } |
|
| 2014 |
- } |
|
| 2015 |
- }() |
|
| 2016 | 1993 |
} |
| 2017 | 1994 |
|
| 1995 |
+ return nil |
|
| 1996 |
+} |
|
| 1997 |
+ |
|
| 1998 |
+func (cid *cidFile) Write(id string) error {
|
|
| 1999 |
+ if _, err := cid.file.Write([]byte(id)); err != nil {
|
|
| 2000 |
+ return fmt.Errorf("Failed to write the container ID to the file: %s", err)
|
|
| 2001 |
+ } |
|
| 2002 |
+ cid.written = true |
|
| 2003 |
+ return nil |
|
| 2004 |
+} |
|
| 2005 |
+ |
|
| 2006 |
+func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string) (engine.Env, error) {
|
|
| 2018 | 2007 |
containerValues := url.Values{}
|
| 2019 |
- if name := flName.Value.String(); name != "" {
|
|
| 2008 |
+ if name != "" {
|
|
| 2020 | 2009 |
containerValues.Set("name", name)
|
| 2021 | 2010 |
} |
| 2022 | 2011 |
|
| 2012 |
+ var data interface{}
|
|
| 2013 |
+ if hostConfig != nil {
|
|
| 2014 |
+ data = runconfig.MergeConfigs(config, hostConfig) |
|
| 2015 |
+ } else {
|
|
| 2016 |
+ data = config |
|
| 2017 |
+ } |
|
| 2018 |
+ |
|
| 2019 |
+ var containerIDFile *cidFile |
|
| 2020 |
+ if cidfile != "" {
|
|
| 2021 |
+ var err error |
|
| 2022 |
+ if containerIDFile, err = newCIDFile(cidfile); err != nil {
|
|
| 2023 |
+ return nil, err |
|
| 2024 |
+ } |
|
| 2025 |
+ defer containerIDFile.Close() |
|
| 2026 |
+ } |
|
| 2027 |
+ |
|
| 2023 | 2028 |
//create the container |
| 2024 |
- stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false)
|
|
| 2029 |
+ stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), data, false)
|
|
| 2025 | 2030 |
//if image not found try to pull it |
| 2026 | 2031 |
if statusCode == 404 {
|
| 2027 | 2032 |
fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", config.Image) |
| 2028 | 2033 |
|
| 2029 | 2034 |
if err = cli.pullImage(config.Image); err != nil {
|
| 2030 |
- return err |
|
| 2035 |
+ return nil, err |
|
| 2031 | 2036 |
} |
| 2032 | 2037 |
// Retry |
| 2033 |
- if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false); err != nil {
|
|
| 2034 |
- return err |
|
| 2038 |
+ if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), data, false); err != nil {
|
|
| 2039 |
+ return nil, err |
|
| 2035 | 2040 |
} |
| 2036 | 2041 |
} else if err != nil {
|
| 2042 |
+ return nil, err |
|
| 2043 |
+ } |
|
| 2044 |
+ |
|
| 2045 |
+ var result engine.Env |
|
| 2046 |
+ if err := result.Decode(stream); err != nil {
|
|
| 2047 |
+ return nil, err |
|
| 2048 |
+ } |
|
| 2049 |
+ |
|
| 2050 |
+ for _, warning := range result.GetList("Warnings") {
|
|
| 2051 |
+ fmt.Fprintf(cli.err, "WARNING: %s\n", warning) |
|
| 2052 |
+ } |
|
| 2053 |
+ |
|
| 2054 |
+ if containerIDFile != nil {
|
|
| 2055 |
+ if err = containerIDFile.Write(result.Get("Id")); err != nil {
|
|
| 2056 |
+ return nil, err |
|
| 2057 |
+ } |
|
| 2058 |
+ } |
|
| 2059 |
+ |
|
| 2060 |
+ return result, nil |
|
| 2061 |
+ |
|
| 2062 |
+} |
|
| 2063 |
+ |
|
| 2064 |
+func (cli *DockerCli) CmdCreate(args ...string) error {
|
|
| 2065 |
+ // FIXME: just use runconfig.Parse already |
|
| 2066 |
+ cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container")
|
|
| 2067 |
+ |
|
| 2068 |
+ // These are flags not stored in Config/HostConfig |
|
| 2069 |
+ var ( |
|
| 2070 |
+ flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
|
|
| 2071 |
+ ) |
|
| 2072 |
+ |
|
| 2073 |
+ config, hostConfig, cmd, err := runconfig.ParseSubcommand(cmd, args, nil) |
|
| 2074 |
+ if err != nil {
|
|
| 2037 | 2075 |
return err |
| 2038 | 2076 |
} |
| 2077 |
+ if config.Image == "" {
|
|
| 2078 |
+ cmd.Usage() |
|
| 2079 |
+ return nil |
|
| 2080 |
+ } |
|
| 2039 | 2081 |
|
| 2040 |
- var runResult engine.Env |
|
| 2041 |
- if err := runResult.Decode(stream); err != nil {
|
|
| 2082 |
+ createResult, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName) |
|
| 2083 |
+ if err != nil {
|
|
| 2042 | 2084 |
return err |
| 2043 | 2085 |
} |
| 2044 | 2086 |
|
| 2045 |
- for _, warning := range runResult.GetList("Warnings") {
|
|
| 2046 |
- fmt.Fprintf(cli.err, "WARNING: %s\n", warning) |
|
| 2087 |
+ fmt.Fprintf(cli.out, "%s\n", createResult.Get("Id"))
|
|
| 2088 |
+ |
|
| 2089 |
+ return nil |
|
| 2090 |
+} |
|
| 2091 |
+ |
|
| 2092 |
+func (cli *DockerCli) CmdRun(args ...string) error {
|
|
| 2093 |
+ // FIXME: just use runconfig.Parse already |
|
| 2094 |
+ cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container")
|
|
| 2095 |
+ |
|
| 2096 |
+ // These are flags not stored in Config/HostConfig |
|
| 2097 |
+ var ( |
|
| 2098 |
+ flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
|
|
| 2099 |
+ flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run container in the background and print new container ID")
|
|
| 2100 |
+ flSigProxy = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy received signals to the process (even in non-TTY mode). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.")
|
|
| 2101 |
+ flName = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
|
|
| 2102 |
+ |
|
| 2103 |
+ flAttach *opts.ListOpts |
|
| 2104 |
+ |
|
| 2105 |
+ ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d")
|
|
| 2106 |
+ ) |
|
| 2107 |
+ |
|
| 2108 |
+ config, hostConfig, cmd, err := runconfig.ParseSubcommand(cmd, args, nil) |
|
| 2109 |
+ if err != nil {
|
|
| 2110 |
+ return err |
|
| 2111 |
+ } |
|
| 2112 |
+ if config.Image == "" {
|
|
| 2113 |
+ cmd.Usage() |
|
| 2114 |
+ return nil |
|
| 2047 | 2115 |
} |
| 2048 | 2116 |
|
| 2049 |
- if len(hostConfig.ContainerIDFile) > 0 {
|
|
| 2050 |
- if _, err = containerIDFile.Write([]byte(runResult.Get("Id"))); err != nil {
|
|
| 2051 |
- return fmt.Errorf("Failed to write the container ID to the file: %s", err)
|
|
| 2117 |
+ if *flDetach {
|
|
| 2118 |
+ if fl := cmd.Lookup("attach"); fl != nil {
|
|
| 2119 |
+ flAttach = fl.Value.(*opts.ListOpts) |
|
| 2120 |
+ if flAttach.Len() != 0 {
|
|
| 2121 |
+ return fmt.Errorf("Conflicting options: -a and -d")
|
|
| 2122 |
+ } |
|
| 2123 |
+ } |
|
| 2124 |
+ if *flAutoRemove {
|
|
| 2125 |
+ return fmt.Errorf("Conflicting options: --rm and -d")
|
|
| 2052 | 2126 |
} |
| 2127 |
+ |
|
| 2128 |
+ config.AttachStdin = false |
|
| 2129 |
+ config.AttachStdout = false |
|
| 2130 |
+ config.AttachStderr = false |
|
| 2131 |
+ config.StdinOnce = false |
|
| 2132 |
+ } |
|
| 2133 |
+ |
|
| 2134 |
+ // Disable flSigProxy in case on TTY |
|
| 2135 |
+ sigProxy := *flSigProxy |
|
| 2136 |
+ if config.Tty {
|
|
| 2137 |
+ sigProxy = false |
|
| 2138 |
+ } |
|
| 2139 |
+ |
|
| 2140 |
+ runResult, err := cli.createContainer(config, nil, hostConfig.ContainerIDFile, *flName) |
|
| 2141 |
+ if err != nil {
|
|
| 2142 |
+ return err |
|
| 2053 | 2143 |
} |
| 2054 | 2144 |
|
| 2055 | 2145 |
if sigProxy {
|
| ... | ... |
@@ -2158,7 +2248,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
| 2158 | 2158 |
var status int |
| 2159 | 2159 |
|
| 2160 | 2160 |
// Attached mode |
| 2161 |
- if autoRemove {
|
|
| 2161 |
+ if *flAutoRemove {
|
|
| 2162 | 2162 |
// Autoremove: wait for the container to finish, retrieve |
| 2163 | 2163 |
// the exit code and remove the container |
| 2164 | 2164 |
if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/wait", nil, false)); err != nil {
|
| ... | ... |
@@ -50,6 +50,14 @@ func (daemon *Daemon) ContainerCreate(job *engine.Job) engine.Status {
|
| 50 | 50 |
for _, warning := range buildWarnings {
|
| 51 | 51 |
job.Errorf("%s\n", warning)
|
| 52 | 52 |
} |
| 53 |
+ |
|
| 54 |
+ if job.EnvExists("HostConfig") {
|
|
| 55 |
+ hostConfig := runconfig.ContainerHostConfigFromJob(job) |
|
| 56 |
+ if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
|
| 57 |
+ return job.Error(err) |
|
| 58 |
+ } |
|
| 59 |
+ } |
|
| 60 |
+ |
|
| 53 | 61 |
return engine.StatusOK |
| 54 | 62 |
} |
| 55 | 63 |
|
| ... | ... |
@@ -53,6 +53,7 @@ func init() {
|
| 53 | 53 |
{"build", "Build an image from a Dockerfile"},
|
| 54 | 54 |
{"commit", "Create a new image from a container's changes"},
|
| 55 | 55 |
{"cp", "Copy files/folders from a container's filesystem to the host path"},
|
| 56 |
+ {"create", "Create a new container"},
|
|
| 56 | 57 |
{"diff", "Inspect changes on a container's filesystem"},
|
| 57 | 58 |
{"events", "Get real time events from the server"},
|
| 58 | 59 |
{"export", "Stream the contents of a container as a tar archive"},
|
| ... | ... |
@@ -370,6 +370,63 @@ path. Paths are relative to the root of the filesystem. |
| 370 | 370 |
|
| 371 | 371 |
Copy files/folders from the PATH to the HOSTPATH |
| 372 | 372 |
|
| 373 |
+ |
|
| 374 |
+## create |
|
| 375 |
+ |
|
| 376 |
+Creates a new container. |
|
| 377 |
+ |
|
| 378 |
+ Usage: docker create [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...] |
|
| 379 |
+ |
|
| 380 |
+ |
|
| 381 |
+ -a, --attach=[] Attach to stdin, stdout or stderr. |
|
| 382 |
+ -c, --cpu-shares=0 CPU shares (relative weight) |
|
| 383 |
+ --cidfile="" Write the container ID to the file |
|
| 384 |
+ --dns=[] Set custom dns servers |
|
| 385 |
+ --dns-search=[] Set custom dns search domains |
|
| 386 |
+ -e, --env=[] Set environment variables |
|
| 387 |
+ --entrypoint="" Overwrite the default entrypoint of the image |
|
| 388 |
+ --env-file=[] Read in a line delimited file of ENV variables |
|
| 389 |
+ --expose=[] Expose a port from the container without publishing it to your host |
|
| 390 |
+ -h, --hostname="" Container host name |
|
| 391 |
+ -i, --interactive=false Keep stdin open even if not attached |
|
| 392 |
+ --link=[] Add link to another container (name:alias) |
|
| 393 |
+ --lxc-conf=[] (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" |
|
| 394 |
+ -m, --memory="" Memory limit (format: <number><optional unit>, where unit = b, k, m or g) |
|
| 395 |
+ --name="" Assign a name to the container |
|
| 396 |
+ --net="bridge" Set the Network mode for the container |
|
| 397 |
+ 'bridge': creates a new network stack for the container on the docker bridge |
|
| 398 |
+ 'none': no networking for this container |
|
| 399 |
+ 'container:<name|id>': reuses another container network stack |
|
| 400 |
+ 'host': use the host network stack inside the contaner |
|
| 401 |
+ -p, --publish=[] Publish a container's port to the host |
|
| 402 |
+ format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort |
|
| 403 |
+ (use 'docker port' to see the actual mapping) |
|
| 404 |
+ -P, --publish-all=false Publish all exposed ports to the host interfaces |
|
| 405 |
+ --privileged=false Give extended privileges to this container |
|
| 406 |
+ -t, --tty=false Allocate a pseudo-tty |
|
| 407 |
+ -u, --user="" Username or UID |
|
| 408 |
+ -v, --volume=[] Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container) |
|
| 409 |
+ --volumes-from=[] Mount volumes from the specified container(s) |
|
| 410 |
+ -w, --workdir="" Working directory inside the container |
|
| 411 |
+ |
|
| 412 |
+ |
|
| 413 |
+The `docker create` command `creates` a writeable container layer over |
|
| 414 |
+the specified image, and prepares it for running the specified |
|
| 415 |
+command. The container id is then printed to stdout. This is similar |
|
| 416 |
+to what `docker run -d <cli_run>`, does except the container is never |
|
| 417 |
+started. You can then use the `docker start <cli_start>` command to |
|
| 418 |
+start the container at any point. |
|
| 419 |
+ |
|
| 420 |
+This is useful when you want to set up a container configuration ahead |
|
| 421 |
+of time, so that it is ready to start when you need it. |
|
| 422 |
+ |
|
| 423 |
+### Example: |
|
| 424 |
+ |
|
| 425 |
+ $ sudo docker create -t -i fedora bash |
|
| 426 |
+ 6d8af538ec541dd581ebc2a24153a28329acb5268abe5ef868c1f1a261221752 |
|
| 427 |
+ $ sudo docker start -a -i 6d8af538ec5 |
|
| 428 |
+ bash-4.2# |
|
| 429 |
+ |
|
| 373 | 430 |
## diff |
| 374 | 431 |
|
| 375 | 432 |
List the changed files and directories in a container᾿s filesystem |
| ... | ... |
@@ -57,7 +57,27 @@ type HostConfig struct {
|
| 57 | 57 |
RestartPolicy RestartPolicy |
| 58 | 58 |
} |
| 59 | 59 |
|
| 60 |
+// This is used by the create command when you want to both set the |
|
| 61 |
+// Config and the HostConfig in the same call |
|
| 62 |
+type ConfigAndHostConfig struct {
|
|
| 63 |
+ Config |
|
| 64 |
+ HostConfig HostConfig |
|
| 65 |
+} |
|
| 66 |
+ |
|
| 67 |
+func MergeConfigs(config *Config, hostConfig *HostConfig) *ConfigAndHostConfig {
|
|
| 68 |
+ return &ConfigAndHostConfig{
|
|
| 69 |
+ *config, |
|
| 70 |
+ *hostConfig, |
|
| 71 |
+ } |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 60 | 74 |
func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
| 75 |
+ if job.EnvExists("HostConfig") {
|
|
| 76 |
+ hostConfig := HostConfig{}
|
|
| 77 |
+ job.GetenvJson("HostConfig", &hostConfig)
|
|
| 78 |
+ return &hostConfig |
|
| 79 |
+ } |
|
| 80 |
+ |
|
| 61 | 81 |
hostConfig := &HostConfig{
|
| 62 | 82 |
ContainerIDFile: job.Getenv("ContainerIDFile"),
|
| 63 | 83 |
Privileged: job.GetenvBool("Privileged"),
|
| ... | ... |
@@ -18,7 +18,6 @@ import ( |
| 18 | 18 |
|
| 19 | 19 |
var ( |
| 20 | 20 |
ErrInvalidWorkingDirectory = fmt.Errorf("The working directory is invalid. It needs to be an absolute path.")
|
| 21 |
- ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d")
|
|
| 22 | 21 |
ErrConflictContainerNetworkAndLinks = fmt.Errorf("Conflicting options: --net=container can't be used with links. This would result in undefined behavior.")
|
| 23 | 22 |
ErrConflictContainerNetworkAndDns = fmt.Errorf("Conflicting options: --net=container can't be used with --dns. This configuration is invalid.")
|
| 24 | 23 |
ErrConflictDetachAutoRemove = fmt.Errorf("Conflicting options: --rm and -d")
|
| ... | ... |
@@ -28,7 +27,7 @@ var ( |
| 28 | 28 |
ErrConflictRestartPolicyAndAutoRemove = fmt.Errorf("Conflicting options: --restart and --rm")
|
| 29 | 29 |
) |
| 30 | 30 |
|
| 31 |
-//FIXME Only used in tests |
|
| 31 |
+// FIXME Only used in tests |
|
| 32 | 32 |
func Parse(args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
| 33 | 33 |
cmd := flag.NewFlagSet("run", flag.ContinueOnError)
|
| 34 | 34 |
cmd.SetOutput(ioutil.Discard) |
| ... | ... |
@@ -60,8 +59,6 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 60 | 60 |
flCapAdd = opts.NewListOpts(nil) |
| 61 | 61 |
flCapDrop = opts.NewListOpts(nil) |
| 62 | 62 |
|
| 63 |
- flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
|
|
| 64 |
- flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run container in the background and print new container ID")
|
|
| 65 | 63 |
flNetwork = cmd.Bool([]string{"#n", "#-networking"}, true, "Enable networking for this container")
|
| 66 | 64 |
flPrivileged = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
|
| 67 | 65 |
flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to the host interfaces")
|
| ... | ... |
@@ -77,15 +74,13 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 77 | 77 |
flCpuset = cmd.String([]string{"-cpuset"}, "", "CPUs in which to allow execution (0-3, 0,1)")
|
| 78 | 78 |
flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container\n'bridge': creates a new network stack for the container on the docker bridge\n'none': no networking for this container\n'container:<name|id>': reuses another container network stack\n'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure.")
|
| 79 | 79 |
flRestartPolicy = cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits (no, on-failure[:max-retry], always)")
|
| 80 |
- // For documentation purpose |
|
| 81 |
- _ = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy received signals to the process (even in non-TTY mode). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.")
|
|
| 82 |
- _ = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
|
|
| 83 | 80 |
) |
| 84 | 81 |
|
| 85 | 82 |
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR.")
|
| 86 | 83 |
cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume (e.g., from the host: -v /host:/container, from Docker: -v /container)")
|
| 87 | 84 |
cmd.Var(&flLinks, []string{"#link", "-link"}, "Add link to another container in the form of name:alias")
|
| 88 | 85 |
cmd.Var(&flDevices, []string{"-device"}, "Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc)")
|
| 86 |
+ |
|
| 89 | 87 |
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
| 90 | 88 |
cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a line delimited file of environment variables")
|
| 91 | 89 |
|
| ... | ... |
@@ -109,15 +104,15 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 109 | 109 |
} |
| 110 | 110 |
|
| 111 | 111 |
// Validate input params |
| 112 |
- if *flDetach && flAttach.Len() > 0 {
|
|
| 113 |
- return nil, nil, cmd, ErrConflictAttachDetach |
|
| 114 |
- } |
|
| 115 | 112 |
if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) {
|
| 116 | 113 |
return nil, nil, cmd, ErrInvalidWorkingDirectory |
| 117 | 114 |
} |
| 118 |
- if *flDetach && *flAutoRemove {
|
|
| 119 |
- return nil, nil, cmd, ErrConflictDetachAutoRemove |
|
| 120 |
- } |
|
| 115 |
+ |
|
| 116 |
+ var ( |
|
| 117 |
+ attachStdin = flAttach.Get("stdin")
|
|
| 118 |
+ attachStdout = flAttach.Get("stdout")
|
|
| 119 |
+ attachStderr = flAttach.Get("stderr")
|
|
| 120 |
+ ) |
|
| 121 | 121 |
|
| 122 | 122 |
if *flNetMode != "bridge" && *flNetMode != "none" && *flHostname != "" {
|
| 123 | 123 |
return nil, nil, cmd, ErrConflictNetworkHostname |
| ... | ... |
@@ -140,13 +135,11 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 140 | 140 |
} |
| 141 | 141 |
|
| 142 | 142 |
// If neither -d or -a are set, attach to everything by default |
| 143 |
- if flAttach.Len() == 0 && !*flDetach {
|
|
| 144 |
- if !*flDetach {
|
|
| 145 |
- flAttach.Set("stdout")
|
|
| 146 |
- flAttach.Set("stderr")
|
|
| 147 |
- if *flStdin {
|
|
| 148 |
- flAttach.Set("stdin")
|
|
| 149 |
- } |
|
| 143 |
+ if flAttach.Len() == 0 {
|
|
| 144 |
+ attachStdout = true |
|
| 145 |
+ attachStderr = true |
|
| 146 |
+ if *flStdin {
|
|
| 147 |
+ attachStdin = true |
|
| 150 | 148 |
} |
| 151 | 149 |
} |
| 152 | 150 |
|
| ... | ... |
@@ -270,9 +263,9 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 270 | 270 |
Memory: flMemory, |
| 271 | 271 |
CpuShares: *flCpuShares, |
| 272 | 272 |
Cpuset: *flCpuset, |
| 273 |
- AttachStdin: flAttach.Get("stdin"),
|
|
| 274 |
- AttachStdout: flAttach.Get("stdout"),
|
|
| 275 |
- AttachStderr: flAttach.Get("stderr"),
|
|
| 273 |
+ AttachStdin: attachStdin, |
|
| 274 |
+ AttachStdout: attachStdout, |
|
| 275 |
+ AttachStderr: attachStderr, |
|
| 276 | 276 |
Env: envVariables, |
| 277 | 277 |
Cmd: runCmd, |
| 278 | 278 |
Image: image, |