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