github.com/kobeld/docker@v1.12.0-rc1/daemon/container_operations.go (about) 1 package daemon 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "os" 8 "path" 9 "strings" 10 11 "github.com/Sirupsen/logrus" 12 "github.com/docker/docker/container" 13 "github.com/docker/docker/daemon/network" 14 derr "github.com/docker/docker/errors" 15 "github.com/docker/docker/pkg/stringid" 16 "github.com/docker/docker/runconfig" 17 containertypes "github.com/docker/engine-api/types/container" 18 networktypes "github.com/docker/engine-api/types/network" 19 "github.com/docker/go-connections/nat" 20 "github.com/docker/libnetwork" 21 "github.com/docker/libnetwork/netlabel" 22 "github.com/docker/libnetwork/options" 23 "github.com/docker/libnetwork/types" 24 ) 25 26 var ( 27 // ErrRootFSReadOnly is returned when a container 28 // rootfs is marked readonly. 29 ErrRootFSReadOnly = errors.New("container rootfs is marked read-only") 30 getPortMapInfo = container.GetSandboxPortMapInfo 31 ) 32 33 func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]libnetwork.SandboxOption, error) { 34 var ( 35 sboxOptions []libnetwork.SandboxOption 36 err error 37 dns []string 38 dnsSearch []string 39 dnsOptions []string 40 bindings = make(nat.PortMap) 41 pbList []types.PortBinding 42 exposeList []types.TransportPort 43 ) 44 45 defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName() 46 sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), 47 libnetwork.OptionDomainname(container.Config.Domainname)) 48 49 if container.HostConfig.NetworkMode.IsHost() { 50 sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) 51 if len(container.HostConfig.ExtraHosts) == 0 { 52 sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts")) 53 } 54 if len(container.HostConfig.DNS) == 0 && len(daemon.configStore.DNS) == 0 && 55 len(container.HostConfig.DNSSearch) == 0 && len(daemon.configStore.DNSSearch) == 0 && 56 len(container.HostConfig.DNSOptions) == 0 && len(daemon.configStore.DNSOptions) == 0 { 57 sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) 58 } 59 } else { 60 // OptionUseExternalKey is mandatory for userns support. 61 // But optional for non-userns support 62 sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey()) 63 } 64 65 container.HostsPath, err = container.GetRootResourcePath("hosts") 66 if err != nil { 67 return nil, err 68 } 69 sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath)) 70 71 container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf") 72 if err != nil { 73 return nil, err 74 } 75 sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath)) 76 77 if len(container.HostConfig.DNS) > 0 { 78 dns = container.HostConfig.DNS 79 } else if len(daemon.configStore.DNS) > 0 { 80 dns = daemon.configStore.DNS 81 } 82 83 for _, d := range dns { 84 sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) 85 } 86 87 if len(container.HostConfig.DNSSearch) > 0 { 88 dnsSearch = container.HostConfig.DNSSearch 89 } else if len(daemon.configStore.DNSSearch) > 0 { 90 dnsSearch = daemon.configStore.DNSSearch 91 } 92 93 for _, ds := range dnsSearch { 94 sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) 95 } 96 97 if len(container.HostConfig.DNSOptions) > 0 { 98 dnsOptions = container.HostConfig.DNSOptions 99 } else if len(daemon.configStore.DNSOptions) > 0 { 100 dnsOptions = daemon.configStore.DNSOptions 101 } 102 103 for _, ds := range dnsOptions { 104 sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds)) 105 } 106 107 if container.NetworkSettings.SecondaryIPAddresses != nil { 108 name := container.Config.Hostname 109 if container.Config.Domainname != "" { 110 name = name + "." + container.Config.Domainname 111 } 112 113 for _, a := range container.NetworkSettings.SecondaryIPAddresses { 114 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) 115 } 116 } 117 118 for _, extraHost := range container.HostConfig.ExtraHosts { 119 // allow IPv6 addresses in extra hosts; only split on first ":" 120 parts := strings.SplitN(extraHost, ":", 2) 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 if _, ok := container.NetworkSettings.Networks[defaultNetName]; !container.HostConfig.NetworkMode.IsDefault() || !ok { 181 return sboxOptions, nil 182 } 183 184 if container.NetworkSettings.Networks[defaultNetName].EndpointID == "" { 185 return sboxOptions, nil 186 } 187 188 var ( 189 childEndpoints, parentEndpoints []string 190 cEndpointID string 191 ) 192 193 children := daemon.children(container) 194 for linkAlias, child := range children { 195 if !isLinkable(child) { 196 return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name) 197 } 198 _, alias := path.Split(linkAlias) 199 // allow access to the linked container via the alias, real name, and container hostname 200 aliasList := alias + " " + child.Config.Hostname 201 // only add the name if alias isn't equal to the name 202 if alias != child.Name[1:] { 203 aliasList = aliasList + " " + child.Name[1:] 204 } 205 sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks[defaultNetName].IPAddress)) 206 cEndpointID = child.NetworkSettings.Networks[defaultNetName].EndpointID 207 if cEndpointID != "" { 208 childEndpoints = append(childEndpoints, cEndpointID) 209 } 210 } 211 212 bridgeSettings := container.NetworkSettings.Networks[defaultNetName] 213 for alias, parent := range daemon.parents(container) { 214 if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() { 215 continue 216 } 217 218 _, alias = path.Split(alias) 219 logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress) 220 sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate( 221 parent.ID, 222 alias, 223 bridgeSettings.IPAddress, 224 )) 225 if cEndpointID != "" { 226 parentEndpoints = append(parentEndpoints, cEndpointID) 227 } 228 } 229 230 linkOptions := options.Generic{ 231 netlabel.GenericData: options.Generic{ 232 "ParentEndpoints": parentEndpoints, 233 "ChildEndpoints": childEndpoints, 234 }, 235 } 236 237 sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) 238 return sboxOptions, nil 239 } 240 241 func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network) error { 242 if container.NetworkSettings == nil { 243 container.NetworkSettings = &network.Settings{Networks: make(map[string]*networktypes.EndpointSettings)} 244 } 245 246 if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() { 247 return runconfig.ErrConflictHostNetwork 248 } 249 250 for s := range container.NetworkSettings.Networks { 251 sn, err := daemon.FindNetwork(s) 252 if err != nil { 253 continue 254 } 255 256 if sn.Name() == n.Name() { 257 // Avoid duplicate config 258 return nil 259 } 260 if !containertypes.NetworkMode(sn.Type()).IsPrivate() || 261 !containertypes.NetworkMode(n.Type()).IsPrivate() { 262 return runconfig.ErrConflictSharedNetwork 263 } 264 if containertypes.NetworkMode(sn.Name()).IsNone() || 265 containertypes.NetworkMode(n.Name()).IsNone() { 266 return runconfig.ErrConflictNoNetwork 267 } 268 } 269 270 if _, ok := container.NetworkSettings.Networks[n.Name()]; !ok { 271 container.NetworkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings) 272 } 273 274 return nil 275 } 276 277 func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error { 278 if err := container.BuildEndpointInfo(n, ep); err != nil { 279 return err 280 } 281 282 if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() { 283 container.NetworkSettings.Bridge = daemon.configStore.bridgeConfig.Iface 284 } 285 286 return nil 287 } 288 289 // UpdateNetwork is used to update the container's network (e.g. when linked containers 290 // get removed/unlinked). 291 func (daemon *Daemon) updateNetwork(container *container.Container) error { 292 ctrl := daemon.netController 293 sid := container.NetworkSettings.SandboxID 294 295 sb, err := ctrl.SandboxByID(sid) 296 if err != nil { 297 return fmt.Errorf("error locating sandbox id %s: %v", sid, err) 298 } 299 300 // Find if container is connected to the default bridge network 301 var n libnetwork.Network 302 for name := range container.NetworkSettings.Networks { 303 sn, err := daemon.FindNetwork(name) 304 if err != nil { 305 continue 306 } 307 if sn.Name() == runconfig.DefaultDaemonNetworkMode().NetworkName() { 308 n = sn 309 break 310 } 311 } 312 313 if n == nil { 314 // Not connected to the default bridge network; Nothing to do 315 return nil 316 } 317 318 options, err := daemon.buildSandboxOptions(container) 319 if err != nil { 320 return fmt.Errorf("Update network failed: %v", err) 321 } 322 323 if err := sb.Refresh(options...); err != nil { 324 return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err) 325 } 326 327 return nil 328 } 329 330 func errClusterNetworkOnRun(n string) error { 331 return fmt.Errorf("swarm-scoped network (%s) is not compatible with `docker create` or `docker run`. This network can be only used docker service", n) 332 } 333 334 // updateContainerNetworkSettings update the network settings 335 func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error { 336 var ( 337 n libnetwork.Network 338 err error 339 ) 340 341 mode := container.HostConfig.NetworkMode 342 if container.Config.NetworkDisabled || mode.IsContainer() { 343 return nil 344 } 345 346 networkName := mode.NetworkName() 347 if mode.IsDefault() { 348 networkName = daemon.netController.Config().Daemon.DefaultNetwork 349 } 350 if mode.IsUserDefined() { 351 n, err = daemon.FindNetwork(networkName) 352 if err != nil { 353 return err 354 } 355 if !container.Managed && n.Info().Dynamic() { 356 return errClusterNetworkOnRun(networkName) 357 } 358 networkName = n.Name() 359 } 360 if container.NetworkSettings == nil { 361 container.NetworkSettings = &network.Settings{} 362 } 363 if len(endpointsConfig) > 0 { 364 container.NetworkSettings.Networks = endpointsConfig 365 } 366 if container.NetworkSettings.Networks == nil { 367 container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings) 368 container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings) 369 } 370 if !mode.IsUserDefined() { 371 return nil 372 } 373 // Make sure to internally store the per network endpoint config by network name 374 if _, ok := container.NetworkSettings.Networks[networkName]; ok { 375 return nil 376 } 377 if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok { 378 container.NetworkSettings.Networks[networkName] = nwConfig 379 delete(container.NetworkSettings.Networks, n.ID()) 380 return nil 381 } 382 383 return nil 384 } 385 386 func (daemon *Daemon) allocateNetwork(container *container.Container) error { 387 controller := daemon.netController 388 389 if daemon.netController == nil { 390 return nil 391 } 392 393 // Cleanup any stale sandbox left over due to ungraceful daemon shutdown 394 if err := controller.SandboxDestroy(container.ID); err != nil { 395 logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID) 396 } 397 398 updateSettings := false 399 if len(container.NetworkSettings.Networks) == 0 { 400 if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() { 401 return nil 402 } 403 404 err := daemon.updateContainerNetworkSettings(container, nil) 405 if err != nil { 406 return err 407 } 408 updateSettings = true 409 } 410 411 for n, nConf := range container.NetworkSettings.Networks { 412 if err := daemon.connectToNetwork(container, n, nConf, updateSettings); err != nil { 413 return err 414 } 415 } 416 417 return container.WriteHostConfig() 418 } 419 420 func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox { 421 var sb libnetwork.Sandbox 422 daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool { 423 if s.ContainerID() == container.ID { 424 sb = s 425 return true 426 } 427 return false 428 }) 429 return sb 430 } 431 432 // hasUserDefinedIPAddress returns whether the passed endpoint configuration contains IP address configuration 433 func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool { 434 return epConfig != nil && epConfig.IPAMConfig != nil && (len(epConfig.IPAMConfig.IPv4Address) > 0 || len(epConfig.IPAMConfig.IPv6Address) > 0) 435 } 436 437 // User specified ip address is acceptable only for networks with user specified subnets. 438 func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error { 439 if n == nil || epConfig == nil { 440 return nil 441 } 442 if !hasUserDefinedIPAddress(epConfig) { 443 return nil 444 } 445 _, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig() 446 for _, s := range []struct { 447 ipConfigured bool 448 subnetConfigs []*libnetwork.IpamConf 449 }{ 450 { 451 ipConfigured: len(epConfig.IPAMConfig.IPv4Address) > 0, 452 subnetConfigs: nwIPv4Configs, 453 }, 454 { 455 ipConfigured: len(epConfig.IPAMConfig.IPv6Address) > 0, 456 subnetConfigs: nwIPv6Configs, 457 }, 458 } { 459 if s.ipConfigured { 460 foundSubnet := false 461 for _, cfg := range s.subnetConfigs { 462 if len(cfg.PreferredPool) > 0 { 463 foundSubnet = true 464 break 465 } 466 } 467 if !foundSubnet { 468 return runconfig.ErrUnsupportedNetworkNoSubnetAndIP 469 } 470 } 471 } 472 473 return nil 474 } 475 476 // cleanOperationalData resets the operational data from the passed endpoint settings 477 func cleanOperationalData(es *networktypes.EndpointSettings) { 478 es.EndpointID = "" 479 es.Gateway = "" 480 es.IPAddress = "" 481 es.IPPrefixLen = 0 482 es.IPv6Gateway = "" 483 es.GlobalIPv6Address = "" 484 es.GlobalIPv6PrefixLen = 0 485 es.MacAddress = "" 486 } 487 488 func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) { 489 if container.HostConfig.NetworkMode.IsContainer() { 490 return nil, runconfig.ErrConflictSharedNetwork 491 } 492 493 if containertypes.NetworkMode(idOrName).IsBridge() && 494 daemon.configStore.DisableBridge { 495 container.Config.NetworkDisabled = true 496 return nil, nil 497 } 498 499 if !containertypes.NetworkMode(idOrName).IsUserDefined() { 500 if hasUserDefinedIPAddress(endpointConfig) { 501 return nil, runconfig.ErrUnsupportedNetworkAndIP 502 } 503 if endpointConfig != nil && len(endpointConfig.Aliases) > 0 { 504 return nil, runconfig.ErrUnsupportedNetworkAndAlias 505 } 506 } else { 507 addShortID := true 508 shortID := stringid.TruncateID(container.ID) 509 for _, alias := range endpointConfig.Aliases { 510 if alias == shortID { 511 addShortID = false 512 break 513 } 514 } 515 if addShortID { 516 endpointConfig.Aliases = append(endpointConfig.Aliases, shortID) 517 } 518 } 519 520 n, err := daemon.FindNetwork(idOrName) 521 if err != nil { 522 return nil, err 523 } 524 525 if err := validateNetworkingConfig(n, endpointConfig); err != nil { 526 return nil, err 527 } 528 529 if updateSettings { 530 if err := daemon.updateNetworkSettings(container, n); err != nil { 531 return nil, err 532 } 533 } 534 return n, nil 535 } 536 537 func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) { 538 if endpointConfig == nil { 539 endpointConfig = &networktypes.EndpointSettings{} 540 } 541 n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings) 542 if err != nil { 543 return err 544 } 545 if n == nil { 546 return nil 547 } 548 549 controller := daemon.netController 550 551 sb := daemon.getNetworkSandbox(container) 552 createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb) 553 if err != nil { 554 return err 555 } 556 557 endpointName := strings.TrimPrefix(container.Name, "/") 558 ep, err := n.CreateEndpoint(endpointName, createOptions...) 559 if err != nil { 560 return err 561 } 562 defer func() { 563 if err != nil { 564 if e := ep.Delete(false); e != nil { 565 logrus.Warnf("Could not rollback container connection to network %s", idOrName) 566 } 567 } 568 }() 569 container.NetworkSettings.Networks[n.Name()] = endpointConfig 570 571 if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil { 572 return err 573 } 574 575 if sb == nil { 576 options, err := daemon.buildSandboxOptions(container) 577 if err != nil { 578 return err 579 } 580 sb, err = controller.NewSandbox(container.ID, options...) 581 if err != nil { 582 return err 583 } 584 585 container.UpdateSandboxNetworkSettings(sb) 586 } 587 588 joinOptions, err := container.BuildJoinOptions(n) 589 if err != nil { 590 return err 591 } 592 593 if err := ep.Join(sb, joinOptions...); err != nil { 594 return err 595 } 596 597 if err := container.UpdateJoinInfo(n, ep); err != nil { 598 return fmt.Errorf("Updating join info failed: %v", err) 599 } 600 601 container.NetworkSettings.Ports = getPortMapInfo(sb) 602 603 daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID}) 604 return nil 605 } 606 607 // ForceEndpointDelete deletes an endpoing from a network forcefully 608 func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error { 609 ep, err := n.EndpointByName(name) 610 if err != nil { 611 return err 612 } 613 return ep.Delete(true) 614 } 615 616 func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { 617 var ( 618 ep libnetwork.Endpoint 619 sbox libnetwork.Sandbox 620 ) 621 622 s := func(current libnetwork.Endpoint) bool { 623 epInfo := current.Info() 624 if epInfo == nil { 625 return false 626 } 627 if sb := epInfo.Sandbox(); sb != nil { 628 if sb.ContainerID() == container.ID { 629 ep = current 630 sbox = sb 631 return true 632 } 633 } 634 return false 635 } 636 n.WalkEndpoints(s) 637 638 if ep == nil && force { 639 epName := strings.TrimPrefix(container.Name, "/") 640 ep, err := n.EndpointByName(epName) 641 if err != nil { 642 return err 643 } 644 return ep.Delete(force) 645 } 646 647 if ep == nil { 648 return fmt.Errorf("container %s is not connected to the network", container.ID) 649 } 650 651 if err := ep.Leave(sbox); err != nil { 652 return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err) 653 } 654 655 container.NetworkSettings.Ports = getPortMapInfo(sbox) 656 657 if err := ep.Delete(false); err != nil { 658 return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err) 659 } 660 661 delete(container.NetworkSettings.Networks, n.Name()) 662 return nil 663 } 664 665 func (daemon *Daemon) initializeNetworking(container *container.Container) error { 666 var err error 667 668 if container.HostConfig.NetworkMode.IsContainer() { 669 // we need to get the hosts files from the container to join 670 nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer()) 671 if err != nil { 672 return err 673 } 674 container.HostnamePath = nc.HostnamePath 675 container.HostsPath = nc.HostsPath 676 container.ResolvConfPath = nc.ResolvConfPath 677 container.Config.Hostname = nc.Config.Hostname 678 container.Config.Domainname = nc.Config.Domainname 679 return nil 680 } 681 682 if container.HostConfig.NetworkMode.IsHost() { 683 container.Config.Hostname, err = os.Hostname() 684 if err != nil { 685 return err 686 } 687 } 688 689 if err := daemon.allocateNetwork(container); err != nil { 690 return err 691 } 692 693 return container.BuildHostnameFile() 694 } 695 696 func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) { 697 nc, err := daemon.GetContainer(connectedContainerID) 698 if err != nil { 699 return nil, err 700 } 701 if containerID == nc.ID { 702 return nil, fmt.Errorf("cannot join own network") 703 } 704 if !nc.IsRunning() { 705 err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID) 706 return nil, derr.NewRequestConflictError(err) 707 } 708 if nc.IsRestarting() { 709 return nil, errContainerIsRestarting(connectedContainerID) 710 } 711 return nc, nil 712 } 713 714 func (daemon *Daemon) releaseNetwork(container *container.Container) { 715 if daemon.netController == nil { 716 return 717 } 718 if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled { 719 return 720 } 721 722 sid := container.NetworkSettings.SandboxID 723 settings := container.NetworkSettings.Networks 724 container.NetworkSettings.Ports = nil 725 726 if sid == "" || len(settings) == 0 { 727 return 728 } 729 730 var networks []libnetwork.Network 731 for n, epSettings := range settings { 732 if nw, err := daemon.FindNetwork(n); err == nil { 733 networks = append(networks, nw) 734 } 735 cleanOperationalData(epSettings) 736 } 737 738 sb, err := daemon.netController.SandboxByID(sid) 739 if err != nil { 740 logrus.Warnf("error locating sandbox id %s: %v", sid, err) 741 return 742 } 743 744 if err := sb.Delete(); err != nil { 745 logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err) 746 } 747 748 for _, nw := range networks { 749 attributes := map[string]string{ 750 "container": container.ID, 751 } 752 daemon.LogNetworkEventWithAttributes(nw, "disconnect", attributes) 753 } 754 }