state_linux.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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/opencontainers/runc/libcontainer/utils"
  9. "github.com/sirupsen/logrus"
  10. "golang.org/x/sys/unix"
  11. )
  12. func newStateTransitionError(from, to containerState) error {
  13. return &stateTransitionError{
  14. From: from.status().String(),
  15. To: to.status().String(),
  16. }
  17. }
  18. // stateTransitionError is returned when an invalid state transition happens from one
  19. // state to another.
  20. type stateTransitionError struct {
  21. From string
  22. To string
  23. }
  24. func (s *stateTransitionError) Error() string {
  25. return fmt.Sprintf("invalid state transition from %s to %s", s.From, s.To)
  26. }
  27. type containerState interface {
  28. transition(containerState) error
  29. destroy() error
  30. status() Status
  31. }
  32. func destroy(c *linuxContainer) error {
  33. if !c.config.Namespaces.Contains(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. if c.config.Hooks != nil {
  56. bundle, annotations := utils.Annotations(c.config.Labels)
  57. s := configs.HookState{
  58. Version: c.config.Version,
  59. ID: c.id,
  60. Bundle: bundle,
  61. Annotations: annotations,
  62. }
  63. for _, hook := range c.config.Hooks.Poststop {
  64. if err := hook.Run(s); err != nil {
  65. return err
  66. }
  67. }
  68. }
  69. return nil
  70. }
  71. // stoppedState represents a container is a stopped/destroyed state.
  72. type stoppedState struct {
  73. c *linuxContainer
  74. }
  75. func (b *stoppedState) status() Status {
  76. return Stopped
  77. }
  78. func (b *stoppedState) transition(s containerState) error {
  79. switch s.(type) {
  80. case *runningState, *restoredState:
  81. b.c.state = s
  82. return nil
  83. case *stoppedState:
  84. return nil
  85. }
  86. return newStateTransitionError(b, s)
  87. }
  88. func (b *stoppedState) destroy() error {
  89. return destroy(b.c)
  90. }
  91. // runningState represents a container that is currently running.
  92. type runningState struct {
  93. c *linuxContainer
  94. }
  95. func (r *runningState) status() Status {
  96. return Running
  97. }
  98. func (r *runningState) transition(s containerState) error {
  99. switch s.(type) {
  100. case *stoppedState:
  101. t, err := r.c.runType()
  102. if err != nil {
  103. return err
  104. }
  105. if t == Running {
  106. return newGenericError(fmt.Errorf("container still running"), ContainerNotStopped)
  107. }
  108. r.c.state = s
  109. return nil
  110. case *pausedState:
  111. r.c.state = s
  112. return nil
  113. case *runningState:
  114. return nil
  115. }
  116. return newStateTransitionError(r, s)
  117. }
  118. func (r *runningState) destroy() error {
  119. t, err := r.c.runType()
  120. if err != nil {
  121. return err
  122. }
  123. if t == Running {
  124. return newGenericError(fmt.Errorf("container is not destroyed"), ContainerNotStopped)
  125. }
  126. return destroy(r.c)
  127. }
  128. type createdState struct {
  129. c *linuxContainer
  130. }
  131. func (i *createdState) status() Status {
  132. return Created
  133. }
  134. func (i *createdState) transition(s containerState) error {
  135. switch s.(type) {
  136. case *runningState, *pausedState, *stoppedState:
  137. i.c.state = s
  138. return nil
  139. case *createdState:
  140. return nil
  141. }
  142. return newStateTransitionError(i, s)
  143. }
  144. func (i *createdState) destroy() error {
  145. i.c.initProcess.signal(unix.SIGKILL)
  146. return destroy(i.c)
  147. }
  148. // pausedState represents a container that is currently pause. It cannot be destroyed in a
  149. // paused state and must transition back to running first.
  150. type pausedState struct {
  151. c *linuxContainer
  152. }
  153. func (p *pausedState) status() Status {
  154. return Paused
  155. }
  156. func (p *pausedState) transition(s containerState) error {
  157. switch s.(type) {
  158. case *runningState, *stoppedState:
  159. p.c.state = s
  160. return nil
  161. case *pausedState:
  162. return nil
  163. }
  164. return newStateTransitionError(p, s)
  165. }
  166. func (p *pausedState) destroy() error {
  167. t, err := p.c.runType()
  168. if err != nil {
  169. return err
  170. }
  171. if t != Running && t != Created {
  172. if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
  173. return err
  174. }
  175. return destroy(p.c)
  176. }
  177. return newGenericError(fmt.Errorf("container is paused"), ContainerPaused)
  178. }
  179. // restoredState is the same as the running state but also has associated checkpoint
  180. // information that maybe need destroyed when the container is stopped and destroy is called.
  181. type restoredState struct {
  182. imageDir string
  183. c *linuxContainer
  184. }
  185. func (r *restoredState) status() Status {
  186. return Running
  187. }
  188. func (r *restoredState) transition(s containerState) error {
  189. switch s.(type) {
  190. case *stoppedState, *runningState:
  191. return nil
  192. }
  193. return newStateTransitionError(r, s)
  194. }
  195. func (r *restoredState) destroy() error {
  196. if _, err := os.Stat(filepath.Join(r.c.root, "checkpoint")); err != nil {
  197. if !os.IsNotExist(err) {
  198. return err
  199. }
  200. }
  201. return destroy(r.c)
  202. }
  203. // loadedState is used whenever a container is restored, loaded, or setting additional
  204. // processes inside and it should not be destroyed when it is exiting.
  205. type loadedState struct {
  206. c *linuxContainer
  207. s Status
  208. }
  209. func (n *loadedState) status() Status {
  210. return n.s
  211. }
  212. func (n *loadedState) transition(s containerState) error {
  213. n.c.state = s
  214. return nil
  215. }
  216. func (n *loadedState) destroy() error {
  217. if err := n.c.refreshState(); err != nil {
  218. return err
  219. }
  220. return n.c.state.destroy()
  221. }