Browse Source

List all ports when calling `docker port container`

Docker-DCO-1.1-Signed-off-by: SvenDowideit <SvenDowideit@home.org.au> (github: SvenDowideit)
SvenDowideit 11 years ago
parent
commit
4e340cedec

+ 26 - 17
api/client/commands.go

@@ -861,26 +861,15 @@ func (cli *DockerCli) CmdTop(args ...string) error {
 }
 
 func (cli *DockerCli) CmdPort(args ...string) error {
-	cmd := cli.Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port that is NAT-ed to PRIVATE_PORT")
+	cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() != 2 {
+	if cmd.NArg() < 1 {
 		cmd.Usage()
 		return nil
 	}
 
-	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]
-	}
-
 	steam, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
 	if err != nil {
 		return err
@@ -895,14 +884,34 @@ func (cli *DockerCli) CmdPort(args ...string) error {
 		return err
 	}
 
-	if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
+	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 := 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 ports {
 		for _, frontend := range frontends {
-			fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
+			fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort)
 		}
-		return nil
 	}
 
-	return fmt.Errorf("Error: No public port '%s' published for %s", cmd.Arg(1), cmd.Arg(0))
+	return nil
 }
 
 // 'docker rmi IMAGE' removes all images with the name IMAGE

+ 21 - 5
docs/man/docker-port.1.md

@@ -2,14 +2,30 @@
 % Docker Community
 % JUNE 2014
 # NAME
-docker-port - Lookup the public-facing port that is NAT-ed to PRIVATE_PORT
+docker-port - List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
 
 # SYNOPSIS
-**docker port**
-CONTAINER PRIVATE_PORT
+**docker port** CONTAINER [PRIVATE_PORT[/PROTO]]
 
-# OPTIONS
-There are no available options.
+# DESCRIPTION
+List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
+
+# EXAMPLES
+You can find out all the ports mapped by not specifying a `PRIVATE_PORT`, or
+ask for just a specific mapping:
+
+    $ docker ps test
+    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                                            NAMES
+    b650456536c7        busybox:latest      top                 54 minutes ago      Up 54 minutes       0.0.0.0:1234->9876/tcp, 0.0.0.0:4321->7890/tcp   test
+    $ docker port test
+    7890/tcp -> 0.0.0.0:4321
+    9876/tcp -> 0.0.0.0:1234
+    $ docker port test 7890/tcp
+    0.0.0.0:4321
+    $ docker port test 7890/udp
+    2014/06/24 11:53:36 Error: No public port '7890/udp' published for test
+    $ docker port test 7890
+    0.0.0.0:4321
 
 # HISTORY
 April 2014, Originally compiled by William Henry (whenry at redhat dot com)

+ 19 - 3
docs/sources/reference/commandline/cli.md

@@ -764,9 +764,25 @@ log entry.
 
 ## port
 
-    Usage: docker port CONTAINER PRIVATE_PORT
-
-    Lookup the public-facing port that is NAT-ed to PRIVATE_PORT
+    Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]]
+
+    List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
+
+You can find out all the ports mapped by not specifying a `PRIVATE_PORT`, or
+just a specific mapping:
+
+    $ docker ps test
+    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                                            NAMES
+    b650456536c7        busybox:latest      top                 54 minutes ago      Up 54 minutes       0.0.0.0:1234->9876/tcp, 0.0.0.0:4321->7890/tcp   test
+    $ docker port test
+    7890/tcp -> 0.0.0.0:4321
+    9876/tcp -> 0.0.0.0:1234
+    $ docker port test 7890/tcp
+    0.0.0.0:4321
+    $ docker port test 7890/udp
+    2014/06/24 11:53:36 Error: No public port '7890/udp' published for test
+    $ docker port test 7890
+    0.0.0.0:4321
 
 ## pause
 

+ 125 - 0
integration-cli/docker_cli_port_test.go

@@ -0,0 +1,125 @@
+package main
+
+import (
+	"os/exec"
+	"sort"
+	"strings"
+	"testing"
+)
+
+func TestListPorts(t *testing.T) {
+	// one port
+	runCmd := exec.Command(dockerBinary, "run", "-d", "-p", "9876:80", "busybox", "top")
+	out, _, err := runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+	firstID := stripTrailingCharacters(out)
+
+	runCmd = exec.Command(dockerBinary, "port", firstID, "80")
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+
+	if !assertPortList(t, out, []string{"0.0.0.0:9876"}) {
+		t.Error("Port list is not correct")
+	}
+
+	runCmd = exec.Command(dockerBinary, "port", firstID)
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+
+	if !assertPortList(t, out, []string{"80/tcp -> 0.0.0.0:9876"}) {
+		t.Error("Port list is not correct")
+	}
+	runCmd = exec.Command(dockerBinary, "rm", "-f", firstID)
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+
+	// three port
+	runCmd = exec.Command(dockerBinary, "run", "-d",
+		"-p", "9876:80",
+		"-p", "9877:81",
+		"-p", "9878:82",
+		"busybox", "top")
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+	ID := stripTrailingCharacters(out)
+
+	runCmd = exec.Command(dockerBinary, "port", ID, "80")
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+
+	if !assertPortList(t, out, []string{"0.0.0.0:9876"}) {
+		t.Error("Port list is not correct")
+	}
+
+	runCmd = exec.Command(dockerBinary, "port", ID)
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+
+	if !assertPortList(t, out, []string{
+		"80/tcp -> 0.0.0.0:9876",
+		"81/tcp -> 0.0.0.0:9877",
+		"82/tcp -> 0.0.0.0:9878"}) {
+		t.Error("Port list is not correct")
+	}
+	runCmd = exec.Command(dockerBinary, "rm", "-f", ID)
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+
+	// more and one port mapped to the same container port
+	runCmd = exec.Command(dockerBinary, "run", "-d",
+		"-p", "9876:80",
+		"-p", "9999:80",
+		"-p", "9877:81",
+		"-p", "9878:82",
+		"busybox", "top")
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+	ID = stripTrailingCharacters(out)
+
+	runCmd = exec.Command(dockerBinary, "port", ID, "80")
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+
+	if !assertPortList(t, out, []string{"0.0.0.0:9876", "0.0.0.0:9999"}) {
+		t.Error("Port list is not correct")
+	}
+
+	runCmd = exec.Command(dockerBinary, "port", ID)
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+
+	if !assertPortList(t, out, []string{
+		"80/tcp -> 0.0.0.0:9876",
+		"80/tcp -> 0.0.0.0:9999",
+		"81/tcp -> 0.0.0.0:9877",
+		"82/tcp -> 0.0.0.0:9878"}) {
+		t.Error("Port list is not correct\n", out)
+	}
+	runCmd = exec.Command(dockerBinary, "rm", "-f", ID)
+	out, _, err = runCommandWithOutput(runCmd)
+	errorOut(err, t, out)
+
+	deleteAllContainers()
+
+	logDone("port - test port list")
+}
+
+func assertPortList(t *testing.T, out string, expected []string) bool {
+	//lines := strings.Split(out, "\n")
+	lines := strings.Split(strings.Trim(out, "\n "), "\n")
+	if len(lines) != len(expected) {
+		t.Errorf("different size lists %s, %d, %d", out, len(lines), len(expected))
+		return false
+	}
+	sort.Strings(lines)
+	sort.Strings(expected)
+
+	for i := 0; i < len(expected); i++ {
+		if lines[i] != expected[i] {
+			t.Error("|" + lines[i] + "!=" + expected[i] + "|")
+			return false
+		}
+	}
+
+	return true
+}