From 306b44380fec7a6653baf8fa8e2929a8f0115659 Mon Sep 17 00:00:00 2001 From: Brent Baude Date: Sun, 23 Feb 2020 11:00:09 -0600 Subject: binding tests for volumes add binding tests for volumes: inspect(get), create, remove, prune, and list implement filters ability for volumes Signed-off-by: Brent Baude --- pkg/api/handlers/libpod/volumes.go | 137 +++++++++++++++++++++++++++++++------ pkg/api/handlers/types.go | 13 ++-- 2 files changed, 126 insertions(+), 24 deletions(-) (limited to 'pkg/api/handlers') diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go index 7e7e46718..9b10ee890 100644 --- a/pkg/api/handlers/libpod/volumes.go +++ b/pkg/api/handlers/libpod/volumes.go @@ -3,9 +3,11 @@ package libpod import ( "encoding/json" "net/http" + "strings" "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/api/handlers" "github.com/containers/libpod/pkg/api/handlers/utils" "github.com/gorilla/schema" @@ -29,7 +31,6 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) return } - // decode params from body if err := json.NewDecoder(r.Body).Decode(&input); err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) @@ -49,14 +50,21 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { parsedOptions, err := shared.ParseVolumeOptions(input.Opts) if err != nil { utils.InternalServerError(w, err) + return } volumeOptions = append(volumeOptions, parsedOptions...) } vol, err := runtime.NewVolume(r.Context(), volumeOptions...) if err != nil { utils.InternalServerError(w, err) + return + } + config, err := vol.Config() + if err != nil { + utils.InternalServerError(w, err) + return } - utils.WriteResponse(w, http.StatusOK, vol.Name()) + utils.WriteResponse(w, http.StatusOK, config) } func InspectVolume(w http.ResponseWriter, r *http.Request) { @@ -76,25 +84,46 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) { } func ListVolumes(w http.ResponseWriter, r *http.Request) { - //var ( - // runtime = r.Context().Value("runtime").(*libpod.Runtime) - // decoder = r.Context().Value("decoder").(*schema.Decoder) - //) - //query := struct { - // Filter string `json:"filter"` - //}{ - // // override any golang type defaults - //} - // - //if err := decoder.Decode(&query, r.URL.Query()); err != nil { - // utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, - // errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) - // return - //} - /* - This is all in main in cmd and needs to be extracted from there first. - */ + var ( + decoder = r.Context().Value("decoder").(*schema.Decoder) + err error + runtime = r.Context().Value("runtime").(*libpod.Runtime) + volumeConfigs []*libpod.VolumeConfig + volumeFilters []libpod.VolumeFilter + ) + query := struct { + Filters map[string][]string `schema:"filters"` + }{ + // override any golang type defaults + } + + if err := decoder.Decode(&query, r.URL.Query()); err != nil { + utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, + errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) + return + } + if len(query.Filters) > 0 { + volumeFilters, err = generateVolumeFilters(query.Filters) + if err != nil { + utils.InternalServerError(w, err) + return + } + } + vols, err := runtime.Volumes(volumeFilters...) + if err != nil { + utils.InternalServerError(w, err) + return + } + for _, v := range vols { + config, err := v.Config() + if err != nil { + utils.InternalServerError(w, err) + return + } + volumeConfigs = append(volumeConfigs, config) + } + utils.WriteResponse(w, http.StatusOK, volumeConfigs) } func PruneVolumes(w http.ResponseWriter, r *http.Request) { @@ -133,9 +162,77 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) { vol, err := runtime.LookupVolume(name) if err != nil { utils.VolumeNotFound(w, name, err) + return } if err := runtime.RemoveVolume(r.Context(), vol, query.Force); err != nil { + if errors.Cause(err) == define.ErrVolumeBeingUsed { + utils.Error(w, "volumes being used", http.StatusConflict, err) + return + } utils.InternalServerError(w, err) + return } utils.WriteResponse(w, http.StatusNoContent, "") } + +func generateVolumeFilters(filters map[string][]string) ([]libpod.VolumeFilter, error) { + var vf []libpod.VolumeFilter + for filter, v := range filters { + for _, val := range v { + switch filter { + case "name": + nameVal := val + vf = append(vf, func(v *libpod.Volume) bool { + return nameVal == v.Name() + }) + case "driver": + driverVal := val + vf = append(vf, func(v *libpod.Volume) bool { + return v.Driver() == driverVal + }) + case "scope": + scopeVal := val + vf = append(vf, func(v *libpod.Volume) bool { + return v.Scope() == scopeVal + }) + case "label": + filterArray := strings.SplitN(val, "=", 2) + filterKey := filterArray[0] + var filterVal string + if len(filterArray) > 1 { + filterVal = filterArray[1] + } else { + filterVal = "" + } + vf = append(vf, func(v *libpod.Volume) bool { + for labelKey, labelValue := range v.Labels() { + if labelKey == filterKey && ("" == filterVal || labelValue == filterVal) { + return true + } + } + return false + }) + case "opt": + filterArray := strings.SplitN(val, "=", 2) + filterKey := filterArray[0] + var filterVal string + if len(filterArray) > 1 { + filterVal = filterArray[1] + } else { + filterVal = "" + } + vf = append(vf, func(v *libpod.Volume) bool { + for labelKey, labelValue := range v.Options() { + if labelKey == filterKey && ("" == filterVal || labelValue == filterVal) { + return true + } + } + return false + }) + default: + return nil, errors.Errorf("%q is in an invalid volume filter", filter) + } + } + } + return vf, nil +} diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go index c72b0f817..2930a9567 100644 --- a/pkg/api/handlers/types.go +++ b/pkg/api/handlers/types.go @@ -128,11 +128,16 @@ type CreateContainerConfig struct { NetworkingConfig dockerNetwork.NetworkingConfig } +// swagger:model VolumeCreate type VolumeCreateConfig struct { - Name string `json:"name"` - Driver string `schema:"driver"` - Label map[string]string `schema:"label"` - Opts map[string]string `schema:"opts"` + // New volume's name. Can be left blank + Name string `schema:"name"` + // Volume driver to use + Driver string `schema:"driver"` + // User-defined key/value metadata. + Label map[string]string `schema:"label"` + // Mapping of driver options and values. + Opts map[string]string `schema:"opts"` } type IDResponse struct { -- cgit v1.2.3-54-g00ecf