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