mirror of
https://github.com/containers/podman.git
synced 2025-07-04 01:48:28 +08:00
Secret create - add ignore option to allow noop
Signed-off-by: Ygal Blum <ygal.blum@gmail.com>
This commit is contained in:
@ -57,6 +57,8 @@ func init() {
|
||||
|
||||
flags.BoolVar(&createOpts.Replace, "replace", false, "If a secret with the same name exists, replace it")
|
||||
|
||||
flags.BoolVar(&createOpts.Ignore, "ignore", false, "If a secret with the same name exists, ignore and do not create a new secret")
|
||||
|
||||
labelFlagName := "label"
|
||||
flags.StringArrayVarP(&labels, labelFlagName, "l", nil, "Specify labels on the secret")
|
||||
_ = createCmd.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone)
|
||||
@ -65,6 +67,11 @@ func init() {
|
||||
func create(cmd *cobra.Command, args []string) error {
|
||||
name := args[0]
|
||||
|
||||
// Validate that --ignore and --replace are not used together
|
||||
if createOpts.Ignore && createOpts.Replace {
|
||||
return errors.New("cannot use --ignore and --replace flags together")
|
||||
}
|
||||
|
||||
var err error
|
||||
path := args[1]
|
||||
|
||||
|
@ -38,6 +38,12 @@ Read secret data from environment variable.
|
||||
|
||||
Print usage statement.
|
||||
|
||||
#### **--ignore**=*false*
|
||||
|
||||
If a secret with the same name already exists, do not return an error and return the existing secret's ID instead of creating a new one.
|
||||
Cannot be used with `--replace`.
|
||||
The default is **false**.
|
||||
|
||||
#### **--label**, **-l**=*key=val1,key2=val2*
|
||||
|
||||
Add label to secret. These labels can be viewed in podman secrete inspect or ls.
|
||||
@ -46,6 +52,7 @@ Add label to secret. These labels can be viewed in podman secrete inspect or ls.
|
||||
|
||||
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.
|
||||
Cannot be used with `--ignore`.
|
||||
The default is **false**.
|
||||
|
||||
## SECRET DRIVERS
|
||||
|
4
go.mod
4
go.mod
@ -13,7 +13,7 @@ require (
|
||||
github.com/checkpoint-restore/go-criu/v7 v7.2.0
|
||||
github.com/containernetworking/plugins v1.7.1
|
||||
github.com/containers/buildah v1.40.1-0.20250604193037-b8d8cc375f30
|
||||
github.com/containers/common v0.63.2-0.20250604184922-bb2062b6265c
|
||||
github.com/containers/common v0.63.2-0.20250624163146-1bc9d1737003
|
||||
github.com/containers/conmon v2.0.20+incompatible
|
||||
github.com/containers/gvisor-tap-vsock v0.8.6
|
||||
github.com/containers/image/v5 v5.35.1-0.20250603145948-347a6e7283ef
|
||||
@ -53,7 +53,7 @@ require (
|
||||
github.com/nxadm/tail v1.4.11
|
||||
github.com/onsi/ginkgo/v2 v2.23.4
|
||||
github.com/onsi/gomega v1.37.0
|
||||
github.com/opencontainers/cgroups v0.0.2
|
||||
github.com/opencontainers/cgroups v0.0.3
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.1.1
|
||||
github.com/opencontainers/runtime-spec v1.2.1
|
||||
|
8
go.sum
8
go.sum
@ -66,8 +66,8 @@ github.com/containernetworking/plugins v1.7.1 h1:CNAR0jviDj6FS5Vg85NTgKWLDzZPfi/
|
||||
github.com/containernetworking/plugins v1.7.1/go.mod h1:xuMdjuio+a1oVQsHKjr/mgzuZ24leAsqUYRnzGoXHy0=
|
||||
github.com/containers/buildah v1.40.1-0.20250604193037-b8d8cc375f30 h1:kCt0fnVBvXY9J98pUDeUc0gHKrhRwaBTWWD3otLutCE=
|
||||
github.com/containers/buildah v1.40.1-0.20250604193037-b8d8cc375f30/go.mod h1:QDecwvjrr+e0VD5GYv2dw7tsiqrz673r8B4rIYFP11Y=
|
||||
github.com/containers/common v0.63.2-0.20250604184922-bb2062b6265c h1:j4epZCkQt8Jdpz2GsUzvqY4MfaOfJamrNpZnmbV84Ug=
|
||||
github.com/containers/common v0.63.2-0.20250604184922-bb2062b6265c/go.mod h1:efNRNweihnq5nXALnAPDXTpC7uJtnFV4pNuETTfvI8s=
|
||||
github.com/containers/common v0.63.2-0.20250624163146-1bc9d1737003 h1:Nk8VZ9Ht7/HnYveikzd8RqNSPphbh358Chmt/GyPeWI=
|
||||
github.com/containers/common v0.63.2-0.20250624163146-1bc9d1737003/go.mod h1:mQkSk7VxbvgOo3vLE7yy6spgWNg8Ni0Zytt8HpmRKRw=
|
||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
||||
github.com/containers/gvisor-tap-vsock v0.8.6 h1:9SeAXK+K2o36CtrgYk6zRXbU3zrayjvkrI8b7/O6u5A=
|
||||
@ -354,8 +354,8 @@ github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus
|
||||
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
|
||||
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/opencontainers/cgroups v0.0.2 h1:A+mAPPMfgKNCEZUUtibESFx06uvhAmvo8sSz3Abwk7o=
|
||||
github.com/opencontainers/cgroups v0.0.2/go.mod h1:s8lktyhlGUqM7OSRL5P7eAW6Wb+kWPNvt4qvVfzA5vs=
|
||||
github.com/opencontainers/cgroups v0.0.3 h1:Jc9dWh/0YLGjdy6J/9Ln8NM5BfTA4W2BY0GMozy3aDU=
|
||||
github.com/opencontainers/cgroups v0.0.3/go.mod h1:s8lktyhlGUqM7OSRL5P7eAW6Wb+kWPNvt4qvVfzA5vs=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
|
@ -27,6 +27,7 @@ func CreateSecret(w http.ResponseWriter, r *http.Request) {
|
||||
DriverOpts map[string]string `schema:"driveropts"`
|
||||
Labels map[string]string `schema:"labels"`
|
||||
Replace bool `schema:"replace"`
|
||||
Ignore bool `schema:"ignore"`
|
||||
}{
|
||||
// override any golang type defaults
|
||||
}
|
||||
@ -40,6 +41,7 @@ func CreateSecret(w http.ResponseWriter, r *http.Request) {
|
||||
opts.DriverOpts = query.DriverOpts
|
||||
opts.Labels = query.Labels
|
||||
opts.Replace = query.Replace
|
||||
opts.Ignore = query.Ignore
|
||||
|
||||
ic := abi.ContainerEngine{Libpod: runtime}
|
||||
report, err := ic.SecretCreate(r.Context(), query.Name, r.Body, opts)
|
||||
|
@ -29,4 +29,5 @@ type CreateOptions struct {
|
||||
DriverOpts map[string]string
|
||||
Labels map[string]string
|
||||
Replace *bool
|
||||
Ignore *bool
|
||||
}
|
||||
|
@ -91,3 +91,18 @@ func (o *CreateOptions) GetReplace() bool {
|
||||
}
|
||||
return *o.Replace
|
||||
}
|
||||
|
||||
// WithIgnore set field Ignore to given value
|
||||
func (o *CreateOptions) WithIgnore(value bool) *CreateOptions {
|
||||
o.Ignore = &value
|
||||
return o
|
||||
}
|
||||
|
||||
// GetIgnore returns value of field Ignore
|
||||
func (o *CreateOptions) GetIgnore() bool {
|
||||
if o.Ignore == nil {
|
||||
var z bool
|
||||
return z
|
||||
}
|
||||
return *o.Ignore
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ type SecretCreateOptions struct {
|
||||
DriverOpts map[string]string
|
||||
Labels map[string]string
|
||||
Replace bool
|
||||
Ignore bool
|
||||
}
|
||||
|
||||
type SecretInspectOptions struct {
|
||||
|
@ -47,9 +47,10 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader
|
||||
}
|
||||
|
||||
storeOpts := secrets.StoreOptions{
|
||||
DriverOpts: options.DriverOpts,
|
||||
Labels: options.Labels,
|
||||
Replace: options.Replace,
|
||||
DriverOpts: options.DriverOpts,
|
||||
Labels: options.Labels,
|
||||
Replace: options.Replace,
|
||||
IgnoreIfExists: options.Ignore,
|
||||
}
|
||||
|
||||
secretID, err := manager.Store(name, data, options.Driver, storeOpts)
|
||||
|
@ -16,7 +16,8 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader
|
||||
WithDriverOpts(options.DriverOpts).
|
||||
WithName(name).
|
||||
WithLabels(options.Labels).
|
||||
WithReplace(options.Replace)
|
||||
WithReplace(options.Replace).
|
||||
WithIgnore(options.Ignore)
|
||||
created, err := secrets.Create(ic.ClientCtx, reader, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -64,6 +64,34 @@ var _ = Describe("Podman secret", func() {
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring("opt1:val1"))
|
||||
})
|
||||
|
||||
It("podman secret create with --ignore", func() {
|
||||
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
|
||||
err := os.WriteFile(secretFilePath, []byte("mysecret"), 0755)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// First create a secret
|
||||
session := podmanTest.Podman([]string{"secret", "create", "ignore-test", secretFilePath})
|
||||
session.WaitWithDefaultTimeout()
|
||||
secrID := session.OutputToString()
|
||||
Expect(session).Should(ExitCleanly())
|
||||
|
||||
// Try to create the same secret again without --ignore, should fail
|
||||
session = podmanTest.Podman([]string{"secret", "create", "ignore-test", secretFilePath})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(ExitWithError(125, "Error: ignore-test: secret name in use"))
|
||||
|
||||
// Try to create the same secret again with --ignore, should succeed and return existing ID
|
||||
session = podmanTest.Podman([]string{"secret", "create", "--ignore", "ignore-test", secretFilePath})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(ExitCleanly())
|
||||
Expect(session.OutputToString()).To(Equal(secrID))
|
||||
|
||||
// Try to use both --ignore and --replace, should fail
|
||||
session = podmanTest.Podman([]string{"secret", "create", "--ignore", "--replace", "ignore-test", secretFilePath})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(ExitWithError(125, "Error: cannot use --ignore and --replace flags together"))
|
||||
})
|
||||
|
||||
It("podman secret create bad name should fail", func() {
|
||||
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
|
||||
err := os.WriteFile(secretFilePath, []byte("mysecret"), 0755)
|
||||
|
43
vendor/github.com/containers/common/pkg/cgroups/memory_linux.go
generated
vendored
43
vendor/github.com/containers/common/pkg/cgroups/memory_linux.go
generated
vendored
@ -3,9 +3,7 @@
|
||||
package cgroups
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/cgroups/fs"
|
||||
@ -57,31 +55,44 @@ func (c *linuxMemHandler) Stat(ctr *CgroupControl, m *cgroups.Stats) error {
|
||||
if ctr.cgroup2 {
|
||||
memoryRoot = filepath.Join(cgroupRoot, ctr.config.Path)
|
||||
limitFilename = "memory.max"
|
||||
if memUsage.Usage.Usage, err = readFileByKeyAsUint64(filepath.Join(memoryRoot, "memory.stat"), "anon"); err != nil {
|
||||
|
||||
// Read memory.current
|
||||
current, err := readFileAsUint64(filepath.Join(memoryRoot, "memory.current"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read inactive_file from memory.stat
|
||||
inactiveFile, err := readFileByKeyAsUint64(filepath.Join(memoryRoot, "memory.stat"), "inactive_file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Docker calculation: memory.current - memory.stat['inactive_file']
|
||||
memUsage.Usage.Usage = 0
|
||||
if inactiveFile < current {
|
||||
memUsage.Usage.Usage = current - inactiveFile
|
||||
}
|
||||
} else {
|
||||
memoryRoot = ctr.getCgroupv1Path(Memory)
|
||||
limitFilename = "memory.limit_in_bytes"
|
||||
|
||||
path := filepath.Join(memoryRoot, "memory.stat")
|
||||
values, err := readCgroupMapPath(path)
|
||||
// Read memory.usage_in_bytes
|
||||
usageInBytes, err := readFileAsUint64(filepath.Join(memoryRoot, "memory.usage_in_bytes"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// cgroup v1 does not have a single "anon" field, but we can calculate it
|
||||
// from total_active_anon and total_inactive_anon
|
||||
// Read total_inactive_file from memory.stat
|
||||
totalInactiveFile, err := readFileByKeyAsUint64(filepath.Join(memoryRoot, "memory.stat"), "total_inactive_file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Docker calculation: memory.usage_in_bytes - memory.stat['total_inactive_file']
|
||||
memUsage.Usage.Usage = 0
|
||||
for _, key := range []string{"total_active_anon", "total_inactive_anon"} {
|
||||
if _, found := values[key]; !found {
|
||||
continue
|
||||
}
|
||||
res, err := strconv.ParseUint(values[key][0], 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse %s from %s: %w", key, path, err)
|
||||
}
|
||||
memUsage.Usage.Usage += res
|
||||
if totalInactiveFile < usageInBytes {
|
||||
memUsage.Usage.Usage = usageInBytes - totalInactiveFile
|
||||
}
|
||||
}
|
||||
|
||||
|
15
vendor/github.com/containers/common/pkg/secrets/secrets.go
generated
vendored
15
vendor/github.com/containers/common/pkg/secrets/secrets.go
generated
vendored
@ -48,6 +48,9 @@ var errAmbiguous = errors.New("secret is ambiguous")
|
||||
// errDataSize indicates that the secret data is too large or too small
|
||||
var errDataSize = errors.New("secret data must be larger than 0 and less than 512000 bytes")
|
||||
|
||||
// errIgnoreIfExistsAndReplace indicates that ignoreIfExists and replace cannot be used together.
|
||||
var errIgnoreIfExistsAndReplace = errors.New("ignoreIfExists and replace cannot be used together")
|
||||
|
||||
// secretsFile is the name of the file that the secrets database will be stored in
|
||||
var secretsFile = "secrets.json"
|
||||
|
||||
@ -114,6 +117,8 @@ type StoreOptions struct {
|
||||
Labels map[string]string
|
||||
// Replace existing secret
|
||||
Replace bool
|
||||
// Ignore if already exists
|
||||
IgnoreIfExists bool
|
||||
}
|
||||
|
||||
// NewManager creates a new secrets manager
|
||||
@ -169,6 +174,11 @@ func (s *SecretsManager) Store(name string, data []byte, driverType string, opti
|
||||
if len(data) == 0 || len(data) >= maxSecretSize {
|
||||
return "", errDataSize
|
||||
}
|
||||
|
||||
if options.IgnoreIfExists && options.Replace {
|
||||
return "", errIgnoreIfExistsAndReplace
|
||||
}
|
||||
|
||||
var secr *Secret
|
||||
s.lockfile.Lock()
|
||||
defer s.lockfile.Unlock()
|
||||
@ -179,13 +189,16 @@ func (s *SecretsManager) Store(name string, data []byte, driverType string, opti
|
||||
}
|
||||
|
||||
if exist {
|
||||
if !options.Replace {
|
||||
if !options.Replace && !options.IgnoreIfExists {
|
||||
return "", fmt.Errorf("%s: %w", name, errSecretNameInUse)
|
||||
}
|
||||
secr, err = s.lookupSecret(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if options.IgnoreIfExists {
|
||||
return secr.ID, nil
|
||||
}
|
||||
secr.UpdatedAt = time.Now()
|
||||
} else {
|
||||
secr = new(Secret)
|
||||
|
2
vendor/github.com/opencontainers/cgroups/config_linux.go
generated
vendored
2
vendor/github.com/opencontainers/cgroups/config_linux.go
generated
vendored
@ -29,7 +29,7 @@ type Cgroup struct {
|
||||
ScopePrefix string `json:"scope_prefix,omitempty"`
|
||||
|
||||
// Resources contains various cgroups settings to apply.
|
||||
*Resources `json:"Resources,omitempty"`
|
||||
*Resources
|
||||
|
||||
// Systemd tells if systemd should be used to manage cgroups.
|
||||
Systemd bool `json:"Systemd,omitempty"`
|
||||
|
27
vendor/github.com/opencontainers/cgroups/utils.go
generated
vendored
27
vendor/github.com/opencontainers/cgroups/utils.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@ -413,16 +414,30 @@ func WriteCgroupProc(dir string, pid int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Since the OCI spec is designed for cgroup v1, in some cases
|
||||
// there is need to convert from the cgroup v1 configuration to cgroup v2
|
||||
// the formula for cpuShares is y = (1 + ((x - 2) * 9999) / 262142)
|
||||
// convert from [2-262144] to [1-10000]
|
||||
// 262144 comes from Linux kernel definition "#define MAX_SHARES (1UL << 18)"
|
||||
// ConvertCPUSharesToCgroupV2Value converts CPU shares, used by cgroup v1,
|
||||
// to CPU weight, used by cgroup v2.
|
||||
//
|
||||
// Cgroup v1 CPU shares has a range of [2^1...2^18], i.e. [2...262144],
|
||||
// and the default value is 1024.
|
||||
//
|
||||
// Cgroup v2 CPU weight has a range of [10^0...10^4], i.e. [1...10000],
|
||||
// and the default value is 100.
|
||||
func ConvertCPUSharesToCgroupV2Value(cpuShares uint64) uint64 {
|
||||
// The value of 0 means "unset".
|
||||
if cpuShares == 0 {
|
||||
return 0
|
||||
}
|
||||
return (1 + ((cpuShares-2)*9999)/262142)
|
||||
if cpuShares <= 2 {
|
||||
return 1
|
||||
}
|
||||
if cpuShares >= 262144 {
|
||||
return 10000
|
||||
}
|
||||
l := math.Log2(float64(cpuShares))
|
||||
// Quadratic function which fits min, max, and default.
|
||||
exponent := (l*l+125*l)/612.0 - 7.0/34.0
|
||||
|
||||
return uint64(math.Ceil(math.Pow(10, exponent)))
|
||||
}
|
||||
|
||||
// ConvertMemorySwapToCgroupV2Value converts MemorySwap value from OCI spec
|
||||
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@ -144,7 +144,7 @@ github.com/containers/buildah/pkg/sshagent
|
||||
github.com/containers/buildah/pkg/util
|
||||
github.com/containers/buildah/pkg/volumes
|
||||
github.com/containers/buildah/util
|
||||
# github.com/containers/common v0.63.2-0.20250604184922-bb2062b6265c
|
||||
# github.com/containers/common v0.63.2-0.20250624163146-1bc9d1737003
|
||||
## explicit; go 1.23.3
|
||||
github.com/containers/common/internal
|
||||
github.com/containers/common/internal/attributedstring
|
||||
@ -802,7 +802,7 @@ github.com/onsi/gomega/matchers/support/goraph/edge
|
||||
github.com/onsi/gomega/matchers/support/goraph/node
|
||||
github.com/onsi/gomega/matchers/support/goraph/util
|
||||
github.com/onsi/gomega/types
|
||||
# github.com/opencontainers/cgroups v0.0.2
|
||||
# github.com/opencontainers/cgroups v0.0.3
|
||||
## explicit; go 1.23.0
|
||||
github.com/opencontainers/cgroups
|
||||
github.com/opencontainers/cgroups/devices/config
|
||||
|
Reference in New Issue
Block a user