Merge pull request #7735 from QiWang19/manifest-inspect

fix allowing inspect manifest of non-local image
This commit is contained in:
OpenShift Merge Robot
2020-10-01 13:32:02 -04:00
committed by GitHub
3 changed files with 94 additions and 23 deletions

View File

@ -6,11 +6,13 @@ import (
"github.com/containers/buildah/manifests" "github.com/containers/buildah/manifests"
copy2 "github.com/containers/image/v5/copy" copy2 "github.com/containers/image/v5/copy"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports/alltransports" "github.com/containers/image/v5/transports/alltransports"
"github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/image" "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/domain/infra/abi"
"github.com/gorilla/schema" "github.com/gorilla/schema"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -48,17 +50,18 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) {
func ManifestInspect(w http.ResponseWriter, r *http.Request) { func ManifestInspect(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime) runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r) name := utils.GetName(r)
newImage, err := runtime.ImageRuntime().NewFromLocal(name) imageEngine := abi.ImageEngine{Libpod: runtime}
if err != nil { inspectReport, inspectError := imageEngine.ManifestInspect(r.Context(), name)
utils.ImageNotFound(w, name, err) if inspectError != nil {
utils.Error(w, "Something went wrong.", http.StatusNotFound, inspectError)
return return
} }
data, err := newImage.InspectManifest() var list manifest.Schema2List
if err != nil { if err := json.Unmarshal(inspectReport, &list); err != nil {
utils.InternalServerError(w, err) utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Unmarshal()"))
return return
} }
utils.WriteResponse(w, http.StatusOK, data) utils.WriteResponse(w, http.StatusOK, &list)
} }
func ManifestAdd(w http.ResponseWriter, r *http.Request) { func ManifestAdd(w http.ResponseWriter, r *http.Request) {

View File

@ -3,6 +3,7 @@
package abi package abi
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -11,15 +12,17 @@ import (
"strings" "strings"
"github.com/containers/buildah/manifests" "github.com/containers/buildah/manifests"
buildahManifests "github.com/containers/buildah/pkg/manifests"
"github.com/containers/buildah/util"
buildahUtil "github.com/containers/buildah/util" buildahUtil "github.com/containers/buildah/util"
cp "github.com/containers/image/v5/copy" cp "github.com/containers/image/v5/copy"
"github.com/containers/image/v5/docker" "github.com/containers/image/v5/docker"
"github.com/containers/image/v5/manifest" "github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports" "github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
libpodImage "github.com/containers/podman/v2/libpod/image" libpodImage "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/util"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
@ -41,28 +44,82 @@ func (ir *ImageEngine) ManifestCreate(ctx context.Context, names, images []strin
// ManifestInspect returns the content of a manifest list or image // ManifestInspect returns the content of a manifest list or image
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte, error) { func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte, error) {
dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name()) if newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(name); err == nil {
_, err := alltransports.ParseImageName(name) // return the manifest in local storage
if err != nil { if list, err := newImage.InspectManifest(); err == nil {
_, err = alltransports.ParseImageName(dockerPrefix + name) buf, err := json.MarshalIndent(list, "", " ")
if err != nil { if err != nil {
return nil, errors.Errorf("invalid image reference %q", name) return buf, errors.Wrapf(err, "error rendering manifest %s for display", name)
}
return buf, nil
// no return if local image is not a list of images type
// continue on getting valid manifest through remote serice
} else if errors.Cause(err) != buildahManifests.ErrManifestTypeNotSupported {
return nil, errors.Wrapf(err, "loading manifest %q", name)
} }
} }
image, err := ir.Libpod.ImageRuntime().New(ctx, name, "", "", nil, nil, libpodImage.SigningOptions{}, nil, util.PullImageMissing) sc := ir.Libpod.SystemContext()
refs, err := util.ResolveNameToReferences(ir.Libpod.GetStore(), sc, name)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "reading image %q", name) return nil, err
} }
var (
latestErr error
result []byte
manType string
b bytes.Buffer
)
appendErr := func(e error) {
if latestErr == nil {
latestErr = e
} else {
latestErr = errors.Wrapf(latestErr, "tried %v\n", e)
}
}
for _, ref := range refs {
src, err := ref.NewImageSource(ctx, sc)
if err != nil {
appendErr(errors.Wrapf(err, "reading image %q", transports.ImageName(ref)))
continue
}
defer src.Close()
list, err := image.InspectManifest() manifestBytes, manifestType, err := src.GetManifest(ctx, nil)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "loading manifest %q", name) appendErr(errors.Wrapf(err, "loading manifest %q", transports.ImageName(ref)))
continue
}
if !manifest.MIMETypeIsMultiImage(manifestType) {
appendErr(errors.Errorf("manifest is of type %s (not a list type)", manifestType))
continue
}
result = manifestBytes
manType = manifestType
break
} }
buf, err := json.MarshalIndent(list, "", " ") if len(result) == 0 && latestErr != nil {
if err != nil { return nil, latestErr
return buf, errors.Wrapf(err, "error rendering manifest for display")
} }
return buf, nil if manType != manifest.DockerV2ListMediaType {
listBlob, err := manifest.ListFromBlob(result, manType)
if err != nil {
return nil, errors.Wrapf(err, "error parsing manifest blob %q as a %q", string(result), manType)
}
list, err := listBlob.ConvertToMIMEType(manifest.DockerV2ListMediaType)
if err != nil {
return nil, err
}
if result, err = list.Serialize(); err != nil {
return nil, err
}
}
err = json.Indent(&b, result, "", " ")
if err != nil {
return nil, errors.Wrapf(err, "error rendering manifest %s for display", name)
}
return b.Bytes(), nil
} }
// ManifestAdd adds images to the manifest list // ManifestAdd adds images to the manifest list

View File

@ -8,6 +8,7 @@ import (
. "github.com/containers/podman/v2/test/utils" . "github.com/containers/podman/v2/test/utils"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
) )
var _ = Describe("Podman manifest", func() { var _ = Describe("Podman manifest", func() {
@ -49,6 +50,16 @@ var _ = Describe("Podman manifest", func() {
Expect(session.ExitCode()).To(Equal(0)) Expect(session.ExitCode()).To(Equal(0))
}) })
It("podman manifest inspect", func() {
session := podmanTest.Podman([]string{"manifest", "inspect", BB})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.PodmanNoCache([]string{"manifest", "inspect", "docker.io/library/busybox"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
It("podman manifest add", func() { It("podman manifest add", func() {
session := podmanTest.Podman([]string{"manifest", "create", "foo"}) session := podmanTest.Podman([]string{"manifest", "create", "foo"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()