Signed-off-by: Srini Brahmaroutu <srbrahma@us.ibm.com>
| ... | ... |
@@ -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")
|