func TestCompare(t *testing.T) { volumes1 := make(map[string]struct{}) volumes1["/test1"] = struct{}{} ports1 := make(nat.PortSet) ports1[nat.Port("1111/tcp")] = struct{}{} ports1[nat.Port("2222/tcp")] = struct{}{} config1 := Config{ ExposedPorts: ports1, Env: []string{"VAR1=1", "VAR2=2"}, Volumes: volumes1, } ports3 := make(nat.PortSet) ports3[nat.Port("0000/tcp")] = struct{}{} ports3[nat.Port("2222/tcp")] = struct{}{} config3 := Config{ ExposedPorts: ports3, Volumes: volumes1, } volumes2 := make(map[string]struct{}) volumes2["/test2"] = struct{}{} config5 := Config{ Env: []string{"VAR1=1", "VAR2=2"}, Volumes: volumes2, } if Compare(&config1, &config3) { t.Fatalf("Compare should return false, ExposedPorts are different") } if Compare(&config1, &config5) { t.Fatalf("Compare should return false, Volumes are different") } if !Compare(&config1, &config1) { t.Fatalf("Compare should return true") } }
func TestLinkNew(t *testing.T) { ports := make(nat.PortSet) ports[nat.Port("6379/tcp")] = struct{}{} link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", nil, ports) if err != nil { t.Fatal(err) } if link == nil { t.FailNow() } if link.Name != "/db/docker" { t.Fail() } if link.Alias() != "docker" { t.Fail() } if link.ParentIP != "172.0.17.3" { t.Fail() } if link.ChildIP != "172.0.17.2" { t.Fail() } for _, p := range link.Ports { if p != nat.Port("6379/tcp") { t.Fail() } } }
func TestLinkMultipleEnv(t *testing.T) { ports := make(nat.PortSet) ports[nat.Port("6379/tcp")] = struct{}{} ports[nat.Port("6380/tcp")] = struct{}{} ports[nat.Port("6381/tcp")] = struct{}{} link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports) if err != nil { t.Fatal(err) } rawEnv := link.ToEnv() env := make(map[string]string, len(rawEnv)) for _, e := range rawEnv { parts := strings.Split(e, "=") if len(parts) != 2 { t.FailNow() } env[parts[0]] = parts[1] } if env["DOCKER_PORT"] != "tcp://172.0.17.2:6379" { t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"]) } if env["DOCKER_PORT_6379_TCP_START"] != "tcp://172.0.17.2:6379" { t.Fatalf("Expected tcp://172.0.17.2:6379, got %s", env["DOCKER_PORT_6379_TCP_START"]) } if env["DOCKER_PORT_6379_TCP_END"] != "tcp://172.0.17.2:6381" { t.Fatalf("Expected tcp://172.0.17.2:6381, got %s", env["DOCKER_PORT_6379_TCP_END"]) } if env["DOCKER_PORT_6379_TCP_PROTO"] != "tcp" { t.Fatalf("Expected tcp, got %s", env["DOCKER_PORT_6379_TCP_PROTO"]) } if env["DOCKER_PORT_6379_TCP_ADDR"] != "172.0.17.2" { t.Fatalf("Expected 172.0.17.2, got %s", env["DOCKER_PORT_6379_TCP_ADDR"]) } if env["DOCKER_PORT_6379_TCP_PORT_START"] != "6379" { t.Fatalf("Expected 6379, got %s", env["DOCKER_PORT_6379_TCP_PORT_START"]) } if env["DOCKER_PORT_6379_TCP_PORT_END"] != "6381" { t.Fatalf("Expected 6381, got %s", env["DOCKER_PORT_6379_TCP_PORT_END"]) } if env["DOCKER_NAME"] != "/db/docker" { t.Fatalf("Expected /db/docker, got %s", env["DOCKER_NAME"]) } if env["DOCKER_ENV_PASSWORD"] != "gordon" { t.Fatalf("Expected gordon, got %s", env["DOCKER_ENV_PASSWORD"]) } }
func TestLinkNaming(t *testing.T) { ports := make(nat.PortSet) ports[nat.Port("6379/tcp")] = struct{}{} link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker-1", nil, ports) if err != nil { t.Fatal(err) } rawEnv := link.ToEnv() env := make(map[string]string, len(rawEnv)) for _, e := range rawEnv { parts := strings.Split(e, "=") if len(parts) != 2 { t.FailNow() } env[parts[0]] = parts[1] } value, ok := env["DOCKER_1_PORT"] if !ok { t.Fatalf("DOCKER_1_PORT not found in env") } if value != "tcp://172.0.17.2:6379" { t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_1_PORT"]) } }
// CmdPort lists port mappings for a container. // If a private port is specified, it also shows the public-facing port that is NATed to the private port. // // 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.Require(flag.Min, 1) cmd.ParseFlags(args, true) serverResp, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil) if err != nil { return err } defer serverResp.body.Close() var c struct { NetworkSettings struct { Ports nat.PortMap } } if err := json.NewDecoder(serverResp.body).Decode(&c); err != nil { return err } if cmd.NArg() == 2 { var ( port = cmd.Arg(1) proto = "tcp" parts = strings.SplitN(port, "/", 2) ) if len(parts) == 2 && len(parts[1]) != 0 { port = parts[0] proto = parts[1] } natPort := port + "/" + proto if frontends, exists := c.NetworkSettings.Ports[nat.Port(port+"/"+proto)]; exists && frontends != nil { for _, frontend := range frontends { fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort) } return nil } return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0)) } for from, frontends := range c.NetworkSettings.Ports { for _, frontend := range frontends { fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort) } } return nil }
func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointOption, error) { var ( portSpecs = make(nat.PortSet) bindings = make(nat.PortMap) pbList []types.PortBinding exposeList []types.TransportPort createOptions []libnetwork.EndpointOption ) if container.Config.ExposedPorts != nil { portSpecs = container.Config.ExposedPorts } if container.hostConfig.PortBindings != nil { for p, b := range container.hostConfig.PortBindings { bindings[p] = []nat.PortBinding{} for _, bb := range b { bindings[p] = append(bindings[p], nat.PortBinding{ HostIp: bb.HostIp, HostPort: bb.HostPort, }) } } } container.NetworkSettings.PortMapping = nil ports := make([]nat.Port, len(portSpecs)) var i int for p := range portSpecs { ports[i] = p i++ } nat.SortPortMap(ports, bindings) for _, port := range ports { expose := types.TransportPort{} expose.Proto = types.ParseProtocol(port.Proto()) expose.Port = uint16(port.Int()) exposeList = append(exposeList, expose) pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} binding := bindings[port] for i := 0; i < len(binding); i++ { pbCopy := pb.GetCopy() pbCopy.HostPort = uint16(nat.Port(binding[i].HostPort).Int()) pbCopy.HostIP = net.ParseIP(binding[i].HostIp) pbList = append(pbList, pbCopy) } if container.hostConfig.PublishAllPorts && len(binding) == 0 { pbList = append(pbList, pb) } } createOptions = append(createOptions, libnetwork.CreateOptionPortMapping(pbList), libnetwork.CreateOptionExposedPorts(exposeList)) if container.Config.MacAddress != "" { mac, err := net.ParseMAC(container.Config.MacAddress) if err != nil { return nil, err } genericOption := options.Generic{ netlabel.MacAddress: mac, } createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) } return createOptions, nil }
func TestMerge(t *testing.T) { volumesImage := make(map[string]struct{}) volumesImage["/test1"] = struct{}{} volumesImage["/test2"] = struct{}{} portsImage := make(nat.PortSet) portsImage[nat.Port("1111/tcp")] = struct{}{} portsImage[nat.Port("2222/tcp")] = struct{}{} configImage := &Config{ ExposedPorts: portsImage, Env: []string{"VAR1=1", "VAR2=2"}, Volumes: volumesImage, } portsUser := make(nat.PortSet) portsUser[nat.Port("2222/tcp")] = struct{}{} portsUser[nat.Port("3333/tcp")] = struct{}{} volumesUser := make(map[string]struct{}) volumesUser["/test3"] = struct{}{} configUser := &Config{ ExposedPorts: portsUser, Env: []string{"VAR2=3", "VAR3=3"}, Volumes: volumesUser, } if err := Merge(configUser, configImage); err != nil { t.Error(err) } if len(configUser.ExposedPorts) != 3 { t.Fatalf("Expected 3 ExposedPorts, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts)) } for portSpecs := range configUser.ExposedPorts { if portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" { t.Fatalf("Expected 1111 or 2222 or 3333, found %s", portSpecs) } } if len(configUser.Env) != 3 { t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env)) } for _, env := range configUser.Env { if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" { t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env) } } if len(configUser.Volumes) != 3 { t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes)) } for v := range configUser.Volumes { if v != "/test1" && v != "/test2" && v != "/test3" { t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v) } } ports, _, err := nat.ParsePortSpecs([]string{"0000"}) if err != nil { t.Error(err) } configImage2 := &Config{ ExposedPorts: ports, } if err := Merge(configUser, configImage2); err != nil { t.Error(err) } if len(configUser.ExposedPorts) != 4 { t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts)) } for portSpecs := range configUser.ExposedPorts { if portSpecs.Port() != "0" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" { t.Fatalf("Expected %q or %q or %q or %q, found %s", 0, 1111, 2222, 3333, portSpecs) } } }
func TestLinkPortRangeEnv(t *testing.T) { ports := make(nat.PortSet) ports[nat.Port("6379/tcp")] = struct{}{} ports[nat.Port("6380/tcp")] = struct{}{} ports[nat.Port("6381/tcp")] = struct{}{} link, err := NewLink("172.0.17.3", "172.0.17.2", "/db/docker", []string{"PASSWORD=gordon"}, ports) if err != nil { t.Fatal(err) } rawEnv := link.ToEnv() env := make(map[string]string, len(rawEnv)) for _, e := range rawEnv { parts := strings.Split(e, "=") if len(parts) != 2 { t.FailNow() } env[parts[0]] = parts[1] } if env["DOCKER_PORT"] != "tcp://172.0.17.2:6379" { t.Fatalf("Expected 172.0.17.2:6379, got %s", env["DOCKER_PORT"]) } if env["DOCKER_PORT_6379_TCP_START"] != "tcp://172.0.17.2:6379" { t.Fatalf("Expected tcp://172.0.17.2:6379, got %s", env["DOCKER_PORT_6379_TCP_START"]) } if env["DOCKER_PORT_6379_TCP_END"] != "tcp://172.0.17.2:6381" { t.Fatalf("Expected tcp://172.0.17.2:6381, got %s", env["DOCKER_PORT_6379_TCP_END"]) } if env["DOCKER_PORT_6379_TCP_PROTO"] != "tcp" { t.Fatalf("Expected tcp, got %s", env["DOCKER_PORT_6379_TCP_PROTO"]) } if env["DOCKER_PORT_6379_TCP_ADDR"] != "172.0.17.2" { t.Fatalf("Expected 172.0.17.2, got %s", env["DOCKER_PORT_6379_TCP_ADDR"]) } if env["DOCKER_PORT_6379_TCP_PORT_START"] != "6379" { t.Fatalf("Expected 6379, got %s", env["DOCKER_PORT_6379_TCP_PORT_START"]) } if env["DOCKER_PORT_6379_TCP_PORT_END"] != "6381" { t.Fatalf("Expected 6381, got %s", env["DOCKER_PORT_6379_TCP_PORT_END"]) } if env["DOCKER_NAME"] != "/db/docker" { t.Fatalf("Expected /db/docker, got %s", env["DOCKER_NAME"]) } if env["DOCKER_ENV_PASSWORD"] != "gordon" { t.Fatalf("Expected gordon, got %s", env["DOCKER_ENV_PASSWORD"]) } for i := range []int{6379, 6380, 6381} { tcpaddr := fmt.Sprintf("DOCKER_PORT_%d_TCP_ADDR", i) tcpport := fmt.Sprintf("DOCKER_PORT_%d_TCP+PORT", i) tcpproto := fmt.Sprintf("DOCKER_PORT_%d_TCP+PROTO", i) tcp := fmt.Sprintf("DOCKER_PORT_%d_TCP", i) if env[tcpaddr] == "172.0.17.2" { t.Fatalf("Expected env %s = 172.0.17.2, got %s", tcpaddr, env[tcpaddr]) } if env[tcpport] == fmt.Sprintf("%d", i) { t.Fatalf("Expected env %s = %d, got %s", tcpport, i, env[tcpport]) } if env[tcpproto] == "tcp" { t.Fatalf("Expected env %s = tcp, got %s", tcpproto, env[tcpproto]) } if env[tcp] == fmt.Sprintf("tcp://172.0.17.2:%d", i) { t.Fatalf("Expected env %s = tcp://172.0.17.2:%d, got %s", tcp, i, env[tcp]) } } }
// Support cross-host linking func (c *Cluster) processLinks(containerNode *node.Node, config *cluster.ContainerConfig) error { originalLinks := config.HostConfig.Links if originalLinks == nil || len(originalLinks) == 0 { return nil } containers := c.Containers() //Cache for the container info in linking cache := map[string](*dockerclient.ContainerInfo){} addr := containerNode.Addr var newLinks []string var newEnv []string var crossHostLinks []string for _, link := range originalLinks { //Parse the link info linkInfo := strings.Split(link, ":") name, alias := linkInfo[0], linkInfo[1] linkContainerName := "/" + name for _, target := range containers { if target.Info.Name == linkContainerName { if addr == target.Engine.Addr { log.Debug("No additional work for the container link on the same host") } else { //Update the link var err error targetInfo := cache[target.Id] if targetInfo == nil { targetInfo, err = target.Engine.InspectContainer(target.Id) if err != nil { log.Warningf("Failed to find the linked container %s: %v", target.Id, err) return err } cache[target.Id] = targetInfo } //Simulate link for container on other hosts ports := make(nat.PortSet) for p := range targetInfo.NetworkSettings.Ports { ports[nat.Port(p)] = struct{}{} } linkName := fmt.Sprintf("/%s/%s", name, alias) newLink, err := links.NewLink("", targetInfo.NetworkSettings.IPAddress, linkName, targetInfo.Config.Env, ports) //Add as cross-host links crossHostLinks = append(crossHostLinks, link) //Ignore this link from the host config link = "" env := newLink.ToEnv() newEnv = append(newEnv, env...) newHost := alias + ":" + targetInfo.NetworkSettings.IPAddress config.HostConfig.ExtraHosts = append(config.HostConfig.ExtraHosts, newHost) } break } } if link != "" { newLinks = append(newLinks, link) } } //Update the Links config.HostConfig.Links = newLinks //Update the Env config.Env = append(config.Env, newEnv...) //Add the Env CROSS_HOST_LINKS if crossHostLinks != nil { envCrossHostLinks := "CROSS_HOST_LINKS=" + strings.Join(crossHostLinks, ";") config.Env = append(config.Env, envCrossHostLinks) } return nil }
func TestCompare(t *testing.T) { ports1 := make(nat.PortSet) ports1[nat.Port("1111/tcp")] = struct{}{} ports1[nat.Port("2222/tcp")] = struct{}{} ports2 := make(nat.PortSet) ports2[nat.Port("3333/tcp")] = struct{}{} ports2[nat.Port("4444/tcp")] = struct{}{} ports3 := make(nat.PortSet) ports3[nat.Port("1111/tcp")] = struct{}{} ports3[nat.Port("2222/tcp")] = struct{}{} ports3[nat.Port("5555/tcp")] = struct{}{} volumes1 := make(map[string]struct{}) volumes1["/test1"] = struct{}{} volumes2 := make(map[string]struct{}) volumes2["/test2"] = struct{}{} volumes3 := make(map[string]struct{}) volumes3["/test1"] = struct{}{} volumes3["/test3"] = struct{}{} envs1 := []string{"ENV1=value1", "ENV2=value2"} envs2 := []string{"ENV1=value1", "ENV3=value3"} entrypoint1 := &Entrypoint{parts: []string{"/bin/sh", "-c"}} entrypoint2 := &Entrypoint{parts: []string{"/bin/sh", "-d"}} entrypoint3 := &Entrypoint{parts: []string{"/bin/sh", "-c", "echo"}} cmd1 := &Command{parts: []string{"/bin/sh", "-c"}} cmd2 := &Command{parts: []string{"/bin/sh", "-d"}} cmd3 := &Command{parts: []string{"/bin/sh", "-c", "echo"}} labels1 := map[string]string{"LABEL1": "value1", "LABEL2": "value2"} labels2 := map[string]string{"LABEL1": "value1", "LABEL2": "value3"} labels3 := map[string]string{"LABEL1": "value1", "LABEL2": "value2", "LABEL3": "value3"} sameConfigs := map[*Config]*Config{ // Empty config &Config{}: {}, // Does not compare hostname, domainname & image &Config{ Hostname: "host1", Domainname: "domain1", Image: "image1", User: "******", }: { Hostname: "host2", Domainname: "domain2", Image: "image2", User: "******", }, // only OpenStdin &Config{OpenStdin: false}: {OpenStdin: false}, // only env &Config{Env: envs1}: {Env: envs1}, // only cmd &Config{Cmd: cmd1}: {Cmd: cmd1}, // only labels &Config{Labels: labels1}: {Labels: labels1}, // only exposedPorts &Config{ExposedPorts: ports1}: {ExposedPorts: ports1}, // only entrypoints &Config{Entrypoint: entrypoint1}: {Entrypoint: entrypoint1}, // only volumes &Config{Volumes: volumes1}: {Volumes: volumes1}, } differentConfigs := map[*Config]*Config{ nil: nil, &Config{ Hostname: "host1", Domainname: "domain1", Image: "image1", User: "******", }: { Hostname: "host1", Domainname: "domain1", Image: "image1", User: "******", }, // only OpenStdin &Config{OpenStdin: false}: {OpenStdin: true}, &Config{OpenStdin: true}: {OpenStdin: false}, // only env &Config{Env: envs1}: {Env: envs2}, // only cmd &Config{Cmd: cmd1}: {Cmd: cmd2}, // not the same number of parts &Config{Cmd: cmd1}: {Cmd: cmd3}, // only labels &Config{Labels: labels1}: {Labels: labels2}, // not the same number of labels &Config{Labels: labels1}: {Labels: labels3}, // only exposedPorts &Config{ExposedPorts: ports1}: {ExposedPorts: ports2}, // not the same number of ports &Config{ExposedPorts: ports1}: {ExposedPorts: ports3}, // only entrypoints &Config{Entrypoint: entrypoint1}: {Entrypoint: entrypoint2}, // not the same number of parts &Config{Entrypoint: entrypoint1}: {Entrypoint: entrypoint3}, // only volumes &Config{Volumes: volumes1}: {Volumes: volumes2}, // not the same number of labels &Config{Volumes: volumes1}: {Volumes: volumes3}, } for config1, config2 := range sameConfigs { if !Compare(config1, config2) { t.Fatalf("Compare should be true for [%v] and [%v]", config1, config2) } } for config1, config2 := range differentConfigs { if Compare(config1, config2) { t.Fatalf("Compare should be false for [%v] and [%v]", config1, config2) } } }