diff options
Diffstat (limited to 'libpod/container_api.go')
-rw-r--r-- | libpod/container_api.go | 265 |
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 |