state_linux.go 4.9 KB

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