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