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