|
@@ -35,6 +35,8 @@ func (ctr *container) newProcess(friendlyName string) *process {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// start starts a created container.
|
|
|
+// Caller needs to lock container ID before calling this method.
|
|
|
func (ctr *container) start() error {
|
|
|
var err error
|
|
|
isServicing := false
|
|
@@ -77,7 +79,7 @@ func (ctr *container) start() error {
|
|
|
createProcessParms.CommandLine = strings.Join(ctr.ociSpec.Process.Args, " ")
|
|
|
|
|
|
// Start the command running in the container.
|
|
|
- hcsProcess, err := ctr.hcsContainer.CreateProcess(createProcessParms)
|
|
|
+ newProcess, err := ctr.hcsContainer.CreateProcess(createProcessParms)
|
|
|
if err != nil {
|
|
|
logrus.Errorf("libcontainerd: CreateProcess() failed %s", err)
|
|
|
if err := ctr.terminate(); err != nil {
|
|
@@ -89,10 +91,21 @@ func (ctr *container) start() error {
|
|
|
}
|
|
|
ctr.startedAt = time.Now()
|
|
|
|
|
|
+ pid := newProcess.Pid()
|
|
|
+ openedProcess, err := ctr.hcsContainer.OpenProcess(pid)
|
|
|
+ if err != nil {
|
|
|
+ logrus.Errorf("OpenProcess() failed %s", err)
|
|
|
+ if err := ctr.terminate(); err != nil {
|
|
|
+ logrus.Errorf("Failed to cleanup after a failed OpenProcess. %s", err)
|
|
|
+ } else {
|
|
|
+ logrus.Debugln("Cleaned up after failed OpenProcess by calling Terminate")
|
|
|
+ }
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
// Save the hcs Process and PID
|
|
|
ctr.process.friendlyName = InitFriendlyName
|
|
|
- pid := hcsProcess.Pid()
|
|
|
- ctr.process.hcsProcess = hcsProcess
|
|
|
+ ctr.process.hcsProcess = openedProcess
|
|
|
|
|
|
// If this is a servicing container, wait on the process synchronously here and
|
|
|
// if it succeeds, wait for it cleanly shutdown and merge into the parent container.
|
|
@@ -109,7 +122,7 @@ func (ctr *container) start() error {
|
|
|
|
|
|
var stdout, stderr io.ReadCloser
|
|
|
var stdin io.WriteCloser
|
|
|
- stdin, stdout, stderr, err = hcsProcess.Stdio()
|
|
|
+ stdin, stdout, stderr, err = newProcess.Stdio()
|
|
|
if err != nil {
|
|
|
logrus.Errorf("libcontainerd: failed to get stdio pipes: %s", err)
|
|
|
if err := ctr.terminate(); err != nil {
|
|
@@ -120,7 +133,7 @@ func (ctr *container) start() error {
|
|
|
|
|
|
iopipe := &IOPipe{Terminal: ctr.ociSpec.Process.Terminal}
|
|
|
|
|
|
- iopipe.Stdin = createStdInCloser(stdin, hcsProcess)
|
|
|
+ iopipe.Stdin = createStdInCloser(stdin, newProcess)
|
|
|
|
|
|
// Convert io.ReadClosers to io.Readers
|
|
|
if stdout != nil {
|
|
@@ -150,6 +163,7 @@ func (ctr *container) start() error {
|
|
|
State: StateStart,
|
|
|
Pid: ctr.systemPid, // Not sure this is needed? Double-check monitor.go in daemon BUGBUG @jhowardmsft
|
|
|
}}
|
|
|
+ logrus.Debugf("libcontainerd: start() completed OK, %+v", si)
|
|
|
return ctr.client.backend.StateChanged(ctr.containerID, si)
|
|
|
|
|
|
}
|
|
@@ -181,10 +195,6 @@ func (ctr *container) waitProcessExitCode(process *process) int {
|
|
|
// has exited to avoid a container being dropped on the floor.
|
|
|
}
|
|
|
|
|
|
- if err := process.hcsProcess.Close(); err != nil {
|
|
|
- logrus.Errorf("libcontainerd: hcsProcess.Close(): %v", err)
|
|
|
- }
|
|
|
-
|
|
|
return exitCode
|
|
|
}
|
|
|
|
|
@@ -196,6 +206,8 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err
|
|
|
logrus.Debugln("libcontainerd: waitExit() on pid", process.systemPid)
|
|
|
|
|
|
exitCode := ctr.waitProcessExitCode(process)
|
|
|
+ // Lock the container while shutting down
|
|
|
+ ctr.client.lock(ctr.containerID)
|
|
|
|
|
|
// Assume the container has exited
|
|
|
si := StateInfo{
|
|
@@ -211,6 +223,7 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err
|
|
|
// But it could have been an exec'd process which exited
|
|
|
if !isFirstProcessToStart {
|
|
|
si.State = StateExitProcess
|
|
|
+ ctr.cleanProcess(process.friendlyName)
|
|
|
} else {
|
|
|
updatePending, err := ctr.hcsContainer.HasPendingUpdates()
|
|
|
if err != nil {
|
|
@@ -236,6 +249,7 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err
|
|
|
} else if restart {
|
|
|
si.State = StateRestart
|
|
|
ctr.restarting = true
|
|
|
+ ctr.client.deleteContainer(ctr.containerID)
|
|
|
waitRestart = wait
|
|
|
}
|
|
|
}
|
|
@@ -243,10 +257,17 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err
|
|
|
// Remove process from list if we have exited
|
|
|
// We need to do so here in case the Message Handler decides to restart it.
|
|
|
if si.State == StateExit {
|
|
|
- ctr.client.deleteContainer(ctr.friendlyName)
|
|
|
+ ctr.client.deleteContainer(ctr.containerID)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if err := process.hcsProcess.Close(); err != nil {
|
|
|
+ logrus.Errorf("libcontainerd: hcsProcess.Close(): %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Unlock here before we call back into the daemon to update state
|
|
|
+ ctr.client.unlock(ctr.containerID)
|
|
|
+
|
|
|
// Call into the backend to notify it of the state change.
|
|
|
logrus.Debugf("libcontainerd: waitExit() calling backend.StateChanged %+v", si)
|
|
|
if err := ctr.client.backend.StateChanged(ctr.containerID, si); err != nil {
|
|
@@ -256,7 +277,6 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err
|
|
|
go func() {
|
|
|
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)
|
|
@@ -275,6 +295,14 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+// cleanProcess removes process from the map.
|
|
|
+// Caller needs to lock container ID before calling this method.
|
|
|
+func (ctr *container) cleanProcess(id string) {
|
|
|
+ delete(ctr.processes, id)
|
|
|
+}
|
|
|
+
|
|
|
+// shutdown shuts down the container in HCS
|
|
|
+// Caller needs to lock container ID before calling this method.
|
|
|
func (ctr *container) shutdown() error {
|
|
|
const shutdownTimeout = time.Minute * 5
|
|
|
err := ctr.hcsContainer.Shutdown()
|
|
@@ -296,6 +324,8 @@ func (ctr *container) shutdown() error {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+// terminate terminates the container in HCS
|
|
|
+// Caller needs to lock container ID before calling this method.
|
|
|
func (ctr *container) terminate() error {
|
|
|
const terminateTimeout = time.Minute * 5
|
|
|
err := ctr.hcsContainer.Terminate()
|