Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libcontainer: Add support for the "pausing" status #1704

Closed
wants to merge 1 commit into from
Closed
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
26 changes: 19 additions & 7 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -1588,11 +1588,13 @@ func (c *linuxContainer) currentStatus() (Status, error) {
// out of process we need to verify the container's status based on runtime
// information and not rely on our in process info.
func (c *linuxContainer) refreshState() error {
paused, err := c.isPaused()
paused, err := c.pausedState()
if err != nil {
return err
}
if paused {
if paused == Pausing {
return c.state.transition(&pausingState{c: c})
} else if paused == Paused {
return c.state.transition(&pausedState{c: c})
}
t, err := c.runType()
Expand Down Expand Up @@ -1628,21 +1630,31 @@ func (c *linuxContainer) runType() (Status, error) {
return Running, nil
}

func (c *linuxContainer) isPaused() (bool, error) {
// pausedState returns -1 (for containers that are neither Pausing or
// Paused), Pausing, or Paused.
func (c *linuxContainer) pausedState() (Status, error) {
fcg := c.cgroupManager.GetPaths()["freezer"]
if fcg == "" {
// A container doesn't have a freezer cgroup
return false, nil
return -1, nil
}
data, err := ioutil.ReadFile(filepath.Join(fcg, "freezer.state"))
if err != nil {
// If freezer cgroup is not mounted, the container would just be not paused.
if os.IsNotExist(err) {
return false, nil
return -1, nil
}
return false, newSystemErrorWithCause(err, "checking if container is paused")
return -1, newSystemErrorWithCause(err, "checking if container is paused")
}
return bytes.Equal(bytes.TrimSpace(data), []byte("FROZEN")), nil
state := string(bytes.TrimSpace(data))
if state == "FREEZING" {
return Pausing, nil
} else if state == "FROZEN" {
return Paused, nil
} else if state == "THAWED" {
return -1, nil
}
return -1, fmt.Errorf("unrecognized freezer.state: %s", state)
}

func (c *linuxContainer) currentState() (*State, error) {
Expand Down
3 changes: 3 additions & 0 deletions libcontainer/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const (

// Container errors
ContainerNotExists
ContainerPausing
ContainerPaused
ContainerNotStopped
ContainerNotRunning
Expand All @@ -33,6 +34,8 @@ func (c ErrorCode) String() string {
return "Id already in use"
case InvalidIdFormat:
return "Invalid format"
case ContainerPausing:
return "Container pausing"
case ContainerPaused:
return "Container paused"
case ConfigInvalid:
Expand Down
41 changes: 38 additions & 3 deletions libcontainer/state_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (r *runningState) transition(s containerState) error {
}
r.c.state = s
return nil
case *pausedState:
case *pausingState, *pausedState:
r.c.state = s
return nil
case *runningState:
Expand Down Expand Up @@ -154,7 +154,7 @@ func (i *createdState) status() Status {

func (i *createdState) transition(s containerState) error {
switch s.(type) {
case *runningState, *pausedState, *stoppedState:
case *runningState, *pausingState, *pausedState, *stoppedState:
i.c.state = s
return nil
case *createdState:
Expand All @@ -168,7 +168,42 @@ func (i *createdState) destroy() error {
return destroy(i.c)
}

// pausedState represents a container that is currently pause. It cannot be destroyed in a
// pausingState represents a container that is currently pausing. It cannot be destroyed in a
// pausing state and must transition back to running first.
type pausingState struct {
c *linuxContainer
}

func (p *pausingState) status() Status {
return Pausing
}

func (p *pausingState) transition(s containerState) error {
switch s.(type) {
case *pausedState, *runningState, *stoppedState:
p.c.state = s
return nil
case *pausingState:
return nil
}
return newStateTransitionError(p, s)
}

func (p *pausingState) destroy() error {
t, err := p.c.runType()
if err != nil {
return err
}
if t != Running && t != Created {
if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
return err
}
return destroy(p.c)
}
return newGenericError(fmt.Errorf("container is pausing"), ContainerPausing)
}

// pausedState represents a container that is currently paused. It cannot be destroyed in a
// paused state and must transition back to running first.
type pausedState struct {
c *linuxContainer
Expand Down
16 changes: 16 additions & 0 deletions libcontainer/state_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var states = map[containerState]Status{
&createdState{}: Created,
&runningState{}: Running,
&restoredState{}: Running,
&pausingState{}: Pausing,
&pausedState{}: Paused,
&stoppedState{}: Stopped,
&loadedState{s: Running}: Running,
Expand Down Expand Up @@ -67,6 +68,19 @@ func TestStoppedStateTransition(t *testing.T) {
)
}

func TestPausingStateTransition(t *testing.T) {
testTransitions(
t,
&pausingState{c: &linuxContainer{}},
[]containerState{
&pausingState{},
&pausedState{},
&runningState{},
&stoppedState{},
},
)
}

func TestPausedStateTransition(t *testing.T) {
testTransitions(
t,
Expand Down Expand Up @@ -96,6 +110,7 @@ func TestRunningStateTransition(t *testing.T) {
&runningState{c: &linuxContainer{}},
[]containerState{
&stoppedState{},
&pausingState{},
&pausedState{},
&runningState{},
},
Expand All @@ -108,6 +123,7 @@ func TestCreatedStateTransition(t *testing.T) {
&createdState{c: &linuxContainer{}},
[]containerState{
&stoppedState{},
&pausingState{},
&pausedState{},
&runningState{},
&createdState{},
Expand Down