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 }