summaryrefslogtreecommitdiff
path: root/libpod/container_internal.go
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@pm.me>2019-12-12 16:19:36 -0500
committerMatthew Heon <matthew.heon@pm.me>2019-12-12 16:35:37 -0500
commitbd44fd5c815fc750fd6b60899328564bee74e6e5 (patch)
tree980a0e85eec4f3a646c1f0ac63c05634fd13510b /libpod/container_internal.go
parentc2dab75f0ec1502e075cf5174d1b308267648fda (diff)
downloadpodman-bd44fd5c815fc750fd6b60899328564bee74e6e5.tar.gz
podman-bd44fd5c815fc750fd6b60899328564bee74e6e5.tar.bz2
podman-bd44fd5c815fc750fd6b60899328564bee74e6e5.zip
Reap exec sessions on cleanup and removal
We currently rely on exec sessions being removed from the state by the Exec() API itself, on detecting the session stopping. This is not a reliable method, though. The Podman frontend for exec could be killed before the session ended, or another Podman process could be holding the lock and prevent update (most notable in `run --rm`, when a container with an active exec session is stopped). To resolve this, add a function to reap active exec sessions from the state, and use it on cleanup (to clear sessions after the container stops) and remove (to do the same when --rm is passed). This is a bit more complicated than it ought to be because Kata and company exist, and we can't guarantee the exec session has a PID on the host, so we have to plumb this through to the OCI runtime. Fixes #4666 Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Diffstat (limited to 'libpod/container_internal.go')
-rw-r--r--libpod/container_internal.go40
1 files changed, 40 insertions, 0 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 1e8a8a580..37801162a 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1749,6 +1749,11 @@ func (c *Container) checkReadyForRemoval() error {
return errors.Wrapf(define.ErrCtrStateInvalid, "cannot remove container %s as it is %s - running or paused containers cannot be removed without force", c.ID(), c.state.State.String())
}
+ // Reap exec sessions
+ if err := c.reapExecSessions(); err != nil {
+ return err
+ }
+
if len(c.state.ExecSessions) != 0 {
return errors.Wrapf(define.ErrCtrStateInvalid, "cannot remove container %s as it has active exec sessions", c.ID())
}
@@ -1855,3 +1860,38 @@ func (c *Container) checkExitFile() error {
// Read the exit file to get our stopped time and exit code.
return c.handleExitFile(exitFile, info)
}
+
+// Reap dead exec sessions
+func (c *Container) reapExecSessions() error {
+ // Instead of saving once per iteration, use a defer to do it once at
+ // the end.
+ var lastErr error
+ needSave := false
+ for id := range c.state.ExecSessions {
+ alive, err := c.ociRuntime.ExecUpdateStatus(c, id)
+ if err != nil {
+ if lastErr != nil {
+ logrus.Errorf("Error reaping exec sessions for container %s: %v", c.ID(), lastErr)
+ }
+ lastErr = err
+ continue
+ }
+ if !alive {
+ // Clean up lingering files and remove the exec session
+ if err := c.ociRuntime.ExecContainerCleanup(c, id); err != nil {
+ return errors.Wrapf(err, "error cleaning up container %s exec session %s files", c.ID(), id)
+ }
+ delete(c.state.ExecSessions, id)
+ needSave = true
+ }
+ }
+ if needSave {
+ if err := c.save(); err != nil {
+ if lastErr != nil {
+ logrus.Errorf("Error reaping exec sessions for container %s: %v", c.ID(), lastErr)
+ }
+ lastErr = err
+ }
+ }
+ return lastErr
+}