service.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package graph
  2. import (
  3. "fmt"
  4. "io"
  5. log "github.com/Sirupsen/logrus"
  6. "github.com/docker/docker/engine"
  7. "github.com/docker/docker/image"
  8. )
  9. func (s *TagStore) Install(eng *engine.Engine) error {
  10. for name, handler := range map[string]engine.Handler{
  11. "image_set": s.CmdSet,
  12. "image_tag": s.CmdTag,
  13. "tag": s.CmdTagLegacy, // FIXME merge with "image_tag"
  14. "image_get": s.CmdGet,
  15. "image_inspect": s.CmdLookup,
  16. "image_tarlayer": s.CmdTarLayer,
  17. "image_export": s.CmdImageExport,
  18. "history": s.CmdHistory,
  19. "images": s.CmdImages,
  20. "viz": s.CmdViz,
  21. "load": s.CmdLoad,
  22. "import": s.CmdImport,
  23. "pull": s.CmdPull,
  24. "push": s.CmdPush,
  25. } {
  26. if err := eng.Register(name, handler); err != nil {
  27. return fmt.Errorf("Could not register %q: %v", name, err)
  28. }
  29. }
  30. return nil
  31. }
  32. // CmdSet stores a new image in the graph.
  33. // Images are stored in the graph using 4 elements:
  34. // - A user-defined ID
  35. // - A collection of metadata describing the image
  36. // - A directory tree stored as a tar archive (also called the "layer")
  37. // - A reference to a "parent" ID on top of which the layer should be applied
  38. //
  39. // NOTE: even though the parent ID is only useful in relation to the layer and how
  40. // to apply it (ie you could represent the full directory tree as 'parent_layer + layer',
  41. // it is treated as a top-level property of the image. This is an artifact of early
  42. // design and should probably be cleaned up in the future to simplify the design.
  43. //
  44. // Syntax: image_set ID
  45. // Input:
  46. // - Layer content must be streamed in tar format on stdin. An empty input is
  47. // valid and represents a nil layer.
  48. //
  49. // - Image metadata must be passed in the command environment.
  50. // 'json': a json-encoded object with all image metadata.
  51. // It will be stored as-is, without any encoding/decoding artifacts.
  52. // That is a requirement of the current registry client implementation,
  53. // because a re-encoded json might invalidate the image checksum at
  54. // the next upload, even with functionaly identical content.
  55. func (s *TagStore) CmdSet(job *engine.Job) engine.Status {
  56. if len(job.Args) != 1 {
  57. return job.Errorf("usage: %s NAME", job.Name)
  58. }
  59. var (
  60. imgJSON = []byte(job.Getenv("json"))
  61. layer = job.Stdin
  62. )
  63. if len(imgJSON) == 0 {
  64. return job.Errorf("mandatory key 'json' is not set")
  65. }
  66. // We have to pass an *image.Image object, even though it will be completely
  67. // ignored in favor of the redundant json data.
  68. // FIXME: the current prototype of Graph.Register is stupid and redundant.
  69. img, err := image.NewImgJSON(imgJSON)
  70. if err != nil {
  71. return job.Error(err)
  72. }
  73. if err := s.graph.Register(img, layer); err != nil {
  74. return job.Error(err)
  75. }
  76. return engine.StatusOK
  77. }
  78. // CmdGet returns information about an image.
  79. // If the image doesn't exist, an empty object is returned, to allow
  80. // checking for an image's existence.
  81. func (s *TagStore) CmdGet(job *engine.Job) engine.Status {
  82. if len(job.Args) != 1 {
  83. return job.Errorf("usage: %s NAME", job.Name)
  84. }
  85. name := job.Args[0]
  86. res := &engine.Env{}
  87. img, err := s.LookupImage(name)
  88. // Note: if the image doesn't exist, LookupImage returns
  89. // nil, nil.
  90. if err != nil {
  91. return job.Error(err)
  92. }
  93. if img != nil {
  94. // We don't directly expose all fields of the Image objects,
  95. // to maintain a clean public API which we can maintain over
  96. // time even if the underlying structure changes.
  97. // We should have done this with the Image object to begin with...
  98. // but we didn't, so now we're doing it here.
  99. //
  100. // Fields that we're probably better off not including:
  101. // - Config/ContainerConfig. Those structs have the same sprawl problem,
  102. // so we shouldn't include them wholesale either.
  103. // - Comment: initially created to fulfill the "every image is a git commit"
  104. // metaphor, in practice people either ignore it or use it as a
  105. // generic description field which it isn't. On deprecation shortlist.
  106. res.SetAuto("Created", img.Created)
  107. res.SetJson("Author", img.Author)
  108. res.Set("Os", img.OS)
  109. res.Set("Architecture", img.Architecture)
  110. res.Set("DockerVersion", img.DockerVersion)
  111. res.SetJson("Id", img.ID)
  112. res.SetJson("Parent", img.Parent)
  113. }
  114. res.WriteTo(job.Stdout)
  115. return engine.StatusOK
  116. }
  117. // CmdLookup return an image encoded in JSON
  118. func (s *TagStore) CmdLookup(job *engine.Job) engine.Status {
  119. if len(job.Args) != 1 {
  120. return job.Errorf("usage: %s NAME", job.Name)
  121. }
  122. name := job.Args[0]
  123. if image, err := s.LookupImage(name); err == nil && image != nil {
  124. if job.GetenvBool("raw") {
  125. b, err := image.RawJson()
  126. if err != nil {
  127. return job.Error(err)
  128. }
  129. job.Stdout.Write(b)
  130. return engine.StatusOK
  131. }
  132. out := &engine.Env{}
  133. out.SetJson("Id", image.ID)
  134. out.SetJson("Parent", image.Parent)
  135. out.SetJson("Comment", image.Comment)
  136. out.SetAuto("Created", image.Created)
  137. out.SetJson("Container", image.Container)
  138. out.SetJson("ContainerConfig", image.ContainerConfig)
  139. out.Set("DockerVersion", image.DockerVersion)
  140. out.SetJson("Author", image.Author)
  141. out.SetJson("Config", image.Config)
  142. out.Set("Architecture", image.Architecture)
  143. out.Set("Os", image.OS)
  144. out.SetInt64("Size", image.Size)
  145. out.SetInt64("VirtualSize", image.GetParentsSize(0)+image.Size)
  146. out.Set("Checksum", image.Checksum)
  147. if _, err = out.WriteTo(job.Stdout); err != nil {
  148. return job.Error(err)
  149. }
  150. return engine.StatusOK
  151. }
  152. return job.Errorf("No such image: %s", name)
  153. }
  154. // CmdTarLayer return the tarLayer of the image
  155. func (s *TagStore) CmdTarLayer(job *engine.Job) engine.Status {
  156. if len(job.Args) != 1 {
  157. return job.Errorf("usage: %s NAME", job.Name)
  158. }
  159. name := job.Args[0]
  160. if image, err := s.LookupImage(name); err == nil && image != nil {
  161. fs, err := image.TarLayer()
  162. if err != nil {
  163. return job.Error(err)
  164. }
  165. defer fs.Close()
  166. written, err := io.Copy(job.Stdout, fs)
  167. if err != nil {
  168. return job.Error(err)
  169. }
  170. log.Debugf("rendered layer for %s of [%d] size", image.ID, written)
  171. return engine.StatusOK
  172. }
  173. return job.Errorf("No such image: %s", name)
  174. }