diff options
author | Brent Baude <bbaude@redhat.com> | 2020-02-23 11:00:09 -0600 |
---|---|---|
committer | Brent Baude <bbaude@redhat.com> | 2020-02-27 13:11:42 -0600 |
commit | 306b44380fec7a6653baf8fa8e2929a8f0115659 (patch) | |
tree | 8affebec363f9a6a25cfbbfd6d6f58b133bd92f7 /pkg/api | |
parent | 3d1af087e6beba5ac31e2c6758fd5696d6d7883f (diff) | |
download | podman-306b44380fec7a6653baf8fa8e2929a8f0115659.tar.gz podman-306b44380fec7a6653baf8fa8e2929a8f0115659.tar.bz2 podman-306b44380fec7a6653baf8fa8e2929a8f0115659.zip |
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 <bbaude@redhat.com>
Diffstat (limited to 'pkg/api')
-rw-r--r-- | pkg/api/handlers/libpod/volumes.go | 137 | ||||
-rw-r--r-- | pkg/api/handlers/types.go | 13 | ||||
-rw-r--r-- | pkg/api/server/register_volumes.go | 43 | ||||
-rw-r--r-- | pkg/api/server/swagger.go | 17 |
4 files changed, 178 insertions, 32 deletions
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 { diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go index efe56a3ad..d1317904b 100644 --- a/pkg/api/server/register_volumes.go +++ b/pkg/api/server/register_volumes.go @@ -11,15 +11,42 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // swagger:operation POST /libpod/volumes/create volumes createVolume // --- // summary: Create a volume + // parameters: + // - in: body + // name: create + // description: attributes for creating a container + // schema: + // $ref: "#/definitions/VolumeCreate" + // produces: + // - application/json + // responses: + // '201': + // $ref: "#/responses/VolumeCreateResponse" + // '500': + // "$ref": "#/responses/InternalError" + r.Handle(VersionedPath("/libpod/volumes/create"), s.APIHandler(libpod.CreateVolume)).Methods(http.MethodPost) + // swagger:operation POST /libpod/volumes/json volumes listVolumes + // --- + // summary: List volumes + // description: Returns a list of networks // produces: // - application/json + // parameters: + // - in: query + // name: filters + // type: string + // description: | + // JSON encoded value of the filters (a map[string][]string) to process on the networks list. Available filters: + // - driver=<volume-driver-name> Matches volumes based on their driver. + // - label=<key> or label=<key>:<value> Matches volumes based on the presence of a label alone or a label and a value. + // - name=<volume-name> Matches all of volume name. + // - opt=<driver-option> Matches a storage driver options // responses: // '200': - // description: tbd + // "$ref": "#/responses/VolumeList" // '500': // "$ref": "#/responses/InternalError" - r.Handle("/libpod/volumes/create", s.APIHandler(libpod.CreateVolume)).Methods(http.MethodPost) - r.Handle("/libpod/volumes/json", s.APIHandler(libpod.ListVolumes)).Methods(http.MethodGet) + r.Handle(VersionedPath("/libpod/volumes/json"), s.APIHandler(libpod.ListVolumes)).Methods(http.MethodGet) // swagger:operation POST /libpod/volumes/prune volumes pruneVolumes // --- // summary: Prune volumes @@ -30,7 +57,7 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // description: no error // '500': // "$ref": "#/responses/InternalError" - r.Handle("/libpod/volumes/prune", s.APIHandler(libpod.PruneVolumes)).Methods(http.MethodPost) + r.Handle(VersionedPath("/libpod/volumes/prune"), s.APIHandler(libpod.PruneVolumes)).Methods(http.MethodPost) // swagger:operation GET /libpod/volumes/{name}/json volumes inspectVolume // --- // summary: Inspect volume @@ -49,7 +76,7 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // "$ref": "#/responses/NoSuchVolume" // '500': // "$ref": "#/responses/InternalError" - r.Handle("/libpod/volumes/{name}/json", s.APIHandler(libpod.InspectVolume)).Methods(http.MethodGet) + r.Handle(VersionedPath("/libpod/volumes/{name}/json"), s.APIHandler(libpod.InspectVolume)).Methods(http.MethodGet) // swagger:operation DELETE /libpod/volumes/{name} volumes removeVolume // --- // summary: Remove volume @@ -68,12 +95,12 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // responses: // 204: // description: no error - // 400: - // $ref: "#/responses/BadParamError" // 404: // $ref: "#/responses/NoSuchVolume" + // 409: + // description: Volume is in use and cannot be removed // 500: // $ref: "#/responses/InternalError" - r.Handle("/libpod/volumes/{name}", s.APIHandler(libpod.RemoveVolume)).Methods(http.MethodDelete) + r.Handle(VersionedPath("/libpod/volumes/{name}"), s.APIHandler(libpod.RemoveVolume)).Methods(http.MethodDelete) return nil } diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go index fc409d816..011196e5a 100644 --- a/pkg/api/server/swagger.go +++ b/pkg/api/server/swagger.go @@ -1,6 +1,7 @@ package server import ( + "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/api/handlers" "github.com/containers/libpod/pkg/api/handlers/utils" ) @@ -139,3 +140,19 @@ type ok struct { ok string } } + +// Volume create response +// swagger:response VolumeCreateResponse +type swagVolumeCreateResponse struct { + // in:body + Body struct { + libpod.VolumeConfig + } +} + +// Volume list +// swagger:response VolumeList +type swagVolumeListResponse struct { + // in:body + Body []libpod.Volume +} |