From 75ac8ebb76508a22d1dc61dae0913a621f7bd172 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 See merge request docker/docker!25383 Signed-off-by: xiekeyang --- libcontainerd/container_linux.go | 41 +++++++++++++++++------------- libcontainerd/container_windows.go | 32 +++++++++++++---------- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/libcontainerd/container_linux.go b/libcontainerd/container_linux.go index 9298218401e81..3a1ccd117bd03 100644 --- a/libcontainerd/container_linux.go +++ b/libcontainerd/container_linux.go @@ -122,6 +122,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, @@ -144,8 +145,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 @@ -154,32 +173,18 @@ func (ctr *container) handleEvent(e *containerd.Event) error { ctr.clean() ctr.client.q.append(e.Id, func() { if err := ctr.client.backend.StateChanged(e.Id, st); err != nil { - logrus.Error(err) + logrus.Errorf("libcontainerd: %v", err) } }) if err != restartmanager.ErrRestartCanceled { - logrus.Error(err) + logrus.Errorf("libcontainerd: %v", err) } } else { ctr.start() } }() } - } - // 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.Error(err) - } if e.Type == StatePause || e.Type == StateResume { ctr.pauseMonitor.handle(e.Type) } @@ -191,7 +196,7 @@ func (ctr *container) handleEvent(e *containerd.Event) error { }) default: - logrus.Debugf("event unhandled: %+v", e) + logrus.Debugf("libcontainerd: event unhandled: %+v", e) } return nil } diff --git a/libcontainerd/container_windows.go b/libcontainerd/container_windows.go index 80adc5f5c671a..bdf3b30a48cd1 100644 --- a/libcontainerd/container_windows.go +++ b/libcontainerd/container_windows.go @@ -117,6 +117,7 @@ func (ctr *container) start() error { // equivalent to (in the linux containerd world) where events come in for // state change notifications from containerd. func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstProcessToStart bool) error { + var waitRestart chan error logrus.Debugln("waitExit on pid", pid) // Block indefinitely for the process to exit. @@ -181,19 +182,7 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr } else if restart { si.State = StateRestart ctr.restarting = true - go func() { - err := <-wait - ctr.restarting = false - 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 } } @@ -209,7 +198,22 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr 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.Debugln("waitExit() completed OK") return nil } From dc020f61988abafd6c00cb1b3eb3bca8e98cbf09 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 See merge request docker/docker!25383 Signed-off-by: xiekeyang --- libcontainerd/container_linux.go | 7 +++++-- libcontainerd/container_windows.go | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libcontainerd/container_linux.go b/libcontainerd/container_linux.go index 3a1ccd117bd03..7315a9ca644cd 100644 --- a/libcontainerd/container_linux.go +++ b/libcontainerd/container_linux.go @@ -168,6 +168,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() @@ -179,8 +184,6 @@ func (ctr *container) handleEvent(e *containerd.Event) error { if err != restartmanager.ErrRestartCanceled { logrus.Errorf("libcontainerd: %v", err) } - } else { - ctr.start() } }() } diff --git a/libcontainerd/container_windows.go b/libcontainerd/container_windows.go index bdf3b30a48cd1..3611523a59653 100644 --- a/libcontainerd/container_windows.go +++ b/libcontainerd/container_windows.go @@ -203,14 +203,16 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr 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...) } }() }