diff --git a/api/types/image/image_inspect.go b/api/types/image/image_inspect.go index baded49457..66a277e557 100644 --- a/api/types/image/image_inspect.go +++ b/api/types/image/image_inspect.go @@ -2,7 +2,6 @@ package image import ( dockerspec "github.com/moby/docker-image-spec/specs-go/v1" - "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/storage" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -43,15 +42,6 @@ type InspectResponse struct { // the manifest is generated and its digest calculated. RepoDigests []string - // Parent is the ID of the parent image. - // - // Depending on how the image was created, this field may be empty and - // is only set for images that were built/created locally. This field - // is omitted if the image was pulled from an image registry. - // - // Deprecated: this field is deprecated, and will be removed in the next release. - Parent string `json:",omitempty"` - // Comment is an optional message that can be set when committing or // importing the image. This field is omitted if not set. Comment string `json:",omitempty"` @@ -63,29 +53,6 @@ type InspectResponse struct { // and omitted otherwise. Created string `json:",omitempty"` - // Container is the ID of the container that was used to create the image. - // - // Depending on how the image was created, this field may be empty. - // - // Deprecated: this field is omitted in API v1.45, but kept for backward compatibility. - Container string `json:",omitempty"` - - // ContainerConfig is an optional field containing the configuration of the - // container that was last committed when creating the image. - // - // Previous versions of Docker builder used this field to store build cache, - // and it is not in active use anymore. - // - // Deprecated: this field is omitted in API v1.45, but kept for backward compatibility. - ContainerConfig *container.Config `json:",omitempty"` - - // DockerVersion is the version of Docker that was used to build the image. - // - // Depending on how the image was created, this field may be omitted. - // - // Deprecated: this field is deprecated, and will be removed in the next release. - DockerVersion string `json:",omitempty"` - // Author is the name of the author that was specified when committing the // image, or as specified through MAINTAINER (deprecated) in the Dockerfile. // This field is omitted if not set. @@ -108,12 +75,6 @@ type InspectResponse struct { // Size is the total size of the image including all layers it is composed of. Size int64 - // VirtualSize is the total size of the image including all layers it is - // composed of. - // - // Deprecated: this field is omitted in API v1.44, but kept for backward compatibility. Use Size instead. - VirtualSize int64 `json:"VirtualSize,omitempty"` - // GraphDriver holds information about the storage driver used to store the // container's and image's filesystem. GraphDriver *storage.DriverData `json:"GraphDriver,omitempty"` diff --git a/daemon/containerd/image_inspect.go b/daemon/containerd/image_inspect.go index deaed0ab0c..d1fc1bcf34 100644 --- a/daemon/containerd/image_inspect.go +++ b/daemon/containerd/image_inspect.go @@ -18,7 +18,7 @@ import ( "golang.org/x/sync/semaphore" ) -func (i *ImageService) ImageInspect(ctx context.Context, refOrID string, opts imagebackend.ImageInspectOpts) (*imagetypes.InspectResponse, error) { +func (i *ImageService) ImageInspect(ctx context.Context, refOrID string, opts imagebackend.ImageInspectOpts) (*imagebackend.InspectData, error) { requestedPlatform := opts.Platform c8dImg, err := i.resolveImage(ctx, refOrID) @@ -85,17 +85,19 @@ func (i *ImageService) ImageInspect(ctx context.Context, refOrID string, opts im target = multi.Best.Target() } - resp := &imagetypes.InspectResponse{ - ID: target.Digest.String(), - RepoTags: repoTags, - Descriptor: &target, - RepoDigests: repoDigests, - Parent: parent, //nolint:staticcheck // ignore SA1019: field is deprecated, but still included in response when present. - Size: size, - Manifests: manifests, - Metadata: imagetypes.Metadata{ - LastTagTime: lastUpdated, + resp := &imagebackend.InspectData{ + InspectResponse: imagetypes.InspectResponse{ + ID: target.Digest.String(), + RepoTags: repoTags, + Descriptor: &target, + RepoDigests: repoDigests, + Size: size, + Manifests: manifests, + Metadata: imagetypes.Metadata{ + LastTagTime: lastUpdated, + }, }, + Parent: parent, // field is deprecated with the legacy builder, but returned by the API if present. } if multi.Best != nil { diff --git a/daemon/image_service.go b/daemon/image_service.go index 8cae555d2c..9fce074a8e 100644 --- a/daemon/image_service.go +++ b/daemon/image_service.go @@ -43,7 +43,7 @@ type ImageService interface { ImageHistory(ctx context.Context, name string, platform *ocispec.Platform) ([]*imagetype.HistoryResponseItem, error) CommitImage(ctx context.Context, c backend.CommitConfig) (image.ID, error) SquashImage(id, parent string) (string, error) - ImageInspect(ctx context.Context, refOrID string, opts imagebackend.ImageInspectOpts) (*imagetype.InspectResponse, error) + ImageInspect(ctx context.Context, refOrID string, opts imagebackend.ImageInspectOpts) (*imagebackend.InspectData, error) ImageDiskUsage(ctx context.Context) (int64, error) // Layers diff --git a/daemon/images/image_inspect.go b/daemon/images/image_inspect.go index 1b223de9f8..535bb594e2 100644 --- a/daemon/images/image_inspect.go +++ b/daemon/images/image_inspect.go @@ -12,7 +12,7 @@ import ( "github.com/moby/moby/v2/daemon/server/imagebackend" ) -func (i *ImageService) ImageInspect(ctx context.Context, refOrID string, opts imagebackend.ImageInspectOpts) (*imagetypes.InspectResponse, error) { +func (i *ImageService) ImageInspect(ctx context.Context, refOrID string, opts imagebackend.ImageInspectOpts) (*imagebackend.InspectData, error) { img, err := i.GetImage(ctx, refOrID, imagebackend.GetImageOpts{Platform: opts.Platform}) if err != nil { return nil, err @@ -54,34 +54,36 @@ func (i *ImageService) ImageInspect(ctx context.Context, refOrID string, opts im } imgConfig := containerConfigToDockerOCIImageConfig(img.Config) - return &imagetypes.InspectResponse{ - ID: img.ID().String(), - RepoTags: repoTags, - RepoDigests: repoDigests, - Parent: img.Parent.String(), //nolint:staticcheck // ignore SA1019: field is deprecated, but still included in response when present (built with legacy builder). - Comment: comment, - Created: created, - Container: img.Container, //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45. - ContainerConfig: &img.ContainerConfig, //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45. - DockerVersion: img.DockerVersion, //nolint:staticcheck // ignore SA1019: field is deprecated, but still included in response when present. - Author: img.Author, - Config: &imgConfig, - Architecture: img.Architecture, - Variant: img.Variant, - Os: img.OperatingSystem(), - OsVersion: img.OSVersion, - Size: size, - GraphDriver: &storage.DriverData{ - Name: i.layerStore.DriverName(), - Data: layerMetadata, - }, - RootFS: imagetypes.RootFS{ - Type: img.RootFS.Type, - Layers: layers, - }, - Metadata: imagetypes.Metadata{ - LastTagTime: lastUpdated, + return &imagebackend.InspectData{ + InspectResponse: imagetypes.InspectResponse{ + ID: img.ID().String(), + RepoTags: repoTags, + RepoDigests: repoDigests, + Comment: comment, + Created: created, + Author: img.Author, + Config: &imgConfig, + Architecture: img.Architecture, + Variant: img.Variant, + Os: img.OperatingSystem(), + OsVersion: img.OSVersion, + Size: size, + GraphDriver: &storage.DriverData{ + Name: i.layerStore.DriverName(), + Data: layerMetadata, + }, + RootFS: imagetypes.RootFS{ + Type: img.RootFS.Type, + Layers: layers, + }, + Metadata: imagetypes.Metadata{ + LastTagTime: lastUpdated, + }, }, + Parent: img.Parent.String(), // field is deprecated with the legacy builder, but still included in response when present (built with legacy builder). + DockerVersion: img.DockerVersion, // field is deprecated with the legacy builder, but still included in response when present. + Container: img.Container, // field is deprecated, but still set on API < v1.45. + ContainerConfig: &img.ContainerConfig, // field is deprecated, but still set on API < v1.45. }, nil } diff --git a/daemon/server/imagebackend/image.go b/daemon/server/imagebackend/image.go index 01b8186b14..b3992c44c2 100644 --- a/daemon/server/imagebackend/image.go +++ b/daemon/server/imagebackend/image.go @@ -4,7 +4,9 @@ import ( "io" "net/http" + "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/filters" + imagetypes "github.com/moby/moby/api/types/image" "github.com/moby/moby/api/types/registry" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -55,3 +57,39 @@ type ImageInspectOpts struct { Manifests bool Platform *ocispec.Platform } + +type InspectData struct { + imagetypes.InspectResponse + + // Parent is the ID of the parent image. + // + // Depending on how the image was created, this field may be empty and + // is only set for images that were built/created locally. This field + // is omitted if the image was pulled from an image registry. + // + // This field is deprecated with the legacy builder, but returned by the API if present. + Parent string `json:",omitempty"` + + // DockerVersion is the version of Docker that was used to build the image. + // + // Depending on how the image was created, this field may be omitted. + // + // This field is deprecated with the legacy builder, but returned by the API if present. + DockerVersion string `json:",omitempty"` + + // Container is the ID of the container that was used to create the image. + // + // Depending on how the image was created, this field may be empty. + // + // This field is removed in API v1.45, but used for API <= v1.44 responses. + Container string + + // ContainerConfig is an optional field containing the configuration of the + // container that was last committed when creating the image. + // + // Previous versions of Docker builder used this field to store build cache, + // and it is not in active use anymore. + // + // This field is removed in API v1.45, but used for API <= v1.44 responses. + ContainerConfig *container.Config +} diff --git a/daemon/server/router/image/backend.go b/daemon/server/router/image/backend.go index 97f3040b29..7d297e90e0 100644 --- a/daemon/server/router/image/backend.go +++ b/daemon/server/router/image/backend.go @@ -26,7 +26,7 @@ type imageBackend interface { ImageHistory(ctx context.Context, imageName string, platform *ocispec.Platform) ([]*image.HistoryResponseItem, error) Images(ctx context.Context, opts imagebackend.ListOptions) ([]*image.Summary, error) GetImage(ctx context.Context, refOrID string, options imagebackend.GetImageOpts) (*dockerimage.Image, error) - ImageInspect(ctx context.Context, refOrID string, options imagebackend.ImageInspectOpts) (*image.InspectResponse, error) + ImageInspect(ctx context.Context, refOrID string, options imagebackend.ImageInspectOpts) (*imagebackend.InspectData, error) TagImage(ctx context.Context, id dockerimage.ID, newRef reference.Named) error ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*image.PruneReport, error) } diff --git a/daemon/server/router/image/image_routes.go b/daemon/server/router/image/image_routes.go index b173f39893..094f484f93 100644 --- a/daemon/server/router/image/image_routes.go +++ b/daemon/server/router/image/image_routes.go @@ -379,13 +379,14 @@ func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWrite return errdefs.InvalidParameter(errors.New("conflicting options: manifests and platform options cannot both be set")) } - imageInspect, err := ir.backend.ImageInspect(ctx, vars["name"], imagebackend.ImageInspectOpts{ + inspectData, err := ir.backend.ImageInspect(ctx, vars["name"], imagebackend.ImageInspectOpts{ Manifests: manifests, Platform: platform, }) if err != nil { return err } + imageInspect := inspectData.InspectResponse var legacyOptions []compat.Option @@ -409,9 +410,11 @@ func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWrite imageInspect.Created = time.Time{}.Format(time.RFC3339Nano) } } - if versions.GreaterThanOrEqualTo(version, "1.45") { - imageInspect.Container = "" //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45. - imageInspect.ContainerConfig = nil //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45. + if versions.LessThan(version, "1.45") { + legacyOptions = append(legacyOptions, compat.WithExtraFields(map[string]any{ + "Container": inspectData.Container, + "ContainerConfig": inspectData.ContainerConfig, + })) } if versions.LessThan(version, "1.48") { imageInspect.Descriptor = nil @@ -420,10 +423,10 @@ func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWrite // These fields have "omitempty" on API v1.52 and higher, // but older API versions returned them unconditionally. legacyOptions = append(legacyOptions, compat.WithExtraFields(map[string]any{ - "Parent": imageInspect.Parent, //nolint:staticcheck // ignore SA1019: field is deprecated, but still included in response when present (built with legacy builder). - "Comment": imageInspect.Comment, - "DockerVersion": imageInspect.DockerVersion, //nolint:staticcheck // ignore SA1019: field is deprecated, but still included in response when present. - "Author": imageInspect.Author, + "Parent": inspectData.Parent, // field is deprecated, but still included in response when present (built with legacy builder). + "Comment": inspectData.Comment, + "DockerVersion": inspectData.DockerVersion, // field is deprecated, but still included in response when present. + "Author": inspectData.Author, })) // preserve fields in the image Config that have an "omitempty" @@ -437,6 +440,15 @@ func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWrite "Config": legacyConfigFields["v1.50-v1.51"], })) } + } else { + if inspectData.Parent != "" { + // field is deprecated, but still included in response when present (built with legacy builder). + legacyOptions = append(legacyOptions, compat.WithExtraFields(map[string]any{"Parent": inspectData.Parent})) + } + if inspectData.DockerVersion != "" { + // field is deprecated, but still included in response when present. + legacyOptions = append(legacyOptions, compat.WithExtraFields(map[string]any{"DockerVersion": inspectData.DockerVersion})) + } } if len(legacyOptions) > 0 { diff --git a/integration-cli/docker_api_build_test.go b/integration-cli/docker_api_build_test.go index 506de2ca23..a0be189eef 100644 --- a/integration-cli/docker_api_build_test.go +++ b/integration-cli/docker_api_build_test.go @@ -319,10 +319,22 @@ func (s *DockerAPISuite) TestBuildOnBuildCache(c *testing.T) { // check parentID is correct // Parent is graphdriver-only if !testEnv.UsingSnapshotter() { - image, err := apiClient.ImageInspect(ctx, childID) + var buf bytes.Buffer + _, err := apiClient.ImageInspect(ctx, childID, client.ImageInspectWithRawResponse(&buf)) assert.NilError(c, err) - assert.Check(c, is.Equal(parentID, image.Parent)) //nolint:staticcheck // ignore SA1019: field is deprecated, but still included in response when present. + var image struct { + // Parent is the ID of the parent image. + // + // Depending on how the image was created, this field may be empty and + // is only set for images that were built/created locally. This field + // is omitted if the image was pulled from an image registry. + Parent string `json:",omitempty"` + } + rawResponse := buf.Bytes() + err = json.Unmarshal(rawResponse, &image) + assert.NilError(c, err, string(rawResponse)) + assert.Check(c, is.Equal(parentID, image.Parent), string(rawResponse)) } } diff --git a/vendor/github.com/moby/moby/api/types/image/image_inspect.go b/vendor/github.com/moby/moby/api/types/image/image_inspect.go index baded49457..66a277e557 100644 --- a/vendor/github.com/moby/moby/api/types/image/image_inspect.go +++ b/vendor/github.com/moby/moby/api/types/image/image_inspect.go @@ -2,7 +2,6 @@ package image import ( dockerspec "github.com/moby/docker-image-spec/specs-go/v1" - "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/storage" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -43,15 +42,6 @@ type InspectResponse struct { // the manifest is generated and its digest calculated. RepoDigests []string - // Parent is the ID of the parent image. - // - // Depending on how the image was created, this field may be empty and - // is only set for images that were built/created locally. This field - // is omitted if the image was pulled from an image registry. - // - // Deprecated: this field is deprecated, and will be removed in the next release. - Parent string `json:",omitempty"` - // Comment is an optional message that can be set when committing or // importing the image. This field is omitted if not set. Comment string `json:",omitempty"` @@ -63,29 +53,6 @@ type InspectResponse struct { // and omitted otherwise. Created string `json:",omitempty"` - // Container is the ID of the container that was used to create the image. - // - // Depending on how the image was created, this field may be empty. - // - // Deprecated: this field is omitted in API v1.45, but kept for backward compatibility. - Container string `json:",omitempty"` - - // ContainerConfig is an optional field containing the configuration of the - // container that was last committed when creating the image. - // - // Previous versions of Docker builder used this field to store build cache, - // and it is not in active use anymore. - // - // Deprecated: this field is omitted in API v1.45, but kept for backward compatibility. - ContainerConfig *container.Config `json:",omitempty"` - - // DockerVersion is the version of Docker that was used to build the image. - // - // Depending on how the image was created, this field may be omitted. - // - // Deprecated: this field is deprecated, and will be removed in the next release. - DockerVersion string `json:",omitempty"` - // Author is the name of the author that was specified when committing the // image, or as specified through MAINTAINER (deprecated) in the Dockerfile. // This field is omitted if not set. @@ -108,12 +75,6 @@ type InspectResponse struct { // Size is the total size of the image including all layers it is composed of. Size int64 - // VirtualSize is the total size of the image including all layers it is - // composed of. - // - // Deprecated: this field is omitted in API v1.44, but kept for backward compatibility. Use Size instead. - VirtualSize int64 `json:"VirtualSize,omitempty"` - // GraphDriver holds information about the storage driver used to store the // container's and image's filesystem. GraphDriver *storage.DriverData `json:"GraphDriver,omitempty"`