aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/manifest/add.go12
-rw-r--r--cmd/podman/manifest/create.go32
-rw-r--r--cmd/podman/manifest/push.go15
-rw-r--r--docs/source/markdown/podman-manifest-create.1.md12
-rw-r--r--pkg/api/handlers/libpod/manifests.go3
-rw-r--r--pkg/api/server/register_manifest.go4
-rw-r--r--pkg/bindings/manifests/types.go3
-rw-r--r--pkg/bindings/manifests/types_create_options.go15
-rw-r--r--pkg/domain/entities/manifest.go5
-rw-r--r--pkg/domain/infra/abi/manifest.go10
-rw-r--r--pkg/domain/infra/tunnel/manifest.go2
-rw-r--r--test/e2e/manifest_test.go8
12 files changed, 111 insertions, 10 deletions
diff --git a/cmd/podman/manifest/add.go b/cmd/podman/manifest/add.go
index 35583ffcb..09a1a9a36 100644
--- a/cmd/podman/manifest/add.go
+++ b/cmd/podman/manifest/add.go
@@ -2,6 +2,7 @@ package manifest
import (
"context"
+ "errors"
"fmt"
"github.com/containers/common/pkg/auth"
@@ -20,6 +21,7 @@ type manifestAddOptsWrapper struct {
entities.ManifestAddOptions
TLSVerifyCLI bool // CLI only
+ Insecure bool // CLI only
CredentialsCLI string
}
@@ -77,6 +79,8 @@ func init() {
flags.StringVar(&manifestAddOpts.OSVersion, osVersionFlagName, "", "override the OS `version` of the specified image")
_ = 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")
variantFlagName := "variant"
@@ -89,7 +93,7 @@ func init() {
}
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
}
@@ -109,6 +113,12 @@ func add(cmd *cobra.Command, args []string) error {
if cmd.Flags().Changed("tls-verify") {
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)
if err != nil {
diff --git a/cmd/podman/manifest/create.go b/cmd/podman/manifest/create.go
index 435b4a57c..0a0ea1d88 100644
--- a/cmd/podman/manifest/create.go
+++ b/cmd/podman/manifest/create.go
@@ -1,16 +1,26 @@
package manifest
import (
+ "errors"
"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"
)
+// 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 (
- manifestCreateOpts = entities.ManifestCreateOptions{}
+ manifestCreateOpts = manifestCreateOptsWrapper{}
createCmd = &cobra.Command{
Use: "create [options] LIST [IMAGE...]",
Short: "Create manifest list or image index",
@@ -32,10 +42,28 @@ func init() {
})
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.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 {
- 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 {
return err
}
diff --git a/cmd/podman/manifest/push.go b/cmd/podman/manifest/push.go
index 756ed2a74..fd67769b8 100644
--- a/cmd/podman/manifest/push.go
+++ b/cmd/podman/manifest/push.go
@@ -1,6 +1,7 @@
package manifest
import (
+ "errors"
"fmt"
"io/ioutil"
@@ -20,9 +21,9 @@ import (
type manifestPushOptsWrapper struct {
entities.ImagePushOptions
- TLSVerifyCLI bool // CLI only
- CredentialsCLI string
- SignPassphraseFileCLI string
+ TLSVerifyCLI, Insecure bool // CLI only
+ CredentialsCLI string
+ SignPassphraseFileCLI string
}
var (
@@ -82,6 +83,8 @@ func init() {
_ = pushCmd.RegisterFlagCompletionFunc(signPassphraseFileFlagName, completion.AutocompleteDefault)
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.SetNormalizeFunc(utils.AliasFlags)
@@ -130,6 +133,12 @@ func push(cmd *cobra.Command, args []string) error {
if cmd.Flags().Changed("tls-verify") {
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)
if err != nil {
return err
diff --git a/docs/source/markdown/podman-manifest-create.1.md b/docs/source/markdown/podman-manifest-create.1.md
index 77a4b9db6..f2aac6069 100644
--- a/docs/source/markdown/podman-manifest-create.1.md
+++ b/docs/source/markdown/podman-manifest-create.1.md
@@ -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
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
```
podman manifest create mylist:v1.11
9cfd24048d5fc80903f088f1531a21bff01172abe66effa8941a4c2308dc745f
+podman manifest create --amend mylist:v1.11
+9cfd24048d5fc80903f088f1531a21bff01172abe66effa8941a4c2308dc745f
```
```
diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go
index b0c93f3b9..fa83bbfe1 100644
--- a/pkg/api/handlers/libpod/manifests.go
+++ b/pkg/api/handlers/libpod/manifests.go
@@ -36,6 +36,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) {
Name string `schema:"name"`
Images []string `schema:"images"`
All bool `schema:"all"`
+ Amend bool `schema:"amend"`
}{
// Add defaults here once needed.
}
@@ -70,7 +71,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) {
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)
if err != nil {
utils.InternalServerError(w, err)
diff --git a/pkg/api/server/register_manifest.go b/pkg/api/server/register_manifest.go
index c22479cf9..7a55eaefe 100644
--- a/pkg/api/server/register_manifest.go
+++ b/pkg/api/server/register_manifest.go
@@ -117,6 +117,10 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error {
// name: all
// type: boolean
// 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
// name: options
// description: options for new manifest
diff --git a/pkg/bindings/manifests/types.go b/pkg/bindings/manifests/types.go
index e23ef798d..5f2557fe1 100644
--- a/pkg/bindings/manifests/types.go
+++ b/pkg/bindings/manifests/types.go
@@ -8,7 +8,8 @@ type InspectOptions struct {
//go:generate go run ../generator/generator.go CreateOptions
// CreateOptions are optional options for creating manifests
type CreateOptions struct {
- All *bool
+ All *bool
+ Amend *bool
}
//go:generate go run ../generator/generator.go ExistsOptions
diff --git a/pkg/bindings/manifests/types_create_options.go b/pkg/bindings/manifests/types_create_options.go
index 960332a82..09942c00a 100644
--- a/pkg/bindings/manifests/types_create_options.go
+++ b/pkg/bindings/manifests/types_create_options.go
@@ -31,3 +31,18 @@ func (o *CreateOptions) GetAll() bool {
}
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
+}
diff --git a/pkg/domain/entities/manifest.go b/pkg/domain/entities/manifest.go
index 126b76c62..f17079271 100644
--- a/pkg/domain/entities/manifest.go
+++ b/pkg/domain/entities/manifest.go
@@ -4,7 +4,12 @@ import "github.com/containers/image/v5/types"
// ManifestCreateOptions provides model for creating manifest
type ManifestCreateOptions struct {
+ // True when adding lists to include all images
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
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index e0c11267e..7e8c86526 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -32,7 +32,15 @@ func (ir *ImageEngine) ManifestCreate(ctx context.Context, name string, images [
manifestList, err := ir.Libpod.LibimageRuntime().CreateManifestList(name)
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}
diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go
index 2a514861d..2e6134051 100644
--- a/pkg/domain/infra/tunnel/manifest.go
+++ b/pkg/domain/infra/tunnel/manifest.go
@@ -15,7 +15,7 @@ import (
// ManifestCreate implements manifest create via ImageEngine
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)
if err != nil {
return imageID, fmt.Errorf("error creating manifest: %w", err)
diff --git a/test/e2e/manifest_test.go b/test/e2e/manifest_test.go
index ee954a1a4..145a016ea 100644
--- a/test/e2e/manifest_test.go
+++ b/test/e2e/manifest_test.go
@@ -49,6 +49,14 @@ var _ = Describe("Podman manifest", func() {
session := podmanTest.Podman([]string{"manifest", "create", "foo"})
session.WaitWithDefaultTimeout()
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() {