[management] expire and disconnect peers while including offline peers (#7467)

This commit is contained in:
Pascal Fischer
2026-09-09 13:44:19 +02:00
committed by GitHub
parent d101f6cc46
commit 269cbadfeb
7 changed files with 350 additions and 32 deletions
+61 -16
View File
@@ -1177,28 +1177,35 @@ func (am *DefaultAccountManager) expireAndUpdatePeers(ctx context.Context, accou
dnsDomain := am.networkMapController.GetDNSDomain(settings)
var peerIDs []string
for _, peer := range peers {
defer func() {
if len(peerIDs) == 0 {
return
}
// this will trigger peer disconnect from the management service
log.Debugf("Expiring %d peers for account %s", len(peerIDs), accountID)
am.networkMapController.DisconnectPeers(ctx, accountID, peerIDs)
}()
for _, candidate := range peers {
// nolint:staticcheck
ctx = context.WithValue(ctx, nbcontext.PeerIDKey, peer.Key)
peerCtx := context.WithValue(ctx, nbcontext.PeerIDKey, candidate.Key)
if peer.UserID == "" {
if candidate.UserID == "" {
// we do not want to expire peers that are added via setup key
continue
}
if peer.Status.LoginExpired {
peer, err := am.expirePeerIfStillDue(peerCtx, accountID, candidate.ID, settings, reason)
if err != nil {
return err
}
if peer == nil {
continue
}
peerIDs = append(peerIDs, peer.ID)
peer.MarkLoginExpired(true)
if err := am.Store.SavePeerStatus(ctx, accountID, peer.ID, *peer.Status); err != nil {
return err
}
meta := peer.EventMeta(dnsDomain)
meta["reason"] = string(reason)
am.StoreEvent(
ctx,
peerCtx,
peer.UserID, peer.ID, accountID,
activity.PeerLoginExpired, meta,
)
@@ -1215,15 +1222,53 @@ func (am *DefaultAccountManager) expireAndUpdatePeers(ctx context.Context, accou
if err != nil {
return fmt.Errorf("notify network map controller of peer update: %w", err)
}
if len(peerIDs) != 0 {
// this will trigger peer disconnect from the management service
log.Debugf("Expiring %d peers for account %s", len(peerIDs), accountID)
am.networkMapController.DisconnectPeers(ctx, accountID, peerIDs)
}
return nil
}
// expirePeerIfStillDue flags the peer as login-expired and returns its fresh copy, or nil
// when it no longer qualifies. The candidate list is read without a lock, so a login that
// landed in between would otherwise be overwritten with a stale expired status.
func (am *DefaultAccountManager) expirePeerIfStillDue(ctx context.Context, accountID, peerID string, settings *types.Settings, reason peerExpirationReason) (*nbpeer.Peer, error) {
var expired *nbpeer.Peer
err := am.Store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
peer, err := transaction.GetPeerByID(ctx, store.LockingStrengthUpdate, accountID, peerID)
if err != nil {
if s, ok := status.FromError(err); ok && s.Type() == status.NotFound {
return nil
}
return err
}
if peer.Status.LoginExpired || !peerExpirationDue(peer, settings, reason) {
return nil
}
peer.MarkLoginExpired(true)
if err := transaction.SavePeerStatus(ctx, accountID, peer.ID, *peer.Status); err != nil {
return err
}
expired = peer
return nil
})
if err != nil {
return nil, err
}
return expired, nil
}
// peerExpirationDue re-evaluates a time-based expiry against the peer's current state.
// Administrative reasons expire the peer unconditionally.
func peerExpirationDue(peer *nbpeer.Peer, settings *types.Settings, reason peerExpirationReason) bool {
switch reason {
case peerExpirationSessionExpired:
expired, _ := peer.LoginExpired(settings.PeerLoginExpiration)
return settings.PeerLoginExpirationEnabled && expired
case peerExpirationInactivity:
expired, _ := peer.SessionExpired(settings.PeerInactivityExpiration)
return settings.PeerInactivityExpirationEnabled && expired
default:
return true
}
}
func (am *DefaultAccountManager) deleteUserFromIDP(ctx context.Context, targetUserID, accountID string) error {
if am.userDeleteFromIDPEnabled {
log.WithContext(ctx).Debugf("user %s deleted from IdP", targetUserID)