inspect.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package client
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "net/url"
  8. "strings"
  9. "text/template"
  10. "github.com/docker/docker/api/types"
  11. Cli "github.com/docker/docker/cli"
  12. flag "github.com/docker/docker/pkg/mflag"
  13. )
  14. var funcMap = template.FuncMap{
  15. "json": func(v interface{}) string {
  16. a, _ := json.Marshal(v)
  17. return string(a)
  18. },
  19. }
  20. // CmdInspect displays low-level information on one or more containers or images.
  21. //
  22. // Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]
  23. func (cli *DockerCli) CmdInspect(args ...string) error {
  24. cmd := Cli.Subcmd("inspect", []string{"CONTAINER|IMAGE [CONTAINER|IMAGE...]"}, Cli.DockerCommands["inspect"].Description, true)
  25. tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template")
  26. inspectType := cmd.String([]string{"-type"}, "", "Return JSON for specified type, (e.g image or container)")
  27. size := cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes if the type is container")
  28. cmd.Require(flag.Min, 1)
  29. cmd.ParseFlags(args, true)
  30. var tmpl *template.Template
  31. var err error
  32. var obj []byte
  33. if *tmplStr != "" {
  34. if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
  35. return Cli.StatusError{StatusCode: 64,
  36. Status: "Template parsing error: " + err.Error()}
  37. }
  38. }
  39. if *inspectType != "" && *inspectType != "container" && *inspectType != "image" {
  40. return fmt.Errorf("%q is not a valid value for --type", *inspectType)
  41. }
  42. indented := new(bytes.Buffer)
  43. indented.WriteString("[\n")
  44. status := 0
  45. isImage := false
  46. v := url.Values{}
  47. if *size {
  48. v.Set("size", "1")
  49. }
  50. for _, name := range cmd.Args() {
  51. if *inspectType == "" || *inspectType == "container" {
  52. obj, _, err = readBody(cli.call("GET", "/containers/"+name+"/json?"+v.Encode(), nil, nil))
  53. if err != nil && *inspectType == "container" {
  54. if strings.Contains(err.Error(), "No such") {
  55. fmt.Fprintf(cli.err, "Error: No such container: %s\n", name)
  56. } else {
  57. fmt.Fprintf(cli.err, "%s", err)
  58. }
  59. status = 1
  60. continue
  61. }
  62. }
  63. if obj == nil && (*inspectType == "" || *inspectType == "image") {
  64. obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, nil))
  65. isImage = true
  66. if err != nil {
  67. if strings.Contains(err.Error(), "No such") {
  68. if *inspectType == "" {
  69. fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
  70. } else {
  71. fmt.Fprintf(cli.err, "Error: No such image: %s\n", name)
  72. }
  73. } else {
  74. fmt.Fprintf(cli.err, "%s", err)
  75. }
  76. status = 1
  77. continue
  78. }
  79. }
  80. if tmpl == nil {
  81. if err := json.Indent(indented, obj, "", " "); err != nil {
  82. fmt.Fprintf(cli.err, "%s\n", err)
  83. status = 1
  84. continue
  85. }
  86. } else {
  87. rdr := bytes.NewReader(obj)
  88. dec := json.NewDecoder(rdr)
  89. if isImage {
  90. inspPtr := types.ImageInspect{}
  91. if err := dec.Decode(&inspPtr); err != nil {
  92. fmt.Fprintf(cli.err, "%s\n", err)
  93. status = 1
  94. continue
  95. }
  96. if err := tmpl.Execute(cli.out, inspPtr); err != nil {
  97. rdr.Seek(0, 0)
  98. var raw interface{}
  99. if err := dec.Decode(&raw); err != nil {
  100. return err
  101. }
  102. if err = tmpl.Execute(cli.out, raw); err != nil {
  103. return err
  104. }
  105. }
  106. } else {
  107. inspPtr := types.ContainerJSON{}
  108. if err := dec.Decode(&inspPtr); err != nil {
  109. fmt.Fprintf(cli.err, "%s\n", err)
  110. status = 1
  111. continue
  112. }
  113. if err := tmpl.Execute(cli.out, inspPtr); err != nil {
  114. rdr.Seek(0, 0)
  115. var raw interface{}
  116. if err := dec.Decode(&raw); err != nil {
  117. return err
  118. }
  119. if err = tmpl.Execute(cli.out, raw); err != nil {
  120. return err
  121. }
  122. }
  123. }
  124. cli.out.Write([]byte{'\n'})
  125. }
  126. indented.WriteString(",")
  127. }
  128. if indented.Len() > 1 {
  129. // Remove trailing ','
  130. indented.Truncate(indented.Len() - 1)
  131. }
  132. indented.WriteString("]\n")
  133. if tmpl == nil {
  134. // Note that we will always write "[]" when "-f" isn't specified,
  135. // to make sure the output would always be array, see
  136. // https://github.com/docker/docker/pull/9500#issuecomment-65846734
  137. if _, err := io.Copy(cli.out, indented); err != nil {
  138. return err
  139. }
  140. }
  141. if status != 0 {
  142. return Cli.StatusError{StatusCode: status}
  143. }
  144. return nil
  145. }