123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- package image // import "github.com/docker/docker/image"
- import (
- "encoding/json"
- "errors"
- "io"
- "runtime"
- "strings"
- "time"
- "github.com/distribution/reference"
- "github.com/docker/docker/api/types/container"
- "github.com/docker/docker/dockerversion"
- "github.com/docker/docker/layer"
- "github.com/opencontainers/go-digest"
- ocispec "github.com/opencontainers/image-spec/specs-go/v1"
- )
- // ID is the content-addressable ID of an image.
- type ID digest.Digest
- func (id ID) String() string {
- return id.Digest().String()
- }
- // Digest converts ID into a digest
- func (id ID) Digest() digest.Digest {
- return digest.Digest(id)
- }
- // IDFromDigest creates an ID from a digest
- //
- // Deprecated: cast to an ID using ID(digest).
- func IDFromDigest(digest digest.Digest) ID {
- return ID(digest)
- }
- // V1Image stores the V1 image configuration.
- type V1Image struct {
- // ID is a unique 64 character identifier of the image
- ID string `json:"id,omitempty"`
- // Parent is the ID of the parent image.
- //
- // Depending on how the image was created, this field may be empty and
- // is only set for images that were built/created locally. This field
- // is empty if the image was pulled from an image registry.
- Parent string `json:"parent,omitempty"`
- // Comment is an optional message that can be set when committing or
- // importing the image.
- Comment string `json:"comment,omitempty"`
- // Created is the timestamp at which the image was created
- Created *time.Time `json:"created"`
- // Container is the ID of the container that was used to create the image.
- //
- // Depending on how the image was created, this field may be empty.
- Container string `json:"container,omitempty"`
- // ContainerConfig is the configuration of the container that was committed
- // into the image.
- ContainerConfig container.Config `json:"container_config,omitempty"`
- // DockerVersion is the version of Docker that was used to build the image.
- //
- // Depending on how the image was created, this field may be empty.
- DockerVersion string `json:"docker_version,omitempty"`
- // Author is the name of the author that was specified when committing the
- // image, or as specified through MAINTAINER (deprecated) in the Dockerfile.
- Author string `json:"author,omitempty"`
- // Config is the configuration of the container received from the client.
- Config *container.Config `json:"config,omitempty"`
- // Architecture is the hardware CPU architecture that the image runs on.
- Architecture string `json:"architecture,omitempty"`
- // Variant is the CPU architecture variant (presently ARM-only).
- Variant string `json:"variant,omitempty"`
- // OS is the Operating System the image is built to run on.
- OS string `json:"os,omitempty"`
- // Size is the total size of the image including all layers it is composed of.
- Size int64 `json:",omitempty"`
- }
- // Image stores the image configuration
- type Image struct {
- V1Image
- // Parent is the ID of the parent image.
- //
- // Depending on how the image was created, this field may be empty and
- // is only set for images that were built/created locally. This field
- // is empty if the image was pulled from an image registry.
- Parent ID `json:"parent,omitempty"` //nolint:govet
- // RootFS contains information about the image's RootFS, including the
- // layer IDs.
- RootFS *RootFS `json:"rootfs,omitempty"`
- History []History `json:"history,omitempty"`
- // OsVersion is the version of the Operating System the image is built to
- // run on (especially for Windows).
- OSVersion string `json:"os.version,omitempty"`
- OSFeatures []string `json:"os.features,omitempty"`
- // rawJSON caches the immutable JSON associated with this image.
- rawJSON []byte
- // computedID is the ID computed from the hash of the image config.
- // Not to be confused with the legacy V1 ID in V1Image.
- computedID ID
- // Details holds additional details about image
- Details *Details `json:"-"`
- }
- // Details provides additional image data
- type Details struct {
- References []reference.Named
- Size int64
- Metadata map[string]string
- Driver string
- LastUpdated time.Time
- }
- // RawJSON returns the immutable JSON associated with the image.
- func (img *Image) RawJSON() []byte {
- return img.rawJSON
- }
- // ID returns the image's content-addressable ID.
- func (img *Image) ID() ID {
- return img.computedID
- }
- // ImageID stringifies ID.
- func (img *Image) ImageID() string {
- return img.ID().String()
- }
- // RunConfig returns the image's container config.
- func (img *Image) RunConfig() *container.Config {
- return img.Config
- }
- // BaseImgArch returns the image's architecture. If not populated, defaults to the host runtime arch.
- func (img *Image) BaseImgArch() string {
- arch := img.Architecture
- if arch == "" {
- arch = runtime.GOARCH
- }
- return arch
- }
- // BaseImgVariant returns the image's variant, whether populated or not.
- // This avoids creating an inconsistency where the stored image variant
- // is "greater than" (i.e. v8 vs v6) the actual image variant.
- func (img *Image) BaseImgVariant() string {
- return img.Variant
- }
- // OperatingSystem returns the image's operating system. If not populated, defaults to the host runtime OS.
- func (img *Image) OperatingSystem() string {
- os := img.OS
- if os == "" {
- os = runtime.GOOS
- }
- return os
- }
- // Platform generates an OCI platform from the image
- func (img *Image) Platform() ocispec.Platform {
- return ocispec.Platform{
- Architecture: img.Architecture,
- OS: img.OS,
- OSVersion: img.OSVersion,
- OSFeatures: img.OSFeatures,
- Variant: img.Variant,
- }
- }
- // MarshalJSON serializes the image to JSON. It sorts the top-level keys so
- // that JSON that's been manipulated by a push/pull cycle with a legacy
- // registry won't end up with a different key order.
- func (img *Image) MarshalJSON() ([]byte, error) {
- type MarshalImage Image
- pass1, err := json.Marshal(MarshalImage(*img))
- if err != nil {
- return nil, err
- }
- var c map[string]*json.RawMessage
- if err := json.Unmarshal(pass1, &c); err != nil {
- return nil, err
- }
- return json.Marshal(c)
- }
- // ChildConfig is the configuration to apply to an Image to create a new
- // Child image. Other properties of the image are copied from the parent.
- type ChildConfig struct {
- ContainerID string
- Author string
- Comment string
- DiffID layer.DiffID
- ContainerConfig *container.Config
- Config *container.Config
- }
- // NewImage creates a new image with the given ID
- func NewImage(id ID) *Image {
- return &Image{
- computedID: id,
- }
- }
- // NewChildImage creates a new Image as a child of this image.
- func NewChildImage(img *Image, child ChildConfig, os string) *Image {
- isEmptyLayer := layer.IsEmpty(child.DiffID)
- var rootFS *RootFS
- if img.RootFS != nil {
- rootFS = img.RootFS.Clone()
- } else {
- rootFS = NewRootFS()
- }
- if !isEmptyLayer {
- rootFS.Append(child.DiffID)
- }
- imgHistory := NewHistory(
- child.Author,
- child.Comment,
- strings.Join(child.ContainerConfig.Cmd, " "),
- isEmptyLayer)
- return &Image{
- V1Image: V1Image{
- DockerVersion: dockerversion.Version,
- Config: child.Config,
- Architecture: img.BaseImgArch(),
- Variant: img.BaseImgVariant(),
- OS: os,
- Container: child.ContainerID,
- ContainerConfig: *child.ContainerConfig,
- Author: child.Author,
- Created: imgHistory.Created,
- },
- RootFS: rootFS,
- History: append(img.History, imgHistory),
- OSFeatures: img.OSFeatures,
- OSVersion: img.OSVersion,
- }
- }
- // Clone clones an image and changes ID.
- func Clone(base *Image, id ID) *Image {
- img := *base
- img.RootFS = img.RootFS.Clone()
- img.V1Image.ID = id.String()
- img.computedID = id
- return &img
- }
- // History stores build commands that were used to create an image
- type History = ocispec.History
- // NewHistory creates a new history struct from arguments, and sets the created
- // time to the current time in UTC
- func NewHistory(author, comment, createdBy string, isEmptyLayer bool) History {
- now := time.Now().UTC()
- return History{
- Author: author,
- Created: &now,
- CreatedBy: createdBy,
- Comment: comment,
- EmptyLayer: isEmptyLayer,
- }
- }
- // Exporter provides interface for loading and saving images
- type Exporter interface {
- Load(io.ReadCloser, io.Writer, bool) error
- // TODO: Load(net.Context, io.ReadCloser, <- chan StatusMessage) error
- Save([]string, io.Writer) error
- }
- // NewFromJSON creates an Image configuration from json.
- func NewFromJSON(src []byte) (*Image, error) {
- img := &Image{}
- if err := json.Unmarshal(src, img); err != nil {
- return nil, err
- }
- if img.RootFS == nil {
- return nil, errors.New("invalid image JSON, no RootFS key")
- }
- img.rawJSON = src
- return img, nil
- }
|