summaryrefslogtreecommitdiff
path: root/libpod/container_internal.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/container_internal.go')
-rw-r--r--libpod/container_internal.go94
1 files changed, 86 insertions, 8 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 540230c26..b9ea50783 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1,6 +1,7 @@
package libpod
import (
+ "bufio"
"bytes"
"context"
"fmt"
@@ -134,6 +135,11 @@ func (c *Container) CheckpointPath() string {
return filepath.Join(c.bundlePath(), "checkpoint")
}
+// PreCheckpointPath returns the path to the directory containing the pre-checkpoint-images
+func (c *Container) PreCheckPointPath() string {
+ return filepath.Join(c.bundlePath(), "pre-checkpoint")
+}
+
// AttachSocketPath retrieves the path of the container's attach socket
func (c *Container) AttachSocketPath() (string, error) {
return c.ociRuntime.AttachSocketPath(c)
@@ -758,7 +764,7 @@ func (c *Container) isStopped() (bool, error) {
return true, err
}
- return !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused), nil
+ return !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopping), nil
}
// save container state to the database
@@ -1284,10 +1290,49 @@ func (c *Container) stop(timeout uint) error {
return err
}
+ // Set the container state to "stopping" and unlock the container
+ // before handing it over to conmon to unblock other commands. #8501
+ // demonstrates nicely that a high stop timeout will block even simple
+ // commands such as `podman ps` from progressing if the container lock
+ // is held when busy-waiting for the container to be stopped.
+ c.state.State = define.ContainerStateStopping
+ if err := c.save(); err != nil {
+ return errors.Wrapf(err, "error saving container %s state before stopping", c.ID())
+ }
+ if !c.batched {
+ c.lock.Unlock()
+ }
+
if err := c.ociRuntime.StopContainer(c, timeout, all); err != nil {
return err
}
+ if !c.batched {
+ c.lock.Lock()
+ if err := c.syncContainer(); err != nil {
+ switch errors.Cause(err) {
+ // If the container has already been removed (e.g., via
+ // the cleanup process), there's nothing left to do.
+ case define.ErrNoSuchCtr, define.ErrCtrRemoved:
+ return nil
+ default:
+ return err
+ }
+ }
+ }
+
+ // Since we're now subject to a race condition with other processes who
+ // may have altered the state (and other data), let's check if the
+ // state has changed. If so, we should return immediately and log a
+ // warning.
+ if c.state.State != define.ContainerStateStopping {
+ logrus.Warnf(
+ "Container %q state changed from %q to %q while waiting for it to be stopped: discontinuing stop procedure as another process interfered",
+ c.ID(), define.ContainerStateStopping, c.state.State,
+ )
+ return nil
+ }
+
c.newContainerEvent(events.Stop)
c.state.PID = 0
@@ -1535,8 +1580,18 @@ func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string)
return nil, err
}
+ // HACK HACK HACK - copy up into a volume driver is 100% broken
+ // right now.
+ if vol.UsesVolumeDriver() {
+ logrus.Infof("Not copying up into volume %s as it uses a volume driver", vol.Name())
+ return vol, nil
+ }
+
// If the volume is not empty, we should not copy up.
- volMount := vol.MountPoint()
+ volMount, err := vol.MountPoint()
+ if err != nil {
+ return nil, err
+ }
contents, err := ioutil.ReadDir(volMount)
if err != nil {
return nil, errors.Wrapf(err, "error listing contents of volume %s mountpoint when copying up from container %s", vol.Name(), c.ID())
@@ -1574,7 +1629,11 @@ func (c *Container) chownVolume(volumeName string) error {
return err
}
- if vol.state.NeedsChown {
+ // TODO: For now, I've disabled chowning volumes owned by non-Podman
+ // drivers. This may be safe, but it's really going to be a case-by-case
+ // thing, I think - safest to leave disabled now and reenable later if
+ // there is a demand.
+ if vol.state.NeedsChown && !vol.UsesVolumeDriver() {
vol.state.NeedsChown = false
uid := int(c.config.Spec.Process.User.UID)
@@ -1601,7 +1660,10 @@ func (c *Container) chownVolume(volumeName string) error {
return err
}
- mountPoint := vol.MountPoint()
+ mountPoint, err := vol.MountPoint()
+ if err != nil {
+ return err
+ }
if err := os.Lchown(mountPoint, uid, gid); err != nil {
return err
@@ -1860,16 +1922,26 @@ func (c *Container) writeStringToStaticDir(filename, contents string) (string, e
return destFileName, nil
}
-// appendStringToRundir appends the provided string to the runtimedir file
-func (c *Container) appendStringToRundir(destFile, output string) (string, error) {
+// appendStringToRunDir appends the provided string to the runtimedir file
+func (c *Container) appendStringToRunDir(destFile, output string) (string, error) {
destFileName := filepath.Join(c.state.RunDir, destFile)
- f, err := os.OpenFile(destFileName, os.O_APPEND|os.O_WRONLY, 0600)
+ f, err := os.OpenFile(destFileName, os.O_APPEND|os.O_RDWR, 0600)
if err != nil {
return "", err
}
defer f.Close()
+ compareStr := strings.TrimRight(output, "\n")
+ scanner := bufio.NewScanner(f)
+ scanner.Split(bufio.ScanLines)
+
+ for scanner.Scan() {
+ if strings.Compare(scanner.Text(), compareStr) == 0 {
+ return filepath.Join(c.state.RunDir, destFile), nil
+ }
+ }
+
if _, err := f.WriteString(output); err != nil {
return "", errors.Wrapf(err, "unable to write %s", destFileName)
}
@@ -2023,6 +2095,12 @@ func (c *Container) checkReadyForRemoval() error {
return nil
}
+// canWithPrevious return the stat of the preCheckPoint dir
+func (c *Container) canWithPrevious() error {
+ _, err := os.Stat(c.PreCheckPointPath())
+ return err
+}
+
// writeJSONFile marshalls and writes the given data to a JSON file
// in the bundle path
func (c *Container) writeJSONFile(v interface{}, file string) error {
@@ -2094,7 +2172,7 @@ func (c *Container) sortUserVolumes(ctrSpec *spec.Spec) ([]*ContainerNamedVolume
// Check for an exit file, and handle one if present
func (c *Container) checkExitFile() error {
// If the container's not running, nothing to do.
- if !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
+ if !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopping) {
return nil
}