Add --replace flag to podman secret create

Users may want to replace the secret used within containers, without
destroying the secret and recreating it.

Partial fix for https://github.com/containers/podman/issues/18667

Make sure podman --remote secret inspect and podman secret inspect
return the same error message.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh
2023-07-09 07:26:09 -04:00
parent 5d706eb027
commit efefd8cf5b
9 changed files with 55 additions and 3 deletions

View File

@ -55,6 +55,8 @@ func init() {
envFlagName := "env" envFlagName := "env"
flags.BoolVar(&env, envFlagName, false, "Read secret data from environment variable") 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" labelFlagName := "label"
flags.StringArrayVarP(&labels, labelFlagName, "l", nil, "Specify labels on the secret") flags.StringArrayVarP(&labels, labelFlagName, "l", nil, "Specify labels on the secret")
_ = createCmd.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone) _ = createCmd.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone)

View File

@ -40,6 +40,12 @@ Print usage statement.
Add label to secret. These labels can be viewed in podman secrete inspect or ls. 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 ## EXAMPLES
``` ```

View File

@ -24,6 +24,7 @@ func CreateSecret(w http.ResponseWriter, r *http.Request) {
Driver string `schema:"driver"` Driver string `schema:"driver"`
DriverOpts map[string]string `schema:"driveropts"` DriverOpts map[string]string `schema:"driveropts"`
Labels map[string]string `schema:"labels"` Labels map[string]string `schema:"labels"`
Replace bool `schema:"replace"`
}{ }{
// override any golang type defaults // override any golang type defaults
} }
@ -36,6 +37,7 @@ func CreateSecret(w http.ResponseWriter, r *http.Request) {
opts.Driver = query.Driver opts.Driver = query.Driver
opts.DriverOpts = query.DriverOpts opts.DriverOpts = query.DriverOpts
opts.Labels = query.Labels opts.Labels = query.Labels
opts.Replace = query.Replace
ic := abi.ContainerEngine{Libpod: runtime} ic := abi.ContainerEngine{Libpod: runtime}
report, err := ic.SecretCreate(r.Context(), query.Name, r.Body, opts) report, err := ic.SecretCreate(r.Context(), query.Name, r.Body, opts)

View File

@ -28,4 +28,5 @@ type CreateOptions struct {
Driver *string Driver *string
DriverOpts map[string]string DriverOpts map[string]string
Labels map[string]string Labels map[string]string
Replace *bool
} }

View File

@ -76,3 +76,18 @@ func (o *CreateOptions) GetLabels() map[string]string {
} }
return o.Labels 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
}

View File

@ -14,6 +14,7 @@ type SecretCreateOptions struct {
Driver string Driver string
DriverOpts map[string]string DriverOpts map[string]string
Labels map[string]string Labels map[string]string
Replace bool
} }
type SecretInspectOptions struct { type SecretInspectOptions struct {

View File

@ -46,6 +46,7 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader
storeOpts := secrets.StoreOptions{ storeOpts := secrets.StoreOptions{
DriverOpts: options.DriverOpts, DriverOpts: options.DriverOpts,
Labels: options.Labels, Labels: options.Labels,
Replace: options.Replace,
} }
secretID, err := manager.Store(name, data, options.Driver, storeOpts) 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 { if secret.Labels == nil {
secret.Labels = make(map[string]string) secret.Labels = make(map[string]string)
} }
if secret.UpdatedAt.IsZero() {
secret.UpdatedAt = secret.CreatedAt
}
report := &entities.SecretInfoReport{ report := &entities.SecretInfoReport{
ID: secret.ID, ID: secret.ID,
CreatedAt: secret.CreatedAt, CreatedAt: secret.CreatedAt,
UpdatedAt: secret.CreatedAt, UpdatedAt: secret.UpdatedAt,
Spec: entities.SecretSpec{ Spec: entities.SecretSpec{
Name: secret.Name, Name: secret.Name,
Driver: entities.SecretDriverSpec{ Driver: entities.SecretDriverSpec{

View File

@ -15,7 +15,8 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader
WithDriver(options.Driver). WithDriver(options.Driver).
WithDriverOpts(options.DriverOpts). WithDriverOpts(options.DriverOpts).
WithName(name). WithName(name).
WithLabels(options.Labels) WithLabels(options.Labels).
WithReplace(options.Replace)
created, err := secrets.Create(ic.ClientCtx, reader, opts) created, err := secrets.Create(ic.ClientCtx, reader, opts)
if err != nil { if err != nil {
return nil, err return nil, err
@ -37,7 +38,7 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string
return nil, nil, err return nil, nil, err
} }
if errModel.ResponseCode == 404 { 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 continue
} }
return nil, nil, err return nil, nil, err

View File

@ -36,6 +36,26 @@ var _ = Describe("Podman secret", func() {
inspect.WaitWithDefaultTimeout() inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(Exit(0)) Expect(inspect).Should(Exit(0))
Expect(inspect.OutputToString()).To(ContainSubstring("opt1:val")) 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() { It("podman secret create bad name should fail", func() {