Merge pull request #11431 from jmguzik/secrets-ls-filters

Add filtering functionality to http api secrets list
This commit is contained in:
OpenShift Merge Robot 2021-09-07 19:24:20 +02:00 committed by GitHub
commit 536f23c0b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 128 additions and 36 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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:

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -86,7 +86,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)

View File

@ -16,7 +16,7 @@ type SecretCreateOptions struct {
}
type SecretListRequest struct {
Filters map[string]string
Filters map[string][]string
}
type SecretListReport struct {

View File

@ -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,6 +96,11 @@ func (ic *ContainerEngine) SecretList(ctx context.Context) ([]*entities.SecretIn
}
report := make([]*entities.SecretInfoReport, 0, len(secretList))
for _, secret := range secretList {
result, err := utils.IfPassesSecretsFilter(secret, opts.Filters)
if err != nil {
return nil, err
}
if result {
reportItem := entities.SecretInfoReport{
ID: secret.ID,
CreatedAt: secret.CreatedAt,
@ -109,6 +115,7 @@ func (ic *ContainerEngine) SecretList(ctx context.Context) ([]*entities.SecretIn
}
report = append(report, &reportItem)
}
}
return report, nil
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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