Пример #1
0
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")
	}
}
Пример #2
0
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()
		}
	}
}
Пример #3
0
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"])
	}
}
Пример #4
0
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"])
	}
}
Пример #5
0
// 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
}
Пример #6
0
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
}
Пример #7
0
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)
		}
	}
}
Пример #8
0
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])
		}
	}
}
Пример #9
0
// 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
}
Пример #10
0
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)
		}
	}
}