summaryrefslogtreecommitdiff
path: root/cmd/podman/volumes
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2020-04-16 14:04:58 -0700
committerGitHub <noreply@github.com>2020-04-16 14:04:58 -0700
commit0d2b5532c417c58bd24e71a56c5c55b43e423a59 (patch)
tree4001e8e47a022bb1b9bfbf2332c42e1aeb802f9e /cmd/podman/volumes
parent88c6fd06cd54fb9a8826306dfdf1a77e400de5de (diff)
parent241326a9a8c20ad7f2bcf651416b836e7778e090 (diff)
downloadpodman-0d2b5532c417c58bd24e71a56c5c55b43e423a59.tar.gz
podman-0d2b5532c417c58bd24e71a56c5c55b43e423a59.tar.bz2
podman-0d2b5532c417c58bd24e71a56c5c55b43e423a59.zip
Merge pull request #5852 from baude/v1prune
Podman V2 birth
Diffstat (limited to 'cmd/podman/volumes')
-rw-r--r--cmd/podman/volumes/create.go72
-rw-r--r--cmd/podman/volumes/inspect.go74
-rw-r--r--cmd/podman/volumes/list.go98
-rw-r--r--cmd/podman/volumes/prune.go74
-rw-r--r--cmd/podman/volumes/rm.go64
-rw-r--r--cmd/podman/volumes/volume.go25
6 files changed, 407 insertions, 0 deletions
diff --git a/cmd/podman/volumes/create.go b/cmd/podman/volumes/create.go
new file mode 100644
index 000000000..df0731791
--- /dev/null
+++ b/cmd/podman/volumes/create.go
@@ -0,0 +1,72 @@
+package volumes
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podman/parse"
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ createDescription = `If using the default driver, "local", the volume will be created on the host in the volumes directory under container storage.`
+
+ createCommand = &cobra.Command{
+ Use: "create [flags] [NAME]",
+ Short: "Create a new volume",
+ Long: createDescription,
+ RunE: create,
+ Example: `podman volume create myvol
+ podman volume create
+ podman volume create --label foo=bar myvol`,
+ }
+)
+
+var (
+ createOpts = entities.VolumeCreateOptions{}
+ opts = struct {
+ Label []string
+ Opts []string
+ }{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: createCommand,
+ Parent: volumeCmd,
+ })
+ flags := createCommand.Flags()
+ flags.StringVar(&createOpts.Driver, "driver", "", "Specify volume driver name (default local)")
+ flags.StringSliceVarP(&opts.Label, "label", "l", []string{}, "Set metadata for a volume (default [])")
+ flags.StringArrayVarP(&opts.Opts, "opt", "o", []string{}, "Set driver specific options (default [])")
+}
+
+func create(cmd *cobra.Command, args []string) error {
+ var (
+ err error
+ )
+ if len(args) > 1 {
+ return errors.Errorf("too many arguments, create takes at most 1 argument")
+ }
+ if len(args) > 0 {
+ createOpts.Name = args[0]
+ }
+ createOpts.Label, err = parse.GetAllLabels([]string{}, opts.Label)
+ if err != nil {
+ return errors.Wrapf(err, "unable to process labels")
+ }
+ createOpts.Options, err = parse.GetAllLabels([]string{}, opts.Opts)
+ if err != nil {
+ return errors.Wrapf(err, "unable to process options")
+ }
+ response, err := registry.ContainerEngine().VolumeCreate(context.Background(), createOpts)
+ if err != nil {
+ return err
+ }
+ fmt.Println(response.IdOrName)
+ return nil
+}
diff --git a/cmd/podman/volumes/inspect.go b/cmd/podman/volumes/inspect.go
new file mode 100644
index 000000000..57e773aef
--- /dev/null
+++ b/cmd/podman/volumes/inspect.go
@@ -0,0 +1,74 @@
+package volumes
+
+import (
+ "encoding/json"
+ "fmt"
+ "html/template"
+ "os"
+
+ "github.com/containers/buildah/pkg/formats"
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+ "golang.org/x/net/context"
+)
+
+var (
+ volumeInspectDescription = `Display detailed information on one or more volumes.
+
+ Use a Go template to change the format from JSON.`
+ inspectCommand = &cobra.Command{
+ Use: "inspect [flags] VOLUME [VOLUME...]",
+ Short: "Display detailed information on one or more volumes",
+ Long: volumeInspectDescription,
+ RunE: inspect,
+ Example: `podman volume inspect myvol
+ podman volume inspect --all
+ podman volume inspect --format "{{.Driver}} {{.Scope}}" myvol`,
+ }
+)
+
+var (
+ inspectOpts = entities.VolumeInspectOptions{}
+ inspectFormat string
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: inspectCommand,
+ Parent: volumeCmd,
+ })
+ flags := inspectCommand.Flags()
+ flags.BoolVarP(&inspectOpts.All, "all", "a", false, "Inspect all volumes")
+ flags.StringVarP(&inspectFormat, "format", "f", "json", "Format volume output using Go template")
+}
+
+func inspect(cmd *cobra.Command, args []string) error {
+ if (inspectOpts.All && len(args) > 0) || (!inspectOpts.All && len(args) < 1) {
+ return errors.New("provide one or more volume names or use --all")
+ }
+ responses, err := registry.ContainerEngine().VolumeInspect(context.Background(), args, inspectOpts)
+ if err != nil {
+ return err
+ }
+ switch inspectFormat {
+ case "", formats.JSONString:
+ jsonOut, err := json.MarshalIndent(responses, "", " ")
+ if err != nil {
+ return errors.Wrapf(err, "error marshalling inspect JSON")
+ }
+ fmt.Println(string(jsonOut))
+ default:
+ tmpl, err := template.New("volumeInspect").Parse(inspectFormat)
+ if err != nil {
+ return err
+ }
+ if err := tmpl.Execute(os.Stdout, responses); err != nil {
+ return err
+ }
+ }
+ return nil
+
+}
diff --git a/cmd/podman/volumes/list.go b/cmd/podman/volumes/list.go
new file mode 100644
index 000000000..fd89db01f
--- /dev/null
+++ b/cmd/podman/volumes/list.go
@@ -0,0 +1,98 @@
+package volumes
+
+import (
+ "context"
+ "html/template"
+ "io"
+ "os"
+ "strings"
+ "text/tabwriter"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ volumeLsDescription = `
+podman volume ls
+
+List all available volumes. The output of the volumes can be filtered
+and the output format can be changed to JSON or a user specified Go template.`
+ lsCommand = &cobra.Command{
+ Use: "ls",
+ Aliases: []string{"list"},
+ Args: cobra.NoArgs,
+ Short: "List volumes",
+ Long: volumeLsDescription,
+ RunE: list,
+ }
+)
+
+var (
+ // Temporary struct to hold cli values.
+ cliOpts = struct {
+ Filter []string
+ Format string
+ Quiet bool
+ }{}
+ lsOpts = entities.VolumeListOptions{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: lsCommand,
+ Parent: volumeCmd,
+ })
+ flags := lsCommand.Flags()
+ flags.StringSliceVarP(&cliOpts.Filter, "filter", "f", []string{}, "Filter volume output")
+ flags.StringVar(&cliOpts.Format, "format", "{{.Driver}}\t{{.Name}}\n", "Format volume output using Go template")
+ flags.BoolVarP(&cliOpts.Quiet, "quiet", "q", false, "Print volume output in quiet mode")
+}
+
+func list(cmd *cobra.Command, args []string) error {
+ var w io.Writer = os.Stdout
+ if cliOpts.Quiet && cmd.Flag("format").Changed {
+ return errors.New("quiet and format flags cannot be used together")
+ }
+ for _, f := range cliOpts.Filter {
+ filterSplit := strings.Split(f, "=")
+ if len(filterSplit) < 2 {
+ return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
+ }
+ lsOpts.Filter[filterSplit[0]] = append(lsOpts.Filter[filterSplit[0]], filterSplit[1:]...)
+ }
+ responses, err := registry.ContainerEngine().VolumeList(context.Background(), lsOpts)
+ if err != nil {
+ return err
+ }
+ // "\t" from the command line is not being recognized as a tab
+ // replacing the string "\t" to a tab character if the user passes in "\t"
+ cliOpts.Format = strings.Replace(cliOpts.Format, `\t`, "\t", -1)
+ if cliOpts.Quiet {
+ cliOpts.Format = "{{.Name}}\n"
+ }
+ headers := "DRIVER\tVOLUME NAME\n"
+ row := cliOpts.Format
+ if !strings.HasSuffix(cliOpts.Format, "\n") {
+ row += "\n"
+ }
+ format := "{{range . }}" + row + "{{end}}"
+ if !cliOpts.Quiet && !cmd.Flag("format").Changed {
+ w = tabwriter.NewWriter(os.Stdout, 12, 2, 2, ' ', 0)
+ format = headers + format
+ }
+ tmpl, err := template.New("listVolume").Parse(format)
+ if err != nil {
+ return err
+ }
+ if err := tmpl.Execute(w, responses); err != nil {
+ return err
+ }
+ if flusher, ok := w.(interface{ Flush() error }); ok {
+ return flusher.Flush()
+ }
+ return nil
+}
diff --git a/cmd/podman/volumes/prune.go b/cmd/podman/volumes/prune.go
new file mode 100644
index 000000000..197a9da9b
--- /dev/null
+++ b/cmd/podman/volumes/prune.go
@@ -0,0 +1,74 @@
+package volumes
+
+import (
+ "bufio"
+ "context"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ volumePruneDescription = `Volumes that are not currently owned by a container will be removed.
+
+ The command prompts for confirmation which can be overridden with the --force flag.
+ Note all data will be destroyed.`
+ pruneCommand = &cobra.Command{
+ Use: "prune",
+ Args: cobra.NoArgs,
+ Short: "Remove all unused volumes",
+ Long: volumePruneDescription,
+ RunE: prune,
+ }
+)
+
+var (
+ pruneOptions entities.VolumePruneOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: pruneCommand,
+ Parent: volumeCmd,
+ })
+ flags := pruneCommand.Flags()
+ flags.BoolVarP(&pruneOptions.Force, "force", "f", false, "Do not prompt for confirmation")
+}
+
+func prune(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ )
+ // Prompt for confirmation if --force is not set
+ if !pruneOptions.Force {
+ reader := bufio.NewReader(os.Stdin)
+ fmt.Println("WARNING! This will remove all volumes not used by at least one container.")
+ fmt.Print("Are you sure you want to continue? [y/N] ")
+ answer, err := reader.ReadString('\n')
+ if err != nil {
+ return errors.Wrapf(err, "error reading input")
+ }
+ if strings.ToLower(answer)[0] != 'y' {
+ return nil
+ }
+ }
+ responses, err := registry.ContainerEngine().VolumePrune(context.Background(), pruneOptions)
+ if err != nil {
+ return err
+ }
+ for _, r := range responses {
+ if r.Err == nil {
+ fmt.Println(r.Id)
+ } else {
+ errs = append(errs, r.Err)
+ }
+ }
+ return errs.PrintErrors()
+}
diff --git a/cmd/podman/volumes/rm.go b/cmd/podman/volumes/rm.go
new file mode 100644
index 000000000..f5a898ff3
--- /dev/null
+++ b/cmd/podman/volumes/rm.go
@@ -0,0 +1,64 @@
+package volumes
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ volumeRmDescription = `Remove one or more existing volumes.
+
+ By default only volumes that are not being used by any containers will be removed. To remove the volumes anyways, use the --force flag.`
+ rmCommand = &cobra.Command{
+ Use: "rm [flags] VOLUME [VOLUME...]",
+ Aliases: []string{"remove"},
+ Short: "Remove one or more volumes",
+ Long: volumeRmDescription,
+ RunE: rm,
+ Example: `podman volume rm myvol1 myvol2
+ podman volume rm --all
+ podman volume rm --force myvol`,
+ }
+)
+
+var (
+ rmOptions = entities.VolumeRmOptions{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: rmCommand,
+ Parent: volumeCmd,
+ })
+ flags := rmCommand.Flags()
+ flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all volumes")
+ flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Remove a volume by force, even if it is being used by a container")
+}
+
+func rm(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ )
+ if (len(args) > 0 && rmOptions.All) || (len(args) < 1 && !rmOptions.All) {
+ return errors.New("choose either one or more volumes or all")
+ }
+ responses, err := registry.ContainerEngine().VolumeRm(context.Background(), args, rmOptions)
+ if err != nil {
+ return err
+ }
+ for _, r := range responses {
+ if r.Err == nil {
+ fmt.Println(r.Id)
+ } else {
+ errs = append(errs, r.Err)
+ }
+ }
+ return errs.PrintErrors()
+}
diff --git a/cmd/podman/volumes/volume.go b/cmd/podman/volumes/volume.go
new file mode 100644
index 000000000..06943da62
--- /dev/null
+++ b/cmd/podman/volumes/volume.go
@@ -0,0 +1,25 @@
+package volumes
+
+import (
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // Command: podman _volume_
+ volumeCmd = &cobra.Command{
+ Use: "volume",
+ Short: "Manage volumes",
+ Long: "Volumes are created in and can be shared between containers",
+ TraverseChildren: true,
+ RunE: registry.SubCommandExists,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: volumeCmd,
+ })
+}