mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-20 20:39:08 +02:00
[management] Optimize affected posture checks and add logs (#6522)
This commit is contained in:
@@ -497,7 +497,7 @@ func (c *Controller) BufferUpdateAffectedPeers(ctx context.Context, accountID st
|
|||||||
c.accountManagerMetrics.CountUpdateAccountPeersTriggered(string(reason.Resource), string(reason.Operation))
|
c.accountManagerMetrics.CountUpdateAccountPeersTriggered(string(reason.Resource), string(reason.Operation))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithContext(ctx).Tracef("buffer updating %d affected peers for account %s from %s", len(peerIDs), accountID, util.GetCallerName())
|
log.WithContext(ctx).Tracef("buffer updating %d affected peers for account %s from %s with reason %s/%s", len(peerIDs), accountID, util.GetCallerName(), reason.Operation, reason.Resource)
|
||||||
|
|
||||||
bufUpd, _ := c.affectedPeerUpdateLocks.LoadOrStore(accountID, &bufferAffectedUpdate{
|
bufUpd, _ := c.affectedPeerUpdateLocks.LoadOrStore(accountID, &bufferAffectedUpdate{
|
||||||
peerIDs: make(map[string]struct{}),
|
peerIDs: make(map[string]struct{}),
|
||||||
|
|||||||
@@ -209,14 +209,14 @@ func (am *DefaultAccountManager) resolvePeerLocation(ctx context.Context, peer *
|
|||||||
if am.geo == nil || realIP == nil {
|
if am.geo == nil || realIP == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if peer.Location.ConnectionIP != nil && peer.Location.ConnectionIP.Equal(realIP) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
location, err := am.geo.Lookup(realIP)
|
location, err := am.geo.Lookup(realIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithContext(ctx).Warnf("failed to get location for peer %s realip: [%s]: %v", peer.ID, realIP.String(), err)
|
log.WithContext(ctx).Warnf("failed to get location for peer %s realip: [%s]: %v", peer.ID, realIP.String(), err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if peer.Location.ConnectionIP != nil && peer.Location.ConnectionIP.Equal(realIP) && peer.Location.GeoNameID == location.City.GeonameID {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return &nbpeer.Location{
|
return &nbpeer.Location{
|
||||||
ConnectionIP: realIP,
|
ConnectionIP: realIP,
|
||||||
CountryCode: location.Country.ISOCode,
|
CountryCode: location.Country.ISOCode,
|
||||||
@@ -1052,7 +1052,7 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
|
|||||||
}
|
}
|
||||||
|
|
||||||
metaDiffAffectsPosture := posture.AffectsPosture(ctx, &metaDiff, resPostureChecks)
|
metaDiffAffectsPosture := posture.AffectsPosture(ctx, &metaDiff, resPostureChecks)
|
||||||
if isStatusChanged || sync.UpdateAccountPeers || ipv6CapabilityChanged || metaDiffAffectsPosture || metaDiff.VersionChanged() || metaDiff.HostnameChanged() {
|
if requiresPeerUpdate(ctx, isStatusChanged, sync.UpdateAccountPeers, ipv6CapabilityChanged, metaDiffAffectsPosture, metaDiff.VersionChanged(), metaDiff.HostnameChanged()) {
|
||||||
changedPeerIDs := []string{peer.ID}
|
changedPeerIDs := []string{peer.ID}
|
||||||
affectedPeerIDs := am.syncPeerAffectedPeers(ctx, accountID, peer.ID, nmap, peerNotValid, metaDiffAffectsPosture)
|
affectedPeerIDs := am.syncPeerAffectedPeers(ctx, accountID, peer.ID, nmap, peerNotValid, metaDiffAffectsPosture)
|
||||||
if err = am.networkMapController.OnPeersUpdated(ctx, accountID, changedPeerIDs, affectedPeerIDs); err != nil {
|
if err = am.networkMapController.OnPeersUpdated(ctx, accountID, changedPeerIDs, affectedPeerIDs); err != nil {
|
||||||
@@ -1063,6 +1063,29 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
|
|||||||
return peer, nmap, resPostureChecks, dnsFwdPort, nil
|
return peer, nmap, resPostureChecks, dnsFwdPort, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requiresPeerUpdate(ctx context.Context, isStatusChanged, updateAccountPeers, ipv6CapabilityChanged, metaDiffAffectsPosture, versionChanged, hostname bool) bool {
|
||||||
|
var reason string
|
||||||
|
switch {
|
||||||
|
case isStatusChanged:
|
||||||
|
reason = "status changed"
|
||||||
|
case updateAccountPeers:
|
||||||
|
reason = "update account peers"
|
||||||
|
case ipv6CapabilityChanged:
|
||||||
|
reason = "ipv6 capability changed"
|
||||||
|
case metaDiffAffectsPosture:
|
||||||
|
reason = "meta diff affects posture"
|
||||||
|
case versionChanged:
|
||||||
|
reason = "version changed"
|
||||||
|
case hostname:
|
||||||
|
reason = "hostname changed"
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithContext(ctx).Tracef("peer update required: %s", reason)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// syncPeerAffectedPeers resolves the peers affected by a SyncPeer change. The
|
// syncPeerAffectedPeers resolves the peers affected by a SyncPeer change. The
|
||||||
// peer's own validated network map is bidirectional for policy and routing
|
// peer's own validated network map is bidirectional for policy and routing
|
||||||
// reachability, so when the peer stays valid and no source-posture gate is in
|
// reachability, so when the peer stays valid and no source-posture gate is in
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import (
|
|||||||
|
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
|
"github.com/netbirdio/netbird/management/server/geolocation"
|
||||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||||
"github.com/netbirdio/netbird/management/server/posture"
|
"github.com/netbirdio/netbird/management/server/posture"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
@@ -2893,3 +2894,141 @@ func TestUpdatePeer_DnsLabelUniqueName(t *testing.T) {
|
|||||||
require.NoError(t, err, "renaming to unique FQDN should succeed")
|
require.NoError(t, err, "renaming to unique FQDN should succeed")
|
||||||
assert.Equal(t, "api-server", updated.DNSLabel, "DNS label should be first label of FQDN")
|
assert.Equal(t, "api-server", updated.DNSLabel, "DNS label should be first label of FQDN")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fakeGeo is a configurable geolocation.Geolocation implementation for tests. It
|
||||||
|
// returns a record built from the configured city geoname id, or an error when set.
|
||||||
|
type fakeGeo struct {
|
||||||
|
geoNameID uint
|
||||||
|
isoCode string
|
||||||
|
cityName string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *fakeGeo) Lookup(net.IP) (*geolocation.Record, error) {
|
||||||
|
if g.err != nil {
|
||||||
|
return nil, g.err
|
||||||
|
}
|
||||||
|
record := &geolocation.Record{}
|
||||||
|
record.City.GeonameID = g.geoNameID
|
||||||
|
record.City.Names.En = g.cityName
|
||||||
|
record.Country.ISOCode = g.isoCode
|
||||||
|
return record, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *fakeGeo) GetAllCountries() ([]geolocation.Country, error) { return nil, nil }
|
||||||
|
|
||||||
|
func (g *fakeGeo) GetCitiesByCountry(string) ([]geolocation.City, error) { return nil, nil }
|
||||||
|
|
||||||
|
func (g *fakeGeo) Stop() error { return nil }
|
||||||
|
|
||||||
|
func TestResolvePeerLocation(t *testing.T) {
|
||||||
|
realIP := net.ParseIP("203.0.113.10")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
geo geolocation.Geolocation
|
||||||
|
peer *nbpeer.Peer
|
||||||
|
realIP net.IP
|
||||||
|
want *nbpeer.Location
|
||||||
|
wantNil bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no geo configured returns nil",
|
||||||
|
geo: nil,
|
||||||
|
peer: &nbpeer.Peer{ID: "p1"},
|
||||||
|
realIP: realIP,
|
||||||
|
wantNil: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nil real IP returns nil",
|
||||||
|
geo: &fakeGeo{geoNameID: 100},
|
||||||
|
peer: &nbpeer.Peer{ID: "p1"},
|
||||||
|
realIP: nil,
|
||||||
|
wantNil: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lookup error returns nil",
|
||||||
|
geo: &fakeGeo{err: fmt.Errorf("lookup boom")},
|
||||||
|
peer: &nbpeer.Peer{ID: "p1"},
|
||||||
|
realIP: realIP,
|
||||||
|
wantNil: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "same IP and same geoname returns nil",
|
||||||
|
geo: &fakeGeo{geoNameID: 100, isoCode: "US", cityName: "City A"},
|
||||||
|
peer: &nbpeer.Peer{
|
||||||
|
ID: "p1",
|
||||||
|
Location: nbpeer.Location{
|
||||||
|
ConnectionIP: realIP,
|
||||||
|
GeoNameID: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
realIP: realIP,
|
||||||
|
wantNil: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "same IP but changed geoname returns location",
|
||||||
|
geo: &fakeGeo{geoNameID: 200, isoCode: "US", cityName: "City B"},
|
||||||
|
peer: &nbpeer.Peer{
|
||||||
|
ID: "p1",
|
||||||
|
Location: nbpeer.Location{
|
||||||
|
ConnectionIP: realIP,
|
||||||
|
GeoNameID: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
realIP: realIP,
|
||||||
|
want: &nbpeer.Location{
|
||||||
|
ConnectionIP: realIP,
|
||||||
|
CountryCode: "US",
|
||||||
|
CityName: "City B",
|
||||||
|
GeoNameID: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "different IP returns location",
|
||||||
|
geo: &fakeGeo{geoNameID: 100, isoCode: "US", cityName: "City A"},
|
||||||
|
peer: &nbpeer.Peer{
|
||||||
|
ID: "p1",
|
||||||
|
Location: nbpeer.Location{
|
||||||
|
ConnectionIP: net.ParseIP("198.51.100.7"),
|
||||||
|
GeoNameID: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
realIP: realIP,
|
||||||
|
want: &nbpeer.Location{
|
||||||
|
ConnectionIP: realIP,
|
||||||
|
CountryCode: "US",
|
||||||
|
CityName: "City A",
|
||||||
|
GeoNameID: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no prior location returns location",
|
||||||
|
geo: &fakeGeo{geoNameID: 100, isoCode: "US", cityName: "City A"},
|
||||||
|
peer: &nbpeer.Peer{ID: "p1"},
|
||||||
|
realIP: realIP,
|
||||||
|
want: &nbpeer.Location{
|
||||||
|
ConnectionIP: realIP,
|
||||||
|
CountryCode: "US",
|
||||||
|
CityName: "City A",
|
||||||
|
GeoNameID: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
am := &DefaultAccountManager{geo: tt.geo}
|
||||||
|
got := am.resolvePeerLocation(context.Background(), tt.peer, tt.realIP)
|
||||||
|
if tt.wantNil {
|
||||||
|
assert.Nil(t, got, "resolved location should be nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NotNil(t, got, "resolved location should not be nil")
|
||||||
|
assert.True(t, tt.want.ConnectionIP.Equal(got.ConnectionIP), "connection IP should match")
|
||||||
|
assert.Equal(t, tt.want.CountryCode, got.CountryCode, "country code should match")
|
||||||
|
assert.Equal(t, tt.want.CityName, got.CityName, "city name should match")
|
||||||
|
assert.Equal(t, tt.want.GeoNameID, got.GeoNameID, "geoname id should match")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user