10BC0 api: image inspect: add back fields that did not omitempty by thaJeztah · Pull Request #50135 · moby/moby · GitHub
[go: up one dir, main page]

Skip to content

Conversation

thaJeztah
Copy link
Member
@thaJeztah thaJeztah commented Jun 3, 2025

commit 4dc961d removed deprecated fields from the image inspect response for API v1.50 and up. As part of that change, it changed the type used for the Config field to use the docker image spect structs, which embeds the OCI image spec structs.

While the OCI image spect struct contains the same fields as we used before, those fields also have "omitempty" set, which means they are now omitted when empty.

We should probably consider deprecating that behavior in the API, and call out that these fields are omitted if not set, but in the meantime, we can add them back with their default (zero) value.

- What I did

- How I did it

- How to verify it

- Human readable description for the release notes

Fix `docker image inspect inspect` omitting empty fields.

- A picture of a cute animal (not mandatory but encouraged)

Copy link
Contributor
@vvoland vvoland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but we should remove that in v1.51+

< 10BC0 details-toggle>
@thaJeztah
Copy link
Member Author

but we should remove that in v1.51+

Probably; I also just came to the conclusion that we can combine the existing fallback with the new one, and (AFAICS) that would also mean we can drop the dockerOCIImageConfigToContainerConfig function that we copied, so simplifying other things as well.

I have a commit doing so; let me push that, and I can squash it iafter that.

@thaJeztah
Copy link
Member Author

OK; pushed a commit; let me know what you think, then I can squash.

@thaJeztah
Copy link
Member Author

Looks like I broke something in that last commit; will have a look tomorrow

@thaJeztah thaJeztah force-pushed the inspect_no_omitempty branch 3 times, most recently from 585aadb to 4ff4fa2 Compare June 3, 2025 22:52
Comment on lines +83 to +84
// prevent mutating legacyConfigFields.
cfg := maps.Clone(ir.legacyConfig)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the problem; I added the legacyConfigFields the router assigns legacyConfig from that, and we didn't de-reference.

Comment on lines +381 to +384
imageInspect := &inspectCompatResponse{
InspectResponse: resp,
legacyConfig: legacyConfigFields["current"],
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW; I started to look if adding a constructor for this would be cleaner, and possibly it could be, but rewriting took me down the rabbit hole, so I'm gonna leave that for a future refactor; possibly combining all the version-related changes below 🤔

Comment on lines +37 to +49
// Legacy fields for current API versions (v1.50 and up). These fields
// did not have an "omitempty" and were always included in the response,
// even if not set; see https://github.com/moby/moby/issues/50134
"current": {
"Cmd": nil,
"Entrypoint": nil,
"Env": nil,
"Labels": nil,
"OnBuild": nil,
"User": "",
"Volumes": nil,
"WorkingDir": "",
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can avoid this one and just marshal the base InspectResponse instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were the ones that had an omit empty, so were not included #50134

So I think using the base would then result in them disappearing again.

But for api v1.51 we can consider doing so, but we'd have to deprecate that behavior first (can do that in a separate PR)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right...

I think what confused me is that the caller is responsible for passing the correct value of legacyConfigFields.

Could we just pass the API version the response should be adapted to?

So

imageInspect := &inspectCompatResponse{
		InspectResponse: resp,
}

would mean the "current"/"latest" and

imageInspect := &inspectCompatResponse{
		InspectResponse: resp,
        version: "1.49"
}

would mean the 1.49 compatible response..

Although that's probably what you meant in https://github.com/moby/moby/pull/50135/files#r2126024062?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, I think it would be slightly easier to understand if we declared a copy-pasted, unexported versions of the "legacy" Config struct and just explicitly filled and marshalled them inside inspectCompatResponse.MarshalJSON.
While more verbose, I think it would be much clearer and easier to understand.

Just a thought though, not a blocker

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we just pass the API version the response should be adapted to?

Yeah, that's something I was considering, and mostly had written, then threw it away thinking to KISS for now. I can still have a look at that though.

I think it would be slightly easier to understand if we declared a copy-pasted, unexported versions of the "legacy" Config struct

Ah, gotcha. Hm.. yes, possibly could work. My goal at least was to avoid having to depend on legacy types or fields if that meant we'd have to continue maintaining the fields (as "deprecated") purely for the old responses (but with empty / zero values).

Having a (non-exported) copy of such structs purely for that purpose is indeed slightly better; what I slightly tried to avoid though was to (in some cases) that potentially requiring to also use legacy indirect types, such as the nat.Port mapping in the code we had;

exposedPorts := make(nat.PortSet, len(cfg.ExposedPorts))
for k, v := range cfg.ExposedPorts {
exposedPorts[nat.Port(k)] = v
}
return &container.Config{

I recall we used to have these "versioned" legacy types, which I guess is a bit of that approach; some of those started to become quite involved though;
https://github.com/moby/moby/blob/v19.03.0/api/types/versions/v1p19/types.go
https://github.com/moby/moby/blob/v19.03.0/api/types/versions/v1p20/types.go
https://github.com/moby/moby/blob/v19.03.0/daemon/inspect.go#L22-L30

commit 4dc961d removed deprecated
fields from the image inspect response for API v1.50 and up. As
part of that change, it changed the type used for the Config field
to use the docker image spect structs, which embeds the OCI image
spec structs.

While the OCI image spect struct contains the same fields as we
used before, those fields also have "omitempty" set, which means
they are now omitted when empty.

We should probably consider deprecating that behavior in the API,
and call out that these fields are omitted if not set, but in the
meantime, we can add them back with their default (zero) value.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
@thaJeztah thaJeztah force-pushed the inspect_no_omitempty branch from 4ff4fa2 to f85394d Compare June 4, 2025 16:02
@thaJeztah
Copy link
Member Author

Squashed the commits, but happy to make additional changes related to #50135 (comment)

@thaJeztah thaJeztah marked this pull request as ready for review June 10, 2025 11:04
@vvoland vvoland added this to the 28.2.3 milestone Jun 11, 2025
@vvoland vvoland merged commit e84353e into moby:master Jun 11, 2025
163 checks passed
@vvoland vvoland modified the milestones: 28.2.3, 28.3.0 Jun 11, 2025
@thaJeztah thaJeztah deleted the inspect_no_omitempty branch June 11, 2025 09:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

panic when pulling an image with docker compose /images/{name}/json does not return image Entrypoint if null
3 participants
0