Merge pull request #499 from crosbymichael/state-fixes
Fix various state bugs for pause and destroy
This commit is contained in:
commit
3268a1ea00
|
@ -189,29 +189,27 @@ func (c *linuxContainer) Start(process *Process) error {
|
||||||
}
|
}
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
|
c.state = &runningState{
|
||||||
|
c: c,
|
||||||
|
}
|
||||||
if doInit {
|
if doInit {
|
||||||
if err := c.updateState(parent); err != nil {
|
if err := c.updateState(parent); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
if c.config.Hooks != nil {
|
||||||
c.state.transition(&nullState{
|
s := configs.HookState{
|
||||||
c: c,
|
Version: c.config.Version,
|
||||||
s: Running,
|
ID: c.id,
|
||||||
})
|
Pid: parent.pid(),
|
||||||
}
|
Root: c.config.Rootfs,
|
||||||
if c.config.Hooks != nil {
|
}
|
||||||
s := configs.HookState{
|
for _, hook := range c.config.Hooks.Poststart {
|
||||||
Version: c.config.Version,
|
if err := hook.Run(s); err != nil {
|
||||||
ID: c.id,
|
if err := parent.terminate(); err != nil {
|
||||||
Pid: parent.pid(),
|
logrus.Warn(err)
|
||||||
Root: c.config.Rootfs,
|
}
|
||||||
}
|
return newSystemError(err)
|
||||||
for _, hook := range c.config.Hooks.Poststart {
|
|
||||||
if err := hook.Run(s); err != nil {
|
|
||||||
if err := parent.terminate(); err != nil {
|
|
||||||
logrus.Warn(err)
|
|
||||||
}
|
}
|
||||||
return newSystemError(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,6 +338,13 @@ func (c *linuxContainer) Destroy() error {
|
||||||
func (c *linuxContainer) Pause() error {
|
func (c *linuxContainer) Pause() error {
|
||||||
c.m.Lock()
|
c.m.Lock()
|
||||||
defer c.m.Unlock()
|
defer c.m.Unlock()
|
||||||
|
status, err := c.currentStatus()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if status != Running {
|
||||||
|
return newGenericError(fmt.Errorf("container not running"), ContainerNotRunning)
|
||||||
|
}
|
||||||
if err := c.cgroupManager.Freeze(configs.Frozen); err != nil {
|
if err := c.cgroupManager.Freeze(configs.Frozen); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -351,6 +356,13 @@ func (c *linuxContainer) Pause() error {
|
||||||
func (c *linuxContainer) Resume() error {
|
func (c *linuxContainer) Resume() error {
|
||||||
c.m.Lock()
|
c.m.Lock()
|
||||||
defer c.m.Unlock()
|
defer c.m.Unlock()
|
||||||
|
status, err := c.currentStatus()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if status != Paused {
|
||||||
|
return newGenericError(fmt.Errorf("container not paused"), ContainerNotPaused)
|
||||||
|
}
|
||||||
if err := c.cgroupManager.Freeze(configs.Thawed); err != nil {
|
if err := c.cgroupManager.Freeze(configs.Thawed); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -939,9 +951,6 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
|
||||||
|
|
||||||
func (c *linuxContainer) updateState(process parentProcess) error {
|
func (c *linuxContainer) updateState(process parentProcess) error {
|
||||||
c.initProcess = process
|
c.initProcess = process
|
||||||
if err := c.refreshState(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
state, err := c.currentState()
|
state, err := c.currentState()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1017,35 +1026,36 @@ func (c *linuxContainer) isPaused() (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linuxContainer) currentState() (*State, error) {
|
func (c *linuxContainer) currentState() (*State, error) {
|
||||||
status, err := c.currentStatus()
|
var (
|
||||||
if err != nil {
|
startTime string
|
||||||
return nil, err
|
externalDescriptors []string
|
||||||
}
|
pid = -1
|
||||||
if status == Destroyed {
|
)
|
||||||
return nil, newGenericError(fmt.Errorf("container destroyed"), ContainerNotExists)
|
if c.initProcess != nil {
|
||||||
}
|
pid = c.initProcess.pid()
|
||||||
startTime, err := c.initProcess.startTime()
|
startTime, _ = c.initProcess.startTime()
|
||||||
if err != nil {
|
externalDescriptors = c.initProcess.externalDescriptors()
|
||||||
return nil, newSystemError(err)
|
|
||||||
}
|
}
|
||||||
state := &State{
|
state := &State{
|
||||||
BaseState: BaseState{
|
BaseState: BaseState{
|
||||||
ID: c.ID(),
|
ID: c.ID(),
|
||||||
Config: *c.config,
|
Config: *c.config,
|
||||||
InitProcessPid: c.initProcess.pid(),
|
InitProcessPid: pid,
|
||||||
InitProcessStartTime: startTime,
|
InitProcessStartTime: startTime,
|
||||||
},
|
},
|
||||||
CgroupPaths: c.cgroupManager.GetPaths(),
|
CgroupPaths: c.cgroupManager.GetPaths(),
|
||||||
NamespacePaths: make(map[configs.NamespaceType]string),
|
NamespacePaths: make(map[configs.NamespaceType]string),
|
||||||
ExternalDescriptors: c.initProcess.externalDescriptors(),
|
ExternalDescriptors: externalDescriptors,
|
||||||
}
|
}
|
||||||
for _, ns := range c.config.Namespaces {
|
if pid > 0 {
|
||||||
state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid())
|
for _, ns := range c.config.Namespaces {
|
||||||
}
|
state.NamespacePaths[ns.Type] = ns.GetPath(pid)
|
||||||
for _, nsType := range configs.NamespaceTypes() {
|
}
|
||||||
if _, ok := state.NamespacePaths[nsType]; !ok {
|
for _, nsType := range configs.NamespaceTypes() {
|
||||||
ns := configs.Namespace{Type: nsType}
|
if _, ok := state.NamespacePaths[nsType]; !ok {
|
||||||
state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid())
|
ns := configs.Namespace{Type: nsType}
|
||||||
|
state.NamespacePaths[ns.Type] = ns.GetPath(pid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state, nil
|
return state, nil
|
||||||
|
|
|
@ -16,6 +16,7 @@ const (
|
||||||
ContainerPaused
|
ContainerPaused
|
||||||
ContainerNotStopped
|
ContainerNotStopped
|
||||||
ContainerNotRunning
|
ContainerNotRunning
|
||||||
|
ContainerNotPaused
|
||||||
|
|
||||||
// Process errors
|
// Process errors
|
||||||
ProcessNotExecuted
|
ProcessNotExecuted
|
||||||
|
@ -46,6 +47,8 @@ func (c ErrorCode) String() string {
|
||||||
return "Container is not running"
|
return "Container is not running"
|
||||||
case ConsoleExists:
|
case ConsoleExists:
|
||||||
return "Console exists for process"
|
return "Console exists for process"
|
||||||
|
case ContainerNotPaused:
|
||||||
|
return "Container is not paused"
|
||||||
default:
|
default:
|
||||||
return "Unknown error"
|
return "Unknown error"
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,6 +203,9 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
|
||||||
root: containerRoot,
|
root: containerRoot,
|
||||||
}
|
}
|
||||||
c.state = &nullState{c: c}
|
c.state = &nullState{c: c}
|
||||||
|
if err := c.refreshState(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ func destroy(c *linuxContainer) error {
|
||||||
if herr := runPoststopHooks(c); err == nil {
|
if herr := runPoststopHooks(c); err == nil {
|
||||||
err = herr
|
err = herr
|
||||||
}
|
}
|
||||||
|
c.state = &stoppedState{c: c}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,10 +117,10 @@ func (r *runningState) transition(s containerState) error {
|
||||||
}
|
}
|
||||||
r.c.state = s
|
r.c.state = s
|
||||||
return nil
|
return nil
|
||||||
case *pausedState:
|
case *pausedState, *nullState:
|
||||||
r.c.state = s
|
r.c.state = s
|
||||||
return nil
|
return nil
|
||||||
case *runningState, *nullState:
|
case *runningState:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return newStateTransitionError(r, s)
|
return newStateTransitionError(r, s)
|
||||||
|
@ -148,7 +149,7 @@ func (p *pausedState) status() Status {
|
||||||
|
|
||||||
func (p *pausedState) transition(s containerState) error {
|
func (p *pausedState) transition(s containerState) error {
|
||||||
switch s.(type) {
|
switch s.(type) {
|
||||||
case *runningState:
|
case *runningState, *stoppedState:
|
||||||
p.c.state = s
|
p.c.state = s
|
||||||
return nil
|
return nil
|
||||||
case *pausedState:
|
case *pausedState:
|
||||||
|
@ -158,6 +159,16 @@ func (p *pausedState) transition(s containerState) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pausedState) destroy() error {
|
func (p *pausedState) destroy() error {
|
||||||
|
isRunning, err := p.c.isRunning()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !isRunning {
|
||||||
|
if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return destroy(p.c)
|
||||||
|
}
|
||||||
return newGenericError(fmt.Errorf("container is paused"), ContainerPaused)
|
return newGenericError(fmt.Errorf("container is paused"), ContainerPaused)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,12 +214,7 @@ func (n *nullState) status() Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *nullState) transition(s containerState) error {
|
func (n *nullState) transition(s containerState) error {
|
||||||
switch s.(type) {
|
n.c.state = s
|
||||||
case *restoredState:
|
|
||||||
n.c.state = s
|
|
||||||
default:
|
|
||||||
// do nothing for null states
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,19 +49,13 @@ func TestPausedStateTransition(t *testing.T) {
|
||||||
valid := []containerState{
|
valid := []containerState{
|
||||||
&pausedState{},
|
&pausedState{},
|
||||||
&runningState{},
|
&runningState{},
|
||||||
|
&stoppedState{},
|
||||||
}
|
}
|
||||||
for _, v := range valid {
|
for _, v := range valid {
|
||||||
if err := s.transition(v); err != nil {
|
if err := s.transition(v); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := s.transition(&stoppedState{})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("transition to stopped state should fail")
|
|
||||||
}
|
|
||||||
if !isStateTransitionError(err) {
|
|
||||||
t.Fatal("expected stateTransitionError")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRestoredStateTransition(t *testing.T) {
|
func TestRestoredStateTransition(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue