Browse code

List all ports when calling `docker port container`

Docker-DCO-1.1-Signed-off-by: SvenDowideit <SvenDowideit@home.org.au> (github: SvenDowideit)

SvenDowideit authored on 2014/06/24 11:03:08
Showing 4 changed files
... ...
@@ -861,26 +861,15 @@ func (cli *DockerCli) CmdTop(args ...string) error {
861 861
 }
862 862
 
863 863
 func (cli *DockerCli) CmdPort(args ...string) error {
864
-	cmd := cli.Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port that is NAT-ed to PRIVATE_PORT")
864
+	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")
865 865
 	if err := cmd.Parse(args); err != nil {
866 866
 		return nil
867 867
 	}
868
-	if cmd.NArg() != 2 {
868
+	if cmd.NArg() < 1 {
869 869
 		cmd.Usage()
870 870
 		return nil
871 871
 	}
872 872
 
873
-	var (
874
-		port  = cmd.Arg(1)
875
-		proto = "tcp"
876
-		parts = strings.SplitN(port, "/", 2)
877
-	)
878
-
879
-	if len(parts) == 2 && len(parts[1]) != 0 {
880
-		port = parts[0]
881
-		proto = parts[1]
882
-	}
883
-
884 873
 	steam, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
885 874
 	if err != nil {
886 875
 		return err
... ...
@@ -895,14 +884,34 @@ func (cli *DockerCli) CmdPort(args ...string) error {
895 895
 		return err
896 896
 	}
897 897
 
898
-	if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
898
+	if cmd.NArg() == 2 {
899
+		var (
900
+			port  = cmd.Arg(1)
901
+			proto = "tcp"
902
+			parts = strings.SplitN(port, "/", 2)
903
+		)
904
+
905
+		if len(parts) == 2 && len(parts[1]) != 0 {
906
+			port = parts[0]
907
+			proto = parts[1]
908
+		}
909
+		natPort := port + "/" + proto
910
+		if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
911
+			for _, frontend := range frontends {
912
+				fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
913
+			}
914
+			return nil
915
+		}
916
+		return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0))
917
+	}
918
+
919
+	for from, frontends := range ports {
899 920
 		for _, frontend := range frontends {
900
-			fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
921
+			fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort)
901 922
 		}
902
-		return nil
903 923
 	}
904 924
 
905
-	return fmt.Errorf("Error: No public port '%s' published for %s", cmd.Arg(1), cmd.Arg(0))
925
+	return nil
906 926
 }
907 927
 
908 928
 // 'docker rmi IMAGE' removes all images with the name IMAGE
... ...
@@ -2,14 +2,30 @@
2 2
 % Docker Community
3 3
 % JUNE 2014
4 4
 # NAME
5
-docker-port - Lookup the public-facing port that is NAT-ed to PRIVATE_PORT
5
+docker-port - List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
6 6
 
7 7
 # SYNOPSIS
8
-**docker port**
9
-CONTAINER PRIVATE_PORT
8
+**docker port** CONTAINER [PRIVATE_PORT[/PROTO]]
10 9
 
11
-# OPTIONS
12
-There are no available options.
10
+# DESCRIPTION
11
+List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
12
+
13
+# EXAMPLES
14
+You can find out all the ports mapped by not specifying a `PRIVATE_PORT`, or
15
+ask for just a specific mapping:
16
+
17
+    $ docker ps test
18
+    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                                            NAMES
19
+    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
20
+    $ docker port test
21
+    7890/tcp -> 0.0.0.0:4321
22
+    9876/tcp -> 0.0.0.0:1234
23
+    $ docker port test 7890/tcp
24
+    0.0.0.0:4321
25
+    $ docker port test 7890/udp
26
+    2014/06/24 11:53:36 Error: No public port '7890/udp' published for test
27
+    $ docker port test 7890
28
+    0.0.0.0:4321
13 29
 
14 30
 # HISTORY
15 31
 April 2014, Originally compiled by William Henry (whenry at redhat dot com)
... ...
@@ -764,9 +764,25 @@ log entry.
764 764
 
765 765
 ## port
766 766
 
767
-    Usage: docker port CONTAINER PRIVATE_PORT
768
-
769
-    Lookup the public-facing port that is NAT-ed to PRIVATE_PORT
767
+    Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]]
768
+
769
+    List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
770
+
771
+You can find out all the ports mapped by not specifying a `PRIVATE_PORT`, or
772
+just a specific mapping:
773
+
774
+    $ docker ps test
775
+    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                                            NAMES
776
+    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
777
+    $ docker port test
778
+    7890/tcp -> 0.0.0.0:4321
779
+    9876/tcp -> 0.0.0.0:1234
780
+    $ docker port test 7890/tcp
781
+    0.0.0.0:4321
782
+    $ docker port test 7890/udp
783
+    2014/06/24 11:53:36 Error: No public port '7890/udp' published for test
784
+    $ docker port test 7890
785
+    0.0.0.0:4321
770 786
 
771 787
 ## pause
772 788
 
