Просмотр исходного кода

pkg: fix reconciling peer updates

Lucas Servén Marín 7 лет назад
Родитель
Сommit
034c27ab78
2 измененных файлов с 43 добавлено и 21 удалено
  1. 14 4
      pkg/k8s/backend.go
  2. 29 17
      pkg/mesh/mesh.go

+ 14 - 4
pkg/k8s/backend.go

@@ -154,13 +154,18 @@ func (nb *nodeBackend) Init(stop <-chan struct{}) error {
 				}
 				}
 				nb.events <- &mesh.NodeEvent{Type: mesh.AddEvent, Node: translateNode(n)}
 				nb.events <- &mesh.NodeEvent{Type: mesh.AddEvent, Node: translateNode(n)}
 			},
 			},
-			UpdateFunc: func(_, obj interface{}) {
+			UpdateFunc: func(old, obj interface{}) {
 				n, ok := obj.(*v1.Node)
 				n, ok := obj.(*v1.Node)
 				if !ok {
 				if !ok {
 					// Failed to decode Node; ignoring...
 					// Failed to decode Node; ignoring...
 					return
 					return
 				}
 				}
-				nb.events <- &mesh.NodeEvent{Type: mesh.UpdateEvent, Node: translateNode(n)}
+				o, ok := old.(*v1.Node)
+				if !ok {
+					// Failed to decode Node; ignoring...
+					return
+				}
+				nb.events <- &mesh.NodeEvent{Type: mesh.UpdateEvent, Node: translateNode(n), Old: translateNode(o)}
 			},
 			},
 			DeleteFunc: func(obj interface{}) {
 			DeleteFunc: func(obj interface{}) {
 				n, ok := obj.(*v1.Node)
 				n, ok := obj.(*v1.Node)
@@ -369,13 +374,18 @@ func (pb *peerBackend) Init(stop <-chan struct{}) error {
 				}
 				}
 				pb.events <- &mesh.PeerEvent{Type: mesh.AddEvent, Peer: translatePeer(p)}
 				pb.events <- &mesh.PeerEvent{Type: mesh.AddEvent, Peer: translatePeer(p)}
 			},
 			},
