image/image.go
82a54398
 package image
33f6a0aa
 
 import (
9001ea26
 	"encoding/json"
01ba0a93
 	"errors"
 	"io"
51360965
 	"runtime"
 	"strings"
9001ea26
 	"time"
 
91e197d6
 	"github.com/docker/docker/api/types/container"
bd5f92d2
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/layer"
7a855799
 	"github.com/opencontainers/go-digest"
33f6a0aa
 )
 
01ba0a93
 // ID is the content-addressable ID of an image.
 type ID digest.Digest
8f57e7d2
 
01ba0a93
 func (id ID) String() string {
80522398
 	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
 func IDFromDigest(digest digest.Digest) ID {
 	return ID(digest)
504e67b8
 }
 
01ba0a93
 // V1Image stores the V1 image configuration.
 type V1Image struct {
b2ec509a
 	// ID is a unique 64 character identifier of the image
504e67b8
 	ID string `json:"id,omitempty"`
b2ec509a
 	// Parent is the ID of the parent image
b0615729
 	Parent string `json:"parent,omitempty"`
b2ec509a
 	// Comment is the commit message that was set when committing the image
b0615729
 	Comment string `json:"comment,omitempty"`
b2ec509a
 	// Created is the timestamp at which the image was created
b0615729
 	Created time.Time `json:"created"`
 	// Container is the id of the container used to commit
 	Container string `json:"container,omitempty"`
bbeb859b
 	// ContainerConfig is the configuration of the container that is committed into the image
7ac4232e
 	ContainerConfig container.Config `json:"container_config,omitempty"`
b2ec509a
 	// DockerVersion specifies the version of Docker that was used to build the image
b0615729
 	DockerVersion string `json:"docker_version,omitempty"`
b2ec509a
 	// Author is the name of the author that was specified when committing the image
b0615729
 	Author string `json:"author,omitempty"`
 	// Config is the configuration of the container received from the client
7ac4232e
 	Config *container.Config `json:"config,omitempty"`
5e1349e0
 	// Architecture is the hardware that the image is built and runs on
b0615729
 	Architecture string `json:"architecture,omitempty"`
 	// OS is the operating system used to build and run the image
 	OS string `json:"os,omitempty"`
 	// Size is the total size of the image including all layers it is composed of
01ba0a93
 	Size int64 `json:",omitempty"`
9001ea26
 }
 
01ba0a93
 // Image stores the image configuration
 type Image struct {
 	V1Image
194eaa5c
 	Parent     ID        `json:"parent,omitempty"`
 	RootFS     *RootFS   `json:"rootfs,omitempty"`
 	History    []History `json:"history,omitempty"`
 	OSVersion  string    `json:"os.version,omitempty"`
 	OSFeatures []string  `json:"os.features,omitempty"`
9001ea26
 
01ba0a93
 	// 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
9001ea26
 }
 
01ba0a93
 // 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
c30a55f1
 }
504e67b8
 
80522398
 // ImageID stringifies ID.
9c332b16
 func (img *Image) ImageID() string {
80522398
 	return img.ID().String()
9c332b16
 }
 
 // RunConfig returns the image's container config.
 func (img *Image) RunConfig() *container.Config {
 	return img.Config
 }
 
0380fbff
 // OperatingSystem returns the image's operating system. If not populated, defaults to the host runtime OS.
 func (img *Image) OperatingSystem() string {
6c336849
 	os := img.OS
 	if os == "" {
 		os = runtime.GOOS
 	}
 	return os
 }
 
01ba0a93
 // 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
504e67b8
 
01ba0a93
 	pass1, err := json.Marshal(MarshalImage(*img))
504e67b8
 	if err != nil {
 		return nil, err
 	}
 
 	var c map[string]*json.RawMessage
01ba0a93
 	if err := json.Unmarshal(pass1, &c); err != nil {
504e67b8
 		return nil, err
 	}
 	return json.Marshal(c)
 }
 
bd5f92d2
 // 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
 }
 
51360965
 // NewChildImage creates a new Image as a child of this image.
8f537806
 func NewChildImage(img *Image, child ChildConfig, platform string) *Image {
bd5f92d2
 	isEmptyLayer := layer.IsEmpty(child.DiffID)
b50ade0b
 	var rootFS *RootFS
 	if img.RootFS != nil {
 		rootFS = img.RootFS.Clone()
 	} else {
51360965
 		rootFS = NewRootFS()
 	}
b50ade0b
 
bd5f92d2
 	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:    runtime.GOARCH,
8f537806
 			OS:              platform,
bd5f92d2
 			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,
 	}
 }
 
01ba0a93
 // History stores build commands that were used to create an image
 type History struct {
b2ec509a
 	// Created is the timestamp at which the image was created
01ba0a93
 	Created time.Time `json:"created"`
b2ec509a
 	// Author is the name of the author that was specified when committing the image
01ba0a93
 	Author string `json:"author,omitempty"`
b2ec509a
 	// CreatedBy keeps the Dockerfile command used while building the image
01ba0a93
 	CreatedBy string `json:"created_by,omitempty"`
b2ec509a
 	// Comment is the commit message that was set when committing the image
01ba0a93
 	Comment string `json:"comment,omitempty"`
 	// EmptyLayer is set to true if this history item did not generate a
 	// layer. Otherwise, the history item is associated with the next
 	// layer in the RootFS section.
 	EmptyLayer bool `json:"empty_layer,omitempty"`
504e67b8
 }
 
bd5f92d2
 // 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 {
 	return History{
 		Author:     author,
 		Created:    time.Now().UTC(),
 		CreatedBy:  createdBy,
 		Comment:    comment,
 		EmptyLayer: isEmptyLayer,
 	}
 }
 
b2ec509a
 // Exporter provides interface for loading and saving images
01ba0a93
 type Exporter interface {
fae09e25
 	Load(io.ReadCloser, io.Writer, bool) error
01ba0a93
 	// 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
504e67b8
 	}
01ba0a93
 	if img.RootFS == nil {
b2ec509a
 		return nil, errors.New("invalid image JSON, no RootFS key")
01ba0a93
 	}
 
 	img.rawJSON = src
 
 	return img, nil
504e67b8
 }