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 <bbaude@redhat.com>
This commit is contained in:
baude
2019-02-11 15:36:24 -06:00
parent 0cd2243596
commit 5be818e715
14 changed files with 101 additions and 52 deletions

15
API.md
View File

@ -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 VolumeRemove(options: VolumeRemoveOpts) []string](#VolumeRemove)
[func VolumesPrune() []string, []string](#VolumesPrune)
[func WaitContainer(name: string) int](#WaitContainer) [func WaitContainer(name: string) int](#WaitContainer)
[type BuildInfo](#BuildInfo) [type BuildInfo](#BuildInfo)
@ -530,7 +532,7 @@ GetVersion returns version and build information of the podman service
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method GetVolumes(args: [[]string](#[]string), all: [bool](https://godoc.org/builtin#bool)) [Volume](#Volume)</div> method GetVolumes(args: [[]string](#[]string), all: [bool](https://godoc.org/builtin#bool)) [Volume](#Volume)</div>
GetVolumes gets slice of the volumes on a remote host
### <a name="HistoryImage"></a>func HistoryImage ### <a name="HistoryImage"></a>func HistoryImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@ -773,7 +775,7 @@ the image cannot be found in local storage; otherwise it will return a [MoreResp
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method ReceiveFile(path: [string](https://godoc.org/builtin#string), delete: [bool](https://godoc.org/builtin#bool)) [int](https://godoc.org/builtin#int)</div> method ReceiveFile(path: [string](https://godoc.org/builtin#string), delete: [bool](https://godoc.org/builtin#bool)) [int](https://godoc.org/builtin#int)</div>
ReceiveFile allows the host to send a remote client a file
### <a name="RemoveContainer"></a>func RemoveContainer ### <a name="RemoveContainer"></a>func RemoveContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@ -856,7 +858,7 @@ search results per registry.
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method SendFile(type: [string](https://godoc.org/builtin#string), length: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div> method SendFile(type: [string](https://godoc.org/builtin#string), length: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div>
Sendfile allows a remote client to send a file to the host
### <a name="StartContainer"></a>func StartContainer ### <a name="StartContainer"></a>func StartContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@ -956,12 +958,17 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.UnpausePod '{"name": "foo
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method VolumeCreate(options: [VolumeCreateOpts](#VolumeCreateOpts)) [string](https://godoc.org/builtin#string)</div> method VolumeCreate(options: [VolumeCreateOpts](#VolumeCreateOpts)) [string](https://godoc.org/builtin#string)</div>
VolumeCreate creates a volume on a remote host
### <a name="VolumeRemove"></a>func VolumeRemove ### <a name="VolumeRemove"></a>func VolumeRemove
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method VolumeRemove(options: [VolumeRemoveOpts](#VolumeRemoveOpts)) [[]string](#[]string)</div> method VolumeRemove(options: [VolumeRemoveOpts](#VolumeRemoveOpts)) [[]string](#[]string)</div>
VolumeRemove removes a volume on a remote host
### <a name="VolumesPrune"></a>func VolumesPrune
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method VolumesPrune() [[]string](#[]string), [[]string](#[]string)</div>
VolumesPrune removes unused volumes on the host
### <a name="WaitContainer"></a>func WaitContainer ### <a name="WaitContainer"></a>func WaitContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">

View File

@ -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 { func getGenerateSubCommands() []*cobra.Command {
return []*cobra.Command{ return []*cobra.Command{
_containerKubeCommand, _containerKubeCommand,

View File

@ -31,16 +31,6 @@ func getPodSubCommands() []*cobra.Command {
return []*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 // commands that only the remoteclient implements
func getGenerateSubCommands() []*cobra.Command { func getGenerateSubCommands() []*cobra.Command {
return []*cobra.Command{} return []*cobra.Command{}

View File

@ -1070,15 +1070,24 @@ method ContainerInspectData(name: string) -> (config: string)
# development of Podman only and generally should not be used. # development of Podman only and generally should not be used.
method ContainerStateData(name: string) -> (config: string) 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) 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) method ReceiveFile(path: string, delete: bool) -> (len: int)
# VolumeCreate creates a volume on a remote host
method VolumeCreate(options: VolumeCreateOpts) -> (volumeName: string) method VolumeCreate(options: VolumeCreateOpts) -> (volumeName: string)
# VolumeRemove removes a volume on a remote host
method VolumeRemove(options: VolumeRemoveOpts) -> (volumeNames: []string) method VolumeRemove(options: VolumeRemoveOpts) -> (volumeNames: []string)
# GetVolumes gets slice of the volumes on a remote host
method GetVolumes(args: []string, all: bool) -> (volumes: []Volume) 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. # ImageNotFound means the image could not be found by the provided name or ID in local storage.
error ImageNotFound (id: string) error ImageNotFound (id: string)

View File

@ -16,8 +16,16 @@ var volumeCommand = cliconfig.PodmanCommand{
Long: volumeDescription, Long: volumeDescription,
}, },
} }
var volumeSubcommands = []*cobra.Command{
_volumeCreateCommand,
_volumeLsCommand,
_volumeRmCommand,
_volumeInspectCommand,
_volumePruneCommand,
}
func init() { func init() {
volumeCommand.AddCommand(getVolumeSubCommands()...)
volumeCommand.SetUsageTemplate(UsageTemplate()) volumeCommand.SetUsageTemplate(UsageTemplate())
volumeCommand.AddCommand(volumeSubcommands...)
rootCmd.AddCommand(volumeCommand.Command)
} }

View File

@ -8,7 +8,6 @@ import (
"strings" "strings"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/adapter" "github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -44,23 +43,20 @@ func init() {
} }
func volumePrune(runtime *adapter.LocalRuntime, ctx context.Context) error { func volumePrune(runtime *adapter.LocalRuntime, ctx context.Context) error {
var lastError error prunedNames, prunedErrors := runtime.PruneVolumes(ctx)
for _, name := range prunedNames {
volumes, err := runtime.GetAllVolumes() fmt.Println(name)
if err != nil {
return err
} }
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 { for _, err := range prunedErrors {
err = runtime.RemoveVolume(ctx, vol, false, true) logrus.Errorf("%q", err)
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())
}
} }
return lastError return lastError
} }
@ -85,6 +81,5 @@ func volumePruneCmd(c *cliconfig.VolumePruneValues) error {
return nil return nil
} }
} }
return volumePrune(runtime, getContext()) return volumePrune(runtime, getContext())
} }

View File

@ -305,3 +305,8 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti
return r.Runtime.Build(ctx, options, dockerfiles...) 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)
}

View File

@ -642,3 +642,17 @@ func varlinkVolumeToVolume(r *LocalRuntime, volumes []iopodman.Volume) []*Volume
} }
return vols 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
}

View File

@ -154,3 +154,27 @@ func (r *Runtime) GetAllVolumes() ([]*Volume, error) {
return r.state.AllVolumes() 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
}

View File

@ -72,3 +72,19 @@ func (i *LibpodAPI) GetVolumes(call iopodman.VarlinkCall, args []string, all boo
} }
return call.ReplyGetVolumes(volumes) 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)
}

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (
@ -50,6 +48,7 @@ var _ = Describe("Podman volume rm", func() {
}) })
It("podman rm with --force flag", func() { It("podman rm with --force flag", func() {
SkipIfRemote()
session := podmanTest.Podman([]string{"create", "-v", "myvol:/myvol", ALPINE, "ls"}) session := podmanTest.Podman([]string{"create", "-v", "myvol:/myvol", ALPINE, "ls"})
cid := session.OutputToString() cid := session.OutputToString()
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()