github.com/psychoss/docker@v1.9.0/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 // cleanup releases any network resources allocated to the container along with any rules 332 // around how containers are linked together. It also unmounts the container's root filesystem. 333 func (container *Container) cleanup() { 334 container.releaseNetwork() 335 336 if err := container.unmountIpcMounts(); err != nil { 337 logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err) 338 } 339 340 if err := container.Unmount(); err != nil { 341 logrus.Errorf("%s: Failed to umount filesystem: %v", container.ID, err) 342 } 343 344 for _, eConfig := range container.execCommands.s { 345 container.daemon.unregisterExecCommand(eConfig) 346 } 347 348 container.unmountVolumes(false) 349 } 350 351 // killSig sends the container the given signal. This wrapper for the 352 // host specific kill command prepares the container before attempting 353 // to send the signal. An error is returned if the container is paused 354 // or not running, or if there is a problem returned from the 355 // underlying kill command. 356 func (container *Container) killSig(sig int) error { 357 logrus.Debugf("Sending %d to %s", sig, container.ID) 358 container.Lock() 359 defer container.Unlock() 360 361 // We could unpause the container for them rather than returning this error 362 if container.Paused { 363 return derr.ErrorCodeUnpauseContainer.WithArgs(container.ID) 364 } 365 366 if !container.Running { 367 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 368 } 369 370 // signal to the monitor that it should not restart the container 371 // after we send the kill signal 372 container.monitor.ExitOnNext() 373 374 // if the container is currently restarting we do not need to send the signal 375 // to the process. Telling the monitor that it should exit on it's next event 376 // loop is enough 377 if container.Restarting { 378 return nil 379 } 380 381 if err := container.daemon.kill(container, sig); err != nil { 382 return err 383 } 384 container.logEvent("kill") 385 return nil 386 } 387 388 // Wrapper aroung killSig() suppressing "no such process" error. 389 func (container *Container) killPossiblyDeadProcess(sig int) error { 390 err := container.killSig(sig) 391 if err == syscall.ESRCH { 392 logrus.Debugf("Cannot kill process (pid=%d) with signal %d: no such process.", container.getPID(), sig) 393 return nil 394 } 395 return err 396 } 397 398 func (container *Container) pause() error { 399 container.Lock() 400 defer container.Unlock() 401 402 // We cannot Pause the container which is not running 403 if !container.Running { 404 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 405 } 406 407 // We cannot Pause the container which is already paused 408 if container.Paused { 409 return derr.ErrorCodeAlreadyPaused.WithArgs(container.ID) 410 } 411 412 if err := container.daemon.execDriver.Pause(container.command); err != nil { 413 return err 414 } 415 container.Paused = true 416 container.logEvent("pause") 417 return nil 418 } 419 420 func (container *Container) unpause() error { 421 container.Lock() 422 defer container.Unlock() 423 424 // We cannot unpause the container which is not running 425 if !container.Running { 426 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 427 } 428 429 // We cannot unpause the container which is not paused 430 if !container.Paused { 431 return derr.ErrorCodeNotPaused.WithArgs(container.ID) 432 } 433 434 if err := container.daemon.execDriver.Unpause(container.command); err != nil { 435 return err 436 } 437 container.Paused = false 438 container.logEvent("unpause") 439 return nil 440 } 441 442 // Kill forcefully terminates a container. 443 func (container *Container) Kill() error { 444 if !container.IsRunning() { 445 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 446 } 447 448 // 1. Send SIGKILL 449 if err := container.killPossiblyDeadProcess(int(syscall.SIGKILL)); err != nil { 450 // While normally we might "return err" here we're not going to 451 // because if we can't stop the container by this point then 452 // its probably because its already stopped. Meaning, between 453 // the time of the IsRunning() call above and now it stopped. 454 // Also, since the err return will be exec driver specific we can't 455 // look for any particular (common) error that would indicate 456 // that the process is already dead vs something else going wrong. 457 // So, instead we'll give it up to 2 more seconds to complete and if 458 // by that time the container is still running, then the error 459 // we got is probably valid and so we return it to the caller. 460 461 if container.IsRunning() { 462 container.WaitStop(2 * time.Second) 463 if container.IsRunning() { 464 return err 465 } 466 } 467 } 468 469 // 2. Wait for the process to die, in last resort, try to kill the process directly 470 if err := killProcessDirectly(container); err != nil { 471 return err 472 } 473 474 container.WaitStop(-1 * time.Second) 475 return nil 476 } 477 478 // Stop halts a container by sending a stop signal, waiting for the given 479 // duration in seconds, and then calling SIGKILL and waiting for the 480 // process to exit. If a negative duration is given, Stop will wait 481 // for the initial signal forever. If the container is not running Stop returns 482 // immediately. 483 func (container *Container) Stop(seconds int) error { 484 if !container.IsRunning() { 485 return nil 486 } 487 488 // 1. Send a SIGTERM 489 if err := container.killPossiblyDeadProcess(container.stopSignal()); err != nil { 490 logrus.Infof("Failed to send SIGTERM to the process, force killing") 491 if err := container.killPossiblyDeadProcess(9); err != nil { 492 return err 493 } 494 } 495 496 // 2. Wait for the process to exit on its own 497 if _, err := container.WaitStop(time.Duration(seconds) * time.Second); err != nil { 498 logrus.Infof("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds) 499 // 3. If it doesn't, then send SIGKILL 500 if err := container.Kill(); err != nil { 501 container.WaitStop(-1 * time.Second) 502 return err 503 } 504 } 505 506 container.logEvent("stop") 507 return nil 508 } 509 510 // Restart attempts to gracefully stop and then start the 511 // container. When stopping, wait for the given duration in seconds to 512 // gracefully stop, before forcefully terminating the container. If 513 // given a negative duration, wait forever for a graceful stop. 514 func (container *Container) Restart(seconds int) error { 515 // Avoid unnecessarily unmounting and then directly mounting 516 // the container when the container stops and then starts 517 // again 518 if err := container.Mount(); err == nil { 519 defer container.Unmount() 520 } 521 522 if err := container.Stop(seconds); err != nil { 523 return err 524 } 525 526 if err := container.Start(); err != nil { 527 return err 528 } 529 530 container.logEvent("restart") 531 return nil 532 } 533 534 // Resize changes the TTY of the process running inside the container 535 // to the given height and width. The container must be running. 536 func (container *Container) Resize(h, w int) error { 537 if !container.IsRunning() { 538 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 539 } 540 if err := container.command.ProcessConfig.Terminal.Resize(h, w); err != nil { 541 return err 542 } 543 container.logEvent("resize") 544 return nil 545 } 546 547 func (container *Container) export() (archive.Archive, error) { 548 if err := container.Mount(); err != nil { 549 return nil, err 550 } 551 552 uidMaps, gidMaps := container.daemon.GetUIDGIDMaps() 553 archive, err := archive.TarWithOptions(container.basefs, &archive.TarOptions{ 554 Compression: archive.Uncompressed, 555 UIDMaps: uidMaps, 556 GIDMaps: gidMaps, 557 }) 558 if err != nil { 559 container.Unmount() 560 return nil, err 561 } 562 arch := ioutils.NewReadCloserWrapper(archive, func() error { 563 err := archive.Close() 564 container.Unmount() 565 return err 566 }) 567 container.logEvent("export") 568 return arch, err 569 } 570 571 // Mount sets container.basefs 572 func (container *Container) Mount() error { 573 return container.daemon.Mount(container) 574 } 575 576 func (container *Container) changes() ([]archive.Change, error) { 577 container.Lock() 578 defer container.Unlock() 579 return container.daemon.changes(container) 580 } 581 582 func (container *Container) getImage() (*image.Image, error) { 583 if container.daemon == nil { 584 return nil, derr.ErrorCodeImageUnregContainer 585 } 586 return container.daemon.graph.Get(container.ImageID) 587 } 588 589 // Unmount asks the daemon to release the layered filesystems that are 590 // mounted by the container. 591 func (container *Container) Unmount() error { 592 return container.daemon.unmount(container) 593 } 594 595 func (container *Container) hostConfigPath() (string, error) { 596 return container.getRootResourcePath("hostconfig.json") 597 } 598 599 func (container *Container) jsonPath() (string, error) { 600 return container.getRootResourcePath("config.json") 601 } 602 603 // This method must be exported to be used from the lxc template 604 // This directory is only usable when the container is running 605 func (container *Container) rootfsPath() string { 606 return container.basefs 607 } 608 609 func validateID(id string) error { 610 if id == "" { 611 return derr.ErrorCodeEmptyID 612 } 613 return nil 614 } 615 616 func (container *Container) copy(resource string) (rc io.ReadCloser, err error) { 617 container.Lock() 618 619 defer func() { 620 if err != nil { 621 // Wait to unlock the container until the archive is fully read 622 // (see the ReadCloseWrapper func below) or if there is an error 623 // before that occurs. 624 container.Unlock() 625 } 626 }() 627 628 if err := container.Mount(); err != nil { 629 return nil, err 630 } 631 632 defer func() { 633 if err != nil { 634 // unmount any volumes 635 container.unmountVolumes(true) 636 // unmount the container's rootfs 637 container.Unmount() 638 } 639 }() 640 641 if err := container.mountVolumes(); err != nil { 642 return nil, err 643 } 644 645 basePath, err := container.GetResourcePath(resource) 646 if err != nil { 647 return nil, err 648 } 649 stat, err := os.Stat(basePath) 650 if err != nil { 651 return nil, err 652 } 653 var filter []string 654 if !stat.IsDir() { 655 d, f := filepath.Split(basePath) 656 basePath = d 657 filter = []string{f} 658 } else { 659 filter = []string{filepath.Base(basePath)} 660 basePath = filepath.Dir(basePath) 661 } 662 archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{ 663 Compression: archive.Uncompressed, 664 IncludeFiles: filter, 665 }) 666 if err != nil { 667 return nil, err 668 } 669 670 reader := ioutils.NewReadCloserWrapper(archive, func() error { 671 err := archive.Close() 672 container.unmountVolumes(true) 673 container.Unmount() 674 container.Unlock() 675 return err 676 }) 677 container.logEvent("copy") 678 return reader, nil 679 } 680 681 // Returns true if the container exposes a certain port 682 func (container *Container) exposes(p nat.Port) bool { 683 _, exists := container.Config.ExposedPorts[p] 684 return exists 685 } 686 687 func (container *Container) getLogConfig() runconfig.LogConfig { 688 cfg := container.hostConfig.LogConfig 689 if cfg.Type != "" || len(cfg.Config) > 0 { // container has log driver configured 690 if cfg.Type == "" { 691 cfg.Type = jsonfilelog.Name 692 } 693 return cfg 694 } 695 // Use daemon's default log config for containers 696 return container.daemon.defaultLogConfig 697 } 698 699 func (container *Container) getLogger() (logger.Logger, error) { 700 if container.logDriver != nil && container.IsRunning() { 701 return container.logDriver, nil 702 } 703 cfg := container.getLogConfig() 704 if err := logger.ValidateLogOpts(cfg.Type, cfg.Config); err != nil { 705 return nil, err 706 } 707 c, err := logger.GetLogDriver(cfg.Type) 708 if err != nil { 709 return nil, derr.ErrorCodeLoggingFactory.WithArgs(err) 710 } 711 ctx := logger.Context{ 712 Config: cfg.Config, 713 ContainerID: container.ID, 714 ContainerName: container.Name, 715 ContainerEntrypoint: container.Path, 716 ContainerArgs: container.Args, 717 ContainerImageID: container.ImageID, 718 ContainerImageName: container.Config.Image, 719 ContainerCreated: container.Created, 720 ContainerEnv: container.Config.Env, 721 ContainerLabels: container.Config.Labels, 722 } 723 724 // Set logging file for "json-logger" 725 if cfg.Type == jsonfilelog.Name { 726 ctx.LogPath, err = container.getRootResourcePath(fmt.Sprintf("%s-json.log", container.ID)) 727 if err != nil { 728 return nil, err 729 } 730 } 731 return c(ctx) 732 } 733 734 func (container *Container) startLogging() error { 735 cfg := container.getLogConfig() 736 if cfg.Type == "none" { 737 return nil // do not start logging routines 738 } 739 740 l, err := container.getLogger() 741 if err != nil { 742 return derr.ErrorCodeInitLogger.WithArgs(err) 743 } 744 745 copier := logger.NewCopier(container.ID, map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l) 746 container.logCopier = copier 747 copier.Run() 748 container.logDriver = l 749 750 // set LogPath field only for json-file logdriver 751 if jl, ok := l.(*jsonfilelog.JSONFileLogger); ok { 752 container.LogPath = jl.LogPath() 753 } 754 755 return nil 756 } 757 758 func (container *Container) waitForStart() error { 759 container.monitor = newContainerMonitor(container, container.hostConfig.RestartPolicy) 760 761 // block until we either receive an error from the initial start of the container's 762 // process or until the process is running in the container 763 select { 764 case <-container.monitor.startSignal: 765 case err := <-promise.Go(container.monitor.Start): 766 return err 767 } 768 769 return nil 770 } 771 772 func (container *Container) getProcessLabel() string { 773 // even if we have a process label return "" if we are running 774 // in privileged mode 775 if container.hostConfig.Privileged { 776 return "" 777 } 778 return container.ProcessLabel 779 } 780 781 func (container *Container) getMountLabel() string { 782 if container.hostConfig.Privileged { 783 return "" 784 } 785 return container.MountLabel 786 } 787 788 func (container *Container) stats() (*execdriver.ResourceStats, error) { 789 return container.daemon.stats(container) 790 } 791 792 func (container *Container) getExecIDs() []string { 793 return container.execCommands.List() 794 } 795 796 func (container *Container) exec(ec *ExecConfig) error { 797 container.Lock() 798 defer container.Unlock() 799 800 callback := func(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error { 801 if processConfig.Tty { 802 // The callback is called after the process Start() 803 // so we are in the parent process. In TTY mode, stdin/out/err is the PtySlave 804 // which we close here. 805 if c, ok := processConfig.Stdout.(io.Closer); ok { 806 c.Close() 807 } 808 } 809 close(ec.waitStart) 810 return nil 811 } 812 813 // We use a callback here instead of a goroutine and an chan for 814 // synchronization purposes 815 cErr := promise.Go(func() error { return container.monitorExec(ec, callback) }) 816 817 // Exec should not return until the process is actually running 818 select { 819 case <-ec.waitStart: 820 case err := <-cErr: 821 return err 822 } 823 824 return nil 825 } 826 827 func (container *Container) monitorExec(ExecConfig *ExecConfig, callback execdriver.DriverCallback) error { 828 var ( 829 err error 830 exitCode int 831 ) 832 pipes := execdriver.NewPipes(ExecConfig.streamConfig.stdin, ExecConfig.streamConfig.stdout, ExecConfig.streamConfig.stderr, ExecConfig.OpenStdin) 833 exitCode, err = container.daemon.Exec(container, ExecConfig, pipes, callback) 834 if err != nil { 835 logrus.Errorf("Error running command in existing container %s: %s", container.ID, err) 836 } 837 logrus.Debugf("Exec task in container %s exited with code %d", container.ID, exitCode) 838 if ExecConfig.OpenStdin { 839 if err := ExecConfig.streamConfig.stdin.Close(); err != nil { 840 logrus.Errorf("Error closing stdin while running in %s: %s", container.ID, err) 841 } 842 } 843 if err := ExecConfig.streamConfig.stdout.Clean(); err != nil { 844 logrus.Errorf("Error closing stdout while running in %s: %s", container.ID, err) 845 } 846 if err := ExecConfig.streamConfig.stderr.Clean(); err != nil { 847 logrus.Errorf("Error closing stderr while running in %s: %s", container.ID, err) 848 } 849 if ExecConfig.ProcessConfig.Terminal != nil { 850 if err := ExecConfig.ProcessConfig.Terminal.Close(); err != nil { 851 logrus.Errorf("Error closing terminal while running in container %s: %s", container.ID, err) 852 } 853 } 854 // remove the exec command from the container's store only and not the 855 // daemon's store so that the exec command can be inspected. 856 container.execCommands.Delete(ExecConfig.ID) 857 return err 858 } 859 860 // Attach connects to the container's TTY, delegating to standard 861 // streams or websockets depending on the configuration. 862 func (container *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error { 863 return attach(&container.streamConfig, container.Config.OpenStdin, container.Config.StdinOnce, container.Config.Tty, stdin, stdout, stderr) 864 } 865 866 func (container *Container) attachWithLogs(stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error { 867 if logs { 868 logDriver, err := container.getLogger() 869 if err != nil { 870 return err 871 } 872 cLog, ok := logDriver.(logger.LogReader) 873 if !ok { 874 return logger.ErrReadLogsNotSupported 875 } 876 logs := cLog.ReadLogs(logger.ReadConfig{Tail: -1}) 877 878 LogLoop: 879 for { 880 select { 881 case msg, ok := <-logs.Msg: 882 if !ok { 883 break LogLoop 884 } 885 if msg.Source == "stdout" && stdout != nil { 886 stdout.Write(msg.Line) 887 } 888 if msg.Source == "stderr" && stderr != nil { 889 stderr.Write(msg.Line) 890 } 891 case err := <-logs.Err: 892 logrus.Errorf("Error streaming logs: %v", err) 893 break LogLoop 894 } 895 } 896 } 897 898 container.logEvent("attach") 899 900 //stream 901 if stream { 902 var stdinPipe io.ReadCloser 903 if stdin != nil { 904 r, w := io.Pipe() 905 go func() { 906 defer w.Close() 907 defer logrus.Debugf("Closing buffered stdin pipe") 908 io.Copy(w, stdin) 909 }() 910 stdinPipe = r 911 } 912 <-container.Attach(stdinPipe, stdout, stderr) 913 // If we are in stdinonce mode, wait for the process to end 914 // otherwise, simply return 915 if container.Config.StdinOnce && !container.Config.Tty { 916 container.WaitStop(-1 * time.Second) 917 } 918 } 919 return nil 920 } 921 922 func attach(streamConfig *streamConfig, openStdin, stdinOnce, tty bool, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error { 923 var ( 924 cStdout, cStderr io.ReadCloser 925 cStdin io.WriteCloser 926 wg sync.WaitGroup 927 errors = make(chan error, 3) 928 ) 929 930 if stdin != nil && openStdin { 931 cStdin = streamConfig.StdinPipe() 932 wg.Add(1) 933 } 934 935 if stdout != nil { 936 cStdout = streamConfig.StdoutPipe() 937 wg.Add(1) 938 } 939 940 if stderr != nil { 941 cStderr = streamConfig.StderrPipe() 942 wg.Add(1) 943 } 944 945 // Connect stdin of container to the http conn. 946 go func() { 947 if stdin == nil || !openStdin { 948 return 949 } 950 logrus.Debugf("attach: stdin: begin") 951 defer func() { 952 if stdinOnce && !tty { 953 cStdin.Close() 954 } else { 955 // No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr 956 if cStdout != nil { 957 cStdout.Close() 958 } 959 if cStderr != nil { 960 cStderr.Close() 961 } 962 } 963 wg.Done() 964 logrus.Debugf("attach: stdin: end") 965 }() 966 967 var err error 968 if tty { 969 _, err = copyEscapable(cStdin, stdin) 970 } else { 971 _, err = io.Copy(cStdin, stdin) 972 973 } 974 if err == io.ErrClosedPipe { 975 err = nil 976 } 977 if err != nil { 978 logrus.Errorf("attach: stdin: %s", err) 979 errors <- err 980 return 981 } 982 }() 983 984 attachStream := func(name string, stream io.Writer, streamPipe io.ReadCloser) { 985 if stream == nil { 986 return 987 } 988 defer func() { 989 // Make sure stdin gets closed 990 if stdin != nil { 991 stdin.Close() 992 } 993 streamPipe.Close() 994 wg.Done() 995 logrus.Debugf("attach: %s: end", name) 996 }() 997 998 logrus.Debugf("attach: %s: begin", name) 999 _, err := io.Copy(stream, streamPipe) 1000 if err == io.ErrClosedPipe { 1001 err = nil 1002 } 1003 if err != nil { 1004 logrus.Errorf("attach: %s: %v", name, err) 1005 errors <- err 1006 } 1007 } 1008 1009 go attachStream("stdout", stdout, cStdout) 1010 go attachStream("stderr", stderr, cStderr) 1011 1012 return promise.Go(func() error { 1013 wg.Wait() 1014 close(errors) 1015 for err := range errors { 1016 if err != nil { 1017 return err 1018 } 1019 } 1020 return nil 1021 }) 1022 } 1023 1024 // Code c/c from io.Copy() modified to handle escape sequence 1025 func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) { 1026 buf := make([]byte, 32*1024) 1027 for { 1028 nr, er := src.Read(buf) 1029 if nr > 0 { 1030 // ---- Docker addition 1031 // char 16 is C-p 1032 if nr == 1 && buf[0] == 16 { 1033 nr, er = src.Read(buf) 1034 // char 17 is C-q 1035 if nr == 1 && buf[0] == 17 { 1036 if err := src.Close(); err != nil { 1037 return 0, err 1038 } 1039 return 0, nil 1040 } 1041 } 1042 // ---- End of docker 1043 nw, ew := dst.Write(buf[0:nr]) 1044 if nw > 0 { 1045 written += int64(nw) 1046 } 1047 if ew != nil { 1048 err = ew 1049 break 1050 } 1051 if nr != nw { 1052 err = io.ErrShortWrite 1053 break 1054 } 1055 } 1056 if er == io.EOF { 1057 break 1058 } 1059 if er != nil { 1060 err = er 1061 break 1062 } 1063 } 1064 return written, err 1065 } 1066 1067 func (container *Container) shouldRestart() bool { 1068 return container.hostConfig.RestartPolicy.Name == "always" || 1069 (container.hostConfig.RestartPolicy.Name == "unless-stopped" && !container.HasBeenManuallyStopped) || 1070 (container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0) 1071 } 1072 1073 func (container *Container) mountVolumes() error { 1074 mounts, err := container.setupMounts() 1075 if err != nil { 1076 return err 1077 } 1078 1079 for _, m := range mounts { 1080 dest, err := container.GetResourcePath(m.Destination) 1081 if err != nil { 1082 return err 1083 } 1084 1085 var stat os.FileInfo 1086 stat, err = os.Stat(m.Source) 1087 if err != nil { 1088 return err 1089 } 1090 if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil { 1091 return err 1092 } 1093 1094 opts := "rbind,ro" 1095 if m.Writable { 1096 opts = "rbind,rw" 1097 } 1098 1099 if err := mount.Mount(m.Source, dest, "bind", opts); err != nil { 1100 return err 1101 } 1102 } 1103 1104 return nil 1105 } 1106 1107 func (container *Container) copyImagePathContent(v volume.Volume, destination string) error { 1108 rootfs, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, destination), container.basefs) 1109 if err != nil { 1110 return err 1111 } 1112 1113 if _, err = ioutil.ReadDir(rootfs); err != nil { 1114 if os.IsNotExist(err) { 1115 return nil 1116 } 1117 return err 1118 } 1119 1120 path, err := v.Mount() 1121 if err != nil { 1122 return err 1123 } 1124 1125 if err := copyExistingContents(rootfs, path); err != nil { 1126 return err 1127 } 1128 1129 return v.Unmount() 1130 } 1131 1132 func (container *Container) stopSignal() int { 1133 var stopSignal syscall.Signal 1134 if container.Config.StopSignal != "" { 1135 stopSignal, _ = signal.ParseSignal(container.Config.StopSignal) 1136 } 1137 1138 if int(stopSignal) == 0 { 1139 stopSignal, _ = signal.ParseSignal(signal.DefaultStopSignal) 1140 } 1141 return int(stopSignal) 1142 }