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