diff --git a/components/engine/commands.go b/components/engine/commands.go index e24b7aeece..ec51983ca0 100644 --- a/components/engine/commands.go +++ b/components/engine/commands.go @@ -31,6 +31,7 @@ import ( "strings" "syscall" "text/tabwriter" + "text/template" "time" ) @@ -632,6 +633,7 @@ func (cli *DockerCli) CmdStart(args ...string) error { func (cli *DockerCli) CmdInspect(args ...string) error { cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container/image") + tmplStr := cmd.String("format", "", "Format the output using the given go template.") if err := cmd.Parse(args); err != nil { return nil } @@ -640,10 +642,21 @@ func (cli *DockerCli) CmdInspect(args ...string) error { return nil } + var tmpl *template.Template + if *tmplStr != "" { + var err error + if tmpl, err = template.New("").Parse(*tmplStr); err != nil { + fmt.Fprintf(cli.err, "Template parsing error: %v\n", err) + return &utils.StatusError{StatusCode: 64, + Status: "Template parsing error: " + err.Error()} + } + } + indented := new(bytes.Buffer) + indented.WriteByte('[') status := 0 - for _, name := range args { + for _, name := range cmd.Args() { obj, _, err := cli.call("GET", "/containers/"+name+"/json", nil) if err != nil { obj, _, err = cli.call("GET", "/images/"+name+"/json", nil) @@ -658,23 +671,40 @@ func (cli *DockerCli) CmdInspect(args ...string) error { } } - if err = json.Indent(indented, obj, "", " "); err != nil { - fmt.Fprintf(cli.err, "%s\n", err) - status = 1 - continue + if tmpl == nil { + if err = json.Indent(indented, obj, "", " "); err != nil { + fmt.Fprintf(cli.err, "%s\n", err) + status = 1 + continue + } + } else { + // Has template, will render + var value interface{} + if err := json.Unmarshal(obj, &value); err != nil { + fmt.Fprintf(cli.err, "%s\n", err) + status = 1 + continue + } + if err := tmpl.Execute(cli.out, value); err != nil { + return err + } + cli.out.Write([]byte{'\n'}) } indented.WriteString(",") } - if indented.Len() > 0 { + if indented.Len() > 1 { // Remove trailing ',' indented.Truncate(indented.Len() - 1) } - fmt.Fprintf(cli.out, "[") - if _, err := io.Copy(cli.out, indented); err != nil { - return err + indented.WriteByte(']') + + if tmpl == nil { + if _, err := io.Copy(cli.out, indented); err != nil { + return err + } } - fmt.Fprintf(cli.out, "]") + if status != 0 { return &utils.StatusError{StatusCode: status} } diff --git a/components/engine/docs/sources/commandline/cli.rst b/components/engine/docs/sources/commandline/cli.rst index a6f15df8a6..d7bb03b954 100644 --- a/components/engine/docs/sources/commandline/cli.rst +++ b/components/engine/docs/sources/commandline/cli.rst @@ -659,6 +659,54 @@ Insert file from github Return low-level information on a container + -format="": template to output results + +By default, this will render all results in a JSON array. If a format +is specified, the given template will be executed for each result. + +Go's `text/template ` package +describes all the details of the format. + +Examples +~~~~~~~~ + +Get an instance's IP Address +............................ + +For the most part, you can pick out any field from the JSON in a +fairly straightforward manner. + +.. code-block:: bash + + docker inspect -format='{{.NetworkSettings.IPAddress}}' $INSTANCE_ID + +List All Port Bindings +...................... + +One can loop over arrays and maps in the results to produce simple +text output: + +.. code-block:: bash + + docker inspect -format='{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' $INSTANCE_ID + +Find a Specific Port Mapping +............................ + +.. code-block:: bash + +The ``.Field`` syntax doesn't work when the field name begins with a +number, but the template language's ``index`` function does. The +``.NetworkSettings.Ports`` section contains a map of the internal port +mappings to a list of external address/port objects, so to grab just +the numeric public port, you use ``index`` to find the specific port +map, and then ``index`` 0 contains first object inside of that. Then +we ask for the ``HostPort`` field to get the public address. + +.. code-block:: bash + + docker inspect -format='{{(index (index .NetworkSettings.Ports "8787/tcp") 0).HostPort}}' $INSTANCE_ID + .. _cli_kill: ``kill`` diff --git a/components/engine/docs/sources/examples/postgresql_service.rst b/components/engine/docs/sources/examples/postgresql_service.rst index 82ca8b59ca..e142f65899 100644 --- a/components/engine/docs/sources/examples/postgresql_service.rst +++ b/components/engine/docs/sources/examples/postgresql_service.rst @@ -127,7 +127,7 @@ on the machine. For ubuntu, use something like .. code-block:: bash - CONTAINER_IP=$(sudo docker inspect $CONTAINER | grep IPAddress | awk '{ print $2 }' | tr -d ',"') + CONTAINER_IP=$(sudo docker inspect -format='{{.NetworkSettings.IPAddress}}' $CONTAINER) psql -h $CONTAINER_IP -p 5432 -d docker -U docker -W As before, create roles or databases if needed.