Compare commits

...

19 Commits

Author SHA1 Message Date
pascal
99dc3b0e7c do in-memory meta update 2026-06-18 15:22:15 +02:00
pascal
023fc1023a ignore ssh 2026-06-18 15:16:46 +02:00
pascal
4de804e128 enforce ssh 2026-06-18 15:07:35 +02:00
pascal
0b3568bd78 revert enableSSH overwrite 2026-06-18 14:56:26 +02:00
pascal
bdcef5efbc save capabilities 2026-06-18 14:53:32 +02:00
pascal
bb6ee60d1b test forced ssh enable 2026-06-18 14:33:45 +02:00
pascal
f6f071880d test forced ssh enable 2026-06-18 14:27:10 +02:00
pascal
230ece1b7c update affected peers on sync 2026-06-18 14:09:42 +02:00
pascal
8defb7944a update affected peers on sync 2026-06-18 14:08:48 +02:00
pascal
fb188208ab update affected peers on sync 2026-06-18 14:00:45 +02:00
pascal
12c2f63845 update affected peers on sync 2026-06-18 13:59:29 +02:00
pascal
92ab202af9 remove meta update 2026-06-18 13:49:02 +02:00
pascal
600c27e727 log on info 2026-06-18 13:40:31 +02:00
pascal
0420842de7 log wt version 2026-06-18 12:30:02 +02:00
pascal
df8fb9db8b log meta diff 2026-06-18 12:17:43 +02:00
pascal
6f3619ca11 remove ipv6 2026-06-18 10:19:32 +02:00
pascal
1197857e34 revert meta 2026-06-18 10:10:15 +02:00
pascal
ed8dcf598f revert meta 2026-06-18 00:29:33 +02:00
pascal
ba4e455b1c update on version chnaged 2026-06-18 00:19:33 +02:00
2 changed files with 125 additions and 63 deletions

View File

