Merge pull request #18019 from ygalblum/add-secret-exists

Add support for secret exists
This commit is contained in:
OpenShift Merge Robot
2023-04-03 10:11:48 -04:00
committed by GitHub
11 changed files with 194 additions and 0 deletions

View File

@ -0,0 +1,38 @@
package secrets
import (
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/spf13/cobra"
)
var (
existsCmd = &cobra.Command{
Use: "exists SECRET",
Short: "Check if a secret exists in local storage",
Long: `If the named secret exists in local storage, podman secret exists exits with 0, otherwise the exit code will be 1.`,
Args: cobra.ExactArgs(1),
RunE: exists,
ValidArgsFunction: common.AutocompleteSecrets,
Example: `podman secret exists ID
podman secret exists SECRET || podman secret create SECRET <secret source>`,
}
)
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: existsCmd,
Parent: secretCmd,
})
}
func exists(cmd *cobra.Command, args []string) error {
found, err := registry.ContainerEngine().SecretExists(registry.GetContext(), args[0])
if err != nil {
return err
}
if !found.Value {
registry.SetExitCode(1)
}
return nil
}

View File

@ -0,0 +1,43 @@
% podman-secret-exists 1
## NAME
podman\-secret\-exists - Check if the given secret exists
## SYNOPSIS
**podman secret exists** *secret*
## DESCRIPTION
**podman secret exists** checks if a secret exists. Podman will return an exit code
of `0` when the secret is found. A `1` will be returned otherwise. An exit code of
`125` indicates there was another issue.
## OPTIONS
#### **--help**, **-h**
Print usage statement
## EXAMPLE
Check if a secret called `mysecret` exists (the secret does actually exist).
```
$ podman secret exists mysecret
$ echo $?
0
$
```
Check if a secret called `mypassword` exists (the secret does not actually exist).
```
$ podman secret exists mypassword
$ echo $?
1
$
```
## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-secret(1)](podman-secret.1.md)**
## HISTORY
April 2023, Originally compiled by Ygal Blum `<ygal.blum@gmail.com>`

View File

@ -14,6 +14,7 @@ podman secret is a set of subcommands that manage secrets.
| Command | Man Page | Description | | Command | Man Page | Description |
| ------- | ------------------------------------------------------ | ------------------------------------------------------ | | ------- | ------------------------------------------------------ | ------------------------------------------------------ |
| create | [podman-secret-create(1)](podman-secret-create.1.md) | Create a new secret | | create | [podman-secret-create(1)](podman-secret-create.1.md) | Create a new secret |
| exists | [podman-secret-exists(1)](podman-secret-exists.1.md) | Check if the given secret exists |
| inspect | [podman-secret-inspect(1)](podman-secret-inspect.1.md) | Display detailed information on one or more secrets | | inspect | [podman-secret-inspect(1)](podman-secret-inspect.1.md) | Display detailed information on one or more secrets |
| ls | [podman-secret-ls(1)](podman-secret-ls.1.md) | List all available secrets | | ls | [podman-secret-ls(1)](podman-secret-ls.1.md) | List all available secrets |
| rm | [podman-secret-rm(1)](podman-secret-rm.1.md) | Remove one or more secrets | | rm | [podman-secret-rm(1)](podman-secret-rm.1.md) | Remove one or more secrets |

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/containers/common/pkg/secrets"
"github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/pkg/api/handlers/utils" "github.com/containers/podman/v4/pkg/api/handlers/utils"
api "github.com/containers/podman/v4/pkg/api/types" api "github.com/containers/podman/v4/pkg/api/types"
@ -44,3 +45,20 @@ func CreateSecret(w http.ResponseWriter, r *http.Request) {
} }
utils.WriteResponse(w, http.StatusOK, report) utils.WriteResponse(w, http.StatusOK, report)
} }
func SecretExists(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
name := utils.GetName(r)
ic := abi.ContainerEngine{Libpod: runtime}
report, err := ic.SecretExists(r.Context(), name)
if err != nil {
utils.InternalServerError(w, err)
return
}
if !report.Value {
utils.SecretNotFound(w, name, secrets.ErrNoSuchSecret)
return
}
utils.WriteResponse(w, http.StatusNoContent, "")
}

View File

