Browse code

Allow go template to work properly with inspect Closes #11641

Signed-off-by: Srini Brahmaroutu <srbrahma@us.ibm.com>

Srini Brahmaroutu authored on 2015/03/27 04:43:00
Showing 8 changed files
... ...
@@ -8,12 +8,14 @@ import (
8 8
 	"strings"
9 9
 	"text/template"
10 10
 
11
+	"github.com/docker/docker/api/types"
11 12
 	flag "github.com/docker/docker/pkg/mflag"
12 13
 )
13 14
 
14 15
 // CmdInspect displays low-level information on one or more containers or images.
15 16
 //
16 17
 // Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]
18
+
17 19
 func (cli *DockerCli) CmdInspect(args ...string) error {
18 20
 	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
19 21
 	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template")
... ...
@@ -34,11 +36,13 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
34 34
 	indented := new(bytes.Buffer)
35 35
 	indented.WriteByte('[')
36 36
 	status := 0
37
+	isImage := false
37 38
 
38 39
 	for _, name := range cmd.Args() {
39 40
 		obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, nil))
40 41
 		if err != nil {
41 42
 			obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, nil))
43
+			isImage = true
42 44
 			if err != nil {
43 45
 				if strings.Contains(err.Error(), "No such") {
44 46
 					fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
... ...
@@ -57,20 +61,29 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
57 57
 				continue
58 58
 			}
59 59
 		} else {
60
-			var value interface{}
61
-
62
-			// Do not use `json.Unmarshal()` because unmarshal JSON into
63
-			// an interface value, Unmarshal stores JSON numbers in
64
-			// float64, which is different from `json.Indent()` does.
65 60
 			dec := json.NewDecoder(bytes.NewReader(obj))
66
-			dec.UseNumber()
67
-			if err := dec.Decode(&value); err != nil {
68
-				fmt.Fprintf(cli.err, "%s\n", err)
69
-				status = 1
70
-				continue
71
-			}
72
-			if err := tmpl.Execute(cli.out, value); err != nil {
73
-				return err
61
+
62
+			if isImage {
63
+				inspPtr := types.ImageInspect{}
64
+				if err := dec.Decode(&inspPtr); err != nil {
65
+					fmt.Fprintf(cli.err, "%s\n", err)
66
+					status = 1
67
+					continue
68
+				}
69
+				if err := tmpl.Execute(cli.out, inspPtr); err != nil {
70
+					return err
71
+				}
72
+			} else {
73
+				inspPtr := types.ContainerJSON{}
74
+				if err := dec.Decode(&inspPtr); err != nil {
75
+					fmt.Fprintf(cli.err, "%s\n", err)
76
+					status = 1
77
+					continue
78
+				}
79
+				if err := tmpl.Execute(cli.out, inspPtr); err != nil {
80
+					return err
81
+
82
+				}
74 83
 			}
75 84
 			cli.out.Write([]byte{'\n'})
76 85
 		}
... ...
@@ -75,6 +75,23 @@ type Image struct {
75 75
 	Labels      map[string]string
76 76
 }
77 77
 
78
+// GET "/images/{name:.*}/json"
79
+type ImageInspect struct {
80
+	Id              string
81
+	Parent          string
82
+	Comment         string
83
+	Created         time.Time
84
+	Container       string
85
+	ContainerConfig *runconfig.Config
86
+	DockerVersion   string
87
+	Author          string
88
+	Config          *runconfig.Config
89
+	Architecture    string
90
+	Os              string
91
+	Size            int64
92
+	VirtualSize     int64
93
+}
94
+
78 95
 type LegacyImage struct {
79 96
 	ID          string `json:"Id"`
80 97
 	Repository  string
... ...
@@ -644,7 +644,7 @@ func (s *DockerSuite) TestContainerApiCommit(c *check.C) {
644 644
 	if err != nil {
645 645
 		c.Fatal(err)
646 646
 	}
647
-	if cmd != "[/bin/sh -c touch /test]" {
647
+	if cmd != "{[/bin/sh -c touch /test]}" {
648 648
 		c.Fatalf("got wrong Cmd from commit: %q", cmd)
649 649
 	}
650 650
 	// sanity check, make sure the image is what we think it is
... ...
@@ -2350,7 +2350,7 @@ func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) {
2350 2350
 
2351 2351
 func (s *DockerSuite) TestBuildCmd(c *check.C) {
2352 2352
 	name := "testbuildcmd"
2353
-	expected := "[/bin/echo Hello World]"
2353
+	expected := "{[/bin/echo Hello World]}"
2354 2354
 	defer deleteImages(name)
2355 2355
 	_, err := buildImage(name,
2356 2356
 		`FROM scratch
... ...
@@ -2370,7 +2370,7 @@ func (s *DockerSuite) TestBuildCmd(c *check.C) {
2370 2370
 
2371 2371
 func (s *DockerSuite) TestBuildExpose(c *check.C) {
2372 2372
 	name := "testbuildexpose"
2373
-	expected := "map[2375/tcp:map[]]"
2373
+	expected := "map[2375/tcp:{}]"
2374 2374
 	defer deleteImages(name)
2375 2375
 	_, err := buildImage(name,
2376 2376
 		`FROM scratch
... ...
@@ -2467,7 +2467,7 @@ func (s *DockerSuite) TestBuildExposeOrder(c *check.C) {
2467 2467
 
2468 2468
 func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) {
2469 2469
 	name := "testbuildexposeuppercaseproto"
2470
-	expected := "map[5678/udp:map[]]"
2470
+	expected := "map[5678/udp:{}]"
2471 2471
 	defer deleteImages(name)
2472 2472
 	_, err := buildImage(name,
2473 2473
 		`FROM scratch
... ...
@@ -2488,7 +2488,7 @@ func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) {
2488 2488
 func (s *DockerSuite) TestBuildExposeHostPort(c *check.C) {
2489 2489
 	// start building docker file with ip:hostPort:containerPort
2490 2490
 	name := "testbuildexpose"
2491
-	expected := "map[5678/tcp:map[]]"
2491
+	expected := "map[5678/tcp:{}]"
2492 2492
 	defer deleteImages(name)
2493 2493
 	_, out, err := buildImageWithOut(name,
2494 2494
 		`FROM scratch
... ...
@@ -2528,7 +2528,7 @@ func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) {
2528 2528
 		c.Fatal(err)
2529 2529
 	}
2530 2530
 
2531
-	expected := "[/bin/echo]"
2531
+	expected := "{[/bin/echo]}"
2532 2532
 	if res != expected {
2533 2533
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
2534 2534
 	}
... ...
@@ -2545,7 +2545,7 @@ func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) {
2545 2545
 		c.Fatal(err)
2546 2546
 	}
2547 2547
 
2548
-	expected = "[]"
2548
+	expected = "{[]}"
2549 2549
 
2550 2550
 	if res != expected {
2551 2551
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
... ...
@@ -2556,7 +2556,7 @@ func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) {
2556 2556
 func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) {
2557 2557
 	name := "testbuildentrypoint"
2558 2558
 	defer deleteImages(name)
2559
-	expected := "[]"
2559
+	expected := "{[]}"
2560 2560
 
2561 2561
 	_, err := buildImage(name,
2562 2562
 		`FROM busybox
... ...
@@ -2577,7 +2577,7 @@ func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) {
2577 2577
 
2578 2578
 func (s *DockerSuite) TestBuildEntrypoint(c *check.C) {
2579 2579
 	name := "testbuildentrypoint"
2580
-	expected := "[/bin/echo]"
2580
+	expected := "{[/bin/echo]}"
2581 2581
 	defer deleteImages(name)
2582 2582
 	_, err := buildImage(name,
2583 2583
 		`FROM scratch
... ...
@@ -3297,8 +3297,8 @@ func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) {
3297 3297
 		c.Fatal(err)
3298 3298
 	}
3299 3299
 	// Cmd must be cleaned up
3300
-	if expected := "<no value>"; res != expected {
3301
-		c.Fatalf("Cmd %s, expected %s", res, expected)
3300
+	if res != "<nil>" {
3301
+		c.Fatalf("Cmd %s, expected nil", res)
3302 3302
 	}
3303 3303
 }
3304 3304
 
... ...
@@ -3371,7 +3371,7 @@ func (s *DockerSuite) TestBuildInheritance(c *check.C) {
3371 3371
 	if err != nil {
3372 3372
 		c.Fatal(err)
3373 3373
 	}
3374
-	if expected := "[/bin/echo]"; res != expected {
3374
+	if expected := "{[/bin/echo]}"; res != expected {
3375 3375
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
3376 3376
 	}
3377 3377
 	ports2, err := inspectField(name, "Config.ExposedPorts")
... ...
@@ -4242,14 +4242,15 @@ func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) {
4242 4242
 	if err != nil {
4243 4243
 		c.Fatal(err)
4244 4244
 	}
4245
-	if expected := "<no value>"; res != expected {
4246
-		c.Fatalf("Cmd %s, expected %s", res, expected)
4245
+	if res != "<nil>" {
4246
+		c.Fatalf("Cmd %s, expected nil", res)
4247 4247
 	}
4248
+
4248 4249
 	res, err = inspectField(name, "Config.Entrypoint")
4249 4250
 	if err != nil {
4250 4251
 		c.Fatal(err)
4251 4252
 	}
4252
-	if expected := "[cat]"; res != expected {
4253
+	if expected := "{[cat]}"; res != expected {
4253 4254
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
4254 4255
 	}
4255 4256
 }
... ...
@@ -251,7 +251,7 @@ func (s *DockerSuite) TestCommitChange(c *check.C) {
251 251
 	defer deleteImages(imageId)
252 252
 
253 253
 	expected := map[string]string{
254
-		"Config.ExposedPorts": "map[8080/tcp:map[]]",
254
+		"Config.ExposedPorts": "map[8080/tcp:{}]",
255 255
 		"Config.Env":          "[DEBUG=true test=1 PATH=/foo]",
256 256
 	}
257 257
 
... ...
@@ -448,7 +448,7 @@ func (s *DockerSuite) TestInspectExecID(c *check.C) {
448 448
 	if err != nil {
449 449
 		c.Fatalf("failed to inspect container: %s, %v", out, err)
450 450
 	}
451
-	if out != "<no value>" {
451
+	if out != "[]" {
452 452
 		c.Fatalf("ExecIDs should be empty, got: %s", out)
453 453
 	}
454 454
 
... ...
@@ -1,7 +1,9 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"os/exec"
6
+	"strconv"
5 7
 	"strings"
6 8
 
7 9
 	"github.com/go-check/check"
... ...
@@ -41,3 +43,58 @@ func (s *DockerSuite) TestInspectInt64(c *check.C) {
41 41
 		c.Fatalf("inspect got wrong value, got: %q, expected: 314572800", inspectOut)
42 42
 	}
43 43
 }
44
+
45
+func (s *DockerSuite) TestInspectImageFilterInt(c *check.C) {
46
+	imageTest := "emptyfs"
47
+	imagesCmd := exec.Command(dockerBinary, "inspect", "--format='{{.Size}}'", imageTest)
48
+	out, exitCode, err := runCommandWithOutput(imagesCmd)
49
+	if exitCode != 0 || err != nil {
50
+		c.Fatalf("failed to inspect image: %s, %v", out, err)
51
+	}
52
+	size, err := strconv.Atoi(strings.TrimSuffix(out, "\n"))
53
+	if err != nil {
54
+		c.Fatalf("failed to inspect size of the image: %s, %v", out, err)
55
+	}
56
+
57
+	//now see if the size turns out to be the same
58
+	formatStr := fmt.Sprintf("--format='{{eq .Size %d}}'", size)
59
+	imagesCmd = exec.Command(dockerBinary, "inspect", formatStr, imageTest)
60
+	out, exitCode, err = runCommandWithOutput(imagesCmd)
61
+	if exitCode != 0 || err != nil {
62
+		c.Fatalf("failed to inspect image: %s, %v", out, err)
63
+	}
64
+	if result, err := strconv.ParseBool(strings.TrimSuffix(out, "\n")); err != nil || !result {
65
+		c.Fatalf("Expected size: %d for image: %s but received size: %s", size, imageTest, strings.TrimSuffix(out, "\n"))
66
+	}
67
+}
68
+
69
+func (s *DockerSuite) TestInspectContainerFilterInt(c *check.C) {
70
+	runCmd := exec.Command("bash", "-c", `echo "blahblah" | docker run -i -a stdin busybox cat`)
71
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
72
+	if err != nil {
73
+		c.Fatalf("failed to run container: %v, output: %q", err, out)
74
+	}
75
+
76
+	id := strings.TrimSpace(out)
77
+
78
+	runCmd = exec.Command(dockerBinary, "inspect", "--format='{{.State.ExitCode}}'", id)
79
+	out, _, err = runCommandWithOutput(runCmd)
80
+	if err != nil {
81
+		c.Fatalf("failed to inspect container: %s, %v", out, err)
82
+	}
83
+	exitCode, err := strconv.Atoi(strings.TrimSuffix(out, "\n"))
84
+	if err != nil {
85
+		c.Fatalf("failed to inspect exitcode of the container: %s, %v", out, err)
86
+	}
87
+
88
+	//now get the exit code to verify
89
+	formatStr := fmt.Sprintf("--format='{{eq .State.ExitCode %d}}'", exitCode)
90
+	runCmd = exec.Command(dockerBinary, "inspect", formatStr, id)
91
+	out, _, err = runCommandWithOutput(runCmd)
92
+	if err != nil {
93
+		c.Fatalf("failed to inspect container: %s, %v", out, err)
94
+	}
95
+	if result, err := strconv.ParseBool(strings.TrimSuffix(out, "\n")); err != nil || !result {
96
+		c.Fatalf("Expected exitcode: %d for container: %s", exitCode, id)
97
+	}
98
+}
... ...
@@ -2443,7 +2443,7 @@ func (s *DockerSuite) TestRunVolumesCleanPaths(c *check.C) {
2443 2443
 	if err != nil {
2444 2444
 		c.Fatal(err)
2445 2445
 	}
2446
-	if out != "<no value>" {
2446
+	if out != "" {
2447 2447
 		c.Fatalf("Found unexpected volume entry for '/foo/' in volumes\n%q", out)
2448 2448
 	}
2449 2449
 
... ...
@@ -2459,7 +2459,7 @@ func (s *DockerSuite) TestRunVolumesCleanPaths(c *check.C) {
2459 2459
 	if err != nil {
2460 2460
 		c.Fatal(err)
2461 2461
 	}
2462
-	if out != "<no value>" {
2462
+	if out != "" {
2463 2463
 		c.Fatalf("Found unexpected volume entry for '/bar/' in volumes\n%q", out)
2464 2464
 	}
2465 2465
 	out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar")