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