mirror of https://github.com/containers/podman.git
Merge pull request #15359 from rhatdan/manifest
Add --insecure flag to podman manifest inspect for Docker compatibility
This commit is contained in:
commit
0702b4cf4c
|
@ -3,14 +3,17 @@ package manifest
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/podman/v4/cmd/podman/common"
|
||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||
"github.com/containers/podman/v4/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
inspectCmd = &cobra.Command{
|
||||
Use: "inspect IMAGE",
|
||||
tlsVerifyCLI bool
|
||||
inspectCmd = &cobra.Command{
|
||||
Use: "inspect [options] IMAGE",
|
||||
Short: "Display the contents of a manifest list or image index",
|
||||
Long: "Display the contents of a manifest list or image index.",
|
||||
RunE: inspect,
|
||||
|
@ -25,10 +28,24 @@ func init() {
|
|||
Command: inspectCmd,
|
||||
Parent: manifestCmd,
|
||||
})
|
||||
flags := inspectCmd.Flags()
|
||||
|
||||
flags.Bool("verbose", false, "Added for Docker compatibility")
|
||||
_ = flags.MarkHidden("verbose")
|
||||
flags.BoolVar(&tlsVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
|
||||
flags.Bool("insecure", false, "Purely for Docker compatibility")
|
||||
_ = flags.MarkHidden("insecure")
|
||||
}
|
||||
|
||||
func inspect(cmd *cobra.Command, args []string) error {
|
||||
buf, err := registry.ImageEngine().ManifestInspect(registry.Context(), args[0])
|
||||
opts := entities.ManifestInspectOptions{}
|
||||
if cmd.Flags().Changed("tls-verify") {
|
||||
opts.SkipTLSVerify = types.NewOptionalBool(!tlsVerifyCLI)
|
||||
} else if cmd.Flags().Changed("insecure") {
|
||||
insecure, _ := cmd.Flags().GetBool("insecure")
|
||||
opts.SkipTLSVerify = types.NewOptionalBool(insecure)
|
||||
}
|
||||
buf, err := registry.ImageEngine().ManifestInspect(registry.Context(), args[0], opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ podman-manifest-add.1.md
|
|||
podman-manifest-annotate.1.md
|
||||
podman-manifest-create.1.md
|
||||
podman-manifest-push.1.md
|
||||
podman-manifest-inspect.1.md
|
||||
podman-pause.1.md
|
||||
podman-pod-clone.1.md
|
||||
podman-pod-create.1.md
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
####> This option file is used in:
|
||||
####> podman build, container runlabel, create, kube play, login, manifest add, manifest create, manifest push, pull, push, run, search
|
||||
####> podman build, container runlabel, create, kube play, login, manifest add, manifest create, manifest inspect, manifest push, pull, push, run, search
|
||||
####> If you edit this file, make sure your changes
|
||||
####> are applicable to all of those.
|
||||
#### **--tls-verify**
|
||||
|
|
|
@ -4,16 +4,19 @@
|
|||
podman\-manifest\-inspect - Display a manifest list or image index
|
||||
|
||||
## SYNOPSIS
|
||||
**podman manifest inspect** *listnameorindexname*
|
||||
**podman manifest inspect** [*options*] *listnameorindexname*
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Displays the manifest list or image index stored using the specified image name.
|
||||
|
||||
## RETURN VALUE
|
||||
|
||||
A formatted JSON representation of the manifest list or image index.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
@@option tls-verify
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
```
|
|
@ -139,10 +139,26 @@ func ManifestExists(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func ManifestInspect(w http.ResponseWriter, r *http.Request) {
|
||||
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||
name := utils.GetName(r)
|
||||
// Wrapper to support 3.x with 4.x libpod
|
||||
query := struct {
|
||||
TLSVerify bool `schema:"tlsVerify"`
|
||||
}{}
|
||||
|
||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||
utils.Error(w, http.StatusBadRequest,
|
||||
fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
|
||||
return
|
||||
}
|
||||
|
||||
imageEngine := abi.ImageEngine{Libpod: runtime}
|
||||
rawManifest, err := imageEngine.ManifestInspect(r.Context(), name)
|
||||
opts := entities.ManifestInspectOptions{}
|
||||
if _, found := r.URL.Query()["tlsVerify"]; found {
|
||||
opts.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
|
||||
}
|
||||
|
||||
rawManifest, err := imageEngine.ManifestInspect(r.Context(), name, opts)
|
||||
if err != nil {
|
||||
utils.Error(w, http.StatusNotFound, err)
|
||||
return
|
||||
|
|
|
@ -175,6 +175,11 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error {
|
|||
// type: string
|
||||
// required: true
|
||||
// description: the name or ID of the manifest list
|
||||
// - in: query
|
||||
// name: tlsVerify
|
||||
// type: boolean
|
||||
// default: true
|
||||
// description: Require HTTPS and verify signatures when contacting registries.
|
||||
// responses:
|
||||
// 200:
|
||||
// $ref: "#/responses/manifestInspect"
|
||||
|
|
|
@ -71,13 +71,27 @@ func Exists(ctx context.Context, name string, options *ExistsOptions) (bool, err
|
|||
}
|
||||
|
||||
// Inspect returns a manifest list for a given name.
|
||||
func Inspect(ctx context.Context, name string, _ *InspectOptions) (*manifest.Schema2List, error) {
|
||||
func Inspect(ctx context.Context, name string, options *InspectOptions) (*manifest.Schema2List, error) {
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if options == nil {
|
||||
options = new(InspectOptions)
|
||||
}
|
||||
|
||||
response, err := conn.DoRequest(ctx, nil, http.MethodGet, "/manifests/%s/json", nil, nil, name)
|
||||
params, err := options.ToParams()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// SkipTLSVerify is special. We need to delete the param added by
|
||||
// ToParams() and change the key and flip the bool
|
||||
if options.SkipTLSVerify != nil {
|
||||
params.Del("SkipTLSVerify")
|
||||
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
|
||||
}
|
||||
|
||||
response, err := conn.DoRequest(ctx, nil, http.MethodGet, "/manifests/%s/json", params, nil, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package manifests
|
|||
//
|
||||
//go:generate go run ../generator/generator.go InspectOptions
|
||||
type InspectOptions struct {
|
||||
SkipTLSVerify *bool
|
||||
}
|
||||
|
||||
// CreateOptions are optional options for creating manifests
|
||||
|
|
|
@ -16,3 +16,18 @@ func (o *InspectOptions) Changed(fieldName string) bool {
|
|||
func (o *InspectOptions) ToParams() (url.Values, error) {
|
||||
return util.ToParams(o)
|
||||
}
|
||||
|
||||
// WithSkipTLSVerify set field SkipTLSVerify to given value
|
||||
func (o *InspectOptions) WithSkipTLSVerify(value bool) *InspectOptions {
|
||||
o.SkipTLSVerify = &value
|
||||
return o
|
||||
}
|
||||
|
||||
// GetSkipTLSVerify returns value of field SkipTLSVerify
|
||||
func (o *InspectOptions) GetSkipTLSVerify() bool {
|
||||
if o.SkipTLSVerify == nil {
|
||||
var z bool
|
||||
return z
|
||||
}
|
||||
return *o.SkipTLSVerify
|
||||
}
|
||||
|
|
|
@ -34,7 +34,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) ([]byte, error)
|
||||
ManifestInspect(ctx context.Context, name string, opts ManifestInspectOptions) ([]byte, error)
|
||||
ManifestAdd(ctx context.Context, listName string, imageNames []string, opts ManifestAddOptions) (string, error)
|
||||
ManifestAnnotate(ctx context.Context, names, image string, opts ManifestAnnotateOptions) (string, error)
|
||||
ManifestRemoveDigest(ctx context.Context, names, image string) (string, error)
|
||||
|
|
|
@ -12,6 +12,12 @@ type ManifestCreateOptions struct {
|
|||
SkipTLSVerify types.OptionalBool `json:"-" schema:"-"`
|
||||
}
|
||||
|
||||
// ManifestInspectOptions provides model for inspecting manifest
|
||||
type ManifestInspectOptions struct {
|
||||
// Should TLS registry certificate be verified?
|
||||
SkipTLSVerify types.OptionalBool `json:"-" schema:"-"`
|
||||
}
|
||||
|
||||
// ManifestAddOptions provides model for adding digests to manifest list
|
||||
//
|
||||
// swagger:model
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/containers/image/v5/pkg/shortnames"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/transports/alltransports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/podman/v4/pkg/domain/entities"
|
||||
"github.com/containers/storage"
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
@ -67,7 +68,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) ([]byte, error) {
|
||||
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string, opts entities.ManifestInspectOptions) ([]byte, 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.
|
||||
|
@ -77,7 +78,7 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
|
|||
if errors.Is(err, storage.ErrImageUnknown) || errors.Is(err, libimage.ErrNotAManifestList) {
|
||||
// Do a remote inspect if there's no local image or if the
|
||||
// local image is not a manifest list.
|
||||
return ir.remoteManifestInspect(ctx, name)
|
||||
return ir.remoteManifestInspect(ctx, name, opts)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
|
@ -101,9 +102,14 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
|
|||
}
|
||||
|
||||
// inspect a remote manifest list.
|
||||
func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string) ([]byte, error) {
|
||||
func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string, opts entities.ManifestInspectOptions) ([]byte, error) {
|
||||
sys := ir.Libpod.SystemContext()
|
||||
|
||||
sys.DockerInsecureSkipTLSVerify = opts.SkipTLSVerify
|
||||
if opts.SkipTLSVerify == types.OptionalBoolTrue {
|
||||
sys.OCIInsecureSkipTLSVerify = true
|
||||
}
|
||||
|
||||
resolved, err := shortnames.Resolve(sys, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -33,8 +33,17 @@ func (ir *ImageEngine) ManifestExists(ctx context.Context, name string) (*entiti
|
|||
}
|
||||
|
||||
// ManifestInspect returns contents of manifest list with given name
|
||||
func (ir *ImageEngine) ManifestInspect(_ context.Context, name string) ([]byte, error) {
|
||||
list, err := manifests.Inspect(ir.ClientCtx, name, nil)
|
||||
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string, opts entities.ManifestInspectOptions) ([]byte, error) {
|
||||
options := new(manifests.InspectOptions)
|
||||
if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
|
||||
if s == types.OptionalBoolTrue {
|
||||
options.WithSkipTLSVerify(true)
|
||||
} else {
|
||||
options.WithSkipTLSVerify(false)
|
||||
}
|
||||
}
|
||||
|
||||
list, err := manifests.Inspect(ir.ClientCtx, name, options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting content of manifest list or image %s: %w", name, err)
|
||||
}
|
||||
|
|
|
@ -232,20 +232,6 @@ Labels.created_at | 20[0-9-]\\\+T[0-9:]\\\+Z
|
|||
run_podman rmi ${aaa_name}:${aaa_tag} ${zzz_name}:${zzz_tag}
|
||||
}
|
||||
|
||||
# Regression test for #8931
|
||||
@test "podman images - bare manifest list" {
|
||||
# Create an empty manifest list and list images.
|
||||
|
||||
run_podman inspect --format '{{.ID}}' $IMAGE
|
||||
iid=$output
|
||||
|
||||
run_podman manifest create test:1.0
|
||||
run_podman images --format '{{.ID}}' --no-trunc
|
||||
[[ "$output" == *"sha256:$iid"* ]]
|
||||
|
||||
run_podman rmi test:1.0
|
||||
}
|
||||
|
||||
@test "podman images - rmi -af removes all containers and pods" {
|
||||
pname=$(random_string)
|
||||
run_podman create --pod new:$pname $IMAGE
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
load helpers
|
||||
|
||||
# Regression test for #8931
|
||||
@test "podman images - bare manifest list" {
|
||||
# Create an empty manifest list and list images.
|
||||
|
||||
run_podman inspect --format '{{.ID}}' $IMAGE
|
||||
iid=$output
|
||||
|
||||
run_podman manifest create test:1.0
|
||||
run_podman manifest inspect --verbose $output
|
||||
is "$output" ".*\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\"" "--insecure is a noop want to make sure manifest inspect is successful"
|
||||
run_podman images --format '{{.ID}}' --no-trunc
|
||||
is "$output" ".*sha256:$iid" "Original image ID still shown in podman-images output"
|
||||
run_podman rmi test:1.0
|
||||
}
|
||||
|
||||
# vim: filetype=sh
|
|
@ -290,6 +290,35 @@ function _test_skopeo_credential_sharing() {
|
|||
rm -f $authfile
|
||||
}
|
||||
|
||||
@test "podman manifest --tls-verify - basic test" {
|
||||
run_podman login --tls-verify=false \
|
||||
--username ${PODMAN_LOGIN_USER} \
|
||||
--password-stdin \
|
||||
localhost:${PODMAN_LOGIN_REGISTRY_PORT} <<<"${PODMAN_LOGIN_PASS}"
|
||||
is "$output" "Login Succeeded!" "output from podman login"
|
||||
|
||||
manifest1="localhost:${PODMAN_LOGIN_REGISTRY_PORT}/test:1.0"
|
||||
run_podman manifest create $manifest1
|
||||
mid=$output
|
||||
run_podman manifest push --authfile=$authfile \
|
||||
--tls-verify=false $mid \
|
||||
$manifest1
|
||||
run_podman manifest rm $manifest1
|
||||
run_podman manifest inspect --insecure $manifest1
|
||||
is "$output" ".*\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\"" "Verify --insecure works against an insecure registry"
|
||||
run_podman 125 manifest inspect --insecure=false $manifest1
|
||||
is "$output" ".*Error: reading image \"docker://$manifest1\": pinging container registry localhost:${PODMAN_LOGIN_REGISTRY_PORT}:" "Verify --insecure=false fails"
|
||||
run_podman manifest inspect --tls-verify=false $manifest1
|
||||
is "$output" ".*\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\"" "Verify --tls-verify=false works against an insecure registry"
|
||||
run_podman 125 manifest inspect --tls-verify=true $manifest1
|
||||
is "$output" ".*Error: reading image \"docker://$manifest1\": pinging container registry localhost:${PODMAN_LOGIN_REGISTRY_PORT}:" "Verify --tls-verify=true fails"
|
||||
|
||||
# Now log out
|
||||
run_podman logout localhost:${PODMAN_LOGIN_REGISTRY_PORT}
|
||||
is "$output" "Removed login credentials for localhost:${PODMAN_LOGIN_REGISTRY_PORT}" \
|
||||
"output from podman logout"
|
||||
}
|
||||
|
||||
# END cooperation with skopeo
|
||||
# END actual tests
|
||||
###############################################################################
|
||||
|
|
Loading…
Reference in New Issue