Signed-off-by: David Calavera <david.calavera@gmail.com>
| ... | ... |
@@ -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 |
+} |