mirror of
https://github.com/containers/podman.git
synced 2025-05-21 09:05:56 +08:00
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:
15
API.md
15
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 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;">
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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{}
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// +build !remoteclient
|
|
||||||
|
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// +build !remoteclient
|
|
||||||
|
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// +build !remoteclient
|
|
||||||
|
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -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()
|
||||||
|
Reference in New Issue
Block a user