Beispiel #1
0
// AddProcess is the handler for adding a process to an already running
// container. It's called through docker exec.
func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAdd Process) error {

	clnt.lock(containerID)
	defer clnt.unlock(containerID)
	container, err := clnt.getContainer(containerID)
	if err != nil {
		return err
	}

	createProcessParms := hcsshim.CreateProcessParams{
		EmulateConsole: procToAdd.Terminal,
		ConsoleSize:    procToAdd.InitialConsoleSize,
	}

	// Take working directory from the process to add if it is defined,
	// otherwise take from the first process.
	if procToAdd.Cwd != "" {
		createProcessParms.WorkingDirectory = procToAdd.Cwd
	} else {
		createProcessParms.WorkingDirectory = container.ociSpec.Process.Cwd
	}

	// Configure the environment for the process
	createProcessParms.Environment = setupEnvironmentVariables(procToAdd.Env)
	createProcessParms.CommandLine = strings.Join(procToAdd.Args, " ")

	logrus.Debugf("commandLine: %s", createProcessParms.CommandLine)

	// Start the command running in the container. Note we always tell HCS to
	// create stdout as it's required regardless of '-i' or '-t' options, so that
	// docker can always grab the output through logs. We also tell HCS to always
	// create stdin, even if it's not used - it will be closed shortly. Stderr
	// is only created if it we're not -t.
	var stdout, stderr io.ReadCloser
	var pid uint32
	iopipe := &IOPipe{Terminal: procToAdd.Terminal}
	pid, iopipe.Stdin, stdout, stderr, err = hcsshim.CreateProcessInComputeSystem(
		containerID,
		true,
		true,
		!procToAdd.Terminal,
		createProcessParms)
	if err != nil {
		logrus.Errorf("AddProcess %s CreateProcessInComputeSystem() failed %s", containerID, err)
		return err
	}

	// Convert io.ReadClosers to io.Readers
	if stdout != nil {
		iopipe.Stdout = openReaderFromPipe(stdout)
	}
	if stderr != nil {
		iopipe.Stderr = openReaderFromPipe(stderr)
	}

	// Add the process to the containers list of processes
	container.processes[processFriendlyName] =
		&process{
			processCommon: processCommon{
				containerID:  containerID,
				friendlyName: processFriendlyName,
				client:       clnt,
				systemPid:    pid,
			},
			commandLine: createProcessParms.CommandLine,
		}

	// Make sure the lock is not held while calling back into the daemon
	clnt.unlock(containerID)

	// Tell the engine to attach streams back to the client
	if err := clnt.backend.AttachStreams(processFriendlyName, *iopipe); err != nil {
		return err
	}

	// Lock again so that the defer unlock doesn't fail. (I really don't like this code)
	clnt.lock(containerID)

	// Spin up a go routine waiting for exit to handle cleanup
	go container.waitExit(pid, processFriendlyName, false)

	return nil
}