Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 50 additions & 40 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,29 +189,27 @@ func (c *linuxContainer) Start(process *Process) error {
}
return newSystemError(err)
}
c.state = &runningState{
c: c,
}
if doInit {
if err := c.updateState(parent); err != nil {
return err
}
} else {
c.state.transition(&nullState{
c: c,
s: Running,
})
}
if c.config.Hooks != nil {
s := configs.HookState{
Version: c.config.Version,
ID: c.id,
Pid: parent.pid(),
Root: c.config.Rootfs,
}
for _, hook := range c.config.Hooks.Poststart {
if err := hook.Run(s); err != nil {
if err := parent.terminate(); err != nil {
logrus.Warn(err)
if c.config.Hooks != nil {
s := configs.HookState{
Version: c.config.Version,
ID: c.id,
Pid: parent.pid(),
Root: c.config.Rootfs,
}
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)
}
return newSystemError(err)
}
}
}
Expand Down Expand Up @@ -340,6 +338,13 @@ func (c *linuxContainer) Destroy() error {
func (c *linuxContainer) Pause() error {
c.m.Lock()
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 {
return err
}
Expand All @@ -351,6 +356,13 @@ func (c *linuxContainer) Pause() error {
func (c *linuxContainer) Resume() error {
c.m.Lock()
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 {
return err
}
Expand Down Expand Up @@ -939,9 +951,6 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc

func (c *linuxContainer) updateState(process parentProcess) error {
c.initProcess = process
if err := c.refreshState(); err != nil {
return err
}
state, err := c.currentState()
if err != nil {
return err
Expand Down Expand Up @@ -1017,35 +1026,36 @@ func (c *linuxContainer) isPaused() (bool, error) {
}

func (c *linuxContainer) currentState() (*State, error) {
status, err := c.currentStatus()
if err != nil {
return nil, err
}
if status == Destroyed {
return nil, newGenericError(fmt.Errorf("container destroyed"), ContainerNotExists)
}
startTime, err := c.initProcess.startTime()
if err != nil {
return nil, newSystemError(err)
var (
startTime string
externalDescriptors []string
pid = -1
)
if c.initProcess != nil {
pid = c.initProcess.pid()
startTime, _ = c.initProcess.startTime()
externalDescriptors = c.initProcess.externalDescriptors()
}
state := &State{
BaseState: BaseState{
ID: c.ID(),
Config: *c.config,
InitProcessPid: c.initProcess.pid(),
InitProcessPid: pid,
InitProcessStartTime: startTime,
},
CgroupPaths: c.cgroupManager.GetPaths(),
NamespacePaths: make(map[configs.NamespaceType]string),
ExternalDescriptors: c.initProcess.externalDescriptors(),
}
for _, ns := range c.config.Namespaces {
state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid())
ExternalDescriptors: externalDescriptors,
}
for _, nsType := range configs.NamespaceTypes() {
if _, ok := state.NamespacePaths[nsType]; !ok {
ns := configs.Namespace{Type: nsType}
state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid())
if pid > 0 {
for _, ns := range c.config.Namespaces {
state.NamespacePaths[ns.Type] = ns.GetPath(pid)
}
for _, nsType := range configs.NamespaceTypes() {
if _, ok := state.NamespacePaths[nsType]; !ok {
ns := configs.Namespace{Type: nsType}
state.NamespacePaths[ns.Type] = ns.GetPath(pid)
}
}
}
return state, nil
Expand Down
3 changes: 3 additions & 0 deletions libcontainer/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
ContainerPaused
ContainerNotStopped
ContainerNotRunning
ContainerNotPaused

// Process errors
ProcessNotExecuted
Expand Down Expand Up @@ -46,6 +47,8 @@ func (c ErrorCode) String() string {
return "Container is not running"
case ConsoleExists:
return "Console exists for process"
case ContainerNotPaused:
return "Container is not paused"
default:
return "Unknown error"
}
Expand Down
3 changes: 3 additions & 0 deletions libcontainer/factory_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
root: containerRoot,
}
c.state = &nullState{c: c}
if err := c.refreshState(); err != nil {
return nil, err
}
return c, nil
}

Expand Down
24 changes: 15 additions & 9 deletions libcontainer/state_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func destroy(c *linuxContainer) error {
if herr := runPoststopHooks(c); err == nil {
err = herr
}
c.state = &stoppedState{c: c}
return err
}

Expand Down Expand Up @@ -116,10 +117,10 @@ func (r *runningState) transition(s containerState) error {
}
r.c.state = s
return nil
case *pausedState:
case *pausedState, *nullState:
r.c.state = s
return nil
case *runningState, *nullState:
case *runningState:
return nil
}
return newStateTransitionError(r, s)
Expand Down Expand Up @@ -148,7 +149,7 @@ func (p *pausedState) status() Status {

func (p *pausedState) transition(s containerState) error {
switch s.(type) {
case *runningState:
case *runningState, *stoppedState:
p.c.state = s
return nil
case *pausedState:
Expand All @@ -158,6 +159,16 @@ func (p *pausedState) transition(s containerState) 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)
}

Expand Down Expand Up @@ -203,12 +214,7 @@ func (n *nullState) status() Status {
}

func (n *nullState) transition(s containerState) error {
switch s.(type) {
case *restoredState:
n.c.state = s
default:
// do nothing for null states
}
n.c.state = s
return nil
}

Expand Down
8 changes: 1 addition & 7 deletions libcontainer/state_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,13 @@ func TestPausedStateTransition(t *testing.T) {
valid := []containerState{
&pausedState{},
&runningState{},
&stoppedState{},
}
for _, v := range valid {
if err := s.transition(v); err != nil {
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) {
Expand Down