Extend flags of manifest add

Extend the flags of `podman manifest add` to include also:

  * cert-dir
  * auth-file
  * creds
  * tls-verify

These options are useful when adding to a manifest an image that is not
part of the local image store. The image resides on a remote registry
that falls into one of these cases: it's not using tls termination, it requires
authentication or it's secured with an unknown tls certificate.

Consider the following scenario: a multi architecture manifest is created as
part of a multi-step CI pipeline running in a containerized way.
All the images referenced by the manifest live inside of a registry
secured with a self-signed tls certificate.

Without this patch the manifest creation step would have to pull all the
multi-architecture images locally via `podman pull`.

With this patch the usage of `podman pull` would not be needed because the
images' digests can be requested straight to the registry. That means the
execution of manifest creation step would be faster and result in less disk
space and network bandwidth being used.

Finally, this is a propagation of a similar fix done inside of buildah
via https://github.com/containers/buildah/pull/2593

Signed-off-by: Flavio Castelli <fcastelli@suse.com>
This commit is contained in:
Flavio Castelli
2020-09-09 12:33:11 +02:00
parent be7778df6c
commit 1158025ef8
3 changed files with 78 additions and 11 deletions

View File

@ -4,14 +4,26 @@ import (
"context"
"fmt"
"github.com/containers/common/pkg/auth"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// manifestAddOptsWrapper wraps entities.ManifestAddOptions and prevents leaking
// CLI-only fields into the API types.
type manifestAddOptsWrapper struct {
entities.ManifestAddOptions
TLSVerifyCLI bool // CLI only
CredentialsCLI string
}
var (
manifestAddOpts = entities.ManifestAddOptions{}
manifestAddOpts = manifestAddOptsWrapper{}
addCmd = &cobra.Command{
Use: "add [flags] LIST LIST",
Short: "Add images to a manifest list or image index",
@ -33,15 +45,48 @@ func init() {
flags.BoolVar(&manifestAddOpts.All, "all", false, "add all of the list's images if the image is a list")
flags.StringSliceVar(&manifestAddOpts.Annotation, "annotation", nil, "set an `annotation` for the specified image")
flags.StringVar(&manifestAddOpts.Arch, "arch", "", "override the `architecture` of the specified image")
flags.StringVar(&manifestAddOpts.Authfile, "authfile", auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&manifestAddOpts.CertDir, "cert-dir", "", "use certificates at the specified path to access the registry")
flags.StringVar(&manifestAddOpts.CredentialsCLI, "creds", "", "use `[username[:password]]` for accessing the registry")
flags.StringSliceVar(&manifestAddOpts.Features, "features", nil, "override the `features` of the specified image")
flags.StringVar(&manifestAddOpts.OS, "os", "", "override the `OS` of the specified image")
flags.StringVar(&manifestAddOpts.OSVersion, "os-version", "", "override the OS `version` of the specified image")
flags.BoolVar(&manifestAddOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
flags.StringVar(&manifestAddOpts.Variant, "variant", "", "override the `Variant` of the specified image")
if registry.IsRemote() {
_ = flags.MarkHidden("authfile")
_ = flags.MarkHidden("cert-dir")
_ = flags.MarkHidden("tls-verify")
}
}
func add(cmd *cobra.Command, args []string) error {
if err := auth.CheckAuthFile(manifestPushOpts.Authfile); err != nil {
return err
}
manifestAddOpts.Images = []string{args[1], args[0]}
listID, err := registry.ImageEngine().ManifestAdd(context.Background(), manifestAddOpts)
if manifestAddOpts.CredentialsCLI != "" {
creds, err := util.ParseRegistryCreds(manifestAddOpts.CredentialsCLI)
if err != nil {
return err
}
manifestAddOpts.Username = creds.Username
manifestAddOpts.Password = creds.Password
}
// TLS verification in c/image is controlled via a `types.OptionalBool`
// which allows for distinguishing among set-true, set-false, unspecified
// which is important to implement a sane way of dealing with defaults of
// boolean CLI flags.
if cmd.Flags().Changed("tls-verify") {
manifestAddOpts.SkipTLSVerify = types.NewOptionalBool(!manifestAddOpts.TLSVerifyCLI)
}
listID, err := registry.ImageEngine().ManifestAdd(context.Background(), manifestAddOpts.ManifestAddOptions)
if err != nil {
return errors.Wrapf(err, "error adding to manifest list %s", args[0])
}

View File

@ -9,14 +9,19 @@ type ManifestCreateOptions struct {
}
type ManifestAddOptions struct {
All bool `json:"all" schema:"all"`
Annotation []string `json:"annotation" schema:"annotation"`
Arch string `json:"arch" schema:"arch"`
Features []string `json:"features" schema:"features"`
Images []string `json:"images" schema:"images"`
OS string `json:"os" schema:"os"`
OSVersion string `json:"os_version" schema:"os_version"`
Variant string `json:"variant" schema:"variant"`
All bool `json:"all" schema:"all"`
Annotation []string `json:"annotation" schema:"annotation"`
Arch string `json:"arch" schema:"arch"`
Authfile string `json:"-" schema:"-"`
CertDir string `json:"-" schema:"-"`
Features []string `json:"features" schema:"features"`
Images []string `json:"images" schema:"images"`
OS string `json:"os" schema:"os"`
OSVersion string `json:"os_version" schema:"os_version"`
Password string `json:"-" schema:"-"`
SkipTLSVerify types.OptionalBool `json:"-" schema:"-"`
Username string `json:"-" schema:"-"`
Variant string `json:"variant" schema:"variant"`
}
type ManifestAnnotateOptions struct {

View File

@ -102,7 +102,24 @@ func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAd
}
manifestAddOpts.Annotation = annotations
}
listID, err := listImage.AddManifest(*ir.Libpod.SystemContext(), manifestAddOpts)
// Set the system context.
sys := ir.Libpod.SystemContext()
if sys != nil {
sys = &types.SystemContext{}
}
sys.AuthFilePath = opts.Authfile
sys.DockerInsecureSkipTLSVerify = opts.SkipTLSVerify
sys.DockerCertPath = opts.CertDir
if opts.Username != "" && opts.Password != "" {
sys.DockerAuthConfig = &types.DockerAuthConfig{
Username: opts.Username,
Password: opts.Password,
}
}
listID, err := listImage.AddManifest(*sys, manifestAddOpts)
if err != nil {
return listID, err
}