state_linux.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // +build linux
  2. package libcontainer
  3. import (
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "github.com/opencontainers/runc/libcontainer/configs"
  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. if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil {
  34. logrus.Warn(err)
  35. }
  36. }
  37. err := c.cgroupManager.Destroy()
  38. if c.intelRdtManager != nil {
  39. if ierr := c.intelRdtManager.Destroy(); err == nil {
  40. err = ierr
  41. }
  42. }
  43. if rerr := os.RemoveAll(c.root); err == nil {
  44. err = rerr
  45. }
  46. c.initProcess = nil
  47. if herr := runPoststopHooks(c); err == nil {
  48. err = herr
  49. }
  50. c.state = &stoppedState{c: c}
  51. return err
  52. }
  53. func runPoststopHooks(c *linuxContainer) error {
  54. if c.config.Hooks != nil {
  55. s, err := c.currentOCIState()
  56. if err != nil {
  57. return err
  58. }
  59. for _, hook := range c.config.Hooks.Poststop {
  60. if err := hook.Run(s); err != nil {
  61. return err
  62. }
  63. }
  64. }
  65. return nil
  66. }
  67. // stoppedState represents a container is a stopped/destroyed state.
  68. type stoppedState struct {
  69. c *linuxContainer
  70. }
  71. func (b *stoppedState) status() Status {
  72. return Stopped
  73. }
  74. func (b *stoppedState) transition(s containerState) error {
  75. switch s.(type) {
  76. case *runningState, *restoredState:
  77. b.c.state = s
  78. return nil
  79. case *stoppedState:
  80. return nil
  81. }
  82. return newStateTransitionError(b, s)
  83. }
  84. func (b *stoppedState) destroy() error {
  85. return destroy(b.c)
  86. }
  87. // runningState represents a container that is currently running.
  88. type runningState struct {
  89. c *linuxContainer
  90. }
  91. func (r *runningState) status() Status {
  92. return Running
  93. }
  94. func (r *runningState) transition(s containerState) error {
  95. switch s.(type) {
  96. case *stoppedState:
  97. t, err := r.c.runType()
  98. if err != nil {
  99. return err
  100. }
  101. if t == Running {
  102. return newGenericError(fmt.Errorf("container still running"), ContainerNotStopped)
  103. }
  104. r.c.state = s
  105. return nil
  106. case *pausedState:
  107. r.c.state = s
  108. return nil
  109. case *runningState:
  110. return nil
  111. }
  112. return newStateTransitionError(r, s)
  113. }
  114. func (r *runningState) destroy() error {
  115. t, err := r.c.runType()
  116. if err != nil {
  117. return err
  118. }
  119. if t == Running {
  120. return newGenericError(fmt.Errorf("container is not destroyed"), ContainerNotStopped)
  121. }
  122. return destroy(r.c)
  123. }
  124. type createdState struct {
  125. c *linuxContainer
  126. }
  127. func (i *createdState) status() Status {
  128. return Created
  129. }
  130. func (i *createdState) transition(s containerState) error {
  131. switch s.(type) {
  132. case *runningState, *pausedState, *stoppedState:
  133. i.c.state = s
  134. return nil
  135. case *createdState:
  136. return nil
  137. }
  138. return newStateTransitionError(i, s)
  139. }
  140. func (i *createdState) destroy() error {
  141. i.c.initProcess.signal(unix.SIGKILL)
  142. return destroy(i.c)
  143. }
  144. // pausedState represents a container that is currently pause. It cannot be destroyed in a
  145. // paused state and must transition back to running first.
  146. type pausedState struct {
  147. c *linuxContainer
  148. }
  149. func (p *pausedState) status() Status {
  150. return Paused
  151. }
  152. func (p *pausedState) transition(s containerState) error {
  153. switch s.(type) {
  154. case *runningState, *stoppedState:
  155. p.c.state = s
  156. return nil
  157. case *pausedState:
  158. return nil
  159. }
  160. return newStateTransitionError(p, s)
  161. }
  162. func (p *pausedState) destroy() error {
  163. t, err := p.c.runType()
  164. if err != nil {
  165. return err
  166. }
  167. if t != Running && t != Created {
  168. if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
  169. return err
  170. }
  171. return destroy(p.c)
  172. }
  173. return newGenericError(fmt.Errorf("container is paused"), ContainerPaused)
  174. }
  175. // restoredState is the same as the running state but also has associated checkpoint
  176. // information that maybe need destroyed when the container is stopped and destroy is called.
  177. type restoredState struct {
  178. imageDir string
  179. c *linuxContainer
  180. }
  181. func (r *restoredState) status() Status {
  182. return Running
  183. }
  184. func (r *restoredState) transition(s containerState) error {
  185. switch s.(type) {
  186. case *stoppedState, *runningState:
  187. return nil
  188. }
  189. return newStateTransitionError(r, s)
  190. }
  191. func (r *restoredState) destroy() error {
  192. if _, err := os.Stat(filepath.Join(r.c.root, "checkpoint")); err != nil {
  193. if !os.IsNotExist(err) {
  194. return err
  195. }
  196. }
  197. return destroy(r.c)
  198. }
  199. // loadedState is used whenever a container is restored, loaded, or setting additional
  200. // processes inside and it should not be destroyed when it is exiting.
  201. type loadedState struct {
  202. c *linuxContainer
  203. s Status
  204. }
  205. func (n *loadedState) status() Status {
  206. return n.s
  207. }
  208. func (n *loadedState) transition(s containerState) error {
  209. n.c.state = s
  210. return nil
  211. }
  212. func (n *loadedState) destroy() error {
  213. if err := n.c.refreshState(); err != nil {
  214. return err
  215. }
  216. return n.c.state.destroy()
  217. }