inspect.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package system
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/cli"
  7. "github.com/docker/docker/cli/command"
  8. "github.com/docker/docker/cli/command/inspect"
  9. apiclient "github.com/docker/docker/client"
  10. "github.com/pkg/errors"
  11. "github.com/spf13/cobra"
  12. "golang.org/x/net/context"
  13. )
  14. type inspectOptions struct {
  15. format string
  16. inspectType string
  17. size bool
  18. ids []string
  19. }
  20. // NewInspectCommand creates a new cobra.Command for `docker inspect`
  21. func NewInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
  22. var opts inspectOptions
  23. cmd := &cobra.Command{
  24. Use: "inspect [OPTIONS] NAME|ID [NAME|ID...]",
  25. Short: "Return low-level information on Docker objects",
  26. Args: cli.RequiresMinArgs(1),
  27. RunE: func(cmd *cobra.Command, args []string) error {
  28. opts.ids = args
  29. return runInspect(dockerCli, opts)
  30. },
  31. }
  32. flags := cmd.Flags()
  33. flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
  34. flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type")
  35. flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes if the type is container")
  36. return cmd
  37. }
  38. func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
  39. var elementSearcher inspect.GetRefFunc
  40. switch opts.inspectType {
  41. case "", "container", "image", "node", "network", "service", "volume", "task", "plugin", "secret":
  42. elementSearcher = inspectAll(context.Background(), dockerCli, opts.size, opts.inspectType)
  43. default:
  44. return errors.Errorf("%q is not a valid value for --type", opts.inspectType)
  45. }
  46. return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher)
  47. }
  48. func inspectContainers(ctx context.Context, dockerCli *command.DockerCli, getSize bool) inspect.GetRefFunc {
  49. return func(ref string) (interface{}, []byte, error) {
  50. return dockerCli.Client().ContainerInspectWithRaw(ctx, ref, getSize)
  51. }
  52. }
  53. func inspectImages(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
  54. return func(ref string) (interface{}, []byte, error) {
  55. return dockerCli.Client().ImageInspectWithRaw(ctx, ref)
  56. }
  57. }
  58. func inspectNetwork(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
  59. return func(ref string) (interface{}, []byte, error) {
  60. return dockerCli.Client().NetworkInspectWithRaw(ctx, ref, false)
  61. }
  62. }
  63. func inspectNode(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
  64. return func(ref string) (interface{}, []byte, error) {
  65. return dockerCli.Client().NodeInspectWithRaw(ctx, ref)
  66. }
  67. }
  68. func inspectService(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
  69. return func(ref string) (interface{}, []byte, error) {
  70. // Service inspect shows defaults values in empty fields.
  71. return dockerCli.Client().ServiceInspectWithRaw(ctx, ref, types.ServiceInspectOptions{InsertDefaults: true})
  72. }
  73. }
  74. func inspectTasks(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
  75. return func(ref string) (interface{}, []byte, error) {
  76. return dockerCli.Client().TaskInspectWithRaw(ctx, ref)
  77. }
  78. }
  79. func inspectVolume(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
  80. return func(ref string) (interface{}, []byte, error) {
  81. return dockerCli.Client().VolumeInspectWithRaw(ctx, ref)
  82. }
  83. }
  84. func inspectPlugin(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
  85. return func(ref string) (interface{}, []byte, error) {
  86. return dockerCli.Client().PluginInspectWithRaw(ctx, ref)
  87. }
  88. }
  89. func inspectSecret(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
  90. return func(ref string) (interface{}, []byte, error) {
  91. return dockerCli.Client().SecretInspectWithRaw(ctx, ref)
  92. }
  93. }
  94. func inspectAll(ctx context.Context, dockerCli *command.DockerCli, getSize bool, typeConstraint string) inspect.GetRefFunc {
  95. var inspectAutodetect = []struct {
  96. objectType string
  97. isSizeSupported bool
  98. isSwarmObject bool
  99. objectInspector func(string) (interface{}, []byte, error)
  100. }{
  101. {
  102. objectType: "container",
  103. isSizeSupported: true,
  104. objectInspector: inspectContainers(ctx, dockerCli, getSize),
  105. },
  106. {
  107. objectType: "image",
  108. objectInspector: inspectImages(ctx, dockerCli),
  109. },
  110. {
  111. objectType: "network",
  112. objectInspector: inspectNetwork(ctx, dockerCli),
  113. },
  114. {
  115. objectType: "volume",
  116. objectInspector: inspectVolume(ctx, dockerCli),
  117. },
  118. {
  119. objectType: "service",
  120. isSwarmObject: true,
  121. objectInspector: inspectService(ctx, dockerCli),
  122. },
  123. {
  124. objectType: "task",
  125. isSwarmObject: true,
  126. objectInspector: inspectTasks(ctx, dockerCli),
  127. },
  128. {
  129. objectType: "node",
  130. isSwarmObject: true,
  131. objectInspector: inspectNode(ctx, dockerCli),
  132. },
  133. {
  134. objectType: "plugin",
  135. objectInspector: inspectPlugin(ctx, dockerCli),
  136. },
  137. {
  138. objectType: "secret",
  139. isSwarmObject: true,
  140. objectInspector: inspectSecret(ctx, dockerCli),
  141. },
  142. }
  143. // isSwarmManager does an Info API call to verify that the daemon is
  144. // a swarm manager.
  145. isSwarmManager := func() bool {
  146. info, err := dockerCli.Client().Info(ctx)
  147. if err != nil {
  148. fmt.Fprintln(dockerCli.Err(), err)
  149. return false
  150. }
  151. return info.Swarm.ControlAvailable
  152. }
  153. isErrNotSupported := func(err error) bool {
  154. return strings.Contains(err.Error(), "not supported")
  155. }
  156. return func(ref string) (interface{}, []byte, error) {
  157. const (
  158. swarmSupportUnknown = iota
  159. swarmSupported
  160. swarmUnsupported
  161. )
  162. isSwarmSupported := swarmSupportUnknown
  163. for _, inspectData := range inspectAutodetect {
  164. if typeConstraint != "" && inspectData.objectType != typeConstraint {
  165. continue
  166. }
  167. if typeConstraint == "" && inspectData.isSwarmObject {
  168. if isSwarmSupported == swarmSupportUnknown {
  169. if isSwarmManager() {
  170. isSwarmSupported = swarmSupported
  171. } else {
  172. isSwarmSupported = swarmUnsupported
  173. }
  174. }
  175. if isSwarmSupported == swarmUnsupported {
  176. continue
  177. }
  178. }
  179. v, raw, err := inspectData.objectInspector(ref)
  180. if err != nil {
  181. if typeConstraint == "" && (apiclient.IsErrNotFound(err) || isErrNotSupported(err)) {
  182. continue
  183. }
  184. return v, raw, err
  185. }
  186. if getSize && !inspectData.isSizeSupported {
  187. fmt.Fprintf(dockerCli.Err(), "WARNING: --size ignored for %s\n", inspectData.objectType)
  188. }
  189. return v, raw, err
  190. }
  191. return nil, nil, errors.Errorf("Error: No such object: %s", ref)
  192. }
  193. }