Fix process locking and state management
There were races with the way process states. This displayed in ways, especially around pausing the container for atomic operations. Users would get errors like, cannnot delete container in paused state and such. This can be eaisly reproduced with `docker` and the following command: ```bash > (for i in `seq 1 25`; do id=$(docker create alpine usleep 50000);docker start $id;docker commit $id;docker wait $id;docker rm $id; done) ``` This two issues that this fixes are: * locks must be held by the owning process, not the state operations. * If a container ends up being paused but before the operation completes, the process exists, make sure we resume the container before setting the the process as exited. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
130d07edd2
commit
831a41b958
@ -40,7 +40,6 @@ func (s Stdio) IsNull() bool {
|
|||||||
|
|
||||||
// Process on a system
|
// Process on a system
|
||||||
type Process interface {
|
type Process interface {
|
||||||
State
|
|
||||||
// ID returns the id for the process
|
// ID returns the id for the process
|
||||||
ID() string
|
ID() string
|
||||||
// Pid returns the pid for the process
|
// Pid returns the pid for the process
|
||||||
@ -57,10 +56,6 @@ type Process interface {
|
|||||||
Status(context.Context) (string, error)
|
Status(context.Context) (string, error)
|
||||||
// Wait blocks until the process has exited
|
// Wait blocks until the process has exited
|
||||||
Wait()
|
Wait()
|
||||||
}
|
|
||||||
|
|
||||||
// State of a process
|
|
||||||
type State interface {
|
|
||||||
// Resize resizes the process console
|
// Resize resizes the process console
|
||||||
Resize(ws console.WinSize) error
|
Resize(ws console.WinSize) error
|
||||||
// Start execution of the process
|
// Start execution of the process
|
||||||
|
@ -41,7 +41,7 @@ import (
|
|||||||
type execProcess struct {
|
type execProcess struct {
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
|
|
||||||
proc.State
|
execState execState
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
id string
|
id string
|
||||||
@ -86,6 +86,13 @@ func (e *execProcess) ExitedAt() time.Time {
|
|||||||
return e.exited
|
return e.exited
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) SetExited(status int) {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
|
e.execState.SetExited(status)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *execProcess) setExited(status int) {
|
func (e *execProcess) setExited(status int) {
|
||||||
e.status = status
|
e.status = status
|
||||||
e.exited = time.Now()
|
e.exited = time.Now()
|
||||||
@ -93,6 +100,13 @@ func (e *execProcess) setExited(status int) {
|
|||||||
close(e.waitBlock)
|
close(e.waitBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Delete(ctx context.Context) error {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
|
return e.execState.Delete(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *execProcess) delete(ctx context.Context) error {
|
func (e *execProcess) delete(ctx context.Context) error {
|
||||||
e.wg.Wait()
|
e.wg.Wait()
|
||||||
if e.io != nil {
|
if e.io != nil {
|
||||||
@ -107,6 +121,13 @@ func (e *execProcess) delete(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Resize(ws console.WinSize) error {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
|
return e.execState.Resize(ws)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *execProcess) resize(ws console.WinSize) error {
|
func (e *execProcess) resize(ws console.WinSize) error {
|
||||||
if e.console == nil {
|
if e.console == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -114,6 +135,13 @@ func (e *execProcess) resize(ws console.WinSize) error {
|
|||||||
return e.console.Resize(ws)
|
return e.console.Resize(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
|
return e.execState.Kill(ctx, sig, false)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error {
|
func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error {
|
||||||
pid := e.pid
|
pid := e.pid
|
||||||
if pid != 0 {
|
if pid != 0 {
|
||||||
@ -132,6 +160,13 @@ func (e *execProcess) Stdio() proc.Stdio {
|
|||||||
return e.stdio
|
return e.stdio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *execProcess) Start(ctx context.Context) error {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
|
return e.execState.Start(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *execProcess) start(ctx context.Context) (err error) {
|
func (e *execProcess) start(ctx context.Context) (err error) {
|
||||||
var (
|
var (
|
||||||
socket *runc.Socket
|
socket *runc.Socket
|
||||||
|
@ -25,6 +25,14 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type execState interface {
|
||||||
|
Resize(console.WinSize) error
|
||||||
|
Start(context.Context) error
|
||||||
|
Delete(context.Context) error
|
||||||
|
Kill(context.Context, uint32, bool) error
|
||||||
|
SetExited(int)
|
||||||
|
}
|
||||||
|
|
||||||
type execCreatedState struct {
|
type execCreatedState struct {
|
||||||
p *execProcess
|
p *execProcess
|
||||||
}
|
}
|
||||||
@ -32,11 +40,11 @@ type execCreatedState struct {
|
|||||||
func (s *execCreatedState) transition(name string) error {
|
func (s *execCreatedState) transition(name string) error {
|
||||||
switch name {
|
switch name {
|
||||||
case "running":
|
case "running":
|
||||||
s.p.State = &execRunningState{p: s.p}
|
s.p.execState = &execRunningState{p: s.p}
|
||||||
case "stopped":
|
case "stopped":
|
||||||
s.p.State = &execStoppedState{p: s.p}
|
s.p.execState = &execStoppedState{p: s.p}
|
||||||
case "deleted":
|
case "deleted":
|
||||||
s.p.State = &deletedState{}
|
s.p.execState = &deletedState{}
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
|
return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
|
||||||
}
|
}
|
||||||
@ -44,15 +52,10 @@ func (s *execCreatedState) transition(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *execCreatedState) Resize(ws console.WinSize) error {
|
func (s *execCreatedState) Resize(ws console.WinSize) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.resize(ws)
|
return s.p.resize(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *execCreatedState) Start(ctx context.Context) error {
|
func (s *execCreatedState) Start(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
if err := s.p.start(ctx); err != nil {
|
if err := s.p.start(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -63,22 +66,15 @@ func (s *execCreatedState) Delete(ctx context.Context) error {
|
|||||||
if err := s.p.delete(ctx); err != nil {
|
if err := s.p.delete(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
return s.transition("deleted")
|
return s.transition("deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *execCreatedState) Kill(ctx context.Context, sig uint32, all bool) error {
|
func (s *execCreatedState) Kill(ctx context.Context, sig uint32, all bool) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.kill(ctx, sig, all)
|
return s.p.kill(ctx, sig, all)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *execCreatedState) SetExited(status int) {
|
func (s *execCreatedState) SetExited(status int) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
s.p.setExited(status)
|
s.p.setExited(status)
|
||||||
|
|
||||||
if err := s.transition("stopped"); err != nil {
|
if err := s.transition("stopped"); err != nil {
|
||||||
@ -93,7 +89,7 @@ type execRunningState struct {
|
|||||||
func (s *execRunningState) transition(name string) error {
|
func (s *execRunningState) transition(name string) error {
|
||||||
switch name {
|
switch name {
|
||||||
case "stopped":
|
case "stopped":
|
||||||
s.p.State = &execStoppedState{p: s.p}
|
s.p.execState = &execStoppedState{p: s.p}
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
|
return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
|
||||||
}
|
}
|
||||||
@ -101,37 +97,22 @@ func (s *execRunningState) transition(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *execRunningState) Resize(ws console.WinSize) error {
|
func (s *execRunningState) Resize(ws console.WinSize) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.resize(ws)
|
return s.p.resize(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *execRunningState) Start(ctx context.Context) error {
|
func (s *execRunningState) Start(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot start a running process")
|
return errors.Errorf("cannot start a running process")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *execRunningState) Delete(ctx context.Context) error {
|
func (s *execRunningState) Delete(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot delete a running process")
|
return errors.Errorf("cannot delete a running process")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *execRunningState) Kill(ctx context.Context, sig uint32, all bool) error {
|
func (s *execRunningState) Kill(ctx context.Context, sig uint32, all bool) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.kill(ctx, sig, all)
|
return s.p.kill(ctx, sig, all)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *execRunningState) SetExited(status int) {
|
func (s *execRunningState) SetExited(status int) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
s.p.setExited(status)
|
s.p.setExited(status)
|
||||||
|
|
||||||
if err := s.transition("stopped"); err != nil {
|
if err := s.transition("stopped"); err != nil {
|
||||||
@ -146,7 +127,7 @@ type execStoppedState struct {
|
|||||||
func (s *execStoppedState) transition(name string) error {
|
func (s *execStoppedState) transition(name string) error {
|
||||||
switch name {
|
switch name {
|
||||||
case "deleted":
|
case "deleted":
|
||||||
s.p.State = &deletedState{}
|
s.p.execState = &deletedState{}
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
|
return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
|
||||||
}
|
}
|
||||||
@ -154,16 +135,10 @@ func (s *execStoppedState) transition(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *execStoppedState) Resize(ws console.WinSize) error {
|
func (s *execStoppedState) Resize(ws console.WinSize) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot resize a stopped container")
|
return errors.Errorf("cannot resize a stopped container")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *execStoppedState) Start(ctx context.Context) error {
|
func (s *execStoppedState) Start(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot start a stopped process")
|
return errors.Errorf("cannot start a stopped process")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,15 +146,11 @@ func (s *execStoppedState) Delete(ctx context.Context) error {
|
|||||||
if err := s.p.delete(ctx); err != nil {
|
if err := s.p.delete(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
return s.transition("deleted")
|
return s.transition("deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error {
|
func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.kill(ctx, sig, all)
|
return s.p.kill(ctx, sig, all)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@ const InitPidFile = "init.pid"
|
|||||||
|
|
||||||
// Init represents an initial process for a container
|
// Init represents an initial process for a container
|
||||||
type Init struct {
|
type Init struct {
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
initState
|
initState initState
|
||||||
|
|
||||||
// mu is used to ensure that `Start()` and `Exited()` calls return in
|
// mu is used to ensure that `Start()` and `Exited()` calls return in
|
||||||
// the right order when invoked in separate go routines.
|
// the right order when invoked in separate go routines.
|
||||||
@ -212,6 +212,7 @@ func (p *Init) Pid() int {
|
|||||||
func (p *Init) ExitStatus() int {
|
func (p *Init) ExitStatus() int {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
return p.status
|
return p.status
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +220,7 @@ func (p *Init) ExitStatus() int {
|
|||||||
func (p *Init) ExitedAt() time.Time {
|
func (p *Init) ExitedAt() time.Time {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
return p.exited
|
return p.exited
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +228,7 @@ func (p *Init) ExitedAt() time.Time {
|
|||||||
func (p *Init) Status(ctx context.Context) (string, error) {
|
func (p *Init) Status(ctx context.Context) (string, error) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
c, err := p.runtime.State(ctx, p.id)
|
c, err := p.runtime.State(ctx, p.id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "does not exist") {
|
if strings.Contains(err.Error(), "does not exist") {
|
||||||
@ -236,11 +239,27 @@ func (p *Init) Status(ctx context.Context) (string, error) {
|
|||||||
return c.Status, nil
|
return c.Status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Init) start(context context.Context) error {
|
// Start the init process
|
||||||
err := p.runtime.Start(context, p.id)
|
func (p *Init) Start(ctx context.Context) error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
return p.initState.Start(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Init) start(ctx context.Context) error {
|
||||||
|
err := p.runtime.Start(ctx, p.id)
|
||||||
return p.runtimeError(err, "OCI runtime start failed")
|
return p.runtimeError(err, "OCI runtime start failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetExited of the init process with the next status
|
||||||
|
func (p *Init) SetExited(status int) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
p.initState.SetExited(status)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Init) setExited(status int) {
|
func (p *Init) setExited(status int) {
|
||||||
p.exited = time.Now()
|
p.exited = time.Now()
|
||||||
p.status = status
|
p.status = status
|
||||||
@ -248,9 +267,17 @@ func (p *Init) setExited(status int) {
|
|||||||
close(p.waitBlock)
|
close(p.waitBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Init) delete(context context.Context) error {
|
// Delete the init process
|
||||||
|
func (p *Init) Delete(ctx context.Context) error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
return p.initState.Delete(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Init) delete(ctx context.Context) error {
|
||||||
p.wg.Wait()
|
p.wg.Wait()
|
||||||
err := p.runtime.Delete(context, p.id, nil)
|
err := p.runtime.Delete(ctx, p.id, nil)
|
||||||
// ignore errors if a runtime has already deleted the process
|
// ignore errors if a runtime has already deleted the process
|
||||||
// but we still hold metadata and pipes
|
// but we still hold metadata and pipes
|
||||||
//
|
//
|
||||||
@ -270,7 +297,7 @@ func (p *Init) delete(context context.Context) error {
|
|||||||
p.io.Close()
|
p.io.Close()
|
||||||
}
|
}
|
||||||
if err2 := mount.UnmountAll(p.Rootfs, 0); err2 != nil {
|
if err2 := mount.UnmountAll(p.Rootfs, 0); err2 != nil {
|
||||||
log.G(context).WithError(err2).Warn("failed to cleanup rootfs mount")
|
log.G(ctx).WithError(err2).Warn("failed to cleanup rootfs mount")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = errors.Wrap(err2, "failed rootfs umount")
|
err = errors.Wrap(err2, "failed rootfs umount")
|
||||||
}
|
}
|
||||||
@ -278,6 +305,17 @@ func (p *Init) delete(context context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resize the init processes console
|
||||||
|
func (p *Init) Resize(ws console.WinSize) error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
if p.console == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.console.Resize(ws)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Init) resize(ws console.WinSize) error {
|
func (p *Init) resize(ws console.WinSize) error {
|
||||||
if p.console == nil {
|
if p.console == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -285,26 +323,40 @@ func (p *Init) resize(ws console.WinSize) error {
|
|||||||
return p.console.Resize(ws)
|
return p.console.Resize(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Init) pause(context context.Context) error {
|
// Pause the init process and all its child processes
|
||||||
err := p.runtime.Pause(context, p.id)
|
func (p *Init) Pause(ctx context.Context) error {
|
||||||
return p.runtimeError(err, "OCI runtime pause failed")
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
return p.initState.Pause(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Init) resume(context context.Context) error {
|
// Resume the init process and all its child processes
|
||||||
err := p.runtime.Resume(context, p.id)
|
func (p *Init) Resume(ctx context.Context) error {
|
||||||
return p.runtimeError(err, "OCI runtime resume failed")
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
return p.initState.Resume(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Init) kill(context context.Context, signal uint32, all bool) error {
|
// Kill the init process
|
||||||
err := p.runtime.Kill(context, p.id, int(signal), &runc.KillOpts{
|
func (p *Init) Kill(ctx context.Context, signal uint32, all bool) error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
return p.initState.Kill(ctx, signal, all)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Init) kill(ctx context.Context, signal uint32, all bool) error {
|
||||||
|
err := p.runtime.Kill(ctx, p.id, int(signal), &runc.KillOpts{
|
||||||
All: all,
|
All: all,
|
||||||
})
|
})
|
||||||
return checkKillError(err)
|
return checkKillError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KillAll processes belonging to the init process
|
// KillAll processes belonging to the init process
|
||||||
func (p *Init) KillAll(context context.Context) error {
|
func (p *Init) KillAll(ctx context.Context) error {
|
||||||
err := p.runtime.Kill(context, p.id, int(syscall.SIGKILL), &runc.KillOpts{
|
err := p.runtime.Kill(ctx, p.id, int(syscall.SIGKILL), &runc.KillOpts{
|
||||||
All: true,
|
All: true,
|
||||||
})
|
})
|
||||||
return p.runtimeError(err, "OCI runtime killall failed")
|
return p.runtimeError(err, "OCI runtime killall failed")
|
||||||
@ -320,8 +372,16 @@ func (p *Init) Runtime() *runc.Runc {
|
|||||||
return p.runtime
|
return p.runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exec returns a new child process
|
||||||
|
func (p *Init) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
return p.initState.Exec(ctx, path, r)
|
||||||
|
}
|
||||||
|
|
||||||
// exec returns a new exec'd process
|
// exec returns a new exec'd process
|
||||||
func (p *Init) exec(context context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
||||||
// process exec request
|
// process exec request
|
||||||
var spec specs.Process
|
var spec specs.Process
|
||||||
if err := json.Unmarshal(r.Spec.Value, &spec); err != nil {
|
if err := json.Unmarshal(r.Spec.Value, &spec); err != nil {
|
||||||
@ -342,18 +402,26 @@ func (p *Init) exec(context context.Context, path string, r *ExecConfig) (proc.P
|
|||||||
},
|
},
|
||||||
waitBlock: make(chan struct{}),
|
waitBlock: make(chan struct{}),
|
||||||
}
|
}
|
||||||
e.State = &execCreatedState{p: e}
|
e.execState = &execCreatedState{p: e}
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Init) checkpoint(context context.Context, r *CheckpointConfig) error {
|
// Checkpoint the init process
|
||||||
|
func (p *Init) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
return p.initState.Checkpoint(ctx, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Init) checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
||||||
var actions []runc.CheckpointAction
|
var actions []runc.CheckpointAction
|
||||||
if !r.Exit {
|
if !r.Exit {
|
||||||
actions = append(actions, runc.LeaveRunning)
|
actions = append(actions, runc.LeaveRunning)
|
||||||
}
|
}
|
||||||
work := filepath.Join(p.WorkDir, "criu-work")
|
work := filepath.Join(p.WorkDir, "criu-work")
|
||||||
defer os.RemoveAll(work)
|
defer os.RemoveAll(work)
|
||||||
if err := p.runtime.Checkpoint(context, p.id, &runc.CheckpointOpts{
|
if err := p.runtime.Checkpoint(ctx, p.id, &runc.CheckpointOpts{
|
||||||
WorkDir: work,
|
WorkDir: work,
|
||||||
ImagePath: r.Path,
|
ImagePath: r.Path,
|
||||||
AllowOpenTCP: r.AllowOpenTCP,
|
AllowOpenTCP: r.AllowOpenTCP,
|
||||||
@ -364,19 +432,27 @@ func (p *Init) checkpoint(context context.Context, r *CheckpointConfig) error {
|
|||||||
}, actions...); err != nil {
|
}, actions...); err != nil {
|
||||||
dumpLog := filepath.Join(p.Bundle, "criu-dump.log")
|
dumpLog := filepath.Join(p.Bundle, "criu-dump.log")
|
||||||
if cerr := copyFile(dumpLog, filepath.Join(work, "dump.log")); cerr != nil {
|
if cerr := copyFile(dumpLog, filepath.Join(work, "dump.log")); cerr != nil {
|
||||||
log.G(context).Error(err)
|
log.G(ctx).Error(err)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("%s path= %s", criuError(err), dumpLog)
|
return fmt.Errorf("%s path= %s", criuError(err), dumpLog)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Init) update(context context.Context, r *google_protobuf.Any) error {
|
// Update the processes resource configuration
|
||||||
|
func (p *Init) Update(ctx context.Context, r *google_protobuf.Any) error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
return p.initState.Update(ctx, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Init) update(ctx context.Context, r *google_protobuf.Any) error {
|
||||||
var resources specs.LinuxResources
|
var resources specs.LinuxResources
|
||||||
if err := json.Unmarshal(r.Value, &resources); err != nil {
|
if err := json.Unmarshal(r.Value, &resources); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return p.runtime.Update(context, p.id, &resources)
|
return p.runtime.Update(ctx, p.id, &resources)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stdio of the process
|
// Stdio of the process
|
||||||
|
@ -30,16 +30,20 @@ import (
|
|||||||
runc "github.com/containerd/go-runc"
|
runc "github.com/containerd/go-runc"
|
||||||
google_protobuf "github.com/gogo/protobuf/types"
|
google_protobuf "github.com/gogo/protobuf/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type initState interface {
|
type initState interface {
|
||||||
proc.State
|
Resize(console.WinSize) error
|
||||||
|
Start(context.Context) error
|
||||||
|
Delete(context.Context) error
|
||||||
Pause(context.Context) error
|
Pause(context.Context) error
|
||||||
Resume(context.Context) error
|
Resume(context.Context) error
|
||||||
Update(context.Context, *google_protobuf.Any) error
|
Update(context.Context, *google_protobuf.Any) error
|
||||||
Checkpoint(context.Context, *CheckpointConfig) error
|
Checkpoint(context.Context, *CheckpointConfig) error
|
||||||
Exec(context.Context, string, *ExecConfig) (proc.Process, error)
|
Exec(context.Context, string, *ExecConfig) (proc.Process, error)
|
||||||
|
Kill(context.Context, uint32, bool) error
|
||||||
|
SetExited(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
type createdState struct {
|
type createdState struct {
|
||||||
@ -61,43 +65,26 @@ func (s *createdState) transition(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) Pause(ctx context.Context) error {
|
func (s *createdState) Pause(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot pause task in created state")
|
return errors.Errorf("cannot pause task in created state")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) Resume(ctx context.Context) error {
|
func (s *createdState) Resume(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot resume task in created state")
|
return errors.Errorf("cannot resume task in created state")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) Update(context context.Context, r *google_protobuf.Any) error {
|
func (s *createdState) Update(ctx context.Context, r *google_protobuf.Any) error {
|
||||||
s.p.mu.Lock()
|
return s.p.update(ctx, r)
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.update(context, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) Checkpoint(context context.Context, r *CheckpointConfig) error {
|
func (s *createdState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot checkpoint a task in created state")
|
return errors.Errorf("cannot checkpoint a task in created state")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) Resize(ws console.WinSize) error {
|
func (s *createdState) Resize(ws console.WinSize) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.resize(ws)
|
return s.p.resize(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) Start(ctx context.Context) error {
|
func (s *createdState) Start(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
if err := s.p.start(ctx); err != nil {
|
if err := s.p.start(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -105,8 +92,6 @@ func (s *createdState) Start(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) Delete(ctx context.Context) error {
|
func (s *createdState) Delete(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
if err := s.p.delete(ctx); err != nil {
|
if err := s.p.delete(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -114,16 +99,10 @@ func (s *createdState) Delete(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) Kill(ctx context.Context, sig uint32, all bool) error {
|
func (s *createdState) Kill(ctx context.Context, sig uint32, all bool) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.kill(ctx, sig, all)
|
return s.p.kill(ctx, sig, all)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) SetExited(status int) {
|
func (s *createdState) SetExited(status int) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
s.p.setExited(status)
|
s.p.setExited(status)
|
||||||
|
|
||||||
if err := s.transition("stopped"); err != nil {
|
if err := s.transition("stopped"); err != nil {
|
||||||
@ -132,8 +111,6 @@ func (s *createdState) SetExited(status int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
return s.p.exec(ctx, path, r)
|
return s.p.exec(ctx, path, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,43 +134,26 @@ func (s *createdCheckpointState) transition(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) Pause(ctx context.Context) error {
|
func (s *createdCheckpointState) Pause(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot pause task in created state")
|
return errors.Errorf("cannot pause task in created state")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) Resume(ctx context.Context) error {
|
func (s *createdCheckpointState) Resume(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot resume task in created state")
|
return errors.Errorf("cannot resume task in created state")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) Update(context context.Context, r *google_protobuf.Any) error {
|
func (s *createdCheckpointState) Update(ctx context.Context, r *google_protobuf.Any) error {
|
||||||
s.p.mu.Lock()
|
return s.p.update(ctx, r)
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.update(context, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) Checkpoint(context context.Context, r *CheckpointConfig) error {
|
func (s *createdCheckpointState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot checkpoint a task in created state")
|
return errors.Errorf("cannot checkpoint a task in created state")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) Resize(ws console.WinSize) error {
|
func (s *createdCheckpointState) Resize(ws console.WinSize) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.resize(ws)
|
return s.p.resize(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) Start(ctx context.Context) error {
|
func (s *createdCheckpointState) Start(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
p := s.p
|
p := s.p
|
||||||
sio := p.stdio
|
sio := p.stdio
|
||||||
|
|
||||||
@ -247,8 +207,6 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) Delete(ctx context.Context) error {
|
func (s *createdCheckpointState) Delete(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
if err := s.p.delete(ctx); err != nil {
|
if err := s.p.delete(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -256,16 +214,10 @@ func (s *createdCheckpointState) Delete(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) Kill(ctx context.Context, sig uint32, all bool) error {
|
func (s *createdCheckpointState) Kill(ctx context.Context, sig uint32, all bool) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.kill(ctx, sig, all)
|
return s.p.kill(ctx, sig, all)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) SetExited(status int) {
|
func (s *createdCheckpointState) SetExited(status int) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
s.p.setExited(status)
|
s.p.setExited(status)
|
||||||
|
|
||||||
if err := s.transition("stopped"); err != nil {
|
if err := s.transition("stopped"); err != nil {
|
||||||
@ -274,9 +226,6 @@ func (s *createdCheckpointState) SetExited(status int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *createdCheckpointState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
func (s *createdCheckpointState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return nil, errors.Errorf("cannot exec in a created state")
|
return nil, errors.Errorf("cannot exec in a created state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,67 +246,42 @@ func (s *runningState) transition(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) Pause(ctx context.Context) error {
|
func (s *runningState) Pause(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
if err := s.p.runtime.Pause(ctx, s.p.id); err != nil {
|
||||||
defer s.p.mu.Unlock()
|
return s.p.runtimeError(err, "OCI runtime pause failed")
|
||||||
if err := s.p.pause(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.transition("paused")
|
return s.transition("paused")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) Resume(ctx context.Context) error {
|
func (s *runningState) Resume(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot resume a running process")
|
return errors.Errorf("cannot resume a running process")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) Update(context context.Context, r *google_protobuf.Any) error {
|
func (s *runningState) Update(ctx context.Context, r *google_protobuf.Any) error {
|
||||||
s.p.mu.Lock()
|
return s.p.update(ctx, r)
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.update(context, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
func (s *runningState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.checkpoint(ctx, r)
|
return s.p.checkpoint(ctx, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) Resize(ws console.WinSize) error {
|
func (s *runningState) Resize(ws console.WinSize) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.resize(ws)
|
return s.p.resize(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) Start(ctx context.Context) error {
|
func (s *runningState) Start(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot start a running process")
|
return errors.Errorf("cannot start a running process")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) Delete(ctx context.Context) error {
|
func (s *runningState) Delete(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot delete a running process")
|
return errors.Errorf("cannot delete a running process")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) Kill(ctx context.Context, sig uint32, all bool) error {
|
func (s *runningState) Kill(ctx context.Context, sig uint32, all bool) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.kill(ctx, sig, all)
|
return s.p.kill(ctx, sig, all)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) SetExited(status int) {
|
func (s *runningState) SetExited(status int) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
s.p.setExited(status)
|
s.p.setExited(status)
|
||||||
|
|
||||||
if err := s.transition("stopped"); err != nil {
|
if err := s.transition("stopped"); err != nil {
|
||||||
@ -366,8 +290,6 @@ func (s *runningState) SetExited(status int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *runningState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
func (s *runningState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
return s.p.exec(ctx, path, r)
|
return s.p.exec(ctx, path, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,79 +310,54 @@ func (s *pausedState) transition(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) Pause(ctx context.Context) error {
|
func (s *pausedState) Pause(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot pause a paused container")
|
return errors.Errorf("cannot pause a paused container")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) Resume(ctx context.Context) error {
|
func (s *pausedState) Resume(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
if err := s.p.runtime.Resume(ctx, s.p.id); err != nil {
|
||||||
defer s.p.mu.Unlock()
|
return s.p.runtimeError(err, "OCI runtime resume failed")
|
||||||
|
|
||||||
if err := s.p.resume(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.transition("running")
|
return s.transition("running")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) Update(context context.Context, r *google_protobuf.Any) error {
|
func (s *pausedState) Update(ctx context.Context, r *google_protobuf.Any) error {
|
||||||
s.p.mu.Lock()
|
return s.p.update(ctx, r)
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.update(context, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
func (s *pausedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.checkpoint(ctx, r)
|
return s.p.checkpoint(ctx, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) Resize(ws console.WinSize) error {
|
func (s *pausedState) Resize(ws console.WinSize) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.resize(ws)
|
return s.p.resize(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) Start(ctx context.Context) error {
|
func (s *pausedState) Start(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot start a paused process")
|
return errors.Errorf("cannot start a paused process")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) Delete(ctx context.Context) error {
|
func (s *pausedState) Delete(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot delete a paused process")
|
return errors.Errorf("cannot delete a paused process")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) Kill(ctx context.Context, sig uint32, all bool) error {
|
func (s *pausedState) Kill(ctx context.Context, sig uint32, all bool) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return s.p.kill(ctx, sig, all)
|
return s.p.kill(ctx, sig, all)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) SetExited(status int) {
|
func (s *pausedState) SetExited(status int) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
s.p.setExited(status)
|
s.p.setExited(status)
|
||||||
|
|
||||||
|
if err := s.p.runtime.Resume(context.Background(), s.p.id); err != nil {
|
||||||
|
logrus.WithError(err).Error("resuming exited container from paused state")
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.transition("stopped"); err != nil {
|
if err := s.transition("stopped"); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pausedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
func (s *pausedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return nil, errors.Errorf("cannot exec in a paused state")
|
return nil, errors.Errorf("cannot exec in a paused state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,50 +376,30 @@ func (s *stoppedState) transition(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *stoppedState) Pause(ctx context.Context) error {
|
func (s *stoppedState) Pause(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot pause a stopped container")
|
return errors.Errorf("cannot pause a stopped container")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stoppedState) Resume(ctx context.Context) error {
|
func (s *stoppedState) Resume(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot resume a stopped container")
|
return errors.Errorf("cannot resume a stopped container")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stoppedState) Update(context context.Context, r *google_protobuf.Any) error {
|
func (s *stoppedState) Update(ctx context.Context, r *google_protobuf.Any) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot update a stopped container")
|
return errors.Errorf("cannot update a stopped container")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stoppedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
func (s *stoppedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot checkpoint a stopped container")
|
return errors.Errorf("cannot checkpoint a stopped container")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stoppedState) Resize(ws console.WinSize) error {
|
func (s *stoppedState) Resize(ws console.WinSize) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot resize a stopped container")
|
return errors.Errorf("cannot resize a stopped container")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stoppedState) Start(ctx context.Context) error {
|
func (s *stoppedState) Start(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return errors.Errorf("cannot start a stopped process")
|
return errors.Errorf("cannot start a stopped process")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stoppedState) Delete(ctx context.Context) error {
|
func (s *stoppedState) Delete(ctx context.Context) error {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
if err := s.p.delete(ctx); err != nil {
|
if err := s.p.delete(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -538,8 +415,5 @@ func (s *stoppedState) SetExited(status int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *stoppedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
func (s *stoppedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
||||||
s.p.mu.Lock()
|
|
||||||
defer s.p.mu.Unlock()
|
|
||||||
|
|
||||||
return nil, errors.Errorf("cannot exec in a stopped state")
|
return nil, errors.Errorf("cannot exec in a stopped state")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user