773 789
new file mode 100644
... ...
@@ -0,0 +1,125 @@
0
+package main
1
+
2
+import (
3
+	"os/exec"
4
+	"sort"
5
+	"strings"
6
+	"testing"
7
+)
8
+
9
+func TestListPorts(t *testing.T) {
10
+	// one port
11
+	runCmd := exec.Command(dockerBinary, "run", "-d", "-p", "9876:80", "busybox", "top")
12
+	out, _, err := runCommandWithOutput(runCmd)
13
+	errorOut(err, t, out)
14
+	firstID := stripTrailingCharacters(out)
15
+
16
+	runCmd = exec.Command(dockerBinary, "port", firstID, "80")
17
+	out, _, err = runCommandWithOutput(runCmd)
18
+	errorOut(err, t, out)
19
+
20
+	if !assertPortList(t, out, []string{"0.0.0.0:9876"}) {
21
+		t.Error("Port list is not correct")
22
+	}
23
+
24
+	runCmd = exec.Command(dockerBinary, "port", firstID)
25
+	out, _, err = runCommandWithOutput(runCmd)
26
+	errorOut(err, t, out)
27
+
28
+	if !assertPortList(t, out, []string{"80/tcp -> 0.0.0.0:9876"}) {
29
+		t.Error("Port list is not correct")
30
+	}
31
+	runCmd = exec.Command(dockerBinary, "rm", "-f", firstID)
32
+	out, _, err = runCommandWithOutput(runCmd)
33
+	errorOut(err, t, out)
34
+
35
+	// three port
36
+	runCmd = exec.Command(dockerBinary, "run", "-d",
37
+		"-p", "9876:80",
38
+		"-p", "9877:81",
39
+		"-p", "9878:82",
40
+		"busybox", "top")
41
+	out, _, err = runCommandWithOutput(runCmd)
42
+	errorOut(err, t, out)
43
+	ID := stripTrailingCharacters(out)
44
+
45
+	runCmd = exec.Command(dockerBinary, "port", ID, "80")
46
+	out, _, err = runCommandWithOutput(runCmd)
47
+	errorOut(err, t, out)
48
+
49
+	if !assertPortList(t, out, []string{"0.0.0.0:9876"}) {
50
+		t.Error("Port list is not correct")
51
+	}
52
+
53
+	runCmd = exec.Command(dockerBinary, "port", ID)
54
+	out, _, err = runCommandWithOutput(runCmd)
55
+	errorOut(err, t, out)
56
+
57
+	if !assertPortList(t, out, []string{
58
+		"80/tcp -> 0.0.0.0:9876",
59
+		"81/tcp -> 0.0.0.0:9877",
60
+		"82/tcp -> 0.0.0.0:9878"}) {
61
+		t.Error("Port list is not correct")
62
+	}
63
+	runCmd = exec.Command(dockerBinary, "rm", "-f", ID)
64
+	out, _, err = runCommandWithOutput(runCmd)
65
+	errorOut(err, t, out)
66
+
67
+	// more and one port mapped to the same container port
68
+	runCmd = exec.Command(dockerBinary, "run", "-d",
69
+		"-p", "9876:80",
70
+		"-p", "9999:80",
71
+		"-p", "9877:81",
72
+		"-p", "9878:82",
73
+		"busybox", "top")
74
+	out, _, err = runCommandWithOutput(runCmd)
75
+	errorOut(err, t, out)
76
+	ID = stripTrailingCharacters(out)
77
+
78
+	runCmd = exec.Command(dockerBinary, "port", ID, "80")
79
+	out, _, err = runCommandWithOutput(runCmd)
80
+	errorOut(err, t, out)
81
+
82
+	if !assertPortList(t, out, []string{"0.0.0.0:9876", "0.0.0.0:9999"}) {
83
+		t.Error("Port list is not correct")
84
+	}
85
+
86
+	runCmd = exec.Command(dockerBinary, "port", ID)
87
+	out, _, err = runCommandWithOutput(runCmd)
88
+	errorOut(err, t, out)
89
+
90
+	if !assertPortList(t, out, []string{
91
+		"80/tcp -> 0.0.0.0:9876",
92
+		"80/tcp -> 0.0.0.0:9999",
93
+		"81/tcp -> 0.0.0.0:9877",
94
+		"82/tcp -> 0.0.0.0:9878"}) {
95
+		t.Error("Port list is not correct\n", out)
96
+	}
97
+	runCmd = exec.Command(dockerBinary, "rm", "-f", ID)
98
+	out, _, err = runCommandWithOutput(runCmd)
99
+	errorOut(err, t, out)
100
+
101
+	deleteAllContainers()
102
+
103
+	logDone("port - test port list")
104
+}
105
+
106
+func assertPortList(t *testing.T, out string, expected []string) bool {
107
+	//lines := strings.Split(out, "\n")
108
+	lines := strings.Split(strings.Trim(out, "\n "), "\n")
109
+	if len(lines) != len(expected) {
110
+		t.Errorf("different size lists %s, %d, %d", out, len(lines), len(expected))
111
+		return false
112
+	}
113
+	sort.Strings(lines)
114
+	sort.Strings(expected)
115
+
116
+	for i := 0; i < len(expected); i++ {
117
+		if lines[i] != expected[i] {
118
+			t.Error("|" + lines[i] + "!=" + expected[i] + "|")
119
+			return false
120
+		}
121
+	}
122
+
123
+	return true
124
+}