summaryrefslogtreecommitdiff
path: root/image/image.go
diff options
context:
space:
mode:
Diffstat (limited to 'image/image.go')
-rw-r--r--image/image.go220
1 files changed, 220 insertions, 0 deletions
diff --git a/image/image.go b/image/image.go
new file mode 100644
index 0000000..ab95d93
--- /dev/null
+++ b/image/image.go
@@ -0,0 +1,220 @@
+package image
+
+import (
+ "encoding/json"
+ "errors"
+ "io"
+ "runtime"
+ "strings"
+ "time"
+
+ "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/dockerversion"
+ "github.com/docker/docker/layer"
+ "github.com/opencontainers/go-digest"
+)
+
+// 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
+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
+ Parent string `json:"parent,omitempty"`
+ // Comment is the commit message that was set when committing 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 used to commit
+ Container string `json:"container,omitempty"`
+ // ContainerConfig is the configuration of the container that is committed into the image
+ ContainerConfig container.Config `json:"container_config,omitempty"`
+ // DockerVersion specifies the version of Docker that was used to build the image
+ DockerVersion string `json:"docker_version,omitempty"`
+ // Author is the name of the author that was specified when committing the image
+ 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 that the image is built and runs on
+ 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
+ Size int64 `json:",omitempty"`
+}
+
+// Image stores the image configuration
+type Image struct {
+ V1Image
+ 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"`
+
+ // 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
+}
+
+// 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
+}
+
+// Platform returns the image's operating system. If not populated, defaults to the host runtime OS.
+func (img *Image) Platform() string {
+ os := img.OS
+ if os == "" {
+ os = runtime.GOOS
+ }
+ return os
+}
+
+// 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
+}
+
+// NewChildImage creates a new Image as a child of this image.
+func NewChildImage(img *Image, child ChildConfig, platform string) *Image {
+ isEmptyLayer := layer.IsEmpty(child.DiffID)
+ rootFS := img.RootFS
+ if rootFS == nil {
+ 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: runtime.GOARCH,
+ OS: platform,
+ 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,
+ }
+}
+
+// History stores build commands that were used to create an image
+type History struct {
+ // Created is the timestamp at which the image was created
+ Created time.Time `json:"created"`
+ // Author is the name of the author that was specified when committing the image
+ Author string `json:"author,omitempty"`
+ // CreatedBy keeps the Dockerfile command used while building the image
+ CreatedBy string `json:"created_by,omitempty"`
+ // Comment is the commit message that was set when committing the image
+ 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"`
+}
+
+// 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,
+ }
+}
+
+// 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
+}