From c60d8a0671b48ffdeda68895e0b7d97b252d66d9 Mon Sep 17 00:00:00 2001
From: Matthew Heon <mheon@redhat.com>
Date: Mon, 29 Jan 2018 11:59:33 -0500
Subject: Add StopWithTimeout API function for containers

Normal Stop should not need a timeout, and should use the default
Add a function that does accept a timeout aside it

Signed-off-by: Matthew Heon <mheon@redhat.com>

Closes: #272
Approved by: rhatdan
---
 cmd/podman/stop.go           |  2 +-
 libpod/container_api.go      | 36 ++++++++++++++++++------------------
 libpod/container_internal.go | 22 ++++++++++++++++++++++
 libpod/runtime.go            |  2 +-
 4 files changed, 42 insertions(+), 20 deletions(-)

diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go
index d18a05bd4..9a0f28994 100644
--- a/cmd/podman/stop.go
+++ b/cmd/podman/stop.go
@@ -101,7 +101,7 @@ func stopCmd(c *cli.Context) error {
 		} else {
 			stopTimeout = ctr.StopTimeout()
 		}
-		if err := ctr.Stop(stopTimeout); err != nil {
+		if err := ctr.StopWithTimeout(stopTimeout); err != nil {
 			if lastError != nil {
 				fmt.Fprintln(os.Stderr, lastError)
 			}
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 2b3c83eb2..cd3485880 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -326,10 +326,11 @@ func (c *Container) Start() error {
 }
 
 // Stop uses the container's stop signal (or SIGTERM if no signal was specified)
-// to stop the container, and if it has not stopped after the given timeout (in
-// seconds), uses SIGKILL to attempt to forcibly stop the container.
-// If timeout is 0, SIGKILL will be used immediately
-func (c *Container) Stop(timeout uint) error {
+// to stop the container, and if it has not stopped after container's stop
+// timeout, SIGKILL is used to attempt to forcibly stop the container
+// Default stop timeout is 10 seconds, but can be overridden when the container
+// is created
+func (c *Container) Stop() error {
 	if !c.locked {
 		c.lock.Lock()
 		defer c.lock.Unlock()
@@ -339,24 +340,23 @@ func (c *Container) Stop(timeout uint) error {
 		}
 	}
 
-	logrus.Debugf("Stopping ctr %s with timeout %d", c.ID(), timeout)
-
-	if c.state.State == ContainerStateConfigured ||
-		c.state.State == ContainerStateUnknown ||
-		c.state.State == ContainerStatePaused {
-		return errors.Wrapf(ErrCtrStateInvalid, "can only stop created, running, or stopped containers")
-	}
+	return c.stop(c.config.StopTimeout)
+}
 
-	if err := c.runtime.ociRuntime.stopContainer(c, timeout); err != nil {
-		return err
-	}
+// StopWithTimeout is a version of Stop that allows a timeout to be specified
+// manually. If timeout is 0, SIGKILL will be used immediately to kill the
+// container.
+func (c *Container) StopWithTimeout(timeout uint) error {
+	if !c.locked {
+		c.lock.Lock()
+		defer c.lock.Unlock()
 
-	// Sync the container's state to pick up return code
-	if err := c.runtime.ociRuntime.updateContainerStatus(c); err != nil {
-		return err
+		if err := c.syncContainer(); err != nil {
+			return err
+		}
 	}
 
-	return c.cleanupStorage()
+	return c.stop(timeout)
 }
 
 // Kill sends a signal to a container
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 9b785bfa5..fd8e826ba 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -302,6 +302,28 @@ func (c *Container) save() error {
 	return nil
 }
 
+// Internal, non-locking function to stop container
+func (c *Container) stop(timeout uint) error {
+	logrus.Debugf("Stopping ctr %s with timeout %d", c.ID(), timeout)
+
+	if c.state.State == ContainerStateConfigured ||
+		c.state.State == ContainerStateUnknown ||
+		c.state.State == ContainerStatePaused {
+		return errors.Wrapf(ErrCtrStateInvalid, "can only stop created, running, or stopped containers")
+	}
+
+	if err := c.runtime.ociRuntime.stopContainer(c, timeout); err != nil {
+		return err
+	}
+
+	// Sync the container's state to pick up return code
+	if err := c.runtime.ociRuntime.updateContainerStatus(c); err != nil {
+		return err
+	}
+
+	return c.cleanupStorage()
+}
+
 // mountStorage sets up the container's root filesystem
 // It mounts the image and any other requested mounts
 // TODO: Add ability to override mount label so we can use this for Mount() too
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 804f69c9e..20ae2c6fe 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -299,7 +299,7 @@ func (r *Runtime) Shutdown(force bool) error {
 			logrus.Errorf("Error retrieving containers from database: %v", err)
 		} else {
 			for _, ctr := range ctrs {
-				if err := ctr.Stop(CtrRemoveTimeout); err != nil {
+				if err := ctr.StopWithTimeout(CtrRemoveTimeout); err != nil {
 					logrus.Errorf("Error stopping container %s: %v", ctr.ID(), err)
 				}
 			}
-- 
cgit v1.2.3-54-g00ecf