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