mirror of https://github.com/containers/podman.git
Merge pull request #11431 from jmguzik/secrets-ls-filters
Add filtering functionality to http api secrets list
This commit is contained in:
commit
536f23c0b7
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -16,7 +16,7 @@ type SecretCreateOptions struct {
|
|||
}
|
||||
|
||||
type SecretListRequest struct {
|
||||
Filters map[string]string
|
||||
Filters map[string][]string
|
||||
}
|
||||
|
||||
type SecretListReport struct {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue