diff --git a/daemon/daemon.go b/daemon/daemon.go index 70f4a7b21b..e64da1cde9 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -686,14 +686,14 @@ func (daemon *Daemon) RegisterLink(parent, child *Container, alias string) error func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.HostConfig) error { if hostConfig != nil && hostConfig.Links != nil { for _, l := range hostConfig.Links { - parts, err := parsers.PartParser("name:alias", l) + name, alias, err := parsers.ParseLink(l) if err != nil { return err } - child, err := daemon.Get(parts["name"]) + child, err := daemon.Get(name) if err != nil { //An error from daemon.Get() means this name could not be found - return fmt.Errorf("Could not get container for %s", parts["name"]) + return fmt.Errorf("Could not get container for %s", name) } for child.hostConfig.NetworkMode.IsContainer() { parts := strings.SplitN(string(child.hostConfig.NetworkMode), ":", 2) @@ -705,7 +705,7 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig. if child.hostConfig.NetworkMode.IsHost() { return runconfig.ErrConflictHostNetworkAndLinks } - if err := daemon.RegisterLink(container, child, parts["alias"]); err != nil { + if err := daemon.RegisterLink(container, child, alias); err != nil { return err } } diff --git a/docs/man/docker-create.1.md b/docs/man/docker-create.1.md index 18a6f870dc..02958e55ed 100644 --- a/docs/man/docker-create.1.md +++ b/docs/man/docker-create.1.md @@ -137,7 +137,8 @@ two memory nodes. Read labels from a file. Delimit each label with an EOL. **--link**=[] - Add link to another container in the form of :alias + Add link to another container in the form of :alias or just + in which case the alias will match the name. **--lxc-conf**=[] (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index 6e533ec6f2..57bda2b65b 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -238,7 +238,8 @@ ENTRYPOINT. Read in a line delimited file of labels **--link**=[] - Add link to another container in the form of :alias + Add link to another container in the form of :alias or just +in which case the alias will match the name If the operator uses **--link** when starting the new client container, then the client diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 30e2f80d0b..c0a88fb737 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -2138,6 +2138,12 @@ Guide. The `--link` flag will link the container named `/redis` into the newly created container with the alias `redis`. The new container can access the network and environment of the `redis` container via environment variables. +The `--link` flag will also just accept the form `` in which case +the alias will match the name. For instance, you could have written the previous +example as: + + $ docker run --link redis --name console ubuntu bash + The `--name` flag will assign the name `console` to the newly created container. diff --git a/docs/sources/reference/run.md b/docs/sources/reference/run.md index aafa34dfc8..fdc905fe44 100644 --- a/docs/sources/reference/run.md +++ b/docs/sources/reference/run.md @@ -942,7 +942,7 @@ or override the Dockerfile's exposed defaults: Both hostPort and containerPort can be specified as a range of ports. When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range. (e.g., `-p 1234-1236:1234-1236/tcp`) (use 'docker port' to see the actual mapping) - --link="" : Add link to another container (:alias) + --link="" : Add link to another container (:alias or ) As mentioned previously, `EXPOSE` (and `--expose`) makes ports available **in** a container for incoming connections. The port number on the diff --git a/docs/sources/userguide/dockerlinks.md b/docs/sources/userguide/dockerlinks.md index 8a20388463..2b7d30cd44 100644 --- a/docs/sources/userguide/dockerlinks.md +++ b/docs/sources/userguide/dockerlinks.md @@ -114,7 +114,7 @@ You can also use `docker inspect` to return the container's name. $ docker inspect -f "{{ .Name }}" aed84ee21bde /web -> **Note:** +> **Note:** > Container names have to be unique. That means you can only call > one container `web`. If you want to re-use a container name you must delete > the old container (with `docker rm`) before you can create a new @@ -151,6 +151,14 @@ earlier. The `--link` flag takes the form: Where `name` is the name of the container we're linking to and `alias` is an alias for the link name. You'll see how that alias gets used shortly. +The `--link` flag also takes the form: + + --link + +In which case the alias will match the name. You could have written the previous +example as: + + $ docker run -d -P --name web --link db training/webapp python app.py Next, inspect your linked containers with `docker inspect`: diff --git a/integration-cli/docker_cli_links_test.go b/integration-cli/docker_cli_links_test.go index 6bb173c10c..56932163ea 100644 --- a/integration-cli/docker_cli_links_test.go +++ b/integration-cli/docker_cli_links_test.go @@ -15,7 +15,6 @@ import ( ) func (s *DockerSuite) TestLinksEtcHostsRegularFile(c *check.C) { - runCmd := exec.Command(dockerBinary, "run", "--net=host", "busybox", "ls", "-la", "/etc/hosts") out, _, _, err := runCommandWithStdoutStderr(runCmd) if err != nil { @@ -331,3 +330,23 @@ func (s *DockerSuite) TestLinksEnvs(c *check.C) { c.Fatalf("Incorrect output: %s", out) } } + +func (s *DockerSuite) TestLinkShortDefinition(c *check.C) { + runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "shortlinkdef", "busybox", "top") + out, _, err := runCommandWithOutput(runCmd) + c.Assert(err, check.IsNil) + + cid := strings.TrimSpace(out) + c.Assert(waitRun(cid), check.IsNil) + + runCmd = exec.Command(dockerBinary, "run", "-d", "--name", "link2", "--link", "shortlinkdef", "busybox", "top") + out, _, err = runCommandWithOutput(runCmd) + c.Assert(err, check.IsNil) + + cid2 := strings.TrimSpace(out) + c.Assert(waitRun(cid2), check.IsNil) + + links, err := inspectFieldJSON(cid2, "HostConfig.Links") + c.Assert(err, check.IsNil) + c.Assert(links, check.Equals, "[\"/shortlinkdef:/link2/shortlinkdef\"]") +} diff --git a/opts/opts.go b/opts/opts.go index 3801596631..c330c27a5d 100644 --- a/opts/opts.go +++ b/opts/opts.go @@ -196,7 +196,7 @@ func ValidateAttach(val string) (string, error) { } func ValidateLink(val string) (string, error) { - if _, err := parsers.PartParser("name:alias", val); err != nil { + if _, _, err := parsers.ParseLink(val); err != nil { return val, err } return val, nil diff --git a/pkg/parsers/parsers.go b/pkg/parsers/parsers.go index 59e294dc22..5049613ac5 100644 --- a/pkg/parsers/parsers.go +++ b/pkg/parsers/parsers.go @@ -135,3 +135,17 @@ func ParsePortRange(ports string) (uint64, uint64, error) { } return start, end, nil } + +func ParseLink(val string) (string, string, error) { + if val == "" { + return "", "", fmt.Errorf("empty string specified for links") + } + arr := strings.Split(val, ":") + if len(arr) > 2 { + return "", "", fmt.Errorf("bad format for links: %s", val) + } + if len(arr) == 1 { + return val, val, nil + } + return arr[0], arr[1], nil +} diff --git a/pkg/parsers/parsers_test.go b/pkg/parsers/parsers_test.go index bc9a1e943c..89f4ae023a 100644 --- a/pkg/parsers/parsers_test.go +++ b/pkg/parsers/parsers_test.go @@ -123,3 +123,35 @@ func TestParsePortRangeIncorrectStartRange(t *testing.T) { t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) } } + +func TestParseLink(t *testing.T) { + name, alias, err := ParseLink("name:alias") + if err != nil { + t.Fatalf("Expected not to error out on a valid name:alias format but got: %v", err) + } + if name != "name" { + t.Fatalf("Link name should have been name, got %s instead", name) + } + if alias != "alias" { + t.Fatalf("Link alias should have been alias, got %s instead", alias) + } + // short format definition + name, alias, err = ParseLink("name") + if err != nil { + t.Fatalf("Expected not to error out on a valid name only format but got: %v", err) + } + if name != "name" { + t.Fatalf("Link name should have been name, got %s instead", name) + } + if alias != "name" { + t.Fatalf("Link alias should have been name, got %s instead", alias) + } + // empty string link definition is not allowed + if _, _, err := ParseLink(""); err == nil || !strings.Contains(err.Error(), "empty string specified for links") { + t.Fatalf("Expected error 'empty string specified for links' but got: %v", err) + } + // more than two colons are not allowed + if _, _, err := ParseLink("link:alias:wrong"); err == nil || !strings.Contains(err.Error(), "bad format for links: link:alias:wrong") { + t.Fatalf("Expected error 'bad format for links: link:alias:wrong' but got: %v", err) + } +} diff --git a/runconfig/config_test.go b/runconfig/config_test.go index 87fc6c6aac..8b1a49f11b 100644 --- a/runconfig/config_test.go +++ b/runconfig/config_test.go @@ -45,13 +45,6 @@ func TestParseRunLinks(t *testing.T) { if _, hostConfig := mustParse(t, ""); len(hostConfig.Links) != 0 { t.Fatalf("Error parsing links. No link expected, received: %v", hostConfig.Links) } - - if _, _, err := parse(t, "--link a"); err == nil { - t.Fatalf("Error parsing links. `--link a` should be an error but is not") - } - if _, _, err := parse(t, "--link"); err == nil { - t.Fatalf("Error parsing links. `--link` should be an error but is not") - } } func TestParseRunAttach(t *testing.T) {