github.com/jandre/docker@v1.7.0/daemon/container_linux.go (about) 1 // +build linux 2 3 package daemon 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "net" 9 "os" 10 "path" 11 "path/filepath" 12 "strconv" 13 "strings" 14 "syscall" 15 "time" 16 17 "github.com/Sirupsen/logrus" 18 "github.com/docker/docker/daemon/execdriver" 19 "github.com/docker/docker/daemon/network" 20 "github.com/docker/docker/links" 21 "github.com/docker/docker/nat" 22 "github.com/docker/docker/pkg/archive" 23 "github.com/docker/docker/pkg/directory" 24 "github.com/docker/docker/pkg/ioutils" 25 "github.com/docker/docker/pkg/stringid" 26 "github.com/docker/docker/pkg/ulimit" 27 "github.com/docker/docker/runconfig" 28 "github.com/docker/docker/utils" 29 "github.com/docker/libcontainer/configs" 30 "github.com/docker/libcontainer/devices" 31 "github.com/docker/libnetwork" 32 "github.com/docker/libnetwork/netlabel" 33 "github.com/docker/libnetwork/options" 34 "github.com/docker/libnetwork/types" 35 ) 36 37 const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 38 39 type Container struct { 40 CommonContainer 41 42 // Fields below here are platform specific. 43 44 AppArmorProfile string 45 activeLinks map[string]*links.Link 46 } 47 48 func killProcessDirectly(container *Container) error { 49 if _, err := container.WaitStop(10 * time.Second); err != nil { 50 // Ensure that we don't kill ourselves 51 if pid := container.GetPid(); pid != 0 { 52 logrus.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", stringid.TruncateID(container.ID)) 53 if err := syscall.Kill(pid, 9); err != nil { 54 if err != syscall.ESRCH { 55 return err 56 } 57 logrus.Debugf("Cannot kill process (pid=%d) with signal 9: no such process.", pid) 58 } 59 } 60 } 61 return nil 62 } 63 64 func (container *Container) setupLinkedContainers() ([]string, error) { 65 var ( 66 env []string 67 daemon = container.daemon 68 ) 69 children, err := daemon.Children(container.Name) 70 if err != nil { 71 return nil, err 72 } 73 74 if len(children) > 0 { 75 container.activeLinks = make(map[string]*links.Link, len(children)) 76 77 // If we encounter an error make sure that we rollback any network 78 // config and iptables changes 79 rollback := func() { 80 for _, link := range container.activeLinks { 81 link.Disable() 82 } 83 container.activeLinks = nil 84 } 85 86 for linkAlias, child := range children { 87 if !child.IsRunning() { 88 return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias) 89 } 90 91 link, err := links.NewLink( 92 container.NetworkSettings.IPAddress, 93 child.NetworkSettings.IPAddress, 94 linkAlias, 95 child.Config.Env, 96 child.Config.ExposedPorts, 97 ) 98 99 if err != nil { 100 rollback() 101 return nil, err 102 } 103 104 container.activeLinks[link.Alias()] = link 105 if err := link.Enable(); err != nil { 106 rollback() 107 return nil, err 108 } 109 110 for _, envVar := range link.ToEnv() { 111 env = append(env, envVar) 112 } 113 } 114 } 115 return env, nil 116 } 117 118 func (container *Container) createDaemonEnvironment(linkedEnv []string) []string { 119 // if a domain name was specified, append it to the hostname (see #7851) 120 fullHostname := container.Config.Hostname 121 if container.Config.Domainname != "" { 122 fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname) 123 } 124 // Setup environment 125 env := []string{ 126 "PATH=" + DefaultPathEnv, 127 "HOSTNAME=" + fullHostname, 128 // Note: we don't set HOME here because it'll get autoset intelligently 129 // based on the value of USER inside dockerinit, but only if it isn't 130 // set already (ie, that can be overridden by setting HOME via -e or ENV 131 // in a Dockerfile). 132 } 133 if container.Config.Tty { 134 env = append(env, "TERM=xterm") 135 } 136 env = append(env, linkedEnv...) 137 // because the env on the container can override certain default values 138 // we need to replace the 'env' keys where they match and append anything 139 // else. 140 env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env) 141 142 return env 143 } 144 145 func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.Device, err error) { 146 device, err := devices.DeviceFromPath(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions) 147 // if there was no error, return the device 148 if err == nil { 149 device.Path = deviceMapping.PathInContainer 150 return append(devs, device), nil 151 } 152 153 // if the device is not a device node 154 // try to see if it's a directory holding many devices 155 if err == devices.ErrNotADevice { 156 157 // check if it is a directory 158 if src, e := os.Stat(deviceMapping.PathOnHost); e == nil && src.IsDir() { 159 160 // mount the internal devices recursively 161 filepath.Walk(deviceMapping.PathOnHost, func(dpath string, f os.FileInfo, e error) error { 162 childDevice, e := devices.DeviceFromPath(dpath, deviceMapping.CgroupPermissions) 163 if e != nil { 164 // ignore the device 165 return nil 166 } 167 168 // add the device to userSpecified devices 169 childDevice.Path = strings.Replace(dpath, deviceMapping.PathOnHost, deviceMapping.PathInContainer, 1) 170 devs = append(devs, childDevice) 171 172 return nil 173 }) 174 } 175 } 176 177 if len(devs) > 0 { 178 return devs, nil 179 } 180 181 return devs, fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err) 182 } 183 184 func populateCommand(c *Container, env []string) error { 185 var en *execdriver.Network 186 if !c.Config.NetworkDisabled { 187 en = &execdriver.Network{ 188 NamespacePath: c.NetworkSettings.SandboxKey, 189 } 190 191 parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2) 192 if parts[0] == "container" { 193 nc, err := c.getNetworkedContainer() 194 if err != nil { 195 return err 196 } 197 en.ContainerID = nc.ID 198 } 199 } 200 201 ipc := &execdriver.Ipc{} 202 203 if c.hostConfig.IpcMode.IsContainer() { 204 ic, err := c.getIpcContainer() 205 if err != nil { 206 return err 207 } 208 ipc.ContainerID = ic.ID 209 } else { 210 ipc.HostIpc = c.hostConfig.IpcMode.IsHost() 211 } 212 213 pid := &execdriver.Pid{} 214 pid.HostPid = c.hostConfig.PidMode.IsHost() 215 216 uts := &execdriver.UTS{ 217 HostUTS: c.hostConfig.UTSMode.IsHost(), 218 } 219 220 // Build lists of devices allowed and created within the container. 221 var userSpecifiedDevices []*configs.Device 222 for _, deviceMapping := range c.hostConfig.Devices { 223 devs, err := getDevicesFromPath(deviceMapping) 224 if err != nil { 225 return err 226 } 227 228 userSpecifiedDevices = append(userSpecifiedDevices, devs...) 229 } 230 231 allowedDevices := mergeDevices(configs.DefaultAllowedDevices, userSpecifiedDevices) 232 233 autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices) 234 235 // TODO: this can be removed after lxc-conf is fully deprecated 236 lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig) 237 if err != nil { 238 return err 239 } 240 241 var rlimits []*ulimit.Rlimit 242 ulimits := c.hostConfig.Ulimits 243 244 // Merge ulimits with daemon defaults 245 ulIdx := make(map[string]*ulimit.Ulimit) 246 for _, ul := range ulimits { 247 ulIdx[ul.Name] = ul 248 } 249 for name, ul := range c.daemon.config.Ulimits { 250 if _, exists := ulIdx[name]; !exists { 251 ulimits = append(ulimits, ul) 252 } 253 } 254 255 for _, limit := range ulimits { 256 rl, err := limit.GetRlimit() 257 if err != nil { 258 return err 259 } 260 rlimits = append(rlimits, rl) 261 } 262 263 resources := &execdriver.Resources{ 264 Memory: c.hostConfig.Memory, 265 MemorySwap: c.hostConfig.MemorySwap, 266 CpuShares: c.hostConfig.CpuShares, 267 CpusetCpus: c.hostConfig.CpusetCpus, 268 CpusetMems: c.hostConfig.CpusetMems, 269 CpuPeriod: c.hostConfig.CpuPeriod, 270 CpuQuota: c.hostConfig.CpuQuota, 271 BlkioWeight: c.hostConfig.BlkioWeight, 272 Rlimits: rlimits, 273 OomKillDisable: c.hostConfig.OomKillDisable, 274 } 275 276 processConfig := execdriver.ProcessConfig{ 277 Privileged: c.hostConfig.Privileged, 278 Entrypoint: c.Path, 279 Arguments: c.Args, 280 Tty: c.Config.Tty, 281 User: c.Config.User, 282 } 283 284 processConfig.SysProcAttr = &syscall.SysProcAttr{Setsid: true} 285 processConfig.Env = env 286 287 c.command = &execdriver.Command{ 288 ID: c.ID, 289 Rootfs: c.RootfsPath(), 290 ReadonlyRootfs: c.hostConfig.ReadonlyRootfs, 291 InitPath: "/.dockerinit", 292 WorkingDir: c.Config.WorkingDir, 293 Network: en, 294 Ipc: ipc, 295 Pid: pid, 296 UTS: uts, 297 Resources: resources, 298 AllowedDevices: allowedDevices, 299 AutoCreatedDevices: autoCreatedDevices, 300 CapAdd: c.hostConfig.CapAdd, 301 CapDrop: c.hostConfig.CapDrop, 302 ProcessConfig: processConfig, 303 ProcessLabel: c.GetProcessLabel(), 304 MountLabel: c.GetMountLabel(), 305 LxcConfig: lxcConfig, 306 AppArmorProfile: c.AppArmorProfile, 307 CgroupParent: c.hostConfig.CgroupParent, 308 } 309 310 return nil 311 } 312 313 func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Device { 314 if len(userDevices) == 0 { 315 return defaultDevices 316 } 317 318 paths := map[string]*configs.Device{} 319 for _, d := range userDevices { 320 paths[d.Path] = d 321 } 322 323 var devs []*configs.Device 324 for _, d := range defaultDevices { 325 if _, defined := paths[d.Path]; !defined { 326 devs = append(devs, d) 327 } 328 } 329 return append(devs, userDevices...) 330 } 331 332 // GetSize, return real size, virtual size 333 func (container *Container) GetSize() (int64, int64) { 334 var ( 335 sizeRw, sizeRootfs int64 336 err error 337 driver = container.daemon.driver 338 ) 339 340 if err := container.Mount(); err != nil { 341 logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err) 342 return sizeRw, sizeRootfs 343 } 344 defer container.Unmount() 345 346 initID := fmt.Sprintf("%s-init", container.ID) 347 sizeRw, err = driver.DiffSize(container.ID, initID) 348 if err != nil { 349 logrus.Errorf("Driver %s couldn't return diff size of container %s: %s", driver, container.ID, err) 350 // FIXME: GetSize should return an error. Not changing it now in case 351 // there is a side-effect. 352 sizeRw = -1 353 } 354 355 if _, err = os.Stat(container.basefs); err == nil { 356 if sizeRootfs, err = directory.Size(container.basefs); err != nil { 357 sizeRootfs = -1 358 } 359 } 360 return sizeRw, sizeRootfs 361 } 362 363 func (container *Container) buildHostnameFile() error { 364 hostnamePath, err := container.GetRootResourcePath("hostname") 365 if err != nil { 366 return err 367 } 368 container.HostnamePath = hostnamePath 369 370 if container.Config.Domainname != "" { 371 return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644) 372 } 373 return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) 374 } 375 376 func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, error) { 377 var ( 378 joinOptions []libnetwork.EndpointOption 379 err error 380 dns []string 381 dnsSearch []string 382 ) 383 384 joinOptions = append(joinOptions, libnetwork.JoinOptionHostname(container.Config.Hostname), 385 libnetwork.JoinOptionDomainname(container.Config.Domainname)) 386 387 if container.hostConfig.NetworkMode.IsHost() { 388 joinOptions = append(joinOptions, libnetwork.JoinOptionUseDefaultSandbox()) 389 } 390 391 container.HostsPath, err = container.GetRootResourcePath("hosts") 392 if err != nil { 393 return nil, err 394 } 395 joinOptions = append(joinOptions, libnetwork.JoinOptionHostsPath(container.HostsPath)) 396 397 container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf") 398 if err != nil { 399 return nil, err 400 } 401 joinOptions = append(joinOptions, libnetwork.JoinOptionResolvConfPath(container.ResolvConfPath)) 402 403 if len(container.hostConfig.Dns) > 0 { 404 dns = container.hostConfig.Dns 405 } else if len(container.daemon.config.Dns) > 0 { 406 dns = container.daemon.config.Dns 407 } 408 409 for _, d := range dns { 410 joinOptions = append(joinOptions, libnetwork.JoinOptionDNS(d)) 411 } 412 413 if len(container.hostConfig.DnsSearch) > 0 { 414 dnsSearch = container.hostConfig.DnsSearch 415 } else if len(container.daemon.config.DnsSearch) > 0 { 416 dnsSearch = container.daemon.config.DnsSearch 417 } 418 419 for _, ds := range dnsSearch { 420 joinOptions = append(joinOptions, libnetwork.JoinOptionDNSSearch(ds)) 421 } 422 423 if container.NetworkSettings.SecondaryIPAddresses != nil { 424 name := container.Config.Hostname 425 if container.Config.Domainname != "" { 426 name = name + "." + container.Config.Domainname 427 } 428 429 for _, a := range container.NetworkSettings.SecondaryIPAddresses { 430 joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(name, a.Addr)) 431 } 432 } 433 434 var childEndpoints, parentEndpoints []string 435 436 children, err := container.daemon.Children(container.Name) 437 if err != nil { 438 return nil, err 439 } 440 441 for linkAlias, child := range children { 442 _, alias := path.Split(linkAlias) 443 // allow access to the linked container via the alias, real name, and container hostname 444 aliasList := alias + " " + child.Config.Hostname 445 // only add the name if alias isn't equal to the name 446 if alias != child.Name[1:] { 447 aliasList = aliasList + " " + child.Name[1:] 448 } 449 joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(aliasList, child.NetworkSettings.IPAddress)) 450 if child.NetworkSettings.EndpointID != "" { 451 childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID) 452 } 453 } 454 455 for _, extraHost := range container.hostConfig.ExtraHosts { 456 // allow IPv6 addresses in extra hosts; only split on first ":" 457 parts := strings.SplitN(extraHost, ":", 2) 458 joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(parts[0], parts[1])) 459 } 460 461 refs := container.daemon.ContainerGraph().RefPaths(container.ID) 462 for _, ref := range refs { 463 if ref.ParentID == "0" { 464 continue 465 } 466 467 c, err := container.daemon.Get(ref.ParentID) 468 if err != nil { 469 logrus.Error(err) 470 } 471 472 if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() { 473 logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress) 474 joinOptions = append(joinOptions, libnetwork.JoinOptionParentUpdate(c.NetworkSettings.EndpointID, ref.Name, container.NetworkSettings.IPAddress)) 475 if c.NetworkSettings.EndpointID != "" { 476 parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID) 477 } 478 } 479 } 480 481 linkOptions := options.Generic{ 482 netlabel.GenericData: options.Generic{ 483 "ParentEndpoints": parentEndpoints, 484 "ChildEndpoints": childEndpoints, 485 }, 486 } 487 488 joinOptions = append(joinOptions, libnetwork.JoinOptionGeneric(linkOptions)) 489 490 return joinOptions, nil 491 } 492 493 func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) { 494 if ep == nil { 495 return nil, fmt.Errorf("invalid endpoint while building port map info") 496 } 497 498 if networkSettings == nil { 499 return nil, fmt.Errorf("invalid networksettings while building port map info") 500 } 501 502 driverInfo, err := ep.DriverInfo() 503 if err != nil { 504 return nil, err 505 } 506 507 if driverInfo == nil { 508 // It is not an error for epInfo to be nil 509 return networkSettings, nil 510 } 511 512 if mac, ok := driverInfo[netlabel.MacAddress]; ok { 513 networkSettings.MacAddress = mac.(net.HardwareAddr).String() 514 } 515 516 networkSettings.Ports = nat.PortMap{} 517 518 if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { 519 if exposedPorts, ok := expData.([]types.TransportPort); ok { 520 for _, tp := range exposedPorts { 521 natPort := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) 522 networkSettings.Ports[natPort] = nil 523 } 524 } 525 } 526 527 mapData, ok := driverInfo[netlabel.PortMap] 528 if !ok { 529 return networkSettings, nil 530 } 531 532 if portMapping, ok := mapData.([]types.PortBinding); ok { 533 for _, pp := range portMapping { 534 natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) 535 natBndg := nat.PortBinding{HostIp: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))} 536 networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg) 537 } 538 } 539 540 return networkSettings, nil 541 } 542 543 func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) { 544 if ep == nil { 545 return nil, fmt.Errorf("invalid endpoint while building port map info") 546 } 547 548 if networkSettings == nil { 549 return nil, fmt.Errorf("invalid networksettings while building port map info") 550 } 551 552 epInfo := ep.Info() 553 if epInfo == nil { 554 // It is not an error to get an empty endpoint info 555 return networkSettings, nil 556 } 557 558 ifaceList := epInfo.InterfaceList() 559 if len(ifaceList) == 0 { 560 return networkSettings, nil 561 } 562 563 iface := ifaceList[0] 564 565 ones, _ := iface.Address().Mask.Size() 566 networkSettings.IPAddress = iface.Address().IP.String() 567 networkSettings.IPPrefixLen = ones 568 569 if iface.AddressIPv6().IP.To16() != nil { 570 onesv6, _ := iface.AddressIPv6().Mask.Size() 571 networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String() 572 networkSettings.GlobalIPv6PrefixLen = onesv6 573 } 574 575 if len(ifaceList) == 1 { 576 return networkSettings, nil 577 } 578 579 networkSettings.SecondaryIPAddresses = make([]network.Address, 0, len(ifaceList)-1) 580 networkSettings.SecondaryIPv6Addresses = make([]network.Address, 0, len(ifaceList)-1) 581 for _, iface := range ifaceList[1:] { 582 ones, _ := iface.Address().Mask.Size() 583 addr := network.Address{Addr: iface.Address().IP.String(), PrefixLen: ones} 584 networkSettings.SecondaryIPAddresses = append(networkSettings.SecondaryIPAddresses, addr) 585 586 if iface.AddressIPv6().IP.To16() != nil { 587 onesv6, _ := iface.AddressIPv6().Mask.Size() 588 addrv6 := network.Address{Addr: iface.AddressIPv6().IP.String(), PrefixLen: onesv6} 589 networkSettings.SecondaryIPv6Addresses = append(networkSettings.SecondaryIPv6Addresses, addrv6) 590 } 591 } 592 593 return networkSettings, nil 594 } 595 596 func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error { 597 epInfo := ep.Info() 598 if epInfo == nil { 599 // It is not an error to get an empty endpoint info 600 return nil 601 } 602 603 container.NetworkSettings.Gateway = epInfo.Gateway().String() 604 if epInfo.GatewayIPv6().To16() != nil { 605 container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String() 606 } 607 608 container.NetworkSettings.SandboxKey = epInfo.SandboxKey() 609 610 return nil 611 } 612 613 func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error { 614 networkSettings := &network.Settings{NetworkID: n.ID(), EndpointID: ep.ID()} 615 616 networkSettings, err := container.buildPortMapInfo(n, ep, networkSettings) 617 if err != nil { 618 return err 619 } 620 621 networkSettings, err = container.buildEndpointInfo(n, ep, networkSettings) 622 if err != nil { 623 return err 624 } 625 626 if container.hostConfig.NetworkMode == runconfig.NetworkMode("bridge") { 627 networkSettings.Bridge = container.daemon.config.Bridge.Iface 628 } 629 630 container.NetworkSettings = networkSettings 631 return nil 632 } 633 634 func (container *Container) UpdateNetwork() error { 635 n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID) 636 if err != nil { 637 return fmt.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err) 638 } 639 640 ep, err := n.EndpointByID(container.NetworkSettings.EndpointID) 641 if err != nil { 642 return fmt.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err) 643 } 644 645 if err := ep.Leave(container.ID); err != nil { 646 return fmt.Errorf("endpoint leave failed: %v", err) 647 648 } 649 650 joinOptions, err := container.buildJoinOptions() 651 if err != nil { 652 return fmt.Errorf("Update network failed: %v", err) 653 } 654 655 if _, err := ep.Join(container.ID, joinOptions...); err != nil { 656 return fmt.Errorf("endpoint join failed: %v", err) 657 } 658 659 if err := container.updateJoinInfo(ep); err != nil { 660 return fmt.Errorf("Updating join info failed: %v", err) 661 } 662 663 return nil 664 } 665 666 func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointOption, error) { 667 var ( 668 portSpecs = make(nat.PortSet) 669 bindings = make(nat.PortMap) 670 pbList []types.PortBinding 671 exposeList []types.TransportPort 672 createOptions []libnetwork.EndpointOption 673 ) 674 675 if container.Config.PortSpecs != nil { 676 if err := migratePortMappings(container.Config, container.hostConfig); err != nil { 677 return nil, err 678 } 679 container.Config.PortSpecs = nil 680 if err := container.WriteHostConfig(); err != nil { 681 return nil, err 682 } 683 } 684 685 if container.Config.ExposedPorts != nil { 686 portSpecs = container.Config.ExposedPorts 687 } 688 689 if container.hostConfig.PortBindings != nil { 690 for p, b := range container.hostConfig.PortBindings { 691 bindings[p] = []nat.PortBinding{} 692 for _, bb := range b { 693 bindings[p] = append(bindings[p], nat.PortBinding{ 694 HostIp: bb.HostIp, 695 HostPort: bb.HostPort, 696 }) 697 } 698 } 699 } 700 701 container.NetworkSettings.PortMapping = nil 702 703 ports := make([]nat.Port, len(portSpecs)) 704 var i int 705 for p := range portSpecs { 706 ports[i] = p 707 i++ 708 } 709 nat.SortPortMap(ports, bindings) 710 for _, port := range ports { 711 expose := types.TransportPort{} 712 expose.Proto = types.ParseProtocol(port.Proto()) 713 expose.Port = uint16(port.Int()) 714 exposeList = append(exposeList, expose) 715 716 pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} 717 binding := bindings[port] 718 for i := 0; i < len(binding); i++ { 719 pbCopy := pb.GetCopy() 720 pbCopy.HostPort = uint16(nat.Port(binding[i].HostPort).Int()) 721 pbCopy.HostIP = net.ParseIP(binding[i].HostIp) 722 pbList = append(pbList, pbCopy) 723 } 724 725 if container.hostConfig.PublishAllPorts && len(binding) == 0 { 726 pbList = append(pbList, pb) 727 } 728 } 729 730 createOptions = append(createOptions, 731 libnetwork.CreateOptionPortMapping(pbList), 732 libnetwork.CreateOptionExposedPorts(exposeList)) 733 734 if container.Config.MacAddress != "" { 735 mac, err := net.ParseMAC(container.Config.MacAddress) 736 if err != nil { 737 return nil, err 738 } 739 740 genericOption := options.Generic{ 741 netlabel.MacAddress: mac, 742 } 743 744 createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) 745 } 746 747 return createOptions, nil 748 } 749 750 func (container *Container) AllocateNetwork() error { 751 mode := container.hostConfig.NetworkMode 752 if container.Config.NetworkDisabled || mode.IsContainer() { 753 return nil 754 } 755 756 var err error 757 758 n, err := container.daemon.netController.NetworkByName(string(mode)) 759 if err != nil { 760 return fmt.Errorf("error locating network with name %s: %v", string(mode), err) 761 } 762 763 createOptions, err := container.buildCreateEndpointOptions() 764 if err != nil { 765 return err 766 } 767 768 ep, err := n.CreateEndpoint(container.Name, createOptions...) 769 if err != nil { 770 return err 771 } 772 773 if err := container.updateNetworkSettings(n, ep); err != nil { 774 return err 775 } 776 777 joinOptions, err := container.buildJoinOptions() 778 if err != nil { 779 return err 780 } 781 782 if _, err := ep.Join(container.ID, joinOptions...); err != nil { 783 return err 784 } 785 786 if err := container.updateJoinInfo(ep); err != nil { 787 return fmt.Errorf("Updating join info failed: %v", err) 788 } 789 790 if err := container.WriteHostConfig(); err != nil { 791 return err 792 } 793 794 return nil 795 } 796 797 func (container *Container) initializeNetworking() error { 798 var err error 799 800 // Make sure NetworkMode has an acceptable value before 801 // initializing networking. 802 if container.hostConfig.NetworkMode == runconfig.NetworkMode("") { 803 container.hostConfig.NetworkMode = runconfig.NetworkMode("bridge") 804 } 805 806 if container.hostConfig.NetworkMode.IsContainer() { 807 // we need to get the hosts files from the container to join 808 nc, err := container.getNetworkedContainer() 809 if err != nil { 810 return err 811 } 812 container.HostnamePath = nc.HostnamePath 813 container.HostsPath = nc.HostsPath 814 container.ResolvConfPath = nc.ResolvConfPath 815 container.Config.Hostname = nc.Config.Hostname 816 container.Config.Domainname = nc.Config.Domainname 817 return nil 818 } 819 820 if container.daemon.config.DisableNetwork { 821 container.Config.NetworkDisabled = true 822 } 823 824 if container.hostConfig.NetworkMode.IsHost() { 825 container.Config.Hostname, err = os.Hostname() 826 if err != nil { 827 return err 828 } 829 830 parts := strings.SplitN(container.Config.Hostname, ".", 2) 831 if len(parts) > 1 { 832 container.Config.Hostname = parts[0] 833 container.Config.Domainname = parts[1] 834 } 835 836 } 837 838 if err := container.AllocateNetwork(); err != nil { 839 return err 840 } 841 842 return container.buildHostnameFile() 843 } 844 845 // Make sure the config is compatible with the current kernel 846 func (container *Container) verifyDaemonSettings() { 847 if container.hostConfig.Memory > 0 && !container.daemon.sysInfo.MemoryLimit { 848 logrus.Warnf("Your kernel does not support memory limit capabilities. Limitation discarded.") 849 container.hostConfig.Memory = 0 850 } 851 if container.hostConfig.Memory > 0 && container.hostConfig.MemorySwap != -1 && !container.daemon.sysInfo.SwapLimit { 852 logrus.Warnf("Your kernel does not support swap limit capabilities. Limitation discarded.") 853 container.hostConfig.MemorySwap = -1 854 } 855 if container.daemon.sysInfo.IPv4ForwardingDisabled { 856 logrus.Warnf("IPv4 forwarding is disabled. Networking will not work") 857 } 858 } 859 860 func (container *Container) ExportRw() (archive.Archive, error) { 861 if err := container.Mount(); err != nil { 862 return nil, err 863 } 864 if container.daemon == nil { 865 return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID) 866 } 867 archive, err := container.daemon.Diff(container) 868 if err != nil { 869 container.Unmount() 870 return nil, err 871 } 872 return ioutils.NewReadCloserWrapper(archive, func() error { 873 err := archive.Close() 874 container.Unmount() 875 return err 876 }), 877 nil 878 } 879 880 func (container *Container) getIpcContainer() (*Container, error) { 881 containerID := container.hostConfig.IpcMode.Container() 882 c, err := container.daemon.Get(containerID) 883 if err != nil { 884 return nil, err 885 } 886 if !c.IsRunning() { 887 return nil, fmt.Errorf("cannot join IPC of a non running container: %s", containerID) 888 } 889 return c, nil 890 } 891 892 func (container *Container) setupWorkingDirectory() error { 893 if container.Config.WorkingDir != "" { 894 container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) 895 896 pth, err := container.GetResourcePath(container.Config.WorkingDir) 897 if err != nil { 898 return err 899 } 900 901 pthInfo, err := os.Stat(pth) 902 if err != nil { 903 if !os.IsNotExist(err) { 904 return err 905 } 906 907 if err := os.MkdirAll(pth, 0755); err != nil { 908 return err 909 } 910 } 911 if pthInfo != nil && !pthInfo.IsDir() { 912 return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir) 913 } 914 } 915 return nil 916 } 917 918 func (container *Container) getNetworkedContainer() (*Container, error) { 919 parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2) 920 switch parts[0] { 921 case "container": 922 if len(parts) != 2 { 923 return nil, fmt.Errorf("no container specified to join network") 924 } 925 nc, err := container.daemon.Get(parts[1]) 926 if err != nil { 927 return nil, err 928 } 929 if container == nc { 930 return nil, fmt.Errorf("cannot join own network") 931 } 932 if !nc.IsRunning() { 933 return nil, fmt.Errorf("cannot join network of a non running container: %s", parts[1]) 934 } 935 return nc, nil 936 default: 937 return nil, fmt.Errorf("network mode not set to container") 938 } 939 } 940 941 func (container *Container) ReleaseNetwork() { 942 if container.hostConfig.NetworkMode.IsContainer() || container.daemon.config.DisableNetwork { 943 return 944 } 945 946 // If the container is not attached to any network do not try 947 // to release network and generate spurious error messages. 948 if container.NetworkSettings.NetworkID == "" { 949 return 950 } 951 952 n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID) 953 if err != nil { 954 logrus.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err) 955 return 956 } 957 958 ep, err := n.EndpointByID(container.NetworkSettings.EndpointID) 959 if err != nil { 960 logrus.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err) 961 return 962 } 963 964 if err := ep.Leave(container.ID); err != nil { 965 logrus.Errorf("leaving endpoint failed: %v", err) 966 } 967 968 if err := ep.Delete(); err != nil { 969 logrus.Errorf("deleting endpoint failed: %v", err) 970 } 971 972 container.NetworkSettings = &network.Settings{} 973 } 974 975 func disableAllActiveLinks(container *Container) { 976 if container.activeLinks != nil { 977 for _, link := range container.activeLinks { 978 link.Disable() 979 } 980 } 981 } 982 983 func (container *Container) DisableLink(name string) { 984 if container.activeLinks != nil { 985 if link, exists := container.activeLinks[name]; exists { 986 link.Disable() 987 delete(container.activeLinks, name) 988 if err := container.UpdateNetwork(); err != nil { 989 logrus.Debugf("Could not update network to remove link: %v", err) 990 } 991 } else { 992 logrus.Debugf("Could not find active link for %s", name) 993 } 994 } 995 } 996 997 func (container *Container) UnmountVolumes(forceSyscall bool) error { 998 var volumeMounts []mountPoint 999 1000 for _, mntPoint := range container.MountPoints { 1001 dest, err := container.GetResourcePath(mntPoint.Destination) 1002 if err != nil { 1003 return err 1004 } 1005 1006 volumeMounts = append(volumeMounts, mountPoint{Destination: dest, Volume: mntPoint.Volume}) 1007 } 1008 1009 for _, mnt := range container.networkMounts() { 1010 dest, err := container.GetResourcePath(mnt.Destination) 1011 if err != nil { 1012 return err 1013 } 1014 1015 volumeMounts = append(volumeMounts, mountPoint{Destination: dest}) 1016 } 1017 1018 for _, volumeMount := range volumeMounts { 1019 if forceSyscall { 1020 syscall.Unmount(volumeMount.Destination, 0) 1021 } 1022 1023 if volumeMount.Volume != nil { 1024 if err := volumeMount.Volume.Unmount(); err != nil { 1025 return err 1026 } 1027 } 1028 } 1029 1030 return nil 1031 }