From 3eeb6b8c6ece615edaf2279b3fdc91754cdecf39 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Wed, 3 Aug 2016 13:45:46 -0700 Subject: [PATCH 1/2] libcontainerd: wait for restart after state change Signed-off-by: Tonis Tiigi Upstream-commit: 495448b2903c1a765cc17dff05afebe16a466917 Component: engine --- .../engine/libcontainerd/container_linux.go | 35 +++++++++++-------- .../engine/libcontainerd/container_windows.go | 32 +++++++++-------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/components/engine/libcontainerd/container_linux.go b/components/engine/libcontainerd/container_linux.go index d6bfc22364..00129e5851 100644 --- a/components/engine/libcontainerd/container_linux.go +++ b/components/engine/libcontainerd/container_linux.go @@ -144,6 +144,7 @@ func (ctr *container) handleEvent(e *containerd.Event) error { defer ctr.client.unlock(ctr.containerID) switch e.Type { case StateExit, StatePause, StateResume, StateOOM: + var waitRestart chan error st := StateInfo{ CommonStateInfo: CommonStateInfo{ State: e.Type, @@ -166,8 +167,26 @@ func (ctr *container) handleEvent(e *containerd.Event) error { st.State = StateRestart ctr.restarting = true ctr.client.deleteContainer(e.Id) + waitRestart = wait + } + } + + // Remove process from list if we have exited + // We need to do so here in case the Message Handler decides to restart it. + switch st.State { + case StateExit: + ctr.clean() + ctr.client.deleteContainer(e.Id) + case StateExitProcess: + ctr.cleanProcess(st.ProcessID) + } + ctr.client.q.append(e.Id, func() { + if err := ctr.client.backend.StateChanged(e.Id, st); err != nil { + logrus.Errorf("libcontainerd: backend.StateChanged(): %v", err) + } + if st.State == StateRestart { go func() { - err := <-wait + err := <-waitRestart ctr.client.lock(ctr.containerID) defer ctr.client.unlock(ctr.containerID) ctr.restarting = false @@ -187,21 +206,7 @@ func (ctr *container) handleEvent(e *containerd.Event) error { } }() } - } - // Remove process from list if we have exited - // We need to do so here in case the Message Handler decides to restart it. - switch st.State { - case StateExit: - ctr.clean() - ctr.client.deleteContainer(e.Id) - case StateExitProcess: - ctr.cleanProcess(st.ProcessID) - } - ctr.client.q.append(e.Id, func() { - if err := ctr.client.backend.StateChanged(e.Id, st); err != nil { - logrus.Errorf("libcontainerd: backend.StateChanged(): %v", err) - } if e.Type == StatePause || e.Type == StateResume { ctr.pauseMonitor.handle(e.Type) } diff --git a/components/engine/libcontainerd/container_windows.go b/components/engine/libcontainerd/container_windows.go index 8e5328941f..4cd18c784b 100644 --- a/components/engine/libcontainerd/container_windows.go +++ b/components/engine/libcontainerd/container_windows.go @@ -195,6 +195,7 @@ func (ctr *container) waitProcessExitCode(process *process) int { // equivalent to (in the linux containerd world) where events come in for // state change notifications from containerd. func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) error { + var waitRestart chan error logrus.Debugln("libcontainerd: waitExit() on pid", process.systemPid) exitCode := ctr.waitProcessExitCode(process) @@ -238,20 +239,7 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err } else if restart { si.State = StateRestart ctr.restarting = true - go func() { - err := <-wait - ctr.restarting = false - ctr.client.deleteContainer(ctr.friendlyName) - if err != nil { - si.State = StateExit - if err := ctr.client.backend.StateChanged(ctr.containerID, si); err != nil { - logrus.Error(err) - } - logrus.Error(err) - } else { - ctr.client.Create(ctr.containerID, ctr.ociSpec, ctr.options...) - } - }() + waitRestart = wait } } @@ -267,6 +255,22 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err if err := ctr.client.backend.StateChanged(ctr.containerID, si); err != nil { logrus.Error(err) } + if si.State == StateRestart { + go func() { + err := <-waitRestart + ctr.restarting = false + ctr.client.deleteContainer(ctr.friendlyName) + if err != nil { + si.State = StateExit + if err := ctr.client.backend.StateChanged(ctr.containerID, si); err != nil { + logrus.Error(err) + } + logrus.Error(err) + } else { + ctr.client.Create(ctr.containerID, ctr.ociSpec, ctr.options...) + } + }() + } logrus.Debugf("libcontainerd: waitExit() completed OK, %+v", si) return nil From c1636749f7c0f3b81652746524dadf30027c6356 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Wed, 3 Aug 2016 15:28:52 -0700 Subject: [PATCH 2/2] libcontainerd: mark container exited after failed restart Signed-off-by: Tonis Tiigi Upstream-commit: 9be0fb45c25e4d8d3cf0aa444da5ae41dd18f435 Component: engine --- components/engine/libcontainerd/container_linux.go | 7 +++++-- components/engine/libcontainerd/container_windows.go | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/components/engine/libcontainerd/container_linux.go b/components/engine/libcontainerd/container_linux.go index 00129e5851..454478b5c2 100644 --- a/components/engine/libcontainerd/container_linux.go +++ b/components/engine/libcontainerd/container_linux.go @@ -190,6 +190,11 @@ func (ctr *container) handleEvent(e *containerd.Event) error { ctr.client.lock(ctr.containerID) defer ctr.client.unlock(ctr.containerID) ctr.restarting = false + if err == nil { + if err = ctr.start(); err != nil { + logrus.Errorf("libcontainerd: error restarting %v", err) + } + } if err != nil { st.State = StateExit ctr.clean() @@ -201,8 +206,6 @@ func (ctr *container) handleEvent(e *containerd.Event) error { if err != restartmanager.ErrRestartCanceled { logrus.Errorf("libcontainerd: %v", err) } - } else { - ctr.start() } }() } diff --git a/components/engine/libcontainerd/container_windows.go b/components/engine/libcontainerd/container_windows.go index 4cd18c784b..cc47934b3d 100644 --- a/components/engine/libcontainerd/container_windows.go +++ b/components/engine/libcontainerd/container_windows.go @@ -260,14 +260,16 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err err := <-waitRestart ctr.restarting = false ctr.client.deleteContainer(ctr.friendlyName) + if err == nil { + if err = ctr.client.Create(ctr.containerID, ctr.ociSpec, ctr.options...); err != nil { + logrus.Errorf("libcontainerd: error restarting %v", err) + } + } if err != nil { si.State = StateExit if err := ctr.client.backend.StateChanged(ctr.containerID, si); err != nil { logrus.Error(err) } - logrus.Error(err) - } else { - ctr.client.Create(ctr.containerID, ctr.ociSpec, ctr.options...) } }() }