aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Guzik <jakubmguzik@gmail.com>2021-09-02 23:01:37 +0200
committerJakub Guzik <jakubmguzik@gmail.com>2021-09-03 10:29:31 +0200
commitd346e6e734dbaac911de0d774a5d8703e2abc83d (patch)
tree0bd5ac510effcc97b70341b6a719cbfcfbc058bc
parent469900406ac51332785455bc8668bd1c053badd6 (diff)
downloadpodman-d346e6e734dbaac911de0d774a5d8703e2abc83d.tar.gz
podman-d346e6e734dbaac911de0d774a5d8703e2abc83d.tar.bz2
podman-d346e6e734dbaac911de0d774a5d8703e2abc83d.zip
Add filtering functionality to http api secrets list
Filtering is missing in both compat API and libpod API, while docker has filtering functinality. This commit enables filtering option using name and id in both libpod and http API. Signed-off-by: Jakub Guzik <jakubmguzik@gmail.com>
-rw-r--r--cmd/podman/common/completion.go2
-rw-r--r--cmd/podman/secrets/list.go2
-rw-r--r--pkg/api/handlers/compat/secrets.go22
-rw-r--r--pkg/api/server/register_secrets.go16
-rw-r--r--pkg/bindings/secrets/secrets.go6
-rw-r--r--pkg/bindings/secrets/types.go1
-rw-r--r--pkg/bindings/secrets/types_list_options.go16
-rw-r--r--pkg/domain/entities/engine_container.go2
-rw-r--r--pkg/domain/entities/secrets.go2
-rw-r--r--pkg/domain/infra/abi/secrets.go31
-rw-r--r--pkg/domain/infra/tunnel/secrets.go5
-rw-r--r--pkg/domain/utils/secrets_filters.go24
-rw-r--r--test/apiv2/50-secrets.at33
13 files changed, 127 insertions, 35 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index 3966606e3..e925fb4f1 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -223,7 +223,7 @@ func getSecrets(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCom
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveNoFileComp
}
- secrets, err := engine.SecretList(registry.GetContext())
+ secrets, err := engine.SecretList(registry.GetContext(), entities.SecretListRequest{})
if err != nil {
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveNoFileComp
diff --git a/cmd/podman/secrets/list.go b/cmd/podman/secrets/list.go
index e64990c6f..f136de4ab 100644
--- a/cmd/podman/secrets/list.go
+++ b/cmd/podman/secrets/list.go
@@ -48,7 +48,7 @@ func init() {
}
func ls(cmd *cobra.Command, args []string) error {
- responses, err := registry.ContainerEngine().SecretList(context.Background())
+ responses, err := registry.ContainerEngine().SecretList(context.Background(), entities.SecretListRequest{})
if err != nil {
return err
}
diff --git a/pkg/api/handlers/compat/secrets.go b/pkg/api/handlers/compat/secrets.go
index 86e3887a4..7dd17ea94 100644
--- a/pkg/api/handlers/compat/secrets.go
+++ b/pkg/api/handlers/compat/secrets.go
@@ -11,31 +11,25 @@ import (
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
- "github.com/gorilla/schema"
+ "github.com/containers/podman/v3/pkg/util"
"github.com/pkg/errors"
)
func ListSecrets(w http.ResponseWriter, r *http.Request) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
- decoder = r.Context().Value("decoder").(*schema.Decoder)
)
- query := struct {
- Filters map[string][]string `schema:"filters"`
- }{}
-
- if err := decoder.Decode(&query, r.URL.Query()); err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ filtersMap, err := util.PrepareFilters(r)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- if len(query.Filters) > 0 {
- utils.Error(w, "filters not supported", http.StatusBadRequest,
- errors.Wrapf(errors.New("bad parameter"), "filters not supported"))
- return
- }
ic := abi.ContainerEngine{Libpod: runtime}
- reports, err := ic.SecretList(r.Context())
+ listOptions := entities.SecretListRequest{
+ Filters: *filtersMap,
+ }
+ reports, err := ic.SecretList(r.Context(), listOptions)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/server/register_secrets.go b/pkg/api/server/register_secrets.go
index ca9790e93..129912179 100644
--- a/pkg/api/server/register_secrets.go
+++ b/pkg/api/server/register_secrets.go
@@ -44,6 +44,14 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error {
// - secrets
// summary: List secrets
// description: Returns a list of secrets
+ // parameters:
+ // - in: query
+ // name: filters
+ // type: string
+ // description: |
+ // JSON encoded value of the filters (a `map[string][]string`) to process on the secrets list. Currently available filters:
+ // - `name=[name]` Matches secrets name (accepts regex).
+ // - `id=[id]` Matches for full or partial ID.
// produces:
// - application/json
// parameters:
@@ -110,6 +118,14 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error {
// - secrets (compat)
// summary: List secrets
// description: Returns a list of secrets
+ // parameters:
+ // - in: query
+ // name: filters
+ // type: string
+ // description: |
+ // JSON encoded value of the filters (a `map[string][]string`) to process on the secrets list. Currently available filters:
+ // - `name=[name]` Matches secrets name (accepts regex).
+ // - `id=[id]` Matches for full or partial ID.
// produces:
// - application/json
// parameters:
diff --git a/pkg/bindings/secrets/secrets.go b/pkg/bindings/secrets/secrets.go
index b741d3e5c..c439971c9 100644
--- a/pkg/bindings/secrets/secrets.go
+++ b/pkg/bindings/secrets/secrets.go
@@ -18,7 +18,11 @@ func List(ctx context.Context, options *ListOptions) ([]*entities.SecretInfoRepo
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/secrets/json", nil, nil)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
+ response, err := conn.DoRequest(nil, http.MethodGet, "/secrets/json", params, nil)
if err != nil {
return secrs, err
}
diff --git a/pkg/bindings/secrets/types.go b/pkg/bindings/secrets/types.go
index a64dea1b4..01c3c248d 100644
--- a/pkg/bindings/secrets/types.go
+++ b/pkg/bindings/secrets/types.go
@@ -3,6 +3,7 @@ package secrets
//go:generate go run ../generator/generator.go ListOptions
// ListOptions are optional options for inspecting secrets
type ListOptions struct {
+ Filters map[string][]string
}
//go:generate go run ../generator/generator.go InspectOptions
diff --git a/pkg/bindings/secrets/types_list_options.go b/pkg/bindings/secrets/types_list_options.go
index 568e021a8..e4501dde8 100644
--- a/pkg/bindings/secrets/types_list_options.go
+++ b/pkg/bindings/secrets/types_list_options.go
@@ -19,3 +19,19 @@ func (o *ListOptions) Changed(fieldName string) bool {
func (o *ListOptions) ToParams() (url.Values, error) {
return util.ToParams(o)
}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index bd011d309..d03e2f719 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -85,7 +85,7 @@ type ContainerEngine interface {
SetupRootless(ctx context.Context, noMoveProcess bool) error
SecretCreate(ctx context.Context, name string, reader io.Reader, options SecretCreateOptions) (*SecretCreateReport, error)
SecretInspect(ctx context.Context, nameOrIDs []string) ([]*SecretInfoReport, []error, error)
- SecretList(ctx context.Context) ([]*SecretInfoReport, error)
+ SecretList(ctx context.Context, opts SecretListRequest) ([]*SecretInfoReport, error)
SecretRm(ctx context.Context, nameOrID []string, opts SecretRmOptions) ([]*SecretRmReport, error)
Shutdown(ctx context.Context)
SystemDf(ctx context.Context, options SystemDfOptions) (*SystemDfReport, error)
diff --git a/pkg/domain/entities/secrets.go b/pkg/domain/entities/secrets.go
index 56a1465b7..55b470d7b 100644
--- a/pkg/domain/entities/secrets.go
+++ b/pkg/domain/entities/secrets.go
@@ -16,7 +16,7 @@ type SecretCreateOptions struct {
}
type SecretListRequest struct {
- Filters map[string]string
+ Filters map[string][]string
}
type SecretListReport struct {
diff --git a/pkg/domain/infra/abi/secrets.go b/pkg/domain/infra/abi/secrets.go
index 0bdb4ce60..2bf8eaae3 100644
--- a/pkg/domain/infra/abi/secrets.go
+++ b/pkg/domain/infra/abi/secrets.go
@@ -7,6 +7,7 @@ import (
"path/filepath"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/domain/utils"
"github.com/pkg/errors"
)
@@ -84,7 +85,7 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string
return reports, errs, nil
}
-func (ic *ContainerEngine) SecretList(ctx context.Context) ([]*entities.SecretInfoReport, error) {
+func (ic *ContainerEngine) SecretList(ctx context.Context, opts entities.SecretListRequest) ([]*entities.SecretInfoReport, error) {
manager, err := ic.Libpod.SecretsManager()
if err != nil {
return nil, err
@@ -95,19 +96,25 @@ func (ic *ContainerEngine) SecretList(ctx context.Context) ([]*entities.SecretIn
}
report := make([]*entities.SecretInfoReport, 0, len(secretList))
for _, secret := range secretList {
- reportItem := entities.SecretInfoReport{
- ID: secret.ID,
- CreatedAt: secret.CreatedAt,
- UpdatedAt: secret.CreatedAt,
- Spec: entities.SecretSpec{
- Name: secret.Name,
- Driver: entities.SecretDriverSpec{
- Name: secret.Driver,
- Options: secret.DriverOptions,
+ result, err := utils.IfPassesSecretsFilter(secret, opts.Filters)
+ if err != nil {
+ return nil, err
+ }
+ if result {
+ reportItem := entities.SecretInfoReport{
+ ID: secret.ID,
+ CreatedAt: secret.CreatedAt,
+ UpdatedAt: secret.CreatedAt,
+ Spec: entities.SecretSpec{
+ Name: secret.Name,
+ Driver: entities.SecretDriverSpec{
+ Name: secret.Driver,
+ Options: secret.DriverOptions,
+ },
},
- },
+ }
+ report = append(report, &reportItem)
}
- report = append(report, &reportItem)
}
return report, nil
}
diff --git a/pkg/domain/infra/tunnel/secrets.go b/pkg/domain/infra/tunnel/secrets.go
index ecbb80931..6337c7fbe 100644
--- a/pkg/domain/infra/tunnel/secrets.go
+++ b/pkg/domain/infra/tunnel/secrets.go
@@ -43,8 +43,9 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string
return allInspect, errs, nil
}
-func (ic *ContainerEngine) SecretList(ctx context.Context) ([]*entities.SecretInfoReport, error) {
- secrs, _ := secrets.List(ic.ClientCtx, nil)
+func (ic *ContainerEngine) SecretList(ctx context.Context, opts entities.SecretListRequest) ([]*entities.SecretInfoReport, error) {
+ options := new(secrets.ListOptions).WithFilters(opts.Filters)
+ secrs, _ := secrets.List(ic.ClientCtx, options)
return secrs, nil
}
diff --git a/pkg/domain/utils/secrets_filters.go b/pkg/domain/utils/secrets_filters.go
new file mode 100644
index 000000000..3ff7c7530
--- /dev/null
+++ b/pkg/domain/utils/secrets_filters.go
@@ -0,0 +1,24 @@
+package utils
+
+import (
+ "strings"
+
+ "github.com/containers/common/pkg/secrets"
+ "github.com/containers/podman/v3/pkg/util"
+ "github.com/pkg/errors"
+)
+
+func IfPassesSecretsFilter(s secrets.Secret, filters map[string][]string) (bool, error) {
+ result := true
+ for key, filterValues := range filters {
+ switch strings.ToLower(key) {
+ case "name":
+ result = util.StringMatchRegexSlice(s.Name, filterValues)
+ case "id":
+ result = util.StringMatchRegexSlice(s.ID, filterValues)
+ default:
+ return false, errors.Errorf("invalid filter %q", key)
+ }
+ }
+ return result, nil
+}
diff --git a/test/apiv2/50-secrets.at b/test/apiv2/50-secrets.at
index 034ec080a..ed0e8fb6b 100644
--- a/test/apiv2/50-secrets.at
+++ b/test/apiv2/50-secrets.at
@@ -27,8 +27,37 @@ t GET secrets 200 \
.[0].Spec.Name=mysecret \
.[0].Version.Index=1
-# secret list unsupported filters
-t GET secrets?filters='{"name":["foo1"]}' 400
+# secret list with filters
+t GET secrets?filters='{"name":["mysecret"]}' 200 \
+ length=1 \
+ .[0].Spec.Name=mysecret \
+ .[0].Version.Index=1
+
+t GET secrets?filters='{"name":["mysecret2"]}' 200 \
+ length=0 \
+
+# secret libpod list with filters
+t GET libpod/secrets/json?filters='{"name":["mysecret"]}' 200 \
+ length=1 \
+ .[0].Spec.Name=mysecret \
+
+t GET libpod/secrets/json?filters='{"name":["mysecret2"]}' 200 \
+ length=0 \
+
+# secret list with unsupported filters
+t GET secrets?filters='{"label":["xyz"]}' 500
+
+#compat api list secrets sanity checks
+t GET secrets?filters='garb1age}' 500 \
+ .cause="invalid character 'g' looking for beginning of value"
+t GET secrets?filters='{"label":["testl' 500 \
+ .cause="unexpected end of JSON input"
+
+#libpod api list secrets sanity checks
+t GET libpod/secrets/json?filters='garb1age}' 500 \
+ .cause="invalid character 'g' looking for beginning of value"
+t GET libpod/secrets/json?filters='{"label":["testl' 500 \
+ .cause="unexpected end of JSON input"
# secret rm
t DELETE secrets/mysecret 204