@ -89,6 +89,27 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error {
// '500': // '500':
// "$ref": "#/responses/internalError" // "$ref": "#/responses/internalError"
r.Handle(VersionedPath("/libpod/secrets/{name}/json"), s.APIHandler(compat.InspectSecret)).Methods(http.MethodGet) r.Handle(VersionedPath("/libpod/secrets/{name}/json"), s.APIHandler(compat.InspectSecret)).Methods(http.MethodGet)
// swagger:operation GET /libpod/secrets/{name}/exists libpod SecretExistsLibpod
// ---
// tags:
// - secrets
// summary: Secret exists
// parameters:
// - in: path
// name: name
// type: string
// required: true
// description: the name or ID of the secret
// produces:
// - application/json
// responses:
// 204:
// description: secret exists
// 404:
// $ref: '#/responses/NoSuchSecret'
// '500':
// "$ref": "#/responses/internalError"
r.Handle(VersionedPath("/libpod/secrets/{name}/exists"), s.APIHandler(libpod.SecretExists)).Methods(http.MethodGet)
// swagger:operation DELETE /libpod/secrets/{name} libpod SecretDeleteLibpod // swagger:operation DELETE /libpod/secrets/{name} libpod SecretDeleteLibpod
// --- // ---
// tags: // tags:

View File

@ -88,3 +88,17 @@ func Create(ctx context.Context, reader io.Reader, options *CreateOptions) (*ent
return create, response.Process(&create) return create, response.Process(&create)
} }
func Exists(ctx context.Context, nameOrID string) (bool, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
return false, err
}
response, err := conn.DoRequest(ctx, nil, http.MethodGet, "/secrets/%s/exists", nil, nil, nameOrID)
if err != nil {
return false, err
}
defer response.Body.Close()
return response.IsSuccess(), nil
}

View File

@ -95,6 +95,7 @@ type ContainerEngine interface { //nolint:interfacebloat
SecretInspect(ctx context.Context, nameOrIDs []string) ([]*SecretInfoReport, []error, error) SecretInspect(ctx context.Context, nameOrIDs []string) ([]*SecretInfoReport, []error, error)
SecretList(ctx context.Context, opts SecretListRequest) ([]*SecretInfoReport, error) SecretList(ctx context.Context, opts SecretListRequest) ([]*SecretInfoReport, error)
SecretRm(ctx context.Context, nameOrID []string, opts SecretRmOptions) ([]*SecretRmReport, error) SecretRm(ctx context.Context, nameOrID []string, opts SecretRmOptions) ([]*SecretRmReport, error)
SecretExists(ctx context.Context, nameOrID string) (*BoolReport, error)
Shutdown(ctx context.Context) Shutdown(ctx context.Context)
SystemDf(ctx context.Context, options SystemDfOptions) (*SystemDfReport, error) SystemDf(ctx context.Context, options SystemDfOptions) (*SystemDfReport, error)
Unshare(ctx context.Context, args []string, options SystemUnshareOptions) error Unshare(ctx context.Context, args []string, options SystemUnshareOptions) error

View File

@ -2,6 +2,7 @@ package abi
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"path/filepath" "path/filepath"
@ -165,3 +166,17 @@ func (ic *ContainerEngine) SecretRm(ctx context.Context, nameOrIDs []string, opt
return reports, nil return reports, nil
} }
func (ic *ContainerEngine) SecretExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
manager, err := ic.Libpod.SecretsManager()
if err != nil {
return nil, err
}
secret, err := manager.Lookup(nameOrID)
if err != nil && !errors.Is(err, secrets.ErrNoSuchSecret) {
return nil, err
}
return &entities.BoolReport{Value: secret != nil}, nil
}

View File

@ -87,3 +87,11 @@ func (ic *ContainerEngine) SecretRm(ctx context.Context, nameOrIDs []string, opt
} }
return allRm, nil return allRm, nil
} }
func (ic *ContainerEngine) SecretExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
exists, err := secrets.Exists(ic.ClientCtx, nameOrID)
if err != nil {
return nil, err
}
return &entities.BoolReport{Value: exists}, nil
}

View File

@ -18,6 +18,12 @@ t GET secrets/mysecret 200 \
# secret inspect non-existent secret # secret inspect non-existent secret
t GET secrets/bogus 404 t GET secrets/bogus 404
# Check exists with existing secret
t GET libpod/secrets/mysecret/exists 204
# Check exists for non-existing secret
t GET libpod/secrets/bogus/exists 404
# secret list # secret list
t GET secrets 200 \ t GET secrets 200 \
length=1 \ length=1 \

View File

@ -372,4 +372,33 @@ var _ = Describe("Podman secret", func() {
Expect(inspect.OutputToString()).To(Equal("map[]")) Expect(inspect.OutputToString()).To(Equal("map[]"))
}) })
It("podman secret exists should return true if secret exists", func() {
secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
err := os.WriteFile(secretFilePath, []byte("mysecret"), 0755)
Expect(err).ToNot(HaveOccurred())
secretName := "does_exist"
session := podmanTest.Podman([]string{"secret", "create", secretName, secretFilePath})
session.WaitWithDefaultTimeout()
secretID := session.OutputToString()
Expect(session).Should(Exit(0))
exists := podmanTest.Podman([]string{"secret", "exists", secretName})
exists.WaitWithDefaultTimeout()
Expect(exists).Should(Exit(0))
exists = podmanTest.Podman([]string{"secret", "exists", secretID})
exists.WaitWithDefaultTimeout()
Expect(exists).Should(Exit(0))
})
It("podman secret exists should return false if secret does not exist", func() {
secretName := "does_not_exist"
exists := podmanTest.Podman([]string{"secret", "exists", secretName})
exists.WaitWithDefaultTimeout()
Expect(exists).Should(Exit(1))
})
}) })