diff --git a/api/client/inspect.go b/api/client/inspect.go index c55cbc738f..cb16b1bb52 100644 --- a/api/client/inspect.go +++ b/api/client/inspect.go @@ -8,7 +8,6 @@ import ( "github.com/docker/docker/api/client/inspect" Cli "github.com/docker/docker/cli" flag "github.com/docker/docker/pkg/mflag" - "github.com/docker/docker/utils/templates" "github.com/docker/engine-api/client" ) @@ -30,7 +29,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error { ctx := context.Background() - var elementSearcher inspectSearcher + var elementSearcher inspect.GetRefFunc switch *inspectType { case "container": elementSearcher = cli.inspectContainers(ctx, *size) @@ -40,22 +39,22 @@ func (cli *DockerCli) CmdInspect(args ...string) error { elementSearcher = cli.inspectAll(ctx, *size) } - return cli.inspectElements(*tmplStr, cmd.Args(), elementSearcher) + return inspect.Inspect(cli.out, cmd.Args(), *tmplStr, elementSearcher) } -func (cli *DockerCli) inspectContainers(ctx context.Context, getSize bool) inspectSearcher { +func (cli *DockerCli) inspectContainers(ctx context.Context, getSize bool) inspect.GetRefFunc { return func(ref string) (interface{}, []byte, error) { return cli.client.ContainerInspectWithRaw(ctx, ref, getSize) } } -func (cli *DockerCli) inspectImages(ctx context.Context, getSize bool) inspectSearcher { +func (cli *DockerCli) inspectImages(ctx context.Context, getSize bool) inspect.GetRefFunc { return func(ref string) (interface{}, []byte, error) { return cli.client.ImageInspectWithRaw(ctx, ref, getSize) } } -func (cli *DockerCli) inspectAll(ctx context.Context, getSize bool) inspectSearcher { +func (cli *DockerCli) inspectAll(ctx context.Context, getSize bool) inspect.GetRefFunc { return func(ref string) (interface{}, []byte, error) { c, rawContainer, err := cli.client.ContainerInspectWithRaw(ctx, ref, getSize) if err != nil { @@ -75,55 +74,3 @@ func (cli *DockerCli) inspectAll(ctx context.Context, getSize bool) inspectSearc return c, rawContainer, err } } - -type inspectSearcher func(ref string) (interface{}, []byte, error) - -func (cli *DockerCli) inspectElements(tmplStr string, references []string, searchByReference inspectSearcher) error { - elementInspector, err := cli.newInspectorWithTemplate(tmplStr) - if err != nil { - return Cli.StatusError{StatusCode: 64, Status: err.Error()} - } - - var inspectErr error - for _, ref := range references { - element, raw, err := searchByReference(ref) - if err != nil { - inspectErr = err - break - } - - if err := elementInspector.Inspect(element, raw); err != nil { - inspectErr = err - break - } - } - - if err := elementInspector.Flush(); err != nil { - cli.inspectErrorStatus(err) - } - - if status := cli.inspectErrorStatus(inspectErr); status != 0 { - return Cli.StatusError{StatusCode: status} - } - return nil -} - -func (cli *DockerCli) inspectErrorStatus(err error) (status int) { - if err != nil { - fmt.Fprintf(cli.err, "%s\n", err) - status = 1 - } - return -} - -func (cli *DockerCli) newInspectorWithTemplate(tmplStr string) (inspect.Inspector, error) { - elementInspector := inspect.NewIndentedInspector(cli.out) - if tmplStr != "" { - tmpl, err := templates.Parse(tmplStr) - if err != nil { - return nil, fmt.Errorf("Template parsing error: %s", err) - } - elementInspector = inspect.NewTemplateInspector(cli.out, tmpl) - } - return elementInspector, nil -} diff --git a/api/client/inspect/inspector.go b/api/client/inspect/inspector.go index a1d16d47c3..5de0e43283 100644 --- a/api/client/inspect/inspector.go +++ b/api/client/inspect/inspector.go @@ -6,6 +6,10 @@ import ( "fmt" "io" "text/template" + + "github.com/Sirupsen/logrus" + "github.com/docker/docker/cli" + "github.com/docker/docker/utils/templates" ) // Inspector defines an interface to implement to process elements @@ -30,6 +34,56 @@ func NewTemplateInspector(outputStream io.Writer, tmpl *template.Template) Inspe } } +// NewTemplateInspectorFromString creates a new TemplateInspector from a string +// which is compiled into a template. +func NewTemplateInspectorFromString(out io.Writer, tmplStr string) (Inspector, error) { + if tmplStr == "" { + return NewIndentedInspector(out), nil + } + + tmpl, err := templates.Parse(tmplStr) + if err != nil { + return nil, fmt.Errorf("Template parsing error: %s", err) + } + return NewTemplateInspector(out, tmpl), nil +} + +// GetRefFunc is a function which used by Inspect to fetch an object from a +// reference +type GetRefFunc func(ref string) (interface{}, []byte, error) + +// Inspect fetches objects by reference using GetRefFunc and writes the json +// representation to the output writer. +func Inspect(out io.Writer, references []string, tmplStr string, getRef GetRefFunc) error { + inspector, err := NewTemplateInspectorFromString(out, tmplStr) + if err != nil { + return cli.StatusError{StatusCode: 64, Status: err.Error()} + } + + var inspectErr error + for _, ref := range references { + element, raw, err := getRef(ref) + if err != nil { + inspectErr = err + break + } + + if err := inspector.Inspect(element, raw); err != nil { + inspectErr = err + break + } + } + + if err := inspector.Flush(); err != nil { + logrus.Errorf("%s\n", err) + } + + if inspectErr != nil { + return cli.StatusError{StatusCode: 1, Status: inspectErr.Error()} + } + return nil +} + // Inspect executes the inspect template. // It decodes the raw element into a map if the initial execution fails. // This allows docker cli to parse inspect structs injected with Swarm fields. diff --git a/api/client/network.go b/api/client/network.go index dfd7b26234..505ecac1cd 100644 --- a/api/client/network.go +++ b/api/client/network.go @@ -9,6 +9,7 @@ import ( "golang.org/x/net/context" + "github.com/docker/docker/api/client/inspect" Cli "github.com/docker/docker/cli" "github.com/docker/docker/opts" flag "github.com/docker/docker/pkg/mflag" @@ -249,7 +250,7 @@ func (cli *DockerCli) CmdNetworkInspect(args ...string) error { return i, nil, err } - return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher) + return inspect.Inspect(cli.out, cmd.Args(), *tmplStr, inspectSearcher) } // Consolidates the ipam configuration as a group from different related configurations