github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/image/image.go (about)

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