@@ -982,7 +982,6 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
var peer *nbpeer.Peer
var updated, versionChanged, ipv6CapabilityChanged bool
var err error
var postureChecks []*posture.Checks
var peerGroupIDs []string
settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthNone, accountID)
@@ -1025,11 +1024,6 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
if err = transaction.SavePeer(ctx, accountID, peer); err != nil {
return err
}
postureChecks, err = getPeerPostureChecks(ctx, transaction, accountID, peer.ID)
if err != nil {
return err
}
}
return nil
})
@@ -1047,9 +1041,10 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
return nil, nil, nil, 0, err
}
if isStatusChanged || sync.UpdateAccountPeers || ipv6CapabilityChanged || (updated && (len(postureChecks) > 0 || versionChanged)) {
if isStatusChanged || sync.UpdateAccountPeers || ipv6CapabilityChanged || updated || versionChanged {
changedPeerIDs := []string{peer.ID}
affectedPeerIDs := am.syncPeerAffectedPeers(ctx, accountID, peer.ID, nmap, peerNotValid, updated, len(postureChecks) > 0)
affectedPeerIDs := am.syncPeerAffectedPeers(ctx, accountID, peer.ID, nmap, peerNotValid, updated)
log.Infof("Sync: peer %s affected peers %s", peer.ID, affectedPeerIDs)
if err = am.networkMapController.OnPeersUpdated(ctx, accountID, changedPeerIDs, affectedPeerIDs); err != nil {
return nil, nil, nil, 0, fmt.Errorf("notify network map controller of peer update: %w", err)
}
@@ -1066,8 +1061,8 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
// metadata change that flips a posture result removes this peer from others'
// maps asymmetrically; that case (and an invalid peer, whose map is empty) falls
// back to the resolver.
func (am *DefaultAccountManager) syncPeerAffectedPeers(ctx context.Context, accountID, peerID string, nmap *types.NetworkMap, peerNotValid, metaUpdated, hasPostureChecks bool) []string {
if peerNotValid || (metaUpdated && hasPostureChecks) {
func (am *DefaultAccountManager) syncPeerAffectedPeers(ctx context.Context, accountID, peerID string, nmap *types.NetworkMap, peerNotValid, metaUpdated bool) []string {
if peerNotValid || metaUpdated {
return am.resolveAffectedPeersForPeerChanges(ctx, am.Store, accountID, []string{peerID})
}
return affectedPeerIDsFromNetworkMap(nmap, peerID)
@@ -1174,6 +1169,8 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login types.Peer
}
}
peer.UpdateMetaIfNew(login.Meta)
return nil
})
if err != nil {
@@ -1190,6 +1187,10 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login types.Peer
return nil, nil, nil, false, err
}
changedPeerIDs := []string{peer.ID}
affectedPeerIDs := am.resolveAffectedPeersForPeerChanges(ctx, am.Store, accountID, changedPeerIDs)
log.Infof("Login: peer %s affected peers %s", peer.ID, affectedPeerIDs)
if isStatusChanged || shouldStorePeer {
changedPeerIDs := []string{peer.ID}
affectedPeerIDs := am.resolveAffectedPeersForPeerChanges(ctx, am.Store, accountID, changedPeerIDs)
@@ -1291,12 +1292,12 @@ func getPeerLoginInfo(ctx context.Context, transaction store.Store, accountID st
return nil, nil, false, err
}
enableSSH, err := isPeerSSHEnabled(ctx, transaction, accountID, peer)
_, err = isPeerSSHEnabled(ctx, transaction, accountID, peer)
if err != nil {
return nil, nil, false, err
}
return network, postureChecks, enableSSH, nil
return network, postureChecks, true, nil
}
func isPeerSSHEnabled(ctx context.Context, transaction store.Store, accountID string, peer *nbpeer.Peer) (bool, error) {

View File

@@ -1,12 +1,16 @@
package peer
import (
"fmt"
"net"
"net/netip"
"slices"
"sort"
"strings"
"time"
log "github.com/sirupsen/logrus"
"github.com/netbirdio/netbird/management/server/util"
"github.com/netbirdio/netbird/shared/management/http/api"
)
@@ -162,49 +166,7 @@ type PeerSystemMeta struct { //nolint:revive
}
func (p PeerSystemMeta) isEqual(other PeerSystemMeta) bool {
sort.Slice(p.NetworkAddresses, func(i, j int) bool {
return p.NetworkAddresses[i].Mac < p.NetworkAddresses[j].Mac
})
sort.Slice(other.NetworkAddresses, func(i, j int) bool {
return other.NetworkAddresses[i].Mac < other.NetworkAddresses[j].Mac
})
equalNetworkAddresses := slices.EqualFunc(p.NetworkAddresses, other.NetworkAddresses, func(addr NetworkAddress, oAddr NetworkAddress) bool {
return addr.Mac == oAddr.Mac && addr.NetIP == oAddr.NetIP
})
if !equalNetworkAddresses {
return false
}
sort.Slice(p.Files, func(i, j int) bool {
return p.Files[i].Path < p.Files[j].Path
})
sort.Slice(other.Files, func(i, j int) bool {
return other.Files[i].Path < other.Files[j].Path
})
equalFiles := slices.EqualFunc(p.Files, other.Files, func(file File, oFile File) bool {
return file.Path == oFile.Path && file.Exist == oFile.Exist && file.ProcessIsRunning == oFile.ProcessIsRunning
})
if !equalFiles {
return false
}
return p.Hostname == other.Hostname &&
p.GoOS == other.GoOS &&
p.Kernel == other.Kernel &&
p.KernelVersion == other.KernelVersion &&
p.Core == other.Core &&
p.Platform == other.Platform &&
p.OS == other.OS &&
p.OSVersion == other.OSVersion &&
p.WtVersion == other.WtVersion &&
p.UIVersion == other.UIVersion &&
p.SystemSerialNumber == other.SystemSerialNumber &&
p.SystemProductName == other.SystemProductName &&
p.SystemManufacturer == other.SystemManufacturer &&
p.Environment.Cloud == other.Environment.Cloud &&
p.Environment.Platform == other.Environment.Platform &&
p.Flags.isEqual(other.Flags) &&
capabilitiesEqual(p.Capabilities, other.Capabilities)
return len(metaDiff(p, other)) == 0
}
func (p PeerSystemMeta) isEmpty() bool {
@@ -247,12 +209,12 @@ func (p *Peer) SupportsSourcePrefixes() bool {
return p.HasCapability(PeerCapabilitySourcePrefixes)
}
func capabilitiesEqual(a, b []int32) bool {
if len(a) != len(b) {
func (a PeerSystemMeta) CapabilitiesEqual(b []int32) bool {
if len(a.Capabilities) != len(b) {
return false
}
set := make(map[int32]struct{}, len(a))
for _, c := range a {
set := make(map[int32]struct{}, len(a.Capabilities))
for _, c := range a.Capabilities {
set[c] = struct{}{}
}
for _, c := range b {
@@ -308,14 +270,113 @@ func (p *Peer) UpdateMetaIfNew(meta PeerSystemMeta) (updated, versionChanged boo
meta.UIVersion = p.Meta.UIVersion
}
if p.Meta.isEqual(meta) {
return updated, versionChanged
oldVersion := p.Meta.WtVersion
diff := metaDiff(p.Meta, meta)
if len(diff) != 0 {
p.Meta = meta
updated = true
}
p.Meta = meta
updated = true
versionInfo := ""
if versionChanged {
versionInfo = fmt.Sprintf("version changed: %s -> %s, ", oldVersion, meta.WtVersion)
}
if versionChanged || updated {
log.WithFields(log.Fields{"peer": p.ID, "key": p.Key}).
Infof("peer meta updated, %s%d field(s) changed: %s", versionInfo, len(diff), strings.Join(diff, ", "))
}
return updated, versionChanged
}
// metaDiff returns a human-readable list of the fields that differ between the
// old and new meta, each formatted as `field: <old> -> <new>`. It is the single
// source of truth for meta comparison: isEqual reports equality as an empty
// diff, so the log line can never disagree with the change decision. Slices are
// cloned before sorting, so callers' meta is not mutated.
func metaDiff(old, new PeerSystemMeta) []string {
var diff []string
add := func(field string, oldVal, newVal any) {
diff = append(diff, fmt.Sprintf("%s: %v -> %v", field, oldVal, newVal))
}
if old.Hostname != new.Hostname {
add("hostname", old.Hostname, new.Hostname)
}
if old.GoOS != new.GoOS {
add("goos", old.GoOS, new.GoOS)
}
if old.Kernel != new.Kernel {
add("kernel", old.Kernel, new.Kernel)
}
if old.KernelVersion != new.KernelVersion {
add("kernel_version", old.KernelVersion, new.KernelVersion)
}
if old.Core != new.Core {
add("core", old.Core, new.Core)
}
if old.Platform != new.Platform {
add("platform", old.Platform, new.Platform)
}
if old.OS != new.OS {
add("os", old.OS, new.OS)
}
if old.OSVersion != new.OSVersion {
add("os_version", old.OSVersion, new.OSVersion)
}
if old.WtVersion != new.WtVersion {
add("wt_version", old.WtVersion, new.WtVersion)
}
if old.UIVersion != new.UIVersion {
add("ui_version", old.UIVersion, new.UIVersion)
}
if old.SystemSerialNumber != new.SystemSerialNumber {
add("system_serial_number", old.SystemSerialNumber, new.SystemSerialNumber)
}
if old.SystemProductName != new.SystemProductName {
add("system_product_name", old.SystemProductName, new.SystemProductName)
}
if old.SystemManufacturer != new.SystemManufacturer {
add("system_manufacturer", old.SystemManufacturer, new.SystemManufacturer)
}
if old.Environment.Cloud != new.Environment.Cloud {
add("environment_cloud", old.Environment.Cloud, new.Environment.Cloud)
}
if old.Environment.Platform != new.Environment.Platform {
add("environment_platform", old.Environment.Platform, new.Environment.Platform)
}
if !old.Flags.isEqual(new.Flags) {
add("flags", fmt.Sprintf("%+v", old.Flags), fmt.Sprintf("%+v", new.Flags))
}
if !old.CapabilitiesEqual(new.Capabilities) {
add("capabilities", old.Capabilities, new.Capabilities)
}
oldAddrs := slices.Clone(old.NetworkAddresses)
newAddrs := slices.Clone(new.NetworkAddresses)
sort.Slice(oldAddrs, func(i, j int) bool { return oldAddrs[i].Mac < oldAddrs[j].Mac })
sort.Slice(newAddrs, func(i, j int) bool { return newAddrs[i].Mac < newAddrs[j].Mac })
if !slices.EqualFunc(oldAddrs, newAddrs, func(a, b NetworkAddress) bool {
return a.Mac == b.Mac && a.NetIP == b.NetIP
}) {
add("network_addresses", fmt.Sprintf("%v", oldAddrs), fmt.Sprintf("%v", newAddrs))
}
oldFiles := slices.Clone(old.Files)
newFiles := slices.Clone(new.Files)
sort.Slice(oldFiles, func(i, j int) bool { return oldFiles[i].Path < oldFiles[j].Path })
sort.Slice(newFiles, func(i, j int) bool { return newFiles[i].Path < newFiles[j].Path })
if !slices.EqualFunc(oldFiles, newFiles, func(a, b File) bool {
return a.Path == b.Path && a.Exist == b.Exist && a.ProcessIsRunning == b.ProcessIsRunning
}) {
add("files", fmt.Sprintf("%v", oldFiles), fmt.Sprintf("%v", newFiles))
}
return diff
}
// GetLastLogin returns the last login time of the peer.
func (p *Peer) GetLastLogin() time.Time {
if p.LastLogin != nil {