diff --git a/hack/xref-helpmsgs-manpages b/hack/xref-helpmsgs-manpages index 627aa2e294..e62f068c8c 100755 --- a/hack/xref-helpmsgs-manpages +++ b/hack/xref-helpmsgs-manpages @@ -52,7 +52,7 @@ my $Format_Exceptions = <<'END_EXCEPTIONS'; # Deep internal structs; pretty sure these are permanent exceptions events .Details history .ImageHistoryLayer -images .ImageSummary +images .Arch .ImageSummary .Os .IsManifestList network-ls .Network # FIXME: this one, maybe? But someone needs to write the text diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index 238277a7d5..8dde5f1f61 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -483,7 +483,7 @@ func GetImages(w http.ResponseWriter, r *http.Request) { imageEngine := abi.ImageEngine{Libpod: runtime} - listOptions := entities.ImageListOptions{All: query.All, Filter: filterList} + listOptions := entities.ImageListOptions{All: query.All, Filter: filterList, ExtendedAttributes: utils.IsLibpodRequest(r)} summaries, err := imageEngine.List(r.Context(), listOptions) if err != nil { utils.Error(w, http.StatusInternalServerError, err) diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index f70663d9f4..1a9b8a6678 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -242,8 +242,11 @@ type ImageSearchReport = entitiesTypes.ImageSearchReport // Image List Options type ImageListOptions struct { - All bool `json:"all" schema:"all"` - Filter []string `json:"Filter,omitempty"` + All bool + // ExtendedAttributes is used by the libpod endpoint only to deliver extra information + // that the compat endpoint does not + ExtendedAttributes bool + Filter []string } type ImagePruneOptions struct { diff --git a/pkg/domain/entities/types/images.go b/pkg/domain/entities/types/images.go index 1a63d5d809..48344cfa9f 100644 --- a/pkg/domain/entities/types/images.go +++ b/pkg/domain/entities/types/images.go @@ -23,9 +23,15 @@ type ImageSummary struct { Dangling bool `json:",omitempty"` // Podman extensions - Names []string `json:",omitempty"` + Arch string `json:",omitempty"` Digest string `json:",omitempty"` History []string `json:",omitempty"` + // IsManifestList is a ptr so we can distinguish between a true + // json empty response and false. the docker compat side needs to return + // empty; where as the libpod side needs a value of true or false + IsManifestList *bool `json:",omitempty"` + Names []string `json:",omitempty"` + Os string `json:",omitempty"` } func (i *ImageSummary) Id() string { //nolint:revive,stylecheck diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go index 2dafc8218b..47eeea4e37 100644 --- a/pkg/domain/infra/abi/images_list.go +++ b/pkg/domain/infra/abi/images_list.go @@ -57,6 +57,21 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) RepoTags: img.Names(), // may include tags and digests ParentId: parentID, } + if opts.ExtendedAttributes { + iml, err := img.IsManifestList(ctx) + if err != nil { + return nil, err + } + s.IsManifestList = &iml + if !iml { + imgData, err := img.Inspect(ctx, nil) + if err != nil { + return nil, err + } + s.Arch = imgData.Architecture + s.Os = imgData.Os + } + } s.Labels, err = img.Labels(ctx) if err != nil { return nil, fmt.Errorf("retrieving label for image %q: you may need to remove the image to resolve the error: %w", img.ID(), err) diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at index 584d7c3958..5f54969f7d 100644 --- a/test/apiv2/12-imagesMore.at +++ b/test/apiv2/12-imagesMore.at @@ -90,3 +90,41 @@ t DELETE libpod/images/$IMAGE 200 \ podman system connection rm $conn stop_registry + +# if an image is a manifest list, it should not have +# anything for arch or os +podman manifest create foobar +t GET libpod/images/json 200 \ .[0].IsManifestList=true \ + .[0].Arch=null \ + .[0].Os=null + + +# list images through the libpod endpoint should return +# IsManifestList (bool), Arch (string), and Os (string) +podman pull -q $IMAGE +t GET libpod/images/json 200 \ .[0].IsManifestList=true\ + .[0].Arch=null \ + .[0].Os=null \ + '.[0].RepoDigests | length=1' \ + .[1].IsManifestList=false \ + .[1].Arch=amd64 \ + .[1].Os=linux + +# if a manifest list and an image are returned with libpod images +# endpoint, then one should be a manifest with IsManifest only; and +# the other image should have IsManifestList, Arch, and Os. +podman manifest add --arch amd64 foobar $IMAGE +t GET libpod/images/json 200 .[0].IsManifestList=true\ + .[0].Arch=null \ + .[0].Os=null \ + '.[0].RepoDigests | length=2' \ + .[1].IsManifestList=false \ + .[1].Arch=amd64 \ + .[1].Os=linux + +t GET images/json 200 .[0].IsManifestList=null \ + .[0].Arch=null \ + .[0].Os=null \ + .[1].IsManifestList=null \ + .[1].Arch=null \ + .[1].Os=null \