github.com/gondor/docker@v1.9.0-rc1/daemon/container.go (about) 1 package daemon 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "sync" 12 "syscall" 13 "time" 14 15 "github.com/opencontainers/runc/libcontainer/label" 16 17 "github.com/Sirupsen/logrus" 18 "github.com/docker/docker/daemon/execdriver" 19 "github.com/docker/docker/daemon/logger" 20 "github.com/docker/docker/daemon/logger/jsonfilelog" 21 "github.com/docker/docker/daemon/network" 22 derr "github.com/docker/docker/errors" 23 "github.com/docker/docker/image" 24 "github.com/docker/docker/pkg/archive" 25 "github.com/docker/docker/pkg/broadcaster" 26 "github.com/docker/docker/pkg/fileutils" 27 "github.com/docker/docker/pkg/ioutils" 28 "github.com/docker/docker/pkg/mount" 29 "github.com/docker/docker/pkg/nat" 30 "github.com/docker/docker/pkg/promise" 31 "github.com/docker/docker/pkg/signal" 32 "github.com/docker/docker/pkg/symlink" 33 "github.com/docker/docker/runconfig" 34 "github.com/docker/docker/volume" 35 ) 36 37 var ( 38 // ErrRootFSReadOnly is returned when a container 39 // rootfs is marked readonly. 40 ErrRootFSReadOnly = errors.New("container rootfs is marked read-only") 41 ) 42 43 type streamConfig struct { 44 stdout *broadcaster.Unbuffered 45 stderr *broadcaster.Unbuffered 46 stdin io.ReadCloser 47 stdinPipe io.WriteCloser 48 } 49 50 // CommonContainer holds the fields for a container which are 51 // applicable across all platforms supported by the daemon. 52 type CommonContainer struct { 53 streamConfig 54 // embed for Container to support states directly. 55 *State `json:"State"` // Needed for remote api version <= 1.11 56 root string // Path to the "home" of the container, including metadata. 57 basefs string // Path to the graphdriver mountpoint 58 ID string 59 Created time.Time 60 Path string 61 Args []string 62 Config *runconfig.Config 63 ImageID string `json:"Image"` 64 NetworkSettings *network.Settings 65 LogPath string 66 Name string 67 Driver string 68 ExecDriver string 69 // MountLabel contains the options for the 'mount' command 70 MountLabel string 71 ProcessLabel string 72 RestartCount int 73 HasBeenStartedBefore bool 74 HasBeenManuallyStopped bool // used for unless-stopped restart policy 75 hostConfig *runconfig.HostConfig 76 command *execdriver.Command 77 monitor *containerMonitor 78 execCommands *execStore 79 daemon *Daemon 80 // logDriver for closing 81 logDriver logger.Logger 82 logCopier *logger.Copier 83 } 84 85 func (container *Container) fromDisk() error { 86 pth, err := container.jsonPath() 87 if err != nil { 88 return err 89 } 90 91 jsonSource, err := os.Open(pth) 92 if err != nil { 93 return err 94 } 95 defer jsonSource.Close() 96 97 dec := json.NewDecoder(jsonSource) 98 99 // Load container settings 100 if err := dec.Decode(container); err != nil { 101 return err 102 } 103 104 if err := label.ReserveLabel(container.ProcessLabel); err != nil { 105 return err 106 } 107 return container.readHostConfig() 108 } 109 110 func (container *Container) toDisk() error { 111 data, err := json.Marshal(container) 112 if err != nil { 113 return err 114 } 115 116 pth, err := container.jsonPath() 117 if err != nil { 118 return err 119 } 120 121 if err := ioutil.WriteFile(pth, data, 0666); err != nil { 122 return err 123 } 124 125 return container.writeHostConfig() 126 } 127 128 func (container *Container) toDiskLocking() error { 129 container.Lock() 130 err := container.toDisk() 131 container.Unlock() 132 return err 133 } 134 135 func (container *Container) readHostConfig() error { 136 container.hostConfig = &runconfig.HostConfig{} 137 // If the hostconfig file does not exist, do not read it. 138 // (We still have to initialize container.hostConfig, 139 // but that's OK, since we just did that above.) 140 pth, err := container.hostConfigPath() 141 if err != nil { 142 return err 143 } 144 145 _, err = os.Stat(pth) 146 if os.IsNotExist(err) { 147 return nil 148 } 149 150 f, err := os.Open(pth) 151 if err != nil { 152 return err 153 } 154 defer f.Close() 155 156 return json.NewDecoder(f).Decode(&container.hostConfig) 157 } 158 159 func (container *Container) writeHostConfig() error { 160 data, err := json.Marshal(container.hostConfig) 161 if err != nil { 162 return err 163 } 164 165 pth, err := container.hostConfigPath() 166 if err != nil { 167 return err 168 } 169 170 return ioutil.WriteFile(pth, data, 0666) 171 } 172 173 func (container *Container) logEvent(action string) { 174 d := container.daemon 175 d.EventsService.Log( 176 action, 177 container.ID, 178 container.Config.Image, 179 ) 180 } 181 182 // GetResourcePath evaluates `path` in the scope of the container's basefs, with proper path 183 // sanitisation. Symlinks are all scoped to the basefs of the container, as 184 // though the container's basefs was `/`. 185 // 186 // The basefs of a container is the host-facing path which is bind-mounted as 187 // `/` inside the container. This method is essentially used to access a 188 // particular path inside the container as though you were a process in that 189 // container. 190 // 191 // NOTE: The returned path is *only* safely scoped inside the container's basefs 192 // if no component of the returned path changes (such as a component 193 // symlinking to a different path) between using this method and using the 194 // path. See symlink.FollowSymlinkInScope for more details. 195 func (container *Container) GetResourcePath(path string) (string, error) { 196 // IMPORTANT - These are paths on the OS where the daemon is running, hence 197 // any filepath operations must be done in an OS agnostic way. 198 cleanPath := filepath.Join(string(os.PathSeparator), path) 199 r, e := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, cleanPath), container.basefs) 200 return r, e 201 } 202 203 // Evaluates `path` in the scope of the container's root, with proper path 204 // sanitisation. Symlinks are all scoped to the root of the container, as 205 // though the container's root was `/`. 206 // 207 // The root of a container is the host-facing configuration metadata directory. 208 // Only use this method to safely access the container's `container.json` or 209 // other metadata files. If in doubt, use container.GetResourcePath. 210 // 211 // NOTE: The returned path is *only* safely scoped inside the container's root 212 // if no component of the returned path changes (such as a component 213 // symlinking to a different path) between using this method and using the 214 // path. See symlink.FollowSymlinkInScope for more details. 215 func (container *Container) getRootResourcePath(path string) (string, error) { 216 // IMPORTANT - These are paths on the OS where the daemon is running, hence 217 // any filepath operations must be done in an OS agnostic way. 218 cleanPath := filepath.Join(string(os.PathSeparator), path) 219 return symlink.FollowSymlinkInScope(filepath.Join(container.root, cleanPath), container.root) 220 } 221 222 func (container *Container) exportContainerRw() (archive.Archive, error) { 223 if container.daemon == nil { 224 return nil, derr.ErrorCodeUnregisteredContainer.WithArgs(container.ID) 225 } 226 archive, err := container.daemon.diff(container) 227 if err != nil { 228 return nil, err 229 } 230 return ioutils.NewReadCloserWrapper(archive, func() error { 231 err := archive.Close() 232 return err 233 }), 234 nil 235 } 236 237 // Start prepares the container to run by setting up everything the 238 // container needs, such as storage and networking, as well as links 239 // between containers. The container is left waiting for a signal to 240 // begin running. 241 func (container *Container) Start() (err error) { 242 container.Lock() 243 defer container.Unlock() 244 245 if container.Running { 246 return nil 247 } 248 249 if container.removalInProgress || container.Dead { 250 return derr.ErrorCodeContainerBeingRemoved 251 } 252 253 // if we encounter an error during start we need to ensure that any other 254 // setup has been cleaned up properly 255 defer func() { 256 if err != nil { 257 container.setError(err) 258 // if no one else has set it, make sure we don't leave it at zero 259 if container.ExitCode == 0 { 260 container.ExitCode = 128 261 } 262 container.toDisk() 263 container.cleanup() 264 container.logEvent("die") 265 } 266 }() 267 268 if err := container.Mount(); err != nil { 269 return err 270 } 271 272 // Make sure NetworkMode has an acceptable value. We do this to ensure 273 // backwards API compatibility. 274 container.hostConfig = runconfig.SetDefaultNetModeIfBlank(container.hostConfig) 275 276 if err := container.initializeNetworking(); err != nil { 277 return err 278 } 279 linkedEnv, err := container.setupLinkedContainers() 280 if err != nil { 281 return err 282 } 283 if err := container.setupWorkingDirectory(); err != nil { 284 return err 285 } 286 env := container.createDaemonEnvironment(linkedEnv) 287 if err := populateCommand(container, env); err != nil { 288 return err 289 } 290 291 if !container.hostConfig.IpcMode.IsContainer() && !container.hostConfig.IpcMode.IsHost() { 292 if err := container.setupIpcDirs(); err != nil { 293 return err 294 } 295 } 296 297 mounts, err := container.setupMounts() 298 if err != nil { 299 return err 300 } 301 mounts = append(mounts, container.ipcMounts()...) 302 303 container.command.Mounts = mounts 304 return container.waitForStart() 305 } 306 307 // streamConfig.StdinPipe returns a WriteCloser which can be used to feed data 308 // to the standard input of the container's active process. 309 // Container.StdoutPipe and Container.StderrPipe each return a ReadCloser 310 // which can be used to retrieve the standard output (and error) generated 311 // by the container's active process. The output (and error) are actually 312 // copied and delivered to all StdoutPipe and StderrPipe consumers, using 313 // a kind of "broadcaster". 314 315 func (streamConfig *streamConfig) StdinPipe() io.WriteCloser { 316 return streamConfig.stdinPipe 317 } 318 319 func (streamConfig *streamConfig) StdoutPipe() io.ReadCloser { 320 reader, writer := io.Pipe() 321 streamConfig.stdout.Add(writer) 322 return ioutils.NewBufReader(reader) 323 } 324 325 func (streamConfig *streamConfig) StderrPipe() io.ReadCloser { 326 reader, writer := io.Pipe() 327 streamConfig.stderr.Add(writer) 328 return ioutils.NewBufReader(reader) 329 } 330 331 func (container *Container) isNetworkAllocated() bool { 332 return container.NetworkSettings.IPAddress != "" 333 } 334 335 // cleanup releases any network resources allocated to the container along with any rules 336 // around how containers are linked together. It also unmounts the container's root filesystem. 337 func (container *Container) cleanup() { 338 container.releaseNetwork() 339 340 if err := container.unmountIpcMounts(); err != nil { 341 logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err) 342 } 343 344 if err := container.Unmount(); err != nil { 345 logrus.Errorf("%s: Failed to umount filesystem: %v", container.ID, err) 346 } 347 348 for _, eConfig := range container.execCommands.s { 349 container.daemon.unregisterExecCommand(eConfig) 350 } 351 352 container.unmountVolumes(false) 353 } 354 355 // killSig sends the container the given signal. This wrapper for the 356 // host specific kill command prepares the container before attempting 357 // to send the signal. An error is returned if the container is paused 358 // or not running, or if there is a problem returned from the 359 // underlying kill command. 360 func (container *Container) killSig(sig int) error { 361 logrus.Debugf("Sending %d to %s", sig, container.ID) 362 container.Lock() 363 defer container.Unlock() 364 365 // We could unpause the container for them rather than returning this error 366 if container.Paused { 367 return derr.ErrorCodeUnpauseContainer.WithArgs(container.ID) 368 } 369 370 if !container.Running { 371 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 372 } 373 374 // signal to the monitor that it should not restart the container 375 // after we send the kill signal 376 container.monitor.ExitOnNext() 377 378 // if the container is currently restarting we do not need to send the signal 379 // to the process. Telling the monitor that it should exit on it's next event 380 // loop is enough 381 if container.Restarting { 382 return nil 383 } 384 385 if err := container.daemon.kill(container, sig); err != nil { 386 return err 387 } 388 container.logEvent("kill") 389 return nil 390 } 391 392 // Wrapper aroung killSig() suppressing "no such process" error. 393 func (container *Container) killPossiblyDeadProcess(sig int) error { 394 err := container.killSig(sig) 395 if err == syscall.ESRCH { 396 logrus.Debugf("Cannot kill process (pid=%d) with signal %d: no such process.", container.getPID(), sig) 397 return nil 398 } 399 return err 400 } 401 402 func (container *Container) pause() error { 403 container.Lock() 404 defer container.Unlock() 405 406 // We cannot Pause the container which is not running 407 if !container.Running { 408 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 409 } 410 411 // We cannot Pause the container which is already paused 412 if container.Paused { 413 return derr.ErrorCodeAlreadyPaused.WithArgs(container.ID) 414 } 415 416 if err := container.daemon.execDriver.Pause(container.command); err != nil { 417 return err 418 } 419 container.Paused = true 420 container.logEvent("pause") 421 return nil 422 } 423 424 func (container *Container) unpause() error { 425 container.Lock() 426 defer container.Unlock() 427 428 // We cannot unpause the container which is not running 429 if !container.Running { 430 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 431 } 432 433 // We cannot unpause the container which is not paused 434 if !container.Paused { 435 return derr.ErrorCodeNotPaused.WithArgs(container.ID) 436 } 437 438 if err := container.daemon.execDriver.Unpause(container.command); err != nil { 439 return err 440 } 441 container.Paused = false 442 container.logEvent("unpause") 443 return nil 444 } 445 446 // Kill forcefully terminates a container. 447 func (container *Container) Kill() error { 448 if !container.IsRunning() { 449 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 450 } 451 452 // 1. Send SIGKILL 453 if err := container.killPossiblyDeadProcess(int(syscall.SIGKILL)); err != nil { 454 // While normally we might "return err" here we're not going to 455 // because if we can't stop the container by this point then 456 // its probably because its already stopped. Meaning, between 457 // the time of the IsRunning() call above and now it stopped. 458 // Also, since the err return will be exec driver specific we can't 459 // look for any particular (common) error that would indicate 460 // that the process is already dead vs something else going wrong. 461 // So, instead we'll give it up to 2 more seconds to complete and if 462 // by that time the container is still running, then the error 463 // we got is probably valid and so we return it to the caller. 464 465 if container.IsRunning() { 466 container.WaitStop(2 * time.Second) 467 if container.IsRunning() { 468 return err 469 } 470 } 471 } 472 473 // 2. Wait for the process to die, in last resort, try to kill the process directly 474 if err := killProcessDirectly(container); err != nil { 475 return err 476 } 477 478 container.WaitStop(-1 * time.Second) 479 return nil 480 } 481 482 // Stop halts a container by sending a stop signal, waiting for the given 483 // duration in seconds, and then calling SIGKILL and waiting for the 484 // process to exit. If a negative duration is given, Stop will wait 485 // for the initial signal forever. If the container is not running Stop returns 486 // immediately. 487 func (container *Container) Stop(seconds int) error { 488 if !container.IsRunning() { 489 return nil 490 } 491 492 // 1. Send a SIGTERM 493 if err := container.killPossiblyDeadProcess(container.stopSignal()); err != nil { 494 logrus.Infof("Failed to send SIGTERM to the process, force killing") 495 if err := container.killPossiblyDeadProcess(9); err != nil { 496 return err 497 } 498 } 499 500 // 2. Wait for the process to exit on its own 501 if _, err := container.WaitStop(time.Duration(seconds) * time.Second); err != nil { 502 logrus.Infof("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds) 503 // 3. If it doesn't, then send SIGKILL 504 if err := container.Kill(); err != nil { 505 container.WaitStop(-1 * time.Second) 506 return err 507 } 508 } 509 510 container.logEvent("stop") 511 return nil 512 } 513 514 // Restart attempts to gracefully stop and then start the 515 // container. When stopping, wait for the given duration in seconds to 516 // gracefully stop, before forcefully terminating the container. If 517 // given a negative duration, wait forever for a graceful stop. 518 func (container *Container) Restart(seconds int) error { 519 // Avoid unnecessarily unmounting and then directly mounting 520 // the container when the container stops and then starts 521 // again 522 if err := container.Mount(); err == nil { 523 defer container.Unmount() 524 } 525 526 if err := container.Stop(seconds); err != nil { 527 return err 528 } 529 530 if err := container.Start(); err != nil { 531 return err 532 } 533 534 container.logEvent("restart") 535 return nil 536 } 537 538 // Resize changes the TTY of the process running inside the container 539 // to the given height and width. The container must be running. 540 func (container *Container) Resize(h, w int) error { 541 if !container.IsRunning() { 542 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 543 } 544 if err := container.command.ProcessConfig.Terminal.Resize(h, w); err != nil { 545 return err 546 } 547 container.logEvent("resize") 548 return nil 549 } 550 551 func (container *Container) export() (archive.Archive, error) { 552 if err := container.Mount(); err != nil { 553 return nil, err 554 } 555 556 uidMaps, gidMaps := container.daemon.GetUIDGIDMaps() 557 archive, err := archive.TarWithOptions(container.basefs, &archive.TarOptions{ 558 Compression: archive.Uncompressed, 559 UIDMaps: uidMaps, 560 GIDMaps: gidMaps, 561 }) 562 if err != nil { 563 container.Unmount() 564 return nil, err 565 } 566 arch := ioutils.NewReadCloserWrapper(archive, func() error { 567 err := archive.Close() 568 container.Unmount() 569 return err 570 }) 571 container.logEvent("export") 572 return arch, err 573 } 574 575 // Mount sets container.basefs 576 func (container *Container) Mount() error { 577 return container.daemon.Mount(container) 578 } 579 580 func (container *Container) changes() ([]archive.Change, error) { 581 container.Lock() 582 defer container.Unlock() 583 return container.daemon.changes(container) 584 } 585 586 func (container *Container) getImage() (*image.Image, error) { 587 if container.daemon == nil { 588 return nil, derr.ErrorCodeImageUnregContainer 589 } 590 return container.daemon.graph.Get(container.ImageID) 591 } 592 593 // Unmount asks the daemon to release the layered filesystems that are 594 // mounted by the container. 595 func (container *Container) Unmount() error { 596 return container.daemon.unmount(container) 597 } 598 599 func (container *Container) hostConfigPath() (string, error) { 600 return container.getRootResourcePath("hostconfig.json") 601 } 602 603 func (container *Container) jsonPath() (string, error) { 604 return container.getRootResourcePath("config.json") 605 } 606 607 // This method must be exported to be used from the lxc template 608 // This directory is only usable when the container is running 609 func (container *Container) rootfsPath() string { 610 return container.basefs 611 } 612 613 func validateID(id string) error { 614 if id == "" { 615 return derr.ErrorCodeEmptyID 616 } 617 return nil 618 } 619 620 func (container *Container) copy(resource string) (rc io.ReadCloser, err error) { 621 container.Lock() 622 623 defer func() { 624 if err != nil { 625 // Wait to unlock the container until the archive is fully read 626 // (see the ReadCloseWrapper func below) or if there is an error 627 // before that occurs. 628 container.Unlock() 629 } 630 }() 631 632 if err := container.Mount(); err != nil { 633 return nil, err 634 } 635 636 defer func() { 637 if err != nil { 638 // unmount any volumes 639 container.unmountVolumes(true) 640 // unmount the container's rootfs 641 container.Unmount() 642 } 643 }() 644 645 if err := container.mountVolumes(); err != nil { 646 return nil, err 647 } 648 649 basePath, err := container.GetResourcePath(resource) 650 if err != nil { 651 return nil, err 652 } 653 stat, err := os.Stat(basePath) 654 if err != nil { 655 return nil, err 656 } 657 var filter []string 658 if !stat.IsDir() { 659 d, f := filepath.Split(basePath) 660 basePath = d 661 filter = []string{f} 662 } else { 663 filter = []string{filepath.Base(basePath)} 664 basePath = filepath.Dir(basePath) 665 } 666 archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{ 667 Compression: archive.Uncompressed, 668 IncludeFiles: filter, 669 }) 670 if err != nil { 671 return nil, err 672 } 673 674 reader := ioutils.NewReadCloserWrapper(archive, func() error { 675 err := archive.Close() 676 container.unmountVolumes(true) 677 container.Unmount() 678 container.Unlock() 679 return err 680 }) 681 container.logEvent("copy") 682 return reader, nil 683 } 684 685 // Returns true if the container exposes a certain port 686 func (container *Container) exposes(p nat.Port) bool { 687 _, exists := container.Config.ExposedPorts[p] 688 return exists 689 } 690 691 func (container *Container) getLogConfig() runconfig.LogConfig { 692 cfg := container.hostConfig.LogConfig 693 if cfg.Type != "" || len(cfg.Config) > 0 { // container has log driver configured 694 if cfg.Type == "" { 695 cfg.Type = jsonfilelog.Name 696 } 697 return cfg 698 } 699 // Use daemon's default log config for containers 700 return container.daemon.defaultLogConfig 701 } 702 703 func (container *Container) getLogger() (logger.Logger, error) { 704 if container.logDriver != nil && container.IsRunning() { 705 return container.logDriver, nil 706 } 707 cfg := container.getLogConfig() 708 if err := logger.ValidateLogOpts(cfg.Type, cfg.Config); err != nil { 709 return nil, err 710 } 711 c, err := logger.GetLogDriver(cfg.Type) 712 if err != nil { 713 return nil, derr.ErrorCodeLoggingFactory.WithArgs(err) 714 } 715 ctx := logger.Context{ 716 Config: cfg.Config, 717 ContainerID: container.ID, 718 ContainerName: container.Name, 719 ContainerEntrypoint: container.Path, 720 ContainerArgs: container.Args, 721 ContainerImageID: container.ImageID, 722 ContainerImageName: container.Config.Image, 723 ContainerCreated: container.Created, 724 ContainerEnv: container.Config.Env, 725 ContainerLabels: container.Config.Labels, 726 } 727 728 // Set logging file for "json-logger" 729 if cfg.Type == jsonfilelog.Name { 730 ctx.LogPath, err = container.getRootResourcePath(fmt.Sprintf("%s-json.log", container.ID)) 731 if err != nil { 732 return nil, err 733 } 734 } 735 return c(ctx) 736 } 737 738 func (container *Container) startLogging() error { 739 cfg := container.getLogConfig() 740 if cfg.Type == "none" { 741 return nil // do not start logging routines 742 } 743 744 l, err := container.getLogger() 745 if err != nil { 746 return derr.ErrorCodeInitLogger.WithArgs(err) 747 } 748 749 copier := logger.NewCopier(container.ID, map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l) 750 container.logCopier = copier 751 copier.Run() 752 container.logDriver = l 753 754 // set LogPath field only for json-file logdriver 755 if jl, ok := l.(*jsonfilelog.JSONFileLogger); ok { 756 container.LogPath = jl.LogPath() 757 } 758 759 return nil 760 } 761 762 func (container *Container) waitForStart() error { 763 container.monitor = newContainerMonitor(container, container.hostConfig.RestartPolicy) 764 765 // block until we either receive an error from the initial start of the container's 766 // process or until the process is running in the container 767 select { 768 case <-container.monitor.startSignal: 769 case err := <-promise.Go(container.monitor.Start): 770 return err 771 } 772 773 return nil 774 } 775 776 func (container *Container) getProcessLabel() string { 777 // even if we have a process label return "" if we are running 778 // in privileged mode 779 if container.hostConfig.Privileged { 780 return "" 781 } 782 return container.ProcessLabel 783 } 784 785 func (container *Container) getMountLabel() string { 786 if container.hostConfig.Privileged { 787 return "" 788 } 789 return container.MountLabel 790 } 791 792 func (container *Container) stats() (*execdriver.ResourceStats, error) { 793 return container.daemon.stats(container) 794 } 795 796 func (container *Container) getExecIDs() []string { 797 return container.execCommands.List() 798 } 799 800 func (container *Container) exec(ec *ExecConfig) error { 801 container.Lock() 802 defer container.Unlock() 803 804 callback := func(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error { 805 if processConfig.Tty { 806 // The callback is called after the process Start() 807 // so we are in the parent process. In TTY mode, stdin/out/err is the PtySlave 808 // which we close here. 809 if c, ok := processConfig.Stdout.(io.Closer); ok { 810 c.Close() 811 } 812 } 813 close(ec.waitStart) 814 return nil 815 } 816 817 // We use a callback here instead of a goroutine and an chan for 818 // synchronization purposes 819 cErr := promise.Go(func() error { return container.monitorExec(ec, callback) }) 820 821 // Exec should not return until the process is actually running 822 select { 823 case <-ec.waitStart: 824 case err := <-cErr: 825 return err 826 } 827 828 return nil 829 } 830 831 func (container *Container) monitorExec(ExecConfig *ExecConfig, callback execdriver.DriverCallback) error { 832 var ( 833 err error 834 exitCode int 835 ) 836 pipes := execdriver.NewPipes(ExecConfig.streamConfig.stdin, ExecConfig.streamConfig.stdout, ExecConfig.streamConfig.stderr, ExecConfig.OpenStdin) 837 exitCode, err = container.daemon.Exec(container, ExecConfig, pipes, callback) 838 if err != nil { 839 logrus.Errorf("Error running command in existing container %s: %s", container.ID, err) 840 } 841 logrus.Debugf("Exec task in container %s exited with code %d", container.ID, exitCode) 842 if ExecConfig.OpenStdin { 843 if err := ExecConfig.streamConfig.stdin.Close(); err != nil { 844 logrus.Errorf("Error closing stdin while running in %s: %s", container.ID, err) 845 } 846 } 847 if err := ExecConfig.streamConfig.stdout.Clean(); err != nil { 848 logrus.Errorf("Error closing stdout while running in %s: %s", container.ID, err) 849 } 850 if err := ExecConfig.streamConfig.stderr.Clean(); err != nil { 851 logrus.Errorf("Error closing stderr while running in %s: %s", container.ID, err) 852 } 853 if ExecConfig.ProcessConfig.Terminal != nil { 854 if err := ExecConfig.ProcessConfig.Terminal.Close(); err != nil { 855 logrus.Errorf("Error closing terminal while running in container %s: %s", container.ID, err) 856 } 857 } 858 // remove the exec command from the container's store only and not the 859 // daemon's store so that the exec command can be inspected. 860 container.execCommands.Delete(ExecConfig.ID) 861 return err 862 } 863 864 // Attach connects to the container's TTY, delegating to standard 865 // streams or websockets depending on the configuration. 866 func (container *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error { 867 return attach(&container.streamConfig, container.Config.OpenStdin, container.Config.StdinOnce, container.Config.Tty, stdin, stdout, stderr) 868 } 869 870 func (container *Container) attachWithLogs(stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error { 871 if logs { 872 logDriver, err := container.getLogger() 873 if err != nil { 874 return err 875 } 876 cLog, ok := logDriver.(logger.LogReader) 877 if !ok { 878 return logger.ErrReadLogsNotSupported 879 } 880 logs := cLog.ReadLogs(logger.ReadConfig{Tail: -1}) 881 882 LogLoop: 883 for { 884 select { 885 case msg, ok := <-logs.Msg: 886 if !ok { 887 break LogLoop 888 } 889 if msg.Source == "stdout" && stdout != nil { 890 stdout.Write(msg.Line) 891 } 892 if msg.Source == "stderr" && stderr != nil { 893 stderr.Write(msg.Line) 894 } 895 case err := <-logs.Err: 896 logrus.Errorf("Error streaming logs: %v", err) 897 break LogLoop 898 } 899 } 900 } 901 902 container.logEvent("attach") 903 904 //stream 905 if stream { 906 var stdinPipe io.ReadCloser 907 if stdin != nil { 908 r, w := io.Pipe() 909 go func() { 910 defer w.Close() 911 defer logrus.Debugf("Closing buffered stdin pipe") 912 io.Copy(w, stdin) 913 }() 914 stdinPipe = r 915 } 916 <-container.Attach(stdinPipe, stdout, stderr) 917 // If we are in stdinonce mode, wait for the process to end 918 // otherwise, simply return 919 if container.Config.StdinOnce && !container.Config.Tty { 920 container.WaitStop(-1 * time.Second) 921 } 922 } 923 return nil 924 } 925 926 func attach(streamConfig *streamConfig, openStdin, stdinOnce, tty bool, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error { 927 var ( 928 cStdout, cStderr io.ReadCloser 929 cStdin io.WriteCloser 930 wg sync.WaitGroup 931 errors = make(chan error, 3) 932 ) 933 934 if stdin != nil && openStdin { 935 cStdin = streamConfig.StdinPipe() 936 wg.Add(1) 937 } 938 939 if stdout != nil { 940 cStdout = streamConfig.StdoutPipe() 941 wg.Add(1) 942 } 943 944 if stderr != nil { 945 cStderr = streamConfig.StderrPipe() 946 wg.Add(1) 947 } 948 949 // Connect stdin of container to the http conn. 950 go func() { 951 if stdin == nil || !openStdin { 952 return 953 } 954 logrus.Debugf("attach: stdin: begin") 955 defer func() { 956 if stdinOnce && !tty { 957 cStdin.Close() 958 } else { 959 // No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr 960 if cStdout != nil { 961 cStdout.Close() 962 } 963 if cStderr != nil { 964 cStderr.Close() 965 } 966 } 967 wg.Done() 968 logrus.Debugf("attach: stdin: end") 969 }() 970 971 var err error 972 if tty { 973 _, err = copyEscapable(cStdin, stdin) 974 } else { 975 _, err = io.Copy(cStdin, stdin) 976 977 } 978 if err == io.ErrClosedPipe { 979 err = nil 980 } 981 if err != nil { 982 logrus.Errorf("attach: stdin: %s", err) 983 errors <- err 984 return 985 } 986 }() 987 988 attachStream := func(name string, stream io.Writer, streamPipe io.ReadCloser) { 989 if stream == nil { 990 return 991 } 992 defer func() { 993 // Make sure stdin gets closed 994 if stdin != nil { 995 stdin.Close() 996 } 997 streamPipe.Close() 998 wg.Done() 999 logrus.Debugf("attach: %s: end", name) 1000 }() 1001 1002 logrus.Debugf("attach: %s: begin", name) 1003 _, err := io.Copy(stream, streamPipe) 1004 if err == io.ErrClosedPipe { 1005 err = nil 1006 } 1007 if err != nil { 1008 logrus.Errorf("attach: %s: %v", name, err) 1009 errors <- err 1010 } 1011 } 1012 1013 go attachStream("stdout", stdout, cStdout) 1014 go attachStream("stderr", stderr, cStderr) 1015 1016 return promise.Go(func() error { 1017 wg.Wait() 1018 close(errors) 1019 for err := range errors { 1020 if err != nil { 1021 return err 1022 } 1023 } 1024 return nil 1025 }) 1026 } 1027 1028 // Code c/c from io.Copy() modified to handle escape sequence 1029 func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) { 1030 buf := make([]byte, 32*1024) 1031 for { 1032 nr, er := src.Read(buf) 1033 if nr > 0 { 1034 // ---- Docker addition 1035 // char 16 is C-p 1036 if nr == 1 && buf[0] == 16 { 1037 nr, er = src.Read(buf) 1038 // char 17 is C-q 1039 if nr == 1 && buf[0] == 17 { 1040 if err := src.Close(); err != nil { 1041 return 0, err 1042 } 1043 return 0, nil 1044 } 1045 } 1046 // ---- End of docker 1047 nw, ew := dst.Write(buf[0:nr]) 1048 if nw > 0 { 1049 written += int64(nw) 1050 } 1051 if ew != nil { 1052 err = ew 1053 break 1054 } 1055 if nr != nw { 1056 err = io.ErrShortWrite 1057 break 1058 } 1059 } 1060 if er == io.EOF { 1061 break 1062 } 1063 if er != nil { 1064 err = er 1065 break 1066 } 1067 } 1068 return written, err 1069 } 1070 1071 func (container *Container) shouldRestart() bool { 1072 return container.hostConfig.RestartPolicy.Name == "always" || 1073 (container.hostConfig.RestartPolicy.Name == "unless-stopped" && !container.HasBeenManuallyStopped) || 1074 (container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0) 1075 } 1076 1077 func (container *Container) mountVolumes() error { 1078 mounts, err := container.setupMounts() 1079 if err != nil { 1080 return err 1081 } 1082 1083 for _, m := range mounts { 1084 dest, err := container.GetResourcePath(m.Destination) 1085 if err != nil { 1086 return err 1087 } 1088 1089 var stat os.FileInfo 1090 stat, err = os.Stat(m.Source) 1091 if err != nil { 1092 return err 1093 } 1094 if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil { 1095 return err 1096 } 1097 1098 opts := "rbind,ro" 1099 if m.Writable { 1100 opts = "rbind,rw" 1101 } 1102 1103 if err := mount.Mount(m.Source, dest, "bind", opts); err != nil { 1104 return err 1105 } 1106 } 1107 1108 return nil 1109 } 1110 1111 func (container *Container) copyImagePathContent(v volume.Volume, destination string) error { 1112 rootfs, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, destination), container.basefs) 1113 if err != nil { 1114 return err 1115 } 1116 1117 if _, err = ioutil.ReadDir(rootfs); err != nil { 1118 if os.IsNotExist(err) { 1119 return nil 1120 } 1121 return err 1122 } 1123 1124 path, err := v.Mount() 1125 if err != nil { 1126 return err 1127 } 1128 1129 if err := copyExistingContents(rootfs, path); err != nil { 1130 return err 1131 } 1132 1133 return v.Unmount() 1134 } 1135 1136 func (container *Container) stopSignal() int { 1137 var stopSignal syscall.Signal 1138 if container.Config.StopSignal != "" { 1139 stopSignal, _ = signal.ParseSignal(container.Config.StopSignal) 1140 } 1141 1142 if int(stopSignal) == 0 { 1143 stopSignal, _ = signal.ParseSignal(signal.DefaultStopSignal) 1144 } 1145 return int(stopSignal) 1146 }