-			UpdateFunc: func(_, obj interface{}) {
+			UpdateFunc: func(old, obj interface{}) {
 				p, ok := obj.(*v1alpha1.Peer)
 				p, ok := obj.(*v1alpha1.Peer)
 				if !ok || p.Validate() != nil {
 				if !ok || p.Validate() != nil {
 					// Failed to decode Peer; ignoring...
 					// Failed to decode Peer; ignoring...
 					return
 					return
 				}
 				}
-				pb.events <- &mesh.PeerEvent{Type: mesh.UpdateEvent, Peer: translatePeer(p)}
+				o, ok := old.(*v1alpha1.Peer)
+				if !ok || o.Validate() != nil {
+					// Failed to decode Peer; ignoring...
+					return
+				}
+				pb.events <- &mesh.PeerEvent{Type: mesh.UpdateEvent, Peer: translatePeer(p), Old: translatePeer(o)}
 			},
 			},
 			DeleteFunc: func(obj interface{}) {
 			DeleteFunc: func(obj interface{}) {
 				p, ok := obj.(*v1alpha1.Peer)
 				p, ok := obj.(*v1alpha1.Peer)

+ 29 - 17
pkg/mesh/mesh.go

@@ -124,12 +124,14 @@ const (
 type NodeEvent struct {
 type NodeEvent struct {
 	Type EventType
 	Type EventType
 	Node *Node
 	Node *Node
+	Old  *Node
 }
 }
 
 
 // PeerEvent represents an event concerning a peer in the cluster.
 // PeerEvent represents an event concerning a peer in the cluster.
 type PeerEvent struct {
 type PeerEvent struct {
 	Type EventType
 	Type EventType
 	Peer *Peer
 	Peer *Peer
+	Old  *Peer
 }
 }
 
 
 // Backend can create clients for all of the
 // Backend can create clients for all of the
@@ -415,8 +417,7 @@ func (m *Mesh) syncNodes(e *NodeEvent) {
 		// An existing node is no longer valid
 		// An existing node is no longer valid
 		// so remove it from the mesh.
 		// so remove it from the mesh.
 		if _, ok := m.nodes[e.Node.Name]; ok {
 		if _, ok := m.nodes[e.Node.Name]; ok {
-			level.Info(logger).Log("msg", "node is no longer in the mesh", "node", e.Node)
-			delete(m.nodes, e.Node.Name)
+			level.Info(logger).Log("msg", "node is no longer ready", "node", e.Node)
 			diff = true
 			diff = true
 		}
 		}
 	} else {
 	} else {
@@ -454,8 +455,7 @@ func (m *Mesh) syncPeers(e *PeerEvent) {
 		// An existing peer is no longer valid
 		// An existing peer is no longer valid
 		// so remove it from the mesh.
 		// so remove it from the mesh.
 		if _, ok := m.peers[key]; ok {
 		if _, ok := m.peers[key]; ok {
-			level.Info(logger).Log("msg", "peer is no longer in the mesh", "peer", e.Peer)
-			delete(m.peers, key)
+			level.Info(logger).Log("msg", "peer is no longer ready", "peer", e.Peer)
 			diff = true
 			diff = true
 		}
 		}
 	} else {
 	} else {
@@ -463,6 +463,10 @@ func (m *Mesh) syncPeers(e *PeerEvent) {
 		case AddEvent:
 		case AddEvent:
 			fallthrough
 			fallthrough
 		case UpdateEvent:
 		case UpdateEvent:
+			if e.Old != nil && key != string(e.Old.PublicKey) {
+				delete(m.peers, string(e.Old.PublicKey))
+				diff = true
+			}
 			if !peersAreEqual(m.peers[key], e.Peer) {
 			if !peersAreEqual(m.peers[key], e.Peer) {
 				m.peers[key] = e.Peer
 				m.peers[key] = e.Peer
 				diff = true
 				diff = true
@@ -483,16 +487,19 @@ func (m *Mesh) syncPeers(e *PeerEvent) {
 // in the backend.
 // in the backend.
 func (m *Mesh) checkIn() {
 func (m *Mesh) checkIn() {
 	m.mu.Lock()
 	m.mu.Lock()
+	defer m.mu.Unlock()
 	n := m.nodes[m.hostname]
 	n := m.nodes[m.hostname]
-	m.mu.Unlock()
 	if n == nil {
 	if n == nil {
 		level.Debug(m.logger).Log("msg", "no local node found in backend")
 		level.Debug(m.logger).Log("msg", "no local node found in backend")
 		return
 		return
 	}
 	}
+	oldTime := n.LastSeen
 	n.LastSeen = time.Now().Unix()
 	n.LastSeen = time.Now().Unix()
 	if err := m.Nodes().Set(m.hostname, n); err != nil {
 	if err := m.Nodes().Set(m.hostname, n); err != nil {
 		level.Error(m.logger).Log("error", fmt.Sprintf("failed to set local node: %v", err), "node", n)
 		level.Error(m.logger).Log("error", fmt.Sprintf("failed to set local node: %v", err), "node", n)
 		m.errorCounter.WithLabelValues("checkin").Inc()
 		m.errorCounter.WithLabelValues("checkin").Inc()
+		// Revert time.
+		n.LastSeen = oldTime
 		return
 		return
 	}
 	}
 	level.Debug(m.logger).Log("msg", "successfully checked in local node in backend")
 	level.Debug(m.logger).Log("msg", "successfully checked in local node in backend")
@@ -526,6 +533,7 @@ func (m *Mesh) handleLocal(n *Node) {
 		level.Debug(m.logger).Log("msg", "successfully reconciled local node against backend")
 		level.Debug(m.logger).Log("msg", "successfully reconciled local node against backend")
 	}
 	}
 	m.mu.Lock()
 	m.mu.Lock()
+
 	n = m.nodes[m.hostname]
 	n = m.nodes[m.hostname]
 	if n == nil {
 	if n == nil {
 		n = &Node{}
 		n = &Node{}
@@ -543,31 +551,33 @@ func (m *Mesh) applyTopology() {
 	m.reconcileCounter.Inc()
 	m.reconcileCounter.Inc()
 	m.mu.Lock()
 	m.mu.Lock()
 	defer m.mu.Unlock()
 	defer m.mu.Unlock()
-	// Ensure all unready nodes are removed.
+	// Ensure only ready nodes are considered.
+	nodes := make(map[string]*Node)
 	var readyNodes float64
 	var readyNodes float64
 	for k := range m.nodes {
 	for k := range m.nodes {
 		if !m.nodes[k].Ready() {
 		if !m.nodes[k].Ready() {
-			delete(m.nodes, k)
 			continue
 			continue
 		}
 		}
+		nodes[k] = m.nodes[k]
 		readyNodes++
 		readyNodes++
 	}
 	}
-	// Ensure all unready peers are removed.
+	// Ensure only ready nodes are considered.
+	peers := make(map[string]*Peer)
 	var readyPeers float64
 	var readyPeers float64
 	for k := range m.peers {
 	for k := range m.peers {
 		if !m.peers[k].Ready() {
 		if !m.peers[k].Ready() {
-			delete(m.peers, k)
 			continue
 			continue
 		}
 		}
+		peers[k] = m.peers[k]
 		readyPeers++
 		readyPeers++
 	}
 	}
 	m.nodesGuage.Set(readyNodes)
 	m.nodesGuage.Set(readyNodes)
 	m.peersGuage.Set(readyPeers)
 	m.peersGuage.Set(readyPeers)
 	// We cannot do anything with the topology until the local node is available.
 	// We cannot do anything with the topology until the local node is available.
-	if m.nodes[m.hostname] == nil {
+	if nodes[m.hostname] == nil {
 		return
 		return
 	}
 	}
-	t, err := NewTopology(m.nodes, m.peers, m.granularity, m.hostname, m.port, m.priv, m.subnet)
+	t, err := NewTopology(nodes, peers, m.granularity, m.hostname, m.port, m.priv, m.subnet)
 	if err != nil {
 	if err != nil {
 		level.Error(m.logger).Log("error", err)
 		level.Error(m.logger).Log("error", err)
 		m.errorCounter.WithLabelValues("apply").Inc()
 		m.errorCounter.WithLabelValues("apply").Inc()
@@ -586,17 +596,17 @@ func (m *Mesh) applyTopology() {
 	}
 	}
 	rules := iptables.ForwardRules(m.subnet)
 	rules := iptables.ForwardRules(m.subnet)
 	var peerCIDRs []*net.IPNet
 	var peerCIDRs []*net.IPNet
-	for _, p := range m.peers {
+	for _, p := range peers {
 		rules = append(rules, iptables.ForwardRules(p.AllowedIPs...)...)
 		rules = append(rules, iptables.ForwardRules(p.AllowedIPs...)...)
 		peerCIDRs = append(peerCIDRs, p.AllowedIPs...)
 		peerCIDRs = append(peerCIDRs, p.AllowedIPs...)
 	}
 	}
-	rules = append(rules, iptables.MasqueradeRules(m.subnet, oneAddressCIDR(t.privateIP.IP), m.nodes[m.hostname].Subnet, t.RemoteSubnets(), peerCIDRs)...)
+	rules = append(rules, iptables.MasqueradeRules(m.subnet, oneAddressCIDR(t.privateIP.IP), nodes[m.hostname].Subnet, t.RemoteSubnets(), peerCIDRs)...)
 	// If we are handling local routes, ensure the local
 	// If we are handling local routes, ensure the local
 	// tunnel has an IP address and IPIP traffic is allowed.
 	// tunnel has an IP address and IPIP traffic is allowed.
 	if m.encapsulate != NeverEncapsulate && m.local {
 	if m.encapsulate != NeverEncapsulate && m.local {
 		var cidrs []*net.IPNet
 		var cidrs []*net.IPNet
 		for _, s := range t.segments {
 		for _, s := range t.segments {
-			if s.location == m.nodes[m.hostname].Location {
+			if s.location == nodes[m.hostname].Location {
 				for i := range s.privateIPs {
 				for i := range s.privateIPs {
 					cidrs = append(cidrs, oneAddressCIDR(s.privateIPs[i]))
 					cidrs = append(cidrs, oneAddressCIDR(s.privateIPs[i]))
 				}
 				}
@@ -607,7 +617,7 @@ func (m *Mesh) applyTopology() {
 
 
 		// If we are handling local routes, ensure the local
 		// If we are handling local routes, ensure the local
 		// tunnel has an IP address.
 		// tunnel has an IP address.
-		if err := iproute.SetAddress(m.tunlIface, oneAddressCIDR(newAllocator(*m.nodes[m.hostname].Subnet).next().IP)); err != nil {
+		if err := iproute.SetAddress(m.tunlIface, oneAddressCIDR(newAllocator(*nodes[m.hostname].Subnet).next().IP)); err != nil {
 			level.Error(m.logger).Log("error", err)
 			level.Error(m.logger).Log("error", err)
 			m.errorCounter.WithLabelValues("apply").Inc()
 			m.errorCounter.WithLabelValues("apply").Inc()
 			return
 			return
@@ -727,8 +737,10 @@ func nodesAreEqual(a, b *Node) bool {
 	if a == b {
 	if a == b {
 		return true
 		return true
 	}
 	}
-	// Ignore LastSeen when comparing equality.
-	return ipNetsEqual(a.ExternalIP, b.ExternalIP) && string(a.Key) == string(b.Key) && ipNetsEqual(a.InternalIP, b.InternalIP) && a.Leader == b.Leader && a.Location == b.Location && a.Name == b.Name && subnetsEqual(a.Subnet, b.Subnet)
+	// Ignore LastSeen when comparing equality we want to check if the nodes are
+	// equivalent. However, we do want to check if LastSeen has transitioned
+	// between valid and invalid.
+	return ipNetsEqual(a.ExternalIP, b.ExternalIP) && string(a.Key) == string(b.Key) && ipNetsEqual(a.InternalIP, b.InternalIP) && a.Leader == b.Leader && a.Location == b.Location && a.Name == b.Name && subnetsEqual(a.Subnet, b.Subnet) && a.Ready() == b.Ready()
 }
 }
 
 
 func peersAreEqual(a, b *Peer) bool {
 func peersAreEqual(a, b *Peer) bool {