Browse code

More descriptive, easier to process container portmappings information in the API

shin- authored on 2013/08/28 07:20:35
Showing 6 changed files
... ...
@@ -1,5 +1,7 @@
1 1
 package docker
2 2
 
3
+import "encoding/json"
4
+
3 5
 type APIHistory struct {
4 6
 	ID        string   `json:"Id"`
5 7
 	Tags      []string `json:",omitempty"`
... ...
@@ -47,7 +49,7 @@ type APIContainers struct {
47 47
 	Command    string
48 48
 	Created    int64
49 49
 	Status     string
50
-	Ports      string
50
+	Ports      []APIPort
51 51
 	SizeRw     int64
52 52
 	SizeRootFs int64
53 53
 }
... ...
@@ -67,7 +69,17 @@ type APIRun struct {
67 67
 }
68 68
 
69 69
 type APIPort struct {
70
-	Port string
70
+	PrivatePort int64
71
+	PublicPort  int64
72
+	Type        string
73
+}
74
+
75
+func (port *APIPort) MarshalJSON() ([]byte, error) {
76
+	return json.Marshal(map[string]interface{}{
77
+		"PrivatePort": port.PrivatePort,
78
+		"PublicPort":  port.PublicPort,
79
+		"Type":        port.Type,
80
+	})
71 81
 }
72 82
 
73 83
 type APIVersion struct {
... ...
@@ -20,6 +20,7 @@ import (
20 20
 	"path/filepath"
21 21
 	"reflect"
22 22
 	"runtime"
23
+	"sort"
23 24
 	"strconv"
24 25
 	"strings"
25 26
 	"syscall"
... ...
@@ -996,6 +997,19 @@ func (cli *DockerCli) CmdImages(args ...string) error {
996 996
 	return nil
997 997
 }
998 998
 
999
+func displayablePorts(ports []APIPort) string {
1000
+	result := []string{}
1001
+	for _, port := range ports {
1002
+		if port.Type == "tcp" {
1003
+			result = append(result, fmt.Sprintf("%d->%d", port.PublicPort, port.PrivatePort))
1004
+		} else {
1005
+			result = append(result, fmt.Sprintf("%d->%d/%s", port.PublicPort, port.PrivatePort, port.Type))
1006
+		}
1007
+	}
1008
+	sort.Strings(result)
1009
+	return strings.Join(result, ", ")
1010
+}
1011
+
999 1012
 func (cli *DockerCli) CmdPs(args ...string) error {
1000 1013
 	cmd := Subcmd("ps", "[OPTIONS]", "List containers")
1001 1014
 	quiet := cmd.Bool("q", false, "Only display numeric IDs")
... ...
@@ -1053,9 +1067,9 @@ func (cli *DockerCli) CmdPs(args ...string) error {
1053 1053
 	for _, out := range outs {
1054 1054
 		if !*quiet {
1055 1055
 			if *noTrunc {
1056
-				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
1056
+				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, displayablePorts(out.Ports))
1057 1057
 			} else {
1058
-				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", utils.TruncateID(out.ID), out.Image, utils.Trunc(out.Command, 20), utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
1058
+				fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", utils.TruncateID(out.ID), out.Image, utils.Trunc(out.Command, 20), utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, displayablePorts(out.Ports))
1059 1059
 			}
1060 1060
 			if *size {
1061 1061
 				if out.SizeRootFs > 0 {
... ...
@@ -152,7 +152,6 @@ func TestRunWorkdirExists(t *testing.T) {
152 152
 
153 153
 }
154 154
 
155
-
156 155
 func TestRunExit(t *testing.T) {
157 156
 	stdin, stdinPipe := io.Pipe()
158 157
 	stdout, stdoutPipe := io.Pipe()
... ...
@@ -15,7 +15,6 @@ import (
15 15
 	"os/exec"
16 16
 	"path"
17 17
 	"path/filepath"
18
-	"sort"
19 18
 	"strconv"
20 19
 	"strings"
21 20
 	"syscall"
... ...
@@ -253,17 +252,28 @@ type NetworkSettings struct {
253 253
 	PortMapping map[string]PortMapping
254 254
 }
255 255
 
256
-// String returns a human-readable description of the port mapping defined in the settings
257
-func (settings *NetworkSettings) PortMappingHuman() string {
258
-	var mapping []string
256
+// returns a more easy to process description of the port mapping defined in the settings
257
+func (settings *NetworkSettings) PortMappingAPI() []APIPort {
258
+	var mapping []APIPort
259 259
 	for private, public := range settings.PortMapping["Tcp"] {
260
-		mapping = append(mapping, fmt.Sprintf("%s->%s", public, private))
260
+		pubint, _ := strconv.ParseInt(public, 0, 0)
261
+		privint, _ := strconv.ParseInt(private, 0, 0)
262
+		mapping = append(mapping, APIPort{
263
+			PrivatePort: privint,
264
+			PublicPort:  pubint,
265
+			Type:        "tcp",
266
+		})
261 267
 	}
262 268
 	for private, public := range settings.PortMapping["Udp"] {
263
-		mapping = append(mapping, fmt.Sprintf("%s->%s/udp", public, private))
269
+		pubint, _ := strconv.ParseInt(public, 0, 0)
270
+		privint, _ := strconv.ParseInt(private, 0, 0)
271
+		mapping = append(mapping, APIPort{
272
+			PrivatePort: privint,
273
+			PublicPort:  pubint,
274
+			Type:        "udp",
275
+		})
264 276
 	}
265
-	sort.Strings(mapping)
266
-	return strings.Join(mapping, ", ")
277
+	return mapping
267 278
 }
268 279
 
269 280
 // Inject the io.Reader at the given path. Note: do not close the reader
... ...
@@ -386,7 +386,7 @@ func (srv *Server) Containers(all, size bool, n int, since, before string) []API
386 386
 		c.Command = fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
387 387
 		c.Created = container.Created.Unix()
388 388
 		c.Status = container.State.String()
389
-		c.Ports = container.NetworkSettings.PortMappingHuman()
389
+		c.Ports = container.NetworkSettings.PortMappingAPI()
390 390
 		if size {
391 391
 			c.SizeRw, c.SizeRootFs = container.GetSize()
392 392
 		}
... ...
@@ -27,10 +27,9 @@ func setupWorkingDirectory(workdir string) {
27 27
 	if workdir == "" {
28 28
 		return
29 29
 	}
30
-    syscall.Chdir(workdir)
30
+	syscall.Chdir(workdir)
31 31
 }
32 32
 
33
-
34 33
 // Takes care of dropping privileges to the desired user
35 34
 func changeUser(u string) {
36 35
 	if u == "" {