summaryrefslogtreecommitdiff
path: root/libpod/container_api.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/container_api.go')
-rw-r--r--libpod/container_api.go265
1 files changed, 14 insertions, 251 deletions
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 039619ea6..967180437 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -9,10 +9,8 @@ import (
"os"
"time"
- "github.com/containers/common/pkg/capabilities"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/events"
- "github.com/containers/storage/pkg/stringid"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -215,142 +213,6 @@ func (c *Container) Kill(signal uint) error {
return c.save()
}
-// Exec starts a new process inside the container
-// Returns an exit code and an error. If Exec was not able to exec in the container before a failure, an exit code of define.ExecErrorCodeCannotInvoke is returned.
-// If another generic error happens, an exit code of define.ExecErrorCodeGeneric is returned.
-// Sometimes, the $RUNTIME exec call errors, and if that is the case, the exit code is the exit code of the call.
-// Otherwise, the exit code will be the exit code of the executed call inside of the container.
-// TODO investigate allowing exec without attaching
-func (c *Container) Exec(tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *AttachStreams, preserveFDs uint, resize chan remotecommand.TerminalSize, detachKeys string) (int, error) {
- var capList []string
- if !c.batched {
- c.lock.Lock()
- defer c.lock.Unlock()
-
- if err := c.syncContainer(); err != nil {
- return define.ExecErrorCodeCannotInvoke, err
- }
- }
-
- if c.state.State != define.ContainerStateRunning {
- return define.ExecErrorCodeCannotInvoke, errors.Wrapf(define.ErrCtrStateInvalid, "cannot exec into container that is not running")
- }
-
- if privileged || c.config.Privileged {
- capList = capabilities.AllCapabilities()
- }
-
- // Generate exec session ID
- // Ensure we don't conflict with an existing session ID
- sessionID := stringid.GenerateNonCryptoID()
- found := true
- // This really ought to be a do-while, but Go doesn't have those...
- for found {
- found = false
- for id := range c.state.ExecSessions {
- if id == sessionID {
- found = true
- break
- }
- }
- if found {
- sessionID = stringid.GenerateNonCryptoID()
- }
- }
-
- logrus.Debugf("Creating new exec session in container %s with session id %s", c.ID(), sessionID)
- if err := c.createExecBundle(sessionID); err != nil {
- return define.ExecErrorCodeCannotInvoke, err
- }
-
- defer func() {
- // cleanup exec bundle
- if err := c.cleanupExecBundle(sessionID); err != nil {
- logrus.Errorf("Error removing exec session %s bundle path for container %s: %v", sessionID, c.ID(), err)
- }
- }()
-
- opts := new(ExecOptions)
- opts.Cmd = cmd
- opts.CapAdd = capList
- opts.Env = env
- opts.Terminal = tty
- opts.Cwd = workDir
- opts.User = user
- opts.Streams = streams
- opts.PreserveFDs = preserveFDs
- opts.Resize = resize
- opts.DetachKeys = detachKeys
-
- pid, attachChan, err := c.ociRuntime.ExecContainer(c, sessionID, opts)
- if err != nil {
- ec := define.ExecErrorCodeGeneric
- // Conmon will pass a non-zero exit code from the runtime as a pid here.
- // we differentiate a pid with an exit code by sending it as negative, so reverse
- // that change and return the exit code the runtime failed with.
- if pid < 0 {
- ec = -1 * pid
- }
- return ec, err
- }
-
- // We have the PID, add it to state
- if c.state.ExecSessions == nil {
- c.state.ExecSessions = make(map[string]*ExecSession)
- }
- session := new(ExecSession)
- session.ID = sessionID
- session.Command = cmd
- session.PID = pid
- c.state.ExecSessions[sessionID] = session
- if err := c.save(); err != nil {
- // Now we have a PID but we can't save it in the DB
- // TODO handle this better
- return define.ExecErrorCodeGeneric, errors.Wrapf(err, "error saving exec sessions %s for container %s", sessionID, c.ID())
- }
- c.newContainerEvent(events.Exec)
- logrus.Debugf("Successfully started exec session %s in container %s", sessionID, c.ID())
-
- // Unlock so other processes can use the container
- if !c.batched {
- c.lock.Unlock()
- }
-
- lastErr := <-attachChan
-
- exitCode, err := c.readExecExitCode(sessionID)
- if err != nil {
- if lastErr != nil {
- logrus.Errorf(lastErr.Error())
- }
- lastErr = err
- }
- if exitCode != 0 {
- if lastErr != nil {
- logrus.Errorf(lastErr.Error())
- }
- lastErr = errors.Wrapf(define.ErrOCIRuntime, "non zero exit code: %d", exitCode)
- }
-
- // Lock again
- if !c.batched {
- c.lock.Lock()
- }
-
- // Sync the container again to pick up changes in state
- if err := c.syncContainer(); err != nil {
- logrus.Errorf("error syncing container %s state to remove exec session %s", c.ID(), sessionID)
- return exitCode, lastErr
- }
-
- // Remove the exec session from state
- delete(c.state.ExecSessions, sessionID)
- if err := c.save(); err != nil {
- logrus.Errorf("Error removing exec session %s from container %s state: %v", sessionID, c.ID(), err)
- }
- return exitCode, lastErr
-}
-
// AttachStreams contains streams that will be attached to the container
type AttachStreams struct {
// OutputStream will be attached to container's STDOUT
@@ -493,7 +355,11 @@ func (c *Container) Unmount(force bool) error {
if c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
return errors.Wrapf(define.ErrCtrStateInvalid, "cannot unmount storage for container %s as it is running or paused", c.ID())
}
- if len(c.state.ExecSessions) != 0 {
+ execSessions, err := c.getActiveExecSessions()
+ if err != nil {
+ return err
+ }
+ if len(execSessions) != 0 {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s has active exec sessions, refusing to unmount", c.ID())
}
return errors.Wrapf(define.ErrInternal, "can't unmount %s last mount, it is still in use", c.ID())
@@ -674,15 +540,15 @@ func (c *Container) Cleanup(ctx context.Context) error {
// If we didn't restart, we perform a normal cleanup
- // Reap exec sessions first.
- if err := c.reapExecSessions(); err != nil {
+ // Check for running exec sessions
+ sessions, err := c.getActiveExecSessions()
+ if err != nil {
return err
}
-
- // Check if we have active exec sessions after reaping.
- if len(c.state.ExecSessions) != 0 {
+ if len(sessions) > 0 {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s has active exec sessions, refusing to clean up", c.ID())
}
+
defer c.newContainerEvent(events.Cleanup)
return c.cleanup(ctx)
}
@@ -757,114 +623,11 @@ func (c *Container) Sync() error {
return nil
}
-// Refresh refreshes a container's state in the database, restarting the
-// container if it is running
+// Refresh is DEPRECATED and REMOVED.
func (c *Container) Refresh(ctx context.Context) error {
- if !c.batched {
- c.lock.Lock()
- defer c.lock.Unlock()
-
- if err := c.syncContainer(); err != nil {
- return err
- }
- }
-
- if c.state.State == define.ContainerStateRemoving {
- return errors.Wrapf(define.ErrCtrStateInvalid, "cannot refresh containers that are being removed")
- }
-
- wasCreated := false
- if c.state.State == define.ContainerStateCreated {
- wasCreated = true
- }
- wasRunning := false
- if c.state.State == define.ContainerStateRunning {
- wasRunning = true
- }
- wasPaused := false
- if c.state.State == define.ContainerStatePaused {
- wasPaused = true
- }
-
- // First, unpause the container if it's paused
- if c.state.State == define.ContainerStatePaused {
- if err := c.unpause(); err != nil {
- return err
- }
- }
-
- // Next, if the container is running, stop it
- if c.state.State == define.ContainerStateRunning {
- if err := c.stop(c.config.StopTimeout); err != nil {
- return err
- }
- }
-
- // If there are active exec sessions, we need to kill them
- if len(c.state.ExecSessions) > 0 {
- logrus.Infof("Killing %d exec sessions in container %s. They will not be restored after refresh.",
- len(c.state.ExecSessions), c.ID())
- }
- for _, session := range c.state.ExecSessions {
- if err := c.ociRuntime.ExecStopContainer(c, session.ID, c.StopTimeout()); err != nil {
- return errors.Wrapf(err, "error stopping exec session %s of container %s", session.ID, c.ID())
- }
- }
-
- // If the container is in ContainerStateStopped, we need to delete it
- // from the runtime and clear conmon state
- if c.state.State == define.ContainerStateStopped {
- if err := c.delete(ctx); err != nil {
- return err
- }
- if err := c.removeConmonFiles(); err != nil {
- return err
- }
- }
-
- // Fire cleanup code one more time unconditionally to ensure we are good
- // to refresh
- if err := c.cleanup(ctx); err != nil {
- return err
- }
-
- logrus.Debugf("Resetting state of container %s", c.ID())
-
- // We've finished unwinding the container back to its initial state
- // Now safe to refresh container state
- if err := resetState(c.state); err != nil {
- return errors.Wrapf(err, "error resetting state of container %s", c.ID())
- }
- if err := c.refresh(); err != nil {
- return err
- }
-
- logrus.Debugf("Successfully refresh container %s state", c.ID())
-
- // Initialize the container if it was created in runc
- if wasCreated || wasRunning || wasPaused {
- if err := c.prepare(); err != nil {
- return err
- }
- if err := c.init(ctx, false); err != nil {
- return err
- }
- }
-
- // If the container was running before, start it
- if wasRunning || wasPaused {
- if err := c.start(); err != nil {
- return err
- }
- }
-
- // If the container was paused before, re-pause it
- if wasPaused {
- if err := c.pause(); err != nil {
- return err
- }
- }
- return nil
+ // This has been deprecated for a long while, and is in the process of
+ // being removed.
+ return define.ErrNotImplemented
}
// ContainerCheckpointOptions is a struct used to pass the parameters