image.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. package image
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io"
  6. "runtime"
  7. "strings"
  8. "time"
  9. "github.com/docker/docker/api/types/container"
  10. "github.com/docker/docker/dockerversion"
  11. "github.com/docker/docker/layer"
  12. "github.com/opencontainers/go-digest"
  13. )
  14. // ID is the content-addressable ID of an image.
  15. type ID digest.Digest
  16. func (id ID) String() string {
  17. return id.Digest().String()
  18. }
  19. // Digest converts ID into a digest
  20. func (id ID) Digest() digest.Digest {
  21. return digest.Digest(id)
  22. }
  23. // IDFromDigest creates an ID from a digest
  24. func IDFromDigest(digest digest.Digest) ID {
  25. return ID(digest)
  26. }
  27. // V1Image stores the V1 image configuration.
  28. type V1Image struct {
  29. // ID is a unique 64 character identifier of the image
  30. ID string `json:"id,omitempty"`
  31. // Parent is the ID of the parent image
  32. Parent string `json:"parent,omitempty"`
  33. // Comment is the commit message that was set when committing the image
  34. Comment string `json:"comment,omitempty"`
  35. // Created is the timestamp at which the image was created
  36. Created time.Time `json:"created"`
  37. // Container is the id of the container used to commit
  38. Container string `json:"container,omitempty"`
  39. // ContainerConfig is the configuration of the container that is committed into the image
  40. ContainerConfig container.Config `json:"container_config,omitempty"`
  41. // DockerVersion specifies the version of Docker that was used to build the image
  42. DockerVersion string `json:"docker_version,omitempty"`
  43. // Author is the name of the author that was specified when committing the image
  44. Author string `json:"author,omitempty"`
  45. // Config is the configuration of the container received from the client
  46. Config *container.Config `json:"config,omitempty"`
  47. // Architecture is the hardware that the image is built and runs on
  48. Architecture string `json:"architecture,omitempty"`
  49. // OS is the operating system used to build and run the image
  50. OS string `json:"os,omitempty"`
  51. // Size is the total size of the image including all layers it is composed of
  52. Size int64 `json:",omitempty"`
  53. }
  54. // Image stores the image configuration
  55. type Image struct {
  56. V1Image
  57. Parent ID `json:"parent,omitempty"`
  58. RootFS *RootFS `json:"rootfs,omitempty"`
  59. History []History `json:"history,omitempty"`
  60. OSVersion string `json:"os.version,omitempty"`
  61. OSFeatures []string `json:"os.features,omitempty"`
  62. // rawJSON caches the immutable JSON associated with this image.
  63. rawJSON []byte
  64. // computedID is the ID computed from the hash of the image config.
  65. // Not to be confused with the legacy V1 ID in V1Image.
  66. computedID ID
  67. }
  68. // RawJSON returns the immutable JSON associated with the image.
  69. func (img *Image) RawJSON() []byte {
  70. return img.rawJSON
  71. }
  72. // ID returns the image's content-addressable ID.
  73. func (img *Image) ID() ID {
  74. return img.computedID
  75. }
  76. // ImageID stringifies ID.
  77. func (img *Image) ImageID() string {
  78. return img.ID().String()
  79. }
  80. // RunConfig returns the image's container config.
  81. func (img *Image) RunConfig() *container.Config {
  82. return img.Config
  83. }
  84. // OperatingSystem returns the image's operating system. If not populated, defaults to the host runtime OS.
  85. func (img *Image) OperatingSystem() string {
  86. os := img.OS
  87. if os == "" {
  88. os = runtime.GOOS
  89. }
  90. return os
  91. }
  92. // MarshalJSON serializes the image to JSON. It sorts the top-level keys so
  93. // that JSON that's been manipulated by a push/pull cycle with a legacy
  94. // registry won't end up with a different key order.
  95. func (img *Image) MarshalJSON() ([]byte, error) {
  96. type MarshalImage Image
  97. pass1, err := json.Marshal(MarshalImage(*img))
  98. if err != nil {
  99. return nil, err
  100. }
  101. var c map[string]*json.RawMessage
  102. if err := json.Unmarshal(pass1, &c); err != nil {
  103. return nil, err
  104. }
  105. return json.Marshal(c)
  106. }
  107. // ChildConfig is the configuration to apply to an Image to create a new
  108. // Child image. Other properties of the image are copied from the parent.
  109. type ChildConfig struct {
  110. ContainerID string
  111. Author string
  112. Comment string
  113. DiffID layer.DiffID
  114. ContainerConfig *container.Config
  115. Config *container.Config
  116. }
  117. // NewChildImage creates a new Image as a child of this image.
  118. func NewChildImage(img *Image, child ChildConfig, platform string) *Image {
  119. isEmptyLayer := layer.IsEmpty(child.DiffID)
  120. var rootFS *RootFS
  121. if img.RootFS != nil {
  122. rootFS = img.RootFS.Clone()
  123. } else {
  124. rootFS = NewRootFS()
  125. }
  126. if !isEmptyLayer {
  127. rootFS.Append(child.DiffID)
  128. }
  129. imgHistory := NewHistory(
  130. child.Author,
  131. child.Comment,
  132. strings.Join(child.ContainerConfig.Cmd, " "),
  133. isEmptyLayer)
  134. return &Image{
  135. V1Image: V1Image{
  136. DockerVersion: dockerversion.Version,
  137. Config: child.Config,
  138. Architecture: runtime.GOARCH,
  139. OS: platform,
  140. Container: child.ContainerID,
  141. ContainerConfig: *child.ContainerConfig,
  142. Author: child.Author,
  143. Created: imgHistory.Created,
  144. },
  145. RootFS: rootFS,
  146. History: append(img.History, imgHistory),
  147. OSFeatures: img.OSFeatures,
  148. OSVersion: img.OSVersion,
  149. }
  150. }
  151. // History stores build commands that were used to create an image
  152. type History struct {
  153. // Created is the timestamp at which the image was created
  154. Created time.Time `json:"created"`
  155. // Author is the name of the author that was specified when committing the image
  156. Author string `json:"author,omitempty"`
  157. // CreatedBy keeps the Dockerfile command used while building the image
  158. CreatedBy string `json:"created_by,omitempty"`
  159. // Comment is the commit message that was set when committing the image
  160. Comment string `json:"comment,omitempty"`
  161. // EmptyLayer is set to true if this history item did not generate a
  162. // layer. Otherwise, the history item is associated with the next
  163. // layer in the RootFS section.
  164. EmptyLayer bool `json:"empty_layer,omitempty"`
  165. }
  166. // NewHistory creates a new history struct from arguments, and sets the created
  167. // time to the current time in UTC
  168. func NewHistory(author, comment, createdBy string, isEmptyLayer bool) History {
  169. return History{
  170. Author: author,
  171. Created: time.Now().UTC(),
  172. CreatedBy: createdBy,
  173. Comment: comment,
  174. EmptyLayer: isEmptyLayer,
  175. }
  176. }
  177. // Exporter provides interface for loading and saving images
  178. type Exporter interface {
  179. Load(io.ReadCloser, io.Writer, bool) error
  180. // TODO: Load(net.Context, io.ReadCloser, <- chan StatusMessage) error
  181. Save([]string, io.Writer) error
  182. }
  183. // NewFromJSON creates an Image configuration from json.
  184. func NewFromJSON(src []byte) (*Image, error) {
  185. img := &Image{}
  186. if err := json.Unmarshal(src, img); err != nil {
  187. return nil, err
  188. }
  189. if img.RootFS == nil {
  190. return nil, errors.New("invalid image JSON, no RootFS key")
  191. }
  192. img.rawJSON = src
  193. return img, nil
  194. }