image.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. package image // import "github.com/docker/docker/image"
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io"
  6. "runtime"
  7. "strings"
  8. "time"
  9. "github.com/distribution/reference"
  10. "github.com/docker/docker/api/types/container"
  11. "github.com/docker/docker/dockerversion"
  12. "github.com/docker/docker/layer"
  13. "github.com/opencontainers/go-digest"
  14. ocispec "github.com/opencontainers/image-spec/specs-go/v1"
  15. )
  16. // ID is the content-addressable ID of an image.
  17. type ID digest.Digest
  18. func (id ID) String() string {
  19. return id.Digest().String()
  20. }
  21. // Digest converts ID into a digest
  22. func (id ID) Digest() digest.Digest {
  23. return digest.Digest(id)
  24. }
  25. // IDFromDigest creates an ID from a digest
  26. //
  27. // Deprecated: cast to an ID using ID(digest).
  28. func IDFromDigest(digest digest.Digest) ID {
  29. return ID(digest)
  30. }
  31. // V1Image stores the V1 image configuration.
  32. type V1Image struct {
  33. // ID is a unique 64 character identifier of the image
  34. ID string `json:"id,omitempty"`
  35. // Parent is the ID of the parent image.
  36. //
  37. // Depending on how the image was created, this field may be empty and
  38. // is only set for images that were built/created locally. This field
  39. // is empty if the image was pulled from an image registry.
  40. Parent string `json:"parent,omitempty"`
  41. // Comment is an optional message that can be set when committing or
  42. // importing the image.
  43. Comment string `json:"comment,omitempty"`
  44. // Created is the timestamp at which the image was created
  45. Created *time.Time `json:"created"`
  46. // Container is the ID of the container that was used to create the image.
  47. //
  48. // Depending on how the image was created, this field may be empty.
  49. Container string `json:"container,omitempty"`
  50. // ContainerConfig is the configuration of the container that was committed
  51. // into the image.
  52. ContainerConfig container.Config `json:"container_config,omitempty"`
  53. // DockerVersion is the version of Docker that was used to build the image.
  54. //
  55. // Depending on how the image was created, this field may be empty.
  56. DockerVersion string `json:"docker_version,omitempty"`
  57. // Author is the name of the author that was specified when committing the
  58. // image, or as specified through MAINTAINER (deprecated) in the Dockerfile.
  59. Author string `json:"author,omitempty"`
  60. // Config is the configuration of the container received from the client.
  61. Config *container.Config `json:"config,omitempty"`
  62. // Architecture is the hardware CPU architecture that the image runs on.
  63. Architecture string `json:"architecture,omitempty"`
  64. // Variant is the CPU architecture variant (presently ARM-only).
  65. Variant string `json:"variant,omitempty"`
  66. // OS is the Operating System the image is built to run on.
  67. OS string `json:"os,omitempty"`
  68. // Size is the total size of the image including all layers it is composed of.
  69. Size int64 `json:",omitempty"`
  70. }
  71. // Image stores the image configuration
  72. type Image struct {
  73. V1Image
  74. // Parent is the ID of the parent image.
  75. //
  76. // Depending on how the image was created, this field may be empty and
  77. // is only set for images that were built/created locally. This field
  78. // is empty if the image was pulled from an image registry.
  79. Parent ID `json:"parent,omitempty"` //nolint:govet
  80. // RootFS contains information about the image's RootFS, including the
  81. // layer IDs.
  82. RootFS *RootFS `json:"rootfs,omitempty"`
  83. History []History `json:"history,omitempty"`
  84. // OsVersion is the version of the Operating System the image is built to
  85. // run on (especially for Windows).
  86. OSVersion string `json:"os.version,omitempty"`
  87. OSFeatures []string `json:"os.features,omitempty"`
  88. // rawJSON caches the immutable JSON associated with this image.
  89. rawJSON []byte
  90. // computedID is the ID computed from the hash of the image config.
  91. // Not to be confused with the legacy V1 ID in V1Image.
  92. computedID ID
  93. // Details holds additional details about image
  94. Details *Details `json:"-"`
  95. }
  96. // Details provides additional image data
  97. type Details struct {
  98. References []reference.Named
  99. Size int64
  100. Metadata map[string]string
  101. Driver string
  102. LastUpdated time.Time
  103. }
  104. // RawJSON returns the immutable JSON associated with the image.
  105. func (img *Image) RawJSON() []byte {
  106. return img.rawJSON
  107. }
  108. // ID returns the image's content-addressable ID.
  109. func (img *Image) ID() ID {
  110. return img.computedID
  111. }
  112. // ImageID stringifies ID.
  113. func (img *Image) ImageID() string {
  114. return img.ID().String()
  115. }
  116. // RunConfig returns the image's container config.
  117. func (img *Image) RunConfig() *container.Config {
  118. return img.Config
  119. }
  120. // BaseImgArch returns the image's architecture. If not populated, defaults to the host runtime arch.
  121. func (img *Image) BaseImgArch() string {
  122. arch := img.Architecture
  123. if arch == "" {
  124. arch = runtime.GOARCH
  125. }
  126. return arch
  127. }
  128. // BaseImgVariant returns the image's variant, whether populated or not.
  129. // This avoids creating an inconsistency where the stored image variant
  130. // is "greater than" (i.e. v8 vs v6) the actual image variant.
  131. func (img *Image) BaseImgVariant() string {
  132. return img.Variant
  133. }
  134. // OperatingSystem returns the image's operating system. If not populated, defaults to the host runtime OS.
  135. func (img *Image) OperatingSystem() string {
  136. os := img.OS
  137. if os == "" {
  138. os = runtime.GOOS
  139. }
  140. return os
  141. }
  142. // Platform generates an OCI platform from the image
  143. func (img *Image) Platform() ocispec.Platform {
  144. return ocispec.Platform{
  145. Architecture: img.Architecture,
  146. OS: img.OS,
  147. OSVersion: img.OSVersion,
  148. OSFeatures: img.OSFeatures,
  149. Variant: img.Variant,
  150. }
  151. }
  152. // MarshalJSON serializes the image to JSON. It sorts the top-level keys so
  153. // that JSON that's been manipulated by a push/pull cycle with a legacy
  154. // registry won't end up with a different key order.
  155. func (img *Image) MarshalJSON() ([]byte, error) {
  156. type MarshalImage Image
  157. pass1, err := json.Marshal(MarshalImage(*img))
  158. if err != nil {
  159. return nil, err
  160. }
  161. var c map[string]*json.RawMessage
  162. if err := json.Unmarshal(pass1, &c); err != nil {
  163. return nil, err
  164. }
  165. return json.Marshal(c)
  166. }
  167. // ChildConfig is the configuration to apply to an Image to create a new
  168. // Child image. Other properties of the image are copied from the parent.
  169. type ChildConfig struct {
  170. ContainerID string
  171. Author string
  172. Comment string
  173. DiffID layer.DiffID
  174. ContainerConfig *container.Config
  175. Config *container.Config
  176. }
  177. // NewImage creates a new image with the given ID
  178. func NewImage(id ID) *Image {
  179. return &Image{
  180. computedID: id,
  181. }
  182. }
  183. // NewChildImage creates a new Image as a child of this image.
  184. func NewChildImage(img *Image, child ChildConfig, os string) *Image {
  185. isEmptyLayer := layer.IsEmpty(child.DiffID)
  186. var rootFS *RootFS
  187. if img.RootFS != nil {
  188. rootFS = img.RootFS.Clone()
  189. } else {
  190. rootFS = NewRootFS()
  191. }
  192. if !isEmptyLayer {
  193. rootFS.Append(child.DiffID)
  194. }
  195. imgHistory := NewHistory(
  196. child.Author,
  197. child.Comment,
  198. strings.Join(child.ContainerConfig.Cmd, " "),
  199. isEmptyLayer)
  200. return &Image{
  201. V1Image: V1Image{
  202. DockerVersion: dockerversion.Version,
  203. Config: child.Config,
  204. Architecture: img.BaseImgArch(),
  205. Variant: img.BaseImgVariant(),
  206. OS: os,
  207. Container: child.ContainerID,
  208. ContainerConfig: *child.ContainerConfig,
  209. Author: child.Author,
  210. Created: imgHistory.Created,
  211. },
  212. RootFS: rootFS,
  213. History: append(img.History, imgHistory),
  214. OSFeatures: img.OSFeatures,
  215. OSVersion: img.OSVersion,
  216. }
  217. }
  218. // Clone clones an image and changes ID.
  219. func Clone(base *Image, id ID) *Image {
  220. img := *base
  221. img.RootFS = img.RootFS.Clone()
  222. img.V1Image.ID = id.String()
  223. img.computedID = id
  224. return &img
  225. }
  226. // History stores build commands that were used to create an image
  227. type History = ocispec.History
  228. // NewHistory creates a new history struct from arguments, and sets the created
  229. // time to the current time in UTC
  230. func NewHistory(author, comment, createdBy string, isEmptyLayer bool) History {
  231. now := time.Now().UTC()
  232. return History{
  233. Author: author,
  234. Created: &now,
  235. CreatedBy: createdBy,
  236. Comment: comment,
  237. EmptyLayer: isEmptyLayer,
  238. }
  239. }
  240. // Exporter provides interface for loading and saving images
  241. type Exporter interface {
  242. Load(io.ReadCloser, io.Writer, bool) error
  243. // TODO: Load(net.Context, io.ReadCloser, <- chan StatusMessage) error
  244. Save([]string, io.Writer) error
  245. }
  246. // NewFromJSON creates an Image configuration from json.
  247. func NewFromJSON(src []byte) (*Image, error) {
  248. img := &Image{}
  249. if err := json.Unmarshal(src, img); err != nil {
  250. return nil, err
  251. }
  252. if img.RootFS == nil {
  253. return nil, errors.New("invalid image JSON, no RootFS key")
  254. }
  255. img.rawJSON = src
  256. return img, nil
  257. }