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