github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/container_operations.go (about) 1 package daemon // import "github.com/docker/docker/daemon" 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "os" 8 "path" 9 "strings" 10 "time" 11 12 containertypes "github.com/docker/docker/api/types/container" 13 networktypes "github.com/docker/docker/api/types/network" 14 "github.com/docker/docker/container" 15 "github.com/docker/docker/daemon/network" 16 "github.com/docker/docker/errdefs" 17 "github.com/docker/docker/opts" 18 "github.com/docker/docker/pkg/stringid" 19 "github.com/docker/docker/runconfig" 20 "github.com/docker/go-connections/nat" 21 "github.com/docker/libnetwork" 22 netconst "github.com/docker/libnetwork/datastore" 23 "github.com/docker/libnetwork/netlabel" 24 "github.com/docker/libnetwork/options" 25 "github.com/docker/libnetwork/types" 26 "github.com/sirupsen/logrus" 27 ) 28 29 var ( 30 // ErrRootFSReadOnly is returned when a container 31 // rootfs is marked readonly. 32 ErrRootFSReadOnly = errors.New("container rootfs is marked read-only") 33 getPortMapInfo = getSandboxPortMapInfo 34 ) 35 36 func (daemon *Daemon) getDNSSearchSettings(container *container.Container) []string { 37 if len(container.HostConfig.DNSSearch) > 0 { 38 return container.HostConfig.DNSSearch 39 } 40 41 if len(daemon.configStore.DNSSearch) > 0 { 42 return daemon.configStore.DNSSearch 43 } 44 45 return nil 46 } 47 48 func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]libnetwork.SandboxOption, error) { 49 var ( 50 sboxOptions []libnetwork.SandboxOption 51 err error 52 dns []string 53 dnsOptions []string 54 bindings = make(nat.PortMap) 55 pbList []types.PortBinding 56 exposeList []types.TransportPort 57 ) 58 59 defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName() 60 sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), 61 libnetwork.OptionDomainname(container.Config.Domainname)) 62 63 if container.HostConfig.NetworkMode.IsHost() { 64 sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) 65 } else { 66 // OptionUseExternalKey is mandatory for userns support. 67 // But optional for non-userns support 68 sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey()) 69 } 70 71 if err = daemon.setupPathsAndSandboxOptions(container, &sboxOptions); err != nil { 72 return nil, err 73 } 74 75 if len(container.HostConfig.DNS) > 0 { 76 dns = container.HostConfig.DNS 77 } else if len(daemon.configStore.DNS) > 0 { 78 dns = daemon.configStore.DNS 79 } 80 81 for _, d := range dns { 82 sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) 83 } 84 85 dnsSearch := daemon.getDNSSearchSettings(container) 86 87 for _, ds := range dnsSearch { 88 sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) 89 } 90 91 if len(container.HostConfig.DNSOptions) > 0 { 92 dnsOptions = container.HostConfig.DNSOptions 93 } else if len(daemon.configStore.DNSOptions) > 0 { 94 dnsOptions = daemon.configStore.DNSOptions 95 } 96 97 for _, ds := range dnsOptions { 98 sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds)) 99 } 100 101 if container.NetworkSettings.SecondaryIPAddresses != nil { 102 name := container.Config.Hostname 103 if container.Config.Domainname != "" { 104 name = name + "." + container.Config.Domainname 105 } 106 107 for _, a := range container.NetworkSettings.SecondaryIPAddresses { 108 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) 109 } 110 } 111 112 for _, extraHost := range container.HostConfig.ExtraHosts { 113 // allow IPv6 addresses in extra hosts; only split on first ":" 114 if _, err := opts.ValidateExtraHost(extraHost); err != nil { 115 return nil, err 116 } 117 parts := strings.SplitN(extraHost, ":", 2) 118 // If the IP Address is a string called "host-gateway", replace this 119 // value with the IP address stored in the daemon level HostGatewayIP 120 // config variable 121 if parts[1] == network.HostGatewayName { 122 gateway := daemon.configStore.HostGatewayIP.String() 123 if gateway == "" { 124 return nil, fmt.Errorf("unable to derive the IP value for host-gateway") 125 } 126 parts[1] = gateway 127 } 128 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) 129 } 130 131 if container.HostConfig.PortBindings != nil { 132 for p, b := range container.HostConfig.PortBindings { 133 bindings[p] = []nat.PortBinding{} 134 for _, bb := range b { 135 bindings[p] = append(bindings[p], nat.PortBinding{ 136 HostIP: bb.HostIP, 137 HostPort: bb.HostPort, 138 }) 139 } 140 } 141 } 142 143 portSpecs := container.Config.ExposedPorts 144 ports := make([]nat.Port, len(portSpecs)) 145 var i int 146 for p := range portSpecs { 147 ports[i] = p 148 i++ 149 } 150 nat.SortPortMap(ports, bindings) 151 for _, port := range ports { 152 expose := types.TransportPort{} 153 expose.Proto = types.ParseProtocol(port.Proto()) 154 expose.Port = uint16(port.Int()) 155 exposeList = append(exposeList, expose) 156 157 pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} 158 binding := bindings[port] 159 for i := 0; i < len(binding); i++ { 160 pbCopy := pb.GetCopy() 161 newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) 162 var portStart, portEnd int 163 if err == nil { 164 portStart, portEnd, err = newP.Range() 165 } 166 if err != nil { 167 return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err) 168 } 169 pbCopy.HostPort = uint16(portStart) 170 pbCopy.HostPortEnd = uint16(portEnd) 171 pbCopy.HostIP = net.ParseIP(binding[i].HostIP) 172 pbList = append(pbList, pbCopy) 173 } 174 175 if container.HostConfig.PublishAllPorts && len(binding) == 0 { 176 pbList = append(pbList, pb) 177 } 178 } 179 180 sboxOptions = append(sboxOptions, 181 libnetwork.OptionPortMapping(pbList), 182 libnetwork.OptionExposedPorts(exposeList)) 183 184 // Legacy Link feature is supported only for the default bridge network. 185 // return if this call to build join options is not for default bridge network 186 // Legacy Link is only supported by docker run --link 187 bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName] 188 if !ok || bridgeSettings.EndpointSettings == nil { 189 return sboxOptions, nil 190 } 191 192 if bridgeSettings.EndpointID == "" { 193 return sboxOptions, nil 194 } 195 196 var ( 197 childEndpoints, parentEndpoints []string 198 cEndpointID string 199 ) 200 201 children := daemon.children(container) 202 for linkAlias, child := range children { 203 if !isLinkable(child) { 204 return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name) 205 } 206 _, alias := path.Split(linkAlias) 207 // allow access to the linked container via the alias, real name, and container hostname 208 aliasList := alias + " " + child.Config.Hostname 209 // only add the name if alias isn't equal to the name 210 if alias != child.Name[1:] { 211 aliasList = aliasList + " " + child.Name[1:] 212 } 213 ipv4 := child.NetworkSettings.Networks[defaultNetName].IPAddress 214 ipv6 := child.NetworkSettings.Networks[defaultNetName].GlobalIPv6Address 215 if ipv4 != "" { 216 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, ipv4)) 217 } 218 if ipv6 != "" { 219 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, ipv6)) 220 } 221 cEndpointID = child.NetworkSettings.Networks[defaultNetName].EndpointID 222 if cEndpointID != "" { 223 childEndpoints = append(childEndpoints, cEndpointID) 224 } 225 } 226 227 for alias, parent := range daemon.parents(container) { 228 if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() { 229 continue 230 } 231 232 _, alias = path.Split(alias) 233 logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress) 234 sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate( 235 parent.ID, 236 alias, 237 bridgeSettings.IPAddress, 238 )) 239 if cEndpointID != "" { 240 parentEndpoints = append(parentEndpoints, cEndpointID) 241 } 242 } 243 244 linkOptions := options.Generic{ 245 netlabel.GenericData: options.Generic{ 246 "ParentEndpoints": parentEndpoints, 247 "ChildEndpoints": childEndpoints, 248 }, 249 } 250 251 sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) 252 return sboxOptions, nil 253 } 254 255 func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings) error { 256 if container.NetworkSettings == nil { 257 container.NetworkSettings = &network.Settings{} 258 } 259 if container.NetworkSettings.Networks == nil { 260 container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings) 261 } 262 263 if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() { 264 return runconfig.ErrConflictHostNetwork 265 } 266 267 for s, v := range container.NetworkSettings.Networks { 268 sn, err := daemon.FindNetwork(getNetworkID(s, v.EndpointSettings)) 269 if err != nil { 270 continue 271 } 272 273 if sn.Name() == n.Name() { 274 // If the network scope is swarm, then this 275 // is an attachable network, which may not 276 // be locally available previously. 277 // So always update. 278 if n.Info().Scope() == netconst.SwarmScope { 279 continue 280 } 281 // Avoid duplicate config 282 return nil 283 } 284 if !containertypes.NetworkMode(sn.Type()).IsPrivate() || 285 !containertypes.NetworkMode(n.Type()).IsPrivate() { 286 return runconfig.ErrConflictSharedNetwork 287 } 288 if containertypes.NetworkMode(sn.Name()).IsNone() || 289 containertypes.NetworkMode(n.Name()).IsNone() { 290 return runconfig.ErrConflictNoNetwork 291 } 292 } 293 294 container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{ 295 EndpointSettings: endpointConfig, 296 } 297 298 return nil 299 } 300 301 func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error { 302 if err := buildEndpointInfo(container.NetworkSettings, n, ep); err != nil { 303 return err 304 } 305 306 if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() { 307 container.NetworkSettings.Bridge = daemon.configStore.BridgeConfig.Iface 308 } 309 310 return nil 311 } 312 313 // UpdateNetwork is used to update the container's network (e.g. when linked containers 314 // get removed/unlinked). 315 func (daemon *Daemon) updateNetwork(container *container.Container) error { 316 var ( 317 start = time.Now() 318 ctrl = daemon.netController 319 sid = container.NetworkSettings.SandboxID 320 ) 321 322 sb, err := ctrl.SandboxByID(sid) 323 if err != nil { 324 return fmt.Errorf("error locating sandbox id %s: %v", sid, err) 325 } 326 327 // Find if container is connected to the default bridge network 328 var n libnetwork.Network 329 for name, v := range container.NetworkSettings.Networks { 330 sn, err := daemon.FindNetwork(getNetworkID(name, v.EndpointSettings)) 331 if err != nil { 332 continue 333 } 334 if sn.Name() == runconfig.DefaultDaemonNetworkMode().NetworkName() { 335 n = sn 336 break 337 } 338 } 339 340 if n == nil { 341 // Not connected to the default bridge network; Nothing to do 342 return nil 343 } 344 345 sbOptions, err := daemon.buildSandboxOptions(container) 346 if err != nil { 347 return fmt.Errorf("Update network failed: %v", err) 348 } 349 350 if err := sb.Refresh(sbOptions...); err != nil { 351 return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err) 352 } 353 354 networkActions.WithValues("update").UpdateSince(start) 355 356 return nil 357 } 358 359 func (daemon *Daemon) findAndAttachNetwork(container *container.Container, idOrName string, epConfig *networktypes.EndpointSettings) (libnetwork.Network, *networktypes.NetworkingConfig, error) { 360 id := getNetworkID(idOrName, epConfig) 361 362 n, err := daemon.FindNetwork(id) 363 if err != nil { 364 // We should always be able to find the network for a 365 // managed container. 366 if container.Managed { 367 return nil, nil, err 368 } 369 } 370 371 // If we found a network and if it is not dynamically created 372 // we should never attempt to attach to that network here. 373 if n != nil { 374 if container.Managed || !n.Info().Dynamic() { 375 return n, nil, nil 376 } 377 // Throw an error if the container is already attached to the network 378 if container.NetworkSettings.Networks != nil { 379 networkName := n.Name() 380 containerName := strings.TrimPrefix(container.Name, "/") 381 if nw, ok := container.NetworkSettings.Networks[networkName]; ok && nw.EndpointID != "" { 382 err := fmt.Errorf("%s is already attached to network %s", containerName, networkName) 383 return n, nil, errdefs.Conflict(err) 384 } 385 } 386 } 387 388 var addresses []string 389 if epConfig != nil && epConfig.IPAMConfig != nil { 390 if epConfig.IPAMConfig.IPv4Address != "" { 391 addresses = append(addresses, epConfig.IPAMConfig.IPv4Address) 392 } 393 394 if epConfig.IPAMConfig.IPv6Address != "" { 395 addresses = append(addresses, epConfig.IPAMConfig.IPv6Address) 396 } 397 } 398 399 var ( 400 config *networktypes.NetworkingConfig 401 retryCount int 402 ) 403 404 if n == nil && daemon.attachableNetworkLock != nil { 405 daemon.attachableNetworkLock.Lock(id) 406 defer daemon.attachableNetworkLock.Unlock(id) 407 } 408 409 for { 410 // In all other cases, attempt to attach to the network to 411 // trigger attachment in the swarm cluster manager. 412 if daemon.clusterProvider != nil { 413 var err error 414 config, err = daemon.clusterProvider.AttachNetwork(id, container.ID, addresses) 415 if err != nil { 416 return nil, nil, err 417 } 418 } 419 420 n, err = daemon.FindNetwork(id) 421 if err != nil { 422 if daemon.clusterProvider != nil { 423 if err := daemon.clusterProvider.DetachNetwork(id, container.ID); err != nil { 424 logrus.Warnf("Could not rollback attachment for container %s to network %s: %v", container.ID, idOrName, err) 425 } 426 } 427 428 // Retry network attach again if we failed to 429 // find the network after successful 430 // attachment because the only reason that 431 // would happen is if some other container 432 // attached to the swarm scope network went down 433 // and removed the network while we were in 434 // the process of attaching. 435 if config != nil { 436 if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok { 437 if retryCount >= 5 { 438 return nil, nil, fmt.Errorf("could not find network %s after successful attachment", idOrName) 439 } 440 retryCount++ 441 continue 442 } 443 } 444 445 return nil, nil, err 446 } 447 448 break 449 } 450 451 // This container has attachment to a swarm scope 452 // network. Update the container network settings accordingly. 453 container.NetworkSettings.HasSwarmEndpoint = true 454 return n, config, nil 455 } 456 457 // updateContainerNetworkSettings updates the network settings 458 func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) { 459 var n libnetwork.Network 460 461 mode := container.HostConfig.NetworkMode 462 if container.Config.NetworkDisabled || mode.IsContainer() { 463 return 464 } 465 466 networkName := mode.NetworkName() 467 if mode.IsDefault() { 468 networkName = daemon.netController.Config().Daemon.DefaultNetwork 469 } 470 471 if mode.IsUserDefined() { 472 var err error 473 474 n, err = daemon.FindNetwork(networkName) 475 if err == nil { 476 networkName = n.Name() 477 } 478 } 479 480 if container.NetworkSettings == nil { 481 container.NetworkSettings = &network.Settings{} 482 } 483 484 if len(endpointsConfig) > 0 { 485 if container.NetworkSettings.Networks == nil { 486 container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings) 487 } 488 489 for name, epConfig := range endpointsConfig { 490 container.NetworkSettings.Networks[name] = &network.EndpointSettings{ 491 EndpointSettings: epConfig, 492 } 493 } 494 } 495 496 if container.NetworkSettings.Networks == nil { 497 container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings) 498 container.NetworkSettings.Networks[networkName] = &network.EndpointSettings{ 499 EndpointSettings: &networktypes.EndpointSettings{}, 500 } 501 } 502 503 // Convert any settings added by client in default name to 504 // engine's default network name key 505 if mode.IsDefault() { 506 if nConf, ok := container.NetworkSettings.Networks[mode.NetworkName()]; ok { 507 container.NetworkSettings.Networks[networkName] = nConf 508 delete(container.NetworkSettings.Networks, mode.NetworkName()) 509 } 510 } 511 512 if !mode.IsUserDefined() { 513 return 514 } 515 // Make sure to internally store the per network endpoint config by network name 516 if _, ok := container.NetworkSettings.Networks[networkName]; ok { 517 return 518 } 519 520 if n != nil { 521 if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok { 522 container.NetworkSettings.Networks[networkName] = nwConfig 523 delete(container.NetworkSettings.Networks, n.ID()) 524 return 525 } 526 } 527 } 528 529 func (daemon *Daemon) allocateNetwork(container *container.Container) (retErr error) { 530 if daemon.netController == nil { 531 return nil 532 } 533 534 var ( 535 start = time.Now() 536 controller = daemon.netController 537 ) 538 539 // Cleanup any stale sandbox left over due to ungraceful daemon shutdown 540 if err := controller.SandboxDestroy(container.ID); err != nil { 541 logrus.WithError(err).Errorf("failed to cleanup up stale network sandbox for container %s", container.ID) 542 } 543 544 if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() { 545 return nil 546 } 547 548 updateSettings := false 549 550 if len(container.NetworkSettings.Networks) == 0 { 551 daemon.updateContainerNetworkSettings(container, nil) 552 updateSettings = true 553 } 554 555 // always connect default network first since only default 556 // network mode support link and we need do some setting 557 // on sandbox initialize for link, but the sandbox only be initialized 558 // on first network connecting. 559 defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName() 560 if nConf, ok := container.NetworkSettings.Networks[defaultNetName]; ok { 561 cleanOperationalData(nConf) 562 if err := daemon.connectToNetwork(container, defaultNetName, nConf.EndpointSettings, updateSettings); err != nil { 563 return err 564 } 565 566 } 567 568 // the intermediate map is necessary because "connectToNetwork" modifies "container.NetworkSettings.Networks" 569 networks := make(map[string]*network.EndpointSettings) 570 for n, epConf := range container.NetworkSettings.Networks { 571 if n == defaultNetName { 572 continue 573 } 574 575 networks[n] = epConf 576 } 577 578 for netName, epConf := range networks { 579 cleanOperationalData(epConf) 580 if err := daemon.connectToNetwork(container, netName, epConf.EndpointSettings, updateSettings); err != nil { 581 return err 582 } 583 } 584 585 // If the container is not to be connected to any network, 586 // create its network sandbox now if not present 587 if len(networks) == 0 { 588 if nil == daemon.getNetworkSandbox(container) { 589 sbOptions, err := daemon.buildSandboxOptions(container) 590 if err != nil { 591 return err 592 } 593 sb, err := daemon.netController.NewSandbox(container.ID, sbOptions...) 594 if err != nil { 595 return err 596 } 597 updateSandboxNetworkSettings(container, sb) 598 defer func() { 599 if retErr != nil { 600 sb.Delete() 601 } 602 }() 603 } 604 605 } 606 607 if _, err := container.WriteHostConfig(); err != nil { 608 return err 609 } 610 networkActions.WithValues("allocate").UpdateSince(start) 611 return nil 612 } 613 614 func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox { 615 var sb libnetwork.Sandbox 616 daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool { 617 if s.ContainerID() == container.ID { 618 sb = s 619 return true 620 } 621 return false 622 }) 623 return sb 624 } 625 626 // hasUserDefinedIPAddress returns whether the passed IPAM configuration contains IP address configuration 627 func hasUserDefinedIPAddress(ipamConfig *networktypes.EndpointIPAMConfig) bool { 628 return ipamConfig != nil && (len(ipamConfig.IPv4Address) > 0 || len(ipamConfig.IPv6Address) > 0) 629 } 630 631 // User specified ip address is acceptable only for networks with user specified subnets. 632 func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error { 633 if n == nil || epConfig == nil { 634 return nil 635 } 636 if !containertypes.NetworkMode(n.Name()).IsUserDefined() { 637 if hasUserDefinedIPAddress(epConfig.IPAMConfig) && !enableIPOnPredefinedNetwork() { 638 return runconfig.ErrUnsupportedNetworkAndIP 639 } 640 if len(epConfig.Aliases) > 0 && !serviceDiscoveryOnDefaultNetwork() { 641 return runconfig.ErrUnsupportedNetworkAndAlias 642 } 643 } 644 if !hasUserDefinedIPAddress(epConfig.IPAMConfig) { 645 return nil 646 } 647 648 _, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig() 649 for _, s := range []struct { 650 ipConfigured bool 651 subnetConfigs []*libnetwork.IpamConf 652 }{ 653 { 654 ipConfigured: len(epConfig.IPAMConfig.IPv4Address) > 0, 655 subnetConfigs: nwIPv4Configs, 656 }, 657 { 658 ipConfigured: len(epConfig.IPAMConfig.IPv6Address) > 0, 659 subnetConfigs: nwIPv6Configs, 660 }, 661 } { 662 if s.ipConfigured { 663 foundSubnet := false 664 for _, cfg := range s.subnetConfigs { 665 if len(cfg.PreferredPool) > 0 { 666 foundSubnet = true 667 break 668 } 669 } 670 if !foundSubnet { 671 return runconfig.ErrUnsupportedNetworkNoSubnetAndIP 672 } 673 } 674 } 675 676 return nil 677 } 678 679 // cleanOperationalData resets the operational data from the passed endpoint settings 680 func cleanOperationalData(es *network.EndpointSettings) { 681 es.EndpointID = "" 682 es.Gateway = "" 683 es.IPAddress = "" 684 es.IPPrefixLen = 0 685 es.IPv6Gateway = "" 686 es.GlobalIPv6Address = "" 687 es.GlobalIPv6PrefixLen = 0 688 es.MacAddress = "" 689 if es.IPAMOperational { 690 es.IPAMConfig = nil 691 } 692 } 693 694 func (daemon *Daemon) updateNetworkConfig(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error { 695 696 if containertypes.NetworkMode(n.Name()).IsUserDefined() { 697 addShortID := true 698 shortID := stringid.TruncateID(container.ID) 699 for _, alias := range endpointConfig.Aliases { 700 if alias == shortID { 701 addShortID = false 702 break 703 } 704 } 705 if addShortID { 706 endpointConfig.Aliases = append(endpointConfig.Aliases, shortID) 707 } 708 if container.Name != container.Config.Hostname { 709 addHostname := true 710 for _, alias := range endpointConfig.Aliases { 711 if alias == container.Config.Hostname { 712 addHostname = false 713 break 714 } 715 } 716 if addHostname { 717 endpointConfig.Aliases = append(endpointConfig.Aliases, container.Config.Hostname) 718 } 719 } 720 } 721 722 if err := validateNetworkingConfig(n, endpointConfig); err != nil { 723 return err 724 } 725 726 if updateSettings { 727 if err := daemon.updateNetworkSettings(container, n, endpointConfig); err != nil { 728 return err 729 } 730 } 731 return nil 732 } 733 734 func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) { 735 start := time.Now() 736 if container.HostConfig.NetworkMode.IsContainer() { 737 return runconfig.ErrConflictSharedNetwork 738 } 739 if containertypes.NetworkMode(idOrName).IsBridge() && 740 daemon.configStore.DisableBridge { 741 container.Config.NetworkDisabled = true 742 return nil 743 } 744 if endpointConfig == nil { 745 endpointConfig = &networktypes.EndpointSettings{} 746 } 747 748 n, config, err := daemon.findAndAttachNetwork(container, idOrName, endpointConfig) 749 if err != nil { 750 return err 751 } 752 if n == nil { 753 return nil 754 } 755 756 var operIPAM bool 757 if config != nil { 758 if epConfig, ok := config.EndpointsConfig[n.Name()]; ok { 759 if endpointConfig.IPAMConfig == nil || 760 (endpointConfig.IPAMConfig.IPv4Address == "" && 761 endpointConfig.IPAMConfig.IPv6Address == "" && 762 len(endpointConfig.IPAMConfig.LinkLocalIPs) == 0) { 763 operIPAM = true 764 } 765 766 // copy IPAMConfig and NetworkID from epConfig via AttachNetwork 767 endpointConfig.IPAMConfig = epConfig.IPAMConfig 768 endpointConfig.NetworkID = epConfig.NetworkID 769 } 770 } 771 772 if err := daemon.updateNetworkConfig(container, n, endpointConfig, updateSettings); err != nil { 773 return err 774 } 775 776 controller := daemon.netController 777 sb := daemon.getNetworkSandbox(container) 778 createOptions, err := buildCreateEndpointOptions(container, n, endpointConfig, sb, daemon.configStore.DNS) 779 if err != nil { 780 return err 781 } 782 783 endpointName := strings.TrimPrefix(container.Name, "/") 784 ep, err := n.CreateEndpoint(endpointName, createOptions...) 785 if err != nil { 786 return err 787 } 788 defer func() { 789 if err != nil { 790 if e := ep.Delete(false); e != nil { 791 logrus.Warnf("Could not rollback container connection to network %s", idOrName) 792 } 793 } 794 }() 795 container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{ 796 EndpointSettings: endpointConfig, 797 IPAMOperational: operIPAM, 798 } 799 800 delete(container.NetworkSettings.Networks, n.ID()) 801 802 if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil { 803 return err 804 } 805 806 if sb == nil { 807 sbOptions, err := daemon.buildSandboxOptions(container) 808 if err != nil { 809 return err 810 } 811 sb, err = controller.NewSandbox(container.ID, sbOptions...) 812 if err != nil { 813 return err 814 } 815 816 updateSandboxNetworkSettings(container, sb) 817 } 818 819 joinOptions, err := buildJoinOptions(container.NetworkSettings, n) 820 if err != nil { 821 return err 822 } 823 824 if err := ep.Join(sb, joinOptions...); err != nil { 825 return err 826 } 827 828 if !container.Managed { 829 // add container name/alias to DNS 830 if err := daemon.ActivateContainerServiceBinding(container.Name); err != nil { 831 return fmt.Errorf("Activate container service binding for %s failed: %v", container.Name, err) 832 } 833 } 834 835 if err := updateJoinInfo(container.NetworkSettings, n, ep); err != nil { 836 return fmt.Errorf("Updating join info failed: %v", err) 837 } 838 839 container.NetworkSettings.Ports = getPortMapInfo(sb) 840 841 daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID}) 842 networkActions.WithValues("connect").UpdateSince(start) 843 return nil 844 } 845 846 func updateJoinInfo(networkSettings *network.Settings, n libnetwork.Network, ep libnetwork.Endpoint) error { 847 if ep == nil { 848 return errors.New("invalid enppoint whhile building portmap info") 849 } 850 851 if networkSettings == nil { 852 return errors.New("invalid network settings while building port map info") 853 } 854 855 if len(networkSettings.Ports) == 0 { 856 pm, err := getEndpointPortMapInfo(ep) 857 if err != nil { 858 return err 859 } 860 networkSettings.Ports = pm 861 } 862 863 epInfo := ep.Info() 864 if epInfo == nil { 865 // It is not an error to get an empty endpoint info 866 return nil 867 } 868 if epInfo.Gateway() != nil { 869 networkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String() 870 } 871 if epInfo.GatewayIPv6().To16() != nil { 872 networkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String() 873 } 874 return nil 875 } 876 877 // ForceEndpointDelete deletes an endpoint from a network forcefully 878 func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error { 879 n, err := daemon.FindNetwork(networkName) 880 if err != nil { 881 return err 882 } 883 884 ep, err := n.EndpointByName(name) 885 if err != nil { 886 return err 887 } 888 return ep.Delete(true) 889 } 890 891 func (daemon *Daemon) disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { 892 var ( 893 ep libnetwork.Endpoint 894 sbox libnetwork.Sandbox 895 ) 896 897 s := func(current libnetwork.Endpoint) bool { 898 epInfo := current.Info() 899 if epInfo == nil { 900 return false 901 } 902 if sb := epInfo.Sandbox(); sb != nil { 903 if sb.ContainerID() == container.ID { 904 ep = current 905 sbox = sb 906 return true 907 } 908 } 909 return false 910 } 911 n.WalkEndpoints(s) 912 913 if ep == nil && force { 914 epName := strings.TrimPrefix(container.Name, "/") 915 ep, err := n.EndpointByName(epName) 916 if err != nil { 917 return err 918 } 919 return ep.Delete(force) 920 } 921 922 if ep == nil { 923 return fmt.Errorf("container %s is not connected to network %s", container.ID, n.Name()) 924 } 925 926 if err := ep.Leave(sbox); err != nil { 927 return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err) 928 } 929 930 container.NetworkSettings.Ports = getPortMapInfo(sbox) 931 932 if err := ep.Delete(false); err != nil { 933 return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err) 934 } 935 936 delete(container.NetworkSettings.Networks, n.Name()) 937 938 daemon.tryDetachContainerFromClusterNetwork(n, container) 939 940 return nil 941 } 942 943 func (daemon *Daemon) tryDetachContainerFromClusterNetwork(network libnetwork.Network, container *container.Container) { 944 if daemon.clusterProvider != nil && network.Info().Dynamic() && !container.Managed { 945 if err := daemon.clusterProvider.DetachNetwork(network.Name(), container.ID); err != nil { 946 logrus.Warnf("error detaching from network %s: %v", network.Name(), err) 947 if err := daemon.clusterProvider.DetachNetwork(network.ID(), container.ID); err != nil { 948 logrus.Warnf("error detaching from network %s: %v", network.ID(), err) 949 } 950 } 951 } 952 attributes := map[string]string{ 953 "container": container.ID, 954 } 955 daemon.LogNetworkEventWithAttributes(network, "disconnect", attributes) 956 } 957 958 func (daemon *Daemon) initializeNetworking(container *container.Container) error { 959 var err error 960 961 if container.HostConfig.NetworkMode.IsContainer() { 962 // we need to get the hosts files from the container to join 963 nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer()) 964 if err != nil { 965 return err 966 } 967 968 err = daemon.initializeNetworkingPaths(container, nc) 969 if err != nil { 970 return err 971 } 972 973 container.Config.Hostname = nc.Config.Hostname 974 container.Config.Domainname = nc.Config.Domainname 975 return nil 976 } 977 978 if container.HostConfig.NetworkMode.IsHost() { 979 if container.Config.Hostname == "" { 980 container.Config.Hostname, err = os.Hostname() 981 if err != nil { 982 return err 983 } 984 } 985 } 986 987 if err := daemon.allocateNetwork(container); err != nil { 988 return err 989 } 990 991 return container.BuildHostnameFile() 992 } 993 994 func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) { 995 nc, err := daemon.GetContainer(connectedContainerID) 996 if err != nil { 997 return nil, err 998 } 999 if containerID == nc.ID { 1000 return nil, fmt.Errorf("cannot join own network") 1001 } 1002 if !nc.IsRunning() { 1003 err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID) 1004 return nil, errdefs.Conflict(err) 1005 } 1006 if nc.IsRestarting() { 1007 return nil, errContainerIsRestarting(connectedContainerID) 1008 } 1009 return nc, nil 1010 } 1011 1012 func (daemon *Daemon) releaseNetwork(container *container.Container) { 1013 start := time.Now() 1014 if daemon.netController == nil { 1015 return 1016 } 1017 if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled { 1018 return 1019 } 1020 1021 sid := container.NetworkSettings.SandboxID 1022 settings := container.NetworkSettings.Networks 1023 container.NetworkSettings.Ports = nil 1024 1025 if sid == "" { 1026 return 1027 } 1028 1029 var networks []libnetwork.Network 1030 for n, epSettings := range settings { 1031 if nw, err := daemon.FindNetwork(getNetworkID(n, epSettings.EndpointSettings)); err == nil { 1032 networks = append(networks, nw) 1033 } 1034 1035 if epSettings.EndpointSettings == nil { 1036 continue 1037 } 1038 1039 cleanOperationalData(epSettings) 1040 } 1041 1042 sb, err := daemon.netController.SandboxByID(sid) 1043 if err != nil { 1044 logrus.Warnf("error locating sandbox id %s: %v", sid, err) 1045 return 1046 } 1047 1048 if err := sb.Delete(); err != nil { 1049 logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err) 1050 } 1051 1052 for _, nw := range networks { 1053 daemon.tryDetachContainerFromClusterNetwork(nw, container) 1054 } 1055 networkActions.WithValues("release").UpdateSince(start) 1056 } 1057 1058 func errRemovalContainer(containerID string) error { 1059 return fmt.Errorf("Container %s is marked for removal and cannot be connected or disconnected to the network", containerID) 1060 } 1061 1062 // ConnectToNetwork connects a container to a network 1063 func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error { 1064 if endpointConfig == nil { 1065 endpointConfig = &networktypes.EndpointSettings{} 1066 } 1067 container.Lock() 1068 defer container.Unlock() 1069 1070 if !container.Running { 1071 if container.RemovalInProgress || container.Dead { 1072 return errRemovalContainer(container.ID) 1073 } 1074 1075 n, err := daemon.FindNetwork(idOrName) 1076 if err == nil && n != nil { 1077 if err := daemon.updateNetworkConfig(container, n, endpointConfig, true); err != nil { 1078 return err 1079 } 1080 } else { 1081 container.NetworkSettings.Networks[idOrName] = &network.EndpointSettings{ 1082 EndpointSettings: endpointConfig, 1083 } 1084 } 1085 } else { 1086 if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil { 1087 return err 1088 } 1089 } 1090 1091 return container.CheckpointTo(daemon.containersReplica) 1092 } 1093 1094 // DisconnectFromNetwork disconnects container from network n. 1095 func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error { 1096 n, err := daemon.FindNetwork(networkName) 1097 container.Lock() 1098 defer container.Unlock() 1099 1100 if !container.Running || (err != nil && force) { 1101 if container.RemovalInProgress || container.Dead { 1102 return errRemovalContainer(container.ID) 1103 } 1104 // In case networkName is resolved we will use n.Name() 1105 // this will cover the case where network id is passed. 1106 if n != nil { 1107 networkName = n.Name() 1108 } 1109 if _, ok := container.NetworkSettings.Networks[networkName]; !ok { 1110 return fmt.Errorf("container %s is not connected to the network %s", container.ID, networkName) 1111 } 1112 delete(container.NetworkSettings.Networks, networkName) 1113 } else if err == nil { 1114 if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() { 1115 return runconfig.ErrConflictHostNetwork 1116 } 1117 1118 if err := daemon.disconnectFromNetwork(container, n, false); err != nil { 1119 return err 1120 } 1121 } else { 1122 return err 1123 } 1124 1125 if err := container.CheckpointTo(daemon.containersReplica); err != nil { 1126 return err 1127 } 1128 1129 if n != nil { 1130 daemon.LogNetworkEventWithAttributes(n, "disconnect", map[string]string{ 1131 "container": container.ID, 1132 }) 1133 } 1134 1135 return nil 1136 } 1137 1138 // ActivateContainerServiceBinding puts this container into load balancer active rotation and DNS response 1139 func (daemon *Daemon) ActivateContainerServiceBinding(containerName string) error { 1140 ctr, err := daemon.GetContainer(containerName) 1141 if err != nil { 1142 return err 1143 } 1144 sb := daemon.getNetworkSandbox(ctr) 1145 if sb == nil { 1146 return fmt.Errorf("network sandbox does not exist for container %s", containerName) 1147 } 1148 return sb.EnableService() 1149 } 1150 1151 // DeactivateContainerServiceBinding removes this container from load balancer active rotation, and DNS response 1152 func (daemon *Daemon) DeactivateContainerServiceBinding(containerName string) error { 1153 ctr, err := daemon.GetContainer(containerName) 1154 if err != nil { 1155 return err 1156 } 1157 sb := daemon.getNetworkSandbox(ctr) 1158 if sb == nil { 1159 // If the network sandbox is not found, then there is nothing to deactivate 1160 logrus.Debugf("Could not find network sandbox for container %s on service binding deactivation request", containerName) 1161 return nil 1162 } 1163 return sb.DisableService() 1164 } 1165 1166 func getNetworkID(name string, endpointSettings *networktypes.EndpointSettings) string { 1167 // We only want to prefer NetworkID for user defined networks. 1168 // For systems like bridge, none, etc. the name is preferred (otherwise restart may cause issues) 1169 if containertypes.NetworkMode(name).IsUserDefined() && endpointSettings != nil && endpointSettings.NetworkID != "" { 1170 return endpointSettings.NetworkID 1171 } 1172 return name 1173 } 1174 1175 // updateSandboxNetworkSettings updates the sandbox ID and Key. 1176 func updateSandboxNetworkSettings(c *container.Container, sb libnetwork.Sandbox) error { 1177 c.NetworkSettings.SandboxID = sb.ID() 1178 c.NetworkSettings.SandboxKey = sb.Key() 1179 return nil 1180 }