state_linux.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // +build linux
  2. package libcontainer
  3. import (
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "github.com/Sirupsen/logrus"
  8. "github.com/opencontainers/runc/libcontainer/configs"
  9. "github.com/opencontainers/runc/libcontainer/utils"
  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 := killCgroupProcesses(c.cgroupManager); err != nil {
  34. logrus.Warn(err)
  35. }
  36. }
  37. err := c.cgroupManager.Destroy()
  38. if rerr := os.RemoveAll(c.root); err == nil {
  39. err = rerr
  40. }
  41. c.initProcess = nil
  42. if herr := runPoststopHooks(c); err == nil {
  43. err = herr
  44. }
  45. c.state = &stoppedState{c: c}
  46. return err
  47. }
  48. func runPoststopHooks(c *linuxContainer) error {
  49. if c.config.Hooks != nil {
  50. s := configs.HookState{
  51. Version: c.config.Version,
  52. ID: c.id,
  53. Root: c.config.Rootfs,
  54. BundlePath: utils.SearchLabels(c.config.Labels, "bundle"),
  55. }
  56. for _, hook := range c.config.Hooks.Poststop {
  57. if err := hook.Run(s); err != nil {
  58. return err
  59. }
  60. }
  61. }
  62. return nil
  63. }
  64. // stoppedState represents a container is a stopped/destroyed state.
  65. type stoppedState struct {
  66. c *linuxContainer
  67. }
  68. func (b *stoppedState) status() Status {
  69. return Destroyed
  70. }
  71. func (b *stoppedState) transition(s containerState) error {
  72. switch s.(type) {
  73. case *runningState:
  74. b.c.state = s
  75. return nil
  76. case *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. running, err := r.c.isRunning()
  98. if err != nil {
  99. return err
  100. }
  101. if 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. running, err := r.c.isRunning()
  116. if err != nil {
  117. return err
  118. }
  119. if running {
  120. return newGenericError(fmt.Errorf("container is not destroyed"), ContainerNotStopped)
  121. }
  122. return destroy(r.c)
  123. }
  124. // pausedState represents a container that is currently pause. It cannot be destroyed in a
  125. // paused state and must transition back to running first.
  126. type pausedState struct {
  127. c *linuxContainer
  128. }
  129. func (p *pausedState) status() Status {
  130. return Paused
  131. }
  132. func (p *pausedState) transition(s containerState) error {
  133. switch s.(type) {
  134. case *runningState, *stoppedState:
  135. p.c.state = s
  136. return nil
  137. case *pausedState:
  138. return nil
  139. }
  140. return newStateTransitionError(p, s)
  141. }
  142. func (p *pausedState) destroy() error {
  143. isRunning, err := p.c.isRunning()
  144. if err != nil {
  145. return err
  146. }
  147. if !isRunning {
  148. if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
  149. return err
  150. }
  151. return destroy(p.c)
  152. }
  153. return newGenericError(fmt.Errorf("container is paused"), ContainerPaused)
  154. }
  155. // restoredState is the same as the running state but also has accociated checkpoint
  156. // information that maybe need destroyed when the container is stopped and destory is called.
  157. type restoredState struct {
  158. imageDir string
  159. c *linuxContainer
  160. }
  161. func (r *restoredState) status() Status {
  162. return Running
  163. }
  164. func (r *restoredState) transition(s containerState) error {
  165. switch s.(type) {
  166. case *stoppedState:
  167. return nil
  168. case *runningState:
  169. return nil
  170. }
  171. return newStateTransitionError(r, s)
  172. }
  173. func (r *restoredState) destroy() error {
  174. if _, err := os.Stat(filepath.Join(r.c.root, "checkpoint")); err != nil {
  175. if !os.IsNotExist(err) {
  176. return err
  177. }
  178. }
  179. return destroy(r.c)
  180. }
  181. // createdState is used whenever a container is restored, loaded, or setting additional
  182. // processes inside and it should not be destroyed when it is exiting.
  183. type createdState struct {
  184. c *linuxContainer
  185. s Status
  186. }
  187. func (n *createdState) status() Status {
  188. return n.s
  189. }
  190. func (n *createdState) transition(s containerState) error {
  191. n.c.state = s
  192. return nil
  193. }
  194. func (n *createdState) destroy() error {
  195. if err := n.c.refreshState(); err != nil {
  196. return err
  197. }
  198. return n.c.state.destroy()
  199. }