12 "github.com/Sirupsen/logrus"
13 "github.com/docker/libnetwork/etchosts"
14 "github.com/docker/libnetwork/netlabel"
15 "github.com/docker/libnetwork/osl"
16 "github.com/docker/libnetwork/types"
19 // Sandbox provides the control over the network container entity. It is a one to one mapping with the container.
20 type Sandbox interface {
21 // ID returns the ID of the sandbox
23 // Key returns the sandbox's key
25 // ContainerID returns the container id associated to this sandbox
27 // Labels returns the sandbox's labels
28 Labels() map[string]interface{}
29 // Statistics retrieves the interfaces' statistics for the sandbox
30 Statistics() (map[string]*types.InterfaceStatistics, error)
31 // Refresh leaves all the endpoints, resets and re-applies the options,
32 // re-joins all the endpoints without destroying the osl sandbox
33 Refresh(options ...SandboxOption) error
34 // SetKey updates the Sandbox Key
35 SetKey(key string) error
36 // Rename changes the name of all attached Endpoints
37 Rename(name string) error
38 // Delete destroys this container after detaching it from all connected endpoints.
40 // Endpoints returns all the endpoints connected to the sandbox
41 Endpoints() []Endpoint
42 // ResolveService returns all the backend details about the containers or hosts
43 // backing a service. Its purpose is to satisfy an SRV query
44 ResolveService(name string) ([]*net.SRV, []net.IP)
45 // EnableService makes a managed container's service available by adding the
46 // endpoint to the service load balancer and service discovery
48 // DisableService removes a managed container's endpoints from the load balancer
49 // and service discovery
50 DisableService() error
53 // SandboxOption is an option setter function type used to pass various options to
54 // NewNetContainer method. The various setter functions of type SandboxOption are
55 // provided by libnetwork, they look like ContainerOptionXXXX(...)
56 type SandboxOption func(sb *sandbox)
58 func (sb *sandbox) processOptions(options ...SandboxOption) {
59 for _, opt := range options {
66 type epHeap []*endpoint
71 config containerConfig
74 controller *controller
76 resolverOnce sync.Once
79 epPriority map[string]int
80 populatedEndpoints map[string]struct{}
81 joinLeaveDone chan struct{}
89 // This mutex is used to serialize service related operation for an endpoint
90 // The lock is here because the endpoint is saved into the store so is not unique
94 // These are the container configs used to customize container /etc/hosts file.
95 type hostsPathConfig struct {
99 originHostsPath string
100 extraHosts []extraHost
101 parentUpdates []parentUpdate
104 type parentUpdate struct {
110 type extraHost struct {
115 // These are the container configs used to customize container /etc/resolv.conf file.
116 type resolvConfPathConfig struct {
117 resolvConfPath string
118 originResolvConfPath string
119 resolvConfHashFile string
121 dnsSearchList []string
122 dnsOptionsList []string
125 type containerConfig struct {
128 generic map[string]interface{}
129 useDefaultSandBox bool
131 prio int // higher the value, more the priority
132 exposedPorts []types.TransportPort
136 resolverIPSandbox = "127.0.0.11"
139 func (sb *sandbox) ID() string {
143 func (sb *sandbox) ContainerID() string {
144 return sb.containerID
147 func (sb *sandbox) Key() string {
148 if sb.config.useDefaultSandBox {
149 return osl.GenerateKey("default")
151 return osl.GenerateKey(sb.id)
154 func (sb *sandbox) Labels() map[string]interface{} {
157 opts := make(map[string]interface{}, len(sb.config.generic))
158 for k, v := range sb.config.generic {
164 func (sb *sandbox) Statistics() (map[string]*types.InterfaceStatistics, error) {
165 m := make(map[string]*types.InterfaceStatistics)
175 for _, i := range osb.Info().Interfaces() {
176 if m[i.DstName()], err = i.Statistics(); err != nil {
184 func (sb *sandbox) Delete() error {
185 return sb.delete(false)
188 func (sb *sandbox) delete(force bool) error {
192 return types.ForbiddenErrorf("another sandbox delete in progress")
194 // Set the inDelete flag. This will ensure that we don't
195 // update the store until we have completed all the endpoint
196 // leaves and deletes. And when endpoint leaves and deletes
197 // are completed then we can finally delete the sandbox object
198 // altogether from the data store. If the daemon exits
199 // ungracefully in the middle of a sandbox delete this way we
200 // will have all the references to the endpoints in the
201 // sandbox so that we can clean them up when we restart
207 // Detach from all endpoints
209 for _, ep := range sb.getConnectedEndpoints() {
210 // gw network endpoint detach and removal are automatic
211 if ep.endpointInGWNetwork() && !force {
214 // Retain the sanbdox if we can't obtain the network from store.
215 if _, err := c.getNetworkFromStore(ep.getNetwork().ID()); err != nil {
216 if c.isDistributedControl() {
219 logrus.Warnf("Failed getting network for ep %s during sandbox %s delete: %v", ep.ID(), sb.ID(), err)
224 if err := ep.Leave(sb); err != nil {
225 logrus.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err)
229 if err := ep.Delete(force); err != nil {
230 logrus.Warnf("Failed deleting endpoint %s: %v\n", ep.ID(), err)
238 return fmt.Errorf("could not cleanup all the endpoints in container %s / sandbox %s", sb.containerID, sb.id)
240 // Container is going away. Path cache in etchosts is most
241 // likely not required any more. Drop it.
242 etchosts.Drop(sb.config.hostsPath)
244 if sb.resolver != nil {
248 if sb.osSbox != nil && !sb.config.useDefaultSandBox {
252 if err := sb.storeDelete(); err != nil {
253 logrus.Warnf("Failed to delete sandbox %s from store: %v", sb.ID(), err)
258 c.ingressSandbox = nil
260 delete(c.sandboxes, sb.ID())
266 func (sb *sandbox) Rename(name string) error {
269 for _, ep := range sb.getConnectedEndpoints() {
270 if ep.endpointInGWNetwork() {
276 if err = ep.rename(name); err != nil {
290 func (sb *sandbox) Refresh(options ...SandboxOption) error {
291 // Store connected endpoints
292 epList := sb.getConnectedEndpoints()
294 // Detach from all endpoints
295 for _, ep := range epList {
296 if err := ep.Leave(sb); err != nil {
297 logrus.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err)
302 sb.config = containerConfig{}
303 sb.processOptions(options...)
305 // Setup discovery files
306 if err := sb.setupResolutionFiles(); err != nil {
310 // Re-connect to all endpoints
311 for _, ep := range epList {
312 if err := ep.Join(sb); err != nil {
313 logrus.Warnf("Failed attach sandbox %s to endpoint %s: %v\n", sb.ID(), ep.ID(), err)
320 func (sb *sandbox) MarshalJSON() ([]byte, error) {
324 // We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need
325 return json.Marshal(sb.id)
328 func (sb *sandbox) UnmarshalJSON(b []byte) (err error) {
333 if err := json.Unmarshal(b, &id); err != nil {
340 func (sb *sandbox) Endpoints() []Endpoint {
344 endpoints := make([]Endpoint, len(sb.endpoints))
345 for i, ep := range sb.endpoints {
351 func (sb *sandbox) getConnectedEndpoints() []*endpoint {
355 eps := make([]*endpoint, len(sb.endpoints))
356 for i, ep := range sb.endpoints {
363 func (sb *sandbox) removeEndpoint(ep *endpoint) {
367 for i, e := range sb.endpoints {
369 heap.Remove(&sb.endpoints, i)
375 func (sb *sandbox) getEndpoint(id string) *endpoint {
379 for _, ep := range sb.endpoints {
388 func (sb *sandbox) updateGateway(ep *endpoint) error {
395 osSbox.UnsetGateway()
396 osSbox.UnsetGatewayIPv6()
403 joinInfo := ep.joinInfo
406 if err := osSbox.SetGateway(joinInfo.gw); err != nil {
407 return fmt.Errorf("failed to set gateway while updating gateway: %v", err)
410 if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil {
411 return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
417 func (sb *sandbox) HandleQueryResp(name string, ip net.IP) {
418 for _, ep := range sb.getConnectedEndpoints() {
420 n.HandleQueryResp(name, ip)
424 func (sb *sandbox) ResolveIP(ip string) string {
426 logrus.Debugf("IP To resolve %v", ip)
428 for _, ep := range sb.getConnectedEndpoints() {
430 svc = n.ResolveIP(ip)
439 func (sb *sandbox) ExecFunc(f func()) error {
444 return osSbox.InvokeFunc(f)
446 return fmt.Errorf("osl sandbox unavailable in ExecFunc for %v", sb.ContainerID())
449 func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP) {
453 logrus.Debugf("Service name To resolve: %v", name)
455 // There are DNS implementaions that allow SRV queries for names not in
456 // the format defined by RFC 2782. Hence specific validations checks are
458 parts := strings.Split(name, ".")
463 for _, ep := range sb.getConnectedEndpoints() {
466 srv, ip = n.ResolveService(name)
474 func getDynamicNwEndpoints(epList []*endpoint) []*endpoint {
476 for _, ep := range epList {
478 if n.dynamic && !n.ingress {
479 eps = append(eps, ep)
485 func getIngressNwEndpoint(epList []*endpoint) *endpoint {
486 for _, ep := range epList {
495 func getLocalNwEndpoints(epList []*endpoint) []*endpoint {
497 for _, ep := range epList {
499 if !n.dynamic && !n.ingress {
500 eps = append(eps, ep)
506 func (sb *sandbox) ResolveName(name string, ipType int) ([]net.IP, bool) {
507 // Embedded server owns the docker network domain. Resolution should work
508 // for both container_name and container_name.network_name
509 // We allow '.' in service name and network name. For a name a.b.c.d the
510 // following have to tried;
511 // {a.b.c.d in the networks container is connected to}
512 // {a.b.c in network d},
513 // {a.b in network c.d},
514 // {a in network b.c.d},
516 logrus.Debugf("Name To resolve: %v", name)
517 name = strings.TrimSuffix(name, ".")
518 reqName := []string{name}
519 networkName := []string{""}
521 if strings.Contains(name, ".") {
525 if i = strings.LastIndex(dup, "."); i == -1 {
528 networkName = append(networkName, name[i+1:])
529 reqName = append(reqName, name[:i])
535 epList := sb.getConnectedEndpoints()
537 // In swarm mode services with exposed ports are connected to user overlay
538 // network, ingress network and docker_gwbridge network. Name resolution
539 // should prioritize returning the VIP/IPs on user overlay network.
540 newList := []*endpoint{}
541 if !sb.controller.isDistributedControl() {
542 newList = append(newList, getDynamicNwEndpoints(epList)...)
543 ingressEP := getIngressNwEndpoint(epList)
544 if ingressEP != nil {
545 newList = append(newList, ingressEP)
547 newList = append(newList, getLocalNwEndpoints(epList)...)
551 for i := 0; i < len(reqName); i++ {
553 // First check for local container alias
554 ip, ipv6Miss := sb.resolveName(reqName[i], networkName[i], epList, true, ipType)
562 // Resolve the actual container name
563 ip, ipv6Miss = sb.resolveName(reqName[i], networkName[i], epList, false, ipType)
574 func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool, ipType int) ([]net.IP, bool) {
577 for _, ep := range epList {
581 if networkName != "" && networkName != n.Name() {
586 if ep.aliases == nil {
592 name, ok = ep.aliases[req]
598 // If it is a regular lookup and if the requested name is an alias
599 // don't perform a svc lookup for this endpoint.
601 if _, ok := ep.aliases[req]; ok {
608 ip, miss := n.ResolveName(name, ipType)
621 func (sb *sandbox) SetKey(basePath string) error {
624 logrus.Debugf("sandbox set key processing took %s for container %s", time.Now().Sub(start), sb.ContainerID())
628 return types.BadRequestErrorf("invalid sandbox key")
634 return types.ForbiddenErrorf("failed to SetKey: sandbox %q delete in progress", sb.id)
636 oldosSbox := sb.osSbox
639 if oldosSbox != nil {
640 // If we already have an OS sandbox, release the network resources from that
641 // and destroy the OS snab. We are moving into a new home further down. Note that none
642 // of the network resources gets destroyed during the move.
646 osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key())
655 // If the resolver was setup before stop it and set it up in the
657 if oldosSbox != nil && sb.resolver != nil {
660 if err := sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err == nil {
661 if err := sb.resolver.Start(); err != nil {
662 logrus.Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err)
665 logrus.Errorf("Resolver Setup Function failed for container %s, %q", sb.ContainerID(), err)
669 for _, ep := range sb.getConnectedEndpoints() {
670 if err = sb.populateNetworkResources(ep); err != nil {
677 func (sb *sandbox) EnableService() error {
678 logrus.Debugf("EnableService %s START", sb.containerID)
679 for _, ep := range sb.getConnectedEndpoints() {
680 if ep.enableService(true) {
681 if err := ep.addServiceInfoToCluster(sb); err != nil {
682 ep.enableService(false)
683 return fmt.Errorf("could not update state for endpoint %s into cluster: %v", ep.Name(), err)
687 logrus.Debugf("EnableService %s DONE", sb.containerID)
691 func (sb *sandbox) DisableService() error {
692 logrus.Debugf("DisableService %s START", sb.containerID)
693 for _, ep := range sb.getConnectedEndpoints() {
694 ep.enableService(false)
696 logrus.Debugf("DisableService %s DONE", sb.containerID)
700 func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) {
701 for _, i := range osSbox.Info().Interfaces() {
702 // Only remove the interfaces owned by this endpoint from the sandbox.
703 if ep.hasInterface(i.SrcName()) {
704 if err := i.Remove(); err != nil {
705 logrus.Debugf("Remove interface %s failed: %v", i.SrcName(), err)
711 joinInfo := ep.joinInfo
718 // Remove non-interface routes.
719 for _, r := range joinInfo.StaticRoutes {
720 if err := osSbox.RemoveStaticRoute(r); err != nil {
721 logrus.Debugf("Remove route failed: %v", err)
726 func (sb *sandbox) releaseOSSbox() {
736 for _, ep := range sb.getConnectedEndpoints() {
737 releaseOSSboxResources(osSbox, ep)
743 func (sb *sandbox) restoreOslSandbox() error {
744 var routes []*types.StaticRoute
746 // restore osl sandbox
747 Ifaces := make(map[string][]osl.IfaceOption)
748 for _, ep := range sb.endpoints {
749 var ifaceOptions []osl.IfaceOption
751 joinInfo := ep.joinInfo
756 logrus.Errorf("error restoring endpoint %s for container %s", ep.Name(), sb.ContainerID())
760 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes))
761 if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
762 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6))
765 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac))
767 if len(i.llAddrs) != 0 {
768 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs))
770 if len(ep.virtualIP) != 0 {
771 vipAlias := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)}
772 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().IPAliases([]*net.IPNet{vipAlias}))
774 Ifaces[fmt.Sprintf("%s+%s", i.srcName, i.dstPrefix)] = ifaceOptions
776 for _, r := range joinInfo.StaticRoutes {
777 routes = append(routes, r)
780 if ep.needResolver() {
781 sb.startResolver(true)
785 gwep := sb.getGatewayEndpoint()
790 // restore osl sandbox
791 err := sb.osSbox.Restore(Ifaces, routes, gwep.joinInfo.gw, gwep.joinInfo.gw6)
799 func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
801 if sb.osSbox == nil {
805 inDelete := sb.inDelete
809 joinInfo := ep.joinInfo
813 if ep.needResolver() {
814 sb.startResolver(false)
817 if i != nil && i.srcName != "" {
818 var ifaceOptions []osl.IfaceOption
820 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes))
821 if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
822 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6))
824 if len(i.llAddrs) != 0 {
825 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs))
827 if len(ep.virtualIP) != 0 {
828 vipAlias := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)}
829 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().IPAliases([]*net.IPNet{vipAlias}))
832 ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac))
835 if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
836 return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)
841 // Set up non-interface routes.
842 for _, r := range joinInfo.StaticRoutes {
843 if err := sb.osSbox.AddStaticRoute(r); err != nil {
844 return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err)
849 if ep == sb.getGatewayEndpoint() {
850 if err := sb.updateGateway(ep); err != nil {
855 // Make sure to add the endpoint to the populated endpoint set
856 // before populating loadbalancers.
858 sb.populatedEndpoints[ep.ID()] = struct{}{}
861 // Populate load balancer only after updating all the other
862 // information including gateway and other routes so that
863 // loadbalancers are populated all the network state is in
864 // place in the sandbox.
865 sb.populateLoadbalancers(ep)
867 // Only update the store if we did not come here as part of
868 // sandbox delete. If we came here as part of delete then do
869 // not bother updating the store. The sandbox object will be
872 return sb.storeUpdate()
878 func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
879 ep := sb.getEndpoint(origEp.id)
881 return fmt.Errorf("could not find the sandbox endpoint data for endpoint %s",
887 inDelete := sb.inDelete
890 releaseOSSboxResources(osSbox, ep)
894 delete(sb.populatedEndpoints, ep.ID())
896 if len(sb.endpoints) == 0 {
897 // sb.endpoints should never be empty and this is unexpected error condition
898 // We log an error message to note this down for debugging purposes.
899 logrus.Errorf("No endpoints in sandbox while trying to remove endpoint %s", ep.Name())
905 gwepBefore, gwepAfter *endpoint
908 for i, e := range sb.endpoints {
912 if len(e.Gateway()) > 0 && gwepBefore == nil {
915 if index != -1 && gwepBefore != nil {
919 heap.Remove(&sb.endpoints, index)
920 for _, e := range sb.endpoints {
921 if len(e.Gateway()) > 0 {
926 delete(sb.epPriority, ep.ID())
929 if gwepAfter != nil && gwepBefore != gwepAfter {
930 sb.updateGateway(gwepAfter)
933 // Only update the store if we did not come here as part of
934 // sandbox delete. If we came here as part of delete then do
935 // not bother updating the store. The sandbox object will be
938 return sb.storeUpdate()
944 func (sb *sandbox) isEndpointPopulated(ep *endpoint) bool {
946 _, ok := sb.populatedEndpoints[ep.ID()]
951 // joinLeaveStart waits to ensure there are no joins or leaves in progress and
952 // marks this join/leave in progress without race
953 func (sb *sandbox) joinLeaveStart() {
957 for sb.joinLeaveDone != nil {
958 joinLeaveDone := sb.joinLeaveDone
962 case <-joinLeaveDone:
968 sb.joinLeaveDone = make(chan struct{})
971 // joinLeaveEnd marks the end of this join/leave operation and
972 // signals the same without race to other join and leave waiters
973 func (sb *sandbox) joinLeaveEnd() {
977 if sb.joinLeaveDone != nil {
978 close(sb.joinLeaveDone)
979 sb.joinLeaveDone = nil
983 func (sb *sandbox) hasPortConfigs() bool {
985 _, hasExpPorts := opts[netlabel.ExposedPorts]
986 _, hasPortMaps := opts[netlabel.PortMap]
987 return hasExpPorts || hasPortMaps
990 // OptionHostname function returns an option setter for hostname option to
991 // be passed to NewSandbox method.
992 func OptionHostname(name string) SandboxOption {
993 return func(sb *sandbox) {
994 sb.config.hostName = name
998 // OptionDomainname function returns an option setter for domainname option to
999 // be passed to NewSandbox method.
1000 func OptionDomainname(name string) SandboxOption {
1001 return func(sb *sandbox) {
1002 sb.config.domainName = name
1006 // OptionHostsPath function returns an option setter for hostspath option to
1007 // be passed to NewSandbox method.
1008 func OptionHostsPath(path string) SandboxOption {
1009 return func(sb *sandbox) {
1010 sb.config.hostsPath = path
1014 // OptionOriginHostsPath function returns an option setter for origin hosts file path
1015 // to be passed to NewSandbox method.
1016 func OptionOriginHostsPath(path string) SandboxOption {
1017 return func(sb *sandbox) {
1018 sb.config.originHostsPath = path
1022 // OptionExtraHost function returns an option setter for extra /etc/hosts options
1023 // which is a name and IP as strings.
1024 func OptionExtraHost(name string, IP string) SandboxOption {
1025 return func(sb *sandbox) {
1026 sb.config.extraHosts = append(sb.config.extraHosts, extraHost{name: name, IP: IP})
1030 // OptionParentUpdate function returns an option setter for parent container
1031 // which needs to update the IP address for the linked container.
1032 func OptionParentUpdate(cid string, name, ip string) SandboxOption {
1033 return func(sb *sandbox) {
1034 sb.config.parentUpdates = append(sb.config.parentUpdates, parentUpdate{cid: cid, name: name, ip: ip})
1038 // OptionResolvConfPath function returns an option setter for resolvconfpath option to
1039 // be passed to net container methods.
1040 func OptionResolvConfPath(path string) SandboxOption {
1041 return func(sb *sandbox) {
1042 sb.config.resolvConfPath = path
1046 // OptionOriginResolvConfPath function returns an option setter to set the path to the
1047 // origin resolv.conf file to be passed to net container methods.
1048 func OptionOriginResolvConfPath(path string) SandboxOption {
1049 return func(sb *sandbox) {
1050 sb.config.originResolvConfPath = path
1054 // OptionDNS function returns an option setter for dns entry option to
1055 // be passed to container Create method.
1056 func OptionDNS(dns string) SandboxOption {
1057 return func(sb *sandbox) {
1058 sb.config.dnsList = append(sb.config.dnsList, dns)
1062 // OptionDNSSearch function returns an option setter for dns search entry option to
1063 // be passed to container Create method.
1064 func OptionDNSSearch(search string) SandboxOption {
1065 return func(sb *sandbox) {
1066 sb.config.dnsSearchList = append(sb.config.dnsSearchList, search)
1070 // OptionDNSOptions function returns an option setter for dns options entry option to
1071 // be passed to container Create method.
1072 func OptionDNSOptions(options string) SandboxOption {
1073 return func(sb *sandbox) {
1074 sb.config.dnsOptionsList = append(sb.config.dnsOptionsList, options)
1078 // OptionUseDefaultSandbox function returns an option setter for using default sandbox to
1079 // be passed to container Create method.
1080 func OptionUseDefaultSandbox() SandboxOption {
1081 return func(sb *sandbox) {
1082 sb.config.useDefaultSandBox = true
1086 // OptionUseExternalKey function returns an option setter for using provided namespace
1087 // instead of creating one.
1088 func OptionUseExternalKey() SandboxOption {
1089 return func(sb *sandbox) {
1090 sb.config.useExternalKey = true
1094 // OptionGeneric function returns an option setter for Generic configuration
1095 // that is not managed by libNetwork but can be used by the Drivers during the call to
1096 // net container creation method. Container Labels are a good example.
1097 func OptionGeneric(generic map[string]interface{}) SandboxOption {
1098 return func(sb *sandbox) {
1099 if sb.config.generic == nil {
1100 sb.config.generic = make(map[string]interface{}, len(generic))
1102 for k, v := range generic {
1103 sb.config.generic[k] = v
1108 // OptionExposedPorts function returns an option setter for the container exposed
1109 // ports option to be passed to container Create method.
1110 func OptionExposedPorts(exposedPorts []types.TransportPort) SandboxOption {
1111 return func(sb *sandbox) {
1112 if sb.config.generic == nil {
1113 sb.config.generic = make(map[string]interface{})
1116 eps := make([]types.TransportPort, len(exposedPorts))
1117 copy(eps, exposedPorts)
1118 // Store endpoint label and in generic because driver needs it
1119 sb.config.exposedPorts = eps
1120 sb.config.generic[netlabel.ExposedPorts] = eps
1124 // OptionPortMapping function returns an option setter for the mapping
1125 // ports option to be passed to container Create method.
1126 func OptionPortMapping(portBindings []types.PortBinding) SandboxOption {
1127 return func(sb *sandbox) {
1128 if sb.config.generic == nil {
1129 sb.config.generic = make(map[string]interface{})
1131 // Store a copy of the bindings as generic data to pass to the driver
1132 pbs := make([]types.PortBinding, len(portBindings))
1133 copy(pbs, portBindings)
1134 sb.config.generic[netlabel.PortMap] = pbs
1138 // OptionIngress function returns an option setter for marking a
1139 // sandbox as the controller's ingress sandbox.
1140 func OptionIngress() SandboxOption {
1141 return func(sb *sandbox) {
1146 func (eh epHeap) Len() int { return len(eh) }
1148 func (eh epHeap) Less(i, j int) bool {
1154 ci, _ := eh[i].getSandbox()
1155 cj, _ := eh[j].getSandbox()
1160 if epi.endpointInGWNetwork() {
1164 if epj.endpointInGWNetwork() {
1168 if epi.getNetwork().Internal() {
1172 if epj.getNetwork().Internal() {
1176 if epi.joinInfo != nil && epj.joinInfo != nil {
1177 if (epi.joinInfo.gw != nil && epi.joinInfo.gw6 != nil) &&
1178 (epj.joinInfo.gw == nil || epj.joinInfo.gw6 == nil) {
1181 if (epj.joinInfo.gw != nil && epj.joinInfo.gw6 != nil) &&
1182 (epi.joinInfo.gw == nil || epi.joinInfo.gw6 == nil) {
1188 cip, ok = ci.epPriority[eh[i].ID()]
1195 cjp, ok = cj.epPriority[eh[j].ID()]
1202 return eh[i].network.Name() < eh[j].network.Name()
1208 func (eh epHeap) Swap(i, j int) { eh[i], eh[j] = eh[j], eh[i] }
1210 func (eh *epHeap) Push(x interface{}) {
1211 *eh = append(*eh, x.(*endpoint))
1214 func (eh *epHeap) Pop() interface{} {
1222 func (sb *sandbox) NdotsSet() bool {