github.com/adityamillind98/moby@v23.0.0-rc.4+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/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 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] == opts.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().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 // the intermediate map is necessary because "connectToNetwork" modifies "container.NetworkSettings.Networks" 568 networks := make(map[string]*network.EndpointSettings) 569 for n, epConf := range container.NetworkSettings.Networks { 570 if n == defaultNetName { 571 continue 572 } 573 574 networks[n] = epConf 575 } 576 577 for netName, epConf := range networks { 578 cleanOperationalData(epConf) 579 if err := daemon.connectToNetwork(container, netName, epConf.EndpointSettings, updateSettings); err != nil { 580 return err 581 } 582 } 583 584 // If the container is not to be connected to any network, 585 // create its network sandbox now if not present 586 if len(networks) == 0 { 587 if nil == daemon.getNetworkSandbox(container) { 588 sbOptions, err := daemon.buildSandboxOptions(container) 589 if err != nil { 590 return err 591 } 592 sb, err := daemon.netController.NewSandbox(container.ID, sbOptions...) 593 if err != nil { 594 return err 595 } 596 updateSandboxNetworkSettings(container, sb) 597 defer func() { 598 if retErr != nil { 599 sb.Delete() 600 } 601 }() 602 } 603 } 604 605 if _, err := container.WriteHostConfig(); err != nil { 606 return err 607 } 608 networkActions.WithValues("allocate").UpdateSince(start) 609 return nil 610 } 611 612 func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox { 613 var sb libnetwork.Sandbox 614 daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool { 615 if s.ContainerID() == container.ID { 616 sb = s 617 return true 618 } 619 return false 620 }) 621 return sb 622 } 623 624 // hasUserDefinedIPAddress returns whether the passed IPAM configuration contains IP address configuration 625 func hasUserDefinedIPAddress(ipamConfig *networktypes.EndpointIPAMConfig) bool { 626 return ipamConfig != nil && (len(ipamConfig.IPv4Address) > 0 || len(ipamConfig.IPv6Address) > 0) 627 } 628 629 // User specified ip address is acceptable only for networks with user specified subnets. 630 func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error { 631 if n == nil || epConfig == nil { 632 return nil 633 } 634 if !containertypes.NetworkMode(n.Name()).IsUserDefined() { 635 if hasUserDefinedIPAddress(epConfig.IPAMConfig) && !enableIPOnPredefinedNetwork() { 636 return runconfig.ErrUnsupportedNetworkAndIP 637 } 638 if len(epConfig.Aliases) > 0 && !serviceDiscoveryOnDefaultNetwork() { 639 return runconfig.ErrUnsupportedNetworkAndAlias 640 } 641 } 642 if !hasUserDefinedIPAddress(epConfig.IPAMConfig) { 643 return nil 644 } 645 646 _, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig() 647 for _, s := range []struct { 648 ipConfigured bool 649 subnetConfigs []*libnetwork.IpamConf 650 }{ 651 { 652 ipConfigured: len(epConfig.IPAMConfig.IPv4Address) > 0, 653 subnetConfigs: nwIPv4Configs, 654 }, 655 { 656 ipConfigured: len(epConfig.IPAMConfig.IPv6Address) > 0, 657 subnetConfigs: nwIPv6Configs, 658 }, 659 } { 660 if s.ipConfigured { 661 foundSubnet := false 662 for _, cfg := range s.subnetConfigs { 663 if len(cfg.PreferredPool) > 0 { 664 foundSubnet = true 665 break 666 } 667 } 668 if !foundSubnet { 669 return runconfig.ErrUnsupportedNetworkNoSubnetAndIP 670 } 671 } 672 } 673 674 return nil 675 } 676 677 // cleanOperationalData resets the operational data from the passed endpoint settings 678 func cleanOperationalData(es *network.EndpointSettings) { 679 es.EndpointID = "" 680 es.Gateway = "" 681 es.IPAddress = "" 682 es.IPPrefixLen = 0 683 es.IPv6Gateway = "" 684 es.GlobalIPv6Address = "" 685 es.GlobalIPv6PrefixLen = 0 686 es.MacAddress = "" 687 if es.IPAMOperational { 688 es.IPAMConfig = nil 689 } 690 } 691 692 func (daemon *Daemon) updateNetworkConfig(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error { 693 694 if containertypes.NetworkMode(n.Name()).IsUserDefined() { 695 addShortID := true 696 shortID := stringid.TruncateID(container.ID) 697 for _, alias := range endpointConfig.Aliases { 698 if alias == shortID { 699 addShortID = false 700 break 701 } 702 } 703 if addShortID { 704 endpointConfig.Aliases = append(endpointConfig.Aliases, shortID) 705 } 706 if container.Name != container.Config.Hostname { 707 addHostname := true 708 for _, alias := range endpointConfig.Aliases { 709 if alias == container.Config.Hostname { 710 addHostname = false 711 break 712 } 713 } 714 if addHostname { 715 endpointConfig.Aliases = append(endpointConfig.Aliases, container.Config.Hostname) 716 } 717 } 718 } 719 720 if err := validateNetworkingConfig(n, endpointConfig); err != nil { 721 return err 722 } 723 724 if updateSettings { 725 if err := daemon.updateNetworkSettings(container, n, endpointConfig); err != nil { 726 return err 727 } 728 } 729 return nil 730 } 731 732 func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) { 733 start := time.Now() 734 if container.HostConfig.NetworkMode.IsContainer() { 735 return runconfig.ErrConflictSharedNetwork 736 } 737 if containertypes.NetworkMode(idOrName).IsBridge() && 738 daemon.configStore.DisableBridge { 739 container.Config.NetworkDisabled = true 740 return nil 741 } 742 if endpointConfig == nil { 743 endpointConfig = &networktypes.EndpointSettings{} 744 } 745 746 n, config, err := daemon.findAndAttachNetwork(container, idOrName, endpointConfig) 747 if err != nil { 748 return err 749 } 750 if n == nil { 751 return nil 752 } 753 754 var operIPAM bool 755 if config != nil { 756 if epConfig, ok := config.EndpointsConfig[n.Name()]; ok { 757 if endpointConfig.IPAMConfig == nil || 758 (endpointConfig.IPAMConfig.IPv4Address == "" && 759 endpointConfig.IPAMConfig.IPv6Address == "" && 760 len(endpointConfig.IPAMConfig.LinkLocalIPs) == 0) { 761 operIPAM = true 762 } 763 764 // copy IPAMConfig and NetworkID from epConfig via AttachNetwork 765 endpointConfig.IPAMConfig = epConfig.IPAMConfig 766 endpointConfig.NetworkID = epConfig.NetworkID 767 } 768 } 769 770 if err := daemon.updateNetworkConfig(container, n, endpointConfig, updateSettings); err != nil { 771 return err 772 } 773 774 controller := daemon.netController 775 sb := daemon.getNetworkSandbox(container) 776 createOptions, err := buildCreateEndpointOptions(container, n, endpointConfig, sb, daemon.configStore.DNS) 777 if err != nil { 778 return err 779 } 780 781 endpointName := strings.TrimPrefix(container.Name, "/") 782 ep, err := n.CreateEndpoint(endpointName, createOptions...) 783 if err != nil { 784 return err 785 } 786 defer func() { 787 if err != nil { 788 if e := ep.Delete(false); e != nil { 789 logrus.Warnf("Could not rollback container connection to network %s", idOrName) 790 } 791 } 792 }() 793 container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{ 794 EndpointSettings: endpointConfig, 795 IPAMOperational: operIPAM, 796 } 797 798 delete(container.NetworkSettings.Networks, n.ID()) 799 800 if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil { 801 return err 802 } 803 804 if sb == nil { 805 sbOptions, err := daemon.buildSandboxOptions(container) 806 if err != nil { 807 return err 808 } 809 sb, err = controller.NewSandbox(container.ID, sbOptions...) 810 if err != nil { 811 return err 812 } 813 814 updateSandboxNetworkSettings(container, sb) 815 } 816 817 joinOptions, err := buildJoinOptions(container.NetworkSettings, n) 818 if err != nil { 819 return err 820 } 821 822 if err := ep.Join(sb, joinOptions...); err != nil { 823 return err 824 } 825 826 if !container.Managed { 827 // add container name/alias to DNS 828 if err := daemon.ActivateContainerServiceBinding(container.Name); err != nil { 829 return fmt.Errorf("Activate container service binding for %s failed: %v", container.Name, err) 830 } 831 } 832 833 if err := updateJoinInfo(container.NetworkSettings, n, ep); err != nil { 834 return fmt.Errorf("Updating join info failed: %v", err) 835 } 836 837 container.NetworkSettings.Ports = getPortMapInfo(sb) 838 839 daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID}) 840 networkActions.WithValues("connect").UpdateSince(start) 841 return nil 842 } 843 844 func updateJoinInfo(networkSettings *network.Settings, n libnetwork.Network, ep libnetwork.Endpoint) error { 845 if ep == nil { 846 return errors.New("invalid enppoint whhile building portmap info") 847 } 848 849 if networkSettings == nil { 850 return errors.New("invalid network settings while building port map info") 851 } 852 853 if len(networkSettings.Ports) == 0 { 854 pm, err := getEndpointPortMapInfo(ep) 855 if err != nil { 856 return err 857 } 858 networkSettings.Ports = pm 859 } 860 861 epInfo := ep.Info() 862 if epInfo == nil { 863 // It is not an error to get an empty endpoint info 864 return nil 865 } 866 if epInfo.Gateway() != nil { 867 networkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String() 868 } 869 if epInfo.GatewayIPv6().To16() != nil { 870 networkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String() 871 } 872 return nil 873 } 874 875 // ForceEndpointDelete deletes an endpoint from a network forcefully 876 func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error { 877 n, err := daemon.FindNetwork(networkName) 878 if err != nil { 879 return err 880 } 881 882 ep, err := n.EndpointByName(name) 883 if err != nil { 884 return err 885 } 886 return ep.Delete(true) 887 } 888 889 func (daemon *Daemon) disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { 890 var ( 891 ep libnetwork.Endpoint 892 sbox libnetwork.Sandbox 893 ) 894 895 s := func(current libnetwork.Endpoint) bool { 896 epInfo := current.Info() 897 if epInfo == nil { 898 return false 899 } 900 if sb := epInfo.Sandbox(); sb != nil { 901 if sb.ContainerID() == container.ID { 902 ep = current 903 sbox = sb 904 return true 905 } 906 } 907 return false 908 } 909 n.WalkEndpoints(s) 910 911 if ep == nil && force { 912 epName := strings.TrimPrefix(container.Name, "/") 913 ep, err := n.EndpointByName(epName) 914 if err != nil { 915 return err 916 } 917 return ep.Delete(force) 918 } 919 920 if ep == nil { 921 return fmt.Errorf("container %s is not connected to network %s", container.ID, n.Name()) 922 } 923 924 if err := ep.Leave(sbox); err != nil { 925 return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err) 926 } 927 928 container.NetworkSettings.Ports = getPortMapInfo(sbox) 929 930 if err := ep.Delete(false); err != nil { 931 return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err) 932 } 933 934 delete(container.NetworkSettings.Networks, n.Name()) 935 936 daemon.tryDetachContainerFromClusterNetwork(n, container) 937 938 return nil 939 } 940 941 func (daemon *Daemon) tryDetachContainerFromClusterNetwork(network libnetwork.Network, container *container.Container) { 942 if daemon.clusterProvider != nil && network.Info().Dynamic() && !container.Managed { 943 if err := daemon.clusterProvider.DetachNetwork(network.Name(), container.ID); err != nil { 944 logrus.Warnf("error detaching from network %s: %v", network.Name(), err) 945 if err := daemon.clusterProvider.DetachNetwork(network.ID(), container.ID); err != nil { 946 logrus.Warnf("error detaching from network %s: %v", network.ID(), err) 947 } 948 } 949 } 950 attributes := map[string]string{ 951 "container": container.ID, 952 } 953 daemon.LogNetworkEventWithAttributes(network, "disconnect", attributes) 954 } 955 956 func (daemon *Daemon) initializeNetworking(container *container.Container) error { 957 var err error 958 959 if container.HostConfig.NetworkMode.IsContainer() { 960 // we need to get the hosts files from the container to join 961 nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer()) 962 if err != nil { 963 return err 964 } 965 966 err = daemon.initializeNetworkingPaths(container, nc) 967 if err != nil { 968 return err 969 } 970 971 container.Config.Hostname = nc.Config.Hostname 972 container.Config.Domainname = nc.Config.Domainname 973 return nil 974 } 975 976 if container.HostConfig.NetworkMode.IsHost() { 977 if container.Config.Hostname == "" { 978 container.Config.Hostname, err = os.Hostname() 979 if err != nil { 980 return err 981 } 982 } 983 } 984 985 if err := daemon.allocateNetwork(container); err != nil { 986 return err 987 } 988 989 return container.BuildHostnameFile() 990 } 991 992 func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) { 993 nc, err := daemon.GetContainer(connectedContainerID) 994 if err != nil { 995 return nil, err 996 } 997 if containerID == nc.ID { 998 return nil, fmt.Errorf("cannot join own network") 999 } 1000 if !nc.IsRunning() { 1001 err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID) 1002 return nil, errdefs.Conflict(err) 1003 } 1004 if nc.IsRestarting() { 1005 return nil, errContainerIsRestarting(connectedContainerID) 1006 } 1007 return nc, nil 1008 } 1009 1010 func (daemon *Daemon) releaseNetwork(container *container.Container) { 1011 start := time.Now() 1012 if daemon.netController == nil { 1013 return 1014 } 1015 if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled { 1016 return 1017 } 1018 1019 sid := container.NetworkSettings.SandboxID 1020 settings := container.NetworkSettings.Networks 1021 container.NetworkSettings.Ports = nil 1022 1023 if sid == "" { 1024 return 1025 } 1026 1027 var networks []libnetwork.Network 1028 for n, epSettings := range settings { 1029 if nw, err := daemon.FindNetwork(getNetworkID(n, epSettings.EndpointSettings)); err == nil { 1030 networks = append(networks, nw) 1031 } 1032 1033 if epSettings.EndpointSettings == nil { 1034 continue 1035 } 1036 1037 cleanOperationalData(epSettings) 1038 } 1039 1040 sb, err := daemon.netController.SandboxByID(sid) 1041 if err != nil { 1042 logrus.Warnf("error locating sandbox id %s: %v", sid, err) 1043 return 1044 } 1045 1046 if err := sb.Delete(); err != nil { 1047 logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err) 1048 } 1049 1050 for _, nw := range networks { 1051 daemon.tryDetachContainerFromClusterNetwork(nw, container) 1052 } 1053 networkActions.WithValues("release").UpdateSince(start) 1054 } 1055 1056 func errRemovalContainer(containerID string) error { 1057 return fmt.Errorf("Container %s is marked for removal and cannot be connected or disconnected to the network", containerID) 1058 } 1059 1060 // ConnectToNetwork connects a container to a network 1061 func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error { 1062 if endpointConfig == nil { 1063 endpointConfig = &networktypes.EndpointSettings{} 1064 } 1065 container.Lock() 1066 defer container.Unlock() 1067 1068 if !container.Running { 1069 if container.RemovalInProgress || container.Dead { 1070 return errRemovalContainer(container.ID) 1071 } 1072 1073 n, err := daemon.FindNetwork(idOrName) 1074 if err == nil && n != nil { 1075 if err := daemon.updateNetworkConfig(container, n, endpointConfig, true); err != nil { 1076 return err 1077 } 1078 } else { 1079 container.NetworkSettings.Networks[idOrName] = &network.EndpointSettings{ 1080 EndpointSettings: endpointConfig, 1081 } 1082 } 1083 } else { 1084 if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil { 1085 return err 1086 } 1087 } 1088 1089 return container.CheckpointTo(daemon.containersReplica) 1090 } 1091 1092 // DisconnectFromNetwork disconnects container from network n. 1093 func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error { 1094 n, err := daemon.FindNetwork(networkName) 1095 container.Lock() 1096 defer container.Unlock() 1097 1098 if !container.Running || (err != nil && force) { 1099 if container.RemovalInProgress || container.Dead { 1100 return errRemovalContainer(container.ID) 1101 } 1102 // In case networkName is resolved we will use n.Name() 1103 // this will cover the case where network id is passed. 1104 if n != nil { 1105 networkName = n.Name() 1106 } 1107 if _, ok := container.NetworkSettings.Networks[networkName]; !ok { 1108 return fmt.Errorf("container %s is not connected to the network %s", container.ID, networkName) 1109 } 1110 delete(container.NetworkSettings.Networks, networkName) 1111 } else if err == nil { 1112 if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() { 1113 return runconfig.ErrConflictHostNetwork 1114 } 1115 1116 if err := daemon.disconnectFromNetwork(container, n, false); err != nil { 1117 return err 1118 } 1119 } else { 1120 return err 1121 } 1122 1123 if err := container.CheckpointTo(daemon.containersReplica); err != nil { 1124 return err 1125 } 1126 1127 if n != nil { 1128 daemon.LogNetworkEventWithAttributes(n, "disconnect", map[string]string{ 1129 "container": container.ID, 1130 }) 1131 } 1132 1133 return nil 1134 } 1135 1136 // ActivateContainerServiceBinding puts this container into load balancer active rotation and DNS response 1137 func (daemon *Daemon) ActivateContainerServiceBinding(containerName string) error { 1138 ctr, err := daemon.GetContainer(containerName) 1139 if err != nil { 1140 return err 1141 } 1142 sb := daemon.getNetworkSandbox(ctr) 1143 if sb == nil { 1144 return fmt.Errorf("network sandbox does not exist for container %s", containerName) 1145 } 1146 return sb.EnableService() 1147 } 1148 1149 // DeactivateContainerServiceBinding removes this container from load balancer active rotation, and DNS response 1150 func (daemon *Daemon) DeactivateContainerServiceBinding(containerName string) error { 1151 ctr, err := daemon.GetContainer(containerName) 1152 if err != nil { 1153 return err 1154 } 1155 sb := daemon.getNetworkSandbox(ctr) 1156 if sb == nil { 1157 // If the network sandbox is not found, then there is nothing to deactivate 1158 logrus.Debugf("Could not find network sandbox for container %s on service binding deactivation request", containerName) 1159 return nil 1160 } 1161 return sb.DisableService() 1162 } 1163 1164 func getNetworkID(name string, endpointSettings *networktypes.EndpointSettings) string { 1165 // We only want to prefer NetworkID for user defined networks. 1166 // For systems like bridge, none, etc. the name is preferred (otherwise restart may cause issues) 1167 if containertypes.NetworkMode(name).IsUserDefined() && endpointSettings != nil && endpointSettings.NetworkID != "" { 1168 return endpointSettings.NetworkID 1169 } 1170 return name 1171 } 1172 1173 // updateSandboxNetworkSettings updates the sandbox ID and Key. 1174 func updateSandboxNetworkSettings(c *container.Container, sb libnetwork.Sandbox) error { 1175 c.NetworkSettings.SandboxID = sb.ID() 1176 c.NetworkSettings.SandboxKey = sb.Key() 1177 return nil 1178 }