From 5be818e715d57f98e4a930632bc599e3fee3aaed Mon Sep 17 00:00:00 2001 From: baude Date: Mon, 11 Feb 2019 15:36:24 -0600 Subject: [PATCH] enable podman-remote volume prune allow users to remotely prune volumes. this is the last volume command for remote enablement. as such, the volume commands are being folded back into main because they are supported for both local and remote clients. also, enable all volume tests that do not use containers as containers are not enabled for the remote client yet. Signed-off-by: baude --- API.md | 15 ++++++++++---- cmd/podman/commands.go | 12 ------------ cmd/podman/commands_remoteclient.go | 10 ---------- cmd/podman/varlink/io.podman.varlink | 9 +++++++++ cmd/podman/volume.go | 10 +++++++++- cmd/podman/volume_prune.go | 29 ++++++++++++---------------- libpod/adapter/runtime.go | 5 +++++ libpod/adapter/runtime_remote.go | 14 ++++++++++++++ libpod/runtime_volume.go | 24 +++++++++++++++++++++++ pkg/varlinkapi/volumes.go | 16 +++++++++++++++ test/e2e/volume_create_test.go | 2 -- test/e2e/volume_inspect_test.go | 2 -- test/e2e/volume_ls_test.go | 2 -- test/e2e/volume_rm_test.go | 3 +-- 14 files changed, 101 insertions(+), 52 deletions(-) diff --git a/API.md b/API.md index e44862c3fc..dea6b7a4c1 100755 --- a/API.md +++ b/API.md @@ -131,6 +131,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [func VolumeRemove(options: VolumeRemoveOpts) []string](#VolumeRemove) +[func VolumesPrune() []string, []string](#VolumesPrune) + [func WaitContainer(name: string) int](#WaitContainer) [type BuildInfo](#BuildInfo) @@ -530,7 +532,7 @@ GetVersion returns version and build information of the podman service
method GetVolumes(args: [[]string](#[]string), all: [bool](https://godoc.org/builtin#bool)) [Volume](#Volume)
- +GetVolumes gets slice of the volumes on a remote host ### func HistoryImage
@@ -773,7 +775,7 @@ the image cannot be found in local storage; otherwise it will return a [MoreResp
method ReceiveFile(path: [string](https://godoc.org/builtin#string), delete: [bool](https://godoc.org/builtin#bool)) [int](https://godoc.org/builtin#int)
- +ReceiveFile allows the host to send a remote client a file ### func RemoveContainer
@@ -856,7 +858,7 @@ search results per registry.
method SendFile(type: [string](https://godoc.org/builtin#string), length: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)
- +Sendfile allows a remote client to send a file to the host ### func StartContainer
@@ -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()