From 52098941000794180a358a6983237cc6c4d30fc1 Mon Sep 17 00:00:00 2001
From: baude <bbaude@redhat.com>
Date: Thu, 6 Dec 2018 15:20:04 -0600
Subject: add timeout to pod stop

like podman stop of containers, we should allow the user to specify
a timeout override when stopping pods; otherwise they have to wait
the full timeout time specified during the pod/container creation.

Signed-off-by: baude <bbaude@redhat.com>
---
 API.md                               |  6 +++---
 cmd/podman/pod_stop.go               | 11 +++++++++--
 cmd/podman/varlink/io.podman.varlink |  4 ++--
 completions/bash/podman              |  2 ++
 docs/podman-pod-stop.1.md            | 34 ++++++++++++++++++++++++++++------
 libpod/pod_api.go                    | 17 +++++++++++++----
 pkg/varlinkapi/pods.go               |  4 ++--
 7 files changed, 59 insertions(+), 19 deletions(-)

diff --git a/API.md b/API.md
index 5465829f3..d45bb8123 100755
--- a/API.md
+++ b/API.md
@@ -113,7 +113,7 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
 
 [func StopContainer(name: string, timeout: int) string](#StopContainer)
 
-[func StopPod(name: string) string](#StopPod)
+[func StopPod(name: string, timeout: int) string](#StopPod)
 
 [func TagImage(name: string, tagged: string) string](#TagImage)
 
@@ -741,8 +741,8 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.StopContainer '{"name": "
 ### <a name="StopPod"></a>func StopPod
 <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
 
-method StopPod(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
-StopPod stops containers in a pod.  It takes the name or ID of a pod.
+method StopPod(name: [string](https://godoc.org/builtin#string), timeout: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div>
+StopPod stops containers in a pod.  It takes the name or ID of a pod and a timeout.
 If the pod cannot be found, a [PodNotFound](#PodNotFound) error will be returned instead.
 Containers in a pod are stopped independently. If there is an error stopping one container, the ID of those containers
 will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError).
diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go
index 14114aa11..d49ba8a00 100644
--- a/cmd/podman/pod_stop.go
+++ b/cmd/podman/pod_stop.go
@@ -2,7 +2,6 @@ package main
 
 import (
 	"fmt"
-
 	"github.com/containers/libpod/cmd/podman/libpodruntime"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
@@ -16,6 +15,10 @@ var (
 			Usage: "stop all running pods",
 		},
 		LatestPodFlag,
+		cli.UintFlag{
+			Name:  "timeout, time, t",
+			Usage: "Seconds to wait for pod stop before killing the container",
+		},
 	}
 	podStopDescription = `
    podman pod stop
@@ -35,6 +38,7 @@ var (
 )
 
 func podStopCmd(c *cli.Context) error {
+	timeout := -1
 	if err := checkMutuallyExclusiveFlags(c); err != nil {
 		return err
 	}
@@ -52,9 +56,12 @@ func podStopCmd(c *cli.Context) error {
 
 	ctx := getContext()
 
+	if c.IsSet("timeout") {
+		timeout = int(c.Uint("timeout"))
+	}
 	for _, pod := range pods {
 		// set cleanup to true to clean mounts and namespaces
-		ctr_errs, err := pod.Stop(ctx, true)
+		ctr_errs, err := pod.StopWithTimeout(ctx, true, timeout)
 		if ctr_errs != nil {
 			for ctr, err := range ctr_errs {
 				if lastError != nil {
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 486f4e60c..3cdc99a83 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -715,7 +715,7 @@ method InspectPod(name: string) -> (pod: string)
 # ~~~
 method StartPod(name: string) -> (pod: string)
 
-# StopPod stops containers in a pod.  It takes the name or ID of a pod.
+# StopPod stops containers in a pod.  It takes the name or ID of a pod and a timeout.
 # If the pod cannot be found, a [PodNotFound](#PodNotFound) error will be returned instead.
 # Containers in a pod are stopped independently. If there is an error stopping one container, the ID of those containers
 # will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError).
@@ -728,7 +728,7 @@ method StartPod(name: string) -> (pod: string)
 #   "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6"
 # }
 # ~~~
-method StopPod(name: string) -> (pod: string)
+method StopPod(name: string, timeout: int) -> (pod: string)
 
 # RestartPod will restart containers in a pod given a pod name or ID. Containers in
 # the pod that are running will be stopped, then all stopped containers will be run.
diff --git a/completions/bash/podman b/completions/bash/podman
index 3382b6c5a..eda7e5973 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -2451,6 +2451,8 @@ _podman_pod_start() {
 
 _podman_pod_stop() {
   local options_with_args="
+      -t
+      --timeout
   "
 
   local boolean_options="
diff --git a/docs/podman-pod-stop.1.md b/docs/podman-pod-stop.1.md
index 74799273e..7544f8bf7 100644
--- a/docs/podman-pod-stop.1.md
+++ b/docs/podman-pod-stop.1.md
@@ -19,26 +19,48 @@ Stops all pods
 
 Instead of providing the pod name or ID, stop the last created pod.
 
+**--timeout, --time, t**
+
+Timeout to wait before forcibly stopping the containers in the pod.
+
 ## EXAMPLE
 
-podman pod stop mywebserverpod
+Stop a pod called *mywebserverpod*
+```
+$ podman pod stop mywebserverpod
 cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907
+```
 
-podman pod stop 490eb 3557fb
+Stop two pods by their short IDs.
+```
+$ podman pod stop 490eb 3557fb
 490eb241aaf704d4dd2629904410fe4aa31965d9310a735f8755267f4ded1de5
 3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
+```
 
+Stop the most recent pod
+```
+$ podman pod stop --latest
 3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
+```
 
-podman pod stop --latest
-3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
-
-podman pod stop --all
+Stop all pods
+```
+$ podman pod stop --all
 19456b4cd557eaf9629825113a552681a6013f8c8cad258e36ab825ef536e818
 3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
 490eb241aaf704d4dd2629904410fe4aa31965d9310a735f8755267f4ded1de5
 70c358daecf71ef9be8f62404f926080ca0133277ef7ce4f6aa2d5af6bb2d3e9
 cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907
+```
+
+Stop all pods with a timeout of 1 second.
+```
+$ podman pod stop -a -t 1
+3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
+490eb241aaf704d4dd2629904410fe4aa31965d9310a735f8755267f4ded1de5
+70c358daecf71ef9be8f62404f926080ca0133277ef7ce4f6aa2d5af6bb2d3e9
+```
 
 ## SEE ALSO
 podman-pod(1), podman-pod-start(1), podman-stop(1)
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index 3d5512e8c..cbac2420f 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -62,7 +62,13 @@ func (p *Pod) Start(ctx context.Context) (map[string]error, error) {
 	return nil, nil
 }
 
-// Stop stops all containers within a pod that are not already stopped
+// Stop stops all containers within a pod without a timeout.  It assumes -1 for
+// a timeout.
+func (p *Pod) Stop(ctx context.Context, cleanup bool) (map[string]error, error) {
+	return p.StopWithTimeout(ctx, cleanup, -1)
+}
+
+// StopWithTimeout stops all containers within a pod that are not already stopped
 // Each container will use its own stop timeout
 // Only running containers will be stopped. Paused, stopped, or created
 // containers will be ignored.
@@ -77,7 +83,7 @@ func (p *Pod) Start(ctx context.Context) (map[string]error, error) {
 // containers. The container ID is mapped to the error encountered. The error is
 // set to ErrCtrExists
 // If both error and the map are nil, all containers were stopped without error
-func (p *Pod) Stop(ctx context.Context, cleanup bool) (map[string]error, error) {
+func (p *Pod) StopWithTimeout(ctx context.Context, cleanup bool, timeout int) (map[string]error, error) {
 	p.lock.Lock()
 	defer p.lock.Unlock()
 
@@ -110,8 +116,11 @@ func (p *Pod) Stop(ctx context.Context, cleanup bool) (map[string]error, error)
 			ctr.lock.Unlock()
 			continue
 		}
-
-		if err := ctr.stop(ctr.config.StopTimeout); err != nil {
+		stopTimeout := ctr.config.StopTimeout
+		if timeout > -1 {
+			stopTimeout = uint(timeout)
+		}
+		if err := ctr.stop(stopTimeout); err != nil {
 			ctr.lock.Unlock()
 			ctrErrors[ctr.ID()] = err
 			continue
diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go
index 7930a956f..461371497 100644
--- a/pkg/varlinkapi/pods.go
+++ b/pkg/varlinkapi/pods.go
@@ -120,12 +120,12 @@ func (i *LibpodAPI) StartPod(call iopodman.VarlinkCall, name string) error {
 }
 
 // StopPod ...
-func (i *LibpodAPI) StopPod(call iopodman.VarlinkCall, name string) error {
+func (i *LibpodAPI) StopPod(call iopodman.VarlinkCall, name string, timeout int64) error {
 	pod, err := i.Runtime.LookupPod(name)
 	if err != nil {
 		return call.ReplyPodNotFound(name)
 	}
-	ctrErrs, err := pod.Stop(getContext(), true)
+	ctrErrs, err := pod.StopWithTimeout(getContext(), true, int(timeout))
 	callErr := handlePodCall(call, pod, ctrErrs, err)
 	if callErr != nil {
 		return err
-- 
cgit v1.2.3-54-g00ecf