github.com/fntlnz/docker@v1.9.0-rc3/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/idtools" 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/docker/volume" 31 "github.com/docker/docker/volume/store" 32 "github.com/docker/libnetwork" 33 "github.com/docker/libnetwork/drivers/bridge" 34 "github.com/docker/libnetwork/netlabel" 35 "github.com/docker/libnetwork/options" 36 "github.com/docker/libnetwork/types" 37 "github.com/opencontainers/runc/libcontainer/configs" 38 "github.com/opencontainers/runc/libcontainer/devices" 39 "github.com/opencontainers/runc/libcontainer/label" 40 ) 41 42 // DefaultPathEnv is unix style list of directories to search for 43 // executables. Each directory is separated from the next by a colon 44 // ':' character . 45 const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 46 47 // Container holds the fields specific to unixen implementations. See 48 // CommonContainer for standard fields common to all containers. 49 type Container struct { 50 CommonContainer 51 52 // Fields below here are platform specific. 53 activeLinks map[string]*links.Link 54 AppArmorProfile string 55 HostnamePath string 56 HostsPath string 57 ShmPath string 58 MqueuePath string 59 MountPoints map[string]*mountPoint 60 ResolvConfPath string 61 62 Volumes map[string]string // Deprecated since 1.7, kept for backwards compatibility 63 VolumesRW map[string]bool // Deprecated since 1.7, kept for backwards compatibility 64 } 65 66 func killProcessDirectly(container *Container) error { 67 if _, err := container.WaitStop(10 * time.Second); err != nil { 68 // Ensure that we don't kill ourselves 69 if pid := container.getPID(); pid != 0 { 70 logrus.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", stringid.TruncateID(container.ID)) 71 if err := syscall.Kill(pid, 9); err != nil { 72 if err != syscall.ESRCH { 73 return err 74 } 75 logrus.Debugf("Cannot kill process (pid=%d) with signal 9: no such process.", pid) 76 } 77 } 78 } 79 return nil 80 } 81 82 func (container *Container) setupLinkedContainers() ([]string, error) { 83 var ( 84 env []string 85 daemon = container.daemon 86 ) 87 children, err := daemon.children(container.Name) 88 if err != nil { 89 return nil, err 90 } 91 92 bridgeSettings := container.NetworkSettings.Networks["bridge"] 93 if bridgeSettings == nil { 94 return nil, nil 95 } 96 97 if len(children) > 0 { 98 for linkAlias, child := range children { 99 if !child.IsRunning() { 100 return nil, derr.ErrorCodeLinkNotRunning.WithArgs(child.Name, linkAlias) 101 } 102 103 childBridgeSettings := child.NetworkSettings.Networks["bridge"] 104 if childBridgeSettings == nil { 105 return nil, fmt.Errorf("container %d not attached to default bridge network", child.ID) 106 } 107 108 link := links.NewLink( 109 bridgeSettings.IPAddress, 110 childBridgeSettings.IPAddress, 111 linkAlias, 112 child.Config.Env, 113 child.Config.ExposedPorts, 114 ) 115 116 for _, envVar := range link.ToEnv() { 117 env = append(env, envVar) 118 } 119 } 120 } 121 return env, nil 122 } 123 124 func (container *Container) createDaemonEnvironment(linkedEnv []string) []string { 125 // if a domain name was specified, append it to the hostname (see #7851) 126 fullHostname := container.Config.Hostname 127 if container.Config.Domainname != "" { 128 fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname) 129 } 130 // Setup environment 131 env := []string{ 132 "PATH=" + DefaultPathEnv, 133 "HOSTNAME=" + fullHostname, 134 // Note: we don't set HOME here because it'll get autoset intelligently 135 // based on the value of USER inside dockerinit, but only if it isn't 136 // set already (ie, that can be overridden by setting HOME via -e or ENV 137 // in a Dockerfile). 138 } 139 if container.Config.Tty { 140 env = append(env, "TERM=xterm") 141 } 142 env = append(env, linkedEnv...) 143 // because the env on the container can override certain default values 144 // we need to replace the 'env' keys where they match and append anything 145 // else. 146 env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env) 147 148 return env 149 } 150 151 func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.Device, err error) { 152 device, err := devices.DeviceFromPath(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions) 153 // if there was no error, return the device 154 if err == nil { 155 device.Path = deviceMapping.PathInContainer 156 return append(devs, device), nil 157 } 158 159 // if the device is not a device node 160 // try to see if it's a directory holding many devices 161 if err == devices.ErrNotADevice { 162 163 // check if it is a directory 164 if src, e := os.Stat(deviceMapping.PathOnHost); e == nil && src.IsDir() { 165 166 // mount the internal devices recursively 167 filepath.Walk(deviceMapping.PathOnHost, func(dpath string, f os.FileInfo, e error) error { 168 childDevice, e := devices.DeviceFromPath(dpath, deviceMapping.CgroupPermissions) 169 if e != nil { 170 // ignore the device 171 return nil 172 } 173 174 // add the device to userSpecified devices 175 childDevice.Path = strings.Replace(dpath, deviceMapping.PathOnHost, deviceMapping.PathInContainer, 1) 176 devs = append(devs, childDevice) 177 178 return nil 179 }) 180 } 181 } 182 183 if len(devs) > 0 { 184 return devs, nil 185 } 186 187 return devs, derr.ErrorCodeDeviceInfo.WithArgs(deviceMapping.PathOnHost, err) 188 } 189 190 func populateCommand(c *Container, env []string) error { 191 var en *execdriver.Network 192 if !c.Config.NetworkDisabled { 193 en = &execdriver.Network{} 194 if !c.daemon.execDriver.SupportsHooks() || c.hostConfig.NetworkMode.IsHost() { 195 en.NamespacePath = c.NetworkSettings.SandboxKey 196 } 197 198 parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2) 199 if parts[0] == "container" { 200 nc, err := c.getNetworkedContainer() 201 if err != nil { 202 return err 203 } 204 en.ContainerID = nc.ID 205 } 206 } 207 208 ipc := &execdriver.Ipc{} 209 var err error 210 c.ShmPath, err = c.shmPath() 211 if err != nil { 212 return err 213 } 214 215 c.MqueuePath, err = c.mqueuePath() 216 if err != nil { 217 return err 218 } 219 220 if c.hostConfig.IpcMode.IsContainer() { 221 ic, err := c.getIpcContainer() 222 if err != nil { 223 return err 224 } 225 ipc.ContainerID = ic.ID 226 c.ShmPath = ic.ShmPath 227 c.MqueuePath = ic.MqueuePath 228 } else { 229 ipc.HostIpc = c.hostConfig.IpcMode.IsHost() 230 if ipc.HostIpc { 231 if _, err := os.Stat("/dev/shm"); err != nil { 232 return fmt.Errorf("/dev/shm is not mounted, but must be for --host=ipc") 233 } 234 if _, err := os.Stat("/dev/mqueue"); err != nil { 235 return fmt.Errorf("/dev/mqueue is not mounted, but must be for --host=ipc") 236 } 237 c.ShmPath = "/dev/shm" 238 c.MqueuePath = "/dev/mqueue" 239 } 240 } 241 242 pid := &execdriver.Pid{} 243 pid.HostPid = c.hostConfig.PidMode.IsHost() 244 245 uts := &execdriver.UTS{ 246 HostUTS: c.hostConfig.UTSMode.IsHost(), 247 } 248 249 // Build lists of devices allowed and created within the container. 250 var userSpecifiedDevices []*configs.Device 251 for _, deviceMapping := range c.hostConfig.Devices { 252 devs, err := getDevicesFromPath(deviceMapping) 253 if err != nil { 254 return err 255 } 256 257 userSpecifiedDevices = append(userSpecifiedDevices, devs...) 258 } 259 260 allowedDevices := mergeDevices(configs.DefaultAllowedDevices, userSpecifiedDevices) 261 262 autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices) 263 264 // TODO: this can be removed after lxc-conf is fully deprecated 265 lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig) 266 if err != nil { 267 return err 268 } 269 270 var rlimits []*ulimit.Rlimit 271 ulimits := c.hostConfig.Ulimits 272 273 // Merge ulimits with daemon defaults 274 ulIdx := make(map[string]*ulimit.Ulimit) 275 for _, ul := range ulimits { 276 ulIdx[ul.Name] = ul 277 } 278 for name, ul := range c.daemon.configStore.Ulimits { 279 if _, exists := ulIdx[name]; !exists { 280 ulimits = append(ulimits, ul) 281 } 282 } 283 284 for _, limit := range ulimits { 285 rl, err := limit.GetRlimit() 286 if err != nil { 287 return err 288 } 289 rlimits = append(rlimits, rl) 290 } 291 292 resources := &execdriver.Resources{ 293 Memory: c.hostConfig.Memory, 294 MemorySwap: c.hostConfig.MemorySwap, 295 MemoryReservation: c.hostConfig.MemoryReservation, 296 KernelMemory: c.hostConfig.KernelMemory, 297 CPUShares: c.hostConfig.CPUShares, 298 CpusetCpus: c.hostConfig.CpusetCpus, 299 CpusetMems: c.hostConfig.CpusetMems, 300 CPUPeriod: c.hostConfig.CPUPeriod, 301 CPUQuota: c.hostConfig.CPUQuota, 302 BlkioWeight: c.hostConfig.BlkioWeight, 303 Rlimits: rlimits, 304 OomKillDisable: c.hostConfig.OomKillDisable, 305 MemorySwappiness: -1, 306 } 307 308 if c.hostConfig.MemorySwappiness != nil { 309 resources.MemorySwappiness = *c.hostConfig.MemorySwappiness 310 } 311 312 processConfig := execdriver.ProcessConfig{ 313 Privileged: c.hostConfig.Privileged, 314 Entrypoint: c.Path, 315 Arguments: c.Args, 316 Tty: c.Config.Tty, 317 User: c.Config.User, 318 } 319 320 processConfig.SysProcAttr = &syscall.SysProcAttr{Setsid: true} 321 processConfig.Env = env 322 323 remappedRoot := &execdriver.User{} 324 rootUID, rootGID := c.daemon.GetRemappedUIDGID() 325 if rootUID != 0 { 326 remappedRoot.UID = rootUID 327 remappedRoot.GID = rootGID 328 } 329 uidMap, gidMap := c.daemon.GetUIDGIDMaps() 330 331 c.command = &execdriver.Command{ 332 ID: c.ID, 333 Rootfs: c.rootfsPath(), 334 ReadonlyRootfs: c.hostConfig.ReadonlyRootfs, 335 InitPath: "/.dockerinit", 336 WorkingDir: c.Config.WorkingDir, 337 Network: en, 338 Ipc: ipc, 339 UIDMapping: uidMap, 340 GIDMapping: gidMap, 341 RemappedRoot: remappedRoot, 342 Pid: pid, 343 UTS: uts, 344 Resources: resources, 345 AllowedDevices: allowedDevices, 346 AutoCreatedDevices: autoCreatedDevices, 347 CapAdd: c.hostConfig.CapAdd.Slice(), 348 CapDrop: c.hostConfig.CapDrop.Slice(), 349 GroupAdd: c.hostConfig.GroupAdd, 350 ProcessConfig: processConfig, 351 ProcessLabel: c.getProcessLabel(), 352 MountLabel: c.getMountLabel(), 353 LxcConfig: lxcConfig, 354 AppArmorProfile: c.AppArmorProfile, 355 CgroupParent: c.hostConfig.CgroupParent, 356 } 357 358 return nil 359 } 360 361 func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Device { 362 if len(userDevices) == 0 { 363 return defaultDevices 364 } 365 366 paths := map[string]*configs.Device{} 367 for _, d := range userDevices { 368 paths[d.Path] = d 369 } 370 371 var devs []*configs.Device 372 for _, d := range defaultDevices { 373 if _, defined := paths[d.Path]; !defined { 374 devs = append(devs, d) 375 } 376 } 377 return append(devs, userDevices...) 378 } 379 380 // GetSize returns the real size & virtual size of the container. 381 func (container *Container) getSize() (int64, int64) { 382 var ( 383 sizeRw, sizeRootfs int64 384 err error 385 driver = container.daemon.driver 386 ) 387 388 if err := container.Mount(); err != nil { 389 logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err) 390 return sizeRw, sizeRootfs 391 } 392 defer container.Unmount() 393 394 initID := fmt.Sprintf("%s-init", container.ID) 395 sizeRw, err = driver.DiffSize(container.ID, initID) 396 if err != nil { 397 logrus.Errorf("Driver %s couldn't return diff size of container %s: %s", driver, container.ID, err) 398 // FIXME: GetSize should return an error. Not changing it now in case 399 // there is a side-effect. 400 sizeRw = -1 401 } 402 403 if _, err = os.Stat(container.basefs); err == nil { 404 if sizeRootfs, err = directory.Size(container.basefs); err != nil { 405 sizeRootfs = -1 406 } 407 } 408 return sizeRw, sizeRootfs 409 } 410 411 // Attempt to set the network mounts given a provided destination and 412 // the path to use for it; return true if the given destination was a 413 // network mount file 414 func (container *Container) trySetNetworkMount(destination string, path string) bool { 415 if destination == "/etc/resolv.conf" { 416 container.ResolvConfPath = path 417 return true 418 } 419 if destination == "/etc/hostname" { 420 container.HostnamePath = path 421 return true 422 } 423 if destination == "/etc/hosts" { 424 container.HostsPath = path 425 return true 426 } 427 428 return false 429 } 430 431 func (container *Container) buildHostnameFile() error { 432 hostnamePath, err := container.getRootResourcePath("hostname") 433 if err != nil { 434 return err 435 } 436 container.HostnamePath = hostnamePath 437 438 if container.Config.Domainname != "" { 439 return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644) 440 } 441 return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) 442 } 443 444 func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetwork.SandboxOption, error) { 445 var ( 446 sboxOptions []libnetwork.SandboxOption 447 err error 448 dns []string 449 dnsSearch []string 450 dnsOptions []string 451 ) 452 453 sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), 454 libnetwork.OptionDomainname(container.Config.Domainname)) 455 456 if container.hostConfig.NetworkMode.IsHost() { 457 sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) 458 sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts")) 459 sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) 460 } else if container.daemon.execDriver.SupportsHooks() { 461 // OptionUseExternalKey is mandatory for userns support. 462 // But optional for non-userns support 463 sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey()) 464 } 465 466 container.HostsPath, err = container.getRootResourcePath("hosts") 467 if err != nil { 468 return nil, err 469 } 470 sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath)) 471 472 container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf") 473 if err != nil { 474 return nil, err 475 } 476 sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath)) 477 478 if len(container.hostConfig.DNS) > 0 { 479 dns = container.hostConfig.DNS 480 } else if len(container.daemon.configStore.DNS) > 0 { 481 dns = container.daemon.configStore.DNS 482 } 483 484 for _, d := range dns { 485 sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) 486 } 487 488 if len(container.hostConfig.DNSSearch) > 0 { 489 dnsSearch = container.hostConfig.DNSSearch 490 } else if len(container.daemon.configStore.DNSSearch) > 0 { 491 dnsSearch = container.daemon.configStore.DNSSearch 492 } 493 494 for _, ds := range dnsSearch { 495 sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) 496 } 497 498 if len(container.hostConfig.DNSOptions) > 0 { 499 dnsOptions = container.hostConfig.DNSOptions 500 } else if len(container.daemon.configStore.DNSOptions) > 0 { 501 dnsOptions = container.daemon.configStore.DNSOptions 502 } 503 504 for _, ds := range dnsOptions { 505 sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds)) 506 } 507 508 if container.NetworkSettings.SecondaryIPAddresses != nil { 509 name := container.Config.Hostname 510 if container.Config.Domainname != "" { 511 name = name + "." + container.Config.Domainname 512 } 513 514 for _, a := range container.NetworkSettings.SecondaryIPAddresses { 515 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) 516 } 517 } 518 519 for _, extraHost := range container.hostConfig.ExtraHosts { 520 // allow IPv6 addresses in extra hosts; only split on first ":" 521 parts := strings.SplitN(extraHost, ":", 2) 522 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) 523 } 524 525 // Link feature is supported only for the default bridge network. 526 // return if this call to build join options is not for default bridge network 527 if n.Name() != "bridge" { 528 return sboxOptions, nil 529 } 530 531 ep, _ := container.getEndpointInNetwork(n) 532 if ep == nil { 533 return sboxOptions, nil 534 } 535 536 var childEndpoints, parentEndpoints []string 537 538 children, err := container.daemon.children(container.Name) 539 if err != nil { 540 return nil, err 541 } 542 543 for linkAlias, child := range children { 544 if !isLinkable(child) { 545 return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name) 546 } 547 _, alias := path.Split(linkAlias) 548 // allow access to the linked container via the alias, real name, and container hostname 549 aliasList := alias + " " + child.Config.Hostname 550 // only add the name if alias isn't equal to the name 551 if alias != child.Name[1:] { 552 aliasList = aliasList + " " + child.Name[1:] 553 } 554 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks["bridge"].IPAddress)) 555 cEndpoint, _ := child.getEndpointInNetwork(n) 556 if cEndpoint != nil && cEndpoint.ID() != "" { 557 childEndpoints = append(childEndpoints, cEndpoint.ID()) 558 } 559 } 560 561 bridgeSettings := container.NetworkSettings.Networks["bridge"] 562 refs := container.daemon.containerGraph().RefPaths(container.ID) 563 for _, ref := range refs { 564 if ref.ParentID == "0" { 565 continue 566 } 567 568 c, err := container.daemon.Get(ref.ParentID) 569 if err != nil { 570 logrus.Error(err) 571 } 572 573 if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() { 574 logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, bridgeSettings.IPAddress) 575 sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, bridgeSettings.IPAddress)) 576 if ep.ID() != "" { 577 parentEndpoints = append(parentEndpoints, ep.ID()) 578 } 579 } 580 } 581 582 linkOptions := options.Generic{ 583 netlabel.GenericData: options.Generic{ 584 "ParentEndpoints": parentEndpoints, 585 "ChildEndpoints": childEndpoints, 586 }, 587 } 588 589 sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) 590 591 return sboxOptions, nil 592 } 593 594 func isLinkable(child *Container) bool { 595 // A container is linkable only if it belongs to the default network 596 _, ok := child.NetworkSettings.Networks["bridge"] 597 return ok 598 } 599 600 func (container *Container) getEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) { 601 endpointName := strings.TrimPrefix(container.Name, "/") 602 return n.EndpointByName(endpointName) 603 } 604 605 func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) { 606 if ep == nil { 607 return nil, derr.ErrorCodeEmptyEndpoint 608 } 609 610 if networkSettings == nil { 611 return nil, derr.ErrorCodeEmptyNetwork 612 } 613 614 driverInfo, err := ep.DriverInfo() 615 if err != nil { 616 return nil, err 617 } 618 619 if driverInfo == nil { 620 // It is not an error for epInfo to be nil 621 return networkSettings, nil 622 } 623 624 networkSettings.Ports = nat.PortMap{} 625 626 if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { 627 if exposedPorts, ok := expData.([]types.TransportPort); ok { 628 for _, tp := range exposedPorts { 629 natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) 630 if err != nil { 631 return nil, derr.ErrorCodeParsingPort.WithArgs(tp.Port, err) 632 } 633 networkSettings.Ports[natPort] = nil 634 } 635 } 636 } 637 638 mapData, ok := driverInfo[netlabel.PortMap] 639 if !ok { 640 return networkSettings, nil 641 } 642 643 if portMapping, ok := mapData.([]types.PortBinding); ok { 644 for _, pp := range portMapping { 645 natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) 646 if err != nil { 647 return nil, err 648 } 649 natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))} 650 networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg) 651 } 652 } 653 654 return networkSettings, nil 655 } 656 657 func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) { 658 if ep == nil { 659 return nil, derr.ErrorCodeEmptyEndpoint 660 } 661 662 if networkSettings == nil { 663 return nil, derr.ErrorCodeEmptyNetwork 664 } 665 666 epInfo := ep.Info() 667 if epInfo == nil { 668 // It is not an error to get an empty endpoint info 669 return networkSettings, nil 670 } 671 672 if _, ok := networkSettings.Networks[n.Name()]; !ok { 673 networkSettings.Networks[n.Name()] = new(network.EndpointSettings) 674 } 675 networkSettings.Networks[n.Name()].EndpointID = ep.ID() 676 677 iface := epInfo.Iface() 678 if iface == nil { 679 return networkSettings, nil 680 } 681 682 if iface.Address() != nil { 683 ones, _ := iface.Address().Mask.Size() 684 networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String() 685 networkSettings.Networks[n.Name()].IPPrefixLen = ones 686 } 687 688 if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil { 689 onesv6, _ := iface.AddressIPv6().Mask.Size() 690 networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String() 691 networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6 692 } 693 694 driverInfo, err := ep.DriverInfo() 695 if err != nil { 696 return nil, err 697 } 698 699 if driverInfo == nil { 700 // It is not an error for epInfo to be nil 701 return networkSettings, nil 702 } 703 if mac, ok := driverInfo[netlabel.MacAddress]; ok { 704 networkSettings.Networks[n.Name()].MacAddress = mac.(net.HardwareAddr).String() 705 } 706 707 return networkSettings, nil 708 } 709 710 func (container *Container) updateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error { 711 epInfo := ep.Info() 712 if epInfo == nil { 713 // It is not an error to get an empty endpoint info 714 return nil 715 } 716 container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String() 717 if epInfo.GatewayIPv6().To16() != nil { 718 container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String() 719 } 720 721 return nil 722 } 723 724 func (container *Container) updateNetworkSettings(n libnetwork.Network) error { 725 if container.NetworkSettings == nil { 726 container.NetworkSettings = &network.Settings{Networks: make(map[string]*network.EndpointSettings)} 727 } 728 729 for s := range container.NetworkSettings.Networks { 730 sn, err := container.daemon.FindNetwork(s) 731 if err != nil { 732 continue 733 } 734 735 if sn.Name() == n.Name() { 736 // Avoid duplicate config 737 return nil 738 } 739 if !runconfig.NetworkMode(sn.Type()).IsPrivate() || 740 !runconfig.NetworkMode(n.Type()).IsPrivate() { 741 return runconfig.ErrConflictSharedNetwork 742 } 743 if runconfig.NetworkMode(sn.Name()).IsNone() || 744 runconfig.NetworkMode(n.Name()).IsNone() { 745 return runconfig.ErrConflictNoNetwork 746 } 747 } 748 container.NetworkSettings.Networks[n.Name()] = new(network.EndpointSettings) 749 750 return nil 751 } 752 753 func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error { 754 networkSettings, err := container.buildPortMapInfo(ep, container.NetworkSettings) 755 if err != nil { 756 return err 757 } 758 759 networkSettings, err = container.buildEndpointInfo(n, ep, networkSettings) 760 if err != nil { 761 return err 762 } 763 764 if container.hostConfig.NetworkMode == runconfig.NetworkMode("bridge") { 765 networkSettings.Bridge = container.daemon.configStore.Bridge.Iface 766 } 767 768 return nil 769 } 770 771 func (container *Container) updateSandboxNetworkSettings(sb libnetwork.Sandbox) error { 772 container.NetworkSettings.SandboxID = sb.ID() 773 container.NetworkSettings.SandboxKey = sb.Key() 774 return nil 775 } 776 777 // UpdateNetwork is used to update the container's network (e.g. when linked containers 778 // get removed/unlinked). 779 func (container *Container) updateNetwork() error { 780 ctrl := container.daemon.netController 781 sid := container.NetworkSettings.SandboxID 782 783 sb, err := ctrl.SandboxByID(sid) 784 if err != nil { 785 return derr.ErrorCodeNoSandbox.WithArgs(sid, err) 786 } 787 788 // Find if container is connected to the default bridge network 789 var n libnetwork.Network 790 for name := range container.NetworkSettings.Networks { 791 sn, err := container.daemon.FindNetwork(name) 792 if err != nil { 793 continue 794 } 795 if sn.Name() == "bridge" { 796 n = sn 797 break 798 } 799 } 800 801 if n == nil { 802 // Not connected to the default bridge network; Nothing to do 803 return nil 804 } 805 806 options, err := container.buildSandboxOptions(n) 807 if err != nil { 808 return derr.ErrorCodeNetworkUpdate.WithArgs(err) 809 } 810 811 if err := sb.Refresh(options...); err != nil { 812 return derr.ErrorCodeNetworkRefresh.WithArgs(sid, err) 813 } 814 815 return nil 816 } 817 818 func (container *Container) buildCreateEndpointOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) { 819 var ( 820 portSpecs = make(nat.PortSet) 821 bindings = make(nat.PortMap) 822 pbList []types.PortBinding 823 exposeList []types.TransportPort 824 createOptions []libnetwork.EndpointOption 825 ) 826 827 if container.Config.ExposedPorts != nil { 828 portSpecs = container.Config.ExposedPorts 829 } 830 831 if container.hostConfig.PortBindings != nil { 832 for p, b := range container.hostConfig.PortBindings { 833 bindings[p] = []nat.PortBinding{} 834 for _, bb := range b { 835 bindings[p] = append(bindings[p], nat.PortBinding{ 836 HostIP: bb.HostIP, 837 HostPort: bb.HostPort, 838 }) 839 } 840 } 841 } 842 843 ports := make([]nat.Port, len(portSpecs)) 844 var i int 845 for p := range portSpecs { 846 ports[i] = p 847 i++ 848 } 849 nat.SortPortMap(ports, bindings) 850 for _, port := range ports { 851 expose := types.TransportPort{} 852 expose.Proto = types.ParseProtocol(port.Proto()) 853 expose.Port = uint16(port.Int()) 854 exposeList = append(exposeList, expose) 855 856 pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} 857 binding := bindings[port] 858 for i := 0; i < len(binding); i++ { 859 pbCopy := pb.GetCopy() 860 newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) 861 var portStart, portEnd int 862 if err == nil { 863 portStart, portEnd, err = newP.Range() 864 } 865 if err != nil { 866 return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err) 867 } 868 pbCopy.HostPort = uint16(portStart) 869 pbCopy.HostPortEnd = uint16(portEnd) 870 pbCopy.HostIP = net.ParseIP(binding[i].HostIP) 871 pbList = append(pbList, pbCopy) 872 } 873 874 if container.hostConfig.PublishAllPorts && len(binding) == 0 { 875 pbList = append(pbList, pb) 876 } 877 } 878 879 createOptions = append(createOptions, 880 libnetwork.CreateOptionPortMapping(pbList), 881 libnetwork.CreateOptionExposedPorts(exposeList)) 882 883 if container.Config.MacAddress != "" { 884 mac, err := net.ParseMAC(container.Config.MacAddress) 885 if err != nil { 886 return nil, err 887 } 888 889 genericOption := options.Generic{ 890 netlabel.MacAddress: mac, 891 } 892 893 createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) 894 } 895 896 if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint { 897 createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) 898 } 899 900 return createOptions, nil 901 } 902 903 func createNetwork(controller libnetwork.NetworkController, dnet string, driver string) (libnetwork.Network, error) { 904 createOptions := []libnetwork.NetworkOption{} 905 genericOption := options.Generic{} 906 907 // Bridge driver is special due to legacy reasons 908 if runconfig.NetworkMode(driver).IsBridge() { 909 genericOption[netlabel.GenericData] = map[string]string{ 910 bridge.BridgeName: dnet, 911 } 912 networkOption := libnetwork.NetworkOptionGeneric(genericOption) 913 createOptions = append(createOptions, networkOption) 914 } 915 916 return controller.NewNetwork(driver, dnet, createOptions...) 917 } 918 919 func (container *Container) allocateNetwork() error { 920 updateSettings := false 921 if len(container.NetworkSettings.Networks) == 0 { 922 mode := container.hostConfig.NetworkMode 923 controller := container.daemon.netController 924 if container.Config.NetworkDisabled || mode.IsContainer() { 925 return nil 926 } 927 928 networkName := mode.NetworkName() 929 if mode.IsDefault() { 930 networkName = controller.Config().Daemon.DefaultNetwork 931 } 932 container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings) 933 container.NetworkSettings.Networks[networkName] = new(network.EndpointSettings) 934 updateSettings = true 935 } 936 937 for n := range container.NetworkSettings.Networks { 938 if err := container.connectToNetwork(n, updateSettings); err != nil { 939 return err 940 } 941 } 942 943 return container.writeHostConfig() 944 } 945 946 // ConnectToNetwork connects a container to a netork 947 func (container *Container) ConnectToNetwork(idOrName string) error { 948 if !container.Running { 949 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 950 } 951 return container.connectToNetwork(idOrName, true) 952 } 953 954 func (container *Container) connectToNetwork(idOrName string, updateSettings bool) error { 955 var err error 956 957 if container.hostConfig.NetworkMode.IsContainer() { 958 return runconfig.ErrConflictSharedNetwork 959 } 960 961 if runconfig.NetworkMode(idOrName).IsBridge() && 962 container.daemon.configStore.DisableBridge { 963 container.Config.NetworkDisabled = true 964 return nil 965 } 966 967 controller := container.daemon.netController 968 969 n, err := container.daemon.FindNetwork(idOrName) 970 if err != nil { 971 return err 972 } 973 974 if updateSettings { 975 if err := container.updateNetworkSettings(n); err != nil { 976 return err 977 } 978 } 979 980 ep, err := container.getEndpointInNetwork(n) 981 if err == nil { 982 return fmt.Errorf("container already connected to network %s", idOrName) 983 } 984 985 if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok { 986 return err 987 } 988 989 createOptions, err := container.buildCreateEndpointOptions(n) 990 if err != nil { 991 return err 992 } 993 994 endpointName := strings.TrimPrefix(container.Name, "/") 995 ep, err = n.CreateEndpoint(endpointName, createOptions...) 996 if err != nil { 997 return err 998 } 999 defer func() { 1000 if err != nil { 1001 if e := ep.Delete(); e != nil { 1002 logrus.Warnf("Could not rollback container connection to network %s", idOrName) 1003 } 1004 } 1005 }() 1006 1007 if err := container.updateEndpointNetworkSettings(n, ep); err != nil { 1008 return err 1009 } 1010 1011 var sb libnetwork.Sandbox 1012 controller.WalkSandboxes(func(s libnetwork.Sandbox) bool { 1013 if s.ContainerID() == container.ID { 1014 sb = s 1015 return true 1016 } 1017 return false 1018 }) 1019 if sb == nil { 1020 options, err := container.buildSandboxOptions(n) 1021 if err != nil { 1022 return err 1023 } 1024 sb, err = controller.NewSandbox(container.ID, options...) 1025 if err != nil { 1026 return err 1027 } 1028 1029 container.updateSandboxNetworkSettings(sb) 1030 } 1031 1032 if err := ep.Join(sb); err != nil { 1033 return err 1034 } 1035 1036 if err := container.updateJoinInfo(n, ep); err != nil { 1037 return derr.ErrorCodeJoinInfo.WithArgs(err) 1038 } 1039 1040 return nil 1041 } 1042 1043 func (container *Container) initializeNetworking() error { 1044 var err error 1045 1046 if container.hostConfig.NetworkMode.IsContainer() { 1047 // we need to get the hosts files from the container to join 1048 nc, err := container.getNetworkedContainer() 1049 if err != nil { 1050 return err 1051 } 1052 container.HostnamePath = nc.HostnamePath 1053 container.HostsPath = nc.HostsPath 1054 container.ResolvConfPath = nc.ResolvConfPath 1055 container.Config.Hostname = nc.Config.Hostname 1056 container.Config.Domainname = nc.Config.Domainname 1057 return nil 1058 } 1059 1060 if container.hostConfig.NetworkMode.IsHost() { 1061 container.Config.Hostname, err = os.Hostname() 1062 if err != nil { 1063 return err 1064 } 1065 1066 parts := strings.SplitN(container.Config.Hostname, ".", 2) 1067 if len(parts) > 1 { 1068 container.Config.Hostname = parts[0] 1069 container.Config.Domainname = parts[1] 1070 } 1071 1072 } 1073 1074 if err := container.allocateNetwork(); err != nil { 1075 return err 1076 } 1077 1078 return container.buildHostnameFile() 1079 } 1080 1081 // called from the libcontainer pre-start hook to set the network 1082 // namespace configuration linkage to the libnetwork "sandbox" entity 1083 func (container *Container) setNetworkNamespaceKey(pid int) error { 1084 path := fmt.Sprintf("/proc/%d/ns/net", pid) 1085 var sandbox libnetwork.Sandbox 1086 search := libnetwork.SandboxContainerWalker(&sandbox, container.ID) 1087 container.daemon.netController.WalkSandboxes(search) 1088 if sandbox == nil { 1089 return derr.ErrorCodeNoSandbox.WithArgs(container.ID) 1090 } 1091 1092 return sandbox.SetKey(path) 1093 } 1094 1095 func (container *Container) getIpcContainer() (*Container, error) { 1096 containerID := container.hostConfig.IpcMode.Container() 1097 c, err := container.daemon.Get(containerID) 1098 if err != nil { 1099 return nil, err 1100 } 1101 if !c.IsRunning() { 1102 return nil, derr.ErrorCodeIPCRunning 1103 } 1104 return c, nil 1105 } 1106 1107 func (container *Container) setupWorkingDirectory() error { 1108 if container.Config.WorkingDir != "" { 1109 container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) 1110 1111 pth, err := container.GetResourcePath(container.Config.WorkingDir) 1112 if err != nil { 1113 return err 1114 } 1115 1116 pthInfo, err := os.Stat(pth) 1117 if err != nil { 1118 if !os.IsNotExist(err) { 1119 return err 1120 } 1121 1122 if err := system.MkdirAll(pth, 0755); err != nil { 1123 return err 1124 } 1125 } 1126 if pthInfo != nil && !pthInfo.IsDir() { 1127 return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir) 1128 } 1129 } 1130 return nil 1131 } 1132 1133 func (container *Container) getNetworkedContainer() (*Container, error) { 1134 parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2) 1135 switch parts[0] { 1136 case "container": 1137 if len(parts) != 2 { 1138 return nil, derr.ErrorCodeParseContainer 1139 } 1140 nc, err := container.daemon.Get(parts[1]) 1141 if err != nil { 1142 return nil, err 1143 } 1144 if container == nc { 1145 return nil, derr.ErrorCodeJoinSelf 1146 } 1147 if !nc.IsRunning() { 1148 return nil, derr.ErrorCodeJoinRunning.WithArgs(parts[1]) 1149 } 1150 return nc, nil 1151 default: 1152 return nil, derr.ErrorCodeModeNotContainer 1153 } 1154 } 1155 1156 func (container *Container) releaseNetwork() { 1157 if container.hostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled { 1158 return 1159 } 1160 1161 sid := container.NetworkSettings.SandboxID 1162 networks := container.NetworkSettings.Networks 1163 for n := range networks { 1164 networks[n] = &network.EndpointSettings{} 1165 } 1166 1167 container.NetworkSettings = &network.Settings{Networks: networks} 1168 1169 if sid == "" || len(networks) == 0 { 1170 return 1171 } 1172 1173 sb, err := container.daemon.netController.SandboxByID(sid) 1174 if err != nil { 1175 logrus.Errorf("error locating sandbox id %s: %v", sid, err) 1176 return 1177 } 1178 1179 if err := sb.Delete(); err != nil { 1180 logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err) 1181 } 1182 } 1183 1184 // DisconnectFromNetwork disconnects a container from a network 1185 func (container *Container) DisconnectFromNetwork(n libnetwork.Network) error { 1186 if !container.Running { 1187 return derr.ErrorCodeNotRunning.WithArgs(container.ID) 1188 } 1189 1190 return container.disconnectFromNetwork(n) 1191 } 1192 1193 func (container *Container) disconnectFromNetwork(n libnetwork.Network) error { 1194 var ( 1195 ep libnetwork.Endpoint 1196 sbox libnetwork.Sandbox 1197 ) 1198 1199 s := func(current libnetwork.Endpoint) bool { 1200 if sb := current.Info().Sandbox(); sb != nil { 1201 if sb.ContainerID() == container.ID { 1202 ep = current 1203 sbox = sb 1204 return true 1205 } 1206 } 1207 return false 1208 } 1209 n.WalkEndpoints(s) 1210 1211 if ep == nil { 1212 return fmt.Errorf("container %s is not connected to the network", container.ID) 1213 } 1214 1215 if err := ep.Leave(sbox); err != nil { 1216 return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err) 1217 } 1218 1219 if err := ep.Delete(); err != nil { 1220 return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err) 1221 } 1222 1223 delete(container.NetworkSettings.Networks, n.Name()) 1224 return nil 1225 } 1226 1227 func (container *Container) unmountVolumes(forceSyscall bool) error { 1228 var volumeMounts []mountPoint 1229 1230 for _, mntPoint := range container.MountPoints { 1231 dest, err := container.GetResourcePath(mntPoint.Destination) 1232 if err != nil { 1233 return err 1234 } 1235 1236 volumeMounts = append(volumeMounts, mountPoint{Destination: dest, Volume: mntPoint.Volume}) 1237 } 1238 1239 for _, mnt := range container.networkMounts() { 1240 dest, err := container.GetResourcePath(mnt.Destination) 1241 if err != nil { 1242 return err 1243 } 1244 1245 volumeMounts = append(volumeMounts, mountPoint{Destination: dest}) 1246 } 1247 1248 for _, volumeMount := range volumeMounts { 1249 if forceSyscall { 1250 syscall.Unmount(volumeMount.Destination, 0) 1251 } 1252 1253 if volumeMount.Volume != nil { 1254 if err := volumeMount.Volume.Unmount(); err != nil { 1255 return err 1256 } 1257 } 1258 } 1259 1260 return nil 1261 } 1262 1263 func (container *Container) networkMounts() []execdriver.Mount { 1264 var mounts []execdriver.Mount 1265 shared := container.hostConfig.NetworkMode.IsContainer() 1266 if container.ResolvConfPath != "" { 1267 if _, err := os.Stat(container.ResolvConfPath); err != nil { 1268 logrus.Warnf("ResolvConfPath set to %q, but can't stat this filename (err = %v); skipping", container.ResolvConfPath, err) 1269 } else { 1270 label.Relabel(container.ResolvConfPath, container.MountLabel, shared) 1271 writable := !container.hostConfig.ReadonlyRootfs 1272 if m, exists := container.MountPoints["/etc/resolv.conf"]; exists { 1273 writable = m.RW 1274 } 1275 mounts = append(mounts, execdriver.Mount{ 1276 Source: container.ResolvConfPath, 1277 Destination: "/etc/resolv.conf", 1278 Writable: writable, 1279 Private: true, 1280 }) 1281 } 1282 } 1283 if container.HostnamePath != "" { 1284 if _, err := os.Stat(container.HostnamePath); err != nil { 1285 logrus.Warnf("HostnamePath set to %q, but can't stat this filename (err = %v); skipping", container.HostnamePath, err) 1286 } else { 1287 label.Relabel(container.HostnamePath, container.MountLabel, shared) 1288 writable := !container.hostConfig.ReadonlyRootfs 1289 if m, exists := container.MountPoints["/etc/hostname"]; exists { 1290 writable = m.RW 1291 } 1292 mounts = append(mounts, execdriver.Mount{ 1293 Source: container.HostnamePath, 1294 Destination: "/etc/hostname", 1295 Writable: writable, 1296 Private: true, 1297 }) 1298 } 1299 } 1300 if container.HostsPath != "" { 1301 if _, err := os.Stat(container.HostsPath); err != nil { 1302 logrus.Warnf("HostsPath set to %q, but can't stat this filename (err = %v); skipping", container.HostsPath, err) 1303 } else { 1304 label.Relabel(container.HostsPath, container.MountLabel, shared) 1305 writable := !container.hostConfig.ReadonlyRootfs 1306 if m, exists := container.MountPoints["/etc/hosts"]; exists { 1307 writable = m.RW 1308 } 1309 mounts = append(mounts, execdriver.Mount{ 1310 Source: container.HostsPath, 1311 Destination: "/etc/hosts", 1312 Writable: writable, 1313 Private: true, 1314 }) 1315 } 1316 } 1317 return mounts 1318 } 1319 1320 func (container *Container) addBindMountPoint(name, source, destination string, rw bool) { 1321 container.MountPoints[destination] = &mountPoint{ 1322 Name: name, 1323 Source: source, 1324 Destination: destination, 1325 RW: rw, 1326 } 1327 } 1328 1329 func (container *Container) addLocalMountPoint(name, destination string, rw bool) { 1330 container.MountPoints[destination] = &mountPoint{ 1331 Name: name, 1332 Driver: volume.DefaultDriverName, 1333 Destination: destination, 1334 RW: rw, 1335 } 1336 } 1337 1338 func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) { 1339 container.MountPoints[destination] = &mountPoint{ 1340 Name: vol.Name(), 1341 Driver: vol.DriverName(), 1342 Destination: destination, 1343 RW: rw, 1344 Volume: vol, 1345 } 1346 } 1347 1348 func (container *Container) isDestinationMounted(destination string) bool { 1349 return container.MountPoints[destination] != nil 1350 } 1351 1352 func (container *Container) prepareMountPoints() error { 1353 for _, config := range container.MountPoints { 1354 if len(config.Driver) > 0 { 1355 v, err := container.daemon.createVolume(config.Name, config.Driver, nil) 1356 if err != nil { 1357 return err 1358 } 1359 config.Volume = v 1360 } 1361 } 1362 return nil 1363 } 1364 1365 func (container *Container) removeMountPoints(rm bool) error { 1366 var rmErrors []string 1367 for _, m := range container.MountPoints { 1368 if m.Volume == nil { 1369 continue 1370 } 1371 container.daemon.volumes.Decrement(m.Volume) 1372 if rm { 1373 err := container.daemon.volumes.Remove(m.Volume) 1374 // ErrVolumeInUse is ignored because having this 1375 // volume being referenced by othe container is 1376 // not an error, but an implementation detail. 1377 // This prevents docker from logging "ERROR: Volume in use" 1378 // where there is another container using the volume. 1379 if err != nil && err != store.ErrVolumeInUse { 1380 rmErrors = append(rmErrors, err.Error()) 1381 } 1382 } 1383 } 1384 if len(rmErrors) > 0 { 1385 return derr.ErrorCodeRemovingVolume.WithArgs(strings.Join(rmErrors, "\n")) 1386 } 1387 return nil 1388 } 1389 1390 func (container *Container) shmPath() (string, error) { 1391 return container.getRootResourcePath("shm") 1392 } 1393 func (container *Container) mqueuePath() (string, error) { 1394 return container.getRootResourcePath("mqueue") 1395 } 1396 1397 func (container *Container) hasMountFor(path string) bool { 1398 _, exists := container.MountPoints[path] 1399 return exists 1400 } 1401 1402 func (container *Container) setupIpcDirs() error { 1403 rootUID, rootGID := container.daemon.GetRemappedUIDGID() 1404 if !container.hasMountFor("/dev/shm") { 1405 shmPath, err := container.shmPath() 1406 if err != nil { 1407 return err 1408 } 1409 1410 if err := idtools.MkdirAllAs(shmPath, 0700, rootUID, rootGID); err != nil { 1411 return err 1412 } 1413 1414 if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel("mode=1777,size=65536k", container.getMountLabel())); err != nil { 1415 return fmt.Errorf("mounting shm tmpfs: %s", err) 1416 } 1417 if err := os.Chown(shmPath, rootUID, rootGID); err != nil { 1418 return err 1419 } 1420 } 1421 1422 if !container.hasMountFor("/dev/mqueue") { 1423 mqueuePath, err := container.mqueuePath() 1424 if err != nil { 1425 return err 1426 } 1427 1428 if err := idtools.MkdirAllAs(mqueuePath, 0700, rootUID, rootGID); err != nil { 1429 return err 1430 } 1431 1432 if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil { 1433 return fmt.Errorf("mounting mqueue mqueue : %s", err) 1434 } 1435 if err := os.Chown(mqueuePath, rootUID, rootGID); err != nil { 1436 return err 1437 } 1438 } 1439 1440 return nil 1441 } 1442 1443 func (container *Container) unmountIpcMounts() error { 1444 if container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost() { 1445 return nil 1446 } 1447 1448 var errors []string 1449 1450 if !container.hasMountFor("/dev/shm") { 1451 shmPath, err := container.shmPath() 1452 if err != nil { 1453 logrus.Error(err) 1454 errors = append(errors, err.Error()) 1455 } else { 1456 if err := detachMounted(shmPath); err != nil { 1457 logrus.Errorf("failed to umount %s: %v", shmPath, err) 1458 errors = append(errors, err.Error()) 1459 } 1460 1461 } 1462 } 1463 1464 if !container.hasMountFor("/dev/mqueue") { 1465 mqueuePath, err := container.mqueuePath() 1466 if err != nil { 1467 logrus.Error(err) 1468 errors = append(errors, err.Error()) 1469 } else { 1470 if err := detachMounted(mqueuePath); err != nil { 1471 logrus.Errorf("failed to umount %s: %v", mqueuePath, err) 1472 errors = append(errors, err.Error()) 1473 } 1474 } 1475 } 1476 1477 if len(errors) > 0 { 1478 return fmt.Errorf("failed to cleanup ipc mounts:\n%v", strings.Join(errors, "\n")) 1479 } 1480 1481 return nil 1482 } 1483 1484 func (container *Container) ipcMounts() []execdriver.Mount { 1485 var mounts []execdriver.Mount 1486 1487 if !container.hasMountFor("/dev/shm") { 1488 label.SetFileLabel(container.ShmPath, container.MountLabel) 1489 mounts = append(mounts, execdriver.Mount{ 1490 Source: container.ShmPath, 1491 Destination: "/dev/shm", 1492 Writable: true, 1493 Private: true, 1494 }) 1495 } 1496 1497 if !container.hasMountFor("/dev/mqueue") { 1498 label.SetFileLabel(container.MqueuePath, container.MountLabel) 1499 mounts = append(mounts, execdriver.Mount{ 1500 Source: container.MqueuePath, 1501 Destination: "/dev/mqueue", 1502 Writable: true, 1503 Private: true, 1504 }) 1505 } 1506 return mounts 1507 } 1508 1509 func detachMounted(path string) error { 1510 return syscall.Unmount(path, syscall.MNT_DETACH) 1511 }