mirror of
https://github.com/containers/podman.git
synced 2025-05-20 00:27:03 +08:00
Should not force conversion of manifest type to DockerV2ListMediaType
Fixes: https://github.com/containers/podman/issues/23163 Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/common/pkg/auth"
|
||||
@ -55,10 +56,14 @@ func inspect(cmd *cobra.Command, args []string) error {
|
||||
insecure, _ := cmd.Flags().GetBool("insecure")
|
||||
inspectOptions.SkipTLSVerify = types.NewOptionalBool(insecure)
|
||||
}
|
||||
buf, err := registry.ImageEngine().ManifestInspect(registry.Context(), args[0], inspectOptions)
|
||||
list, err := registry.ImageEngine().ManifestInspect(registry.Context(), args[0], inspectOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(buf))
|
||||
prettyJSON, err := json.MarshalIndent(list, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(prettyJSON))
|
||||
return nil
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/containers/common/libimage/define"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/podman/v5/libpod"
|
||||
@ -190,19 +189,13 @@ func ManifestInspect(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
imageEngine := abi.ImageEngine{Libpod: runtime}
|
||||
rawManifest, err := imageEngine.ManifestInspect(r.Context(), name, opts)
|
||||
manifest, err := imageEngine.ManifestInspect(r.Context(), name, opts)
|
||||
if err != nil {
|
||||
utils.Error(w, http.StatusNotFound, err)
|
||||
return
|
||||
}
|
||||
|
||||
var schema2List define.ManifestListData
|
||||
if err := json.Unmarshal(rawManifest, &schema2List); err != nil {
|
||||
utils.Error(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
utils.WriteResponse(w, http.StatusOK, schema2List)
|
||||
utils.WriteResponse(w, http.StatusOK, manifest)
|
||||
}
|
||||
|
||||
// ManifestAddV3 remove digest from manifest list
|
||||
|
@ -3,6 +3,7 @@ package entities
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containers/common/libimage/define"
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/common/pkg/ssh"
|
||||
"github.com/containers/podman/v5/pkg/domain/entities/reports"
|
||||
@ -34,7 +35,7 @@ type ImageEngine interface { //nolint:interfacebloat
|
||||
Untag(ctx context.Context, nameOrID string, tags []string, options ImageUntagOptions) error
|
||||
ManifestCreate(ctx context.Context, name string, images []string, opts ManifestCreateOptions) (string, error)
|
||||
ManifestExists(ctx context.Context, name string) (*BoolReport, error)
|
||||
ManifestInspect(ctx context.Context, name string, opts ManifestInspectOptions) ([]byte, error)
|
||||
ManifestInspect(ctx context.Context, name string, opts ManifestInspectOptions) (*define.ManifestListData, error)
|
||||
ManifestAdd(ctx context.Context, listName string, imageNames []string, opts ManifestAddOptions) (string, error)
|
||||
ManifestAddArtifact(ctx context.Context, name string, files []string, opts ManifestAddArtifactOptions) (string, error)
|
||||
ManifestAnnotate(ctx context.Context, names, image string, opts ManifestAnnotateOptions) (string, error)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package abi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@ -12,6 +11,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/libimage"
|
||||
"github.com/containers/common/libimage/define"
|
||||
cp "github.com/containers/image/v5/copy"
|
||||
"github.com/containers/image/v5/docker"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
@ -79,7 +79,7 @@ func (ir *ImageEngine) ManifestExists(ctx context.Context, name string) (*entiti
|
||||
}
|
||||
|
||||
// ManifestInspect returns the content of a manifest list or image
|
||||
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string, opts entities.ManifestInspectOptions) ([]byte, error) {
|
||||
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string, opts entities.ManifestInspectOptions) (*define.ManifestListData, error) {
|
||||
// NOTE: we have to do a bit of a limbo here as `podman manifest
|
||||
// inspect foo` wants to do a remote-inspect of foo iff "foo" in the
|
||||
// containers storage is an ordinary image but not a manifest list.
|
||||
@ -95,25 +95,12 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string, opts en
|
||||
return nil, err
|
||||
}
|
||||
|
||||
schema2List, err := manifestList.Inspect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawSchema2List, err := json.Marshal(schema2List)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
if err := json.Indent(&b, rawSchema2List, "", " "); err != nil {
|
||||
return nil, fmt.Errorf("rendering manifest %s for display: %w", name, err)
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
return manifestList.Inspect()
|
||||
}
|
||||
|
||||
// inspect a remote manifest list.
|
||||
func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string, opts entities.ManifestInspectOptions) ([]byte, error) {
|
||||
func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string, opts entities.ManifestInspectOptions) (*define.ManifestListData, error) {
|
||||
inspectList := define.ManifestListData{}
|
||||
sys := ir.Libpod.SystemContext()
|
||||
|
||||
if opts.Authfile != "" {
|
||||
@ -134,7 +121,6 @@ func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string, o
|
||||
latestErr error
|
||||
result []byte
|
||||
manType string
|
||||
b bytes.Buffer
|
||||
)
|
||||
appendErr := func(e error) {
|
||||
if latestErr == nil {
|
||||
@ -181,27 +167,24 @@ func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string, o
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing manifest blob %q as a %q: %w", string(result), manType, err)
|
||||
}
|
||||
|
||||
if result, err = schema2Manifest.Serialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
listBlob, err := manifest.ListFromBlob(result, manType)
|
||||
list, err := manifest.ListFromBlob(result, manType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing manifest blob %q as a %q: %w", string(result), manType, err)
|
||||
}
|
||||
list, err := listBlob.ConvertToMIMEType(manifest.DockerV2ListMediaType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result, err = list.Serialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err = json.Indent(&b, result, "", " "); err != nil {
|
||||
return nil, fmt.Errorf("rendering manifest %s for display: %w", name, err)
|
||||
if err := json.Unmarshal(result, &inspectList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
return &inspectList, nil
|
||||
}
|
||||
|
||||
// ManifestAdd adds images to the manifest list
|
||||
|
@ -2,11 +2,11 @@ package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/libimage/define"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/podman/v5/pkg/bindings/images"
|
||||
"github.com/containers/podman/v5/pkg/bindings/manifests"
|
||||
@ -34,7 +34,7 @@ func (ir *ImageEngine) ManifestExists(ctx context.Context, name string) (*entiti
|
||||
}
|
||||
|
||||
// ManifestInspect returns contents of manifest list with given name
|
||||
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string, opts entities.ManifestInspectOptions) ([]byte, error) {
|
||||
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string, opts entities.ManifestInspectOptions) (*define.ManifestListData, error) {
|
||||
options := new(manifests.InspectOptions).WithAuthfile(opts.Authfile)
|
||||
if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
|
||||
if s == types.OptionalBoolTrue {
|
||||
@ -49,11 +49,7 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string, opts en
|
||||
return nil, fmt.Errorf("getting content of manifest list or image %s: %w", name, err)
|
||||
}
|
||||
|
||||
buf, err := json.MarshalIndent(list, "", " ")
|
||||
if err != nil {
|
||||
return buf, fmt.Errorf("rendering manifest for display: %w", err)
|
||||
}
|
||||
return buf, err
|
||||
return list, err
|
||||
}
|
||||
|
||||
// ManifestAdd adds images to the manifest list
|
||||
|
@ -107,7 +107,7 @@ function validate_instance_compression {
|
||||
is "$output" ".*\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\"" "Verify --tls-verify=false with REGISTRY_AUTH_FILE works against an insecure registry"
|
||||
}
|
||||
|
||||
@test "manifest list --add-compression with zstd" {
|
||||
@test "manifest list --add-compression with zstd:chunked" {
|
||||
skip_if_remote "running a local registry doesn't work with podman-remote"
|
||||
|
||||
# Using TARGETARCH gives us distinct images for each arch
|
||||
@ -133,17 +133,40 @@ EOF
|
||||
# Push to local registry; the magic key here is --add-compression...
|
||||
local manifestpushed="localhost:${PODMAN_LOGIN_REGISTRY_PORT}/$manifestlocal"
|
||||
local authfile=${PODMAN_LOGIN_WORKDIR}/auth-manifest.json
|
||||
run_podman manifest push --authfile=$authfile --all --compression-format gzip --add-compression zstd --tls-verify=false $manifestlocal $manifestpushed
|
||||
run_podman manifest push --authfile=$authfile --all --compression-format gzip --add-compression zstd:chunked --tls-verify=false $manifestlocal $manifestpushed
|
||||
|
||||
# ...and use skopeo to confirm that each component has the right settings
|
||||
echo "$_LOG_PROMPT skopeo inspect ... $manifestpushed"
|
||||
list=$(skopeo inspect --authfile=$authfile --tls-verify=false --raw docker://$manifestpushed)
|
||||
jq . <<<"$list"
|
||||
smanifest=$(skopeo inspect --authfile=$authfile --tls-verify=false --raw docker://$manifestpushed)
|
||||
jq . <<<"$smanifest"
|
||||
|
||||
validate_instance_compression "0" "$list" "amd64" "gzip"
|
||||
validate_instance_compression "1" "$list" "arm64" "gzip"
|
||||
validate_instance_compression "2" "$list" "amd64" "zstd"
|
||||
validate_instance_compression "3" "$list" "arm64" "zstd"
|
||||
validate_instance_compression "0" "$smanifest" "amd64" "gzip"
|
||||
validate_instance_compression "1" "$smanifest" "arm64" "gzip"
|
||||
validate_instance_compression "2" "$smanifest" "amd64" "zstd"
|
||||
validate_instance_compression "3" "$smanifest" "arm64" "zstd"
|
||||
|
||||
run_podman manifest inspect --authfile=$authfile --tls-verify=false \
|
||||
$manifestpushed
|
||||
pmanifest="$output"
|
||||
|
||||
objects=$(for obj in 0 1 2 3; do echo \
|
||||
".manifests[$obj].annotations" \
|
||||
".manifests[$obj].digest" \
|
||||
".manifests[$obj].platform.architecture" \
|
||||
".manifests[$obj].platform.os" \
|
||||
".manifests[$obj].mediaType" \
|
||||
".manifests[$obj].size" \
|
||||
; done)
|
||||
for object in \
|
||||
$objects \
|
||||
'.schemaVersion' \
|
||||
'.mediaType' \
|
||||
; do
|
||||
skopeoObj=$(jq -r "$object" <<<"$smanifest")
|
||||
podmanObj=$(jq -r "$object" <<<"$pmanifest")
|
||||
assert "$skopeoObj" != "$smanifest" "\"$object\" does not exist in skopeo result"
|
||||
assert "$podmanObj" == "$skopeoObj" "podman \"$object\" does not match skopeo"
|
||||
done
|
||||
|
||||
run_podman rmi image_amd image_arm
|
||||
run_podman manifest rm $manifestlocal
|
||||
|
Reference in New Issue
Block a user