github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/image/image.go (about)

     1  package 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  	"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  	// OS is the operating system used to build and run the image
    57  	OS string `json:"os,omitempty"`
    58  	// Size is the total size of the image including all layers it is composed of
    59  	Size int64 `json:",omitempty"`
    60  }
    61  
    62  // Image stores the image configuration
    63  type Image struct {
    64  	V1Image
    65  	Parent     ID        `json:"parent,omitempty"`
    66  	RootFS     *RootFS   `json:"rootfs,omitempty"`
    67  	History    []History `json:"history,omitempty"`
    68  	OSVersion  string    `json:"os.version,omitempty"`
    69  	OSFeatures []string  `json:"os.features,omitempty"`
    70  
    71  	// rawJSON caches the immutable JSON associated with this image.
    72  	rawJSON []byte
    73  
    74  	// computedID is the ID computed from the hash of the image config.
    75  	// Not to be confused with the legacy V1 ID in V1Image.
    76  	computedID ID
    77  }
    78  
    79  // RawJSON returns the immutable JSON associated with the image.
    80  func (img *Image) RawJSON() []byte {
    81  	return img.rawJSON
    82  }
    83  
    84  // ID returns the image's content-addressable ID.
    85  func (img *Image) ID() ID {
    86  	return img.computedID
    87  }
    88  
    89  // ImageID stringifies ID.
    90  func (img *Image) ImageID() string {
    91  	return img.ID().String()
    92  }
    93  
    94  // RunConfig returns the image's container config.
    95  func (img *Image) RunConfig() *container.Config {
    96  	return img.Config
    97  }
    98  
    99  // OperatingSystem returns the image's operating system. If not populated, defaults to the host runtime OS.
   100  func (img *Image) OperatingSystem() string {
   101  	os := img.OS
   102  	if os == "" {
   103  		os = runtime.GOOS
   104  	}
   105  	return os
   106  }
   107  
   108  // MarshalJSON serializes the image to JSON. It sorts the top-level keys so
   109  // that JSON that's been manipulated by a push/pull cycle with a legacy
   110  // registry won't end up with a different key order.
   111  func (img *Image) MarshalJSON() ([]byte, error) {
   112  	type MarshalImage Image
   113  
   114  	pass1, err := json.Marshal(MarshalImage(*img))
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	var c map[string]*json.RawMessage
   120  	if err := json.Unmarshal(pass1, &c); err != nil {
   121  		return nil, err
   122  	}
   123  	return json.Marshal(c)
   124  }
   125  
   126  // ChildConfig is the configuration to apply to an Image to create a new
   127  // Child image. Other properties of the image are copied from the parent.
   128  type ChildConfig struct {
   129  	ContainerID     string
   130  	Author          string
   131  	Comment         string
   132  	DiffID          layer.DiffID
   133  	ContainerConfig *container.Config
   134  	Config          *container.Config
   135  }
   136  
   137  // NewChildImage creates a new Image as a child of this image.
   138  func NewChildImage(img *Image, child ChildConfig, platform string) *Image {
   139  	isEmptyLayer := layer.IsEmpty(child.DiffID)
   140  	var rootFS *RootFS
   141  	if img.RootFS != nil {
   142  		rootFS = img.RootFS.Clone()
   143  	} else {
   144  		rootFS = NewRootFS()
   145  	}
   146  
   147  	if !isEmptyLayer {
   148  		rootFS.Append(child.DiffID)
   149  	}
   150  	imgHistory := NewHistory(
   151  		child.Author,
   152  		child.Comment,
   153  		strings.Join(child.ContainerConfig.Cmd, " "),
   154  		isEmptyLayer)
   155  
   156  	return &Image{
   157  		V1Image: V1Image{
   158  			DockerVersion:   dockerversion.Version,
   159  			Config:          child.Config,
   160  			Architecture:    runtime.GOARCH,
   161  			OS:              platform,
   162  			Container:       child.ContainerID,
   163  			ContainerConfig: *child.ContainerConfig,
   164  			Author:          child.Author,
   165  			Created:         imgHistory.Created,
   166  		},
   167  		RootFS:     rootFS,
   168  		History:    append(img.History, imgHistory),
   169  		OSFeatures: img.OSFeatures,
   170  		OSVersion:  img.OSVersion,
   171  	}
   172  }
   173  
   174  // History stores build commands that were used to create an image
   175  type History struct {
   176  	// Created is the timestamp at which the image was created
   177  	Created time.Time `json:"created"`
   178  	// Author is the name of the author that was specified when committing the image
   179  	Author string `json:"author,omitempty"`
   180  	// CreatedBy keeps the Dockerfile command used while building the image
   181  	CreatedBy string `json:"created_by,omitempty"`
   182  	// Comment is the commit message that was set when committing the image
   183  	Comment string `json:"comment,omitempty"`
   184  	// EmptyLayer is set to true if this history item did not generate a
   185  	// layer. Otherwise, the history item is associated with the next
   186  	// layer in the RootFS section.
   187  	EmptyLayer bool `json:"empty_layer,omitempty"`
   188  }
   189  
   190  // NewHistory creates a new history struct from arguments, and sets the created
   191  // time to the current time in UTC
   192  func NewHistory(author, comment, createdBy string, isEmptyLayer bool) History {
   193  	return History{
   194  		Author:     author,
   195  		Created:    time.Now().UTC(),
   196  		CreatedBy:  createdBy,
   197  		Comment:    comment,
   198  		EmptyLayer: isEmptyLayer,
   199  	}
   200  }
   201  
   202  // Exporter provides interface for loading and saving images
   203  type Exporter interface {
   204  	Load(io.ReadCloser, io.Writer, bool) error
   205  	// TODO: Load(net.Context, io.ReadCloser, <- chan StatusMessage) error
   206  	Save([]string, io.Writer) error
   207  }
   208  
   209  // NewFromJSON creates an Image configuration from json.
   210  func NewFromJSON(src []byte) (*Image, error) {
   211  	img := &Image{}
   212  
   213  	if err := json.Unmarshal(src, img); err != nil {
   214  		return nil, err
   215  	}
   216  	if img.RootFS == nil {
   217  		return nil, errors.New("invalid image JSON, no RootFS key")
   218  	}
   219  
   220  	img.rawJSON = src
   221  
   222  	return img, nil
   223  }