github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/libnetwork/service_common.go (about)

     1  //go:build linux || windows
     2  // +build linux windows
     3  
     4  package libnetwork
     5  
     6  import (
     7  	"net"
     8  
     9  	"github.com/docker/docker/libnetwork/internal/setmatrix"
    10  	"github.com/sirupsen/logrus"
    11  )
    12  
    13  const maxSetStringLen = 350
    14  
    15  func (c *controller) addEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, addService bool, method string) error {
    16  	n, err := c.NetworkByID(nID)
    17  	if err != nil {
    18  		return err
    19  	}
    20  
    21  	logrus.Debugf("addEndpointNameResolution %s %s add_service:%t sAliases:%v tAliases:%v", eID, svcName, addService, serviceAliases, taskAliases)
    22  
    23  	// Add container resolution mappings
    24  	if err := c.addContainerNameResolution(nID, eID, containerName, taskAliases, ip, method); err != nil {
    25  		return err
    26  	}
    27  
    28  	serviceID := svcID
    29  	if serviceID == "" {
    30  		// This is the case of a normal container not part of a service
    31  		serviceID = eID
    32  	}
    33  
    34  	// Add endpoint IP to special "tasks.svc_name" so that the applications have access to DNS RR.
    35  	n.(*network).addSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method)
    36  	for _, alias := range serviceAliases {
    37  		n.(*network).addSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method)
    38  	}
    39  
    40  	// Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR
    41  	if len(vip) == 0 {
    42  		n.(*network).addSvcRecords(eID, svcName, serviceID, ip, nil, false, method)
    43  		for _, alias := range serviceAliases {
    44  			n.(*network).addSvcRecords(eID, alias, serviceID, ip, nil, false, method)
    45  		}
    46  	}
    47  
    48  	if addService && len(vip) != 0 {
    49  		n.(*network).addSvcRecords(eID, svcName, serviceID, vip, nil, false, method)
    50  		for _, alias := range serviceAliases {
    51  			n.(*network).addSvcRecords(eID, alias, serviceID, vip, nil, false, method)
    52  		}
    53  	}
    54  
    55  	return nil
    56  }
    57  
    58  func (c *controller) addContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
    59  	n, err := c.NetworkByID(nID)
    60  	if err != nil {
    61  		return err
    62  	}
    63  	logrus.Debugf("addContainerNameResolution %s %s", eID, containerName)
    64  
    65  	// Add resolution for container name
    66  	n.(*network).addSvcRecords(eID, containerName, eID, ip, nil, true, method)
    67  
    68  	// Add resolution for taskaliases
    69  	for _, alias := range taskAliases {
    70  		n.(*network).addSvcRecords(eID, alias, eID, ip, nil, false, method)
    71  	}
    72  
    73  	return nil
    74  }
    75  
    76  func (c *controller) deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, rmService, multipleEntries bool, method string) error {
    77  	n, err := c.NetworkByID(nID)
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	logrus.Debugf("deleteEndpointNameResolution %s %s rm_service:%t suppress:%t sAliases:%v tAliases:%v", eID, svcName, rmService, multipleEntries, serviceAliases, taskAliases)
    83  
    84  	// Delete container resolution mappings
    85  	if err := c.delContainerNameResolution(nID, eID, containerName, taskAliases, ip, method); err != nil {
    86  		logrus.WithError(err).Warn("Error delting container from resolver")
    87  	}
    88  
    89  	serviceID := svcID
    90  	if serviceID == "" {
    91  		// This is the case of a normal container not part of a service
    92  		serviceID = eID
    93  	}
    94  
    95  	// Delete the special "tasks.svc_name" backend record.
    96  	if !multipleEntries {
    97  		n.(*network).deleteSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method)
    98  		for _, alias := range serviceAliases {
    99  			n.(*network).deleteSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method)
   100  		}
   101  	}
   102  
   103  	// If we are doing DNS RR delete the endpoint IP from DNS record right away.
   104  	if !multipleEntries && len(vip) == 0 {
   105  		n.(*network).deleteSvcRecords(eID, svcName, serviceID, ip, nil, false, method)
   106  		for _, alias := range serviceAliases {
   107  			n.(*network).deleteSvcRecords(eID, alias, serviceID, ip, nil, false, method)
   108  		}
   109  	}
   110  
   111  	// Remove the DNS record for VIP only if we are removing the service
   112  	if rmService && len(vip) != 0 && !multipleEntries {
   113  		n.(*network).deleteSvcRecords(eID, svcName, serviceID, vip, nil, false, method)
   114  		for _, alias := range serviceAliases {
   115  			n.(*network).deleteSvcRecords(eID, alias, serviceID, vip, nil, false, method)
   116  		}
   117  	}
   118  
   119  	return nil
   120  }
   121  
   122  func (c *controller) delContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
   123  	n, err := c.NetworkByID(nID)
   124  	if err != nil {
   125  		return err
   126  	}
   127  	logrus.Debugf("delContainerNameResolution %s %s", eID, containerName)
   128  
   129  	// Delete resolution for container name
   130  	n.(*network).deleteSvcRecords(eID, containerName, eID, ip, nil, true, method)
   131  
   132  	// Delete resolution for taskaliases
   133  	for _, alias := range taskAliases {
   134  		n.(*network).deleteSvcRecords(eID, alias, eID, ip, nil, true, method)
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  func newService(name string, id string, ingressPorts []*PortConfig, serviceAliases []string) *service {
   141  	return &service{
   142  		name:          name,
   143  		id:            id,
   144  		ingressPorts:  ingressPorts,
   145  		loadBalancers: make(map[string]*loadBalancer),
   146  		aliases:       serviceAliases,
   147  		ipToEndpoint:  setmatrix.NewSetMatrix(),
   148  	}
   149  }
   150  
   151  func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int {
   152  	skey := serviceKey{
   153  		id:    sid,
   154  		ports: portConfigs(ingressPorts).String(),
   155  	}
   156  	c.Lock()
   157  	s, ok := c.serviceBindings[skey]
   158  	c.Unlock()
   159  
   160  	if !ok {
   161  		return 0
   162  	}
   163  
   164  	s.Lock()
   165  	lb := s.loadBalancers[nid]
   166  	s.Unlock()
   167  
   168  	return int(lb.fwMark)
   169  }
   170  
   171  // cleanupServiceDiscovery when the network is being deleted, erase all the associated service discovery records
   172  func (c *controller) cleanupServiceDiscovery(cleanupNID string) {
   173  	c.Lock()
   174  	defer c.Unlock()
   175  	if cleanupNID == "" {
   176  		logrus.Debugf("cleanupServiceDiscovery for all networks")
   177  		c.svcRecords = make(map[string]svcInfo)
   178  		return
   179  	}
   180  	logrus.Debugf("cleanupServiceDiscovery for network:%s", cleanupNID)
   181  	delete(c.svcRecords, cleanupNID)
   182  }
   183  
   184  func (c *controller) cleanupServiceBindings(cleanupNID string) {
   185  	var cleanupFuncs []func()
   186  
   187  	logrus.Debugf("cleanupServiceBindings for %s", cleanupNID)
   188  	c.Lock()
   189  	services := make([]*service, 0, len(c.serviceBindings))
   190  	for _, s := range c.serviceBindings {
   191  		services = append(services, s)
   192  	}
   193  	c.Unlock()
   194  
   195  	for _, s := range services {
   196  		s.Lock()
   197  		// Skip the serviceBindings that got deleted
   198  		if s.deleted {
   199  			s.Unlock()
   200  			continue
   201  		}
   202  		for nid, lb := range s.loadBalancers {
   203  			if cleanupNID != "" && nid != cleanupNID {
   204  				continue
   205  			}
   206  			for eid, be := range lb.backEnds {
   207  				cleanupFuncs = append(cleanupFuncs, makeServiceCleanupFunc(c, s, nid, eid, lb.vip, be.ip))
   208  			}
   209  		}
   210  		s.Unlock()
   211  	}
   212  
   213  	for _, f := range cleanupFuncs {
   214  		f()
   215  	}
   216  }
   217  
   218  func makeServiceCleanupFunc(c *controller, s *service, nID, eID string, vip net.IP, ip net.IP) func() {
   219  	// ContainerName and taskAliases are not available here, this is still fine because the Service discovery
   220  	// cleanup already happened before. The only thing that rmServiceBinding is still doing here a part from the Load
   221  	// Balancer bookeeping, is to keep consistent the mapping of endpoint to IP.
   222  	return func() {
   223  		if err := c.rmServiceBinding(s.name, s.id, nID, eID, "", vip, s.ingressPorts, s.aliases, []string{}, ip, "cleanupServiceBindings", false, true); err != nil {
   224  			logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v", s.id, nID, eID, err)
   225  		}
   226  	}
   227  }
   228  
   229  func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases, taskAliases []string, ip net.IP, method string) error {
   230  	var addService bool
   231  
   232  	// Failure to lock the network ID on add can result in racing
   233  	// racing against network deletion resulting in inconsistent
   234  	// state in the c.serviceBindings map and it's sub-maps. Also,
   235  	// always lock network ID before services to avoid deadlock.
   236  	c.networkLocker.Lock(nID)
   237  	defer c.networkLocker.Unlock(nID) //nolint:errcheck
   238  
   239  	n, err := c.NetworkByID(nID)
   240  	if err != nil {
   241  		return err
   242  	}
   243  
   244  	skey := serviceKey{
   245  		id:    svcID,
   246  		ports: portConfigs(ingressPorts).String(),
   247  	}
   248  
   249  	var s *service
   250  	for {
   251  		c.Lock()
   252  		var ok bool
   253  		s, ok = c.serviceBindings[skey]
   254  		if !ok {
   255  			// Create a new service if we are seeing this service
   256  			// for the first time.
   257  			s = newService(svcName, svcID, ingressPorts, serviceAliases)
   258  			c.serviceBindings[skey] = s
   259  		}
   260  		c.Unlock()
   261  		s.Lock()
   262  		if !s.deleted {
   263  			// ok the object is good to be used
   264  			break
   265  		}
   266  		s.Unlock()
   267  	}
   268  	logrus.Debugf("addServiceBinding from %s START for %s %s p:%p nid:%s skey:%v", method, svcName, eID, s, nID, skey)
   269  	defer s.Unlock()
   270  
   271  	lb, ok := s.loadBalancers[nID]
   272  	if !ok {
   273  		// Create a new load balancer if we are seeing this
   274  		// network attachment on the service for the first
   275  		// time.
   276  		fwMarkCtrMu.Lock()
   277  
   278  		lb = &loadBalancer{
   279  			vip:      vip,
   280  			fwMark:   fwMarkCtr,
   281  			backEnds: make(map[string]*lbBackend),
   282  			service:  s,
   283  		}
   284  
   285  		fwMarkCtr++
   286  		fwMarkCtrMu.Unlock()
   287  
   288  		s.loadBalancers[nID] = lb
   289  		addService = true
   290  	}
   291  
   292  	lb.backEnds[eID] = &lbBackend{ip, false}
   293  
   294  	ok, entries := s.assignIPToEndpoint(ip.String(), eID)
   295  	if !ok || entries > 1 {
   296  		setStr, b := s.printIPToEndpoint(ip.String())
   297  		if len(setStr) > maxSetStringLen {
   298  			setStr = setStr[:maxSetStringLen]
   299  		}
   300  		logrus.Warnf("addServiceBinding %s possible transient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr)
   301  	}
   302  
   303  	// Add loadbalancer service and backend to the network
   304  	n.(*network).addLBBackend(ip, lb)
   305  
   306  	// Add the appropriate name resolutions
   307  	if err := c.addEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, addService, "addServiceBinding"); err != nil {
   308  		return err
   309  	}
   310  
   311  	logrus.Debugf("addServiceBinding from %s END for %s %s", method, svcName, eID)
   312  
   313  	return nil
   314  }
   315  
   316  func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases []string, taskAliases []string, ip net.IP, method string, deleteSvcRecords bool, fullRemove bool) error {
   317  	var rmService bool
   318  
   319  	skey := serviceKey{
   320  		id:    svcID,
   321  		ports: portConfigs(ingressPorts).String(),
   322  	}
   323  
   324  	c.Lock()
   325  	s, ok := c.serviceBindings[skey]
   326  	c.Unlock()
   327  	if !ok {
   328  		logrus.Warnf("rmServiceBinding %s %s %s aborted c.serviceBindings[skey] !ok", method, svcName, eID)
   329  		return nil
   330  	}
   331  
   332  	s.Lock()
   333  	defer s.Unlock()
   334  	logrus.Debugf("rmServiceBinding from %s START for %s %s p:%p nid:%s sKey:%v deleteSvc:%t", method, svcName, eID, s, nID, skey, deleteSvcRecords)
   335  	lb, ok := s.loadBalancers[nID]
   336  	if !ok {
   337  		logrus.Warnf("rmServiceBinding %s %s %s aborted s.loadBalancers[nid] !ok", method, svcName, eID)
   338  		return nil
   339  	}
   340  
   341  	be, ok := lb.backEnds[eID]
   342  	if !ok {
   343  		logrus.Warnf("rmServiceBinding %s %s %s aborted lb.backEnds[eid] && lb.disabled[eid] !ok", method, svcName, eID)
   344  		return nil
   345  	}
   346  
   347  	if fullRemove {
   348  		// delete regardless
   349  		delete(lb.backEnds, eID)
   350  	} else {
   351  		be.disabled = true
   352  	}
   353  
   354  	if len(lb.backEnds) == 0 {
   355  		// All the backends for this service have been
   356  		// removed. Time to remove the load balancer and also
   357  		// remove the service entry in IPVS.
   358  		rmService = true
   359  
   360  		delete(s.loadBalancers, nID)
   361  		logrus.Debugf("rmServiceBinding %s delete %s, p:%p in loadbalancers len:%d", eID, nID, lb, len(s.loadBalancers))
   362  	}
   363  
   364  	ok, entries := s.removeIPToEndpoint(ip.String(), eID)
   365  	if !ok || entries > 0 {
   366  		setStr, b := s.printIPToEndpoint(ip.String())
   367  		if len(setStr) > maxSetStringLen {
   368  			setStr = setStr[:maxSetStringLen]
   369  		}
   370  		logrus.Warnf("rmServiceBinding %s possible transient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr)
   371  	}
   372  
   373  	// Remove loadbalancer service(if needed) and backend in all
   374  	// sandboxes in the network only if the vip is valid.
   375  	if entries == 0 {
   376  		// The network may well have been deleted from the store (and
   377  		// dataplane) before the last of the service bindings.  On Linux that's
   378  		// ok because removing the network sandbox from the dataplane
   379  		// implicitly cleans up all related dataplane state.
   380  		// On the Windows dataplane, VFP policylists must be removed
   381  		// independently of the network, and they must be removed before the HNS
   382  		// network. Otherwise, policylist removal fails with "network not
   383  		// found." On Windows cleanupServiceBindings must be called prior to
   384  		// removing the network from the store or dataplane.
   385  		n, err := c.NetworkByID(nID)
   386  		if err == nil {
   387  			n.(*network).rmLBBackend(ip, lb, rmService, fullRemove)
   388  		}
   389  	}
   390  
   391  	// Delete the name resolutions
   392  	if deleteSvcRecords {
   393  		if err := c.deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, rmService, entries > 0, "rmServiceBinding"); err != nil {
   394  			return err
   395  		}
   396  	}
   397  
   398  	if len(s.loadBalancers) == 0 {
   399  		// All loadbalancers for the service removed. Time to
   400  		// remove the service itself.
   401  		c.Lock()
   402  
   403  		// Mark the object as deleted so that the add won't use it wrongly
   404  		s.deleted = true
   405  		// NOTE The delete from the serviceBindings map has to be the last operation else we are allowing a race between this service
   406  		// that is getting deleted and a new service that will be created if the entry is not anymore there
   407  		delete(c.serviceBindings, skey)
   408  		c.Unlock()
   409  	}
   410  
   411  	logrus.Debugf("rmServiceBinding from %s END for %s %s", method, svcName, eID)
   412  	return nil
   413  }