summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrent Baude <bbaude@redhat.com>2020-03-21 13:47:07 -0500
committerBrent Baude <bbaude@redhat.com>2020-03-22 13:24:45 -0500
commit9536560b4f3a38fbba4ac61c357dd3627fb6cf4e (patch)
tree8d8cf1471d590752357f06088044d1dcf752ee70
parent2ffff3c6abacad855ce7ddf8290514ebe1424d7f (diff)
downloadpodman-9536560b4f3a38fbba4ac61c357dd3627fb6cf4e.tar.gz
podman-9536560b4f3a38fbba4ac61c357dd3627fb6cf4e.tar.bz2
podman-9536560b4f3a38fbba4ac61c357dd3627fb6cf4e.zip
podmanv2 add core container commands
add core container commands for podmanv2: kill, pause, restart, rm, stop, unpause Signed-off-by: Brent Baude <bbaude@redhat.com>
-rw-r--r--cmd/podmanV2/containers/kill.go71
-rw-r--r--cmd/podmanV2/containers/pause.go63
-rw-r--r--cmd/podmanV2/containers/restart.go78
-rw-r--r--cmd/podmanV2/containers/rm.go93
-rw-r--r--cmd/podmanV2/containers/stop.go87
-rw-r--r--cmd/podmanV2/containers/unpause.go60
-rw-r--r--cmd/podmanV2/containers/utils.go1
-rw-r--r--cmd/podmanV2/containers/wait.go33
-rw-r--r--cmd/podmanV2/parse/parse.go45
-rw-r--r--cmd/podmanV2/root.go5
-rw-r--r--cmd/podmanV2/utils/error.go16
-rw-r--r--cmd/podmanV2/utils/remote.go10
-rw-r--r--pkg/api/handlers/compat/containers.go14
-rw-r--r--pkg/api/handlers/compat/containers_restart.go16
-rw-r--r--pkg/bindings/containers/containers.go8
-rw-r--r--pkg/bindings/test/volumes_test.go2
-rw-r--r--pkg/domain/entities/containers.go60
-rw-r--r--pkg/domain/entities/engine_container.go7
-rw-r--r--pkg/domain/infra/abi/containers.go199
-rw-r--r--pkg/domain/infra/tunnel/containers.go105
-rw-r--r--pkg/domain/infra/tunnel/helpers.go3
-rw-r--r--pkg/signal/signal_linux.go19
-rw-r--r--pkg/signal/signal_unsupported.go6
-rw-r--r--pkg/util/utils.go6
24 files changed, 954 insertions, 53 deletions
diff --git a/cmd/podmanV2/containers/kill.go b/cmd/podmanV2/containers/kill.go
new file mode 100644
index 000000000..b02dcf9da
--- /dev/null
+++ b/cmd/podmanV2/containers/kill.go
@@ -0,0 +1,71 @@
+package containers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/parse"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/signal"
+ "github.com/spf13/cobra"
+)
+
+var (
+ killDescription = "The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal."
+ killCommand = &cobra.Command{
+ Use: "kill [flags] CONTAINER [CONTAINER...]",
+ Short: "Kill one or more running containers with a specific signal",
+ Long: killDescription,
+ RunE: kill,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ },
+ Example: `podman kill mywebserver
+ podman kill 860a4b23
+ podman kill --signal TERM ctrID`,
+ }
+)
+
+var (
+ killOptions = entities.KillOptions{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: killCommand,
+ })
+ flags := killCommand.Flags()
+ flags.BoolVarP(&killOptions.All, "all", "a", false, "Signal all running containers")
+ flags.StringVarP(&killOptions.Signal, "signal", "s", "KILL", "Signal to send to the container")
+ flags.BoolVarP(&killOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ if utils.IsRemote() {
+ _ = flags.MarkHidden("latest")
+ }
+}
+
+func kill(cmd *cobra.Command, args []string) error {
+ var (
+ err error
+ errs utils.OutputErrors
+ )
+ // Check if the signalString provided by the user is valid
+ // Invalid signals will return err
+ if _, err = signal.ParseSignalNameOrNumber(killOptions.Signal); err != nil {
+ return err
+ }
+ responses, err := registry.ContainerEngine().ContainerKill(context.Background(), args, killOptions)
+ 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/podmanV2/containers/pause.go b/cmd/podmanV2/containers/pause.go
new file mode 100644
index 000000000..3f3e7c38d
--- /dev/null
+++ b/cmd/podmanV2/containers/pause.go
@@ -0,0 +1,63 @@
+package containers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ pauseDescription = `Pauses one or more running containers. The container name or ID can be used.`
+ pauseCommand = &cobra.Command{
+ Use: "pause [flags] CONTAINER [CONTAINER...]",
+ Short: "Pause all the processes in one or more containers",
+ Long: pauseDescription,
+ RunE: pause,
+ Example: `podman pause mywebserver
+ podman pause 860a4b23
+ podman pause -a`,
+ }
+
+ pauseOpts = entities.PauseUnPauseOptions{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: pauseCommand,
+ })
+ flags := pauseCommand.Flags()
+ flags.BoolVarP(&pauseOpts.All, "all", "a", false, "Pause all running containers")
+ pauseCommand.SetHelpTemplate(registry.HelpTemplate())
+ pauseCommand.SetUsageTemplate(registry.UsageTemplate())
+}
+
+func pause(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ )
+ if rootless.IsRootless() && !utils.IsRemote() {
+ return errors.New("pause is not supported for rootless containers")
+ }
+ if len(args) < 1 && !pauseOpts.All {
+ return errors.Errorf("you must provide at least one container name or id")
+ }
+ 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)
+ } else {
+ errs = append(errs, r.Err)
+ }
+ }
+ return errs.PrintErrors()
+}
diff --git a/cmd/podmanV2/containers/restart.go b/cmd/podmanV2/containers/restart.go
new file mode 100644
index 000000000..ee9c34361
--- /dev/null
+++ b/cmd/podmanV2/containers/restart.go
@@ -0,0 +1,78 @@
+package containers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/parse"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ restartDescription = `Restarts one or more running containers. The container ID or name can be used.
+
+ A timeout before forcibly stopping can be set, but defaults to 10 seconds.`
+ restartCommand = &cobra.Command{
+ Use: "restart [flags] CONTAINER [CONTAINER...]",
+ Short: "Restart one or more containers",
+ Long: restartDescription,
+ RunE: restart,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ },
+ Example: `podman restart ctrID
+ podman restart --latest
+ podman restart ctrID1 ctrID2`,
+ }
+)
+
+var (
+ restartOptions = entities.RestartOptions{}
+ restartTimeout uint
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: restartCommand,
+ })
+ flags := restartCommand.Flags()
+ flags.BoolVarP(&restartOptions.All, "all", "a", false, "Restart all non-running containers")
+ flags.BoolVarP(&restartOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.BoolVar(&restartOptions.Running, "running", false, "Restart only running containers when --all is used")
+ flags.UintVarP(&restartTimeout, "timeout", "t", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
+ flags.UintVar(&restartTimeout, "time", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
+ if utils.IsRemote() {
+ _ = flags.MarkHidden("latest")
+ }
+}
+
+func restart(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ )
+ if len(args) < 1 && !restartOptions.Latest && !restartOptions.All {
+ return errors.Wrapf(define.ErrInvalidArg, "you must provide at least one container name or ID")
+ }
+
+ if cmd.Flag("timeout").Changed || cmd.Flag("time").Changed {
+ restartOptions.Timeout = &restartTimeout
+ }
+ responses, err := registry.ContainerEngine().ContainerRestart(context.Background(), args, restartOptions)
+ 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/podmanV2/containers/rm.go b/cmd/podmanV2/containers/rm.go
new file mode 100644
index 000000000..af7a38fb1
--- /dev/null
+++ b/cmd/podmanV2/containers/rm.go
@@ -0,0 +1,93 @@
+package containers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/parse"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+)
+
+var (
+ rmDescription = `Removes one or more containers from the host. The container name or ID can be used.
+
+ Command does not remove images. Running or unusable containers will not be removed without the -f option.`
+ rmCommand = &cobra.Command{
+ Use: "rm [flags] CONTAINER [CONTAINER...]",
+ Short: "Remove one or more containers",
+ Long: rmDescription,
+ RunE: rm,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ },
+ Example: `podman rm imageID
+ podman rm mywebserver myflaskserver 860a4b23
+ podman rm --force --all
+ podman rm -f c684f0d469f2`,
+ }
+)
+
+var (
+ rmOptions = entities.RmOptions{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: rmCommand,
+ })
+ flags := rmCommand.Flags()
+ flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all containers")
+ flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
+ flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Force removal of a running or unusable container. The default is false")
+ flags.BoolVarP(&rmOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.BoolVar(&rmOptions.Storage, "storage", false, "Remove container from storage library")
+ flags.BoolVarP(&rmOptions.Volumes, "volumes", "v", false, "Remove anonymous volumes associated with the container")
+ flags.StringArrayVarP(&rmOptions.CIDFiles, "cidfile", "", nil, "Read the container ID from the file")
+ if utils.IsRemote() {
+ _ = flags.MarkHidden("latest")
+ _ = flags.MarkHidden("ignore")
+ _ = flags.MarkHidden("cidfile")
+ _ = flags.MarkHidden("storage")
+ }
+
+}
+
+func rm(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ )
+ // Storage conflicts with --all/--latest/--volumes/--cidfile/--ignore
+ if rmOptions.Storage {
+ if rmOptions.All || rmOptions.Ignore || rmOptions.Latest || rmOptions.Volumes || rmOptions.CIDFiles != nil {
+ return errors.Errorf("--storage conflicts with --volumes, --all, --latest, --ignore and --cidfile")
+ }
+ }
+ responses, err := registry.ContainerEngine().ContainerRm(context.Background(), args, rmOptions)
+ if err != nil {
+ // TODO exitcode is a global main variable to track exit codes.
+ // we need this enabled
+ //if len(c.InputArgs) < 2 {
+ // exitCode = setExitCode(err)
+ //}
+ return err
+ }
+ for _, r := range responses {
+ if r.Err != nil {
+ // TODO this will not work with the remote client
+ if errors.Cause(err) == define.ErrWillDeadlock {
+ logrus.Errorf("Potential deadlock detected - please run 'podman system renumber' to resolve")
+ }
+ errs = append(errs, r.Err)
+ } else {
+ fmt.Println(r.Id)
+ }
+ }
+ return errs.PrintErrors()
+}
diff --git a/cmd/podmanV2/containers/stop.go b/cmd/podmanV2/containers/stop.go
new file mode 100644
index 000000000..066202298
--- /dev/null
+++ b/cmd/podmanV2/containers/stop.go
@@ -0,0 +1,87 @@
+package containers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/parse"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ stopDescription = `Stops one or more running containers. The container name or ID can be used.
+
+ A timeout to forcibly stop the container can also be set but defaults to 10 seconds otherwise.`
+ stopCommand = &cobra.Command{
+ Use: "stop [flags] CONTAINER [CONTAINER...]",
+ Short: "Stop one or more containers",
+ Long: stopDescription,
+ RunE: stop,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ },
+ Example: `podman stop ctrID
+ podman stop --latest
+ podman stop --timeout 2 mywebserver 6e534f14da9d`,
+ }
+)
+
+var (
+ stopOptions = entities.StopOptions{}
+ stopTimeout uint
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: stopCommand,
+ })
+ flags := stopCommand.Flags()
+ flags.BoolVarP(&stopOptions.All, "all", "a", false, "Stop all running containers")
+ flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
+ flags.StringArrayVarP(&stopOptions.CIDFiles, "cidfile", "", nil, "Read the container ID from the file")
+ flags.BoolVarP(&stopOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.UintVar(&stopTimeout, "time", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
+ flags.UintVarP(&stopTimeout, "timeout", "t", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
+ if registry.EngineOpts.EngineMode == entities.ABIMode {
+ _ = flags.MarkHidden("latest")
+ _ = flags.MarkHidden("cidfile")
+ _ = flags.MarkHidden("ignore")
+ }
+}
+
+func stop(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ )
+ if cmd.Flag("timeout").Changed && cmd.Flag("time").Changed {
+ return errors.New("the --timeout and --time flags are mutually exclusive")
+ }
+ stopOptions.Timeout = define.CtrRemoveTimeout
+ if cmd.Flag("timeout").Changed || cmd.Flag("time").Changed {
+ stopOptions.Timeout = stopTimeout
+ }
+
+ // TODO How do we access global attributes?
+ //if c.Bool("trace") {
+ // span, _ := opentracing.StartSpanFromContext(Ctx, "stopCmd")
+ // defer span.Finish()
+ //}
+ responses, err := registry.ContainerEngine().ContainerStop(context.Background(), args, stopOptions)
+ 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/podmanV2/containers/unpause.go b/cmd/podmanV2/containers/unpause.go
new file mode 100644
index 000000000..697132a53
--- /dev/null
+++ b/cmd/podmanV2/containers/unpause.go
@@ -0,0 +1,60 @@
+package containers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ unpauseDescription = `Unpauses one or more previously paused containers. The container name or ID can be used.`
+ unpauseCommand = &cobra.Command{
+ Use: "unpause [flags] CONTAINER [CONTAINER...]",
+ Short: "Unpause the processes in one or more containers",
+ Long: unpauseDescription,
+ RunE: unpause,
+ Example: `podman unpause ctrID
+ podman unpause --all`,
+ }
+ unPauseOptions = entities.PauseUnPauseOptions{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: unpauseCommand,
+ Parent: containerCmd,
+ })
+ flags := unpauseCommand.Flags()
+ flags.BoolVarP(&unPauseOptions.All, "all", "a", false, "Pause all running containers")
+}
+
+func unpause(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ )
+ if rootless.IsRootless() && !utils.IsRemote() {
+ return errors.New("unpause is not supported for rootless containers")
+ }
+ if len(args) < 1 && !unPauseOptions.All {
+ return errors.Errorf("you must provide at least one container name or id")
+ }
+ responses, err := registry.ContainerEngine().ContainerUnpause(context.Background(), args, unPauseOptions)
+ 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/podmanV2/containers/utils.go b/cmd/podmanV2/containers/utils.go
new file mode 100644
index 000000000..0c09d3e40
--- /dev/null
+++ b/cmd/podmanV2/containers/utils.go
@@ -0,0 +1 @@
+package containers
diff --git a/cmd/podmanV2/containers/wait.go b/cmd/podmanV2/containers/wait.go
index 27acb3348..cded8e571 100644
--- a/cmd/podmanV2/containers/wait.go
+++ b/cmd/podmanV2/containers/wait.go
@@ -5,7 +5,9 @@ import (
"fmt"
"time"
+ "github.com/containers/libpod/cmd/podmanV2/parse"
"github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
@@ -20,6 +22,9 @@ var (
Short: "Block on one or more containers",
Long: waitDescription,
RunE: wait,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ },
Example: `podman wait --latest
podman wait --interval 5000 ctrID
podman wait ctrID1 ctrID2`,
@@ -27,7 +32,7 @@ var (
)
var (
- waitFlags = entities.WaitOptions{}
+ waitOptions = entities.WaitOptions{}
waitCondition string
)
@@ -35,12 +40,11 @@ func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: waitCommand,
- Parent: containerCmd,
})
flags := waitCommand.Flags()
- flags.DurationVarP(&waitFlags.Interval, "interval", "i", time.Duration(250), "Milliseconds to wait before polling for completion")
- flags.BoolVarP(&waitFlags.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.DurationVarP(&waitOptions.Interval, "interval", "i", time.Duration(250), "Milliseconds to wait before polling for completion")
+ flags.BoolVarP(&waitOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.StringVar(&waitCondition, "condition", "stopped", "Condition to wait on")
if registry.EngineOpts.EngineMode == entities.ABIMode {
// TODO: This is the same as V1. We could skip creating the flag altogether in V2...
@@ -50,33 +54,28 @@ func init() {
func wait(cmd *cobra.Command, args []string) error {
var (
- err error
+ err error
+ errs utils.OutputErrors
)
- if waitFlags.Latest && len(args) > 0 {
- return errors.New("cannot combine latest flag and arguments")
- }
- if waitFlags.Interval == 0 {
+ if waitOptions.Interval == 0 {
return errors.New("interval must be greater then 0")
}
- waitFlags.Condition, err = define.StringToContainerStatus(waitCondition)
+ waitOptions.Condition, err = define.StringToContainerStatus(waitCondition)
if err != nil {
return err
}
- responses, err := registry.ContainerEngine().ContainerWait(context.Background(), args, waitFlags)
+ responses, err := registry.ContainerEngine().ContainerWait(context.Background(), args, waitOptions)
if err != nil {
return err
}
for _, r := range responses {
if r.Error == nil {
fmt.Println(r.Id)
+ } else {
+ errs = append(errs, r.Error)
}
}
- for _, r := range responses {
- if r.Error != nil {
- fmt.Println(err)
- }
- }
- return nil
+ return errs.PrintErrors()
}
diff --git a/cmd/podmanV2/parse/parse.go b/cmd/podmanV2/parse/parse.go
index 03cda268c..10d2146fa 100644
--- a/cmd/podmanV2/parse/parse.go
+++ b/cmd/podmanV2/parse/parse.go
@@ -13,6 +13,7 @@ import (
"strings"
"github.com/pkg/errors"
+ "github.com/spf13/cobra"
)
const (
@@ -186,3 +187,47 @@ func ValidURL(urlStr string) error {
}
return nil
}
+
+// checkAllLatestAndCIDFile checks that --all and --latest are used correctly.
+// If cidfile is set, also check for the --cidfile flag.
+func CheckAllLatestAndCIDFile(c *cobra.Command, args []string, ignoreArgLen bool, cidfile bool) error {
+ argLen := len(args)
+ if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil {
+ if !cidfile {
+ return errors.New("unable to lookup values for 'latest' or 'all'")
+ } else if c.Flags().Lookup("cidfile") == nil {
+ return errors.New("unable to lookup values for 'latest', 'all' or 'cidfile'")
+ }
+ }
+
+ specifiedAll, _ := c.Flags().GetBool("all")
+ specifiedLatest, _ := c.Flags().GetBool("latest")
+ specifiedCIDFile := false
+ if cid, _ := c.Flags().GetStringArray("cidfile"); len(cid) > 0 {
+ specifiedCIDFile = true
+ }
+
+ if specifiedCIDFile && (specifiedAll || specifiedLatest) {
+ return errors.Errorf("--all, --latest and --cidfile cannot be used together")
+ } else if specifiedAll && specifiedLatest {
+ return errors.Errorf("--all and --latest cannot be used together")
+ }
+
+ if ignoreArgLen {
+ return nil
+ }
+ if (argLen > 0) && (specifiedAll || specifiedLatest) {
+ return errors.Errorf("no arguments are needed with --all or --latest")
+ } else if cidfile && (argLen > 0) && (specifiedAll || specifiedLatest || specifiedCIDFile) {
+ return errors.Errorf("no arguments are needed with --all, --latest or --cidfile")
+ }
+
+ if specifiedCIDFile {
+ return nil
+ }
+
+ if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedCIDFile {
+ return errors.Errorf("you must provide at least one name or id")
+ }
+ return nil
+}
diff --git a/cmd/podmanV2/root.go b/cmd/podmanV2/root.go
index 24b083b9f..b0dd7643f 100644
--- a/cmd/podmanV2/root.go
+++ b/cmd/podmanV2/root.go
@@ -23,8 +23,9 @@ var rootCmd = &cobra.Command{
func init() {
// Override default --help information of `--version` global flag}
var dummyVersion bool
- rootCmd.PersistentFlags().BoolVarP(&dummyVersion, "version", "v", false, "Version of podman")
- rootCmd.PersistentFlags().StringVarP(&registry.EngineOpts.Uri, "remote", "r", "", "URL to access podman service")
+ // TODO had to disable shorthand -v for version due to -v rm with volume
+ rootCmd.PersistentFlags().BoolVar(&dummyVersion, "version", false, "Version of Podman")
+ rootCmd.PersistentFlags().StringVarP(&registry.EngineOpts.Uri, "remote", "r", "", "URL to access Podman service")
rootCmd.PersistentFlags().StringSliceVar(&registry.EngineOpts.Identities, "identity", []string{}, "path to SSH identity file")
}
diff --git a/cmd/podmanV2/utils/error.go b/cmd/podmanV2/utils/error.go
new file mode 100644
index 000000000..3464f0779
--- /dev/null
+++ b/cmd/podmanV2/utils/error.go
@@ -0,0 +1,16 @@
+package utils
+
+import "fmt"
+
+type OutputErrors []error
+
+func (o OutputErrors) PrintErrors() (lastError error) {
+ if len(o) == 0 {
+ return
+ }
+ lastError = o[len(o)-1]
+ for e := 0; e < len(o)-1; e++ {
+ fmt.Println(o[e])
+ }
+ return
+}
diff --git a/cmd/podmanV2/utils/remote.go b/cmd/podmanV2/utils/remote.go
new file mode 100644
index 000000000..d0c8a272d
--- /dev/null
+++ b/cmd/podmanV2/utils/remote.go
@@ -0,0 +1,10 @@
+package utils
+
+import (
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+func IsRemote() bool {
+ return registry.EngineOpts.EngineMode == entities.TunnelMode
+}
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 3a269fe50..2ce113d30 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -7,7 +7,6 @@ import (
"strconv"
"strings"
"sync"
- "syscall"
"time"
"github.com/containers/libpod/libpod"
@@ -15,6 +14,7 @@ import (
"github.com/containers/libpod/libpod/logs"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/signal"
"github.com/containers/libpod/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -145,14 +145,20 @@ func KillContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- Signal syscall.Signal `schema:"signal"`
+ Signal string `schema:"signal"`
}{
- Signal: syscall.SIGKILL,
+ Signal: "KILL",
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
return
}
+
+ sig, err := signal.ParseSignalNameOrNumber(query.Signal)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
name := utils.GetName(r)
con, err := runtime.LookupContainer(name)
if err != nil {
@@ -172,7 +178,7 @@ func KillContainer(w http.ResponseWriter, r *http.Request) {
return
}
- err = con.Kill(uint(query.Signal))
+ err = con.Kill(uint(sig))
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "unable to kill Container %s", name))
}
diff --git a/pkg/api/handlers/compat/containers_restart.go b/pkg/api/handlers/compat/containers_restart.go
index 5b8fafaa4..343bf96d2 100644
--- a/pkg/api/handlers/compat/containers_restart.go
+++ b/pkg/api/handlers/compat/containers_restart.go
@@ -1,11 +1,9 @@
package compat
import (
- "fmt"
"net/http"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -32,20 +30,6 @@ func RestartContainer(w http.ResponseWriter, r *http.Request) {
return
}
- state, err := con.State()
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
-
- // FIXME: This is not in the swagger.yml...
- // If the Container is stopped already, send a 409
- if state == define.ContainerStateStopped || state == define.ContainerStateExited {
- msg := fmt.Sprintf("Container %s is not running", name)
- utils.Error(w, msg, http.StatusConflict, errors.New(msg))
- return
- }
-
timeout := con.StopTimeout()
if _, found := r.URL.Query()["t"]; found {
timeout = uint(query.Timeout)
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 534555a00..231b6f232 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -126,13 +126,13 @@ func Inspect(ctx context.Context, nameOrID string, size *bool) (*libpod.InspectC
// Kill sends a given signal to a given container. The signal should be the string
// representation of a signal like 'SIGKILL'. The nameOrID can be a container name
// or a partial/full ID
-func Kill(ctx context.Context, nameOrID string, signal string) error {
+func Kill(ctx context.Context, nameOrID string, sig string) error {
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
params := url.Values{}
- params.Set("signal", signal)
+ params.Set("signal", sig)
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nameOrID)
if err != nil {
return err
@@ -247,14 +247,14 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
// Stop stops a running container. The timeout is optional. The nameOrID can be a container name
// or a partial/full ID
-func Stop(ctx context.Context, nameOrID string, timeout *int) error {
+func Stop(ctx context.Context, nameOrID string, timeout *uint) error {
params := url.Values{}
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
if timeout != nil {
- params.Set("t", strconv.Itoa(*timeout))
+ params.Set("t", strconv.Itoa(int(*timeout)))
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/stop", params, nameOrID)
if err != nil {
diff --git a/pkg/bindings/test/volumes_test.go b/pkg/bindings/test/volumes_test.go
index 9da034d24..59fe48f22 100644
--- a/pkg/bindings/test/volumes_test.go
+++ b/pkg/bindings/test/volumes_test.go
@@ -102,7 +102,7 @@ var _ = Describe("Podman volumes", func() {
Expect(code).To(BeNumerically("==", http.StatusConflict))
// Removing with a volume in use with force should work with a stopped container
- zero := 0
+ zero := uint(0)
err = containers.Stop(connText, "vtest", &zero)
Expect(err).To(BeNil())
err = volumes.Remove(connText, vol.Name, &bindings.PTrue)
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 0e1208b3b..8b7406ae8 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -21,3 +21,63 @@ type WaitReport struct {
type BoolReport struct {
Value bool
}
+
+type PauseUnPauseOptions struct {
+ All bool
+}
+
+type PauseUnpauseReport struct {
+ Err error
+ Id string
+}
+
+type StopOptions struct {
+ All bool
+ CIDFiles []string
+ Ignore bool
+ Latest bool
+ Timeout uint
+}
+
+type StopReport struct {
+ Err error
+ Id string
+}
+
+type KillOptions struct {
+ All bool
+ Latest bool
+ Signal string
+}
+
+type KillReport struct {
+ Err error
+ Id string
+}
+
+type RestartOptions struct {
+ All bool
+ Latest bool
+ Running bool
+ Timeout *uint
+}
+
+type RestartReport struct {
+ Err error
+ Id string
+}
+
+type RmOptions struct {
+ All bool
+ CIDFiles []string
+ Force bool
+ Ignore bool
+ Latest bool
+ Storage bool
+ Volumes bool
+}
+
+type RmReport struct {
+ Err error
+ Id string
+}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 5820c12c3..2887f0b51 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -5,9 +5,14 @@ import (
)
type ContainerEngine interface {
- ContainerDelete(ctx context.Context, opts ContainerDeleteOptions) (*ContainerDeleteReport, error)
ContainerPrune(ctx context.Context) (*ContainerPruneReport, error)
ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error)
+ ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error)
+ ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
+ ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
+ ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
+ ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
+ ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
PodDelete(ctx context.Context, opts PodPruneOptions) (*PodDeleteReport, error)
PodExists(ctx context.Context, nameOrId string) (*BoolReport, error)
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index cdcd77246..47deb010a 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -4,11 +4,16 @@ package abi
import (
"context"
+ "io/ioutil"
+ "strings"
+ "github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter/shortcuts"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/signal"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// TODO: Should return *entities.ContainerExistsReport, error
@@ -41,8 +46,198 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
return responses, nil
}
-func (ic *ContainerEngine) ContainerDelete(ctx context.Context, opts entities.ContainerDeleteOptions) (*entities.ContainerDeleteReport, error) {
- panic("implement me")
+func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
+ var (
+ ctrs []*libpod.Container
+ err error
+ report []*entities.PauseUnpauseReport
+ )
+ if options.All {
+ ctrs, err = ic.Libpod.GetAllContainers()
+ } else {
+ ctrs, err = shortcuts.GetContainersByContext(false, false, namesOrIds, ic.Libpod)
+ }
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ err := c.Pause()
+ report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
+ }
+ return report, nil
+}
+
+func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
+ var (
+ ctrs []*libpod.Container
+ err error
+ report []*entities.PauseUnpauseReport
+ )
+ if options.All {
+ ctrs, err = ic.Libpod.GetAllContainers()
+ } else {
+ ctrs, err = shortcuts.GetContainersByContext(false, false, namesOrIds, ic.Libpod)
+ }
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ err := c.Unpause()
+ report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
+ }
+ return report, nil
+}
+func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
+ var (
+ reports []*entities.StopReport
+ )
+ names := namesOrIds
+ for _, cidFile := range options.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "error reading CIDFile")
+ }
+ id := strings.Split(string(content), "\n")[0]
+ names = append(names, id)
+ }
+ ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, names, ic.Libpod)
+ if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
+ return nil, err
+ }
+ for _, con := range ctrs {
+ report := entities.StopReport{Id: con.ID()}
+ err = con.StopWithTimeout(options.Timeout)
+ if err != nil {
+ // These first two are considered non-fatal under the right conditions
+ if errors.Cause(err) == define.ErrCtrStopped {
+ logrus.Debugf("Container %s is already stopped", con.ID())
+ reports = append(reports, &report)
+ continue
+
+ } else if options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
+ logrus.Debugf("Container %s is not running, could not stop", con.ID())
+ reports = append(reports, &report)
+ continue
+ }
+ report.Err = err
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
+ var (
+ reports []*entities.KillReport
+ )
+ sig, err := signal.ParseSignalNameOrNumber(options.Signal)
+ if err != nil {
+ return nil, err
+ }
+ ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, con := range ctrs {
+ reports = append(reports, &entities.KillReport{
+ Id: con.ID(),
+ Err: con.Kill(uint(sig)),
+ })
+ }
+ return reports, nil
+}
+func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
+ var (
+ reports []*entities.RestartReport
+ )
+ ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, con := range ctrs {
+ timeout := con.StopTimeout()
+ if options.Timeout != nil {
+ timeout = *options.Timeout
+ }
+ reports = append(reports, &entities.RestartReport{
+ Id: con.ID(),
+ Err: con.RestartWithTimeout(ctx, timeout),
+ })
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
+ var (
+ reports []*entities.RmReport
+ )
+ if options.Storage {
+ for _, ctr := range namesOrIds {
+ report := entities.RmReport{Id: ctr}
+ if err := ic.Libpod.RemoveStorageContainer(ctr, options.Force); err != nil {
+ report.Err = err
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+ }
+
+ names := namesOrIds
+ for _, cidFile := range options.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "error reading CIDFile")
+ }
+ id := strings.Split(string(content), "\n")[0]
+ names = append(names, id)
+ }
+
+ ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, names, ic.Libpod)
+ if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
+ // Failed to get containers. If force is specified, get the containers ID
+ // and evict them
+ if !options.Force {
+ return nil, err
+ }
+
+ for _, ctr := range namesOrIds {
+ logrus.Debugf("Evicting container %q", ctr)
+ report := entities.RmReport{Id: ctr}
+ id, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes)
+ if err != nil {
+ if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
+ logrus.Debugf("Ignoring error (--allow-missing): %v", err)
+ reports = append(reports, &report)
+ continue
+ }
+ report.Err = errors.Wrapf(err, "Failed to evict container: %q", id)
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+ }
+
+ for _, c := range ctrs {
+ report := entities.RmReport{Id: c.ID()}
+ err := ic.Libpod.RemoveContainer(ctx, c, options.Force, options.Volumes)
+ if err != nil {
+ if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
+ logrus.Debugf("Ignoring error (--allow-missing): %v", err)
+ reports = append(reports, &report)
+ continue
+ }
+ logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error())
+ report.Err = err
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
}
func (ic *ContainerEngine) ContainerPrune(ctx context.Context) (*entities.ContainerPruneReport, error) {
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 8bf74126d..21f62df6b 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -40,3 +40,108 @@ func (r *ContainerEngine) ContainerDelete(ctx context.Context, opts entities.Con
func (r *ContainerEngine) ContainerPrune(ctx context.Context) (*entities.ContainerPruneReport, error) {
panic("implement me")
}
+func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
+ var (
+ reports []*entities.PauseUnpauseReport
+ )
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ err := containers.Pause(ic.ClientCxt, c.ID)
+ reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
+ var (
+ reports []*entities.PauseUnpauseReport
+ )
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ err := containers.Unpause(ic.ClientCxt, c.ID)
+ reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
+ var (
+ reports []*entities.StopReport
+ )
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ report := entities.StopReport{Id: c.ID}
+ report.Err = containers.Stop(ic.ClientCxt, c.ID, &options.Timeout)
+ // TODO we need to associate errors returned by http with common
+ // define.errors so that we can equity tests. this will allow output
+ // to be the same as the native client
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
+ var (
+ reports []*entities.KillReport
+ )
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ reports = append(reports, &entities.KillReport{
+ Id: c.ID,
+ Err: containers.Kill(ic.ClientCxt, c.ID, options.Signal),
+ })
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
+ var (
+ reports []*entities.RestartReport
+ timeout *int
+ )
+ if options.Timeout != nil {
+ t := int(*options.Timeout)
+ timeout = &t
+ }
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ reports = append(reports, &entities.RestartReport{
+ Id: c.ID,
+ Err: containers.Restart(ic.ClientCxt, c.ID, timeout),
+ })
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
+ var (
+ reports []*entities.RmReport
+ )
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ // TODO there is no endpoint for container eviction. Need to discuss
+ for _, c := range ctrs {
+ reports = append(reports, &entities.RmReport{
+ Id: c.ID,
+ Err: containers.Remove(ic.ClientCxt, c.ID, &options.Force, &options.Volumes),
+ })
+ }
+ return reports, nil
+}
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
index d5a3224c2..11fca5278 100644
--- a/pkg/domain/infra/tunnel/helpers.go
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -2,6 +2,7 @@ package tunnel
import (
"context"
+ "strings"
"github.com/containers/libpod/pkg/api/handlers/libpod"
"github.com/containers/libpod/pkg/bindings"
@@ -27,7 +28,7 @@ func getContainersByContext(contextWithConnection context.Context, all bool, nam
for _, id := range namesOrIds {
var found bool
for _, con := range c {
- if id == con.ID || util.StringInSlice(id, con.Names) {
+ if id == con.ID || strings.HasPrefix(con.ID, id) || util.StringInSlice(id, con.Names) {
cons = append(cons, con)
found = true
break
diff --git a/pkg/signal/signal_linux.go b/pkg/signal/signal_linux.go
index 3d549898f..76ab16ec7 100644
--- a/pkg/signal/signal_linux.go
+++ b/pkg/signal/signal_linux.go
@@ -104,11 +104,11 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) {
}
return syscall.Signal(s), nil
}
- signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
+ sig, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
if !ok {
return -1, fmt.Errorf("invalid signal: %s", rawSignal)
}
- return signal, nil
+ return sig, nil
}
// CatchAll catches all signals and relays them to the specified channel.
@@ -125,3 +125,18 @@ func StopCatch(sigc chan os.Signal) {
signal.Stop(sigc)
close(sigc)
}
+
+// ParseSignalNameOrNumber translates a string to a valid syscall signal. Input
+// can be a name or number representation i.e. "KILL" "9"
+func ParseSignalNameOrNumber(rawSignal string) (syscall.Signal, error) {
+ s, err := ParseSignal(rawSignal)
+ if err == nil {
+ return s, nil
+ }
+ for k, v := range signalMap {
+ if k == strings.ToUpper(rawSignal) {
+ return v, nil
+ }
+ }
+ return -1, fmt.Errorf("invalid signal: %s", rawSignal)
+}
diff --git a/pkg/signal/signal_unsupported.go b/pkg/signal/signal_unsupported.go
index 0a92a5b3a..f946d802d 100644
--- a/pkg/signal/signal_unsupported.go
+++ b/pkg/signal/signal_unsupported.go
@@ -26,3 +26,9 @@ func CatchAll(sigc chan os.Signal) {
func StopCatch(sigc chan os.Signal) {
panic("Unsupported on non-linux platforms")
}
+
+// ParseSignalNameOrNumber translates a string to a valid syscall signal. Input
+// can be a name or number representation i.e. "KILL" "9"
+func ParseSignalNameOrNumber(rawSignal string) (syscall.Signal, error) {
+ return 0, fmt.Errorf("unsupported on non-linux platforms")
+}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index a4df48c88..3e11c010a 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -309,15 +309,15 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) {
// Strip off leading dash, to allow -1 or -HUP
basename := strings.TrimPrefix(rawSignal, "-")
- signal, err := signal.ParseSignal(basename)
+ sig, err := signal.ParseSignal(basename)
if err != nil {
return -1, err
}
// 64 is SIGRTMAX; wish we could get this from a standard Go library
- if signal < 1 || signal > 64 {
+ if sig < 1 || sig > 64 {
return -1, errors.Errorf("valid signals are 1 through 64")
}
- return signal, nil
+ return sig, nil
}
// ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping