mirror of
https://github.com/containers/podman.git
synced 2025-06-02 02:26:52 +08:00
podmanv2 volumes
add volume commands: create, inspect, ls, prune, and rm Signed-off-by: Brent Baude <bbaude@redhat.com>
This commit is contained in:
74
cmd/podmanV2/volumes/inspect.go
Normal file
74
cmd/podmanV2/volumes/inspect.go
Normal file
@ -0,0 +1,74 @@
|
||||
package volumes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/containers/buildah/pkg/formats"
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
volumeInspectDescription = `Display detailed information on one or more volumes.
|
||||
|
||||
Use a Go template to change the format from JSON.`
|
||||
inspectCommand = &cobra.Command{
|
||||
Use: "inspect [flags] VOLUME [VOLUME...]",
|
||||
Short: "Display detailed information on one or more volumes",
|
||||
Long: volumeInspectDescription,
|
||||
RunE: inspect,
|
||||
Example: `podman volume inspect myvol
|
||||
podman volume inspect --all
|
||||
podman volume inspect --format "{{.Driver}} {{.Scope}}" myvol`,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
inspectOpts = entities.VolumeInspectOptions{}
|
||||
inspectFormat string
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: inspectCommand,
|
||||
Parent: volumeCmd,
|
||||
})
|
||||
flags := inspectCommand.Flags()
|
||||
flags.BoolVarP(&inspectOpts.All, "all", "a", false, "Inspect all volumes")
|
||||
flags.StringVarP(&inspectFormat, "format", "f", "json", "Format volume output using Go template")
|
||||
}
|
||||
|
||||
func inspect(cmd *cobra.Command, args []string) error {
|
||||
if (inspectOpts.All && len(args) > 0) || (!inspectOpts.All && len(args) < 1) {
|
||||
return errors.New("provide one or more volume names or use --all")
|
||||
}
|
||||
responses, err := registry.ContainerEngine().VolumeInspect(context.Background(), args, inspectOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch inspectFormat {
|
||||
case "", formats.JSONString:
|
||||
jsonOut, err := json.MarshalIndent(responses, "", " ")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error marshalling inspect JSON")
|
||||
}
|
||||
fmt.Println(string(jsonOut))
|
||||
default:
|
||||
tmpl, err := template.New("volumeInspect").Parse(inspectFormat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tmpl.Execute(os.Stdout, responses); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
98
cmd/podmanV2/volumes/list.go
Normal file
98
cmd/podmanV2/volumes/list.go
Normal file
@ -0,0 +1,98 @@
|
||||
package volumes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
volumeLsDescription = `
|
||||
podman volume ls
|
||||
|
||||
List all available volumes. The output of the volumes can be filtered
|
||||
and the output format can be changed to JSON or a user specified Go template.`
|
||||
lsCommand = &cobra.Command{
|
||||
Use: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Args: cobra.NoArgs,
|
||||
Short: "List volumes",
|
||||
Long: volumeLsDescription,
|
||||
RunE: list,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// Temporary struct to hold cli values.
|
||||
cliOpts = struct {
|
||||
Filter []string
|
||||
Format string
|
||||
Quiet bool
|
||||
}{}
|
||||
lsOpts = entities.VolumeListOptions{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: lsCommand,
|
||||
Parent: volumeCmd,
|
||||
})
|
||||
flags := lsCommand.Flags()
|
||||
flags.StringSliceVarP(&cliOpts.Filter, "filter", "f", []string{}, "Filter volume output")
|
||||
flags.StringVar(&cliOpts.Format, "format", "{{.Driver}}\t{{.Name}}\n", "Format volume output using Go template")
|
||||
flags.BoolVarP(&cliOpts.Quiet, "quiet", "q", false, "Print volume output in quiet mode")
|
||||
}
|
||||
|
||||
func list(cmd *cobra.Command, args []string) error {
|
||||
var w io.Writer = os.Stdout
|
||||
if cliOpts.Quiet && cmd.Flag("format").Changed {
|
||||
return errors.New("quiet and format flags cannot be used together")
|
||||
}
|
||||
for _, f := range cliOpts.Filter {
|
||||
filterSplit := strings.Split(f, "=")
|
||||
if len(filterSplit) < 2 {
|
||||
return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
|
||||
}
|
||||
lsOpts.Filter[filterSplit[0]] = append(lsOpts.Filter[filterSplit[0]], filterSplit[1:]...)
|
||||
}
|
||||
responses, err := registry.ContainerEngine().VolumeList(context.Background(), lsOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// "\t" from the command line is not being recognized as a tab
|
||||
// replacing the string "\t" to a tab character if the user passes in "\t"
|
||||
cliOpts.Format = strings.Replace(cliOpts.Format, `\t`, "\t", -1)
|
||||
if cliOpts.Quiet {
|
||||
cliOpts.Format = "{{.Name}}\n"
|
||||
}
|
||||
headers := "DRIVER\tVOLUME NAME\n"
|
||||
row := cliOpts.Format
|
||||
if !strings.HasSuffix(cliOpts.Format, "\n") {
|
||||
row += "\n"
|
||||
}
|
||||
format := "{{range . }}" + row + "{{end}}"
|
||||
if !cliOpts.Quiet && !cmd.Flag("format").Changed {
|
||||
w = tabwriter.NewWriter(os.Stdout, 12, 2, 2, ' ', 0)
|
||||
format = headers + format
|
||||
}
|
||||
tmpl, err := template.New("listVolume").Parse(format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tmpl.Execute(w, responses); err != nil {
|
||||
return err
|
||||
}
|
||||
if flusher, ok := w.(interface{ Flush() error }); ok {
|
||||
return flusher.Flush()
|
||||
}
|
||||
return nil
|
||||
}
|
74
cmd/podmanV2/volumes/prune.go
Normal file
74
cmd/podmanV2/volumes/prune.go
Normal file
@ -0,0 +1,74 @@
|
||||
package volumes
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/cmd/podmanV2/utils"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
volumePruneDescription = `Volumes that are not currently owned by a container will be removed.
|
||||
|
||||
The command prompts for confirmation which can be overridden with the --force flag.
|
||||
Note all data will be destroyed.`
|
||||
pruneCommand = &cobra.Command{
|
||||
Use: "prune",
|
||||
Args: cobra.NoArgs,
|
||||
Short: "Remove all unused volumes",
|
||||
Long: volumePruneDescription,
|
||||
RunE: prune,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
pruneOptions entities.VolumePruneOptions
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: pruneCommand,
|
||||
Parent: volumeCmd,
|
||||
})
|
||||
flags := pruneCommand.Flags()
|
||||
flags.BoolVarP(&pruneOptions.Force, "force", "f", false, "Do not prompt for confirmation")
|
||||
}
|
||||
|
||||
func prune(cmd *cobra.Command, args []string) error {
|
||||
var (
|
||||
errs utils.OutputErrors
|
||||
)
|
||||
// Prompt for confirmation if --force is not set
|
||||
if !pruneOptions.Force {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Println("WARNING! This will remove all volumes not used by at least one container.")
|
||||
fmt.Print("Are you sure you want to continue? [y/N] ")
|
||||
answer, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error reading input")
|
||||
}
|
||||
if strings.ToLower(answer)[0] != 'y' {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
responses, err := registry.ContainerEngine().VolumePrune(context.Background(), pruneOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range responses {
|
||||
if r.Err == nil {
|
||||
fmt.Println(r.Id)
|
||||
} else {
|
||||
errs = append(errs, r.Err)
|
||||
}
|
||||
}
|
||||
return errs.PrintErrors()
|
||||
}
|
64
cmd/podmanV2/volumes/rm.go
Normal file
64
cmd/podmanV2/volumes/rm.go
Normal file
@ -0,0 +1,64 @@
|
||||
package volumes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/cmd/podmanV2/utils"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
volumeRmDescription = `Remove one or more existing volumes.
|
||||
|
||||
By default only volumes that are not being used by any containers will be removed. To remove the volumes anyways, use the --force flag.`
|
||||
rmCommand = &cobra.Command{
|
||||
Use: "rm [flags] VOLUME [VOLUME...]",
|
||||
Aliases: []string{"remove"},
|
||||
Short: "Remove one or more volumes",
|
||||
Long: volumeRmDescription,
|
||||
RunE: rm,
|
||||
Example: `podman volume rm myvol1 myvol2
|
||||
podman volume rm --all
|
||||
podman volume rm --force myvol`,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
rmOptions = entities.VolumeRmOptions{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: rmCommand,
|
||||
Parent: volumeCmd,
|
||||
})
|
||||
flags := rmCommand.Flags()
|
||||
flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all volumes")
|
||||
flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Remove a volume by force, even if it is being used by a container")
|
||||
}
|
||||
|
||||
func rm(cmd *cobra.Command, args []string) error {
|
||||
var (
|
||||
errs utils.OutputErrors
|
||||
)
|
||||
if (len(args) > 0 && rmOptions.All) || (len(args) < 1 && !rmOptions.All) {
|
||||
return errors.New("choose either one or more volumes or all")
|
||||
}
|
||||
responses, err := registry.ContainerEngine().VolumeRm(context.Background(), args, rmOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range responses {
|
||||
if r.Err == nil {
|
||||
fmt.Println(r.Id)
|
||||
} else {
|
||||
errs = append(errs, r.Err)
|
||||
}
|
||||
}
|
||||
return errs.PrintErrors()
|
||||
}
|
1
go.mod
1
go.mod
@ -59,6 +59,7 @@ require (
|
||||
github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b
|
||||
github.com/vishvananda/netlink v1.1.0
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/containers/libpod/libpod/events"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -35,7 +36,6 @@ func (r *Runtime) RemoveVolume(ctx context.Context, v *Volume, force bool) error
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return r.removeVolume(ctx, v, force)
|
||||
}
|
||||
|
||||
@ -130,26 +130,24 @@ func (r *Runtime) GetAllVolumes() ([]*Volume, error) {
|
||||
}
|
||||
|
||||
// PruneVolumes removes unused volumes from the system
|
||||
func (r *Runtime) PruneVolumes(ctx context.Context) ([]string, []error) {
|
||||
func (r *Runtime) PruneVolumes(ctx context.Context) ([]*entities.VolumePruneReport, error) {
|
||||
var (
|
||||
prunedIDs []string
|
||||
pruneErrors []error
|
||||
reports []*entities.VolumePruneReport
|
||||
)
|
||||
vols, err := r.GetAllVolumes()
|
||||
if err != nil {
|
||||
pruneErrors = append(pruneErrors, err)
|
||||
return nil, pruneErrors
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, vol := range vols {
|
||||
if err := r.RemoveVolume(ctx, vol, false); err != nil {
|
||||
if errors.Cause(err) != define.ErrVolumeBeingUsed && errors.Cause(err) != define.ErrVolumeRemoved {
|
||||
pruneErrors = append(pruneErrors, err)
|
||||
reports = append(reports, &entities.VolumePruneReport{Id: vol.Name(), Err: err})
|
||||
}
|
||||
continue
|
||||
}
|
||||
vol.newVolumeEvent(events.Prune)
|
||||
prunedIDs = append(prunedIDs, vol.Name())
|
||||
reports = append(reports, &entities.VolumePruneReport{Id: vol.Name()})
|
||||
}
|
||||
return prunedIDs, pruneErrors
|
||||
return reports, nil
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
// ---
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 }
|
||||
|
@ -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
|
||||
}
|
||||
|
70
pkg/domain/filters/volumes.go
Normal file
70
pkg/domain/filters/volumes.go
Normal file
@ -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
|
||||
}
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
Reference in New Issue
Block a user