mirror of
https://github.com/netbirdio/netbird.git
synced 2026-03-31 06:34:19 -04:00
Compare commits
6 Commits
poc-token-
...
evaluate/n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4bed26e416 | ||
|
|
67cc8bd655 | ||
|
|
42be72a86c | ||
|
|
16387a823a | ||
|
|
b4dddc8d0f | ||
|
|
7a0dc10ccc |
1
go.mod
1
go.mod
@@ -67,6 +67,7 @@ require (
|
||||
github.com/pion/transport/v3 v3.0.1
|
||||
github.com/pion/turn/v3 v3.0.1
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/r3labs/diff v1.1.0
|
||||
github.com/rs/xid v1.3.0
|
||||
github.com/shirou/gopsutil/v3 v3.24.4
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
||||
|
||||
2
go.sum
2
go.sum
@@ -415,6 +415,8 @@ github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+a
|
||||
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
|
||||
github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek=
|
||||
github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk=
|
||||
github.com/r3labs/diff v1.1.0 h1:V53xhrbTHrWFWq3gI4b94AjgEJOerO1+1l0xyHOBi8M=
|
||||
github.com/r3labs/diff v1.1.0/go.mod h1:7WjXasNzi0vJetRcB/RqNl5dlIsmXcTTLmF5IoH6Xig=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so=
|
||||
|
||||
@@ -167,6 +167,8 @@ type DefaultAccountManager struct {
|
||||
userDeleteFromIDPEnabled bool
|
||||
|
||||
integratedPeerValidator integrated_validator.IntegratedValidator
|
||||
|
||||
networkMapHash map[string]uint64
|
||||
}
|
||||
|
||||
// Settings represents Account settings structure that can be modified via API and Dashboard
|
||||
|
||||
121
management/server/hash.go
Normal file
121
management/server/hash.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/hashstructure/v2"
|
||||
"github.com/r3labs/diff"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func updateAccountPeers(account *Account) {
|
||||
//start := time.Now()
|
||||
//defer func() {
|
||||
// duration := time.Since(start)
|
||||
// log.Printf("Finished execution of updateAccountPeers, took %v\n", duration)
|
||||
//}()
|
||||
|
||||
peers := account.GetPeers()
|
||||
|
||||
approvedPeersMap := make(map[string]struct{}, len(peers))
|
||||
for _, peer := range peers {
|
||||
approvedPeersMap[peer.ID] = struct{}{}
|
||||
}
|
||||
|
||||
for _, peer := range peers {
|
||||
//if !am.peersUpdateManager.HasChannel(peer.ID) {
|
||||
// log.Tracef("peer %s doesn't have a channel, skipping network map update", peer.ID)
|
||||
// continue
|
||||
//}
|
||||
|
||||
_ = account.GetPeerNetworkMap(peer.ID, "netbird.io", approvedPeersMap)
|
||||
|
||||
//remotePeerNetworkMap := account.GetPeerNetworkMap(peer.ID, am.dnsDomain, approvedPeersMap)
|
||||
//postureChecks := am.getPeerPostureChecks(account, peer)
|
||||
//update := toSyncResponse(nil, peer, nil, remotePeerNetworkMap, am.GetDNSDomain(), postureChecks)
|
||||
//am.peersUpdateManager.SendUpdate(peer.ID, &UpdateMessage{Update: update})
|
||||
}
|
||||
}
|
||||
|
||||
func updateAccountPeersWithHash(account *Account) {
|
||||
//start := time.Now()
|
||||
//var skipUpdate int
|
||||
//defer func() {
|
||||
// duration := time.Since(start)
|
||||
// log.Printf("Finished execution of updateAccountPeers, took %v\n", duration.Nanoseconds())
|
||||
// log.Println("not updated peers: ", skipUpdate)
|
||||
//}()
|
||||
|
||||
peers := account.GetPeers()
|
||||
approvedPeersMap := make(map[string]struct{}, len(peers))
|
||||
for _, peer := range peers {
|
||||
approvedPeersMap[peer.ID] = struct{}{}
|
||||
}
|
||||
|
||||
for _, peer := range peers {
|
||||
//if !am.peersUpdateManager.HasChannel(peer.ID) {
|
||||
// log.Tracef("peer %s doesn't have a channel, skipping network map update", peer.ID)
|
||||
// continue
|
||||
//}
|
||||
//33006042459
|
||||
// 8700718125
|
||||
|
||||
remotePeerNetworkMap := account.GetPeerNetworkMap(peer.ID, "netbird.io", approvedPeersMap)
|
||||
//log.Println("firewall rules: ", len(remotePeerNetworkMap.FirewallRules))
|
||||
hashStr, err := hashstructure.Hash(remotePeerNetworkMap, hashstructure.FormatV2, &hashstructure.HashOptions{
|
||||
ZeroNil: true,
|
||||
IgnoreZeroValue: true,
|
||||
SlicesAsSets: true,
|
||||
UseStringer: true,
|
||||
//Hasher: xxhash.New(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("failed to generate network map hash: %v", err)
|
||||
} else {
|
||||
if peer.NetworkMapHash == hashStr {
|
||||
//log.Debugf("not sending network map update to peer: %s as there is nothing new", peer.ID)
|
||||
//skipUpdate++
|
||||
continue
|
||||
}
|
||||
peer.NetworkMapHash = hashStr
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func updateAccountPeersWithDiff(account *Account) {
|
||||
//start := time.Now()
|
||||
//var skipUpdate int
|
||||
//defer func() {
|
||||
// duration := time.Since(start)
|
||||
// log.Printf("Finished execution of updateAccountPeers, took %v\n", duration.Nanoseconds())
|
||||
// log.Println("not updated peers: ", skipUpdate)
|
||||
//}()
|
||||
|
||||
peers := account.GetPeers()
|
||||
approvedPeersMap := make(map[string]struct{}, len(peers))
|
||||
for _, peer := range peers {
|
||||
approvedPeersMap[peer.ID] = struct{}{}
|
||||
}
|
||||
|
||||
for _, peer := range peers {
|
||||
//if !am.peersUpdateManager.HasChannel(peer.ID) {
|
||||
// log.Tracef("peer %s doesn't have a channel, skipping network map update", peer.ID)
|
||||
// continue
|
||||
//}
|
||||
//33006042459
|
||||
// 8700718125
|
||||
|
||||
remotePeerNetworkMap := account.GetPeerNetworkMap(peer.ID, "netbird.io", approvedPeersMap)
|
||||
peer.NetworkMap = remotePeerNetworkMap
|
||||
changelog, err := diff.Diff(peer.NetworkMap, remotePeerNetworkMap)
|
||||
if err != nil {
|
||||
log.Errorf("failed to generate network map diff: %v", err)
|
||||
} else {
|
||||
if len(changelog) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//48868101197
|
||||
// 8700718125
|
||||
424
management/server/hash_test.go
Normal file
424
management/server/hash_test.go
Normal file
@@ -0,0 +1,424 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/hashstructure/v2"
|
||||
nbdns "github.com/netbirdio/netbird/dns"
|
||||
nbgroup "github.com/netbirdio/netbird/management/server/group"
|
||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||
route2 "github.com/netbirdio/netbird/route"
|
||||
"github.com/r3labs/diff"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func initTestAccount(b *testing.B, numPerAccount int) *Account {
|
||||
b.Helper()
|
||||
|
||||
account := newAccountWithId("account_id", "testuser", "")
|
||||
groupALL, err := account.GetGroupAll()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
setupKey := GenerateDefaultSetupKey()
|
||||
account.SetupKeys[setupKey.Key] = setupKey
|
||||
for n := 0; n < numPerAccount; n++ {
|
||||
netIP := randomIPv4()
|
||||
peerID := fmt.Sprintf("%s-peer-%d", account.Id, n)
|
||||
|
||||
peer := &nbpeer.Peer{
|
||||
ID: peerID,
|
||||
Key: peerID,
|
||||
SetupKey: "",
|
||||
IP: netIP,
|
||||
Name: peerID,
|
||||
DNSLabel: peerID,
|
||||
UserID: userID,
|
||||
Status: &nbpeer.PeerStatus{Connected: false, LastSeen: time.Now()},
|
||||
SSHEnabled: false,
|
||||
}
|
||||
account.Peers[peerID] = peer
|
||||
group, _ := account.GetGroupAll()
|
||||
group.Peers = append(group.Peers, peerID)
|
||||
user := &User{
|
||||
Id: fmt.Sprintf("%s-user-%d", account.Id, n),
|
||||
AccountID: account.Id,
|
||||
}
|
||||
account.Users[user.Id] = user
|
||||
route := &route2.Route{
|
||||
ID: route2.ID(fmt.Sprintf("network-id-%d", n)),
|
||||
Description: "base route",
|
||||
NetID: route2.NetID(fmt.Sprintf("network-id-%d", n)),
|
||||
Network: netip.MustParsePrefix(netIP.String() + "/24"),
|
||||
NetworkType: route2.IPv4Network,
|
||||
Metric: 9999,
|
||||
Masquerade: false,
|
||||
Enabled: true,
|
||||
Groups: []string{groupALL.ID},
|
||||
}
|
||||
account.Routes[route.ID] = route
|
||||
|
||||
group = &nbgroup.Group{
|
||||
ID: fmt.Sprintf("group-id-%d", n),
|
||||
AccountID: account.Id,
|
||||
Name: fmt.Sprintf("group-id-%d", n),
|
||||
Issued: "api",
|
||||
Peers: nil,
|
||||
}
|
||||
account.Groups[group.ID] = group
|
||||
|
||||
nameserver := &nbdns.NameServerGroup{
|
||||
ID: fmt.Sprintf("nameserver-id-%d", n),
|
||||
AccountID: account.Id,
|
||||
Name: fmt.Sprintf("nameserver-id-%d", n),
|
||||
Description: "",
|
||||
NameServers: []nbdns.NameServer{{IP: netip.MustParseAddr(netIP.String()), NSType: nbdns.UDPNameServerType}},
|
||||
Groups: []string{group.ID},
|
||||
Primary: false,
|
||||
Domains: nil,
|
||||
Enabled: false,
|
||||
SearchDomainsEnabled: false,
|
||||
}
|
||||
account.NameServerGroups[nameserver.ID] = nameserver
|
||||
|
||||
setupKey := GenerateDefaultSetupKey()
|
||||
account.SetupKeys[setupKey.Key] = setupKey
|
||||
}
|
||||
|
||||
group := &nbgroup.Group{
|
||||
ID: "randomID",
|
||||
AccountID: account.Id,
|
||||
Name: "randomName",
|
||||
Issued: "api",
|
||||
Peers: groupALL.Peers[:numPerAccount-1],
|
||||
}
|
||||
account.Groups[group.ID] = group
|
||||
|
||||
account.Policies = []*Policy{
|
||||
{
|
||||
ID: "RuleDefault",
|
||||
Name: "Default",
|
||||
Description: "This is a default rule that allows connections between all the resources",
|
||||
Enabled: true,
|
||||
Rules: []*PolicyRule{
|
||||
{
|
||||
ID: "RuleDefault",
|
||||
Name: "Default",
|
||||
Description: "This is a default rule that allows connections between all the resources",
|
||||
Bidirectional: true,
|
||||
Enabled: true,
|
||||
Protocol: PolicyRuleProtocolTCP,
|
||||
Action: PolicyTrafficActionAccept,
|
||||
Sources: []string{
|
||||
group.ID,
|
||||
},
|
||||
Destinations: []string{
|
||||
group.ID,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "RuleDefault2",
|
||||
Name: "Default",
|
||||
Description: "This is a default rule that allows connections between all the resources",
|
||||
Bidirectional: true,
|
||||
Enabled: true,
|
||||
Protocol: PolicyRuleProtocolUDP,
|
||||
Action: PolicyTrafficActionAccept,
|
||||
Sources: []string{
|
||||
groupALL.ID,
|
||||
},
|
||||
Destinations: []string{
|
||||
groupALL.ID,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return account
|
||||
}
|
||||
|
||||
// 1000 - 6717416375 ns/op
|
||||
// 500 - 1732888875 ns/op
|
||||
func BenchmarkTest_updateAccountPeers100(b *testing.B) {
|
||||
account := initTestAccount(b, 100)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
updateAccountPeers(account)
|
||||
}
|
||||
}
|
||||
|
||||
// 1000 - 28943404000 ns/op
|
||||
// 500 - 7365024500 ns/op
|
||||
func BenchmarkTest_updateAccountPeersWithHash100(b *testing.B) {
|
||||
account := initTestAccount(b, 100)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithHash(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeersWithDiff100(b *testing.B) {
|
||||
account := initTestAccount(b, 100)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithDiff(account)
|
||||
}
|
||||
}
|
||||
|
||||
// 1000 - 6717416375 ns/op
|
||||
// 500 - 1732888875 ns/op
|
||||
func BenchmarkTest_updateAccountPeers200(b *testing.B) {
|
||||
account := initTestAccount(b, 200)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
updateAccountPeers(account)
|
||||
}
|
||||
}
|
||||
|
||||
// 1000 - 28943404000 ns/op
|
||||
// 500 - 7365024500 ns/op
|
||||
func BenchmarkTest_updateAccountPeersWithHash200(b *testing.B) {
|
||||
account := initTestAccount(b, 200)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithHash(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeersWithDiff200(b *testing.B) {
|
||||
account := initTestAccount(b, 200)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithDiff(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeers500(b *testing.B) {
|
||||
account := initTestAccount(b, 500)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
updateAccountPeers(account)
|
||||
}
|
||||
}
|
||||
|
||||
// 1000 - 28943404000 ns/op
|
||||
// 500 - 7365024500 ns/op
|
||||
func BenchmarkTest_updateAccountPeersWithHash500(b *testing.B) {
|
||||
account := initTestAccount(b, 500)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithHash(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeersWithDiff500(b *testing.B) {
|
||||
account := initTestAccount(b, 500)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithDiff(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeers1000(b *testing.B) {
|
||||
account := initTestAccount(b, 1000)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
updateAccountPeers(account)
|
||||
}
|
||||
}
|
||||
|
||||
// 1000 - 28943404000 ns/op
|
||||
// 500 - 7365024500 ns/op
|
||||
func BenchmarkTest_updateAccountPeersWithHash1000(b *testing.B) {
|
||||
account := initTestAccount(b, 1000)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithHash(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeersWithDiff1000(b *testing.B) {
|
||||
account := initTestAccount(b, 1000)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithDiff(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeers1500(b *testing.B) {
|
||||
account := initTestAccount(b, 1500)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
updateAccountPeers(account)
|
||||
}
|
||||
}
|
||||
|
||||
// 1000 - 28943404000 ns/op
|
||||
// 500 - 7365024500 ns/op
|
||||
func BenchmarkTest_updateAccountPeersWithHash1500(b *testing.B) {
|
||||
account := initTestAccount(b, 1500)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithHash(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeersWithDiff1500(b *testing.B) {
|
||||
account := initTestAccount(b, 1500)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithDiff(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeers2000(b *testing.B) {
|
||||
account := initTestAccount(b, 2000)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
updateAccountPeers(account)
|
||||
}
|
||||
}
|
||||
|
||||
// 1000 - 28943404000 ns/op
|
||||
// 500 - 7365024500 ns/op
|
||||
func BenchmarkTest_updateAccountPeersWithHash2000(b *testing.B) {
|
||||
account := initTestAccount(b, 2000)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithHash(account)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTest_updateAccountPeersWithDiff2000(b *testing.B) {
|
||||
account := initTestAccount(b, 2000)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Debug(i)
|
||||
updateAccountPeersWithDiff(account)
|
||||
}
|
||||
}
|
||||
|
||||
type TestStruct struct {
|
||||
Name string
|
||||
Value int
|
||||
Ignored string `diff:"-" hash:"ignore"`
|
||||
Compared string
|
||||
}
|
||||
|
||||
func TestDiffIgnoreTag(t *testing.T) {
|
||||
a := TestStruct{
|
||||
Name: "test",
|
||||
Value: 30,
|
||||
Ignored: "This should be ignored",
|
||||
Compared: "This should be compared",
|
||||
}
|
||||
|
||||
b := TestStruct{
|
||||
Name: "test",
|
||||
Value: 31,
|
||||
Ignored: "This is different but should be ignored",
|
||||
Compared: "This is different and should be compared",
|
||||
}
|
||||
|
||||
changelog, err := diff.Diff(a, b)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check that only the expected fields are in the changelog
|
||||
assert.Len(t, changelog, 2)
|
||||
|
||||
// Check that the 'Age' field change is detected
|
||||
ageChange := getChangeForField(changelog, "Value")
|
||||
assert.NotNil(t, ageChange)
|
||||
assert.Equal(t, 30, ageChange.From)
|
||||
assert.Equal(t, 31, ageChange.To)
|
||||
|
||||
// Check that the 'Compared' field change is detected
|
||||
comparedChange := getChangeForField(changelog, "Compared")
|
||||
assert.NotNil(t, comparedChange)
|
||||
assert.Equal(t, "This should be compared", comparedChange.From)
|
||||
assert.Equal(t, "This is different and should be compared", comparedChange.To)
|
||||
|
||||
// Check that the 'Ignored' field is not in the changelog
|
||||
ignoredChange := getChangeForField(changelog, "Ignored")
|
||||
assert.Nil(t, ignoredChange)
|
||||
}
|
||||
|
||||
func TestHashIgnoreTag(t *testing.T) {
|
||||
a := TestStruct{
|
||||
Name: "test",
|
||||
Value: 30,
|
||||
Ignored: "This should be ignored",
|
||||
Compared: "This should be compared",
|
||||
}
|
||||
|
||||
b := TestStruct{
|
||||
Name: "test",
|
||||
Value: 30,
|
||||
Ignored: "This is different but should be ignored",
|
||||
Compared: "This should be compared",
|
||||
}
|
||||
|
||||
c := TestStruct{
|
||||
Name: "test",
|
||||
Value: 31,
|
||||
Ignored: "This should be ignored",
|
||||
Compared: "This should be compared",
|
||||
}
|
||||
|
||||
d := TestStruct{
|
||||
Name: "test",
|
||||
Value: 30,
|
||||
Ignored: "This should be ignored",
|
||||
Compared: "This is different and should be compared",
|
||||
}
|
||||
|
||||
opts := &hashstructure.HashOptions{
|
||||
ZeroNil: true,
|
||||
IgnoreZeroValue: true,
|
||||
SlicesAsSets: true,
|
||||
UseStringer: true,
|
||||
}
|
||||
|
||||
hashA, err := hashstructure.Hash(a, hashstructure.FormatV2, opts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
hashB, err := hashstructure.Hash(b, hashstructure.FormatV2, opts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
hashC, err := hashstructure.Hash(c, hashstructure.FormatV2, opts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
hashD, err := hashstructure.Hash(d, hashstructure.FormatV2, opts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test that changing the ignored field does not change the hash
|
||||
assert.Equal(t, hashA, hashB)
|
||||
|
||||
// Test that changing a non-ignored field does change the hash
|
||||
assert.NotEqual(t, hashA, hashC)
|
||||
assert.NotEqual(t, hashA, hashD)
|
||||
}
|
||||
|
||||
func getChangeForField(changelog diff.Changelog, fieldName string) *diff.Change {
|
||||
for _, change := range changelog {
|
||||
if change.Path[0] == fieldName {
|
||||
return &change
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -40,9 +40,9 @@ type Network struct {
|
||||
Dns string
|
||||
// Serial is an ID that increments by 1 when any change to the network happened (e.g. new peer has been added).
|
||||
// Used to synchronize state to the client apps.
|
||||
Serial uint64
|
||||
Serial uint64 `diff:"-"`
|
||||
|
||||
mu sync.Mutex `json:"-" gorm:"-"`
|
||||
mu sync.Mutex `json:"-" gorm:"-" diff:"-"`
|
||||
}
|
||||
|
||||
// NewNetwork creates a new Network initializing it with a Serial=0
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/hashstructure/v2"
|
||||
"github.com/netbirdio/netbird/management/server/posture"
|
||||
"github.com/rs/xid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -915,6 +916,18 @@ func updatePeerMeta(peer *nbpeer.Peer, meta nbpeer.PeerSystemMeta, account *Acco
|
||||
// updateAccountPeers updates all peers that belong to an account.
|
||||
// Should be called when changes have to be synced to peers.
|
||||
func (am *DefaultAccountManager) updateAccountPeers(account *Account) {
|
||||
start := time.Now()
|
||||
var skipUpdate int
|
||||
defer func() {
|
||||
duration := time.Since(start)
|
||||
log.Printf("Finished execution of updateAccountPeers, took %v\n", duration)
|
||||
log.Println("not updated peers: ", skipUpdate)
|
||||
}()
|
||||
|
||||
if am.networkMapHash == nil {
|
||||
am.networkMapHash = map[string]uint64{}
|
||||
}
|
||||
|
||||
peers := account.GetPeers()
|
||||
|
||||
approvedPeersMap, err := am.GetValidatedPeers(account)
|
||||
@@ -922,14 +935,32 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) {
|
||||
log.Errorf("failed send out updates to peers, failed to validate peer: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, peer := range peers {
|
||||
if !am.peersUpdateManager.HasChannel(peer.ID) {
|
||||
log.Tracef("peer %s doesn't have a channel, skipping network map update", peer.ID)
|
||||
continue
|
||||
//if !am.peersUpdateManager.HasChannel(peer.ID) {
|
||||
// log.Tracef("peer %s doesn't have a channel, skipping network map update", peer.ID)
|
||||
// continue
|
||||
//}
|
||||
|
||||
remotePeerNetworkMap := account.GetPeerNetworkMap(peer.ID, am.dnsDomain, approvedPeersMap)
|
||||
hash, err := hashstructure.Hash(remotePeerNetworkMap, hashstructure.FormatV2, &hashstructure.HashOptions{
|
||||
ZeroNil: true,
|
||||
IgnoreZeroValue: true,
|
||||
SlicesAsSets: true,
|
||||
UseStringer: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("failed to generate network map hash: %v", err)
|
||||
} else {
|
||||
if am.networkMapHash[peer.ID] == hash {
|
||||
log.Debugf("not sending network map update to peer: %s as there is nothing new", peer.ID)
|
||||
skipUpdate++
|
||||
continue
|
||||
}
|
||||
am.networkMapHash[peer.ID] = hash
|
||||
}
|
||||
|
||||
postureChecks := am.getPeerPostureChecks(account, peer)
|
||||
remotePeerNetworkMap := account.GetPeerNetworkMap(peer.ID, am.dnsDomain, approvedPeersMap)
|
||||
update := toSyncResponse(nil, peer, nil, remotePeerNetworkMap, am.GetDNSDomain(), postureChecks)
|
||||
am.peersUpdateManager.SendUpdate(peer.ID, &UpdateMessage{Update: update})
|
||||
}
|
||||
|
||||
@@ -18,35 +18,38 @@ type Peer struct {
|
||||
// WireGuard public key
|
||||
Key string `gorm:"index"`
|
||||
// A setup key this peer was registered with
|
||||
SetupKey string
|
||||
SetupKey string `diff:"-" hash:"ignore"`
|
||||
// IP address of the Peer
|
||||
IP net.IP `gorm:"serializer:json"`
|
||||
// Meta is a Peer system meta data
|
||||
Meta PeerSystemMeta `gorm:"embedded;embeddedPrefix:meta_"`
|
||||
Meta PeerSystemMeta `gorm:"embedded;embeddedPrefix:meta_" diff:"-" hash:"ignore"`
|
||||
// Name is peer's name (machine name)
|
||||
Name string
|
||||
// DNSLabel is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's
|
||||
// domain to the peer label. e.g. peer-dns-label.netbird.cloud
|
||||
DNSLabel string
|
||||
// Status peer's management connection status
|
||||
Status *PeerStatus `gorm:"embedded;embeddedPrefix:peer_status_"`
|
||||
Status *PeerStatus `gorm:"embedded;embeddedPrefix:peer_status_" diff:"-" hash:"ignore"`
|
||||
// The user ID that registered the peer
|
||||
UserID string
|
||||
UserID string `diff:"-" hash:"ignore"`
|
||||
// SSHKey is a public SSH key of the peer
|
||||
SSHKey string
|
||||
// SSHEnabled indicates whether SSH server is enabled on the peer
|
||||
SSHEnabled bool
|
||||
// LoginExpirationEnabled indicates whether peer's login expiration is enabled and once expired the peer has to re-login.
|
||||
// Works with LastLogin
|
||||
LoginExpirationEnabled bool
|
||||
LoginExpirationEnabled bool `diff:"-" hash:"ignore"`
|
||||
// LastLogin the time when peer performed last login operation
|
||||
LastLogin time.Time
|
||||
LastLogin time.Time `diff:"-" hash:"ignore"`
|
||||
// CreatedAt records the time the peer was created
|
||||
CreatedAt time.Time
|
||||
CreatedAt time.Time `diff:"-" hash:"ignore"`
|
||||
// Indicate ephemeral peer attribute
|
||||
Ephemeral bool
|
||||
Ephemeral bool `diff:"-" hash:"ignore"`
|
||||
// Geo location based on connection IP
|
||||
Location Location `gorm:"embedded;embeddedPrefix:location_"`
|
||||
Location Location `gorm:"embedded;embeddedPrefix:location_" diff:"-" hash:"ignore"`
|
||||
|
||||
NetworkMap any `diff:"-" hash:"ignore"`
|
||||
NetworkMapHash uint64 ` diff:"-" hash:"ignore"`
|
||||
}
|
||||
|
||||
type PeerStatus struct { //nolint:revive
|
||||
|
||||
Reference in New Issue
Block a user