github.com/fcwu/docker@v1.4.2-0.20150115145920-2a69ca89f0df/daemon/container.go (about) 1 package daemon 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "os" 11 "path" 12 "path/filepath" 13 "strings" 14 "syscall" 15 "time" 16 17 "github.com/docker/libcontainer/devices" 18 "github.com/docker/libcontainer/label" 19 20 log "github.com/Sirupsen/logrus" 21 "github.com/docker/docker/daemon/execdriver" 22 "github.com/docker/docker/engine" 23 "github.com/docker/docker/image" 24 "github.com/docker/docker/links" 25 "github.com/docker/docker/nat" 26 "github.com/docker/docker/pkg/archive" 27 "github.com/docker/docker/pkg/broadcastwriter" 28 "github.com/docker/docker/pkg/ioutils" 29 "github.com/docker/docker/pkg/networkfs/etchosts" 30 "github.com/docker/docker/pkg/networkfs/resolvconf" 31 "github.com/docker/docker/pkg/promise" 32 "github.com/docker/docker/pkg/symlink" 33 "github.com/docker/docker/runconfig" 34 "github.com/docker/docker/utils" 35 ) 36 37 const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 38 39 var ( 40 ErrNotATTY = errors.New("The PTY is not a file") 41 ErrNoTTY = errors.New("No PTY found") 42 ErrContainerStart = errors.New("The container failed to start. Unknown error") 43 ErrContainerStartTimeout = errors.New("The container failed to start due to timed out.") 44 ) 45 46 type StreamConfig struct { 47 stdout *broadcastwriter.BroadcastWriter 48 stderr *broadcastwriter.BroadcastWriter 49 stdin io.ReadCloser 50 stdinPipe io.WriteCloser 51 } 52 53 type Container struct { 54 *State `json:"State"` // Needed for remote api version <= 1.11 55 root string // Path to the "home" of the container, including metadata. 56 basefs string // Path to the graphdriver mountpoint 57 58 ID string 59 60 Created time.Time 61 62 Path string 63 Args []string 64 65 Config *runconfig.Config 66 ImageID string `json:"Image"` 67 68 NetworkSettings *NetworkSettings 69 70 ResolvConfPath string 71 HostnamePath string 72 HostsPath string 73 Name string 74 Driver string 75 ExecDriver string 76 77 command *execdriver.Command 78 StreamConfig 79 80 daemon *Daemon 81 MountLabel, ProcessLabel string 82 AppArmorProfile string 83 RestartCount int 84 85 // Maps container paths to volume paths. The key in this is the path to which 86 // the volume is being mounted inside the container. Value is the path of the 87 // volume on disk 88 Volumes map[string]string 89 // Store rw/ro in a separate structure to preserve reverse-compatibility on-disk. 90 // Easier than migrating older container configs :) 91 VolumesRW map[string]bool 92 hostConfig *runconfig.HostConfig 93 94 activeLinks map[string]*links.Link 95 monitor *containerMonitor 96 execCommands *execStore 97 } 98 99 func (container *Container) FromDisk() error { 100 pth, err := container.jsonPath() 101 if err != nil { 102 return err 103 } 104 105 jsonSource, err := os.Open(pth) 106 if err != nil { 107 return err 108 } 109 defer jsonSource.Close() 110 111 dec := json.NewDecoder(jsonSource) 112 113 // Load container settings 114 // udp broke compat of docker.PortMapping, but it's not used when loading a container, we can skip it 115 if err := dec.Decode(container); err != nil && !strings.Contains(err.Error(), "docker.PortMapping") { 116 return err 117 } 118 119 if err := label.ReserveLabel(container.ProcessLabel); err != nil { 120 return err 121 } 122 return container.readHostConfig() 123 } 124 125 func (container *Container) toDisk() error { 126 data, err := json.Marshal(container) 127 if err != nil { 128 return err 129 } 130 131 pth, err := container.jsonPath() 132 if err != nil { 133 return err 134 } 135 136 err = ioutil.WriteFile(pth, data, 0666) 137 if err != nil { 138 return err 139 } 140 141 return container.WriteHostConfig() 142 } 143 144 func (container *Container) ToDisk() error { 145 container.Lock() 146 err := container.toDisk() 147 container.Unlock() 148 return err 149 } 150 151 func (container *Container) readHostConfig() error { 152 container.hostConfig = &runconfig.HostConfig{} 153 // If the hostconfig file does not exist, do not read it. 154 // (We still have to initialize container.hostConfig, 155 // but that's OK, since we just did that above.) 156 pth, err := container.hostConfigPath() 157 if err != nil { 158 return err 159 } 160 161 _, err = os.Stat(pth) 162 if os.IsNotExist(err) { 163 return nil 164 } 165 166 data, err := ioutil.ReadFile(pth) 167 if err != nil { 168 return err 169 } 170 return json.Unmarshal(data, container.hostConfig) 171 } 172 173 func (container *Container) WriteHostConfig() error { 174 data, err := json.Marshal(container.hostConfig) 175 if err != nil { 176 return err 177 } 178 179 pth, err := container.hostConfigPath() 180 if err != nil { 181 return err 182 } 183 184 return ioutil.WriteFile(pth, data, 0666) 185 } 186 187 func (container *Container) LogEvent(action string) { 188 d := container.daemon 189 if err := d.eng.Job("log", action, container.ID, d.Repositories().ImageName(container.ImageID)).Run(); err != nil { 190 log.Errorf("Error logging event %s for %s: %s", action, container.ID, err) 191 } 192 } 193 194 func (container *Container) getResourcePath(path string) (string, error) { 195 cleanPath := filepath.Join("/", path) 196 return symlink.FollowSymlinkInScope(filepath.Join(container.basefs, cleanPath), container.basefs) 197 } 198 199 func (container *Container) getRootResourcePath(path string) (string, error) { 200 cleanPath := filepath.Join("/", path) 201 return symlink.FollowSymlinkInScope(filepath.Join(container.root, cleanPath), container.root) 202 } 203 204 func populateCommand(c *Container, env []string) error { 205 en := &execdriver.Network{ 206 Mtu: c.daemon.config.Mtu, 207 Interface: nil, 208 } 209 210 parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2) 211 switch parts[0] { 212 case "none": 213 case "host": 214 en.HostNetworking = true 215 case "bridge", "": // empty string to support existing containers 216 if !c.Config.NetworkDisabled { 217 network := c.NetworkSettings 218 en.Interface = &execdriver.NetworkInterface{ 219 Gateway: network.Gateway, 220 Bridge: network.Bridge, 221 IPAddress: network.IPAddress, 222 IPPrefixLen: network.IPPrefixLen, 223 MacAddress: network.MacAddress, 224 } 225 } 226 case "container": 227 nc, err := c.getNetworkedContainer() 228 if err != nil { 229 return err 230 } 231 en.ContainerID = nc.ID 232 default: 233 return fmt.Errorf("invalid network mode: %s", c.hostConfig.NetworkMode) 234 } 235 236 ipc := &execdriver.Ipc{} 237 238 if c.hostConfig.IpcMode.IsContainer() { 239 ic, err := c.getIpcContainer() 240 if err != nil { 241 return err 242 } 243 ipc.ContainerID = ic.ID 244 } else { 245 ipc.HostIpc = c.hostConfig.IpcMode.IsHost() 246 } 247 248 // Build lists of devices allowed and created within the container. 249 userSpecifiedDevices := make([]*devices.Device, len(c.hostConfig.Devices)) 250 for i, deviceMapping := range c.hostConfig.Devices { 251 device, err := devices.GetDevice(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions) 252 if err != nil { 253 return fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err) 254 } 255 device.Path = deviceMapping.PathInContainer 256 userSpecifiedDevices[i] = device 257 } 258 allowedDevices := append(devices.DefaultAllowedDevices, userSpecifiedDevices...) 259 260 autoCreatedDevices := append(devices.DefaultAutoCreatedDevices, userSpecifiedDevices...) 261 262 // TODO: this can be removed after lxc-conf is fully deprecated 263 lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig) 264 if err != nil { 265 return err 266 } 267 268 resources := &execdriver.Resources{ 269 Memory: c.Config.Memory, 270 MemorySwap: c.Config.MemorySwap, 271 CpuShares: c.Config.CpuShares, 272 Cpuset: c.Config.Cpuset, 273 } 274 275 processConfig := execdriver.ProcessConfig{ 276 Privileged: c.hostConfig.Privileged, 277 Entrypoint: c.Path, 278 Arguments: c.Args, 279 Tty: c.Config.Tty, 280 User: c.Config.User, 281 } 282 283 processConfig.SysProcAttr = &syscall.SysProcAttr{Setsid: true} 284 processConfig.Env = env 285 286 c.command = &execdriver.Command{ 287 ID: c.ID, 288 Rootfs: c.RootfsPath(), 289 InitPath: "/.dockerinit", 290 WorkingDir: c.Config.WorkingDir, 291 Network: en, 292 Ipc: ipc, 293 Resources: resources, 294 AllowedDevices: allowedDevices, 295 AutoCreatedDevices: autoCreatedDevices, 296 CapAdd: c.hostConfig.CapAdd, 297 CapDrop: c.hostConfig.CapDrop, 298 ProcessConfig: processConfig, 299 ProcessLabel: c.GetProcessLabel(), 300 MountLabel: c.GetMountLabel(), 301 LxcConfig: lxcConfig, 302 AppArmorProfile: c.AppArmorProfile, 303 } 304 305 return nil 306 } 307 308 func (container *Container) Start() (err error) { 309 container.Lock() 310 defer container.Unlock() 311 312 if container.Running { 313 return nil 314 } 315 316 // if we encounter and error during start we need to ensure that any other 317 // setup has been cleaned up properly 318 defer func() { 319 if err != nil { 320 container.setError(err) 321 // if no one else has set it, make sure we don't leave it at zero 322 if container.ExitCode == 0 { 323 container.ExitCode = 128 324 } 325 container.toDisk() 326 container.cleanup() 327 } 328 }() 329 330 if err := container.setupContainerDns(); err != nil { 331 return err 332 } 333 if err := container.Mount(); err != nil { 334 return err 335 } 336 if err := container.initializeNetworking(); err != nil { 337 return err 338 } 339 if err := container.updateParentsHosts(); err != nil { 340 return err 341 } 342 container.verifyDaemonSettings() 343 if err := container.prepareVolumes(); err != nil { 344 return err 345 } 346 linkedEnv, err := container.setupLinkedContainers() 347 if err != nil { 348 return err 349 } 350 if err := container.setupWorkingDirectory(); err != nil { 351 return err 352 } 353 env := container.createDaemonEnvironment(linkedEnv) 354 if err := populateCommand(container, env); err != nil { 355 return err 356 } 357 if err := container.setupMounts(); err != nil { 358 return err 359 } 360 361 return container.waitForStart() 362 } 363 364 func (container *Container) Run() error { 365 if err := container.Start(); err != nil { 366 return err 367 } 368 container.WaitStop(-1 * time.Second) 369 return nil 370 } 371 372 func (container *Container) Output() (output []byte, err error) { 373 pipe := container.StdoutPipe() 374 defer pipe.Close() 375 if err := container.Start(); err != nil { 376 return nil, err 377 } 378 output, err = ioutil.ReadAll(pipe) 379 container.WaitStop(-1 * time.Second) 380 return output, err 381 } 382 383 // StreamConfig.StdinPipe returns a WriteCloser which can be used to feed data 384 // to the standard input of the container's active process. 385 // Container.StdoutPipe and Container.StderrPipe each return a ReadCloser 386 // which can be used to retrieve the standard output (and error) generated 387 // by the container's active process. The output (and error) are actually 388 // copied and delivered to all StdoutPipe and StderrPipe consumers, using 389 // a kind of "broadcaster". 390 391 func (streamConfig *StreamConfig) StdinPipe() io.WriteCloser { 392 return streamConfig.stdinPipe 393 } 394 395 func (streamConfig *StreamConfig) StdoutPipe() io.ReadCloser { 396 reader, writer := io.Pipe() 397 streamConfig.stdout.AddWriter(writer, "") 398 return ioutils.NewBufReader(reader) 399 } 400 401 func (streamConfig *StreamConfig) StderrPipe() io.ReadCloser { 402 reader, writer := io.Pipe() 403 streamConfig.stderr.AddWriter(writer, "") 404 return ioutils.NewBufReader(reader) 405 } 406 407 func (streamConfig *StreamConfig) StdoutLogPipe() io.ReadCloser { 408 reader, writer := io.Pipe() 409 streamConfig.stdout.AddWriter(writer, "stdout") 410 return ioutils.NewBufReader(reader) 411 } 412 413 func (streamConfig *StreamConfig) StderrLogPipe() io.ReadCloser { 414 reader, writer := io.Pipe() 415 streamConfig.stderr.AddWriter(writer, "stderr") 416 return ioutils.NewBufReader(reader) 417 } 418 419 func (container *Container) buildHostnameFile() error { 420 hostnamePath, err := container.getRootResourcePath("hostname") 421 if err != nil { 422 return err 423 } 424 container.HostnamePath = hostnamePath 425 426 if container.Config.Domainname != "" { 427 return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644) 428 } 429 return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) 430 } 431 432 func (container *Container) buildHostsFiles(IP string) error { 433 434 hostsPath, err := container.getRootResourcePath("hosts") 435 if err != nil { 436 return err 437 } 438 container.HostsPath = hostsPath 439 440 var extraContent []etchosts.Record 441 442 children, err := container.daemon.Children(container.Name) 443 if err != nil { 444 return err 445 } 446 447 for linkAlias, child := range children { 448 _, alias := path.Split(linkAlias) 449 extraContent = append(extraContent, etchosts.Record{Hosts: alias, IP: child.NetworkSettings.IPAddress}) 450 } 451 452 for _, extraHost := range container.hostConfig.ExtraHosts { 453 parts := strings.Split(extraHost, ":") 454 extraContent = append(extraContent, etchosts.Record{Hosts: parts[0], IP: parts[1]}) 455 } 456 457 return etchosts.Build(container.HostsPath, IP, container.Config.Hostname, container.Config.Domainname, extraContent) 458 } 459 460 func (container *Container) buildHostnameAndHostsFiles(IP string) error { 461 if err := container.buildHostnameFile(); err != nil { 462 return err 463 } 464 465 return container.buildHostsFiles(IP) 466 } 467 468 func (container *Container) AllocateNetwork() error { 469 mode := container.hostConfig.NetworkMode 470 if container.Config.NetworkDisabled || !mode.IsPrivate() { 471 return nil 472 } 473 474 var ( 475 env *engine.Env 476 err error 477 eng = container.daemon.eng 478 ) 479 480 job := eng.Job("allocate_interface", container.ID) 481 job.Setenv("RequestedMac", container.Config.MacAddress) 482 if env, err = job.Stdout.AddEnv(); err != nil { 483 return err 484 } 485 if err = job.Run(); err != nil { 486 return err 487 } 488 489 // Error handling: At this point, the interface is allocated so we have to 490 // make sure that it is always released in case of error, otherwise we 491 // might leak resources. 492 493 if container.Config.PortSpecs != nil { 494 if err = migratePortMappings(container.Config, container.hostConfig); err != nil { 495 eng.Job("release_interface", container.ID).Run() 496 return err 497 } 498 container.Config.PortSpecs = nil 499 if err = container.WriteHostConfig(); err != nil { 500 eng.Job("release_interface", container.ID).Run() 501 return err 502 } 503 } 504 505 var ( 506 portSpecs = make(nat.PortSet) 507 bindings = make(nat.PortMap) 508 ) 509 510 if container.Config.ExposedPorts != nil { 511 portSpecs = container.Config.ExposedPorts 512 } 513 514 if container.hostConfig.PortBindings != nil { 515 for p, b := range container.hostConfig.PortBindings { 516 bindings[p] = []nat.PortBinding{} 517 for _, bb := range b { 518 bindings[p] = append(bindings[p], nat.PortBinding{ 519 HostIp: bb.HostIp, 520 HostPort: bb.HostPort, 521 }) 522 } 523 } 524 } 525 526 container.NetworkSettings.PortMapping = nil 527 528 for port := range portSpecs { 529 if err = container.allocatePort(eng, port, bindings); err != nil { 530 eng.Job("release_interface", container.ID).Run() 531 return err 532 } 533 } 534 container.WriteHostConfig() 535 536 container.NetworkSettings.Ports = bindings 537 container.NetworkSettings.Bridge = env.Get("Bridge") 538 container.NetworkSettings.IPAddress = env.Get("IP") 539 container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen") 540 container.NetworkSettings.MacAddress = env.Get("MacAddress") 541 container.NetworkSettings.Gateway = env.Get("Gateway") 542 543 return nil 544 } 545 546 func (container *Container) ReleaseNetwork() { 547 if container.Config.NetworkDisabled || !container.hostConfig.NetworkMode.IsPrivate() { 548 return 549 } 550 eng := container.daemon.eng 551 552 job := eng.Job("release_interface", container.ID) 553 job.SetenvBool("overrideShutdown", true) 554 job.Run() 555 container.NetworkSettings = &NetworkSettings{} 556 } 557 558 func (container *Container) isNetworkAllocated() bool { 559 return container.NetworkSettings.IPAddress != "" 560 } 561 562 func (container *Container) RestoreNetwork() error { 563 mode := container.hostConfig.NetworkMode 564 // Don't attempt a restore if we previously didn't allocate networking. 565 // This might be a legacy container with no network allocated, in which case the 566 // allocation will happen once and for all at start. 567 if !container.isNetworkAllocated() || container.Config.NetworkDisabled || !mode.IsPrivate() { 568 return nil 569 } 570 571 eng := container.daemon.eng 572 573 // Re-allocate the interface with the same IP and MAC address. 574 job := eng.Job("allocate_interface", container.ID) 575 job.Setenv("RequestedIP", container.NetworkSettings.IPAddress) 576 job.Setenv("RequestedMac", container.NetworkSettings.MacAddress) 577 if err := job.Run(); err != nil { 578 return err 579 } 580 581 // Re-allocate any previously allocated ports. 582 for port := range container.NetworkSettings.Ports { 583 if err := container.allocatePort(eng, port, container.NetworkSettings.Ports); err != nil { 584 return err 585 } 586 } 587 return nil 588 } 589 590 // cleanup releases any network resources allocated to the container along with any rules 591 // around how containers are linked together. It also unmounts the container's root filesystem. 592 func (container *Container) cleanup() { 593 container.ReleaseNetwork() 594 595 // Disable all active links 596 if container.activeLinks != nil { 597 for _, link := range container.activeLinks { 598 link.Disable() 599 } 600 } 601 602 if err := container.Unmount(); err != nil { 603 log.Errorf("%v: Failed to umount filesystem: %v", container.ID, err) 604 } 605 606 for _, eConfig := range container.execCommands.s { 607 container.daemon.unregisterExecCommand(eConfig) 608 } 609 } 610 611 func (container *Container) KillSig(sig int) error { 612 log.Debugf("Sending %d to %s", sig, container.ID) 613 container.Lock() 614 defer container.Unlock() 615 616 // We could unpause the container for them rather than returning this error 617 if container.Paused { 618 return fmt.Errorf("Container %s is paused. Unpause the container before stopping", container.ID) 619 } 620 621 if !container.Running { 622 return nil 623 } 624 625 // signal to the monitor that it should not restart the container 626 // after we send the kill signal 627 container.monitor.ExitOnNext() 628 629 // if the container is currently restarting we do not need to send the signal 630 // to the process. Telling the monitor that it should exit on it's next event 631 // loop is enough 632 if container.Restarting { 633 return nil 634 } 635 636 return container.daemon.Kill(container, sig) 637 } 638 639 func (container *Container) Pause() error { 640 if container.IsPaused() { 641 return fmt.Errorf("Container %s is already paused", container.ID) 642 } 643 if !container.IsRunning() { 644 return fmt.Errorf("Container %s is not running", container.ID) 645 } 646 return container.daemon.Pause(container) 647 } 648 649 func (container *Container) Unpause() error { 650 if !container.IsPaused() { 651 return fmt.Errorf("Container %s is not paused", container.ID) 652 } 653 if !container.IsRunning() { 654 return fmt.Errorf("Container %s is not running", container.ID) 655 } 656 return container.daemon.Unpause(container) 657 } 658 659 func (container *Container) Kill() error { 660 if !container.IsRunning() { 661 return nil 662 } 663 664 // 1. Send SIGKILL 665 if err := container.KillSig(9); err != nil { 666 return err 667 } 668 669 // 2. Wait for the process to die, in last resort, try to kill the process directly 670 if _, err := container.WaitStop(10 * time.Second); err != nil { 671 // Ensure that we don't kill ourselves 672 if pid := container.GetPid(); pid != 0 { 673 log.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", utils.TruncateID(container.ID)) 674 if err := syscall.Kill(pid, 9); err != nil { 675 return err 676 } 677 } 678 } 679 680 container.WaitStop(-1 * time.Second) 681 return nil 682 } 683 684 func (container *Container) Stop(seconds int) error { 685 if !container.IsRunning() { 686 return nil 687 } 688 689 // 1. Send a SIGTERM 690 if err := container.KillSig(15); err != nil { 691 log.Infof("Failed to send SIGTERM to the process, force killing") 692 if err := container.KillSig(9); err != nil { 693 return err 694 } 695 } 696 697 // 2. Wait for the process to exit on its own 698 if _, err := container.WaitStop(time.Duration(seconds) * time.Second); err != nil { 699 log.Infof("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds) 700 // 3. If it doesn't, then send SIGKILL 701 if err := container.Kill(); err != nil { 702 container.WaitStop(-1 * time.Second) 703 return err 704 } 705 } 706 return nil 707 } 708 709 func (container *Container) Restart(seconds int) error { 710 // Avoid unnecessarily unmounting and then directly mounting 711 // the container when the container stops and then starts 712 // again 713 if err := container.Mount(); err == nil { 714 defer container.Unmount() 715 } 716 717 if err := container.Stop(seconds); err != nil { 718 return err 719 } 720 return container.Start() 721 } 722 723 func (container *Container) Resize(h, w int) error { 724 if !container.IsRunning() { 725 return fmt.Errorf("Cannot resize container %s, container is not running", container.ID) 726 } 727 return container.command.ProcessConfig.Terminal.Resize(h, w) 728 } 729 730 func (container *Container) ExportRw() (archive.Archive, error) { 731 if err := container.Mount(); err != nil { 732 return nil, err 733 } 734 if container.daemon == nil { 735 return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID) 736 } 737 archive, err := container.daemon.Diff(container) 738 if err != nil { 739 container.Unmount() 740 return nil, err 741 } 742 return ioutils.NewReadCloserWrapper(archive, func() error { 743 err := archive.Close() 744 container.Unmount() 745 return err 746 }), 747 nil 748 } 749 750 func (container *Container) Export() (archive.Archive, error) { 751 if err := container.Mount(); err != nil { 752 return nil, err 753 } 754 755 archive, err := archive.Tar(container.basefs, archive.Uncompressed) 756 if err != nil { 757 container.Unmount() 758 return nil, err 759 } 760 return ioutils.NewReadCloserWrapper(archive, func() error { 761 err := archive.Close() 762 container.Unmount() 763 return err 764 }), 765 nil 766 } 767 768 func (container *Container) Mount() error { 769 return container.daemon.Mount(container) 770 } 771 772 func (container *Container) changes() ([]archive.Change, error) { 773 return container.daemon.Changes(container) 774 } 775 776 func (container *Container) Changes() ([]archive.Change, error) { 777 container.Lock() 778 defer container.Unlock() 779 return container.changes() 780 } 781 782 func (container *Container) GetImage() (*image.Image, error) { 783 if container.daemon == nil { 784 return nil, fmt.Errorf("Can't get image of unregistered container") 785 } 786 return container.daemon.graph.Get(container.ImageID) 787 } 788 789 func (container *Container) Unmount() error { 790 return container.daemon.Unmount(container) 791 } 792 793 func (container *Container) logPath(name string) (string, error) { 794 return container.getRootResourcePath(fmt.Sprintf("%s-%s.log", container.ID, name)) 795 } 796 797 func (container *Container) ReadLog(name string) (io.Reader, error) { 798 pth, err := container.logPath(name) 799 if err != nil { 800 return nil, err 801 } 802 return os.Open(pth) 803 } 804 805 func (container *Container) hostConfigPath() (string, error) { 806 return container.getRootResourcePath("hostconfig.json") 807 } 808 809 func (container *Container) jsonPath() (string, error) { 810 return container.getRootResourcePath("config.json") 811 } 812 813 // This method must be exported to be used from the lxc template 814 // This directory is only usable when the container is running 815 func (container *Container) RootfsPath() string { 816 return container.basefs 817 } 818 819 func validateID(id string) error { 820 if id == "" { 821 return fmt.Errorf("Invalid empty id") 822 } 823 return nil 824 } 825 826 // GetSize, return real size, virtual size 827 func (container *Container) GetSize() (int64, int64) { 828 var ( 829 sizeRw, sizeRootfs int64 830 err error 831 driver = container.daemon.driver 832 ) 833 834 if err := container.Mount(); err != nil { 835 log.Errorf("Warning: failed to compute size of container rootfs %s: %s", container.ID, err) 836 return sizeRw, sizeRootfs 837 } 838 defer container.Unmount() 839 840 initID := fmt.Sprintf("%s-init", container.ID) 841 sizeRw, err = driver.DiffSize(container.ID, initID) 842 if err != nil { 843 log.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err) 844 // FIXME: GetSize should return an error. Not changing it now in case 845 // there is a side-effect. 846 sizeRw = -1 847 } 848 849 if _, err = os.Stat(container.basefs); err != nil { 850 if sizeRootfs, err = utils.TreeSize(container.basefs); err != nil { 851 sizeRootfs = -1 852 } 853 } 854 return sizeRw, sizeRootfs 855 } 856 857 func (container *Container) Copy(resource string) (io.ReadCloser, error) { 858 if err := container.Mount(); err != nil { 859 return nil, err 860 } 861 862 basePath, err := container.getResourcePath(resource) 863 if err != nil { 864 container.Unmount() 865 return nil, err 866 } 867 868 // Check if this is actually in a volume 869 for _, mnt := range container.VolumeMounts() { 870 if len(mnt.MountToPath) > 0 && strings.HasPrefix(resource, mnt.MountToPath[1:]) { 871 return mnt.Export(resource) 872 } 873 } 874 875 stat, err := os.Stat(basePath) 876 if err != nil { 877 container.Unmount() 878 return nil, err 879 } 880 var filter []string 881 if !stat.IsDir() { 882 d, f := path.Split(basePath) 883 basePath = d 884 filter = []string{f} 885 } else { 886 filter = []string{path.Base(basePath)} 887 basePath = path.Dir(basePath) 888 } 889 890 archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{ 891 Compression: archive.Uncompressed, 892 IncludeFiles: filter, 893 }) 894 if err != nil { 895 container.Unmount() 896 return nil, err 897 } 898 return ioutils.NewReadCloserWrapper(archive, func() error { 899 err := archive.Close() 900 container.Unmount() 901 return err 902 }), 903 nil 904 } 905 906 // Returns true if the container exposes a certain port 907 func (container *Container) Exposes(p nat.Port) bool { 908 _, exists := container.Config.ExposedPorts[p] 909 return exists 910 } 911 912 func (container *Container) GetPtyMaster() (*os.File, error) { 913 ttyConsole, ok := container.command.ProcessConfig.Terminal.(execdriver.TtyTerminal) 914 if !ok { 915 return nil, ErrNoTTY 916 } 917 return ttyConsole.Master(), nil 918 } 919 920 func (container *Container) HostConfig() *runconfig.HostConfig { 921 container.Lock() 922 res := container.hostConfig 923 container.Unlock() 924 return res 925 } 926 927 func (container *Container) SetHostConfig(hostConfig *runconfig.HostConfig) { 928 container.Lock() 929 container.hostConfig = hostConfig 930 container.Unlock() 931 } 932 933 func (container *Container) DisableLink(name string) { 934 if container.activeLinks != nil { 935 if link, exists := container.activeLinks[name]; exists { 936 link.Disable() 937 } else { 938 log.Debugf("Could not find active link for %s", name) 939 } 940 } 941 } 942 943 func (container *Container) setupContainerDns() error { 944 if container.ResolvConfPath != "" { 945 return nil 946 } 947 948 var ( 949 config = container.hostConfig 950 daemon = container.daemon 951 ) 952 953 resolvConf, err := resolvconf.Get() 954 if err != nil { 955 return err 956 } 957 container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf") 958 if err != nil { 959 return err 960 } 961 962 if config.NetworkMode != "host" { 963 // check configurations for any container/daemon dns settings 964 if len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0 { 965 var ( 966 dns = resolvconf.GetNameservers(resolvConf) 967 dnsSearch = resolvconf.GetSearchDomains(resolvConf) 968 ) 969 if len(config.Dns) > 0 { 970 dns = config.Dns 971 } else if len(daemon.config.Dns) > 0 { 972 dns = daemon.config.Dns 973 } 974 if len(config.DnsSearch) > 0 { 975 dnsSearch = config.DnsSearch 976 } else if len(daemon.config.DnsSearch) > 0 { 977 dnsSearch = daemon.config.DnsSearch 978 } 979 return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch) 980 } 981 982 // replace any localhost/127.* nameservers 983 resolvConf = utils.RemoveLocalDns(resolvConf) 984 // if the resulting resolvConf is empty, use DefaultDns 985 if !bytes.Contains(resolvConf, []byte("nameserver")) { 986 log.Infof("No non localhost DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v", DefaultDns) 987 // prefix the default dns options with nameserver 988 resolvConf = append(resolvConf, []byte("\nnameserver "+strings.Join(DefaultDns, "\nnameserver "))...) 989 } 990 } 991 return ioutil.WriteFile(container.ResolvConfPath, resolvConf, 0644) 992 } 993 994 func (container *Container) updateParentsHosts() error { 995 parents, err := container.daemon.Parents(container.Name) 996 if err != nil { 997 return err 998 } 999 for _, cid := range parents { 1000 if cid == "0" { 1001 continue 1002 } 1003 1004 c := container.daemon.Get(cid) 1005 if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() { 1006 if err := etchosts.Update(c.HostsPath, container.NetworkSettings.IPAddress, container.Name[1:]); err != nil { 1007 log.Errorf("Failed to update /etc/hosts in parent container: %v", err) 1008 } 1009 } 1010 } 1011 return nil 1012 } 1013 1014 func (container *Container) initializeNetworking() error { 1015 var err error 1016 if container.hostConfig.NetworkMode.IsHost() { 1017 container.Config.Hostname, err = os.Hostname() 1018 if err != nil { 1019 return err 1020 } 1021 1022 parts := strings.SplitN(container.Config.Hostname, ".", 2) 1023 if len(parts) > 1 { 1024 container.Config.Hostname = parts[0] 1025 container.Config.Domainname = parts[1] 1026 } 1027 1028 content, err := ioutil.ReadFile("/etc/hosts") 1029 if os.IsNotExist(err) { 1030 return container.buildHostnameAndHostsFiles("") 1031 } else if err != nil { 1032 return err 1033 } 1034 1035 if err := container.buildHostnameFile(); err != nil { 1036 return err 1037 } 1038 1039 hostsPath, err := container.getRootResourcePath("hosts") 1040 if err != nil { 1041 return err 1042 } 1043 container.HostsPath = hostsPath 1044 1045 return ioutil.WriteFile(container.HostsPath, content, 0644) 1046 } 1047 if container.hostConfig.NetworkMode.IsContainer() { 1048 // we need to get the hosts files from the container to join 1049 nc, err := container.getNetworkedContainer() 1050 if err != nil { 1051 return err 1052 } 1053 container.HostsPath = nc.HostsPath 1054 container.ResolvConfPath = nc.ResolvConfPath 1055 container.Config.Hostname = nc.Config.Hostname 1056 container.Config.Domainname = nc.Config.Domainname 1057 return nil 1058 } 1059 if container.daemon.config.DisableNetwork { 1060 container.Config.NetworkDisabled = true 1061 return container.buildHostnameAndHostsFiles("127.0.1.1") 1062 } 1063 if err := container.AllocateNetwork(); err != nil { 1064 return err 1065 } 1066 return container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress) 1067 } 1068 1069 // Make sure the config is compatible with the current kernel 1070 func (container *Container) verifyDaemonSettings() { 1071 if container.Config.Memory > 0 && !container.daemon.sysInfo.MemoryLimit { 1072 log.Infof("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.") 1073 container.Config.Memory = 0 1074 } 1075 if container.Config.Memory > 0 && !container.daemon.sysInfo.SwapLimit { 1076 log.Infof("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.") 1077 container.Config.MemorySwap = -1 1078 } 1079 if container.daemon.sysInfo.IPv4ForwardingDisabled { 1080 log.Infof("WARNING: IPv4 forwarding is disabled. Networking will not work") 1081 } 1082 } 1083 1084 func (container *Container) setupLinkedContainers() ([]string, error) { 1085 var ( 1086 env []string 1087 daemon = container.daemon 1088 ) 1089 children, err := daemon.Children(container.Name) 1090 if err != nil { 1091 return nil, err 1092 } 1093 1094 if len(children) > 0 { 1095 container.activeLinks = make(map[string]*links.Link, len(children)) 1096 1097 // If we encounter an error make sure that we rollback any network 1098 // config and ip table changes 1099 rollback := func() { 1100 for _, link := range container.activeLinks { 1101 link.Disable() 1102 } 1103 container.activeLinks = nil 1104 } 1105 1106 for linkAlias, child := range children { 1107 if !child.IsRunning() { 1108 return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias) 1109 } 1110 1111 link, err := links.NewLink( 1112 container.NetworkSettings.IPAddress, 1113 child.NetworkSettings.IPAddress, 1114 linkAlias, 1115 child.Config.Env, 1116 child.Config.ExposedPorts, 1117 daemon.eng) 1118 1119 if err != nil { 1120 rollback() 1121 return nil, err 1122 } 1123 1124 container.activeLinks[link.Alias()] = link 1125 if err := link.Enable(); err != nil { 1126 rollback() 1127 return nil, err 1128 } 1129 1130 for _, envVar := range link.ToEnv() { 1131 env = append(env, envVar) 1132 } 1133 } 1134 } 1135 return env, nil 1136 } 1137 1138 func (container *Container) createDaemonEnvironment(linkedEnv []string) []string { 1139 // if a domain name was specified, append it to the hostname (see #7851) 1140 fullHostname := container.Config.Hostname 1141 if container.Config.Domainname != "" { 1142 fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname) 1143 } 1144 // Setup environment 1145 env := []string{ 1146 "PATH=" + DefaultPathEnv, 1147 "HOSTNAME=" + fullHostname, 1148 // Note: we don't set HOME here because it'll get autoset intelligently 1149 // based on the value of USER inside dockerinit, but only if it isn't 1150 // set already (ie, that can be overridden by setting HOME via -e or ENV 1151 // in a Dockerfile). 1152 } 1153 if container.Config.Tty { 1154 env = append(env, "TERM=xterm") 1155 } 1156 env = append(env, linkedEnv...) 1157 // because the env on the container can override certain default values 1158 // we need to replace the 'env' keys where they match and append anything 1159 // else. 1160 env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env) 1161 1162 return env 1163 } 1164 1165 func (container *Container) setupWorkingDirectory() error { 1166 if container.Config.WorkingDir != "" { 1167 container.Config.WorkingDir = path.Clean(container.Config.WorkingDir) 1168 1169 pth, err := container.getResourcePath(container.Config.WorkingDir) 1170 if err != nil { 1171 return err 1172 } 1173 1174 pthInfo, err := os.Stat(pth) 1175 if err != nil { 1176 if !os.IsNotExist(err) { 1177 return err 1178 } 1179 1180 if err := os.MkdirAll(pth, 0755); err != nil { 1181 return err 1182 } 1183 } 1184 if pthInfo != nil && !pthInfo.IsDir() { 1185 return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir) 1186 } 1187 } 1188 return nil 1189 } 1190 1191 func (container *Container) startLoggingToDisk() error { 1192 // Setup logging of stdout and stderr to disk 1193 pth, err := container.logPath("json") 1194 if err != nil { 1195 return err 1196 } 1197 1198 if err := container.daemon.LogToDisk(container.stdout, pth, "stdout"); err != nil { 1199 return err 1200 } 1201 1202 if err := container.daemon.LogToDisk(container.stderr, pth, "stderr"); err != nil { 1203 return err 1204 } 1205 1206 return nil 1207 } 1208 1209 func (container *Container) waitForStart() error { 1210 container.monitor = newContainerMonitor(container, container.hostConfig.RestartPolicy) 1211 1212 // block until we either receive an error from the initial start of the container's 1213 // process or until the process is running in the container 1214 select { 1215 case <-container.monitor.startSignal: 1216 case err := <-promise.Go(container.monitor.Start): 1217 return err 1218 } 1219 1220 return nil 1221 } 1222 1223 func (container *Container) allocatePort(eng *engine.Engine, port nat.Port, bindings nat.PortMap) error { 1224 binding := bindings[port] 1225 if container.hostConfig.PublishAllPorts && len(binding) == 0 { 1226 binding = append(binding, nat.PortBinding{}) 1227 } 1228 1229 for i := 0; i < len(binding); i++ { 1230 b := binding[i] 1231 1232 job := eng.Job("allocate_port", container.ID) 1233 job.Setenv("HostIP", b.HostIp) 1234 job.Setenv("HostPort", b.HostPort) 1235 job.Setenv("Proto", port.Proto()) 1236 job.Setenv("ContainerPort", port.Port()) 1237 1238 portEnv, err := job.Stdout.AddEnv() 1239 if err != nil { 1240 return err 1241 } 1242 if err := job.Run(); err != nil { 1243 return err 1244 } 1245 b.HostIp = portEnv.Get("HostIP") 1246 b.HostPort = portEnv.Get("HostPort") 1247 1248 binding[i] = b 1249 } 1250 bindings[port] = binding 1251 return nil 1252 } 1253 1254 func (container *Container) GetProcessLabel() string { 1255 // even if we have a process label return "" if we are running 1256 // in privileged mode 1257 if container.hostConfig.Privileged { 1258 return "" 1259 } 1260 return container.ProcessLabel 1261 } 1262 1263 func (container *Container) GetMountLabel() string { 1264 if container.hostConfig.Privileged { 1265 return "" 1266 } 1267 return container.MountLabel 1268 } 1269 1270 func (container *Container) getIpcContainer() (*Container, error) { 1271 containerID := container.hostConfig.IpcMode.Container() 1272 c := container.daemon.Get(containerID) 1273 if c == nil { 1274 return nil, fmt.Errorf("no such container to join IPC: %s", containerID) 1275 } 1276 if !c.IsRunning() { 1277 return nil, fmt.Errorf("cannot join IPC of a non running container: %s", containerID) 1278 } 1279 return c, nil 1280 } 1281 1282 func (container *Container) getNetworkedContainer() (*Container, error) { 1283 parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2) 1284 switch parts[0] { 1285 case "container": 1286 if len(parts) != 2 { 1287 return nil, fmt.Errorf("no container specified to join network") 1288 } 1289 nc := container.daemon.Get(parts[1]) 1290 if nc == nil { 1291 return nil, fmt.Errorf("no such container to join network: %s", parts[1]) 1292 } 1293 if !nc.IsRunning() { 1294 return nil, fmt.Errorf("cannot join network of a non running container: %s", parts[1]) 1295 } 1296 return nc, nil 1297 default: 1298 return nil, fmt.Errorf("network mode not set to container") 1299 } 1300 }