...
1 package libcontainer
2
3 import (
4 "fmt"
5 "os"
6 "path/filepath"
7
8 "github.com/opencontainers/runc/libcontainer/configs"
9 "github.com/opencontainers/runtime-spec/specs-go"
10 "github.com/sirupsen/logrus"
11 "golang.org/x/sys/unix"
12 )
13
14 func newStateTransitionError(from, to containerState) error {
15 return &stateTransitionError{
16 From: from.status().String(),
17 To: to.status().String(),
18 }
19 }
20
21
22
23 type stateTransitionError struct {
24 From string
25 To string
26 }
27
28 func (s *stateTransitionError) Error() string {
29 return fmt.Sprintf("invalid state transition from %s to %s", s.From, s.To)
30 }
31
32 type containerState interface {
33 transition(containerState) error
34 destroy() error
35 status() Status
36 }
37
38 func destroy(c *linuxContainer) error {
39 if !c.config.Namespaces.Contains(configs.NEWPID) ||
40 c.config.Namespaces.PathOf(configs.NEWPID) != "" {
41 if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil {
42 logrus.Warn(err)
43 }
44 }
45 err := c.cgroupManager.Destroy()
46 if c.intelRdtManager != nil {
47 if ierr := c.intelRdtManager.Destroy(); err == nil {
48 err = ierr
49 }
50 }
51 if rerr := os.RemoveAll(c.root); err == nil {
52 err = rerr
53 }
54 c.initProcess = nil
55 if herr := runPoststopHooks(c); err == nil {
56 err = herr
57 }
58 c.state = &stoppedState{c: c}
59 return err
60 }
61
62 func runPoststopHooks(c *linuxContainer) error {
63 hooks := c.config.Hooks
64 if hooks == nil {
65 return nil
66 }
67
68 s, err := c.currentOCIState()
69 if err != nil {
70 return err
71 }
72 s.Status = specs.StateStopped
73
74 if err := hooks[configs.Poststop].RunHooks(s); err != nil {
75 return err
76 }
77
78 return nil
79 }
80
81
82 type stoppedState struct {
83 c *linuxContainer
84 }
85
86 func (b *stoppedState) status() Status {
87 return Stopped
88 }
89
90 func (b *stoppedState) transition(s containerState) error {
91 switch s.(type) {
92 case *runningState, *restoredState:
93 b.c.state = s
94 return nil
95 case *stoppedState:
96 return nil
97 }
98 return newStateTransitionError(b, s)
99 }
100
101 func (b *stoppedState) destroy() error {
102 return destroy(b.c)
103 }
104
105
106 type runningState struct {
107 c *linuxContainer
108 }
109
110 func (r *runningState) status() Status {
111 return Running
112 }
113
114 func (r *runningState) transition(s containerState) error {
115 switch s.(type) {
116 case *stoppedState:
117 if r.c.runType() == Running {
118 return ErrRunning
119 }
120 r.c.state = s
121 return nil
122 case *pausedState:
123 r.c.state = s
124 return nil
125 case *runningState:
126 return nil
127 }
128 return newStateTransitionError(r, s)
129 }
130
131 func (r *runningState) destroy() error {
132 if r.c.runType() == Running {
133 return ErrRunning
134 }
135 return destroy(r.c)
136 }
137
138 type createdState struct {
139 c *linuxContainer
140 }
141
142 func (i *createdState) status() Status {
143 return Created
144 }
145
146 func (i *createdState) transition(s containerState) error {
147 switch s.(type) {
148 case *runningState, *pausedState, *stoppedState:
149 i.c.state = s
150 return nil
151 case *createdState:
152 return nil
153 }
154 return newStateTransitionError(i, s)
155 }
156
157 func (i *createdState) destroy() error {
158 _ = i.c.initProcess.signal(unix.SIGKILL)
159 return destroy(i.c)
160 }
161
162
163
164 type pausedState struct {
165 c *linuxContainer
166 }
167
168 func (p *pausedState) status() Status {
169 return Paused
170 }
171
172 func (p *pausedState) transition(s containerState) error {
173 switch s.(type) {
174 case *runningState, *stoppedState:
175 p.c.state = s
176 return nil
177 case *pausedState:
178 return nil
179 }
180 return newStateTransitionError(p, s)
181 }
182
183 func (p *pausedState) destroy() error {
184 t := p.c.runType()
185 if t != Running && t != Created {
186 if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
187 return err
188 }
189 return destroy(p.c)
190 }
191 return ErrPaused
192 }
193
194
195
196 type restoredState struct {
197 imageDir string
198 c *linuxContainer
199 }
200
201 func (r *restoredState) status() Status {
202 return Running
203 }
204
205 func (r *restoredState) transition(s containerState) error {
206 switch s.(type) {
207 case *stoppedState, *runningState:
208 return nil
209 }
210 return newStateTransitionError(r, s)
211 }
212
213 func (r *restoredState) destroy() error {
214 if _, err := os.Stat(filepath.Join(r.c.root, "checkpoint")); err != nil {
215 if !os.IsNotExist(err) {
216 return err
217 }
218 }
219 return destroy(r.c)
220 }
221
222
223
224 type loadedState struct {
225 c *linuxContainer
226 s Status
227 }
228
229 func (n *loadedState) status() Status {
230 return n.s
231 }
232
233 func (n *loadedState) transition(s containerState) error {
234 n.c.state = s
235 return nil
236 }
237
238 func (n *loadedState) destroy() error {
239 if err := n.c.refreshState(); err != nil {
240 return err
241 }
242 return n.c.state.destroy()
243 }
244
View as plain text