github.com/OpenFlowLabs/moby@v17.12.1-ce-rc2+incompatible/integration-cli/docker_cli_port_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"regexp"
     7  	"sort"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/docker/docker/integration-cli/checker"
    12  	"github.com/go-check/check"
    13  )
    14  
    15  func (s *DockerSuite) TestPortList(c *check.C) {
    16  	testRequires(c, DaemonIsLinux)
    17  	// one port
    18  	out, _ := dockerCmd(c, "run", "-d", "-p", "9876:80", "busybox", "top")
    19  	firstID := strings.TrimSpace(out)
    20  
    21  	out, _ = dockerCmd(c, "port", firstID, "80")
    22  
    23  	err := assertPortList(c, out, []string{"0.0.0.0:9876"})
    24  	// Port list is not correct
    25  	c.Assert(err, checker.IsNil)
    26  
    27  	out, _ = dockerCmd(c, "port", firstID)
    28  
    29  	err = assertPortList(c, out, []string{"80/tcp -> 0.0.0.0:9876"})
    30  	// Port list is not correct
    31  	c.Assert(err, checker.IsNil)
    32  
    33  	dockerCmd(c, "rm", "-f", firstID)
    34  
    35  	// three port
    36  	out, _ = dockerCmd(c, "run", "-d",
    37  		"-p", "9876:80",
    38  		"-p", "9877:81",
    39  		"-p", "9878:82",
    40  		"busybox", "top")
    41  	ID := strings.TrimSpace(out)
    42  
    43  	out, _ = dockerCmd(c, "port", ID, "80")
    44  
    45  	err = assertPortList(c, out, []string{"0.0.0.0:9876"})
    46  	// Port list is not correct
    47  	c.Assert(err, checker.IsNil)
    48  
    49  	out, _ = dockerCmd(c, "port", ID)
    50  
    51  	err = assertPortList(c, out, []string{
    52  		"80/tcp -> 0.0.0.0:9876",
    53  		"81/tcp -> 0.0.0.0:9877",
    54  		"82/tcp -> 0.0.0.0:9878"})
    55  	// Port list is not correct
    56  	c.Assert(err, checker.IsNil)
    57  
    58  	dockerCmd(c, "rm", "-f", ID)
    59  
    60  	// more and one port mapped to the same container port
    61  	out, _ = dockerCmd(c, "run", "-d",
    62  		"-p", "9876:80",
    63  		"-p", "9999:80",
    64  		"-p", "9877:81",
    65  		"-p", "9878:82",
    66  		"busybox", "top")
    67  	ID = strings.TrimSpace(out)
    68  
    69  	out, _ = dockerCmd(c, "port", ID, "80")
    70  
    71  	err = assertPortList(c, out, []string{"0.0.0.0:9876", "0.0.0.0:9999"})
    72  	// Port list is not correct
    73  	c.Assert(err, checker.IsNil)
    74  
    75  	out, _ = dockerCmd(c, "port", ID)
    76  
    77  	err = assertPortList(c, out, []string{
    78  		"80/tcp -> 0.0.0.0:9876",
    79  		"80/tcp -> 0.0.0.0:9999",
    80  		"81/tcp -> 0.0.0.0:9877",
    81  		"82/tcp -> 0.0.0.0:9878"})
    82  	// Port list is not correct
    83  	c.Assert(err, checker.IsNil)
    84  	dockerCmd(c, "rm", "-f", ID)
    85  
    86  	testRange := func() {
    87  		// host port ranges used
    88  		IDs := make([]string, 3)
    89  		for i := 0; i < 3; i++ {
    90  			out, _ = dockerCmd(c, "run", "-d",
    91  				"-p", "9090-9092:80",
    92  				"busybox", "top")
    93  			IDs[i] = strings.TrimSpace(out)
    94  
    95  			out, _ = dockerCmd(c, "port", IDs[i])
    96  
    97  			err = assertPortList(c, out, []string{fmt.Sprintf("80/tcp -> 0.0.0.0:%d", 9090+i)})
    98  			// Port list is not correct
    99  			c.Assert(err, checker.IsNil)
   100  		}
   101  
   102  		// test port range exhaustion
   103  		out, _, err = dockerCmdWithError("run", "-d",
   104  			"-p", "9090-9092:80",
   105  			"busybox", "top")
   106  		// Exhausted port range did not return an error
   107  		c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
   108  
   109  		for i := 0; i < 3; i++ {
   110  			dockerCmd(c, "rm", "-f", IDs[i])
   111  		}
   112  	}
   113  	testRange()
   114  	// Verify we ran re-use port ranges after they are no longer in use.
   115  	testRange()
   116  
   117  	// test invalid port ranges
   118  	for _, invalidRange := range []string{"9090-9089:80", "9090-:80", "-9090:80"} {
   119  		out, _, err = dockerCmdWithError("run", "-d",
   120  			"-p", invalidRange,
   121  			"busybox", "top")
   122  		// Port range should have returned an error
   123  		c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
   124  	}
   125  
   126  	// test host range:container range spec.
   127  	out, _ = dockerCmd(c, "run", "-d",
   128  		"-p", "9800-9803:80-83",
   129  		"busybox", "top")
   130  	ID = strings.TrimSpace(out)
   131  
   132  	out, _ = dockerCmd(c, "port", ID)
   133  
   134  	err = assertPortList(c, out, []string{
   135  		"80/tcp -> 0.0.0.0:9800",
   136  		"81/tcp -> 0.0.0.0:9801",
   137  		"82/tcp -> 0.0.0.0:9802",
   138  		"83/tcp -> 0.0.0.0:9803"})
   139  	// Port list is not correct
   140  	c.Assert(err, checker.IsNil)
   141  	dockerCmd(c, "rm", "-f", ID)
   142  
   143  	// test mixing protocols in same port range
   144  	out, _ = dockerCmd(c, "run", "-d",
   145  		"-p", "8000-8080:80",
   146  		"-p", "8000-8080:80/udp",
   147  		"busybox", "top")
   148  	ID = strings.TrimSpace(out)
   149  
   150  	out, _ = dockerCmd(c, "port", ID)
   151  
   152  	// Running this test multiple times causes the TCP port to increment.
   153  	err = assertPortRange(c, out, []int{8000, 8080}, []int{8000, 8080})
   154  	// Port list is not correct
   155  	c.Assert(err, checker.IsNil)
   156  	dockerCmd(c, "rm", "-f", ID)
   157  }
   158  
   159  func assertPortList(c *check.C, out string, expected []string) error {
   160  	lines := strings.Split(strings.Trim(out, "\n "), "\n")
   161  	if len(lines) != len(expected) {
   162  		return fmt.Errorf("different size lists %s, %d, %d", out, len(lines), len(expected))
   163  	}
   164  	sort.Strings(lines)
   165  	sort.Strings(expected)
   166  
   167  	for i := 0; i < len(expected); i++ {
   168  		if lines[i] != expected[i] {
   169  			return fmt.Errorf("|" + lines[i] + "!=" + expected[i] + "|")
   170  		}
   171  	}
   172  
   173  	return nil
   174  }
   175  
   176  func assertPortRange(c *check.C, out string, expectedTcp, expectedUdp []int) error {
   177  	lines := strings.Split(strings.Trim(out, "\n "), "\n")
   178  
   179  	var validTcp, validUdp bool
   180  	for _, l := range lines {
   181  		// 80/tcp -> 0.0.0.0:8015
   182  		port, err := strconv.Atoi(strings.Split(l, ":")[1])
   183  		if err != nil {
   184  			return err
   185  		}
   186  		if strings.Contains(l, "tcp") && expectedTcp != nil {
   187  			if port < expectedTcp[0] || port > expectedTcp[1] {
   188  				return fmt.Errorf("tcp port (%d) not in range expected range %d-%d", port, expectedTcp[0], expectedTcp[1])
   189  			}
   190  			validTcp = true
   191  		}
   192  		if strings.Contains(l, "udp") && expectedUdp != nil {
   193  			if port < expectedUdp[0] || port > expectedUdp[1] {
   194  				return fmt.Errorf("udp port (%d) not in range expected range %d-%d", port, expectedUdp[0], expectedUdp[1])
   195  			}
   196  			validUdp = true
   197  		}
   198  	}
   199  	if !validTcp {
   200  		return fmt.Errorf("tcp port not found")
   201  	}
   202  	if !validUdp {
   203  		return fmt.Errorf("udp port not found")
   204  	}
   205  	return nil
   206  }
   207  
   208  func stopRemoveContainer(id string, c *check.C) {
   209  	dockerCmd(c, "rm", "-f", id)
   210  }
   211  
   212  func (s *DockerSuite) TestUnpublishedPortsInPsOutput(c *check.C) {
   213  	testRequires(c, DaemonIsLinux)
   214  	// Run busybox with command line expose (equivalent to EXPOSE in image's Dockerfile) for the following ports
   215  	port1 := 80
   216  	port2 := 443
   217  	expose1 := fmt.Sprintf("--expose=%d", port1)
   218  	expose2 := fmt.Sprintf("--expose=%d", port2)
   219  	dockerCmd(c, "run", "-d", expose1, expose2, "busybox", "sleep", "5")
   220  
   221  	// Check docker ps o/p for last created container reports the unpublished ports
   222  	unpPort1 := fmt.Sprintf("%d/tcp", port1)
   223  	unpPort2 := fmt.Sprintf("%d/tcp", port2)
   224  	out, _ := dockerCmd(c, "ps", "-n=1")
   225  	// Missing unpublished ports in docker ps output
   226  	c.Assert(out, checker.Contains, unpPort1)
   227  	// Missing unpublished ports in docker ps output
   228  	c.Assert(out, checker.Contains, unpPort2)
   229  
   230  	// Run the container forcing to publish the exposed ports
   231  	dockerCmd(c, "run", "-d", "-P", expose1, expose2, "busybox", "sleep", "5")
   232  
   233  	// Check docker ps o/p for last created container reports the exposed ports in the port bindings
   234  	expBndRegx1 := regexp.MustCompile(`0.0.0.0:\d\d\d\d\d->` + unpPort1)
   235  	expBndRegx2 := regexp.MustCompile(`0.0.0.0:\d\d\d\d\d->` + unpPort2)
   236  	out, _ = dockerCmd(c, "ps", "-n=1")
   237  	// Cannot find expected port binding port (0.0.0.0:xxxxx->unpPort1) in docker ps output
   238  	c.Assert(expBndRegx1.MatchString(out), checker.Equals, true, check.Commentf("out: %s; unpPort1: %s", out, unpPort1))
   239  	// Cannot find expected port binding port (0.0.0.0:xxxxx->unpPort2) in docker ps output
   240  	c.Assert(expBndRegx2.MatchString(out), checker.Equals, true, check.Commentf("out: %s; unpPort2: %s", out, unpPort2))
   241  
   242  	// Run the container specifying explicit port bindings for the exposed ports
   243  	offset := 10000
   244  	pFlag1 := fmt.Sprintf("%d:%d", offset+port1, port1)
   245  	pFlag2 := fmt.Sprintf("%d:%d", offset+port2, port2)
   246  	out, _ = dockerCmd(c, "run", "-d", "-p", pFlag1, "-p", pFlag2, expose1, expose2, "busybox", "sleep", "5")
   247  	id := strings.TrimSpace(out)
   248  
   249  	// Check docker ps o/p for last created container reports the specified port mappings
   250  	expBnd1 := fmt.Sprintf("0.0.0.0:%d->%s", offset+port1, unpPort1)
   251  	expBnd2 := fmt.Sprintf("0.0.0.0:%d->%s", offset+port2, unpPort2)
   252  	out, _ = dockerCmd(c, "ps", "-n=1")
   253  	// Cannot find expected port binding (expBnd1) in docker ps output
   254  	c.Assert(out, checker.Contains, expBnd1)
   255  	// Cannot find expected port binding (expBnd2) in docker ps output
   256  	c.Assert(out, checker.Contains, expBnd2)
   257  
   258  	// Remove container now otherwise it will interfere with next test
   259  	stopRemoveContainer(id, c)
   260  
   261  	// Run the container with explicit port bindings and no exposed ports
   262  	out, _ = dockerCmd(c, "run", "-d", "-p", pFlag1, "-p", pFlag2, "busybox", "sleep", "5")
   263  	id = strings.TrimSpace(out)
   264  
   265  	// Check docker ps o/p for last created container reports the specified port mappings
   266  	out, _ = dockerCmd(c, "ps", "-n=1")
   267  	// Cannot find expected port binding (expBnd1) in docker ps output
   268  	c.Assert(out, checker.Contains, expBnd1)
   269  	// Cannot find expected port binding (expBnd2) in docker ps output
   270  	c.Assert(out, checker.Contains, expBnd2)
   271  	// Remove container now otherwise it will interfere with next test
   272  	stopRemoveContainer(id, c)
   273  
   274  	// Run the container with one unpublished exposed port and one explicit port binding
   275  	dockerCmd(c, "run", "-d", expose1, "-p", pFlag2, "busybox", "sleep", "5")
   276  
   277  	// Check docker ps o/p for last created container reports the specified unpublished port and port mapping
   278  	out, _ = dockerCmd(c, "ps", "-n=1")
   279  	// Missing unpublished exposed ports (unpPort1) in docker ps output
   280  	c.Assert(out, checker.Contains, unpPort1)
   281  	// Missing port binding (expBnd2) in docker ps output
   282  	c.Assert(out, checker.Contains, expBnd2)
   283  }
   284  
   285  func (s *DockerSuite) TestPortHostBinding(c *check.C) {
   286  	testRequires(c, DaemonIsLinux, NotUserNamespace)
   287  	out, _ := dockerCmd(c, "run", "-d", "-p", "9876:80", "busybox",
   288  		"nc", "-l", "-p", "80")
   289  	firstID := strings.TrimSpace(out)
   290  
   291  	out, _ = dockerCmd(c, "port", firstID, "80")
   292  
   293  	err := assertPortList(c, out, []string{"0.0.0.0:9876"})
   294  	// Port list is not correct
   295  	c.Assert(err, checker.IsNil)
   296  
   297  	dockerCmd(c, "run", "--net=host", "busybox",
   298  		"nc", "localhost", "9876")
   299  
   300  	dockerCmd(c, "rm", "-f", firstID)
   301  
   302  	out, _, err = dockerCmdWithError("run", "--net=host", "busybox", "nc", "localhost", "9876")
   303  	// Port is still bound after the Container is removed
   304  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
   305  }
   306  
   307  func (s *DockerSuite) TestPortExposeHostBinding(c *check.C) {
   308  	testRequires(c, DaemonIsLinux, NotUserNamespace)
   309  	out, _ := dockerCmd(c, "run", "-d", "-P", "--expose", "80", "busybox",
   310  		"nc", "-l", "-p", "80")
   311  	firstID := strings.TrimSpace(out)
   312  
   313  	out, _ = dockerCmd(c, "port", firstID, "80")
   314  
   315  	_, exposedPort, err := net.SplitHostPort(out)
   316  	c.Assert(err, checker.IsNil, check.Commentf("out: %s", out))
   317  
   318  	dockerCmd(c, "run", "--net=host", "busybox",
   319  		"nc", "localhost", strings.TrimSpace(exposedPort))
   320  
   321  	dockerCmd(c, "rm", "-f", firstID)
   322  
   323  	out, _, err = dockerCmdWithError("run", "--net=host", "busybox",
   324  		"nc", "localhost", strings.TrimSpace(exposedPort))
   325  	// Port is still bound after the Container is removed
   326  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
   327  }
   328  
   329  func (s *DockerSuite) TestPortBindingOnSandbox(c *check.C) {
   330  	testRequires(c, DaemonIsLinux, NotUserNamespace)
   331  	dockerCmd(c, "network", "create", "--internal", "-d", "bridge", "internal-net")
   332  	nr := getNetworkResource(c, "internal-net")
   333  	c.Assert(nr.Internal, checker.Equals, true)
   334  
   335  	dockerCmd(c, "run", "--net", "internal-net", "-d", "--name", "c1",
   336  		"-p", "8080:8080", "busybox", "nc", "-l", "-p", "8080")
   337  	c.Assert(waitRun("c1"), check.IsNil)
   338  
   339  	_, _, err := dockerCmdWithError("run", "--net=host", "busybox", "nc", "localhost", "8080")
   340  	c.Assert(err, check.NotNil,
   341  		check.Commentf("Port mapping on internal network is expected to fail"))
   342  
   343  	// Connect container to another normal bridge network
   344  	dockerCmd(c, "network", "create", "-d", "bridge", "foo-net")
   345  	dockerCmd(c, "network", "connect", "foo-net", "c1")
   346  
   347  	_, _, err = dockerCmdWithError("run", "--net=host", "busybox", "nc", "localhost", "8080")
   348  	c.Assert(err, check.IsNil,
   349  		check.Commentf("Port mapping on the new network is expected to succeed"))
   350  
   351  }