method SendFile(type: [string](https://godoc.org/builtin#string), length: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)
@@ -956,12 +958,17 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.UnpausePod '{"name": "foo
method VolumeCreate(options: [VolumeCreateOpts](#VolumeCreateOpts)) [string](https://godoc.org/builtin#string)
-
+VolumeCreate creates a volume on a remote host
###
func VolumeRemove
method VolumeRemove(options: [VolumeRemoveOpts](#VolumeRemoveOpts)) [[]string](#[]string)
+VolumeRemove removes a volume on a remote host
+###
func VolumesPrune
+
+method VolumesPrune() [[]string](#[]string), [[]string](#[]string)
+VolumesPrune removes unused volumes on the host
###
func WaitContainer
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index 90e2ab5cf1..9004a5941d 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -114,18 +114,6 @@ func getPodSubCommands() []*cobra.Command {
}
}
-// Commands that the local client implements
-func getVolumeSubCommands() []*cobra.Command {
- return []*cobra.Command{
- _volumeCreateCommand,
- _volumeLsCommand,
- _volumeRmCommand,
- _volumeInspectCommand,
- _volumePruneCommand,
- }
-}
-
-// Commands that the local client implements
func getGenerateSubCommands() []*cobra.Command {
return []*cobra.Command{
_containerKubeCommand,
diff --git a/cmd/podman/commands_remoteclient.go b/cmd/podman/commands_remoteclient.go
index 7bdba1c198..ba0a4d47ec 100644
--- a/cmd/podman/commands_remoteclient.go
+++ b/cmd/podman/commands_remoteclient.go
@@ -31,16 +31,6 @@ func getPodSubCommands() []*cobra.Command {
return []*cobra.Command{}
}
-// commands that only the remoteclient implements
-func getVolumeSubCommands() []*cobra.Command {
- return []*cobra.Command{
- _volumeCreateCommand,
- _volumeRmCommand,
- _volumeLsCommand,
- _volumeInspectCommand,
- }
-}
-
// commands that only the remoteclient implements
func getGenerateSubCommands() []*cobra.Command {
return []*cobra.Command{}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index dc6a25c44b..94947c0e01 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -1070,15 +1070,24 @@ method ContainerInspectData(name: string) -> (config: string)
# development of Podman only and generally should not be used.
method ContainerStateData(name: string) -> (config: string)
+# Sendfile allows a remote client to send a file to the host
method SendFile(type: string, length: int) -> (file_handle: string)
+
+# ReceiveFile allows the host to send a remote client a file
method ReceiveFile(path: string, delete: bool) -> (len: int)
+# VolumeCreate creates a volume on a remote host
method VolumeCreate(options: VolumeCreateOpts) -> (volumeName: string)
+# VolumeRemove removes a volume on a remote host
method VolumeRemove(options: VolumeRemoveOpts) -> (volumeNames: []string)
+# GetVolumes gets slice of the volumes on a remote host
method GetVolumes(args: []string, all: bool) -> (volumes: []Volume)
+# VolumesPrune removes unused volumes on the host
+method VolumesPrune() -> (prunedNames: []string, prunedErrors: []string)
+
# ImageNotFound means the image could not be found by the provided name or ID in local storage.
error ImageNotFound (id: string)
diff --git a/cmd/podman/volume.go b/cmd/podman/volume.go
index 36798a19e3..8a86641515 100644
--- a/cmd/podman/volume.go
+++ b/cmd/podman/volume.go
@@ -16,8 +16,16 @@ var volumeCommand = cliconfig.PodmanCommand{
Long: volumeDescription,
},
}
+var volumeSubcommands = []*cobra.Command{
+ _volumeCreateCommand,
+ _volumeLsCommand,
+ _volumeRmCommand,
+ _volumeInspectCommand,
+ _volumePruneCommand,
+}
func init() {
- volumeCommand.AddCommand(getVolumeSubCommands()...)
volumeCommand.SetUsageTemplate(UsageTemplate())
+ volumeCommand.AddCommand(volumeSubcommands...)
+ rootCmd.AddCommand(volumeCommand.Command)
}
diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go
index 74228fa5bc..a2205140fb 100644
--- a/cmd/podman/volume_prune.go
+++ b/cmd/podman/volume_prune.go
@@ -8,7 +8,6 @@ import (
"strings"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -44,23 +43,20 @@ func init() {
}
func volumePrune(runtime *adapter.LocalRuntime, ctx context.Context) error {
- var lastError error
-
- volumes, err := runtime.GetAllVolumes()
- if err != nil {
- return err
+ prunedNames, prunedErrors := runtime.PruneVolumes(ctx)
+ for _, name := range prunedNames {
+ fmt.Println(name)
}
+ if len(prunedErrors) == 0 {
+ return nil
+ }
+ // Grab the last error
+ lastError := prunedErrors[len(prunedErrors)-1]
+ // Remove the last error from the error slice
+ prunedErrors = prunedErrors[:len(prunedErrors)-1]
- for _, vol := range volumes {
- err = runtime.RemoveVolume(ctx, vol, false, true)
- if err == nil {
- fmt.Println(vol.Name())
- } else if err != libpod.ErrVolumeBeingUsed {
- if lastError != nil {
- logrus.Errorf("%q", lastError)
- }
- lastError = errors.Wrapf(err, "failed to remove volume %q", vol.Name())
- }
+ for _, err := range prunedErrors {
+ logrus.Errorf("%q", err)
}
return lastError
}
@@ -85,6 +81,5 @@ func volumePruneCmd(c *cliconfig.VolumePruneValues) error {
return nil
}
}
-
return volumePrune(runtime, getContext())
}
diff --git a/libpod/adapter/runtime.go b/libpod/adapter/runtime.go
index 3146cf5db5..02ef9af079 100644
--- a/libpod/adapter/runtime.go
+++ b/libpod/adapter/runtime.go
@@ -305,3 +305,8 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti
return r.Runtime.Build(ctx, options, dockerfiles...)
}
+
+// PruneVolumes is a wrapper function for libpod PruneVolumes
+func (r *LocalRuntime) PruneVolumes(ctx context.Context) ([]string, []error) {
+ return r.Runtime.PruneVolumes(ctx)
+}
diff --git a/libpod/adapter/runtime_remote.go b/libpod/adapter/runtime_remote.go
index 66ff5ed516..974ee63cac 100644
--- a/libpod/adapter/runtime_remote.go
+++ b/libpod/adapter/runtime_remote.go
@@ -642,3 +642,17 @@ func varlinkVolumeToVolume(r *LocalRuntime, volumes []iopodman.Volume) []*Volume
}
return vols
}
+
+// PruneVolumes removes all unused volumes from the remote system
+func (r *LocalRuntime) PruneVolumes(ctx context.Context) ([]string, []error) {
+ var errs []error
+ prunedNames, prunedErrors, err := iopodman.VolumesPrune().Call(r.Conn)
+ if err != nil {
+ return []string{}, []error{err}
+ }
+ // We need to transform the string results of the error into actual error types
+ for _, e := range prunedErrors {
+ errs = append(errs, errors.New(e))
+ }
+ return prunedNames, errs
+}
diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go
index 485f64bf15..beae50ac9d 100644
--- a/libpod/runtime_volume.go
+++ b/libpod/runtime_volume.go
@@ -154,3 +154,27 @@ func (r *Runtime) GetAllVolumes() ([]*Volume, error) {
return r.state.AllVolumes()
}
+
+// PruneVolumes removes unused volumes from the system
+func (r *Runtime) PruneVolumes(ctx context.Context) ([]string, []error) {
+ var (
+ prunedIDs []string
+ pruneErrors []error
+ )
+ vols, err := r.GetAllVolumes()
+ if err != nil {
+ pruneErrors = append(pruneErrors, err)
+ return nil, pruneErrors
+ }
+
+ for _, vol := range vols {
+ if err := r.RemoveVolume(ctx, vol, false, true); err != nil {
+ if err != ErrVolumeBeingUsed {
+ pruneErrors = append(pruneErrors, err)
+ }
+ continue
+ }
+ prunedIDs = append(prunedIDs, vol.Name())
+ }
+ return prunedIDs, pruneErrors
+}
diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go
index d41b070656..02874d2b1b 100644
--- a/pkg/varlinkapi/volumes.go
+++ b/pkg/varlinkapi/volumes.go
@@ -72,3 +72,19 @@ func (i *LibpodAPI) GetVolumes(call iopodman.VarlinkCall, args []string, all boo
}
return call.ReplyGetVolumes(volumes)
}
+
+// 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{})
+ }
+
+ // We need to take the errors and capture their strings to go back over
+ // varlink
+ for _, e := range prunedErrors {
+ errs = append(errs, e.Error())
+ }
+ return call.ReplyVolumesPrune(prunedNames, errs)
+}
diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go
index 9e525786e2..50ee63f2a3 100644
--- a/test/e2e/volume_create_test.go
+++ b/test/e2e/volume_create_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/volume_inspect_test.go b/test/e2e/volume_inspect_test.go
index aacdbe8bed..d0d5a601ef 100644
--- a/test/e2e/volume_inspect_test.go
+++ b/test/e2e/volume_inspect_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go
index d2ee558c12..119d29d9b8 100644
--- a/test/e2e/volume_ls_test.go
+++ b/test/e2e/volume_ls_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/volume_rm_test.go b/test/e2e/volume_rm_test.go
index 295b290e41..6a1e7d0e88 100644
--- a/test/e2e/volume_rm_test.go
+++ b/test/e2e/volume_rm_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
@@ -50,6 +48,7 @@ var _ = Describe("Podman volume rm", func() {
})
It("podman rm with --force flag", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"create", "-v", "myvol:/myvol", ALPINE, "ls"})
cid := session.OutputToString()
session.WaitWithDefaultTimeout()