diff --git a/cmd/podman/secrets/create.go b/cmd/podman/secrets/create.go index 9e720f22b9..cae95d29c2 100644 --- a/cmd/podman/secrets/create.go +++ b/cmd/podman/secrets/create.go @@ -55,6 +55,8 @@ func init() { envFlagName := "env" flags.BoolVar(&env, envFlagName, false, "Read secret data from environment variable") + flags.BoolVar(&createOpts.Replace, "replace", false, "If a secret with the same name exists, replace it") + labelFlagName := "label" flags.StringArrayVarP(&labels, labelFlagName, "l", nil, "Specify labels on the secret") _ = createCmd.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone) diff --git a/docs/source/markdown/podman-secret-create.1.md b/docs/source/markdown/podman-secret-create.1.md index 1024a35fdd..428f7cc174 100644 --- a/docs/source/markdown/podman-secret-create.1.md +++ b/docs/source/markdown/podman-secret-create.1.md @@ -40,6 +40,12 @@ Print usage statement. Add label to secret. These labels can be viewed in podman secrete inspect or ls. +#### **--replace**=*false* + +If existing secret with the same name already exists, update the secret. +The `--replace` option does not change secrets within existing containers, only newly created containers. + The default is **false**. + ## EXAMPLES ``` diff --git a/pkg/api/handlers/libpod/secrets.go b/pkg/api/handlers/libpod/secrets.go index ec6b60d953..7c7fd11aeb 100644 --- a/pkg/api/handlers/libpod/secrets.go +++ b/pkg/api/handlers/libpod/secrets.go @@ -24,6 +24,7 @@ func CreateSecret(w http.ResponseWriter, r *http.Request) { Driver string `schema:"driver"` DriverOpts map[string]string `schema:"driveropts"` Labels map[string]string `schema:"labels"` + Replace bool `schema:"replace"` }{ // override any golang type defaults } @@ -36,6 +37,7 @@ func CreateSecret(w http.ResponseWriter, r *http.Request) { opts.Driver = query.Driver opts.DriverOpts = query.DriverOpts opts.Labels = query.Labels + opts.Replace = query.Replace ic := abi.ContainerEngine{Libpod: runtime} report, err := ic.SecretCreate(r.Context(), query.Name, r.Body, opts) diff --git a/pkg/bindings/secrets/types.go b/pkg/bindings/secrets/types.go index 71f8c07c70..4b4244a94d 100644 --- a/pkg/bindings/secrets/types.go +++ b/pkg/bindings/secrets/types.go @@ -28,4 +28,5 @@ type CreateOptions struct { Driver *string DriverOpts map[string]string Labels map[string]string + Replace *bool } diff --git a/pkg/bindings/secrets/types_create_options.go b/pkg/bindings/secrets/types_create_options.go index c9c88e1f34..19ae02d720 100644 --- a/pkg/bindings/secrets/types_create_options.go +++ b/pkg/bindings/secrets/types_create_options.go @@ -76,3 +76,18 @@ func (o *CreateOptions) GetLabels() map[string]string { } return o.Labels } + +// WithReplace set field Replace to given value +func (o *CreateOptions) WithReplace(value bool) *CreateOptions { + o.Replace = &value + return o +} + +// GetReplace returns value of field Replace +func (o *CreateOptions) GetReplace() bool { + if o.Replace == nil { + var z bool + return z + } + return *o.Replace +} diff --git a/pkg/domain/entities/secrets.go b/pkg/domain/entities/secrets.go index b485ca1d5d..66e1857361 100644 --- a/pkg/domain/entities/secrets.go +++ b/pkg/domain/entities/secrets.go @@ -14,6 +14,7 @@ type SecretCreateOptions struct { Driver string DriverOpts map[string]string Labels map[string]string + Replace bool } type SecretInspectOptions struct { diff --git a/pkg/domain/infra/abi/secrets.go b/pkg/domain/infra/abi/secrets.go index 1efb45434e..a3228d0bf0 100644 --- a/pkg/domain/infra/abi/secrets.go +++ b/pkg/domain/infra/abi/secrets.go @@ -46,6 +46,7 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader storeOpts := secrets.StoreOptions{ DriverOpts: options.DriverOpts, Labels: options.Labels, + Replace: options.Replace, } secretID, err := manager.Store(name, data, options.Driver, storeOpts) @@ -86,10 +87,13 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string if secret.Labels == nil { secret.Labels = make(map[string]string) } + if secret.UpdatedAt.IsZero() { + secret.UpdatedAt = secret.CreatedAt + } report := &entities.SecretInfoReport{ ID: secret.ID, CreatedAt: secret.CreatedAt, - UpdatedAt: secret.CreatedAt, + UpdatedAt: secret.UpdatedAt, Spec: entities.SecretSpec{ Name: secret.Name, Driver: entities.SecretDriverSpec{ diff --git a/pkg/domain/infra/tunnel/secrets.go b/pkg/domain/infra/tunnel/secrets.go index faf0b0d432..d1fd6486ca 100644 --- a/pkg/domain/infra/tunnel/secrets.go +++ b/pkg/domain/infra/tunnel/secrets.go @@ -15,7 +15,8 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader WithDriver(options.Driver). WithDriverOpts(options.DriverOpts). WithName(name). - WithLabels(options.Labels) + WithLabels(options.Labels). + WithReplace(options.Replace) created, err := secrets.Create(ic.ClientCtx, reader, opts) if err != nil { return nil, err @@ -37,7 +38,7 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string return nil, nil, err } if errModel.ResponseCode == 404 { - errs = append(errs, fmt.Errorf("no such secret %q", name)) + errs = append(errs, fmt.Errorf("no secret with name or id %q: no such secret ", name)) continue } return nil, nil, err diff --git a/test/e2e/secret_test.go b/test/e2e/secret_test.go index a93b3d8c1a..b7f0b79661 100644 --- a/test/e2e/secret_test.go +++ b/test/e2e/secret_test.go @@ -36,6 +36,26 @@ var _ = Describe("Podman secret", func() { inspect.WaitWithDefaultTimeout() Expect(inspect).Should(Exit(0)) Expect(inspect.OutputToString()).To(ContainSubstring("opt1:val")) + + session = podmanTest.Podman([]string{"secret", "create", "-d", "file", "--driver-opts", "opt1=val1", "a", secretFilePath}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(125)) + Expect(session.ErrorToString()).To(Equal("Error: a: secret name in use")) + + session = podmanTest.Podman([]string{"secret", "create", "-d", "file", "--driver-opts", "opt1=val1", "--replace", "a", secretFilePath}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(Not(Equal(secrID))) + + inspect = podmanTest.Podman([]string{"secret", "inspect", "-f", "{{.Spec.Driver.Options}}", secrID}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).To(ExitWithError()) + Expect(inspect.ErrorToString()).To(ContainSubstring(fmt.Sprintf("Error: inspecting secret: no secret with name or id %q: no such secret", secrID))) + + inspect = podmanTest.Podman([]string{"secret", "inspect", "-f", "{{.Spec.Driver.Options}}", "a"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring("opt1:val1")) }) It("podman secret create bad name should fail", func() {