github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/state_linux.go (about)

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