podman-remote volume inspect|ls

add the ability to list and inspect volumes using the remote
client and varlink

Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
baude
2019-02-11 12:47:47 -06:00
parent 8a16f83b0a
commit 4f60f79a27
9 changed files with 260 additions and 38 deletions

38
API.md
View File

@ -53,6 +53,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func GetVersion() string, string, string, string, string, int](#GetVersion)
[func GetVolumes(args: []string, all: bool) Volume](#GetVolumes)
[func HistoryImage(name: string) ImageHistory](#HistoryImage)
[func ImageExists(name: string) int](#ImageExists)
@ -175,6 +177,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[type MoreResponse](#MoreResponse)
[type NotImplemented](#NotImplemented)
[type PodContainerErrorData](#PodContainerErrorData)
[type PodCreate](#PodCreate)
@ -185,6 +189,10 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[type Sockets](#Sockets)
[type StringResponse](#StringResponse)
[type Volume](#Volume)
[type VolumeCreateOpts](#VolumeCreateOpts)
[type VolumeRemoveOpts](#VolumeRemoveOpts)
@ -516,6 +524,11 @@ $ varlink call unix:/run/podman/io.podman/io.podman.GetPodStats '{"name": "7f62b
method GetVersion() [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [int](https://godoc.org/builtin#int)</div>
GetVersion returns version and build information of the podman service
### <a name="GetVolumes"></a>func GetVolumes
<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>
### <a name="HistoryImage"></a>func HistoryImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@ -1480,6 +1493,11 @@ MoreResponse is a struct for when responses from varlink requires longer output
logs [[]string](#[]string)
id [string](https://godoc.org/builtin#string)
### <a name="NotImplemented"></a>type NotImplemented
comment [string](https://godoc.org/builtin#string)
### <a name="PodContainerErrorData"></a>type PodContainerErrorData
@ -1557,6 +1575,26 @@ container_id [string](https://godoc.org/builtin#string)
io_socket [string](https://godoc.org/builtin#string)
control_socket [string](https://godoc.org/builtin#string)
### <a name="StringResponse"></a>type StringResponse
message [string](https://godoc.org/builtin#string)
### <a name="Volume"></a>type Volume
name [string](https://godoc.org/builtin#string)
labels [map[string]](#map[string])
mountPoint [string](https://godoc.org/builtin#string)
driver [string](https://godoc.org/builtin#string)
options [map[string]](#map[string])
scope [string](https://godoc.org/builtin#string)
### <a name="VolumeCreateOpts"></a>type VolumeCreateOpts

View File

@ -36,6 +36,8 @@ func getVolumeSubCommands() []*cobra.Command {
return []*cobra.Command{
_volumeCreateCommand,
_volumeRmCommand,
_volumeLsCommand,
_volumeInspectCommand,
}
}

View File

@ -2,6 +2,22 @@
# in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in the upstream libpod repository.
interface io.podman
type Volume (
name: string,
labels: [string]string,
mountPoint: string,
driver: string,
options: [string]string,
scope: string
)
type NotImplemented (
comment: string
)
type StringResponse (
message: string
)
# ContainerChanges describes the return struct for ListContainerChanges
type ContainerChanges (
@ -1044,6 +1060,7 @@ method VolumeCreate(options: VolumeCreateOpts) -> (volumeName: string)
method VolumeRemove(options: VolumeRemoveOpts) -> (volumeNames: []string)
method GetVolumes(args: []string, all: bool) -> (volumes: []Volume)
# ImageNotFound means the image could not be found by the provided name or ID in local storage.
error ImageNotFound (id: string)

View File

@ -2,9 +2,8 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@ -39,22 +38,19 @@ func init() {
}
func volumeInspectCmd(c *cliconfig.VolumeInspectValues) error {
var err error
if (c.All && len(c.InputArgs) > 0) || (!c.All && len(c.InputArgs) < 1) {
return errors.New("provide one or more volume names or use --all")
}
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
defer runtime.Shutdown(false)
opts := volumeLsOptions{
Format: c.Format,
vols, err := runtime.InspectVolumes(getContext(), c)
if err != nil {
return err
}
vols, lastError := getVolumesFromContext(&c.PodmanCommand, runtime)
if lastError != nil {
logrus.Errorf("%q", lastError)
}
return generateVolLsOutput(vols, opts, runtime)
return generateVolLsOutput(vols, volumeLsOptions{Format: c.Format})
}

View File

@ -6,8 +6,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/formats"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -71,7 +70,7 @@ func init() {
}
func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
@ -87,7 +86,7 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
opts.Format = genVolLsFormat(c)
// Get the filter functions based on any filters set
var filterFuncs []libpod.VolumeFilter
var filterFuncs []adapter.VolumeFilter
if c.Filter != "" {
filters := strings.Split(c.Filter, ",")
for _, f := range filters {
@ -95,7 +94,7 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
if len(filterSplit) < 2 {
return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
}
generatedFunc, err := generateVolumeFilterFuncs(filterSplit[0], filterSplit[1], runtime)
generatedFunc, err := generateVolumeFilterFuncs(filterSplit[0], filterSplit[1])
if err != nil {
return errors.Wrapf(err, "invalid filter")
}
@ -103,13 +102,12 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
}
}
volumes, err := runtime.GetAllVolumes()
volumes, err := runtime.Volumes(getContext())
if err != nil {
return err
}
// Get the volumes that match the filter
volsFiltered := make([]*libpod.Volume, 0, len(volumes))
volsFiltered := make([]*adapter.Volume, 0, len(volumes))
for _, vol := range volumes {
include := true
for _, filter := range filterFuncs {
@ -120,7 +118,7 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
volsFiltered = append(volsFiltered, vol)
}
}
return generateVolLsOutput(volsFiltered, opts, runtime)
return generateVolLsOutput(volsFiltered, opts)
}
// generate the template based on conditions given
@ -206,7 +204,7 @@ func getVolTemplateOutput(lsParams []volumeLsJSONParams, opts volumeLsOptions) (
}
// getVolJSONParams returns the volumes in JSON format
func getVolJSONParams(volumes []*libpod.Volume, opts volumeLsOptions, runtime *libpod.Runtime) ([]volumeLsJSONParams, error) {
func getVolJSONParams(volumes []*adapter.Volume) []volumeLsJSONParams {
var lsOutput []volumeLsJSONParams
for _, volume := range volumes {
@ -221,25 +219,19 @@ func getVolJSONParams(volumes []*libpod.Volume, opts volumeLsOptions, runtime *l
lsOutput = append(lsOutput, params)
}
return lsOutput, nil
return lsOutput
}
// generateVolLsOutput generates the output based on the format, JSON or Go Template, and prints it out
func generateVolLsOutput(volumes []*libpod.Volume, opts volumeLsOptions, runtime *libpod.Runtime) error {
func generateVolLsOutput(volumes []*adapter.Volume, opts volumeLsOptions) error {
if len(volumes) == 0 && opts.Format != formats.JSONString {
return nil
}
lsOutput, err := getVolJSONParams(volumes, opts, runtime)
if err != nil {
return err
}
lsOutput := getVolJSONParams(volumes)
var out formats.Writer
switch opts.Format {
case formats.JSONString:
if err != nil {
return errors.Wrapf(err, "unable to create JSON for volume output")
}
out = formats.JSONStructArray{Output: volLsToGeneric([]volumeLsTemplateParams{}, lsOutput)}
default:
lsOutput, err := getVolTemplateOutput(lsOutput, opts)
@ -252,18 +244,18 @@ func generateVolLsOutput(volumes []*libpod.Volume, opts volumeLsOptions, runtime
}
// generateVolumeFilterFuncs returns the true if the volume matches the filter set, otherwise it returns false.
func generateVolumeFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) (func(volume *libpod.Volume) bool, error) {
func generateVolumeFilterFuncs(filter, filterValue string) (func(volume *adapter.Volume) bool, error) {
switch filter {
case "name":
return func(v *libpod.Volume) bool {
return func(v *adapter.Volume) bool {
return strings.Contains(v.Name(), filterValue)
}, nil
case "driver":
return func(v *libpod.Volume) bool {
return func(v *adapter.Volume) bool {
return v.Driver() == filterValue
}, nil
case "scope":
return func(v *libpod.Volume) bool {
return func(v *adapter.Volume) bool {
return v.Scope() == filterValue
}, nil
case "label":
@ -274,7 +266,7 @@ func generateVolumeFilterFuncs(filter, filterValue string, runtime *libpod.Runti
} else {
filterValue = ""
}
return func(v *libpod.Volume) bool {
return func(v *adapter.Volume) bool {
for labelKey, labelValue := range v.Labels() {
if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
return true
@ -290,7 +282,7 @@ func generateVolumeFilterFuncs(filter, filterValue string, runtime *libpod.Runti
} else {
filterValue = ""
}
return func(v *libpod.Volume) bool {
return func(v *adapter.Volume) bool {
for labelKey, labelValue := range v.Options() {
if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
return true

View File

@ -35,6 +35,14 @@ type Container struct {
*libpod.Container
}
// Volume ...
type Volume struct {
*libpod.Volume
}
// VolumeFilter is for filtering volumes on the client
type VolumeFilter func(*Volume) bool
// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
func GetRuntime(c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
runtime, err := libpodruntime.GetRuntime(c)
@ -200,3 +208,49 @@ func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestM
}
return newImage.PushImageToHeuristicDestination(ctx, destination, manifestMIMEType, authfile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, nil)
}
// InspectVolumes returns a slice of volumes based on an arg list or --all
func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeInspectValues) ([]*Volume, error) {
var (
volumes []*libpod.Volume
err error
)
if c.All {
volumes, err = r.GetAllVolumes()
} else {
for _, v := range c.InputArgs {
vol, err := r.GetVolume(v)
if err != nil {
return nil, err
}
volumes = append(volumes, vol)
}
}
if err != nil {
return nil, err
}
return libpodVolumeToVolume(volumes), nil
}
// Volumes returns a slice of localruntime volumes
func (r *LocalRuntime) Volumes(ctx context.Context) ([]*Volume, error) {
vols, err := r.GetAllVolumes()
if err != nil {
return nil, err
}
return libpodVolumeToVolume(vols), nil
}
// libpodVolumeToVolume converts a slice of libpod volumes to a slice
// of localruntime volumes (same as libpod)
func libpodVolumeToVolume(volumes []*libpod.Volume) []*Volume {
var vols []*Volume
for _, v := range volumes {
newVol := Volume{
v,
}
vols = append(vols, &newVol)
}
return vols
}

View File

@ -92,6 +92,18 @@ type remoteContainer struct {
state *libpod.ContainerState
}
type VolumeFilter func(*Volume) bool
// Volume is embed for libpod volumes
type Volume struct {
remoteVolume
}
type remoteVolume struct {
Runtime *LocalRuntime
config *libpod.VolumeConfig
}
// GetImages returns a slice of containerimages over a varlink connection
func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) {
var newImages []*ContainerImage
@ -480,3 +492,45 @@ func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestM
return err
}
// InspectVolumes returns a slice of volumes based on an arg list or --all
func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeInspectValues) ([]*Volume, error) {
reply, err := iopodman.GetVolumes().Call(r.Conn, c.InputArgs, c.All)
if err != nil {
return nil, err
}
return varlinkVolumeToVolume(r, reply), nil
}
//Volumes returns a slice of adapter.volumes based on information about libpod
// volumes over a varlink connection
func (r *LocalRuntime) Volumes(ctx context.Context) ([]*Volume, error) {
reply, err := iopodman.GetVolumes().Call(r.Conn, []string{}, true)
if err != nil {
return nil, err
}
return varlinkVolumeToVolume(r, reply), nil
}
func varlinkVolumeToVolume(r *LocalRuntime, volumes []iopodman.Volume) []*Volume {
var vols []*Volume
for _, v := range volumes {
volumeConfig := libpod.VolumeConfig{
Name: v.Name,
Labels: v.Labels,
MountPoint: v.MountPoint,
Driver: v.Driver,
Options: v.Options,
Scope: v.Scope,
}
n := remoteVolume{
Runtime: r,
config: &volumeConfig,
}
newVol := Volume{
n,
}
vols = append(vols, &newVol)
}
return vols
}

View File

@ -0,0 +1,33 @@
// +build remoteclient
package adapter
// Name returns the name of the volume
func (v *Volume) Name() string {
return v.config.Name
}
//Labels returns the labels for a volume
func (v *Volume) Labels() map[string]string {
return v.config.Labels
}
// Driver returns the driver for the volume
func (v *Volume) Driver() string {
return v.config.Driver
}
// Options returns the options a volume was created with
func (v *Volume) Options() map[string]string {
return v.config.Options
}
// MountPath returns the path the volume is mounted to
func (v *Volume) MountPoint() string {
return v.config.MountPoint
}
// Scope returns the scope for an adapter.volume
func (v *Volume) Scope() string {
return v.config.Scope
}

View File

@ -36,3 +36,39 @@ func (i *LibpodAPI) VolumeRemove(call iopodman.VarlinkCall, options iopodman.Vol
}
return call.ReplyVolumeRemove(deletedVolumes)
}
// GetVolumes returns all the volumes known to the remote system
func (i *LibpodAPI) GetVolumes(call iopodman.VarlinkCall, args []string, all bool) error {
var (
err error
reply []*libpod.Volume
volumes []iopodman.Volume
)
if all {
reply, err = i.Runtime.GetAllVolumes()
} else {
for _, v := range args {
vol, err := i.Runtime.GetVolume(v)
if err != nil {
return err
}
reply = append(reply, vol)
}
}
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
// Build the iopodman.volume struct for the return
for _, v := range reply {
newVol := iopodman.Volume{
Driver: v.Driver(),
Labels: v.Labels(),
MountPoint: v.MountPoint(),
Name: v.Name(),
Options: v.Options(),
Scope: v.Scope(),
}
volumes = append(volumes, newVol)
}
return call.ReplyGetVolumes(volumes)
}