github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/state_linux.go (about) 1 // +build linux 2 3 package libcontainer 4 5 import ( 6 "fmt" 7 "os" 8 "path/filepath" 9 "syscall" 10 11 "github.com/Sirupsen/logrus" 12 "github.com/opencontainers/runc/libcontainer/configs" 13 "github.com/opencontainers/runc/libcontainer/utils" 14 ) 15 16 func newStateTransitionError(from, to containerState) error { 17 return &stateTransitionError{ 18 From: from.status().String(), 19 To: to.status().String(), 20 } 21 } 22 23 // stateTransitionError is returned when an invalid state transition happens from one 24 // state to another. 25 type stateTransitionError struct { 26 From string 27 To string 28 } 29 30 func (s *stateTransitionError) Error() string { 31 return fmt.Sprintf("invalid state transition from %s to %s", s.From, s.To) 32 } 33 34 type containerState interface { 35 transition(containerState) error 36 destroy() error 37 status() Status 38 } 39 40 func destroy(c *linuxContainer) error { 41 if !c.config.Namespaces.Contains(configs.NEWPID) { 42 if err := signalAllProcesses(c.cgroupManager, syscall.SIGKILL); err != nil { 43 logrus.Warn(err) 44 } 45 } 46 err := c.cgroupManager.Destroy() 47 if rerr := os.RemoveAll(c.root); err == nil { 48 err = rerr 49 } 50 c.initProcess = nil 51 if herr := runPoststopHooks(c); err == nil { 52 err = herr 53 } 54 c.state = &stoppedState{c: c} 55 return err 56 } 57 58 func runPoststopHooks(c *linuxContainer) error { 59 if c.config.Hooks != nil { 60 s := configs.HookState{ 61 Version: c.config.Version, 62 ID: c.id, 63 Root: c.config.Rootfs, 64 BundlePath: utils.SearchLabels(c.config.Labels, "bundle"), 65 } 66 for _, hook := range c.config.Hooks.Poststop { 67 if err := hook.Run(s); err != nil { 68 return err 69 } 70 } 71 } 72 return nil 73 } 74 75 // stoppedState represents a container is a stopped/destroyed state. 76 type stoppedState struct { 77 c *linuxContainer 78 } 79 80 func (b *stoppedState) status() Status { 81 return Stopped 82 } 83 84 func (b *stoppedState) transition(s containerState) error { 85 switch s.(type) { 86 case *runningState, *restoredState: 87 b.c.state = s 88 return nil 89 case *stoppedState: 90 return nil 91 } 92 return newStateTransitionError(b, s) 93 } 94 95 func (b *stoppedState) destroy() error { 96 return destroy(b.c) 97 } 98 99 // runningState represents a container that is currently running. 100 type runningState struct { 101 c *linuxContainer 102 } 103 104 func (r *runningState) status() Status { 105 return Running 106 } 107 108 func (r *runningState) transition(s containerState) error { 109 switch s.(type) { 110 case *stoppedState: 111 t, err := r.c.runType() 112 if err != nil { 113 return err 114 } 115 if t == Running { 116 return newGenericError(fmt.Errorf("container still running"), ContainerNotStopped) 117 } 118 r.c.state = s 119 return nil 120 case *pausedState: 121 r.c.state = s 122 return nil 123 case *runningState: 124 return nil 125 } 126 return newStateTransitionError(r, s) 127 } 128 129 func (r *runningState) destroy() error { 130 t, err := r.c.runType() 131 if err != nil { 132 return err 133 } 134 if t == Running { 135 return newGenericError(fmt.Errorf("container is not destroyed"), ContainerNotStopped) 136 } 137 return destroy(r.c) 138 } 139 140 type createdState struct { 141 c *linuxContainer 142 } 143 144 func (i *createdState) status() Status { 145 return Created 146 } 147 148 func (i *createdState) transition(s containerState) error { 149 switch s.(type) { 150 case *runningState, *pausedState, *stoppedState: 151 i.c.state = s 152 return nil 153 case *createdState: 154 return nil 155 } 156 return newStateTransitionError(i, s) 157 } 158 159 func (i *createdState) destroy() error { 160 i.c.initProcess.signal(syscall.SIGKILL) 161 return destroy(i.c) 162 } 163 164 // pausedState represents a container that is currently pause. It cannot be destroyed in a 165 // paused state and must transition back to running first. 166 type pausedState struct { 167 c *linuxContainer 168 } 169 170 func (p *pausedState) status() Status { 171 return Paused 172 } 173 174 func (p *pausedState) transition(s containerState) error { 175 switch s.(type) { 176 case *runningState, *stoppedState: 177 p.c.state = s 178 return nil 179 case *pausedState: 180 return nil 181 } 182 return newStateTransitionError(p, s) 183 } 184 185 func (p *pausedState) destroy() error { 186 t, err := p.c.runType() 187 if err != nil { 188 return err 189 } 190 if t != Running && t != Created { 191 if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil { 192 return err 193 } 194 return destroy(p.c) 195 } 196 return newGenericError(fmt.Errorf("container is paused"), ContainerPaused) 197 } 198 199 // restoredState is the same as the running state but also has accociated checkpoint 200 // information that maybe need destroyed when the container is stopped and destroy is called. 201 type restoredState struct { 202 imageDir string 203 c *linuxContainer 204 } 205 206 func (r *restoredState) status() Status { 207 return Running 208 } 209 210 func (r *restoredState) transition(s containerState) error { 211 switch s.(type) { 212 case *stoppedState, *runningState: 213 return nil 214 } 215 return newStateTransitionError(r, s) 216 } 217 218 func (r *restoredState) destroy() error { 219 if _, err := os.Stat(filepath.Join(r.c.root, "checkpoint")); err != nil { 220 if !os.IsNotExist(err) { 221 return err 222 } 223 } 224 return destroy(r.c) 225 } 226 227 // loadedState is used whenever a container is restored, loaded, or setting additional 228 // processes inside and it should not be destroyed when it is exiting. 229 type loadedState struct { 230 c *linuxContainer 231 s Status 232 } 233 234 func (n *loadedState) status() Status { 235 return n.s 236 } 237 238 func (n *loadedState) transition(s containerState) error { 239 n.c.state = s 240 return nil 241 } 242 243 func (n *loadedState) destroy() error { 244 if err := n.c.refreshState(); err != nil { 245 return err 246 } 247 return n.c.state.destroy() 248 }