It makes the behavior completely consistent across commands.
It adds tests to check that execution stops when an element is not
found.
Signed-off-by: David Calavera <david.calavera@gmail.com>
| ... | ... |
@@ -34,97 +34,100 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
|
| 34 | 34 |
return fmt.Errorf("%q is not a valid value for --type", *inspectType)
|
| 35 | 35 |
} |
| 36 | 36 |
|
| 37 |
- var ( |
|
| 38 |
- err error |
|
| 39 |
- tmpl *template.Template |
|
| 40 |
- elementInspector inspect.Inspector |
|
| 41 |
- ) |
|
| 42 |
- |
|
| 43 |
- if *tmplStr != "" {
|
|
| 44 |
- if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
|
|
| 45 |
- return Cli.StatusError{StatusCode: 64,
|
|
| 46 |
- Status: "Template parsing error: " + err.Error()} |
|
| 47 |
- } |
|
| 48 |
- } |
|
| 49 |
- |
|
| 50 |
- if tmpl != nil {
|
|
| 51 |
- elementInspector = inspect.NewTemplateInspector(cli.out, tmpl) |
|
| 52 |
- } else {
|
|
| 53 |
- elementInspector = inspect.NewIndentedInspector(cli.out) |
|
| 54 |
- } |
|
| 55 |
- |
|
| 37 |
+ var elementSearcher inspectSearcher |
|
| 56 | 38 |
switch *inspectType {
|
| 57 | 39 |
case "container": |
| 58 |
- err = cli.inspectContainers(cmd.Args(), *size, elementInspector) |
|
| 59 |
- case "images": |
|
| 60 |
- err = cli.inspectImages(cmd.Args(), *size, elementInspector) |
|
| 40 |
+ elementSearcher = cli.inspectContainers(*size) |
|
| 41 |
+ case "image": |
|
| 42 |
+ elementSearcher = cli.inspectImages(*size) |
|
| 61 | 43 |
default: |
| 62 |
- err = cli.inspectAll(cmd.Args(), *size, elementInspector) |
|
| 44 |
+ elementSearcher = cli.inspectAll(*size) |
|
| 63 | 45 |
} |
| 64 | 46 |
|
| 65 |
- if err := elementInspector.Flush(); err != nil {
|
|
| 66 |
- return err |
|
| 67 |
- } |
|
| 68 |
- return err |
|
| 47 |
+ return cli.inspectElements(*tmplStr, cmd.Args(), elementSearcher) |
|
| 69 | 48 |
} |
| 70 | 49 |
|
| 71 |
-func (cli *DockerCli) inspectContainers(containerIDs []string, getSize bool, elementInspector inspect.Inspector) error {
|
|
| 72 |
- for _, containerID := range containerIDs {
|
|
| 73 |
- if err := cli.inspectContainer(containerID, getSize, elementInspector); err != nil {
|
|
| 74 |
- if lib.IsErrContainerNotFound(err) {
|
|
| 75 |
- return fmt.Errorf("Error: No such container: %s\n", containerID)
|
|
| 76 |
- } |
|
| 77 |
- return err |
|
| 78 |
- } |
|
| 50 |
+func (cli *DockerCli) inspectContainers(getSize bool) inspectSearcher {
|
|
| 51 |
+ return func(ref string) (interface{}, []byte, error) {
|
|
| 52 |
+ return cli.client.ContainerInspectWithRaw(ref, getSize) |
|
| 79 | 53 |
} |
| 80 |
- return nil |
|
| 81 | 54 |
} |
| 82 | 55 |
|
| 83 |
-func (cli *DockerCli) inspectImages(imageIDs []string, getSize bool, elementInspector inspect.Inspector) error {
|
|
| 84 |
- for _, imageID := range imageIDs {
|
|
| 85 |
- if err := cli.inspectImage(imageID, getSize, elementInspector); err != nil {
|
|
| 86 |
- if lib.IsErrImageNotFound(err) {
|
|
| 87 |
- return fmt.Errorf("Error: No such image: %s\n", imageID)
|
|
| 88 |
- } |
|
| 89 |
- return err |
|
| 90 |
- } |
|
| 56 |
+func (cli *DockerCli) inspectImages(getSize bool) inspectSearcher {
|
|
| 57 |
+ return func(ref string) (interface{}, []byte, error) {
|
|
| 58 |
+ return cli.client.ImageInspectWithRaw(ref, getSize) |
|
| 91 | 59 |
} |
| 92 |
- return nil |
|
| 93 | 60 |
} |
| 94 | 61 |
|
| 95 |
-func (cli *DockerCli) inspectAll(ids []string, getSize bool, elementInspector inspect.Inspector) error {
|
|
| 96 |
- for _, id := range ids {
|
|
| 97 |
- if err := cli.inspectContainer(id, getSize, elementInspector); err != nil {
|
|
| 62 |
+func (cli *DockerCli) inspectAll(getSize bool) inspectSearcher {
|
|
| 63 |
+ return func(ref string) (interface{}, []byte, error) {
|
|
| 64 |
+ c, rawContainer, err := cli.client.ContainerInspectWithRaw(ref, getSize) |
|
| 65 |
+ if err != nil {
|
|
| 98 | 66 |
// Search for image with that id if a container doesn't exist. |
| 99 | 67 |
if lib.IsErrContainerNotFound(err) {
|
| 100 |
- if err := cli.inspectImage(id, getSize, elementInspector); err != nil {
|
|
| 68 |
+ i, rawImage, err := cli.client.ImageInspectWithRaw(ref, getSize) |
|
| 69 |
+ if err != nil {
|
|
| 101 | 70 |
if lib.IsErrImageNotFound(err) {
|
| 102 |
- return fmt.Errorf("Error: No such image or container: %s", id)
|
|
| 71 |
+ return nil, nil, fmt.Errorf("Error: No such image or container: %s", ref)
|
|
| 103 | 72 |
} |
| 104 |
- return err |
|
| 73 |
+ return nil, nil, err |
|
| 105 | 74 |
} |
| 106 |
- continue |
|
| 75 |
+ return i, rawImage, err |
|
| 107 | 76 |
} |
| 108 |
- return err |
|
| 77 |
+ return nil, nil, err |
|
| 109 | 78 |
} |
| 79 |
+ return c, rawContainer, err |
|
| 110 | 80 |
} |
| 111 |
- return nil |
|
| 112 | 81 |
} |
| 113 | 82 |
|
| 114 |
-func (cli *DockerCli) inspectContainer(containerID string, getSize bool, elementInspector inspect.Inspector) error {
|
|
| 115 |
- c, raw, err := cli.client.ContainerInspectWithRaw(containerID, getSize) |
|
| 83 |
+type inspectSearcher func(ref string) (interface{}, []byte, error)
|
|
| 84 |
+ |
|
| 85 |
+func (cli *DockerCli) inspectElements(tmplStr string, references []string, searchByReference inspectSearcher) error {
|
|
| 86 |
+ elementInspector, err := cli.newInspectorWithTemplate(tmplStr) |
|
| 116 | 87 |
if err != nil {
|
| 117 |
- return err |
|
| 88 |
+ return Cli.StatusError{StatusCode: 64, Status: err.Error()}
|
|
| 89 |
+ } |
|
| 90 |
+ |
|
| 91 |
+ var inspectErr error |
|
| 92 |
+ for _, ref := range references {
|
|
| 93 |
+ element, raw, err := searchByReference(ref) |
|
| 94 |
+ if err != nil {
|
|
| 95 |
+ inspectErr = err |
|
| 96 |
+ break |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ if err := elementInspector.Inspect(element, raw); err != nil {
|
|
| 100 |
+ inspectErr = err |
|
| 101 |
+ break |
|
| 102 |
+ } |
|
| 118 | 103 |
} |
| 119 | 104 |
|
| 120 |
- return elementInspector.Inspect(c, raw) |
|
| 105 |
+ if err := elementInspector.Flush(); err != nil {
|
|
| 106 |
+ cli.inspectErrorStatus(err) |
|
| 107 |
+ } |
|
| 108 |
+ |
|
| 109 |
+ if status := cli.inspectErrorStatus(inspectErr); status != 0 {
|
|
| 110 |
+ return Cli.StatusError{StatusCode: status}
|
|
| 111 |
+ } |
|
| 112 |
+ return nil |
|
| 121 | 113 |
} |
| 122 | 114 |
|
| 123 |
-func (cli *DockerCli) inspectImage(imageID string, getSize bool, elementInspector inspect.Inspector) error {
|
|
| 124 |
- i, raw, err := cli.client.ImageInspectWithRaw(imageID, getSize) |
|
| 115 |
+func (cli *DockerCli) inspectErrorStatus(err error) (status int) {
|
|
| 125 | 116 |
if err != nil {
|
| 126 |
- return err |
|
| 117 |
+ fmt.Fprintf(cli.err, "%s\n", err) |
|
| 118 |
+ status = 1 |
|
| 127 | 119 |
} |
| 120 |
+ return |
|
| 121 |
+} |
|
| 128 | 122 |
|
| 129 |
- return elementInspector.Inspect(i, raw) |
|
| 123 |
+func (cli *DockerCli) newInspectorWithTemplate(tmplStr string) (inspect.Inspector, error) {
|
|
| 124 |
+ elementInspector := inspect.NewIndentedInspector(cli.out) |
|
| 125 |
+ if tmplStr != "" {
|
|
| 126 |
+ tmpl, err := template.New("").Funcs(funcMap).Parse(tmplStr)
|
|
| 127 |
+ if err != nil {
|
|
| 128 |
+ return nil, fmt.Errorf("Template parsing error: %s", err)
|
|
| 129 |
+ } |
|
| 130 |
+ elementInspector = inspect.NewTemplateInspector(cli.out, tmpl) |
|
| 131 |
+ } |
|
| 132 |
+ return elementInspector, nil |
|
| 130 | 133 |
} |
| ... | ... |
@@ -33,29 +33,41 @@ func NewTemplateInspector(outputStream io.Writer, tmpl *template.Template) Inspe |
| 33 | 33 |
// Inspect executes the inspect template. |
| 34 | 34 |
// It decodes the raw element into a map if the initial execution fails. |
| 35 | 35 |
// This allows docker cli to parse inspect structs injected with Swarm fields. |
| 36 |
-func (i TemplateInspector) Inspect(typedElement interface{}, rawElement []byte) error {
|
|
| 36 |
+func (i *TemplateInspector) Inspect(typedElement interface{}, rawElement []byte) error {
|
|
| 37 | 37 |
buffer := new(bytes.Buffer) |
| 38 | 38 |
if err := i.tmpl.Execute(buffer, typedElement); err != nil {
|
| 39 |
- var raw interface{}
|
|
| 40 |
- rdr := bytes.NewReader(rawElement) |
|
| 41 |
- dec := json.NewDecoder(rdr) |
|
| 42 |
- |
|
| 43 |
- if rawErr := dec.Decode(&raw); rawErr != nil {
|
|
| 44 |
- return fmt.Errorf("unable to read inspect data: %v\n", rawErr)
|
|
| 39 |
+ if rawElement == nil {
|
|
| 40 |
+ return fmt.Errorf("Template parsing error: %v", err)
|
|
| 45 | 41 |
} |
| 42 |
+ return i.tryRawInspectFallback(rawElement) |
|
| 43 |
+ } |
|
| 44 |
+ i.buffer.Write(buffer.Bytes()) |
|
| 45 |
+ i.buffer.WriteByte('\n')
|
|
| 46 |
+ return nil |
|
| 47 |
+} |
|
| 46 | 48 |
|
| 47 |
- tmplMissingKey := i.tmpl.Option("missingkey=error")
|
|
| 48 |
- if rawErr := tmplMissingKey.Execute(buffer, raw); rawErr != nil {
|
|
| 49 |
- return fmt.Errorf("Template parsing error: %v\n", err)
|
|
| 50 |
- } |
|
| 49 |
+func (i *TemplateInspector) tryRawInspectFallback(rawElement []byte) error {
|
|
| 50 |
+ var raw interface{}
|
|
| 51 |
+ buffer := new(bytes.Buffer) |
|
| 52 |
+ rdr := bytes.NewReader(rawElement) |
|
| 53 |
+ dec := json.NewDecoder(rdr) |
|
| 54 |
+ |
|
| 55 |
+ if rawErr := dec.Decode(&raw); rawErr != nil {
|
|
| 56 |
+ return fmt.Errorf("unable to read inspect data: %v", rawErr)
|
|
| 57 |
+ } |
|
| 58 |
+ |
|
| 59 |
+ tmplMissingKey := i.tmpl.Option("missingkey=error")
|
|
| 60 |
+ if rawErr := tmplMissingKey.Execute(buffer, raw); rawErr != nil {
|
|
| 61 |
+ return fmt.Errorf("Template parsing error: %v", rawErr)
|
|
| 51 | 62 |
} |
| 63 |
+ |
|
| 52 | 64 |
i.buffer.Write(buffer.Bytes()) |
| 53 | 65 |
i.buffer.WriteByte('\n')
|
| 54 | 66 |
return nil |
| 55 | 67 |
} |
| 56 | 68 |
|
| 57 | 69 |
// Flush write the result of inspecting all elements into the output stream. |
| 58 |
-func (i TemplateInspector) Flush() error {
|
|
| 70 |
+func (i *TemplateInspector) Flush() error {
|
|
| 59 | 71 |
_, err := io.Copy(i.outputStream, i.buffer) |
| 60 | 72 |
return err |
| 61 | 73 |
} |
| ... | ... |
@@ -63,39 +75,37 @@ func (i TemplateInspector) Flush() error {
|
| 63 | 63 |
// IndentedInspector uses a buffer to stop the indented representation of an element. |
| 64 | 64 |
type IndentedInspector struct {
|
| 65 | 65 |
outputStream io.Writer |
| 66 |
- indented *bytes.Buffer |
|
| 66 |
+ elements []interface{}
|
|
| 67 | 67 |
} |
| 68 | 68 |
|
| 69 | 69 |
// NewIndentedInspector generates a new IndentedInspector. |
| 70 | 70 |
func NewIndentedInspector(outputStream io.Writer) Inspector {
|
| 71 |
- indented := new(bytes.Buffer) |
|
| 72 |
- indented.WriteString("[\n")
|
|
| 73 | 71 |
return &IndentedInspector{
|
| 74 | 72 |
outputStream: outputStream, |
| 75 |
- indented: indented, |
|
| 76 | 73 |
} |
| 77 | 74 |
} |
| 78 | 75 |
|
| 79 | 76 |
// Inspect writes the raw element with an indented json format. |
| 80 |
-func (i IndentedInspector) Inspect(_ interface{}, rawElement []byte) error {
|
|
| 81 |
- if err := json.Indent(i.indented, rawElement, "", " "); err != nil {
|
|
| 82 |
- return err |
|
| 83 |
- } |
|
| 84 |
- i.indented.WriteByte(',')
|
|
| 77 |
+func (i *IndentedInspector) Inspect(typedElement interface{}, _ []byte) error {
|
|
| 78 |
+ i.elements = append(i.elements, typedElement) |
|
| 85 | 79 |
return nil |
| 86 | 80 |
} |
| 87 | 81 |
|
| 88 | 82 |
// Flush write the result of inspecting all elements into the output stream. |
| 89 |
-func (i IndentedInspector) Flush() error {
|
|
| 90 |
- if i.indented.Len() > 1 {
|
|
| 91 |
- // Remove trailing ',' |
|
| 92 |
- i.indented.Truncate(i.indented.Len() - 1) |
|
| 83 |
+func (i *IndentedInspector) Flush() error {
|
|
| 84 |
+ if len(i.elements) == 0 {
|
|
| 85 |
+ _, err := io.WriteString(i.outputStream, "[]\n") |
|
| 86 |
+ return err |
|
| 93 | 87 |
} |
| 94 |
- i.indented.WriteString("]\n")
|
|
| 95 | 88 |
|
| 96 |
- // Note that we will always write "[]" when "-f" isn't specified, |
|
| 97 |
- // to make sure the output would always be array, see |
|
| 98 |
- // https://github.com/docker/docker/pull/9500#issuecomment-65846734 |
|
| 99 |
- _, err := io.Copy(i.outputStream, i.indented) |
|
| 89 |
+ buffer, err := json.MarshalIndent(i.elements, "", " ") |
|
| 90 |
+ if err != nil {
|
|
| 91 |
+ return err |
|
| 92 |
+ } |
|
| 93 |
+ |
|
| 94 |
+ if _, err := io.Copy(i.outputStream, bytes.NewReader(buffer)); err != nil {
|
|
| 95 |
+ return err |
|
| 96 |
+ } |
|
| 97 |
+ _, err = io.WriteString(i.outputStream, "\n") |
|
| 100 | 98 |
return err |
| 101 | 99 |
} |
| ... | ... |
@@ -15,7 +15,7 @@ type imageNotFoundError struct {
|
| 15 | 15 |
|
| 16 | 16 |
// Error returns a string representation of an imageNotFoundError |
| 17 | 17 |
func (i imageNotFoundError) Error() string {
|
| 18 |
- return fmt.Sprintf("Image not found: %s", i.imageID)
|
|
| 18 |
+ return fmt.Sprintf("Error: No such image: %s", i.imageID)
|
|
| 19 | 19 |
} |
| 20 | 20 |
|
| 21 | 21 |
// IsErrImageNotFound returns true if the error is caused |
| ... | ... |
@@ -32,7 +32,7 @@ type containerNotFoundError struct {
|
| 32 | 32 |
|
| 33 | 33 |
// Error returns a string representation of an containerNotFoundError |
| 34 | 34 |
func (e containerNotFoundError) Error() string {
|
| 35 |
- return fmt.Sprintf("Container not found: %s", e.containerID)
|
|
| 35 |
+ return fmt.Sprintf("Error: No such container: %s", e.containerID)
|
|
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 | 38 |
// IsErrContainerNotFound returns true if the error is caused |
| ... | ... |
@@ -42,6 +42,40 @@ func IsErrContainerNotFound(err error) bool {
|
| 42 | 42 |
return ok |
| 43 | 43 |
} |
| 44 | 44 |
|
| 45 |
+// networkNotFoundError implements an error returned when a network is not in the docker host. |
|
| 46 |
+type networkNotFoundError struct {
|
|
| 47 |
+ networkID string |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+// Error returns a string representation of an networkNotFoundError |
|
| 51 |
+func (e networkNotFoundError) Error() string {
|
|
| 52 |
+ return fmt.Sprintf("Error: No such network: %s", e.networkID)
|
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+// IsErrNetworkNotFound returns true if the error is caused |
|
| 56 |
+// when a network is not found in the docker host. |
|
| 57 |
+func IsErrNetworkNotFound(err error) bool {
|
|
| 58 |
+ _, ok := err.(networkNotFoundError) |
|
| 59 |
+ return ok |
|
| 60 |
+} |
|
| 61 |
+ |
|
| 62 |
+// volumeNotFoundError implements an error returned when a volume is not in the docker host. |
|
| 63 |
+type volumeNotFoundError struct {
|
|
| 64 |
+ volumeID string |
|
| 65 |
+} |
|
| 66 |
+ |
|
| 67 |
+// Error returns a string representation of an networkNotFoundError |
|
| 68 |
+func (e volumeNotFoundError) Error() string {
|
|
| 69 |
+ return fmt.Sprintf("Error: No such volume: %s", e.volumeID)
|
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+// IsErrVolumeNotFound returns true if the error is caused |
|
| 73 |
+// when a volume is not found in the docker host. |
|
| 74 |
+func IsErrVolumeNotFound(err error) bool {
|
|
| 75 |
+ _, ok := err.(networkNotFoundError) |
|
| 76 |
+ return ok |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 45 | 79 |
// unauthorizedError represents an authorization error in a remote registry. |
| 46 | 80 |
type unauthorizedError struct {
|
| 47 | 81 |
cause error |
| ... | ... |
@@ -2,6 +2,7 @@ package lib |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 |
+ "net/http" |
|
| 5 | 6 |
|
| 6 | 7 |
"github.com/docker/docker/api/types" |
| 7 | 8 |
) |
| ... | ... |
@@ -59,6 +60,9 @@ func (cli *Client) NetworkInspect(networkID string) (types.NetworkResource, erro |
| 59 | 59 |
var networkResource types.NetworkResource |
| 60 | 60 |
resp, err := cli.get("/networks/"+networkID, nil, nil)
|
| 61 | 61 |
if err != nil {
|
| 62 |
+ if resp.statusCode == http.StatusNotFound {
|
|
| 63 |
+ return networkResource, networkNotFoundError{networkID}
|
|
| 64 |
+ } |
|
| 62 | 65 |
return networkResource, err |
| 63 | 66 |
} |
| 64 | 67 |
defer ensureReaderClosed(resp) |
| ... | ... |
@@ -2,6 +2,7 @@ package lib |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 |
+ "net/http" |
|
| 5 | 6 |
"net/url" |
| 6 | 7 |
|
| 7 | 8 |
"github.com/docker/docker/api/types" |
| ... | ... |
@@ -35,6 +36,9 @@ func (cli *Client) VolumeInspect(volumeID string) (types.Volume, error) {
|
| 35 | 35 |
var volume types.Volume |
| 36 | 36 |
resp, err := cli.get("/volumes/"+volumeID, nil, nil)
|
| 37 | 37 |
if err != nil {
|
| 38 |
+ if resp.statusCode == http.StatusNotFound {
|
|
| 39 |
+ return volume, volumeNotFoundError{volumeID}
|
|
| 40 |
+ } |
|
| 38 | 41 |
return volume, err |
| 39 | 42 |
} |
| 40 | 43 |
defer ensureReaderClosed(resp) |
| ... | ... |
@@ -1,14 +1,10 @@ |
| 1 | 1 |
package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "bytes" |
|
| 5 |
- "encoding/json" |
|
| 6 | 4 |
"fmt" |
| 7 |
- "io" |
|
| 8 | 5 |
"net" |
| 9 | 6 |
"strings" |
| 10 | 7 |
"text/tabwriter" |
| 11 |
- "text/template" |
|
| 12 | 8 |
|
| 13 | 9 |
"github.com/docker/docker/api/types" |
| 14 | 10 |
Cli "github.com/docker/docker/cli" |
| ... | ... |
@@ -192,61 +188,12 @@ func (cli *DockerCli) CmdNetworkInspect(args ...string) error {
|
| 192 | 192 |
return err |
| 193 | 193 |
} |
| 194 | 194 |
|
| 195 |
- var tmpl *template.Template |
|
| 196 |
- if *tmplStr != "" {
|
|
| 197 |
- var err error |
|
| 198 |
- tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr)
|
|
| 199 |
- if err != nil {
|
|
| 200 |
- return err |
|
| 201 |
- } |
|
| 195 |
+ inspectSearcher := func(name string) (interface{}, []byte, error) {
|
|
| 196 |
+ i, err := cli.client.NetworkInspect(name) |
|
| 197 |
+ return i, nil, err |
|
| 202 | 198 |
} |
| 203 | 199 |
|
| 204 |
- status := 0 |
|
| 205 |
- var networks []types.NetworkResource |
|
| 206 |
- buf := new(bytes.Buffer) |
|
| 207 |
- for _, name := range cmd.Args() {
|
|
| 208 |
- networkResource, err := cli.client.NetworkInspect(name) |
|
| 209 |
- if err != nil {
|
|
| 210 |
- fmt.Fprintf(cli.err, "%s\n", err) |
|
| 211 |
- return Cli.StatusError{StatusCode: 1}
|
|
| 212 |
- } |
|
| 213 |
- if tmpl == nil {
|
|
| 214 |
- networks = append(networks, networkResource) |
|
| 215 |
- continue |
|
| 216 |
- } |
|
| 217 |
- |
|
| 218 |
- if err := tmpl.Execute(buf, &networkResource); err != nil {
|
|
| 219 |
- fmt.Fprintf(cli.err, "%s\n", err) |
|
| 220 |
- return Cli.StatusError{StatusCode: 1}
|
|
| 221 |
- } |
|
| 222 |
- buf.WriteString("\n")
|
|
| 223 |
- } |
|
| 224 |
- |
|
| 225 |
- if tmpl != nil {
|
|
| 226 |
- if _, err := io.Copy(cli.out, buf); err != nil {
|
|
| 227 |
- return err |
|
| 228 |
- } |
|
| 229 |
- return nil |
|
| 230 |
- } |
|
| 231 |
- |
|
| 232 |
- if len(networks) == 0 {
|
|
| 233 |
- io.WriteString(cli.out, "[]") |
|
| 234 |
- } |
|
| 235 |
- |
|
| 236 |
- b, err := json.MarshalIndent(networks, "", " ") |
|
| 237 |
- if err != nil {
|
|
| 238 |
- return err |
|
| 239 |
- } |
|
| 240 |
- |
|
| 241 |
- if _, err := io.Copy(cli.out, bytes.NewReader(b)); err != nil {
|
|
| 242 |
- return err |
|
| 243 |
- } |
|
| 244 |
- io.WriteString(cli.out, "\n") |
|
| 245 |
- |
|
| 246 |
- if status != 0 {
|
|
| 247 |
- return Cli.StatusError{StatusCode: status}
|
|
| 248 |
- } |
|
| 249 |
- return nil |
|
| 200 |
+ return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher) |
|
| 250 | 201 |
} |
| 251 | 202 |
|
| 252 | 203 |
// Consolidates the ipam configuration as a group from different related configurations |
| ... | ... |
@@ -1,12 +1,8 @@ |
| 1 | 1 |
package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "bytes" |
|
| 5 |
- "encoding/json" |
|
| 6 | 4 |
"fmt" |
| 7 |
- "io" |
|
| 8 | 5 |
"text/tabwriter" |
| 9 |
- "text/template" |
|
| 10 | 6 |
|
| 11 | 7 |
"github.com/docker/docker/api/types" |
| 12 | 8 |
Cli "github.com/docker/docker/cli" |
| ... | ... |
@@ -98,58 +94,12 @@ func (cli *DockerCli) CmdVolumeInspect(args ...string) error {
|
| 98 | 98 |
return nil |
| 99 | 99 |
} |
| 100 | 100 |
|
| 101 |
- var tmpl *template.Template |
|
| 102 |
- if *tmplStr != "" {
|
|
| 103 |
- var err error |
|
| 104 |
- tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr)
|
|
| 105 |
- if err != nil {
|
|
| 106 |
- return err |
|
| 107 |
- } |
|
| 101 |
+ inspectSearcher := func(name string) (interface{}, []byte, error) {
|
|
| 102 |
+ i, err := cli.client.VolumeInspect(name) |
|
| 103 |
+ return i, nil, err |
|
| 108 | 104 |
} |
| 109 | 105 |
|
| 110 |
- var status = 0 |
|
| 111 |
- var volumes []*types.Volume |
|
| 112 |
- |
|
| 113 |
- for _, name := range cmd.Args() {
|
|
| 114 |
- volume, err := cli.client.VolumeInspect(name) |
|
| 115 |
- if err != nil {
|
|
| 116 |
- fmt.Fprintf(cli.err, "Unable to read inspect data: %v\n", err) |
|
| 117 |
- status = 1 |
|
| 118 |
- break |
|
| 119 |
- } |
|
| 120 |
- |
|
| 121 |
- if tmpl == nil {
|
|
| 122 |
- volumes = append(volumes, &volume) |
|
| 123 |
- continue |
|
| 124 |
- } |
|
| 125 |
- |
|
| 126 |
- buf := bytes.NewBufferString("")
|
|
| 127 |
- if err := tmpl.Execute(buf, &volume); err != nil {
|
|
| 128 |
- fmt.Fprintf(cli.err, "Template parsing error: %v\n", err) |
|
| 129 |
- status = 1 |
|
| 130 |
- break |
|
| 131 |
- } |
|
| 132 |
- |
|
| 133 |
- cli.out.Write(buf.Bytes()) |
|
| 134 |
- cli.out.Write([]byte{'\n'})
|
|
| 135 |
- } |
|
| 136 |
- |
|
| 137 |
- if tmpl == nil {
|
|
| 138 |
- b, err := json.MarshalIndent(volumes, "", " ") |
|
| 139 |
- if err != nil {
|
|
| 140 |
- return err |
|
| 141 |
- } |
|
| 142 |
- _, err = io.Copy(cli.out, bytes.NewReader(b)) |
|
| 143 |
- if err != nil {
|
|
| 144 |
- return err |
|
| 145 |
- } |
|
| 146 |
- io.WriteString(cli.out, "\n") |
|
| 147 |
- } |
|
| 148 |
- |
|
| 149 |
- if status != 0 {
|
|
| 150 |
- return Cli.StatusError{StatusCode: status}
|
|
| 151 |
- } |
|
| 152 |
- return nil |
|
| 106 |
+ return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher) |
|
| 153 | 107 |
} |
| 154 | 108 |
|
| 155 | 109 |
// CmdVolumeCreate creates a new container from a given image. |
| ... | ... |
@@ -356,3 +356,14 @@ func (s *DockerSuite) TestInspectByPrefix(c *check.C) {
|
| 356 | 356 |
c.Assert(err, checker.IsNil) |
| 357 | 357 |
c.Assert(id, checker.Equals, id3) |
| 358 | 358 |
} |
| 359 |
+ |
|
| 360 |
+func (s *DockerSuite) TestInspectStopWhenNotFound(c *check.C) {
|
|
| 361 |
+ dockerCmd(c, "run", "--name=busybox", "-d", "busybox", "top") |
|
| 362 |
+ dockerCmd(c, "run", "--name=not-shown", "-d", "busybox", "top") |
|
| 363 |
+ out, _, err := dockerCmdWithError("inspect", "--type=container", "--format='{{.Name}}'", "busybox", "missing", "not-shown")
|
|
| 364 |
+ |
|
| 365 |
+ c.Assert(err, checker.Not(check.IsNil)) |
|
| 366 |
+ c.Assert(out, checker.Contains, "busybox") |
|
| 367 |
+ c.Assert(out, checker.Not(checker.Contains), "not-shown") |
|
| 368 |
+ c.Assert(out, checker.Contains, "Error: No such container: missing") |
|
| 369 |
+} |
| ... | ... |
@@ -317,7 +317,7 @@ func (s *DockerSuite) TestDockerInspectMultipleNetwork(c *check.C) {
|
| 317 | 317 |
c.Assert(exitCode, checker.Equals, 1) |
| 318 | 318 |
c.Assert(out, checker.Contains, "Error: No such network: nonexistent") |
| 319 | 319 |
networkResources = []types.NetworkResource{}
|
| 320 |
- inspectOut := strings.SplitN(out, "\n", 2)[1] |
|
| 320 |
+ inspectOut := strings.SplitN(out, "\nError: No such network: nonexistent\n", 2)[0] |
|
| 321 | 321 |
err = json.Unmarshal([]byte(inspectOut), &networkResources) |
| 322 | 322 |
c.Assert(networkResources, checker.HasLen, 1) |
| 323 | 323 |
|
| ... | ... |
@@ -53,15 +53,17 @@ func (s *DockerSuite) TestVolumeCliInspect(c *check.C) {
|
| 53 | 53 |
func (s *DockerSuite) TestVolumeCliInspectMulti(c *check.C) {
|
| 54 | 54 |
dockerCmd(c, "volume", "create", "--name", "test1") |
| 55 | 55 |
dockerCmd(c, "volume", "create", "--name", "test2") |
| 56 |
+ dockerCmd(c, "volume", "create", "--name", "not-shown") |
|
| 56 | 57 |
|
| 57 |
- out, _, err := dockerCmdWithError("volume", "inspect", "--format='{{ .Name }}'", "test1", "test2", "doesntexist")
|
|
| 58 |
+ out, _, err := dockerCmdWithError("volume", "inspect", "--format='{{ .Name }}'", "test1", "test2", "doesntexist", "not-shown")
|
|
| 58 | 59 |
c.Assert(err, checker.NotNil) |
| 59 | 60 |
outArr := strings.Split(strings.TrimSpace(out), "\n") |
| 60 | 61 |
c.Assert(len(outArr), check.Equals, 3, check.Commentf("\n%s", out))
|
| 61 | 62 |
|
| 62 |
- c.Assert(strings.Contains(out, "test1\n"), check.Equals, true) |
|
| 63 |
- c.Assert(strings.Contains(out, "test2\n"), check.Equals, true) |
|
| 64 |
- c.Assert(strings.Contains(out, "Error: No such volume: doesntexist\n"), check.Equals, true) |
|
| 63 |
+ c.Assert(out, checker.Contains, "test1") |
|
| 64 |
+ c.Assert(out, checker.Contains, "test2") |
|
| 65 |
+ c.Assert(out, checker.Contains, "Error: No such volume: doesntexist") |
|
| 66 |
+ c.Assert(out, checker.Not(checker.Contains), "not-shown") |
|
| 65 | 67 |
} |
| 66 | 68 |
|
| 67 | 69 |
func (s *DockerSuite) TestVolumeCliLs(c *check.C) {
|