github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/daemon/container_unix.go (about) 1 // +build linux freebsd 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/links" 20 "github.com/docker/docker/daemon/network" 21 derr "github.com/docker/docker/errors" 22 "github.com/docker/docker/pkg/directory" 23 "github.com/docker/docker/pkg/nat" 24 "github.com/docker/docker/pkg/stringid" 25 "github.com/docker/docker/pkg/system" 26 "github.com/docker/docker/pkg/ulimit" 27 "github.com/docker/docker/runconfig" 28 "github.com/docker/docker/utils" 29 "github.com/docker/docker/volume" 30 "github.com/docker/docker/volume/store" 31 "github.com/docker/libnetwork" 32 "github.com/docker/libnetwork/netlabel" 33 "github.com/docker/libnetwork/options" 34 "github.com/docker/libnetwork/types" 35 "github.com/opencontainers/runc/libcontainer/configs" 36 "github.com/opencontainers/runc/libcontainer/devices" 37 "github.com/opencontainers/runc/libcontainer/label" 38 ) 39 40 // DefaultPathEnv is unix style list of directories to search for 41 // executables. Each directory is separated from the next by a colon 42 // ':' character . 43 const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 44 45 // Container holds the fields specific to unixen implementations. See 46 // CommonContainer for standard fields common to all containers. 47 type Container struct { 48 CommonContainer 49 50 // Fields below here are platform specific. 51 activeLinks map[string]*links.Link 52 AppArmorProfile string 53 HostnamePath string 54 HostsPath string 55 MountPoints map[string]*mountPoint 56 ResolvConfPath string 57 58 Volumes map[string]string // Deprecated since 1.7, kept for backwards compatibility 59 VolumesRW map[string]bool // Deprecated since 1.7, kept for backwards compatibility 60 } 61 62 func killProcessDirectly(container *Container) error { 63 if _, err := container.WaitStop(10 * time.Second); err != nil { 64 // Ensure that we don't kill ourselves 65 if pid := container.getPID(); pid != 0 { 66 logrus.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", stringid.TruncateID(container.ID)) 67 if err := syscall.Kill(pid, 9); err != nil { 68 if err != syscall.ESRCH { 69 return err 70 } 71 logrus.Debugf("Cannot kill process (pid=%d) with signal 9: no such process.", pid) 72 } 73 } 74 } 75 return nil 76 } 77 78 func (container *Container) setupLinkedContainers() ([]string, error) { 79 var ( 80 env []string 81 daemon = container.daemon 82 ) 83 children, err := daemon.children(container.Name) 84 if err != nil { 85 return nil, err 86 } 87 88 if len(children) > 0 { 89 for linkAlias, child := range children { 90 if !child.IsRunning() { 91 return nil, derr.ErrorCodeLinkNotRunning.WithArgs(child.Name, linkAlias) 92 } 93 94 link := links.NewLink( 95 container.NetworkSettings.IPAddress, 96 child.NetworkSettings.IPAddress, 97 linkAlias, 98 child.Config.Env, 99 child.Config.ExposedPorts, 100 ) 101 102 for _, envVar := range link.ToEnv() { 103 env = append(env, envVar) 104 } 105 } 106 } 107 return env, nil 108 } 109 110 func (container *Container) createDaemonEnvironment(linkedEnv []string) []string { 111 // if a domain name was specified, append it to the hostname (see #7851) 112 fullHostname := container.Config.Hostname 113 if container.Config.Domainname != "" { 114 fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname) 115 } 116 // Setup environment 117 env := []string{ 118 "PATH=" + DefaultPathEnv, 119 "HOSTNAME=" + fullHostname, 120 // Note: we don't set HOME here because it'll get autoset intelligently 121 // based on the value of USER inside dockerinit, but only if it isn't 122 // set already (ie, that can be overridden by setting HOME via -e or ENV 123 // in a Dockerfile). 124 } 125 if container.Config.Tty { 126 env = append(env, "TERM=xterm") 127 } 128 env = append(env, linkedEnv...) 129 // because the env on the container can override certain default values 130 // we need to replace the 'env' keys where they match and append anything 131 // else. 132 env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env) 133 134 return env 135 } 136 137 func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.Device, err error) { 138 device, err := devices.DeviceFromPath(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions) 139 // if there was no error, return the device 140 if err == nil { 141 device.Path = deviceMapping.PathInContainer 142 return append(devs, device), nil 143 } 144 145 // if the device is not a device node 146 // try to see if it's a directory holding many devices 147 if err == devices.ErrNotADevice { 148 149 // check if it is a directory 150 if src, e := os.Stat(deviceMapping.PathOnHost); e == nil && src.IsDir() { 151 152 // mount the internal devices recursively 153 filepath.Walk(deviceMapping.PathOnHost, func(dpath string, f os.FileInfo, e error) error { 154 childDevice, e := devices.DeviceFromPath(dpath, deviceMapping.CgroupPermissions) 155 if e != nil { 156 // ignore the device 157 return nil 158 } 159 160 // add the device to userSpecified devices 161 childDevice.Path = strings.Replace(dpath, deviceMapping.PathOnHost, deviceMapping.PathInContainer, 1) 162 devs = append(devs, childDevice) 163 164 return nil 165 }) 166 } 167 } 168 169 if len(devs) > 0 { 170 return devs, nil 171 } 172 173 return devs, derr.ErrorCodeDeviceInfo.WithArgs(deviceMapping.PathOnHost, err) 174 } 175 176 func populateCommand(c *Container, env []string) error { 177 var en *execdriver.Network 178 if !c.Config.NetworkDisabled { 179 en = &execdriver.Network{} 180 if !c.daemon.execDriver.SupportsHooks() || c.hostConfig.NetworkMode.IsHost() { 181 en.NamespacePath = c.NetworkSettings.SandboxKey 182 } 183 184 parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2) 185 if parts[0] == "container" { 186 nc, err := c.getNetworkedContainer() 187 if err != nil { 188 return err 189 } 190 en.ContainerID = nc.ID 191 } 192 } 193 194 ipc := &execdriver.Ipc{} 195 196 if c.hostConfig.IpcMode.IsContainer() { 197 ic, err := c.getIpcContainer() 198 if err != nil { 199 return err 200 } 201 ipc.ContainerID = ic.ID 202 } else { 203 ipc.HostIpc = c.hostConfig.IpcMode.IsHost() 204 } 205 206 pid := &execdriver.Pid{} 207 pid.HostPid = c.hostConfig.PidMode.IsHost() 208 209 uts := &execdriver.UTS{ 210 HostUTS: c.hostConfig.UTSMode.IsHost(), 211 } 212 213 // Build lists of devices allowed and created within the container. 214 var userSpecifiedDevices []*configs.Device 215 for _, deviceMapping := range c.hostConfig.Devices { 216 devs, err := getDevicesFromPath(deviceMapping) 217 if err != nil { 218 return err 219 } 220 221 userSpecifiedDevices = append(userSpecifiedDevices, devs...) 222 } 223 224 allowedDevices := mergeDevices(configs.DefaultAllowedDevices, userSpecifiedDevices) 225 226 autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices) 227 228 // TODO: this can be removed after lxc-conf is fully deprecated 229 lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig) 230 if err != nil { 231 return err 232 } 233 234 var rlimits []*ulimit.Rlimit 235 ulimits := c.hostConfig.Ulimits 236 237 // Merge ulimits with daemon defaults 238 ulIdx := make(map[string]*ulimit.Ulimit) 239 for _, ul := range ulimits { 240 ulIdx[ul.Name] = ul 241 } 242 for name, ul := range c.daemon.configStore.Ulimits { 243 if _, exists := ulIdx[name]; !exists { 244 ulimits = append(ulimits, ul) 245 } 246 } 247 248 for _, limit := range ulimits { 249 rl, err := limit.GetRlimit() 250 if err != nil { 251 return err 252 } 253 rlimits = append(rlimits, rl) 254 } 255 256 resources := &execdriver.Resources{ 257 Memory: c.hostConfig.Memory, 258 MemorySwap: c.hostConfig.MemorySwap, 259 KernelMemory: c.hostConfig.KernelMemory, 260 CPUShares: c.hostConfig.CPUShares, 261 CpusetCpus: c.hostConfig.CpusetCpus, 262 CpusetMems: c.hostConfig.CpusetMems, 263 CPUPeriod: c.hostConfig.CPUPeriod, 264 CPUQuota: c.hostConfig.CPUQuota, 265 BlkioWeight: c.hostConfig.BlkioWeight, 266 Rlimits: rlimits, 267 OomKillDisable: c.hostConfig.OomKillDisable, 268 MemorySwappiness: -1, 269 } 270 271 if c.hostConfig.MemorySwappiness != nil { 272 resources.MemorySwappiness = *c.hostConfig.MemorySwappiness 273 } 274 275 processConfig := execdriver.ProcessConfig{ 276 Privileged: c.hostConfig.Privileged, 277 Entrypoint: c.Path, 278 Arguments: c.Args, 279 Tty: c.Config.Tty, 280 User: c.Config.User, 281 } 282 283 processConfig.SysProcAttr = &syscall.SysProcAttr{Setsid: true} 284 processConfig.Env = env 285 286 c.command = &execdriver.Command{ 287 ID: c.ID, 288 Rootfs: c.rootfsPath(), 289 ReadonlyRootfs: c.hostConfig.ReadonlyRootfs, 290 InitPath: "/.dockerinit", 291 WorkingDir: c.Config.WorkingDir, 292 Network: en, 293 Ipc: ipc, 294 Pid: pid, 295 UTS: uts, 296 Resources: resources, 297 AllowedDevices: allowedDevices, 298 AutoCreatedDevices: autoCreatedDevices, 299 CapAdd: c.hostConfig.CapAdd.Slice(), 300 CapDrop: c.hostConfig.CapDrop.Slice(), 301 GroupAdd: c.hostConfig.GroupAdd, 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 returns the real size & virtual size of the container. 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 // Attempt to set the network mounts given a provided destination and 364 // the path to use for it; return true if the given destination was a 365 // network mount file 366 func (container *Container) trySetNetworkMount(destination string, path string) bool { 367 if destination == "/etc/resolv.conf" { 368 container.ResolvConfPath = path 369 return true 370 } 371 if destination == "/etc/hostname" { 372 container.HostnamePath = path 373 return true 374 } 375 if destination == "/etc/hosts" { 376 container.HostsPath = path 377 return true 378 } 379 380 return false 381 } 382 383 func (container *Container) buildHostnameFile() error { 384 hostnamePath, err := container.getRootResourcePath("hostname") 385 if err != nil { 386 return err 387 } 388 container.HostnamePath = hostnamePath 389 390 if container.Config.Domainname != "" { 391 return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644) 392 } 393 return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) 394 } 395 396 func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, error) { 397 var ( 398 sboxOptions []libnetwork.SandboxOption 399 err error 400 dns []string 401 dnsSearch []string 402 dnsOptions []string 403 ) 404 405 sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), 406 libnetwork.OptionDomainname(container.Config.Domainname)) 407 408 if container.hostConfig.NetworkMode.IsHost() { 409 sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) 410 sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts")) 411 sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) 412 } else if container.daemon.execDriver.SupportsHooks() { 413 // OptionUseExternalKey is mandatory for userns support. 414 // But optional for non-userns support 415 sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey()) 416 } 417 418 container.HostsPath, err = container.getRootResourcePath("hosts") 419 if err != nil { 420 return nil, err 421 } 422 sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath)) 423 424 container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf") 425 if err != nil { 426 return nil, err 427 } 428 sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath)) 429 430 if len(container.hostConfig.DNS) > 0 { 431 dns = container.hostConfig.DNS 432 } else if len(container.daemon.configStore.DNS) > 0 { 433 dns = container.daemon.configStore.DNS 434 } 435 436 for _, d := range dns { 437 sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) 438 } 439 440 if len(container.hostConfig.DNSSearch) > 0 { 441 dnsSearch = container.hostConfig.DNSSearch 442 } else if len(container.daemon.configStore.DNSSearch) > 0 { 443 dnsSearch = container.daemon.configStore.DNSSearch 444 } 445 446 for _, ds := range dnsSearch { 447 sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) 448 } 449 450 if len(container.hostConfig.DNSOptions) > 0 { 451 dnsOptions = container.hostConfig.DNSOptions 452 } else if len(container.daemon.configStore.DNSOptions) > 0 { 453 dnsOptions = container.daemon.configStore.DNSOptions 454 } 455 456 for _, ds := range dnsOptions { 457 sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds)) 458 } 459 460 if container.NetworkSettings.SecondaryIPAddresses != nil { 461 name := container.Config.Hostname 462 if container.Config.Domainname != "" { 463 name = name + "." + container.Config.Domainname 464 } 465 466 for _, a := range container.NetworkSettings.SecondaryIPAddresses { 467 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) 468 } 469 } 470 471 var childEndpoints, parentEndpoints []string 472 473 children, err := container.daemon.children(container.Name) 474 if err != nil { 475 return nil, err 476 } 477 478 for linkAlias, child := range children { 479 _, alias := path.Split(linkAlias) 480 // allow access to the linked container via the alias, real name, and container hostname 481 aliasList := alias + " " + child.Config.Hostname 482 // only add the name if alias isn't equal to the name 483 if alias != child.Name[1:] { 484 aliasList = aliasList + " " + child.Name[1:] 485 } 486 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.IPAddress)) 487 if child.NetworkSettings.EndpointID != "" { 488 childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID) 489 } 490 } 491 492 for _, extraHost := range container.hostConfig.ExtraHosts { 493 // allow IPv6 addresses in extra hosts; only split on first ":" 494 parts := strings.SplitN(extraHost, ":", 2) 495 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) 496 } 497 498 refs := container.daemon.containerGraph().RefPaths(container.ID) 499 for _, ref := range refs { 500 if ref.ParentID == "0" { 501 continue 502 } 503 504 c, err := container.daemon.Get(ref.ParentID) 505 if err != nil { 506 logrus.Error(err) 507 } 508 509 if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() { 510 logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress) 511 sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, container.NetworkSettings.IPAddress)) 512 if c.NetworkSettings.EndpointID != "" { 513 parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID) 514 } 515 } 516 } 517 518 linkOptions := options.Generic{ 519 netlabel.GenericData: options.Generic{ 520 "ParentEndpoints": parentEndpoints, 521 "ChildEndpoints": childEndpoints, 522 }, 523 } 524 525 sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) 526 527 return sboxOptions, nil 528 } 529 530 func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) { 531 if ep == nil { 532 return nil, derr.ErrorCodeEmptyEndpoint 533 } 534 535 if networkSettings == nil { 536 return nil, derr.ErrorCodeEmptyNetwork 537 } 538 539 driverInfo, err := ep.DriverInfo() 540 if err != nil { 541 return nil, err 542 } 543 544 if driverInfo == nil { 545 // It is not an error for epInfo to be nil 546 return networkSettings, nil 547 } 548 549 if mac, ok := driverInfo[netlabel.MacAddress]; ok { 550 networkSettings.MacAddress = mac.(net.HardwareAddr).String() 551 } 552 553 networkSettings.Ports = nat.PortMap{} 554 555 if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { 556 if exposedPorts, ok := expData.([]types.TransportPort); ok { 557 for _, tp := range exposedPorts { 558 natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) 559 if err != nil { 560 return nil, derr.ErrorCodeParsingPort.WithArgs(tp.Port, err) 561 } 562 networkSettings.Ports[natPort] = nil 563 } 564 } 565 } 566 567 mapData, ok := driverInfo[netlabel.PortMap] 568 if !ok { 569 return networkSettings, nil 570 } 571 572 if portMapping, ok := mapData.([]types.PortBinding); ok { 573 for _, pp := range portMapping { 574 natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) 575 if err != nil { 576 return nil, err 577 } 578 natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))} 579 networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg) 580 } 581 } 582 583 return networkSettings, nil 584 } 585 586 func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) { 587 if ep == nil { 588 return nil, derr.ErrorCodeEmptyEndpoint 589 } 590 591 if networkSettings == nil { 592 return nil, derr.ErrorCodeEmptyNetwork 593 } 594 595 epInfo := ep.Info() 596 if epInfo == nil { 597 // It is not an error to get an empty endpoint info 598 return networkSettings, nil 599 } 600 601 iface := epInfo.Iface() 602 if iface == nil { 603 return networkSettings, nil 604 } 605 606 ones, _ := iface.Address().Mask.Size() 607 networkSettings.IPAddress = iface.Address().IP.String() 608 networkSettings.IPPrefixLen = ones 609 610 if iface.AddressIPv6().IP.To16() != nil { 611 onesv6, _ := iface.AddressIPv6().Mask.Size() 612 networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String() 613 networkSettings.GlobalIPv6PrefixLen = onesv6 614 } 615 616 return networkSettings, nil 617 } 618 619 func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error { 620 epInfo := ep.Info() 621 if epInfo == nil { 622 // It is not an error to get an empty endpoint info 623 return nil 624 } 625 626 container.NetworkSettings.Gateway = epInfo.Gateway().String() 627 if epInfo.GatewayIPv6().To16() != nil { 628 container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String() 629 } 630 631 return nil 632 } 633 634 func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error { 635 networkSettings := &network.Settings{NetworkID: n.ID(), EndpointID: ep.ID()} 636 637 networkSettings, err := container.buildPortMapInfo(ep, networkSettings) 638 if err != nil { 639 return err 640 } 641 642 networkSettings, err = container.buildEndpointInfo(ep, networkSettings) 643 if err != nil { 644 return err 645 } 646 647 if container.hostConfig.NetworkMode == runconfig.NetworkMode("bridge") { 648 networkSettings.Bridge = container.daemon.configStore.Bridge.Iface 649 } 650 651 container.NetworkSettings = networkSettings 652 return nil 653 } 654 655 func (container *Container) updateSandboxNetworkSettings(sb libnetwork.Sandbox) error { 656 container.NetworkSettings.SandboxID = sb.ID() 657 container.NetworkSettings.SandboxKey = sb.Key() 658 return nil 659 } 660 661 // UpdateNetwork is used to update the container's network (e.g. when linked containers 662 // get removed/unlinked). 663 func (container *Container) updateNetwork() error { 664 ctrl := container.daemon.netController 665 sid := container.NetworkSettings.SandboxID 666 667 sb, err := ctrl.SandboxByID(sid) 668 if err != nil { 669 return derr.ErrorCodeNoSandbox.WithArgs(sid, err) 670 } 671 672 options, err := container.buildSandboxOptions() 673 if err != nil { 674 return derr.ErrorCodeNetworkUpdate.WithArgs(err) 675 } 676 677 if err := sb.Refresh(options...); err != nil { 678 return derr.ErrorCodeNetworkRefresh.WithArgs(sid, err) 679 } 680 681 return nil 682 } 683 684 func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointOption, error) { 685 var ( 686 portSpecs = make(nat.PortSet) 687 bindings = make(nat.PortMap) 688 pbList []types.PortBinding 689 exposeList []types.TransportPort 690 createOptions []libnetwork.EndpointOption 691 ) 692 693 if container.Config.ExposedPorts != nil { 694 portSpecs = container.Config.ExposedPorts 695 } 696 697 if container.hostConfig.PortBindings != nil { 698 for p, b := range container.hostConfig.PortBindings { 699 bindings[p] = []nat.PortBinding{} 700 for _, bb := range b { 701 bindings[p] = append(bindings[p], nat.PortBinding{ 702 HostIP: bb.HostIP, 703 HostPort: bb.HostPort, 704 }) 705 } 706 } 707 } 708 709 ports := make([]nat.Port, len(portSpecs)) 710 var i int 711 for p := range portSpecs { 712 ports[i] = p 713 i++ 714 } 715 nat.SortPortMap(ports, bindings) 716 for _, port := range ports { 717 expose := types.TransportPort{} 718 expose.Proto = types.ParseProtocol(port.Proto()) 719 expose.Port = uint16(port.Int()) 720 exposeList = append(exposeList, expose) 721 722 pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} 723 binding := bindings[port] 724 for i := 0; i < len(binding); i++ { 725 pbCopy := pb.GetCopy() 726 newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) 727 var portStart, portEnd int 728 if err == nil { 729 portStart, portEnd, err = newP.Range() 730 } 731 if err != nil { 732 return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err) 733 } 734 pbCopy.HostPort = uint16(portStart) 735 pbCopy.HostPortEnd = uint16(portEnd) 736 pbCopy.HostIP = net.ParseIP(binding[i].HostIP) 737 pbList = append(pbList, pbCopy) 738 } 739 740 if container.hostConfig.PublishAllPorts && len(binding) == 0 { 741 pbList = append(pbList, pb) 742 } 743 } 744 745 createOptions = append(createOptions, 746 libnetwork.CreateOptionPortMapping(pbList), 747 libnetwork.CreateOptionExposedPorts(exposeList)) 748 749 if container.Config.MacAddress != "" { 750 mac, err := net.ParseMAC(container.Config.MacAddress) 751 if err != nil { 752 return nil, err 753 } 754 755 genericOption := options.Generic{ 756 netlabel.MacAddress: mac, 757 } 758 759 createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) 760 } 761 762 return createOptions, nil 763 } 764 765 func parseService(controller libnetwork.NetworkController, service string) (string, string, string) { 766 dn := controller.Config().Daemon.DefaultNetwork 767 dd := controller.Config().Daemon.DefaultDriver 768 769 snd := strings.Split(service, ".") 770 if len(snd) > 2 { 771 return strings.Join(snd[:len(snd)-2], "."), snd[len(snd)-2], snd[len(snd)-1] 772 } 773 if len(snd) > 1 { 774 return snd[0], snd[1], dd 775 } 776 return snd[0], dn, dd 777 } 778 779 func createNetwork(controller libnetwork.NetworkController, dnet string, driver string) (libnetwork.Network, error) { 780 createOptions := []libnetwork.NetworkOption{} 781 genericOption := options.Generic{} 782 783 // Bridge driver is special due to legacy reasons 784 if runconfig.NetworkMode(driver).IsBridge() { 785 genericOption[netlabel.GenericData] = map[string]interface{}{ 786 "BridgeName": dnet, 787 "AllowNonDefaultBridge": "true", 788 } 789 networkOption := libnetwork.NetworkOptionGeneric(genericOption) 790 createOptions = append(createOptions, networkOption) 791 } 792 793 return controller.NewNetwork(driver, dnet, createOptions...) 794 } 795 796 func (container *Container) secondaryNetworkRequired(primaryNetworkType string) bool { 797 switch primaryNetworkType { 798 case "bridge", "none", "host", "container": 799 return false 800 } 801 802 if container.daemon.configStore.DisableBridge { 803 return false 804 } 805 806 if container.Config.ExposedPorts != nil && len(container.Config.ExposedPorts) > 0 { 807 return true 808 } 809 if container.hostConfig.PortBindings != nil && len(container.hostConfig.PortBindings) > 0 { 810 return true 811 } 812 return false 813 } 814 815 func (container *Container) allocateNetwork() error { 816 mode := container.hostConfig.NetworkMode 817 controller := container.daemon.netController 818 if container.Config.NetworkDisabled || mode.IsContainer() { 819 return nil 820 } 821 822 networkDriver := string(mode) 823 service := container.Config.PublishService 824 networkName := mode.NetworkName() 825 if mode.IsDefault() { 826 if service != "" { 827 service, networkName, networkDriver = parseService(controller, service) 828 } else { 829 networkName = controller.Config().Daemon.DefaultNetwork 830 networkDriver = controller.Config().Daemon.DefaultDriver 831 } 832 } else if service != "" { 833 return derr.ErrorCodeNetworkConflict 834 } 835 836 if runconfig.NetworkMode(networkDriver).IsBridge() && container.daemon.configStore.DisableBridge { 837 container.Config.NetworkDisabled = true 838 return nil 839 } 840 841 if service == "" { 842 // dot character "." has a special meaning to support SERVICE[.NETWORK] format. 843 // For backward compatibility, replacing "." with "-", instead of failing 844 service = strings.Replace(container.Name, ".", "-", -1) 845 // Service names dont like "/" in them. removing it instead of failing for backward compatibility 846 service = strings.Replace(service, "/", "", -1) 847 } 848 849 if container.secondaryNetworkRequired(networkDriver) { 850 // Configure Bridge as secondary network for port binding purposes 851 if err := container.configureNetwork("bridge", service, "bridge", false); err != nil { 852 return err 853 } 854 } 855 856 if err := container.configureNetwork(networkName, service, networkDriver, mode.IsDefault()); err != nil { 857 return err 858 } 859 860 return container.writeHostConfig() 861 } 862 863 func (container *Container) configureNetwork(networkName, service, networkDriver string, canCreateNetwork bool) error { 864 controller := container.daemon.netController 865 866 n, err := controller.NetworkByName(networkName) 867 if err != nil { 868 if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok || !canCreateNetwork { 869 return err 870 } 871 872 if n, err = createNetwork(controller, networkName, networkDriver); err != nil { 873 return err 874 } 875 } 876 877 ep, err := n.EndpointByName(service) 878 if err != nil { 879 if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok { 880 return err 881 } 882 883 createOptions, err := container.buildCreateEndpointOptions() 884 if err != nil { 885 return err 886 } 887 888 ep, err = n.CreateEndpoint(service, createOptions...) 889 if err != nil { 890 return err 891 } 892 } 893 894 if err := container.updateEndpointNetworkSettings(n, ep); err != nil { 895 return err 896 } 897 898 var sb libnetwork.Sandbox 899 controller.WalkSandboxes(func(s libnetwork.Sandbox) bool { 900 if s.ContainerID() == container.ID { 901 sb = s 902 return true 903 } 904 return false 905 }) 906 if sb == nil { 907 options, err := container.buildSandboxOptions() 908 if err != nil { 909 return err 910 } 911 sb, err = controller.NewSandbox(container.ID, options...) 912 if err != nil { 913 return err 914 } 915 } 916 917 container.updateSandboxNetworkSettings(sb) 918 919 if err := ep.Join(sb); err != nil { 920 return err 921 } 922 923 if err := container.updateJoinInfo(ep); err != nil { 924 return derr.ErrorCodeJoinInfo.WithArgs(err) 925 } 926 927 return nil 928 } 929 930 func (container *Container) initializeNetworking() error { 931 var err error 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 // called from the libcontainer pre-start hook to set the network 969 // namespace configuration linkage to the libnetwork "sandbox" entity 970 func (container *Container) setNetworkNamespaceKey(pid int) error { 971 path := fmt.Sprintf("/proc/%d/ns/net", pid) 972 var sandbox libnetwork.Sandbox 973 search := libnetwork.SandboxContainerWalker(&sandbox, container.ID) 974 container.daemon.netController.WalkSandboxes(search) 975 if sandbox == nil { 976 return fmt.Errorf("no sandbox present for %s", container.ID) 977 } 978 979 return sandbox.SetKey(path) 980 } 981 982 func (container *Container) getIpcContainer() (*Container, error) { 983 containerID := container.hostConfig.IpcMode.Container() 984 c, err := container.daemon.Get(containerID) 985 if err != nil { 986 return nil, err 987 } 988 if !c.IsRunning() { 989 return nil, derr.ErrorCodeIPCRunning 990 } 991 return c, nil 992 } 993 994 func (container *Container) setupWorkingDirectory() error { 995 if container.Config.WorkingDir != "" { 996 container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) 997 998 pth, err := container.GetResourcePath(container.Config.WorkingDir) 999 if err != nil { 1000 return err 1001 } 1002 1003 pthInfo, err := os.Stat(pth) 1004 if err != nil { 1005 if !os.IsNotExist(err) { 1006 return err 1007 } 1008 1009 if err := system.MkdirAll(pth, 0755); err != nil { 1010 return err 1011 } 1012 } 1013 if pthInfo != nil && !pthInfo.IsDir() { 1014 return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir) 1015 } 1016 } 1017 return nil 1018 } 1019 1020 func (container *Container) getNetworkedContainer() (*Container, error) { 1021 parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2) 1022 switch parts[0] { 1023 case "container": 1024 if len(parts) != 2 { 1025 return nil, derr.ErrorCodeParseContainer 1026 } 1027 nc, err := container.daemon.Get(parts[1]) 1028 if err != nil { 1029 return nil, err 1030 } 1031 if container == nc { 1032 return nil, derr.ErrorCodeJoinSelf 1033 } 1034 if !nc.IsRunning() { 1035 return nil, derr.ErrorCodeJoinRunning.WithArgs(parts[1]) 1036 } 1037 return nc, nil 1038 default: 1039 return nil, derr.ErrorCodeModeNotContainer 1040 } 1041 } 1042 1043 func (container *Container) releaseNetwork() { 1044 if container.hostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled { 1045 return 1046 } 1047 1048 sid := container.NetworkSettings.SandboxID 1049 eid := container.NetworkSettings.EndpointID 1050 nid := container.NetworkSettings.NetworkID 1051 1052 container.NetworkSettings = &network.Settings{} 1053 1054 if sid == "" || nid == "" || eid == "" { 1055 return 1056 } 1057 1058 sb, err := container.daemon.netController.SandboxByID(sid) 1059 if err != nil { 1060 logrus.Errorf("error locating sandbox id %s: %v", sid, err) 1061 return 1062 } 1063 1064 n, err := container.daemon.netController.NetworkByID(nid) 1065 if err != nil { 1066 logrus.Errorf("error locating network id %s: %v", nid, err) 1067 return 1068 } 1069 1070 ep, err := n.EndpointByID(eid) 1071 if err != nil { 1072 logrus.Errorf("error locating endpoint id %s: %v", eid, err) 1073 return 1074 } 1075 1076 if err := sb.Delete(); err != nil { 1077 logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err) 1078 return 1079 } 1080 1081 // In addition to leaving all endpoints, delete implicitly created endpoint 1082 if container.Config.PublishService == "" { 1083 if err := ep.Delete(); err != nil { 1084 logrus.Errorf("deleting endpoint failed: %v", err) 1085 } 1086 } 1087 } 1088 1089 func (container *Container) unmountVolumes(forceSyscall bool) error { 1090 var volumeMounts []mountPoint 1091 1092 for _, mntPoint := range container.MountPoints { 1093 dest, err := container.GetResourcePath(mntPoint.Destination) 1094 if err != nil { 1095 return err 1096 } 1097 1098 volumeMounts = append(volumeMounts, mountPoint{Destination: dest, Volume: mntPoint.Volume}) 1099 } 1100 1101 for _, mnt := range container.networkMounts() { 1102 dest, err := container.GetResourcePath(mnt.Destination) 1103 if err != nil { 1104 return err 1105 } 1106 1107 volumeMounts = append(volumeMounts, mountPoint{Destination: dest}) 1108 } 1109 1110 for _, volumeMount := range volumeMounts { 1111 if forceSyscall { 1112 syscall.Unmount(volumeMount.Destination, 0) 1113 } 1114 1115 if volumeMount.Volume != nil { 1116 if err := volumeMount.Volume.Unmount(); err != nil { 1117 return err 1118 } 1119 } 1120 } 1121 1122 return nil 1123 } 1124 1125 func (container *Container) networkMounts() []execdriver.Mount { 1126 var mounts []execdriver.Mount 1127 shared := container.hostConfig.NetworkMode.IsContainer() 1128 if container.ResolvConfPath != "" { 1129 label.Relabel(container.ResolvConfPath, container.MountLabel, shared) 1130 writable := !container.hostConfig.ReadonlyRootfs 1131 if m, exists := container.MountPoints["/etc/resolv.conf"]; exists { 1132 writable = m.RW 1133 } 1134 mounts = append(mounts, execdriver.Mount{ 1135 Source: container.ResolvConfPath, 1136 Destination: "/etc/resolv.conf", 1137 Writable: writable, 1138 Private: true, 1139 }) 1140 } 1141 if container.HostnamePath != "" { 1142 label.Relabel(container.HostnamePath, container.MountLabel, shared) 1143 writable := !container.hostConfig.ReadonlyRootfs 1144 if m, exists := container.MountPoints["/etc/hostname"]; exists { 1145 writable = m.RW 1146 } 1147 mounts = append(mounts, execdriver.Mount{ 1148 Source: container.HostnamePath, 1149 Destination: "/etc/hostname", 1150 Writable: writable, 1151 Private: true, 1152 }) 1153 } 1154 if container.HostsPath != "" { 1155 label.Relabel(container.HostsPath, container.MountLabel, shared) 1156 writable := !container.hostConfig.ReadonlyRootfs 1157 if m, exists := container.MountPoints["/etc/hosts"]; exists { 1158 writable = m.RW 1159 } 1160 mounts = append(mounts, execdriver.Mount{ 1161 Source: container.HostsPath, 1162 Destination: "/etc/hosts", 1163 Writable: writable, 1164 Private: true, 1165 }) 1166 } 1167 return mounts 1168 } 1169 1170 func (container *Container) addBindMountPoint(name, source, destination string, rw bool) { 1171 container.MountPoints[destination] = &mountPoint{ 1172 Name: name, 1173 Source: source, 1174 Destination: destination, 1175 RW: rw, 1176 } 1177 } 1178 1179 func (container *Container) addLocalMountPoint(name, destination string, rw bool) { 1180 container.MountPoints[destination] = &mountPoint{ 1181 Name: name, 1182 Driver: volume.DefaultDriverName, 1183 Destination: destination, 1184 RW: rw, 1185 } 1186 } 1187 1188 func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) { 1189 container.MountPoints[destination] = &mountPoint{ 1190 Name: vol.Name(), 1191 Driver: vol.DriverName(), 1192 Destination: destination, 1193 RW: rw, 1194 Volume: vol, 1195 } 1196 } 1197 1198 func (container *Container) isDestinationMounted(destination string) bool { 1199 return container.MountPoints[destination] != nil 1200 } 1201 1202 func (container *Container) prepareMountPoints() error { 1203 for _, config := range container.MountPoints { 1204 if len(config.Driver) > 0 { 1205 v, err := container.daemon.createVolume(config.Name, config.Driver, nil) 1206 if err != nil { 1207 return err 1208 } 1209 config.Volume = v 1210 } 1211 } 1212 return nil 1213 } 1214 1215 func (container *Container) removeMountPoints(rm bool) error { 1216 var rmErrors []string 1217 for _, m := range container.MountPoints { 1218 if m.Volume == nil { 1219 continue 1220 } 1221 container.daemon.volumes.Decrement(m.Volume) 1222 if rm { 1223 err := container.daemon.volumes.Remove(m.Volume) 1224 // ErrVolumeInUse is ignored because having this 1225 // volume being referenced by othe container is 1226 // not an error, but an implementation detail. 1227 // This prevents docker from logging "ERROR: Volume in use" 1228 // where there is another container using the volume. 1229 if err != nil && err != store.ErrVolumeInUse { 1230 rmErrors = append(rmErrors, err.Error()) 1231 } 1232 } 1233 } 1234 if len(rmErrors) > 0 { 1235 return derr.ErrorCodeRemovingVolume.WithArgs(strings.Join(rmErrors, "\n")) 1236 } 1237 return nil 1238 }