// +build linux windows package libnetwork import ( "net" "github.com/Sirupsen/logrus" ) func newService(name string, id string, ingressPorts []*PortConfig, aliases []string) *service { return &service{ name: name, id: id, ingressPorts: ingressPorts, loadBalancers: make(map[string]*loadBalancer), aliases: aliases, } } func (c *controller) cleanupServiceBindings(cleanupNID string) { var cleanupFuncs []func() c.Lock() services := make([]*service, 0, len(c.serviceBindings)) for _, s := range c.serviceBindings { services = append(services, s) } c.Unlock() for _, s := range services { s.Lock() for nid, lb := range s.loadBalancers { if cleanupNID != "" && nid != cleanupNID { continue } for eid, ip := range lb.backEnds { service := s loadBalancer := lb networkID := nid epID := eid epIP := ip cleanupFuncs = append(cleanupFuncs, func() { if err := c.rmServiceBinding(service.name, service.id, networkID, epID, loadBalancer.vip, service.ingressPorts, service.aliases, epIP); err != nil { logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v", service.id, networkID, epID, err) } }) } } s.Unlock() } for _, f := range cleanupFuncs { f() } } func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, ingressPorts []*PortConfig, aliases []string, ip net.IP) error { n, err := c.NetworkByID(nid) if err != nil { return err } skey := serviceKey{ id: sid, ports: portConfigs(ingressPorts).String(), } c.Lock() s, ok := c.serviceBindings[skey] if !ok { // Create a new service if we are seeing this service // for the first time. s = newService(name, sid, ingressPorts, aliases) c.serviceBindings[skey] = s } c.Unlock() // Add endpoint IP to special "tasks.svc_name" so that the // applications have access to DNS RR. n.(*network).addSvcRecords("tasks."+name, ip, nil, false) for _, alias := range aliases { n.(*network).addSvcRecords("tasks."+alias, ip, nil, false) } // Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR svcIP := vip if len(svcIP) == 0 { svcIP = ip } n.(*network).addSvcRecords(name, svcIP, nil, false) for _, alias := range aliases { n.(*network).addSvcRecords(alias, svcIP, nil, false) } s.Lock() defer s.Unlock() lb, ok := s.loadBalancers[nid] if !ok { // Create a new load balancer if we are seeing this // network attachment on the service for the first // time. lb = &loadBalancer{ vip: vip, fwMark: fwMarkCtr, backEnds: make(map[string]net.IP), service: s, } fwMarkCtrMu.Lock() fwMarkCtr++ fwMarkCtrMu.Unlock() s.loadBalancers[nid] = lb } lb.backEnds[eid] = ip // Add loadbalancer service and backend in all sandboxes in // the network only if vip is valid. if len(vip) != 0 { n.(*network).addLBBackend(ip, vip, lb.fwMark, ingressPorts) } return nil } func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, ingressPorts []*PortConfig, aliases []string, ip net.IP) error { var rmService bool n, err := c.NetworkByID(nid) if err != nil { return err } skey := serviceKey{ id: sid, ports: portConfigs(ingressPorts).String(), } c.Lock() s, ok := c.serviceBindings[skey] c.Unlock() if !ok { return nil } s.Lock() lb, ok := s.loadBalancers[nid] if !ok { s.Unlock() return nil } _, ok = lb.backEnds[eid] if !ok { s.Unlock() return nil } delete(lb.backEnds, eid) if len(lb.backEnds) == 0 { // All the backends for this service have been // removed. Time to remove the load balancer and also // remove the service entry in IPVS. rmService = true delete(s.loadBalancers, nid) } if len(s.loadBalancers) == 0 { // All loadbalancers for the service removed. Time to // remove the service itself. c.Lock() delete(c.serviceBindings, skey) c.Unlock() } // Remove loadbalancer service(if needed) and backend in all // sandboxes in the network only if the vip is valid. if len(vip) != 0 { n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService) } s.Unlock() // Delete the special "tasks.svc_name" backend record. n.(*network).deleteSvcRecords("tasks."+name, ip, nil, false) for _, alias := range aliases { n.(*network).deleteSvcRecords("tasks."+alias, ip, nil, false) } // If we are doing DNS RR add the endpoint IP to DNS record // right away. if len(vip) == 0 { n.(*network).deleteSvcRecords(name, ip, nil, false) for _, alias := range aliases { n.(*network).deleteSvcRecords(alias, ip, nil, false) } } // Remove the DNS record for VIP only if we are removing the service if rmService && len(vip) != 0 { n.(*network).deleteSvcRecords(name, vip, nil, false) for _, alias := range aliases { n.(*network).deleteSvcRecords(alias, vip, nil, false) } } return nil }