Browse code

Merge pull request #10835 from jfrazelle/port-ranges

Steve Francia authored on 2015/02/20 06:11:59
Showing 3 changed files
... ...
@@ -29,21 +29,78 @@ func ValidateHost(val string) (string, error) {
29 29
 	return host, nil
30 30
 }
31 31
 
32
-//TODO remove, used on < 1.5 in getContainersJSON
32
+// TODO remove, used on < 1.5 in getContainersJSON
33 33
 func DisplayablePorts(ports *engine.Table) string {
34
-	result := []string{}
35
-	ports.SetKey("PublicPort")
34
+	var (
35
+		result          = []string{}
36
+		hostMappings    = []string{}
37
+		firstInGroupMap map[string]int
38
+		lastInGroupMap  map[string]int
39
+	)
40
+	firstInGroupMap = make(map[string]int)
41
+	lastInGroupMap = make(map[string]int)
42
+	ports.SetKey("PrivatePort")
36 43
 	ports.Sort()
37 44
 	for _, port := range ports.Data {
38
-		if port.Get("IP") == "" {
39
-			result = append(result, fmt.Sprintf("%d/%s", port.GetInt("PrivatePort"), port.Get("Type")))
40
-		} else {
41
-			result = append(result, fmt.Sprintf("%s:%d->%d/%s", port.Get("IP"), port.GetInt("PublicPort"), port.GetInt("PrivatePort"), port.Get("Type")))
45
+		var (
46
+			current      = port.GetInt("PrivatePort")
47
+			portKey      = port.Get("Type")
48
+			firstInGroup int
49
+			lastInGroup  int
50
+		)
51
+		if port.Get("IP") != "" {
52
+			if port.GetInt("PublicPort") != current {
53
+				hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", port.Get("IP"), port.GetInt("PublicPort"), port.GetInt("PrivatePort"), port.Get("Type")))
54
+				continue
55
+			}
56
+			portKey = fmt.Sprintf("%s/%s", port.Get("IP"), port.Get("Type"))
42 57
 		}
58
+		firstInGroup = firstInGroupMap[portKey]
59
+		lastInGroup = lastInGroupMap[portKey]
60
+
61
+		if firstInGroup == 0 {
62
+			firstInGroupMap[portKey] = current
63
+			lastInGroupMap[portKey] = current
64
+			continue
65
+		}
66
+
67
+		if current == (lastInGroup + 1) {
68
+			lastInGroupMap[portKey] = current
69
+			continue
70
+		}
71
+		result = append(result, FormGroup(portKey, firstInGroup, lastInGroup))
72
+		firstInGroupMap[portKey] = current
73
+		lastInGroupMap[portKey] = current
74
+	}
75
+	for portKey, firstInGroup := range firstInGroupMap {
76
+		result = append(result, FormGroup(portKey, firstInGroup, lastInGroupMap[portKey]))
43 77
 	}
78
+	result = append(result, hostMappings...)
44 79
 	return strings.Join(result, ", ")
45 80
 }
46 81
 
82
+func FormGroup(key string, start, last int) string {
83
+	var (
84
+		group     string
85
+		parts     = strings.Split(key, "/")
86
+		groupType = parts[0]
87
+		ip        = ""
88
+	)
89
+	if len(parts) > 1 {
90
+		ip = parts[0]
91
+		groupType = parts[1]
92
+	}
93
+	if start == last {
94
+		group = fmt.Sprintf("%d", start)
95
+	} else {
96
+		group = fmt.Sprintf("%d-%d", start, last)
97
+	}
98
+	if ip != "" {
99
+		group = fmt.Sprintf("%s:%s->%s", ip, group, group)
100
+	}
101
+	return fmt.Sprintf("%s/%s", group, groupType)
102
+}
103
+
47 104
 func MatchesContentType(contentType, expectedType string) bool {
48 105
 	mimetype, _, err := mime.ParseMediaType(contentType)
49 106
 	if err != nil {
... ...
@@ -1442,13 +1442,15 @@ The `docker rename` command allows the container to be renamed to a different na
1442 1442
 Running `docker ps --no-trunc` showing 2 linked containers.
1443 1443
 
1444 1444
     $ sudo docker ps
1445
-    CONTAINER ID                                                            IMAGE                        COMMAND                CREATED              STATUS              PORTS               NAMES
1446
-    f7ee772232194fcc088c6bdec6ea09f7b3f6c54d53934658164b8602d7cd4744        ubuntu:12.04                 bash                   17 seconds ago       Up 16 seconds                           webapp
1447
-    d0963715a061c7c7b7cc80b2646da913a959fbf13e80a971d4a60f6997a2f595        crosbymichael/redis:latest   /redis-server --dir    33 minutes ago       Up 33 minutes       6379/tcp            redis,webapp/db
1445
+    CONTAINER ID        IMAGE                        COMMAND                CREATED              STATUS              PORTS               NAMES
1446
+    4c01db0b339c        ubuntu:12.04                 bash                   17 seconds ago       Up 16 seconds       3300-3310/tcp       webapp
1447
+    d7886598dbe2        crosbymichael/redis:latest   /redis-server --dir    33 minutes ago       Up 33 minutes       6379/tcp            redis,webapp/db
1448 1448
 
1449 1449
 `docker ps` will show only running containers by default. To see all containers:
1450 1450
 `docker ps -a`
1451 1451
 
1452
+`docker ps` will group exposed ports into a single range if possible. E.g., a container that exposes TCP ports `100, 101, 102` will display `100-102/tcp` in the `PORTS` column.
1453
+
1452 1454
 #### Filtering
1453 1455
 
1454 1456
 The filtering flag (`-f` or `--filter)` format is a `key=value` pair. If there is more
... ...
@@ -566,3 +566,25 @@ func TestPsLinkedWithNoTrunc(t *testing.T) {
566 566
 		t.Fatalf("Expected array: %v, got: %v", expected, names)
567 567
 	}
568 568
 }
569
+
570
+func TestPsGroupPortRange(t *testing.T) {
571
+	defer deleteAllContainers()
572
+
573
+	portRange := "3300-3900"
574
+	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "porttest", "-p", portRange+":"+portRange, "busybox", "top"))
575
+	if err != nil {
576
+		t.Fatal(out, err)
577
+	}
578
+
579
+	out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "ps"))
580
+	if err != nil {
581
+		t.Fatal(out, err)
582
+	}
583
+
584
+	// check that the port range is in the output
585
+	if !strings.Contains(string(out), portRange) {
586
+		t.Fatalf("docker ps output should have had the port range %q: %s", portRange, string(out))
587
+	}
588
+
589
+	logDone("ps - port range")
590
+}