Skip to content

Commit 4e340ce

Browse files
committed
List all ports when calling docker port container
Docker-DCO-1.1-Signed-off-by: SvenDowideit <SvenDowideit@home.org.au> (github: SvenDowideit)
1 parent 6eaac7d commit 4e340ce

File tree

4 files changed

+191
-25
lines changed

4 files changed

+191
-25
lines changed

api/client/commands.go

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -861,26 +861,15 @@ func (cli *DockerCli) CmdTop(args ...string) error {
861861
}
862862

863863
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")
865865
if err := cmd.Parse(args); err != nil {
866866
return nil
867867
}
868-
if cmd.NArg() != 2 {
868+
if cmd.NArg() < 1 {
869869
cmd.Usage()
870870
return nil
871871
}
872872

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-
884873
steam, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
885874
if err != nil {
886875
return err
@@ -895,14 +884,34 @@ func (cli *DockerCli) CmdPort(args ...string) error {
895884
return err
896885
}
897886

898-
if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
887+
if cmd.NArg() == 2 {
888+
var (
889+
port = cmd.Arg(1)
890+
proto = "tcp"
891+
parts = strings.SplitN(port, "/", 2)
892+
)
893+
894+
if len(parts) == 2 && len(parts[1]) != 0 {
895+
port = parts[0]
896+
proto = parts[1]
897+
}
898+
natPort := port + "/" + proto
899+
if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
900+
for _, frontend := range frontends {
901+
fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
902+
}
903+
return nil
904+
}
905+
return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0))
906+
}
907+
908+
for from, frontends := range ports {
899909
for _, frontend := range frontends {
900-
fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
910+
fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort)
901911
}
902-
return nil
903912
}
904913

905-
return fmt.Errorf("Error: No public port '%s' published for %s", cmd.Arg(1), cmd.Arg(0))
914+
return nil
906915
}
907916

908917
// 'docker rmi IMAGE' removes all images with the name IMAGE

docs/man/docker-port.1.md

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,30 @@
22
% Docker Community
33
% JUNE 2014
44
# 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
66

77
# SYNOPSIS
8-
**docker port**
9-
CONTAINER PRIVATE_PORT
8+
**docker port** CONTAINER [PRIVATE_PORT[/PROTO]]
109

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
1329

1430
# HISTORY
1531
April 2014, Originally compiled by William Henry (whenry at redhat dot com)

docs/sources/reference/commandline/cli.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -764,9 +764,25 @@ log entry.
764764

765765
## port
766766

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
770786

771787
## pause
772788

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package main
2+
3+
import (
4+
"os/exec"
5+
"sort"
6+
"strings"
7+
"testing"
8+
)
9+
10+
func TestListPorts(t *testing.T) {
11+
// one port
12+
runCmd := exec.Command(dockerBinary, "run", "-d", "-p", "9876:80", "busybox", "top")
13+
out, _, err := runCommandWithOutput(runCmd)
14+
errorOut(err, t, out)
15+
firstID := stripTrailingCharacters(out)
16+
17+
runCmd = exec.Command(dockerBinary, "port", firstID, "80")
18+
out, _, err = runCommandWithOutput(runCmd)
19+
errorOut(err, t, out)
20+
21+
if !assertPortList(t, out, []string{"0.0.0.0:9876"}) {
22+
t.Error("Port list is not correct")
23+
}
24+
25+
runCmd = exec.Command(dockerBinary, "port", firstID)
26+
out, _, err = runCommandWithOutput(runCmd)
27+
errorOut(err, t, out)
28+
29+
if !assertPortList(t, out, []string{"80/tcp -> 0.0.0.0:9876"}) {
30+
t.Error("Port list is not correct")
31+
}
32+
runCmd = exec.Command(dockerBinary, "rm", "-f", firstID)
33+
out, _, err = runCommandWithOutput(runCmd)
34+
errorOut(err, t, out)
35+
36+
// three port
37+
runCmd = exec.Command(dockerBinary, "run", "-d",
38+
"-p", "9876:80",
39+
"-p", "9877:81",
40+
"-p", "9878:82",
41+
"busybox", "top")
42+
out, _, err = runCommandWithOutput(runCmd)
43+
errorOut(err, t, out)
44+
ID := stripTrailingCharacters(out)
45+
46+
runCmd = exec.Command(dockerBinary, "port", ID, "80")
47+
out, _, err = runCommandWithOutput(runCmd)
48+
errorOut(err, t, out)
49+
50+
if !assertPortList(t, out, []string{"0.0.0.0:9876"}) {
51+
t.Error("Port list is not correct")
52+
}
53+
54+
runCmd = exec.Command(dockerBinary, "port", ID)
55+
out, _, err = runCommandWithOutput(runCmd)
56+
errorOut(err, t, out)
57+
58+
if !assertPortList(t, out, []string{
59+
"80/tcp -> 0.0.0.0:9876",
60+
"81/tcp -> 0.0.0.0:9877",
61+
"82/tcp -> 0.0.0.0:9878"}) {
62+
t.Error("Port list is not correct")
63+
}
64+
runCmd = exec.Command(dockerBinary, "rm", "-f", ID)
65+
out, _, err = runCommandWithOutput(runCmd)
66+
errorOut(err, t, out)
67+
68+
// more and one port mapped to the same container port
69+
runCmd = exec.Command(dockerBinary, "run", "-d",
70+
"-p", "9876:80",
71+
"-p", "9999:80",
72+
"-p", "9877:81",
73+
"-p", "9878:82",
74+
"busybox", "top")
75+
out, _, err = runCommandWithOutput(runCmd)
76+
errorOut(err, t, out)
77+
ID = stripTrailingCharacters(out)
78+
79+
runCmd = exec.Command(dockerBinary, "port", ID, "80")
80+
out, _, err = runCommandWithOutput(runCmd)
81+
errorOut(err, t, out)
82+
83+
if !assertPortList(t, out, []string{"0.0.0.0:9876", "0.0.0.0:9999"}) {
84+
t.Error("Port list is not correct")
85+
}
86+
87+
runCmd = exec.Command(dockerBinary, "port", ID)
88+
out, _, err = runCommandWithOutput(runCmd)
89+
errorOut(err, t, out)
90+
91+
if !assertPortList(t, out, []string{
92+
"80/tcp -> 0.0.0.0:9876",
93+
"80/tcp -> 0.0.0.0:9999",
94+
"81/tcp -> 0.0.0.0:9877",
95+
"82/tcp -> 0.0.0.0:9878"}) {
96+
t.Error("Port list is not correct\n", out)
97+
}
98+
runCmd = exec.Command(dockerBinary, "rm", "-f", ID)
99+
out, _, err = runCommandWithOutput(runCmd)
100+
errorOut(err, t, out)
101+
102+
deleteAllContainers()
103+
104+
logDone("port - test port list")
105+
}
106+
107+
func assertPortList(t *testing.T, out string, expected []string) bool {
108+
//lines := strings.Split(out, "\n")
109+
lines := strings.Split(strings.Trim(out, "\n "), "\n")
110+
if len(lines) != len(expected) {
111+
t.Errorf("different size lists %s, %d, %d", out, len(lines), len(expected))
112+
return false
113+
}
114+
sort.Strings(lines)
115+
sort.Strings(expected)
116+
117+
for i := 0; i < len(expected); i++ {
118+
if lines[i] != expected[i] {
119+
t.Error("|" + lines[i] + "!=" + expected[i] + "|")
120+
return false
121+
}
122+
}
123+
124+
return true
125+
}

0 commit comments

Comments
 (0)