ensure online status and route changes are propagated (#1564)
This commit is contained in:
parent
0153e26392
commit
f65f4eca35
40 changed files with 3170 additions and 857 deletions
|
@ -61,11 +61,6 @@ func (hsdb *HSDatabase) listPeers(node *types.Node) (types.Nodes, error) {
|
|||
|
||||
sort.Slice(nodes, func(i, j int) bool { return nodes[i].ID < nodes[j].ID })
|
||||
|
||||
log.Trace().
|
||||
Caller().
|
||||
Str("node", node.Hostname).
|
||||
Msgf("Found peers: %s", nodes.String())
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
|
@ -176,6 +171,12 @@ func (hsdb *HSDatabase) GetNodeByMachineKey(
|
|||
hsdb.mu.RLock()
|
||||
defer hsdb.mu.RUnlock()
|
||||
|
||||
return hsdb.getNodeByMachineKey(machineKey)
|
||||
}
|
||||
|
||||
func (hsdb *HSDatabase) getNodeByMachineKey(
|
||||
machineKey key.MachinePublic,
|
||||
) (*types.Node, error) {
|
||||
mach := types.Node{}
|
||||
if result := hsdb.db.
|
||||
Preload("AuthKey").
|
||||
|
@ -252,6 +253,10 @@ func (hsdb *HSDatabase) SetTags(
|
|||
hsdb.mu.Lock()
|
||||
defer hsdb.mu.Unlock()
|
||||
|
||||
if len(tags) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
newTags := []string{}
|
||||
for _, tag := range tags {
|
||||
if !util.StringOrPrefixListContains(newTags, tag) {
|
||||
|
@ -265,10 +270,14 @@ func (hsdb *HSDatabase) SetTags(
|
|||
return fmt.Errorf("failed to update tags for node in the database: %w", err)
|
||||
}
|
||||
|
||||
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
||||
Type: types.StatePeerChanged,
|
||||
Changed: types.Nodes{node},
|
||||
}, node.MachineKey.String())
|
||||
stateUpdate := types.StateUpdate{
|
||||
Type: types.StatePeerChanged,
|
||||
ChangeNodes: types.Nodes{node},
|
||||
Message: "called from db.SetTags",
|
||||
}
|
||||
if stateUpdate.Valid() {
|
||||
hsdb.notifier.NotifyWithIgnore(stateUpdate, node.MachineKey.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -301,10 +310,14 @@ func (hsdb *HSDatabase) RenameNode(node *types.Node, newName string) error {
|
|||
return fmt.Errorf("failed to rename node in the database: %w", err)
|
||||
}
|
||||
|
||||
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
||||
Type: types.StatePeerChanged,
|
||||
Changed: types.Nodes{node},
|
||||
}, node.MachineKey.String())
|
||||
stateUpdate := types.StateUpdate{
|
||||
Type: types.StatePeerChanged,
|
||||
ChangeNodes: types.Nodes{node},
|
||||
Message: "called from db.RenameNode",
|
||||
}
|
||||
if stateUpdate.Valid() {
|
||||
hsdb.notifier.NotifyWithIgnore(stateUpdate, node.MachineKey.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -327,10 +340,18 @@ func (hsdb *HSDatabase) nodeSetExpiry(node *types.Node, expiry time.Time) error
|
|||
)
|
||||
}
|
||||
|
||||
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
||||
Type: types.StatePeerChanged,
|
||||
Changed: types.Nodes{node},
|
||||
}, node.MachineKey.String())
|
||||
stateUpdate := types.StateUpdate{
|
||||
Type: types.StatePeerChangedPatch,
|
||||
ChangePatches: []*tailcfg.PeerChange{
|
||||
{
|
||||
NodeID: tailcfg.NodeID(node.ID),
|
||||
KeyExpiry: &expiry,
|
||||
},
|
||||
},
|
||||
}
|
||||
if stateUpdate.Valid() {
|
||||
hsdb.notifier.NotifyAll(stateUpdate)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -354,10 +375,13 @@ func (hsdb *HSDatabase) deleteNode(node *types.Node) error {
|
|||
return err
|
||||
}
|
||||
|
||||
hsdb.notifier.NotifyAll(types.StateUpdate{
|
||||
stateUpdate := types.StateUpdate{
|
||||
Type: types.StatePeerRemoved,
|
||||
Removed: []tailcfg.NodeID{tailcfg.NodeID(node.ID)},
|
||||
})
|
||||
}
|
||||
if stateUpdate.Valid() {
|
||||
hsdb.notifier.NotifyAll(stateUpdate)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -629,20 +653,6 @@ func (hsdb *HSDatabase) IsRoutesEnabled(node *types.Node, routeStr string) bool
|
|||
return false
|
||||
}
|
||||
|
||||
func (hsdb *HSDatabase) ListOnlineNodes(
|
||||
node *types.Node,
|
||||
) (map[tailcfg.NodeID]bool, error) {
|
||||
hsdb.mu.RLock()
|
||||
defer hsdb.mu.RUnlock()
|
||||
|
||||
peers, err := hsdb.listPeers(node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return peers.OnlineNodeMap(), nil
|
||||
}
|
||||
|
||||
// enableRoutes enables new routes based on a list of new routes.
|
||||
func (hsdb *HSDatabase) enableRoutes(node *types.Node, routeStrs ...string) error {
|
||||
newRoutes := make([]netip.Prefix, len(routeStrs))
|
||||
|
@ -694,10 +704,30 @@ func (hsdb *HSDatabase) enableRoutes(node *types.Node, routeStrs ...string) erro
|
|||
}
|
||||
}
|
||||
|
||||
hsdb.notifier.NotifyWithIgnore(types.StateUpdate{
|
||||
Type: types.StatePeerChanged,
|
||||
Changed: types.Nodes{node},
|
||||
}, node.MachineKey.String())
|
||||
// Ensure the node has the latest routes when notifying the other
|
||||
// nodes
|
||||
nRoutes, err := hsdb.getNodeRoutes(node)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read back routes: %w", err)
|
||||
}
|
||||
|
||||
node.Routes = nRoutes
|
||||
|
||||
log.Trace().
|
||||
Caller().
|
||||
Str("node", node.Hostname).
|
||||
Strs("routes", routeStrs).
|
||||
Msg("enabling routes")
|
||||
|
||||
stateUpdate := types.StateUpdate{
|
||||
Type: types.StatePeerChanged,
|
||||
ChangeNodes: types.Nodes{node},
|
||||
Message: "called from db.enableRoutes",
|
||||
}
|
||||
if stateUpdate.Valid() {
|
||||
hsdb.notifier.NotifyWithIgnore(
|
||||
stateUpdate, node.MachineKey.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -728,7 +758,10 @@ func generateGivenName(suppliedName string, randomSuffix bool) (string, error) {
|
|||
return normalizedHostname, nil
|
||||
}
|
||||
|
||||
func (hsdb *HSDatabase) GenerateGivenName(mkey key.MachinePublic, suppliedName string) (string, error) {
|
||||
func (hsdb *HSDatabase) GenerateGivenName(
|
||||
mkey key.MachinePublic,
|
||||
suppliedName string,
|
||||
) (string, error) {
|
||||
hsdb.mu.RLock()
|
||||
defer hsdb.mu.RUnlock()
|
||||
|
||||
|
@ -823,53 +856,54 @@ func (hsdb *HSDatabase) ExpireExpiredNodes(lastCheck time.Time) time.Time {
|
|||
// checked everything.
|
||||
started := time.Now()
|
||||
|
||||
users, err := hsdb.listUsers()
|
||||
expired := make([]*tailcfg.PeerChange, 0)
|
||||
|
||||
nodes, err := hsdb.listNodes()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error listing users")
|
||||
log.Error().
|
||||
Err(err).
|
||||
Msg("Error listing nodes to find expired nodes")
|
||||
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
for index, node := range nodes {
|
||||
if node.IsExpired() &&
|
||||
// TODO(kradalby): Replace this, it is very spammy
|
||||
// It will notify about all nodes that has been expired.
|
||||
// It should only notify about expired nodes since _last check_.
|
||||
node.Expiry.After(lastCheck) {
|
||||
expired = append(expired, &tailcfg.PeerChange{
|
||||
NodeID: tailcfg.NodeID(node.ID),
|
||||
KeyExpiry: node.Expiry,
|
||||
})
|
||||
|
||||
for _, user := range users {
|
||||
nodes, err := hsdb.listNodesByUser(user.Name)
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("user", user.Name).
|
||||
Msg("Error listing nodes in user")
|
||||
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
|
||||
expired := make([]tailcfg.NodeID, 0)
|
||||
for index, node := range nodes {
|
||||
if node.IsExpired() &&
|
||||
node.Expiry.After(lastCheck) {
|
||||
expired = append(expired, tailcfg.NodeID(node.ID))
|
||||
|
||||
now := time.Now()
|
||||
err := hsdb.nodeSetExpiry(nodes[index], now)
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("node", node.Hostname).
|
||||
Str("name", node.GivenName).
|
||||
Msg("🤮 Cannot expire node")
|
||||
} else {
|
||||
log.Info().
|
||||
Str("node", node.Hostname).
|
||||
Str("name", node.GivenName).
|
||||
Msg("Node successfully expired")
|
||||
}
|
||||
now := time.Now()
|
||||
// Do not use setNodeExpiry as that has a notifier hook, which
|
||||
// can cause a deadlock, we are updating all changed nodes later
|
||||
// and there is no point in notifiying twice.
|
||||
if err := hsdb.db.Model(nodes[index]).Updates(types.Node{
|
||||
Expiry: &now,
|
||||
}).Error; err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("node", node.Hostname).
|
||||
Str("name", node.GivenName).
|
||||
Msg("🤮 Cannot expire node")
|
||||
} else {
|
||||
log.Info().
|
||||
Str("node", node.Hostname).
|
||||
Str("name", node.GivenName).
|
||||
Msg("Node successfully expired")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(expired) > 0 {
|
||||
hsdb.notifier.NotifyAll(types.StateUpdate{
|
||||
Type: types.StatePeerRemoved,
|
||||
Removed: expired,
|
||||
})
|
||||
}
|
||||
stateUpdate := types.StateUpdate{
|
||||
Type: types.StatePeerChangedPatch,
|
||||
ChangePatches: expired,
|
||||
}
|
||||
if stateUpdate.Valid() {
|
||||
hsdb.notifier.NotifyAll(stateUpdate)
|
||||
}
|
||||
|
||||
return started
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue