From ae614920bfe2510ca6d1dd6cea02bbe17ddb245c Mon Sep 17 00:00:00 2001 From: Brent Baude Date: Sat, 21 Mar 2020 14:29:30 -0500 Subject: podmanv2 volumes add volume commands: create, inspect, ls, prune, and rm Signed-off-by: Brent Baude --- pkg/adapter/runtime.go | 18 +++- pkg/api/handlers/libpod/volumes.go | 140 ++++++++++---------------------- pkg/api/server/register_volumes.go | 10 +-- pkg/api/server/swagger.go | 7 ++ pkg/bindings/volumes/volumes.go | 15 ++-- pkg/domain/entities/engine_container.go | 9 +- pkg/domain/entities/types.go | 8 -- pkg/domain/entities/volumes.go | 89 +++++++++++++++----- pkg/domain/filters/volumes.go | 70 ++++++++++++++++ pkg/domain/infra/abi/containers.go | 20 ----- pkg/domain/infra/abi/volumes.go | 108 ++++++++++++++++++++++++ pkg/domain/infra/tunnel/containers.go | 7 -- pkg/domain/infra/tunnel/runtime.go | 18 ---- pkg/domain/infra/tunnel/volumes.go | 54 ++++++++++++ pkg/varlinkapi/volumes.go | 24 +++--- 15 files changed, 398 insertions(+), 199 deletions(-) create mode 100644 pkg/domain/filters/volumes.go (limited to 'pkg') diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index dfe6b7f07..7817a1f98 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -347,7 +347,23 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti // PruneVolumes is a wrapper function for libpod PruneVolumes func (r *LocalRuntime) PruneVolumes(ctx context.Context) ([]string, []error) { - return r.Runtime.PruneVolumes(ctx) + var ( + vids []string + errs []error + ) + reports, err := r.Runtime.PruneVolumes(ctx) + if err != nil { + errs = append(errs, err) + return vids, errs + } + for _, r := range reports { + if r.Err == nil { + vids = append(vids, r.Id) + } else { + errs = append(errs, r.Err) + } + } + return vids, errs } // SaveImage is a wrapper function for saving an image to the local filesystem diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go index 06ca1d225..e61d272f4 100644 --- a/pkg/api/handlers/libpod/volumes.go +++ b/pkg/api/handlers/libpod/volumes.go @@ -3,16 +3,15 @@ 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/utils" "github.com/containers/libpod/pkg/domain/entities" + "github.com/containers/libpod/pkg/domain/filters" "github.com/gorilla/schema" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" ) func CreateVolume(w http.ResponseWriter, r *http.Request) { @@ -65,14 +64,14 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { return } volResponse := entities.VolumeConfigResponse{ - Name: config.Name, - Labels: config.Labels, - Driver: config.Driver, - MountPoint: config.MountPoint, - CreatedTime: config.CreatedTime, - Options: config.Options, - UID: config.UID, - GID: config.GID, + Name: config.Name, + Driver: config.Driver, + Mountpoint: config.MountPoint, + CreatedAt: config.CreatedTime, + Labels: config.Labels, + Options: config.Options, + UID: config.UID, + GID: config.GID, } utils.WriteResponse(w, http.StatusOK, volResponse) } @@ -85,21 +84,27 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) { vol, err := runtime.GetVolume(name) if err != nil { utils.VolumeNotFound(w, name, err) + return } - inspect, err := vol.Inspect() - if err != nil { - utils.InternalServerError(w, err) + volResponse := entities.VolumeConfigResponse{ + Name: vol.Name(), + Driver: vol.Driver(), + Mountpoint: vol.MountPoint(), + CreatedAt: vol.CreatedTime(), + Labels: vol.Labels(), + Scope: vol.Scope(), + Options: vol.Options(), + UID: vol.UID(), + GID: vol.GID(), } - utils.WriteResponse(w, http.StatusOK, inspect) + utils.WriteResponse(w, http.StatusOK, volResponse) } func ListVolumes(w http.ResponseWriter, r *http.Request) { var ( decoder = r.Context().Value("decoder").(*schema.Decoder) - err error runtime = r.Context().Value("runtime").(*libpod.Runtime) - volumeConfigs []*libpod.VolumeConfig - volumeFilters []libpod.VolumeFilter + volumeConfigs []*entities.VolumeListReport ) query := struct { Filters map[string][]string `schema:"filters"` @@ -113,25 +118,30 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) { return } - if len(query.Filters) > 0 { - volumeFilters, err = generateVolumeFilters(query.Filters) - if err != nil { - utils.InternalServerError(w, err) - return - } + volumeFilters, err := filters.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 + config := entities.VolumeConfigResponse{ + Name: v.Name(), + Driver: v.Driver(), + Mountpoint: v.MountPoint(), + CreatedAt: v.CreatedTime(), + Labels: v.Labels(), + Scope: v.Scope(), + Options: v.Options(), + UID: v.UID(), + GID: v.GID(), } - volumeConfigs = append(volumeConfigs, config) + volumeConfigs = append(volumeConfigs, &entities.VolumeListReport{VolumeConfigResponse: config}) } utils.WriteResponse(w, http.StatusOK, volumeConfigs) } @@ -140,14 +150,10 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) { var ( runtime = r.Context().Value("runtime").(*libpod.Runtime) ) - pruned, errs := runtime.PruneVolumes(r.Context()) - if errs != nil { - if len(errs) > 1 { - for _, err := range errs { - log.Infof("Request Failed(%s): %s", http.StatusText(http.StatusInternalServerError), err.Error()) - } - } - utils.InternalServerError(w, errs[len(errs)-1]) + pruned, err := runtime.PruneVolumes(r.Context()) + if err != nil { + utils.InternalServerError(w, err) + return } utils.WriteResponse(w, http.StatusOK, pruned) } @@ -184,65 +190,3 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) { } 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/server/register_volumes.go b/pkg/api/server/register_volumes.go index 2cf249cc3..93b972b6b 100644 --- a/pkg/api/server/register_volumes.go +++ b/pkg/api/server/register_volumes.go @@ -53,8 +53,8 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // produces: // - application/json // responses: - // '204': - // description: no error + // '200': + // "$ref": "#/responses/VolumePruneResponse" // '500': // "$ref": "#/responses/InternalError" r.Handle(VersionedPath("/libpod/volumes/prune"), s.APIHandler(libpod.PruneVolumes)).Methods(http.MethodPost) @@ -71,11 +71,11 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // - application/json // responses: // '200': - // "$ref": "#/responses/InspectVolumeResponse" + // "$ref": "#/responses/VolumeCreateResponse" // '404': - // "$ref": "#/responses/NoSuchVolume" + // "$ref": "#/responses/NoSuchVolume" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/InternalError" r.Handle(VersionedPath("/libpod/volumes/{name}/json"), s.APIHandler(libpod.InspectVolume)).Methods(http.MethodGet) // swagger:operation DELETE /libpod/volumes/{name} volumes removeVolume // --- diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go index 2e1a269f2..50ce42b3b 100644 --- a/pkg/api/server/swagger.go +++ b/pkg/api/server/swagger.go @@ -151,6 +151,13 @@ type ok struct { } } +// Volume prune response +// swagger:response VolumePruneResponse +type swagVolumePruneResponse struct { + // in:body + Body []entities.VolumePruneReport +} + // Volume create response // swagger:response VolumeCreateResponse type swagVolumeCreateResponse struct { diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go index a2164e0af..cef9246cb 100644 --- a/pkg/bindings/volumes/volumes.go +++ b/pkg/bindings/volumes/volumes.go @@ -7,7 +7,6 @@ import ( "strconv" "strings" - "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/bindings" "github.com/containers/libpod/pkg/domain/entities" jsoniter "github.com/json-iterator/go" @@ -35,9 +34,9 @@ func Create(ctx context.Context, config entities.VolumeCreateOptions) (*entities } // Inspect returns low-level information about a volume. -func Inspect(ctx context.Context, nameOrID string) (*libpod.InspectVolumeData, error) { +func Inspect(ctx context.Context, nameOrID string) (*entities.VolumeConfigResponse, error) { var ( - inspect libpod.InspectVolumeData + inspect entities.VolumeConfigResponse ) conn, err := bindings.GetClient(ctx) if err != nil { @@ -52,9 +51,9 @@ func Inspect(ctx context.Context, nameOrID string) (*libpod.InspectVolumeData, e // List returns the configurations for existing volumes in the form of a slice. Optionally, filters // can be used to refine the list of volumes. -func List(ctx context.Context, filters map[string][]string) ([]*libpod.VolumeConfig, error) { +func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeListReport, error) { var ( - vols []*libpod.VolumeConfig + vols []*entities.VolumeListReport ) conn, err := bindings.GetClient(ctx) if err != nil { @@ -76,9 +75,9 @@ func List(ctx context.Context, filters map[string][]string) ([]*libpod.VolumeCon } // Prune removes unused volumes from the local filesystem. -func Prune(ctx context.Context) ([]string, error) { +func Prune(ctx context.Context) ([]*entities.VolumePruneReport, error) { var ( - pruned []string + pruned []*entities.VolumePruneReport ) conn, err := bindings.GetClient(ctx) if err != nil { @@ -86,7 +85,7 @@ func Prune(ctx context.Context) ([]string, error) { } response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", nil) if err != nil { - return pruned, err + return nil, err } return pruned, response.Process(&pruned) } diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 2887f0b51..2efdbd602 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -5,7 +5,6 @@ import ( ) type ContainerEngine interface { - ContainerPrune(ctx context.Context) (*ContainerPruneReport, error) ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error) ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error) ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) @@ -14,10 +13,10 @@ type ContainerEngine interface { ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error) ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error) - PodDelete(ctx context.Context, opts PodPruneOptions) (*PodDeleteReport, error) PodExists(ctx context.Context, nameOrId string) (*BoolReport, error) - PodPrune(ctx context.Context) (*PodPruneReport, error) VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IdOrNameResponse, error) - VolumeDelete(ctx context.Context, opts VolumeDeleteOptions) (*VolumeDeleteReport, error) - VolumePrune(ctx context.Context) (*VolumePruneReport, error) + VolumeInspect(ctx context.Context, namesOrIds []string, opts VolumeInspectOptions) ([]*VolumeInspectReport, error) + VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error) + VolumePrune(ctx context.Context, opts VolumePruneOptions) ([]*VolumePruneReport, error) + VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error) } diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go index 6f947dc4d..e7757a74b 100644 --- a/pkg/domain/entities/types.go +++ b/pkg/domain/entities/types.go @@ -13,13 +13,5 @@ type Report struct { Err map[string]error } -type ContainerDeleteOptions struct{} -type ContainerDeleteReport struct{ Report } -type ContainerPruneReport struct{ Report } - type PodDeleteReport struct{ Report } type PodPruneOptions struct{} -type PodPruneReport struct{ Report } -type VolumeDeleteOptions struct{} -type VolumeDeleteReport struct{ Report } -type VolumePruneReport struct{ Report } diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go index ad12d0d01..23c066083 100644 --- a/pkg/domain/entities/volumes.go +++ b/pkg/domain/entities/volumes.go @@ -1,6 +1,8 @@ package entities -import "time" +import ( + "time" +) // swagger:model VolumeCreate type VolumeCreateOptions struct { @@ -20,22 +22,71 @@ type IdOrNameResponse struct { } type VolumeConfigResponse struct { - // Name of the volume. - Name string `json:"name"` - Labels map[string]string `json:"labels"` - // The volume driver. Empty string or local does not activate a volume - // driver, all other volumes will. - Driver string `json:"volumeDriver"` - // The location the volume is mounted at. - MountPoint string `json:"mountPoint"` - // Time the volume was created. - CreatedTime time.Time `json:"createdAt,omitempty"` - // Options to pass to the volume driver. For the local driver, this is - // a list of mount options. For other drivers, they are passed to the - // volume driver handling the volume. - Options map[string]string `json:"volumeOptions,omitempty"` - // UID the volume will be created as. - UID int `json:"uid"` - // GID the volume will be created as. - GID int `json:"gid"` + // Name is the name of the volume. + Name string `json:"Name"` + // Driver is the driver used to create the volume. + // This will be properly implemented in a future version. + Driver string `json:"Driver"` + // Mountpoint is the path on the host where the volume is mounted. + Mountpoint string `json:"Mountpoint"` + // CreatedAt is the date and time the volume was created at. This is not + // stored for older Libpod volumes; if so, it will be omitted. + CreatedAt time.Time `json:"CreatedAt,omitempty"` + // Status is presently unused and provided only for Docker compatibility. + // In the future it will be used to return information on the volume's + // current state. + Status map[string]string `json:"Status,omitempty"` + // Labels includes the volume's configured labels, key:value pairs that + // can be passed during volume creation to provide information for third + // party tools. + Labels map[string]string `json:"Labels"` + // Scope is unused and provided solely for Docker compatibility. It is + // unconditionally set to "local". + Scope string `json:"Scope"` + // Options is a set of options that were used when creating the volume. + // It is presently not used. + Options map[string]string `json:"Options"` + // UID is the UID that the volume was created with. + UID int `json:"UID,omitempty"` + // GID is the GID that the volume was created with. + GID int `json:"GID,omitempty"` + // Anonymous indicates that the volume was created as an anonymous + // volume for a specific container, and will be be removed when any + // container using it is removed. + Anonymous bool `json:"Anonymous,omitempty"` +} + +type VolumeRmOptions struct { + All bool + Force bool +} + +type VolumeRmReport struct { + Err error + Id string +} + +type VolumeInspectOptions struct { + All bool +} + +type VolumeInspectReport struct { + *VolumeConfigResponse +} + +type VolumePruneOptions struct { + Force bool +} + +type VolumePruneReport struct { + Err error + Id string +} + +type VolumeListOptions struct { + Filter map[string][]string +} + +type VolumeListReport struct { + VolumeConfigResponse } diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go new file mode 100644 index 000000000..f97c3f570 --- /dev/null +++ b/pkg/domain/filters/volumes.go @@ -0,0 +1,70 @@ +package filters + +import ( + "strings" + + "github.com/containers/libpod/libpod" + "github.com/pkg/errors" +) + +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/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 47deb010a..a3da310c2 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -239,23 +239,3 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, } return reports, nil } - -func (ic *ContainerEngine) ContainerPrune(ctx context.Context) (*entities.ContainerPruneReport, error) { - panic("implement me") -} - -func (ic *ContainerEngine) PodDelete(ctx context.Context, opts entities.PodPruneOptions) (*entities.PodDeleteReport, error) { - panic("implement me") -} - -func (ic *ContainerEngine) PodPrune(ctx context.Context) (*entities.PodPruneReport, error) { - panic("implement me") -} - -func (ic *ContainerEngine) VolumeDelete(ctx context.Context, opts entities.VolumeDeleteOptions) (*entities.VolumeDeleteReport, error) { - panic("implement me") -} - -func (ic *ContainerEngine) VolumePrune(ctx context.Context) (*entities.VolumePruneReport, error) { - panic("implement me") -} diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go index 0783af441..0cc20474e 100644 --- a/pkg/domain/infra/abi/volumes.go +++ b/pkg/domain/infra/abi/volumes.go @@ -7,7 +7,9 @@ import ( "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/domain/entities" + "github.com/containers/libpod/pkg/domain/filters" "github.com/containers/libpod/pkg/domain/infra/abi/parse" + "github.com/pkg/errors" ) func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IdOrNameResponse, error) { @@ -36,3 +38,109 @@ func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.Volum } return &entities.IdOrNameResponse{IdOrName: vol.Name()}, nil } + +func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, opts entities.VolumeRmOptions) ([]*entities.VolumeRmReport, error) { + var ( + err error + reports []*entities.VolumeRmReport + vols []*libpod.Volume + ) + if opts.All { + vols, err = ic.Libpod.Volumes() + if err != nil { + return nil, err + } + } else { + for _, id := range namesOrIds { + vol, err := ic.Libpod.LookupVolume(id) + if err != nil { + reports = append(reports, &entities.VolumeRmReport{ + Err: err, + Id: id, + }) + continue + } + vols = append(vols, vol) + } + } + for _, vol := range vols { + reports = append(reports, &entities.VolumeRmReport{ + Err: ic.Libpod.RemoveVolume(ctx, vol, opts.Force), + Id: vol.Name(), + }) + } + return reports, nil +} + +func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.VolumeInspectOptions) ([]*entities.VolumeInspectReport, error) { + var ( + err error + reports []*entities.VolumeInspectReport + vols []*libpod.Volume + ) + + // Note: as with previous implementation, a single failure here + // results a return. + if opts.All { + vols, err = ic.Libpod.GetAllVolumes() + if err != nil { + return nil, err + } + } else { + for _, v := range namesOrIds { + vol, err := ic.Libpod.LookupVolume(v) + if err != nil { + return nil, errors.Wrapf(err, "error inspecting volume %s", v) + } + vols = append(vols, vol) + } + } + for _, v := range vols { + config := entities.VolumeConfigResponse{ + Name: v.Name(), + Driver: v.Driver(), + Mountpoint: v.MountPoint(), + CreatedAt: v.CreatedTime(), + Labels: v.Labels(), + Scope: v.Scope(), + Options: v.Options(), + UID: v.UID(), + GID: v.GID(), + } + reports = append(reports, &entities.VolumeInspectReport{&config}) + } + return reports, nil +} + +func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) { + return ic.Libpod.PruneVolumes(ctx) +} + +func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) { + var ( + reports []*entities.VolumeListReport + ) + volumeFilters, err := filters.GenerateVolumeFilters(opts.Filter) + if err != nil { + return nil, err + } + vols, err := ic.Libpod.Volumes(volumeFilters...) + if err != nil { + return nil, err + } + for _, v := range vols { + config := entities.VolumeConfigResponse{ + Name: v.Name(), + Driver: v.Driver(), + Mountpoint: v.MountPoint(), + CreatedAt: v.CreatedTime(), + Labels: v.Labels(), + Scope: v.Scope(), + Options: v.Options(), + UID: v.UID(), + GID: v.GID(), + } + reports = append(reports, &entities.VolumeListReport{config}) + } + return reports, nil +} diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 21f62df6b..a8ecff41b 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -33,13 +33,6 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin return responses, nil } -func (r *ContainerEngine) ContainerDelete(ctx context.Context, opts entities.ContainerDeleteOptions) (*entities.ContainerDeleteReport, error) { - panic("implement me") -} - -func (r *ContainerEngine) ContainerPrune(ctx context.Context) (*entities.ContainerPruneReport, error) { - panic("implement me") -} func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { var ( reports []*entities.PauseUnpauseReport diff --git a/pkg/domain/infra/tunnel/runtime.go b/pkg/domain/infra/tunnel/runtime.go index eb9b34e4a..c111f99e9 100644 --- a/pkg/domain/infra/tunnel/runtime.go +++ b/pkg/domain/infra/tunnel/runtime.go @@ -2,8 +2,6 @@ package tunnel import ( "context" - - "github.com/containers/libpod/pkg/domain/entities" ) // Image-related runtime using an ssh-tunnel to utilize Podman service @@ -15,19 +13,3 @@ type ImageEngine struct { type ContainerEngine struct { ClientCxt context.Context } - -func (r *ContainerEngine) PodDelete(ctx context.Context, opts entities.PodPruneOptions) (*entities.PodDeleteReport, error) { - panic("implement me") -} - -func (r *ContainerEngine) PodPrune(ctx context.Context) (*entities.PodPruneReport, error) { - panic("implement me") -} - -func (r *ContainerEngine) VolumeDelete(ctx context.Context, opts entities.VolumeDeleteOptions) (*entities.VolumeDeleteReport, error) { - panic("implement me") -} - -func (r *ContainerEngine) VolumePrune(ctx context.Context) (*entities.VolumePruneReport, error) { - panic("implement me") -} diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go index 49cf6a2f6..e48a7fa7c 100644 --- a/pkg/domain/infra/tunnel/volumes.go +++ b/pkg/domain/infra/tunnel/volumes.go @@ -14,3 +14,57 @@ func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.Volum } return &entities.IdOrNameResponse{IdOrName: response.Name}, nil } + +func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, opts entities.VolumeRmOptions) ([]*entities.VolumeRmReport, error) { + var ( + reports []*entities.VolumeRmReport + ) + + if opts.All { + vols, err := volumes.List(ic.ClientCxt, nil) + if err != nil { + return nil, err + } + for _, v := range vols { + namesOrIds = append(namesOrIds, v.Name) + } + } + for _, id := range namesOrIds { + reports = append(reports, &entities.VolumeRmReport{ + Err: volumes.Remove(ic.ClientCxt, id, &opts.Force), + Id: id, + }) + } + return reports, nil +} + +func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.VolumeInspectOptions) ([]*entities.VolumeInspectReport, error) { + var ( + reports []*entities.VolumeInspectReport + ) + if opts.All { + vols, err := volumes.List(ic.ClientCxt, nil) + if err != nil { + return nil, err + } + for _, v := range vols { + namesOrIds = append(namesOrIds, v.Name) + } + } + for _, id := range namesOrIds { + data, err := volumes.Inspect(ic.ClientCxt, id) + if err != nil { + return nil, err + } + reports = append(reports, &entities.VolumeInspectReport{VolumeConfigResponse: data}) + } + return reports, nil +} + +func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) { + return volumes.Prune(ic.ClientCxt) +} + +func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) { + return volumes.List(ic.ClientCxt, opts.Filter) +} diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go index 2dddd3008..cbb4a70cc 100644 --- a/pkg/varlinkapi/volumes.go +++ b/pkg/varlinkapi/volumes.go @@ -105,16 +105,20 @@ func (i *LibpodAPI) InspectVolume(call iopodman.VarlinkCall, name string) error // VolumesPrune removes unused images via a varlink call func (i *LibpodAPI) VolumesPrune(call iopodman.VarlinkCall) error { - var errs []string - prunedNames, prunedErrors := i.Runtime.PruneVolumes(getContext()) - if len(prunedErrors) == 0 { - return call.ReplyVolumesPrune(prunedNames, []string{}) + var ( + prunedErrors []string + prunedNames []string + ) + responses, err := i.Runtime.PruneVolumes(getContext()) + if err != nil { + return call.ReplyVolumesPrune([]string{}, []string{err.Error()}) } - - // We need to take the errors and capture their strings to go back over - // varlink - for _, e := range prunedErrors { - errs = append(errs, e.Error()) + for _, i := range responses { + if i.Err == nil { + prunedNames = append(prunedNames, i.Id) + } else { + prunedErrors = append(prunedErrors, i.Err.Error()) + } } - return call.ReplyVolumesPrune(prunedNames, errs) + return call.ReplyVolumesPrune(prunedNames, prunedErrors) } -- cgit v1.2.3-54-g00ecf