diff --git a/api/client/inspect.go b/api/client/inspect.go index 75861cdf20..db281795cd 100644 --- a/api/client/inspect.go +++ b/api/client/inspect.go @@ -8,12 +8,14 @@ import ( "strings" "text/template" + "github.com/docker/docker/api/types" flag "github.com/docker/docker/pkg/mflag" ) // CmdInspect displays low-level information on one or more containers or images. // // Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...] + func (cli *DockerCli) CmdInspect(args ...string) error { cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true) 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 { indented := new(bytes.Buffer) indented.WriteByte('[') status := 0 + isImage := false for _, name := range cmd.Args() { obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, nil)) if err != nil { obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, nil)) + isImage = true if err != nil { if strings.Contains(err.Error(), "No such") { fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name) @@ -57,20 +61,29 @@ func (cli *DockerCli) CmdInspect(args ...string) error { continue } } else { - var value interface{} - - // Do not use `json.Unmarshal()` because unmarshal JSON into - // an interface value, Unmarshal stores JSON numbers in - // float64, which is different from `json.Indent()` does. dec := json.NewDecoder(bytes.NewReader(obj)) - dec.UseNumber() - if err := dec.Decode(&value); err != nil { - fmt.Fprintf(cli.err, "%s\n", err) - status = 1 - continue - } - if err := tmpl.Execute(cli.out, value); err != nil { - return err + + if isImage { + inspPtr := types.ImageInspect{} + if err := dec.Decode(&inspPtr); err != nil { + fmt.Fprintf(cli.err, "%s\n", err) + status = 1 + continue + } + if err := tmpl.Execute(cli.out, inspPtr); err != nil { + return err + } + } else { + inspPtr := types.ContainerJSON{} + if err := dec.Decode(&inspPtr); err != nil { + fmt.Fprintf(cli.err, "%s\n", err) + status = 1 + continue + } + if err := tmpl.Execute(cli.out, inspPtr); err != nil { + return err + + } } cli.out.Write([]byte{'\n'}) } diff --git a/api/types/types.go b/api/types/types.go index 656aa1a6eb..7c31065460 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -75,6 +75,23 @@ type Image struct { Labels map[string]string } +// GET "/images/{name:.*}/json" +type ImageInspect struct { + Id string + Parent string + Comment string + Created time.Time + Container string + ContainerConfig *runconfig.Config + DockerVersion string + Author string + Config *runconfig.Config + Architecture string + Os string + Size int64 + VirtualSize int64 +} + type LegacyImage struct { ID string `json:"Id"` Repository string diff --git a/integration-cli/docker_api_containers_test.go b/integration-cli/docker_api_containers_test.go index 0351d412af..8efc6239d9 100644 --- a/integration-cli/docker_api_containers_test.go +++ b/integration-cli/docker_api_containers_test.go @@ -644,7 +644,7 @@ func (s *DockerSuite) TestContainerApiCommit(c *check.C) { if err != nil { c.Fatal(err) } - if cmd != "[/bin/sh -c touch /test]" { + if cmd != "{[/bin/sh -c touch /test]}" { c.Fatalf("got wrong Cmd from commit: %q", cmd) } // sanity check, make sure the image is what we think it is diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index 56a11cdd4e..70e4ba114c 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -2349,7 +2349,7 @@ func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) { func (s *DockerSuite) TestBuildCmd(c *check.C) { name := "testbuildcmd" - expected := "[/bin/echo Hello World]" + expected := "{[/bin/echo Hello World]}" defer deleteImages(name) _, err := buildImage(name, `FROM scratch @@ -2369,7 +2369,7 @@ func (s *DockerSuite) TestBuildCmd(c *check.C) { func (s *DockerSuite) TestBuildExpose(c *check.C) { name := "testbuildexpose" - expected := "map[2375/tcp:map[]]" + expected := "map[2375/tcp:{}]" defer deleteImages(name) _, err := buildImage(name, `FROM scratch @@ -2466,7 +2466,7 @@ func (s *DockerSuite) TestBuildExposeOrder(c *check.C) { func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) { name := "testbuildexposeuppercaseproto" - expected := "map[5678/udp:map[]]" + expected := "map[5678/udp:{}]" defer deleteImages(name) _, err := buildImage(name, `FROM scratch @@ -2487,7 +2487,7 @@ func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) { func (s *DockerSuite) TestBuildExposeHostPort(c *check.C) { // start building docker file with ip:hostPort:containerPort name := "testbuildexpose" - expected := "map[5678/tcp:map[]]" + expected := "map[5678/tcp:{}]" defer deleteImages(name) _, out, err := buildImageWithOut(name, `FROM scratch @@ -2527,7 +2527,7 @@ func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) { c.Fatal(err) } - expected := "[/bin/echo]" + expected := "{[/bin/echo]}" if res != expected { c.Fatalf("Entrypoint %s, expected %s", res, expected) } @@ -2544,7 +2544,7 @@ func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) { c.Fatal(err) } - expected = "[]" + expected = "{[]}" if res != expected { c.Fatalf("Entrypoint %s, expected %s", res, expected) @@ -2555,7 +2555,7 @@ func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) { func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) { name := "testbuildentrypoint" defer deleteImages(name) - expected := "[]" + expected := "{[]}" _, err := buildImage(name, `FROM busybox @@ -2576,7 +2576,7 @@ func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) { func (s *DockerSuite) TestBuildEntrypoint(c *check.C) { name := "testbuildentrypoint" - expected := "[/bin/echo]" + expected := "{[/bin/echo]}" defer deleteImages(name) _, err := buildImage(name, `FROM scratch @@ -3296,8 +3296,8 @@ func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) { c.Fatal(err) } // Cmd must be cleaned up - if expected := ""; res != expected { - c.Fatalf("Cmd %s, expected %s", res, expected) + if res != "" { + c.Fatalf("Cmd %s, expected nil", res) } } @@ -3370,7 +3370,7 @@ func (s *DockerSuite) TestBuildInheritance(c *check.C) { if err != nil { c.Fatal(err) } - if expected := "[/bin/echo]"; res != expected { + if expected := "{[/bin/echo]}"; res != expected { c.Fatalf("Entrypoint %s, expected %s", res, expected) } ports2, err := inspectField(name, "Config.ExposedPorts") @@ -4241,14 +4241,15 @@ func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) { if err != nil { c.Fatal(err) } - if expected := ""; res != expected { - c.Fatalf("Cmd %s, expected %s", res, expected) + if res != "" { + c.Fatalf("Cmd %s, expected nil", res) } + res, err = inspectField(name, "Config.Entrypoint") if err != nil { c.Fatal(err) } - if expected := "[cat]"; res != expected { + if expected := "{[cat]}"; res != expected { c.Fatalf("Entrypoint %s, expected %s", res, expected) } } diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go index 9bbff09ccd..a75621f3a3 100644 --- a/integration-cli/docker_cli_commit_test.go +++ b/integration-cli/docker_cli_commit_test.go @@ -251,7 +251,7 @@ func (s *DockerSuite) TestCommitChange(c *check.C) { defer deleteImages(imageId) expected := map[string]string{ - "Config.ExposedPorts": "map[8080/tcp:map[]]", + "Config.ExposedPorts": "map[8080/tcp:{}]", "Config.Env": "[DEBUG=true test=1 PATH=/foo]", } diff --git a/integration-cli/docker_cli_exec_test.go b/integration-cli/docker_cli_exec_test.go index 7fc3d4f25c..0716c486b5 100644 --- a/integration-cli/docker_cli_exec_test.go +++ b/integration-cli/docker_cli_exec_test.go @@ -448,7 +448,7 @@ func (s *DockerSuite) TestInspectExecID(c *check.C) { if err != nil { c.Fatalf("failed to inspect container: %s, %v", out, err) } - if out != "" { + if out != "[]" { c.Fatalf("ExecIDs should be empty, got: %s", out) } diff --git a/integration-cli/docker_cli_inspect_test.go b/integration-cli/docker_cli_inspect_test.go index 9a5a7b6604..58c61a9d0f 100644 --- a/integration-cli/docker_cli_inspect_test.go +++ b/integration-cli/docker_cli_inspect_test.go @@ -1,7 +1,9 @@ package main import ( + "fmt" "os/exec" + "strconv" "strings" "github.com/go-check/check" @@ -41,3 +43,58 @@ func (s *DockerSuite) TestInspectInt64(c *check.C) { c.Fatalf("inspect got wrong value, got: %q, expected: 314572800", inspectOut) } } + +func (s *DockerSuite) TestInspectImageFilterInt(c *check.C) { + imageTest := "emptyfs" + imagesCmd := exec.Command(dockerBinary, "inspect", "--format='{{.Size}}'", imageTest) + out, exitCode, err := runCommandWithOutput(imagesCmd) + if exitCode != 0 || err != nil { + c.Fatalf("failed to inspect image: %s, %v", out, err) + } + size, err := strconv.Atoi(strings.TrimSuffix(out, "\n")) + if err != nil { + c.Fatalf("failed to inspect size of the image: %s, %v", out, err) + } + + //now see if the size turns out to be the same + formatStr := fmt.Sprintf("--format='{{eq .Size %d}}'", size) + imagesCmd = exec.Command(dockerBinary, "inspect", formatStr, imageTest) + out, exitCode, err = runCommandWithOutput(imagesCmd) + if exitCode != 0 || err != nil { + c.Fatalf("failed to inspect image: %s, %v", out, err) + } + if result, err := strconv.ParseBool(strings.TrimSuffix(out, "\n")); err != nil || !result { + c.Fatalf("Expected size: %d for image: %s but received size: %s", size, imageTest, strings.TrimSuffix(out, "\n")) + } +} + +func (s *DockerSuite) TestInspectContainerFilterInt(c *check.C) { + runCmd := exec.Command("bash", "-c", `echo "blahblah" | docker run -i -a stdin busybox cat`) + out, _, _, err := runCommandWithStdoutStderr(runCmd) + if err != nil { + c.Fatalf("failed to run container: %v, output: %q", err, out) + } + + id := strings.TrimSpace(out) + + runCmd = exec.Command(dockerBinary, "inspect", "--format='{{.State.ExitCode}}'", id) + out, _, err = runCommandWithOutput(runCmd) + if err != nil { + c.Fatalf("failed to inspect container: %s, %v", out, err) + } + exitCode, err := strconv.Atoi(strings.TrimSuffix(out, "\n")) + if err != nil { + c.Fatalf("failed to inspect exitcode of the container: %s, %v", out, err) + } + + //now get the exit code to verify + formatStr := fmt.Sprintf("--format='{{eq .State.ExitCode %d}}'", exitCode) + runCmd = exec.Command(dockerBinary, "inspect", formatStr, id) + out, _, err = runCommandWithOutput(runCmd) + if err != nil { + c.Fatalf("failed to inspect container: %s, %v", out, err) + } + if result, err := strconv.ParseBool(strings.TrimSuffix(out, "\n")); err != nil || !result { + c.Fatalf("Expected exitcode: %d for container: %s", exitCode, id) + } +} diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index f23417037f..8da6f3b879 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -2441,7 +2441,7 @@ func (s *DockerSuite) TestRunVolumesCleanPaths(c *check.C) { if err != nil { c.Fatal(err) } - if out != "" { + if out != "" { c.Fatalf("Found unexpected volume entry for '/foo/' in volumes\n%q", out) } @@ -2457,7 +2457,7 @@ func (s *DockerSuite) TestRunVolumesCleanPaths(c *check.C) { if err != nil { c.Fatal(err) } - if out != "" { + if out != "" { c.Fatalf("Found unexpected volume entry for '/bar/' in volumes\n%q", out) } out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar")