github.com/chenchun/docker@v1.3.2-0.20150629222414-20467faf132b/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.ExposedPorts != nil { 676 portSpecs = container.Config.ExposedPorts 677 } 678 679 if container.hostConfig.PortBindings != nil { 680 for p, b := range container.hostConfig.PortBindings { 681 bindings[p] = []nat.PortBinding{} 682 for _, bb := range b { 683 bindings[p] = append(bindings[p], nat.PortBinding{ 684 HostIp: bb.HostIp, 685 HostPort: bb.HostPort, 686 }) 687 } 688 } 689 } 690 691 container.NetworkSettings.PortMapping = nil 692 693 ports := make([]nat.Port, len(portSpecs)) 694 var i int 695 for p := range portSpecs { 696 ports[i] = p 697 i++ 698 } 699 nat.SortPortMap(ports, bindings) 700 for _, port := range ports { 701 expose := types.TransportPort{} 702 expose.Proto = types.ParseProtocol(port.Proto()) 703 expose.Port = uint16(port.Int()) 704 exposeList = append(exposeList, expose) 705 706 pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} 707 binding := bindings[port] 708 for i := 0; i < len(binding); i++ { 709 pbCopy := pb.GetCopy() 710 pbCopy.HostPort = uint16(nat.Port(binding[i].HostPort).Int()) 711 pbCopy.HostIP = net.ParseIP(binding[i].HostIp) 712 pbList = append(pbList, pbCopy) 713 } 714 715 if container.hostConfig.PublishAllPorts && len(binding) == 0 { 716 pbList = append(pbList, pb) 717 } 718 } 719 720 createOptions = append(createOptions, 721 libnetwork.CreateOptionPortMapping(pbList), 722 libnetwork.CreateOptionExposedPorts(exposeList)) 723 724 if container.Config.MacAddress != "" { 725 mac, err := net.ParseMAC(container.Config.MacAddress) 726 if err != nil { 727 return nil, err 728 } 729 730 genericOption := options.Generic{ 731 netlabel.MacAddress: mac, 732 } 733 734 createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) 735 } 736 737 return createOptions, nil 738 } 739 740 func parseService(controller libnetwork.NetworkController, service string) (string, string, string) { 741 dn := controller.Config().Daemon.DefaultNetwork 742 dd := controller.Config().Daemon.DefaultDriver 743 744 snd := strings.Split(service, ".") 745 if len(snd) > 2 { 746 return strings.Join(snd[:len(snd)-2], "."), snd[len(snd)-2], snd[len(snd)-1] 747 } 748 if len(snd) > 1 { 749 return snd[0], snd[1], dd 750 } 751 return snd[0], dn, dd 752 } 753 754 func createNetwork(controller libnetwork.NetworkController, dnet string, driver string) (libnetwork.Network, error) { 755 createOptions := []libnetwork.NetworkOption{} 756 genericOption := options.Generic{} 757 758 // Bridge driver is special due to legacy reasons 759 if runconfig.NetworkMode(driver).IsBridge() { 760 genericOption[netlabel.GenericData] = map[string]interface{}{ 761 "BridgeName": dnet, 762 "AllowNonDefaultBridge": "true", 763 } 764 networkOption := libnetwork.NetworkOptionGeneric(genericOption) 765 createOptions = append(createOptions, networkOption) 766 } 767 768 return controller.NewNetwork(driver, dnet, createOptions...) 769 } 770 771 func (container *Container) secondaryNetworkRequired(primaryNetworkType string) bool { 772 switch primaryNetworkType { 773 case "bridge", "none", "host", "container": 774 return false 775 } 776 if container.Config.ExposedPorts != nil && len(container.Config.ExposedPorts) > 0 { 777 return true 778 } 779 if container.hostConfig.PortBindings != nil && len(container.hostConfig.PortBindings) > 0 { 780 return true 781 } 782 return false 783 } 784 785 func (container *Container) AllocateNetwork() error { 786 mode := container.hostConfig.NetworkMode 787 controller := container.daemon.netController 788 if container.Config.NetworkDisabled || mode.IsContainer() { 789 return nil 790 } 791 792 networkDriver := string(mode) 793 service := container.Config.PublishService 794 networkName := mode.NetworkName() 795 if mode.IsDefault() { 796 if service != "" { 797 service, networkName, networkDriver = parseService(controller, service) 798 } else { 799 networkName = controller.Config().Daemon.DefaultNetwork 800 networkDriver = controller.Config().Daemon.DefaultDriver 801 } 802 } else if service != "" { 803 return fmt.Errorf("conflicting options: publishing a service and network mode") 804 } 805 806 if service == "" { 807 // dot character "." has a special meaning to support SERVICE[.NETWORK] format. 808 // For backward compatiblity, replacing "." with "-", instead of failing 809 service = strings.Replace(container.Name, ".", "-", -1) 810 // Service names dont like "/" in them. removing it instead of failing for backward compatibility 811 service = strings.Replace(service, "/", "", -1) 812 } 813 814 if container.secondaryNetworkRequired(networkDriver) { 815 // Configure Bridge as secondary network for port binding purposes 816 if err := container.configureNetwork("bridge", service, "bridge", false); err != nil { 817 return err 818 } 819 } 820 821 if err := container.configureNetwork(networkName, service, networkDriver, mode.IsDefault()); err != nil { 822 return err 823 } 824 825 return container.WriteHostConfig() 826 } 827 828 func (container *Container) configureNetwork(networkName, service, networkDriver string, canCreateNetwork bool) error { 829 controller := container.daemon.netController 830 n, err := controller.NetworkByName(networkName) 831 if err != nil { 832 if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok || !canCreateNetwork { 833 return err 834 } 835 836 if n, err = createNetwork(controller, networkName, networkDriver); err != nil { 837 return err 838 } 839 } 840 841 ep, err := n.EndpointByName(service) 842 if err != nil { 843 if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok { 844 return err 845 } 846 847 createOptions, err := container.buildCreateEndpointOptions() 848 if err != nil { 849 return err 850 } 851 852 ep, err = n.CreateEndpoint(service, createOptions...) 853 if err != nil { 854 return err 855 } 856 } 857 858 if err := container.updateNetworkSettings(n, ep); err != nil { 859 return err 860 } 861 862 joinOptions, err := container.buildJoinOptions() 863 if err != nil { 864 return err 865 } 866 867 if err := ep.Join(container.ID, joinOptions...); err != nil { 868 return err 869 } 870 871 if err := container.updateJoinInfo(ep); err != nil { 872 return fmt.Errorf("Updating join info failed: %v", err) 873 } 874 875 return nil 876 } 877 878 func (container *Container) initializeNetworking() error { 879 var err error 880 881 // Make sure NetworkMode has an acceptable value before 882 // initializing networking. 883 if container.hostConfig.NetworkMode == runconfig.NetworkMode("") { 884 container.hostConfig.NetworkMode = runconfig.NetworkMode("default") 885 } 886 if container.hostConfig.NetworkMode.IsContainer() { 887 // we need to get the hosts files from the container to join 888 nc, err := container.getNetworkedContainer() 889 if err != nil { 890 return err 891 } 892 container.HostnamePath = nc.HostnamePath 893 container.HostsPath = nc.HostsPath 894 container.ResolvConfPath = nc.ResolvConfPath 895 container.Config.Hostname = nc.Config.Hostname 896 container.Config.Domainname = nc.Config.Domainname 897 return nil 898 } 899 900 if container.daemon.config.DisableNetwork { 901 container.Config.NetworkDisabled = true 902 } 903 904 if container.hostConfig.NetworkMode.IsHost() { 905 container.Config.Hostname, err = os.Hostname() 906 if err != nil { 907 return err 908 } 909 910 parts := strings.SplitN(container.Config.Hostname, ".", 2) 911 if len(parts) > 1 { 912 container.Config.Hostname = parts[0] 913 container.Config.Domainname = parts[1] 914 } 915 916 } 917 918 if err := container.AllocateNetwork(); err != nil { 919 return err 920 } 921 922 return container.buildHostnameFile() 923 } 924 925 func (container *Container) ExportRw() (archive.Archive, error) { 926 if container.daemon == nil { 927 return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID) 928 } 929 archive, err := container.daemon.Diff(container) 930 if err != nil { 931 return nil, err 932 } 933 return ioutils.NewReadCloserWrapper(archive, func() error { 934 err := archive.Close() 935 return err 936 }), 937 nil 938 } 939 940 func (container *Container) getIpcContainer() (*Container, error) { 941 containerID := container.hostConfig.IpcMode.Container() 942 c, err := container.daemon.Get(containerID) 943 if err != nil { 944 return nil, err 945 } 946 if !c.IsRunning() { 947 return nil, fmt.Errorf("cannot join IPC of a non running container: %s", containerID) 948 } 949 return c, nil 950 } 951 952 func (container *Container) setupWorkingDirectory() error { 953 if container.Config.WorkingDir != "" { 954 container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) 955 956 pth, err := container.GetResourcePath(container.Config.WorkingDir) 957 if err != nil { 958 return err 959 } 960 961 pthInfo, err := os.Stat(pth) 962 if err != nil { 963 if !os.IsNotExist(err) { 964 return err 965 } 966 967 if err := os.MkdirAll(pth, 0755); err != nil { 968 return err 969 } 970 } 971 if pthInfo != nil && !pthInfo.IsDir() { 972 return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir) 973 } 974 } 975 return nil 976 } 977 978 func (container *Container) getNetworkedContainer() (*Container, error) { 979 parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2) 980 switch parts[0] { 981 case "container": 982 if len(parts) != 2 { 983 return nil, fmt.Errorf("no container specified to join network") 984 } 985 nc, err := container.daemon.Get(parts[1]) 986 if err != nil { 987 return nil, err 988 } 989 if container == nc { 990 return nil, fmt.Errorf("cannot join own network") 991 } 992 if !nc.IsRunning() { 993 return nil, fmt.Errorf("cannot join network of a non running container: %s", parts[1]) 994 } 995 return nc, nil 996 default: 997 return nil, fmt.Errorf("network mode not set to container") 998 } 999 } 1000 1001 func (container *Container) ReleaseNetwork() { 1002 if container.hostConfig.NetworkMode.IsContainer() || container.daemon.config.DisableNetwork { 1003 return 1004 } 1005 1006 eid := container.NetworkSettings.EndpointID 1007 nid := container.NetworkSettings.NetworkID 1008 1009 container.NetworkSettings = &network.Settings{} 1010 1011 if nid == "" || eid == "" { 1012 return 1013 } 1014 1015 n, err := container.daemon.netController.NetworkByID(nid) 1016 if err != nil { 1017 logrus.Errorf("error locating network id %s: %v", nid, err) 1018 return 1019 } 1020 1021 ep, err := n.EndpointByID(eid) 1022 if err != nil { 1023 logrus.Errorf("error locating endpoint id %s: %v", eid, err) 1024 return 1025 } 1026 1027 switch { 1028 case container.hostConfig.NetworkMode.IsHost(): 1029 if err := ep.Leave(container.ID); err != nil { 1030 logrus.Errorf("Error leaving endpoint id %s for container %s: %v", eid, container.ID, err) 1031 return 1032 } 1033 default: 1034 if err := container.daemon.netController.LeaveAll(container.ID); err != nil { 1035 logrus.Errorf("Leave all failed for %s: %v", container.ID, err) 1036 return 1037 } 1038 } 1039 1040 // In addition to leaving all endpoints, delete implicitly created endpoint 1041 if container.Config.PublishService == "" { 1042 if err := ep.Delete(); err != nil { 1043 logrus.Errorf("deleting endpoint failed: %v", err) 1044 } 1045 } 1046 1047 } 1048 1049 func disableAllActiveLinks(container *Container) { 1050 if container.activeLinks != nil { 1051 for _, link := range container.activeLinks { 1052 link.Disable() 1053 } 1054 } 1055 } 1056 1057 func (container *Container) DisableLink(name string) { 1058 if container.activeLinks != nil { 1059 if link, exists := container.activeLinks[name]; exists { 1060 link.Disable() 1061 delete(container.activeLinks, name) 1062 if err := container.UpdateNetwork(); err != nil { 1063 logrus.Debugf("Could not update network to remove link: %v", err) 1064 } 1065 } else { 1066 logrus.Debugf("Could not find active link for %s", name) 1067 } 1068 } 1069 } 1070 1071 func (container *Container) UnmountVolumes(forceSyscall bool) error { 1072 var volumeMounts []mountPoint 1073 1074 for _, mntPoint := range container.MountPoints { 1075 dest, err := container.GetResourcePath(mntPoint.Destination) 1076 if err != nil { 1077 return err 1078 } 1079 1080 volumeMounts = append(volumeMounts, mountPoint{Destination: dest, Volume: mntPoint.Volume}) 1081 } 1082 1083 for _, mnt := range container.networkMounts() { 1084 dest, err := container.GetResourcePath(mnt.Destination) 1085 if err != nil { 1086 return err 1087 } 1088 1089 volumeMounts = append(volumeMounts, mountPoint{Destination: dest}) 1090 } 1091 1092 for _, volumeMount := range volumeMounts { 1093 if forceSyscall { 1094 syscall.Unmount(volumeMount.Destination, 0) 1095 } 1096 1097 if volumeMount.Volume != nil { 1098 if err := volumeMount.Volume.Unmount(); err != nil { 1099 return err 1100 } 1101 } 1102 } 1103 1104 return nil 1105 }