From 9b152ef20e9cadf61547897ae21071098256bf79 Mon Sep 17 00:00:00 2001
From: Toshiki Sonoda <sonoda.toshiki@fujitsu.com>
Date: Wed, 20 Jul 2022 19:30:11 +0900
Subject: Add pause/unpause --latest, --cidfile, --filter

--latest : pause/unpause the latest container.
--filter : pause/unpause the filtered container.
--cidfile : Read container ID from the specified file and pause/unpause the container.

Signed-off-by: Toshiki Sonoda <sonoda.toshiki@fujitsu.com>
---
 cmd/podman/containers/pause.go   | 83 ++++++++++++++++++++++++++++----------
 cmd/podman/containers/unpause.go | 86 ++++++++++++++++++++++++++++++----------
 2 files changed, 127 insertions(+), 42 deletions(-)

(limited to 'cmd/podman')

diff --git a/cmd/podman/containers/pause.go b/cmd/podman/containers/pause.go
index af6f740f2..53aa423ac 100644
--- a/cmd/podman/containers/pause.go
+++ b/cmd/podman/containers/pause.go
@@ -2,61 +2,88 @@ package containers
 
 import (
 	"context"
-	"errors"
 	"fmt"
+	"io/ioutil"
+	"strings"
 
+	"github.com/containers/common/pkg/completion"
 	"github.com/containers/podman/v4/cmd/podman/common"
 	"github.com/containers/podman/v4/cmd/podman/registry"
 	"github.com/containers/podman/v4/cmd/podman/utils"
+	"github.com/containers/podman/v4/cmd/podman/validate"
 	"github.com/containers/podman/v4/pkg/domain/entities"
 	"github.com/spf13/cobra"
-	"github.com/spf13/pflag"
 )
 
 var (
 	pauseDescription = `Pauses one or more running containers.  The container name or ID can be used.`
 	pauseCommand     = &cobra.Command{
-		Use:               "pause [options] CONTAINER [CONTAINER...]",
-		Short:             "Pause all the processes in one or more containers",
-		Long:              pauseDescription,
-		RunE:              pause,
+		Use:   "pause [options] CONTAINER [CONTAINER...]",
+		Short: "Pause all the processes in one or more containers",
+		Long:  pauseDescription,
+		RunE:  pause,
+		Args: func(cmd *cobra.Command, args []string) error {
+			return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile")
+		},
 		ValidArgsFunction: common.AutocompleteContainersRunning,
 		Example: `podman pause mywebserver
   podman pause 860a4b23
-  podman pause -a`,
+  podman pause --all`,
 	}
 
 	containerPauseCommand = &cobra.Command{
-		Use:               pauseCommand.Use,
-		Short:             pauseCommand.Short,
-		Long:              pauseCommand.Long,
-		RunE:              pauseCommand.RunE,
+		Use:   pauseCommand.Use,
+		Short: pauseCommand.Short,
+		Long:  pauseCommand.Long,
+		RunE:  pauseCommand.RunE,
+		Args: func(cmd *cobra.Command, args []string) error {
+			return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile")
+		},
 		ValidArgsFunction: pauseCommand.ValidArgsFunction,
 		Example: `podman container pause mywebserver
   podman container pause 860a4b23
-  podman container pause -a`,
+  podman container pause --all`,
 	}
+)
 
-	pauseOpts = entities.PauseUnPauseOptions{}
+var (
+	pauseOpts = entities.PauseUnPauseOptions{
+		Filters: make(map[string][]string),
+	}
+	pauseCidFiles = []string{}
 )
 
