...

Source file src/github.com/opencontainers/runc/libcontainer/state_linux.go

Documentation: github.com/opencontainers/runc/libcontainer

     1  package libcontainer
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/opencontainers/runc/libcontainer/configs"
     9  	"github.com/opencontainers/runtime-spec/specs-go"
    10  	"github.com/sirupsen/logrus"
    11  	"golang.org/x/sys/unix"
    12  )
    13  
    14  func newStateTransitionError(from, to containerState) error {
    15  	return &stateTransitionError{
    16  		From: from.status().String(),
    17  		To:   to.status().String(),
    18  	}
    19  }
    20  
    21  // stateTransitionError is returned when an invalid state transition happens from one
    22  // state to another.
    23  type stateTransitionError struct {
    24  	From string
    25  	To   string
    26  }
    27  
    28  func (s *stateTransitionError) Error() string {
    29  	return fmt.Sprintf("invalid state transition from %s to %s", s.From, s.To)
    30  }
    31  
    32  type containerState interface {
    33  	transition(containerState) error
    34  	destroy() error
    35  	status() Status
    36  }
    37  
    38  func destroy(c *linuxContainer) error {
    39  	if !c.config.Namespaces.Contains(configs.NEWPID) ||
    40  		c.config.Namespaces.PathOf(configs.NEWPID) != "" {
    41  		if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil {
    42  			logrus.Warn(err)
    43  		}
    44  	}
    45  	err := c.cgroupManager.Destroy()
    46  	if c.intelRdtManager != nil {
    47  		if ierr := c.intelRdtManager.Destroy(); err == nil {
    48  			err = ierr
    49  		}
    50  	}
    51  	if rerr := os.RemoveAll(c.root); err == nil {
    52  		err = rerr
    53  	}
    54  	c.initProcess = nil
    55  	if herr := runPoststopHooks(c); err == nil {
    56  		err = herr
    57  	}
    58  	c.state = &stoppedState{c: c}
    59  	return err
    60  }
    61  
    62  func runPoststopHooks(c *linuxContainer) error {
    63  	hooks := c.config.Hooks
    64  	if hooks == nil {
    65  		return nil
    66  	}
    67  
    68  	s, err := c.currentOCIState()
    69  	if err != nil {
    70  		return err
    71  	}
    72  	s.Status = specs.StateStopped
    73  
    74  	if err := hooks[configs.Poststop].RunHooks(s); err != nil {
    75  		return err
    76  	}
    77  
    78  	return nil
    79  }
    80  
    81  // stoppedState represents a container is a stopped/destroyed state.
    82  type stoppedState struct {
    83  	c *linuxContainer
    84  }
    85  
    86  func (b *stoppedState) status() Status {
    87  	return Stopped
    88  }
    89  
    90  func (b *stoppedState) transition(s containerState) error {
    91  	switch s.(type) {
    92  	case *runningState, *restoredState:
    93  		b.c.state = s
    94  		return nil
    95  	case *stoppedState:
    96  		return nil
    97  	}
    98  	return newStateTransitionError(b, s)
    99  }
   100  
   101  func (b *stoppedState) destroy() error {
   102  	return destroy(b.c)
   103  }
   104  
   105  // runningState represents a container that is currently running.
   106  type runningState struct {
   107  	c *linuxContainer
   108  }
   109  
   110  func (r *runningState) status() Status {
   111  	return Running
   112  }
   113  
   114  func (r *runningState) transition(s containerState) error {
   115  	switch s.(type) {
   116  	case *stoppedState:
   117  		if r.c.runType() == Running {
   118  			return ErrRunning
   119  		}
   120  		r.c.state = s
   121  		return nil
   122  	case *pausedState:
   123  		r.c.state = s
   124  		return nil
   125  	case *runningState:
   126  		return nil
   127  	}
   128  	return newStateTransitionError(r, s)
   129  }
   130  
   131  func (r *runningState) destroy() error {
   132  	if r.c.runType() == Running {
   133  		return ErrRunning
   134  	}
   135  	return destroy(r.c)
   136  }
   137  
   138  type createdState struct {
   139  	c *linuxContainer
   140  }
   141  
   142  func (i *createdState) status() Status {
   143  	return Created
   144  }
   145  
   146  func (i *createdState) transition(s containerState) error {
   147  	switch s.(type) {
   148  	case *runningState, *pausedState, *stoppedState:
   149  		i.c.state = s
   150  		return nil
   151  	case *createdState:
   152  		return nil
   153  	}
   154  	return newStateTransitionError(i, s)
   155  }
   156  
   157  func (i *createdState) destroy() error {
   158  	_ = i.c.initProcess.signal(unix.SIGKILL)
   159  	return destroy(i.c)
   160  }
   161  
   162  // pausedState represents a container that is currently pause.  It cannot be destroyed in a
   163  // paused state and must transition back to running first.
   164  type pausedState struct {
   165  	c *linuxContainer
   166  }
   167  
   168  func (p *pausedState) status() Status {
   169  	return Paused
   170  }
   171  
   172  func (p *pausedState) transition(s containerState) error {
   173  	switch s.(type) {
   174  	case *runningState, *stoppedState:
   175  		p.c.state = s
   176  		return nil
   177  	case *pausedState:
   178  		return nil
   179  	}
   180  	return newStateTransitionError(p, s)
   181  }
   182  
   183  func (p *pausedState) destroy() error {
   184  	t := p.c.runType()
   185  	if t != Running && t != Created {
   186  		if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
   187  			return err
   188  		}
   189  		return destroy(p.c)
   190  	}
   191  	return ErrPaused
   192  }
   193  
   194  // restoredState is the same as the running state but also has associated checkpoint
   195  // information that maybe need destroyed when the container is stopped and destroy is called.
   196  type restoredState struct {
   197  	imageDir string
   198  	c        *linuxContainer
   199  }
   200  
   201  func (r *restoredState) status() Status {
   202  	return Running
   203  }
   204  
   205  func (r *restoredState) transition(s containerState) error {
   206  	switch s.(type) {
   207  	case *stoppedState, *runningState:
   208  		return nil
   209  	}
   210  	return newStateTransitionError(r, s)
   211  }
   212  
   213  func (r *restoredState) destroy() error {
   214  	if _, err := os.Stat(filepath.Join(r.c.root, "checkpoint")); err != nil {
   215  		if !os.IsNotExist(err) {
   216  			return err
   217  		}
   218  	}
   219  	return destroy(r.c)
   220  }
   221  
   222  // loadedState is used whenever a container is restored, loaded, or setting additional
   223  // processes inside and it should not be destroyed when it is exiting.
   224  type loadedState struct {
   225  	c *linuxContainer
   226  	s Status
   227  }
   228  
   229  func (n *loadedState) status() Status {
   230  	return n.s
   231  }
   232  
   233  func (n *loadedState) transition(s containerState) error {
   234  	n.c.state = s
   235  	return nil
   236  }
   237  
   238  func (n *loadedState) destroy() error {
   239  	if err := n.c.refreshState(); err != nil {
   240  		return err
   241  	}
   242  	return n.c.state.destroy()
   243  }
   244  

View as plain text