diff options
author | OpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com> | 2020-04-16 14:04:58 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-16 14:04:58 -0700 |
commit | 0d2b5532c417c58bd24e71a56c5c55b43e423a59 (patch) | |
tree | 4001e8e47a022bb1b9bfbf2332c42e1aeb802f9e /cmd/podman/volumes | |
parent | 88c6fd06cd54fb9a8826306dfdf1a77e400de5de (diff) | |
parent | 241326a9a8c20ad7f2bcf651416b836e7778e090 (diff) | |
download | podman-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.go | 72 | ||||
-rw-r--r-- | cmd/podman/volumes/inspect.go | 74 | ||||
-rw-r--r-- | cmd/podman/volumes/list.go | 98 | ||||
-rw-r--r-- | cmd/podman/volumes/prune.go | 74 | ||||
-rw-r--r-- | cmd/podman/volumes/rm.go | 64 | ||||
-rw-r--r-- | cmd/podman/volumes/volume.go | 25 |
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, + }) +} |