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 |
} |