123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- // +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) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int {
- skey := serviceKey{
- id: sid,
- ports: portConfigs(ingressPorts).String(),
- }
- c.Lock()
- s, ok := c.serviceBindings[skey]
- c.Unlock()
- if !ok {
- return 0
- }
- s.Lock()
- lb := s.loadBalancers[nid]
- s.Unlock()
- return int(lb.fwMark)
- }
- 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
- }
|