github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/image/image.go (about)

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