-func pauseFlags(flags *pflag.FlagSet) {
+func pauseFlags(cmd *cobra.Command) {
+	flags := cmd.Flags()
+
 	flags.BoolVarP(&pauseOpts.All, "all", "a", false, "Pause all running containers")
+
+	cidfileFlagName := "cidfile"
+	flags.StringArrayVar(&pauseCidFiles, cidfileFlagName, nil, "Read the container ID from the file")
+	_ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
+
+	filterFlagName := "filter"
+	flags.StringSliceVarP(&filters, filterFlagName, "f", []string{}, "Filter output based on conditions given")
+	_ = cmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompletePsFilters)
+
+	if registry.IsRemote() {
+		_ = flags.MarkHidden("cidfile")
+	}
 }
 
 func init() {
 	registry.Commands = append(registry.Commands, registry.CliCommand{
 		Command: pauseCommand,
 	})
-	flags := pauseCommand.Flags()
-	pauseFlags(flags)
+	pauseFlags(pauseCommand)
+	validate.AddLatestFlag(pauseCommand, &pauseOpts.Latest)
 
 	registry.Commands = append(registry.Commands, registry.CliCommand{
 		Command: containerPauseCommand,
 		Parent:  containerCmd,
 	})
-	containerPauseFlags := containerPauseCommand.Flags()
-	pauseFlags(containerPauseFlags)
+	pauseFlags(containerPauseCommand)
+	validate.AddLatestFlag(containerPauseCommand, &pauseOpts.Latest)
 }
 
 func pause(cmd *cobra.Command, args []string) error {
@@ -64,16 +91,30 @@ func pause(cmd *cobra.Command, args []string) error {
 		errs utils.OutputErrors
 	)
 
-	if len(args) < 1 && !pauseOpts.All {
-		return errors.New("you must provide at least one container name or id")
+	for _, cidFile := range pauseCidFiles {
+		content, err := ioutil.ReadFile(cidFile)
+		if err != nil {
+			return fmt.Errorf("error reading CIDFile: %w", err)
+		}
+		id := strings.Split(string(content), "\n")[0]
+		args = append(args, id)
+	}
+
+	for _, f := range filters {
+		split := strings.SplitN(f, "=", 2)
+		if len(split) < 2 {
+			return fmt.Errorf("invalid filter %q", f)
+		}
+		pauseOpts.Filters[split[0]] = append(pauseOpts.Filters[split[0]], split[1])
 	}
+
 	responses, err := registry.ContainerEngine().ContainerPause(context.Background(), args, pauseOpts)
 	if err != nil {
 		return err
 	}
 	for _, r := range responses {
 		if r.Err == nil {
-			fmt.Println(r.Id)
+			fmt.Println(r.RawInput)
 		} else {
 			errs = append(errs, r.Err)
 		}
diff --git a/cmd/podman/containers/unpause.go b/cmd/podman/containers/unpause.go
index a5375e737..4282e490e 100644
--- a/cmd/podman/containers/unpause.go
+++ b/cmd/podman/containers/unpause.go
@@ -4,59 +4,87 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"io/ioutil"
+	"strings"
 
 	"github.com/containers/common/pkg/cgroups"
+	"github.com/containers/common/pkg/completion"
 	"github.com/containers/podman/v4/cmd/podman/common"
 	"github.com/containers/podman/v4/cmd/podman/registry"
 	"github.com/containers/podman/v4/cmd/podman/utils"
+	"github.com/containers/podman/v4/cmd/podman/validate"
 	"github.com/containers/podman/v4/pkg/domain/entities"
 	"github.com/containers/podman/v4/pkg/rootless"
 	"github.com/spf13/cobra"
-	"github.com/spf13/pflag"
 )
 
 var (
 	unpauseDescription = `Unpauses one or more previously paused containers.  The container name or ID can be used.`
 	unpauseCommand     = &cobra.Command{
-		Use:               "unpause [options] CONTAINER [CONTAINER...]",
-		Short:             "Unpause the processes in one or more containers",
-		Long:              unpauseDescription,
-		RunE:              unpause,
+		Use:   "unpause [options] CONTAINER [CONTAINER...]",
+		Short: "Unpause the processes in one or more containers",
+		Long:  unpauseDescription,
+		RunE:  unpause,
+		Args: func(cmd *cobra.Command, args []string) error {
+			return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile")
+		},
 		ValidArgsFunction: common.AutocompleteContainersPaused,
 		Example: `podman unpause ctrID
   podman unpause --all`,
 	}
-	unPauseOptions = entities.PauseUnPauseOptions{}
 
 	containerUnpauseCommand = &cobra.Command{
-		Use:               unpauseCommand.Use,
-		Short:             unpauseCommand.Short,
-		Long:              unpauseCommand.Long,
-		RunE:              unpauseCommand.RunE,
+		Use:   unpauseCommand.Use,
+		Short: unpauseCommand.Short,
+		Long:  unpauseCommand.Long,
+		RunE:  unpauseCommand.RunE,
+		Args: func(cmd *cobra.Command, args []string) error {
+			return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile")
+		},
 		ValidArgsFunction: unpauseCommand.ValidArgsFunction,
 		Example: `podman container unpause ctrID
   podman container unpause --all`,
 	}
 )
 
-func unpauseFlags(flags *pflag.FlagSet) {
-	flags.BoolVarP(&unPauseOptions.All, "all", "a", false, "Pause all running containers")
+var (
+	unpauseOpts = entities.PauseUnPauseOptions{
+		Filters: make(map[string][]string),
+	}
+	unpauseCidFiles = []string{}
+)
+
+func unpauseFlags(cmd *cobra.Command) {
+	flags := cmd.Flags()
+
+	flags.BoolVarP(&unpauseOpts.All, "all", "a", false, "Unpause all paused containers")
+
+	cidfileFlagName := "cidfile"
+	flags.StringArrayVar(&unpauseCidFiles, cidfileFlagName, nil, "Read the container ID from the file")
+	_ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
+
+	filterFlagName := "filter"
+	flags.StringSliceVarP(&filters, filterFlagName, "f", []string{}, "Filter output based on conditions given")
+	_ = cmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompletePsFilters)
+
+	if registry.IsRemote() {
+		_ = flags.MarkHidden("cidfile")
+	}
 }
 
 func init() {
 	registry.Commands = append(registry.Commands, registry.CliCommand{
 		Command: unpauseCommand,
 	})
-	flags := unpauseCommand.Flags()
-	unpauseFlags(flags)
+	unpauseFlags(unpauseCommand)
+	validate.AddLatestFlag(unpauseCommand, &unpauseOpts.Latest)
 
 	registry.Commands = append(registry.Commands, registry.CliCommand{
 		Command: containerUnpauseCommand,
 		Parent:  containerCmd,
 	})
-
-	unpauseCommandFlags := containerUnpauseCommand.Flags()
-	unpauseFlags(unpauseCommandFlags)
+	unpauseFlags(containerUnpauseCommand)
+	validate.AddLatestFlag(containerUnpauseCommand, &unpauseOpts.Latest)
 }
 
 func unpause(cmd *cobra.Command, args []string) error {
@@ -69,16 +97,32 @@ func unpause(cmd *cobra.Command, args []string) error {
 			return errors.New("unpause is not supported for cgroupv1 rootless containers")
 		}
 	}
-	if len(args) < 1 && !unPauseOptions.All {
-		return errors.New("you must provide at least one container name or id")
+
+	for _, cidFile := range unpauseCidFiles {
+		content, err := ioutil.ReadFile(cidFile)
+		if err != nil {
+			return fmt.Errorf("error reading CIDFile: %w", err)
+		}
+		id := strings.Split(string(content), "\n")[0]
+		args = append(args, id)
+	}
+
+	for _, f := range filters {
+		split := strings.SplitN(f, "=", 2)
+		if len(split) < 2 {
+			return fmt.Errorf("invalid filter %q", f)
+		}
+		unpauseOpts.Filters[split[0]] = append(unpauseOpts.Filters[split[0]], split[1])
 	}
-	responses, err := registry.ContainerEngine().ContainerUnpause(context.Background(), args, unPauseOptions)
+
+	responses, err := registry.ContainerEngine().ContainerUnpause(context.Background(), args, unpauseOpts)
 	if err != nil {
 		return err
 	}
+
 	for _, r := range responses {
 		if r.Err == nil {
-			fmt.Println(r.Id)
+			fmt.Println(r.RawInput)
 		} else {
 			errs = append(errs, r.Err)
 		}
-- 
cgit v1.2.3-54-g00ecf