mirror of https://github.com/containers/podman.git
Merge pull request #15350 from nalind/manifest-amend
podman manifest create: accept --amend and --insecure flags
This commit is contained in:
commit
a9131050cf
|
@ -2,6 +2,7 @@ package manifest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/auth"
|
"github.com/containers/common/pkg/auth"
|
||||||
|
@ -20,6 +21,7 @@ type manifestAddOptsWrapper struct {
|
||||||
entities.ManifestAddOptions
|
entities.ManifestAddOptions
|
||||||
|
|
||||||
TLSVerifyCLI bool // CLI only
|
TLSVerifyCLI bool // CLI only
|
||||||
|
Insecure bool // CLI only
|
||||||
CredentialsCLI string
|
CredentialsCLI string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +79,8 @@ func init() {
|
||||||
flags.StringVar(&manifestAddOpts.OSVersion, osVersionFlagName, "", "override the OS `version` of the specified image")
|
flags.StringVar(&manifestAddOpts.OSVersion, osVersionFlagName, "", "override the OS `version` of the specified image")
|
||||||
_ = addCmd.RegisterFlagCompletionFunc(osVersionFlagName, completion.AutocompleteNone)
|
_ = addCmd.RegisterFlagCompletionFunc(osVersionFlagName, completion.AutocompleteNone)
|
||||||
|
|
||||||
|
flags.BoolVar(&manifestAddOpts.Insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry")
|
||||||
|
_ = flags.MarkHidden("insecure")
|
||||||
flags.BoolVar(&manifestAddOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
|
flags.BoolVar(&manifestAddOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
|
||||||
|
|
||||||
variantFlagName := "variant"
|
variantFlagName := "variant"
|
||||||
|
@ -89,7 +93,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func add(cmd *cobra.Command, args []string) error {
|
func add(cmd *cobra.Command, args []string) error {
|
||||||
if err := auth.CheckAuthFile(manifestPushOpts.Authfile); err != nil {
|
if err := auth.CheckAuthFile(manifestAddOpts.Authfile); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +113,12 @@ func add(cmd *cobra.Command, args []string) error {
|
||||||
if cmd.Flags().Changed("tls-verify") {
|
if cmd.Flags().Changed("tls-verify") {
|
||||||
manifestAddOpts.SkipTLSVerify = types.NewOptionalBool(!manifestAddOpts.TLSVerifyCLI)
|
manifestAddOpts.SkipTLSVerify = types.NewOptionalBool(!manifestAddOpts.TLSVerifyCLI)
|
||||||
}
|
}
|
||||||
|
if cmd.Flags().Changed("insecure") {
|
||||||
|
if manifestAddOpts.SkipTLSVerify != types.OptionalBoolUndefined {
|
||||||
|
return errors.New("--insecure may not be used with --tls-verify")
|
||||||
|
}
|
||||||
|
manifestAddOpts.SkipTLSVerify = types.NewOptionalBool(manifestAddOpts.Insecure)
|
||||||
|
}
|
||||||
|
|
||||||
listID, err := registry.ImageEngine().ManifestAdd(context.Background(), args[0], args[1:], manifestAddOpts.ManifestAddOptions)
|
listID, err := registry.ImageEngine().ManifestAdd(context.Background(), args[0], args[1:], manifestAddOpts.ManifestAddOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,16 +1,26 @@
|
||||||
package manifest
|
package manifest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/podman/v4/cmd/podman/common"
|
"github.com/containers/podman/v4/cmd/podman/common"
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
"github.com/containers/podman/v4/pkg/domain/entities"
|
"github.com/containers/podman/v4/pkg/domain/entities"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// manifestCreateOptsWrapper wraps entities.ManifestCreateOptions and prevents leaking
|
||||||
|
// CLI-only fields into the API types.
|
||||||
|
type manifestCreateOptsWrapper struct {
|
||||||
|
entities.ManifestCreateOptions
|
||||||
|
|
||||||
|
TLSVerifyCLI, Insecure bool // CLI only
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
manifestCreateOpts = entities.ManifestCreateOptions{}
|
manifestCreateOpts = manifestCreateOptsWrapper{}
|
||||||
createCmd = &cobra.Command{
|
createCmd = &cobra.Command{
|
||||||
Use: "create [options] LIST [IMAGE...]",
|
Use: "create [options] LIST [IMAGE...]",
|
||||||
Short: "Create manifest list or image index",
|
Short: "Create manifest list or image index",
|
||||||
|
@ -32,10 +42,28 @@ func init() {
|
||||||
})
|
})
|
||||||
flags := createCmd.Flags()
|
flags := createCmd.Flags()
|
||||||
flags.BoolVar(&manifestCreateOpts.All, "all", false, "add all of the lists' images if the images to add are lists")
|
flags.BoolVar(&manifestCreateOpts.All, "all", false, "add all of the lists' images if the images to add are lists")
|
||||||
|
flags.BoolVar(&manifestCreateOpts.Amend, "amend", false, "modify an existing list if one with the desired name already exists")
|
||||||
|
flags.BoolVar(&manifestCreateOpts.Insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry")
|
||||||
|
_ = flags.MarkHidden("insecure")
|
||||||
|
flags.BoolVar(&manifestCreateOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
|
||||||
}
|
}
|
||||||
|
|
||||||
func create(cmd *cobra.Command, args []string) error {
|
func create(cmd *cobra.Command, args []string) error {
|
||||||
imageID, err := registry.ImageEngine().ManifestCreate(registry.Context(), args[0], args[1:], manifestCreateOpts)
|
// 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") {
|
||||||
|
manifestCreateOpts.SkipTLSVerify = types.NewOptionalBool(!manifestCreateOpts.TLSVerifyCLI)
|
||||||
|
}
|
||||||
|
if cmd.Flags().Changed("insecure") {
|
||||||
|
if manifestCreateOpts.SkipTLSVerify != types.OptionalBoolUndefined {
|
||||||
|
return errors.New("--insecure may not be used with --tls-verify")
|
||||||
|
}
|
||||||
|
manifestCreateOpts.SkipTLSVerify = types.NewOptionalBool(manifestCreateOpts.Insecure)
|
||||||
|
}
|
||||||
|
|
||||||
|
imageID, err := registry.ImageEngine().ManifestCreate(registry.Context(), args[0], args[1:], manifestCreateOpts.ManifestCreateOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package manifest
|
package manifest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
|
@ -20,9 +21,9 @@ import (
|
||||||
type manifestPushOptsWrapper struct {
|
type manifestPushOptsWrapper struct {
|
||||||
entities.ImagePushOptions
|
entities.ImagePushOptions
|
||||||
|
|
||||||
TLSVerifyCLI bool // CLI only
|
TLSVerifyCLI, Insecure bool // CLI only
|
||||||
CredentialsCLI string
|
CredentialsCLI string
|
||||||
SignPassphraseFileCLI string
|
SignPassphraseFileCLI string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -82,6 +83,8 @@ func init() {
|
||||||
_ = pushCmd.RegisterFlagCompletionFunc(signPassphraseFileFlagName, completion.AutocompleteDefault)
|
_ = pushCmd.RegisterFlagCompletionFunc(signPassphraseFileFlagName, completion.AutocompleteDefault)
|
||||||
|
|
||||||
flags.BoolVar(&manifestPushOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
|
flags.BoolVar(&manifestPushOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
|
||||||
|
flags.BoolVar(&manifestPushOpts.Insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry")
|
||||||
|
_ = flags.MarkHidden("insecure")
|
||||||
flags.BoolVarP(&manifestPushOpts.Quiet, "quiet", "q", false, "don't output progress information when pushing lists")
|
flags.BoolVarP(&manifestPushOpts.Quiet, "quiet", "q", false, "don't output progress information when pushing lists")
|
||||||
flags.SetNormalizeFunc(utils.AliasFlags)
|
flags.SetNormalizeFunc(utils.AliasFlags)
|
||||||
|
|
||||||
|
@ -130,6 +133,12 @@ func push(cmd *cobra.Command, args []string) error {
|
||||||
if cmd.Flags().Changed("tls-verify") {
|
if cmd.Flags().Changed("tls-verify") {
|
||||||
manifestPushOpts.SkipTLSVerify = types.NewOptionalBool(!manifestPushOpts.TLSVerifyCLI)
|
manifestPushOpts.SkipTLSVerify = types.NewOptionalBool(!manifestPushOpts.TLSVerifyCLI)
|
||||||
}
|
}
|
||||||
|
if cmd.Flags().Changed("insecure") {
|
||||||
|
if manifestPushOpts.SkipTLSVerify != types.OptionalBoolUndefined {
|
||||||
|
return errors.New("--insecure may not be used with --tls-verify")
|
||||||
|
}
|
||||||
|
manifestPushOpts.SkipTLSVerify = types.NewOptionalBool(manifestPushOpts.Insecure)
|
||||||
|
}
|
||||||
digest, err := registry.ImageEngine().ManifestPush(registry.Context(), args[0], args[1], manifestPushOpts.ImagePushOptions)
|
digest, err := registry.ImageEngine().ManifestPush(registry.Context(), args[0], args[1], manifestPushOpts.ImagePushOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -22,11 +22,23 @@ If any of the images which should be added to the new list or index are
|
||||||
themselves lists or indexes, add all of their contents. By default, only one
|
themselves lists or indexes, add all of their contents. By default, only one
|
||||||
image from such a list will be added to the newly-created list or index.
|
image from such a list will be added to the newly-created list or index.
|
||||||
|
|
||||||
|
#### **--amend**
|
||||||
|
|
||||||
|
If a manifest list named *listnameorindexname* already exists, modify the
|
||||||
|
preexisting list instead of exiting with an error. The contents of
|
||||||
|
*listnameorindexname* are not modified if no *imagename*s are given.
|
||||||
|
|
||||||
|
#### **--tls-verify**
|
||||||
|
|
||||||
|
Require HTTPS and verify certificates when talking to container registries. (defaults to true)
|
||||||
|
|
||||||
## EXAMPLES
|
## EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
podman manifest create mylist:v1.11
|
podman manifest create mylist:v1.11
|
||||||
9cfd24048d5fc80903f088f1531a21bff01172abe66effa8941a4c2308dc745f
|
9cfd24048d5fc80903f088f1531a21bff01172abe66effa8941a4c2308dc745f
|
||||||
|
podman manifest create --amend mylist:v1.11
|
||||||
|
9cfd24048d5fc80903f088f1531a21bff01172abe66effa8941a4c2308dc745f
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -36,6 +36,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
Name string `schema:"name"`
|
Name string `schema:"name"`
|
||||||
Images []string `schema:"images"`
|
Images []string `schema:"images"`
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
|
Amend bool `schema:"amend"`
|
||||||
}{
|
}{
|
||||||
// Add defaults here once needed.
|
// Add defaults here once needed.
|
||||||
}
|
}
|
||||||
|
@ -70,7 +71,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
imageEngine := abi.ImageEngine{Libpod: runtime}
|
imageEngine := abi.ImageEngine{Libpod: runtime}
|
||||||
|
|
||||||
createOptions := entities.ManifestCreateOptions{All: query.All}
|
createOptions := entities.ManifestCreateOptions{All: query.All, Amend: query.Amend}
|
||||||
manID, err := imageEngine.ManifestCreate(r.Context(), query.Name, query.Images, createOptions)
|
manID, err := imageEngine.ManifestCreate(r.Context(), query.Name, query.Images, createOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
|
|
|
@ -117,6 +117,10 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error {
|
||||||
// name: all
|
// name: all
|
||||||
// type: boolean
|
// type: boolean
|
||||||
// description: add all contents if given list
|
// description: add all contents if given list
|
||||||
|
// - in: query
|
||||||
|
// name: amend
|
||||||
|
// type: boolean
|
||||||
|
// description: modify an existing list if one with the desired name already exists
|
||||||
// - in: body
|
// - in: body
|
||||||
// name: options
|
// name: options
|
||||||
// description: options for new manifest
|
// description: options for new manifest
|
||||||
|
|
|
@ -8,7 +8,8 @@ type InspectOptions struct {
|
||||||
//go:generate go run ../generator/generator.go CreateOptions
|
//go:generate go run ../generator/generator.go CreateOptions
|
||||||
// CreateOptions are optional options for creating manifests
|
// CreateOptions are optional options for creating manifests
|
||||||
type CreateOptions struct {
|
type CreateOptions struct {
|
||||||
All *bool
|
All *bool
|
||||||
|
Amend *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate go run ../generator/generator.go ExistsOptions
|
//go:generate go run ../generator/generator.go ExistsOptions
|
||||||
|
|
|
@ -31,3 +31,18 @@ func (o *CreateOptions) GetAll() bool {
|
||||||
}
|
}
|
||||||
return *o.All
|
return *o.All
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithAmend set field Amend to given value
|
||||||
|
func (o *CreateOptions) WithAmend(value bool) *CreateOptions {
|
||||||
|
o.Amend = &value
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAmend returns value of field Amend
|
||||||
|
func (o *CreateOptions) GetAmend() bool {
|
||||||
|
if o.Amend == nil {
|
||||||
|
var z bool
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
return *o.Amend
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,12 @@ import "github.com/containers/image/v5/types"
|
||||||
|
|
||||||
// ManifestCreateOptions provides model for creating manifest
|
// ManifestCreateOptions provides model for creating manifest
|
||||||
type ManifestCreateOptions struct {
|
type ManifestCreateOptions struct {
|
||||||
|
// True when adding lists to include all images
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
|
// Amend an extant list if there's already one with the desired name
|
||||||
|
Amend bool `schema:"amend"`
|
||||||
|
// Should TLS registry certificate be verified?
|
||||||
|
SkipTLSVerify types.OptionalBool `json:"-" schema:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManifestAddOptions provides model for adding digests to manifest list
|
// ManifestAddOptions provides model for adding digests to manifest list
|
||||||
|
|
|
@ -32,7 +32,15 @@ func (ir *ImageEngine) ManifestCreate(ctx context.Context, name string, images [
|
||||||
|
|
||||||
manifestList, err := ir.Libpod.LibimageRuntime().CreateManifestList(name)
|
manifestList, err := ir.Libpod.LibimageRuntime().CreateManifestList(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
if errors.Is(err, storage.ErrDuplicateName) && opts.Amend {
|
||||||
|
amendList, amendErr := ir.Libpod.LibimageRuntime().LookupManifestList(name)
|
||||||
|
if amendErr != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
manifestList = amendList
|
||||||
|
} else {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addOptions := &libimage.ManifestListAddOptions{All: opts.All}
|
addOptions := &libimage.ManifestListAddOptions{All: opts.All}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
// ManifestCreate implements manifest create via ImageEngine
|
// ManifestCreate implements manifest create via ImageEngine
|
||||||
func (ir *ImageEngine) ManifestCreate(ctx context.Context, name string, images []string, opts entities.ManifestCreateOptions) (string, error) {
|
func (ir *ImageEngine) ManifestCreate(ctx context.Context, name string, images []string, opts entities.ManifestCreateOptions) (string, error) {
|
||||||
options := new(manifests.CreateOptions).WithAll(opts.All)
|
options := new(manifests.CreateOptions).WithAll(opts.All).WithAmend(opts.Amend)
|
||||||
imageID, err := manifests.Create(ir.ClientCtx, name, images, options)
|
imageID, err := manifests.Create(ir.ClientCtx, name, images, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return imageID, fmt.Errorf("error creating manifest: %w", err)
|
return imageID, fmt.Errorf("error creating manifest: %w", err)
|
||||||
|
|
|
@ -49,6 +49,14 @@ var _ = Describe("Podman manifest", func() {
|
||||||
session := podmanTest.Podman([]string{"manifest", "create", "foo"})
|
session := podmanTest.Podman([]string{"manifest", "create", "foo"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(Exit(0))
|
Expect(session).Should(Exit(0))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"manifest", "create", "foo"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).To(ExitWithError())
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"manifest", "create", "--amend", "foo"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("create w/ image", func() {
|
It("create w/ image", func() {
|
||||||
|
|
Loading…
Reference in New Issue