Пример #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, nil)
	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, nil)
	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
func TestLinkContainers(t *testing.T) {
	// Init driver
	if err := InitDriver(new(Config)); err != nil {
		t.Fatal("Failed to initialize network driver")
	}

	// Allocate interface
	if _, err := Allocate("container_id", "", "", ""); err != nil {
		t.Fatal("Failed to allocate network interface")
	}

	bridgeIface = "lo"
	if _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter, false); err != nil {
		t.Fatal(err)
	}

	if err := LinkContainers("-I", "172.17.0.1", "172.17.0.2", []nat.Port{nat.Port("1234")}, false); err != nil {
		t.Fatal("LinkContainers failed")
	}

	// flush rules
	if _, err := iptables.Raw([]string{"-F", "DOCKER"}...); err != nil {
		t.Fatal(err)
	}

}
Пример #6
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", "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)

	stream, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil)
	if err != nil {
		return err
	}

	var c struct {
		NetworkSettings struct {
			Ports nat.PortMap
		}
	}

	if err := json.NewDecoder(stream).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
}
Пример #7
0
func TestHostnameFormatChecking(t *testing.T) {
	freePort := findFreePort(t)

	if err := InitDriver(new(Config)); err != nil {
		t.Fatal("Failed to initialize network driver")
	}

	// Allocate interface
	if _, err := Allocate("container_id", "", "", ""); err != nil {
		t.Fatal("Failed to allocate network interface")
	}

	port := nat.Port(freePort + "/tcp")
	binding := nat.PortBinding{HostIp: "localhost", HostPort: freePort}

	if _, err := AllocatePort("container_id", port, binding); err == nil {
		t.Fatal("Failed to check invalid HostIP")
	}
}
Пример #8
0
func LinkContainers(job *engine.Job) error {
	var (
		action       = job.Args[0]
		nfAction     iptables.Action
		childIP      = job.Getenv("ChildIP")
		parentIP     = job.Getenv("ParentIP")
		ignoreErrors = job.GetenvBool("IgnoreErrors")
		ports        = job.GetenvList("Ports")
	)

	switch action {
	case "-A":
		nfAction = iptables.Append
	case "-I":
		nfAction = iptables.Insert
	case "-D":
		nfAction = iptables.Delete
	default:
		return fmt.Errorf("Invalid action '%s' specified", action)
	}

	ip1 := net.ParseIP(parentIP)
	if ip1 == nil {
		return fmt.Errorf("Parent IP '%s' is invalid", parentIP)
	}
	ip2 := net.ParseIP(childIP)
	if ip2 == nil {
		return fmt.Errorf("Child IP '%s' is invalid", childIP)
	}

	chain := iptables.Chain{Name: "DOCKER", Bridge: bridgeIface}
	for _, p := range ports {
		port := nat.Port(p)
		if err := chain.Link(nfAction, ip1, ip2, port.Int(), port.Proto()); !ignoreErrors && err != nil {
			return err
		}
	}
	return nil
}
Пример #9
0
func TestAllocatePortDetection(t *testing.T) {
	freePort := findFreePort(t)

	if err := InitDriver(new(Config)); err != nil {
		t.Fatal("Failed to initialize network driver")
	}

	// Allocate interface
	if _, err := Allocate("container_id", "", "", ""); err != nil {
		t.Fatal("Failed to allocate network interface")
	}

	port := nat.Port(freePort + "/tcp")
	binding := nat.PortBinding{HostIp: "127.0.0.1", HostPort: freePort}

	// Allocate same port twice, expect failure on second call
	if _, err := AllocatePort("container_id", port, binding); err != nil {
		t.Fatal("Failed to find a free port to allocate")
	}
	if _, err := AllocatePort("container_id", port, binding); err == nil {
		t.Fatal("Duplicate port allocation granted by AllocatePort")
	}
}
Пример #10
0
func LinkContainers(job *engine.Job) engine.Status {
	var (
		action       = job.Args[0]
		childIP      = job.Getenv("ChildIP")
		parentIP     = job.Getenv("ParentIP")
		ignoreErrors = job.GetenvBool("IgnoreErrors")
		ports        = job.GetenvList("Ports")
	)
	for _, value := range ports {
		port := nat.Port(value)
		if output, err := iptables.Raw(action, "FORWARD",
			"-i", bridgeIface, "-o", bridgeIface,
			"-p", port.Proto(),
			"-s", parentIP,
			"--dport", strconv.Itoa(port.Int()),
			"-d", childIP,
			"-j", "ACCEPT"); !ignoreErrors && err != nil {
			return job.Error(err)
		} else if len(output) != 0 {
			return job.Errorf("Error toggle iptables forward: %s", output)
		}

		if output, err := iptables.Raw(action, "FORWARD",
			"-i", bridgeIface, "-o", bridgeIface,
			"-p", port.Proto(),
			"-s", childIP,
			"--sport", strconv.Itoa(port.Int()),
			"-d", parentIP,
			"-j", "ACCEPT"); !ignoreErrors && err != nil {
			return job.Error(err)
		} else if len(output) != 0 {
			return job.Errorf("Error toggle iptables forward: %s", output)
		}
	}
	return engine.StatusOK
}
Пример #11
0
func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daemon.Container, string) {
	var (
		err          error
		id           string
		outputBuffer = bytes.NewBuffer(nil)
		strPort      string
		eng          = NewTestEngine(t)
		daemon       = mkDaemonFromEngine(eng, t)
		port         = 5554
		p            nat.Port
	)
	defer func() {
		if err != nil {
			daemon.Nuke()
		}
	}()

	for {
		port += 1
		strPort = strconv.Itoa(port)
		var cmd string
		if proto == "tcp" {
			cmd = "socat TCP-LISTEN:" + strPort + ",reuseaddr,fork EXEC:/bin/cat"
		} else if proto == "udp" {
			cmd = "socat UDP-RECVFROM:" + strPort + ",fork EXEC:/bin/cat"
		} else {
			t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
		}
		ep := make(map[nat.Port]struct{}, 1)
		p = nat.Port(fmt.Sprintf("%s/%s", strPort, proto))
		ep[p] = struct{}{}

		jobCreate := eng.Job("create")
		jobCreate.Setenv("Image", unitTestImageID)
		jobCreate.SetenvList("Cmd", []string{"sh", "-c", cmd})
		jobCreate.SetenvList("PortSpecs", []string{fmt.Sprintf("%s/%s", strPort, proto)})
		jobCreate.SetenvJson("ExposedPorts", ep)
		jobCreate.Stdout.Add(outputBuffer)
		if err := jobCreate.Run(); err != nil {
			t.Fatal(err)
		}
		id = engine.Tail(outputBuffer, 1)
		// FIXME: this relies on the undocumented behavior of daemon.Create
		// which will return a nil error AND container if the exposed ports
		// are invalid. That behavior should be fixed!
		if id != "" {
			break
		}
		t.Logf("Port %v already in use, trying another one", strPort)

	}

	jobStart := eng.Job("start", id)
	portBindings := make(map[nat.Port][]nat.PortBinding)
	portBindings[p] = []nat.PortBinding{
		{},
	}
	if err := jobStart.SetenvJson("PortsBindings", portBindings); err != nil {
		t.Fatal(err)
	}
	if err := jobStart.Run(); err != nil {
		t.Fatal(err)
	}

	container := daemon.Get(id)
	if container == nil {
		t.Fatalf("Couldn't fetch test container %s", id)
	}

	setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
		for !container.IsRunning() {
			time.Sleep(10 * time.Millisecond)
		}
	})

	// Even if the state is running, lets give some time to lxc to spawn the process
	container.WaitStop(500 * time.Millisecond)

	strPort = container.NetworkSettings.Ports[p][0].HostPort
	return daemon, container, strPort
}
Пример #12
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])
		}
	}
}
Пример #13
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.PortSpecs != nil {
		if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
			return nil, err
		}
		container.Config.PortSpecs = nil
		if err := container.WriteHostConfig(); err != nil {
			return nil, err
		}
	}

	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
}
Пример #14
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)
		}
	}
}
Пример #15
0
func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daemon.Container, string) {
	var (
		err     error
		id      string
		strPort string
		eng     = NewTestEngine(t)
		daemon  = mkDaemonFromEngine(eng, t)
		port    = 5554
		p       nat.Port
	)
	defer func() {
		if err != nil {
			daemon.Nuke()
		}
	}()

	for {
		port += 1
		strPort = strconv.Itoa(port)
		var cmd string
		if proto == "tcp" {
			cmd = "socat TCP-LISTEN:" + strPort + ",reuseaddr,fork EXEC:/bin/cat"
		} else if proto == "udp" {
			cmd = "socat UDP-RECVFROM:" + strPort + ",fork EXEC:/bin/cat"
		} else {
			t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
		}
		ep := make(map[nat.Port]struct{}, 1)
		p = nat.Port(fmt.Sprintf("%s/%s", strPort, proto))
		ep[p] = struct{}{}

		c := &runconfig.Config{
			Image:        unitTestImageID,
			Cmd:          runconfig.NewCommand("sh", "-c", cmd),
			PortSpecs:    []string{fmt.Sprintf("%s/%s", strPort, proto)},
			ExposedPorts: ep,
		}

		id, _, err = daemon.ContainerCreate(unitTestImageID, c, &runconfig.HostConfig{})
		// FIXME: this relies on the undocumented behavior of daemon.Create
		// which will return a nil error AND container if the exposed ports
		// are invalid. That behavior should be fixed!
		if id != "" {
			break
		}
		t.Logf("Port %v already in use, trying another one", strPort)

	}

	if err := daemon.ContainerStart(id, &runconfig.HostConfig{}); err != nil {
		t.Fatal(err)
	}

	container, err := daemon.Get(id)
	if err != nil {
		t.Fatal(err)
	}

	setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
		for !container.IsRunning() {
			time.Sleep(10 * time.Millisecond)
		}
	})

	// Even if the state is running, lets give some time to lxc to spawn the process
	container.WaitStop(500 * time.Millisecond)

	strPort = container.NetworkSettings.Ports[p][0].HostPort
	return daemon, container, strPort
}