Browse code

Decouple daemon and container to execute processes.

Signed-off-by: David Calavera <david.calavera@gmail.com>

David Calavera authored on 2015/11/03 10:49:36
Showing 2 changed files
... ...
@@ -420,70 +420,6 @@ func (container *Container) getExecIDs() []string {
420 420
 	return container.execCommands.List()
421 421
 }
422 422
 
423
-func (container *Container) exec(ec *ExecConfig) error {
424
-	container.Lock()
425
-	defer container.Unlock()
426
-
427
-	callback := func(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
428
-		if processConfig.Tty {
429
-			// The callback is called after the process Start()
430
-			// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlave
431
-			// which we close here.
432
-			if c, ok := processConfig.Stdout.(io.Closer); ok {
433
-				c.Close()
434
-			}
435
-		}
436
-		close(ec.waitStart)
437
-		return nil
438
-	}
439
-
440
-	// We use a callback here instead of a goroutine and an chan for
441
-	// synchronization purposes
442
-	cErr := promise.Go(func() error { return container.monitorExec(ec, callback) })
443
-
444
-	// Exec should not return until the process is actually running
445
-	select {
446
-	case <-ec.waitStart:
447
-	case err := <-cErr:
448
-		return err
449
-	}
450
-
451
-	return nil
452
-}
453
-
454
-func (container *Container) monitorExec(ExecConfig *ExecConfig, callback execdriver.DriverCallback) error {
455
-	var (
456
-		err      error
457
-		exitCode int
458
-	)
459
-	pipes := execdriver.NewPipes(ExecConfig.streamConfig.stdin, ExecConfig.streamConfig.stdout, ExecConfig.streamConfig.stderr, ExecConfig.OpenStdin)
460
-	exitCode, err = container.daemon.Exec(container, ExecConfig, pipes, callback)
461
-	if err != nil {
462
-		logrus.Errorf("Error running command in existing container %s: %s", container.ID, err)
463
-	}
464
-	logrus.Debugf("Exec task in container %s exited with code %d", container.ID, exitCode)
465
-	if ExecConfig.OpenStdin {
466
-		if err := ExecConfig.streamConfig.stdin.Close(); err != nil {
467
-			logrus.Errorf("Error closing stdin while running in %s: %s", container.ID, err)
468
-		}
469
-	}
470
-	if err := ExecConfig.streamConfig.stdout.Clean(); err != nil {
471
-		logrus.Errorf("Error closing stdout while running in %s: %s", container.ID, err)
472
-	}
473
-	if err := ExecConfig.streamConfig.stderr.Clean(); err != nil {
474
-		logrus.Errorf("Error closing stderr while running in %s: %s", container.ID, err)
475
-	}
476
-	if ExecConfig.ProcessConfig.Terminal != nil {
477
-		if err := ExecConfig.ProcessConfig.Terminal.Close(); err != nil {
478
-			logrus.Errorf("Error closing terminal while running in container %s: %s", container.ID, err)
479
-		}
480
-	}
481
-	// remove the exec command from the container's store only and not the
482
-	// daemon's store so that the exec command can be inspected.
483
-	container.execCommands.Delete(ExecConfig.ID)
484
-	return err
485
-}
486
-
487 423
 // Attach connects to the container's TTY, delegating to standard
488 424
 // streams or websockets depending on the configuration.
489 425
 func (container *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error {
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/docker/docker/pkg/broadcaster"
14 14
 	"github.com/docker/docker/pkg/ioutils"
15 15
 	"github.com/docker/docker/pkg/pools"
16
+	"github.com/docker/docker/pkg/promise"
16 17
 	"github.com/docker/docker/pkg/stringid"
17 18
 	"github.com/docker/docker/pkg/stringutils"
18 19
 	"github.com/docker/docker/runconfig"
... ...
@@ -251,7 +252,7 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
251 251
 	// the exitStatus) even after the cmd is done running.
252 252
 
253 253
 	go func() {
254
-		execErr <- container.exec(ec)
254
+		execErr <- d.containerExec(container, ec)
255 255
 	}()
256 256
 
257 257
 	select {
... ...
@@ -329,3 +330,67 @@ func (d *Daemon) containerExecIds() map[string]struct{} {
329 329
 	}
330 330
 	return ids
331 331
 }
332
+
333
+func (daemon *Daemon) containerExec(container *Container, ec *ExecConfig) error {
334
+	container.Lock()
335
+	defer container.Unlock()
336
+
337
+	callback := func(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
338
+		if processConfig.Tty {
339
+			// The callback is called after the process Start()
340
+			// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlave
341
+			// which we close here.
342
+			if c, ok := processConfig.Stdout.(io.Closer); ok {
343
+				c.Close()
344
+			}
345
+		}
346
+		close(ec.waitStart)
347
+		return nil
348
+	}
349
+
350
+	// We use a callback here instead of a goroutine and an chan for
351
+	// synchronization purposes
352
+	cErr := promise.Go(func() error { return daemon.monitorExec(container, ec, callback) })
353
+
354
+	// Exec should not return until the process is actually running
355
+	select {
356
+	case <-ec.waitStart:
357
+	case err := <-cErr:
358
+		return err
359
+	}
360
+
361
+	return nil
362
+}
363
+
364
+func (daemon *Daemon) monitorExec(container *Container, ExecConfig *ExecConfig, callback execdriver.DriverCallback) error {
365
+	var (
366
+		err      error
367
+		exitCode int
368
+	)
369
+	pipes := execdriver.NewPipes(ExecConfig.streamConfig.stdin, ExecConfig.streamConfig.stdout, ExecConfig.streamConfig.stderr, ExecConfig.OpenStdin)
370
+	exitCode, err = daemon.Exec(container, ExecConfig, pipes, callback)
371
+	if err != nil {
372
+		logrus.Errorf("Error running command in existing container %s: %s", container.ID, err)
373
+	}
374
+	logrus.Debugf("Exec task in container %s exited with code %d", container.ID, exitCode)
375
+	if ExecConfig.OpenStdin {
376
+		if err := ExecConfig.streamConfig.stdin.Close(); err != nil {
377
+			logrus.Errorf("Error closing stdin while running in %s: %s", container.ID, err)
378
+		}
379
+	}
380
+	if err := ExecConfig.streamConfig.stdout.Clean(); err != nil {
381
+		logrus.Errorf("Error closing stdout while running in %s: %s", container.ID, err)
382
+	}
383
+	if err := ExecConfig.streamConfig.stderr.Clean(); err != nil {
384
+		logrus.Errorf("Error closing stderr while running in %s: %s", container.ID, err)
385
+	}
386
+	if ExecConfig.ProcessConfig.Terminal != nil {
387
+		if err := ExecConfig.ProcessConfig.Terminal.Close(); err != nil {
388
+			logrus.Errorf("Error closing terminal while running in container %s: %s", container.ID, err)
389
+		}
390
+	}
391
+	// remove the exec command from the container's store only and not the
392
+	// daemon's store so that the exec command can be inspected.
393
+	container.execCommands.Delete(ExecConfig.ID)
394
+	return err
395
+}