mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-07 22:19:08 +02:00
[management] fix the concurrency handling within the update message tests (#8000)
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"testing/synctest"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus/push"
|
"github.com/prometheus/client_golang/prometheus/push"
|
||||||
@@ -40,6 +41,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
||||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||||
networkmapdbfactory "github.com/netbirdio/netbird/management/internals/network_map_db/factory"
|
networkmapdbfactory "github.com/netbirdio/netbird/management/internals/network_map_db/factory"
|
||||||
|
networkmap_sqlite "github.com/netbirdio/netbird/management/internals/network_map_db/sqlite"
|
||||||
"github.com/netbirdio/netbird/management/internals/server/config"
|
"github.com/netbirdio/netbird/management/internals/server/config"
|
||||||
nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc"
|
nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc"
|
||||||
nbAccount "github.com/netbirdio/netbird/management/server/account"
|
nbAccount "github.com/netbirdio/netbird/management/server/account"
|
||||||
@@ -1297,7 +1299,9 @@ func TestAccountManager_AddPeerWithUserID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
|
func TestAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
|
||||||
testAccountManager_NetworkUpdates_SaveGroup(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
testAccountManager_NetworkUpdates_SaveGroup(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
|
func testAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
|
||||||
@@ -1330,6 +1334,8 @@ func testAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
|
|||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
defer updateManager.CloseChannel(context.Background(), peer1.ID)
|
defer updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
@@ -1352,7 +1358,9 @@ func testAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
|
func TestAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
|
||||||
testAccountManager_NetworkUpdates_DeletePolicy(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
testAccountManager_NetworkUpdates_DeletePolicy(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
|
func testAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
|
||||||
@@ -1361,13 +1369,7 @@ func testAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
|
|||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
defer updateManager.CloseChannel(context.Background(), peer1.ID)
|
defer updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
|
|
||||||
// Ensure that we do not receive an update message before the policy is deleted
|
settleAffectedUpdates(updMsg)
|
||||||
time.Sleep(time.Second)
|
|
||||||
select {
|
|
||||||
case <-updMsg:
|
|
||||||
t.Logf("received addPeer update message before policy deletion")
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
@@ -1390,7 +1392,9 @@ func testAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
|
func TestAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
|
||||||
testAccountManager_NetworkUpdates_SavePolicy(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
testAccountManager_NetworkUpdates_SavePolicy(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
|
func testAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
|
||||||
@@ -1410,6 +1414,8 @@ func testAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
|
|||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
defer updateManager.CloseChannel(context.Background(), peer1.ID)
|
defer updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
@@ -1443,7 +1449,9 @@ func testAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
|
func TestAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
|
||||||
testAccountManager_NetworkUpdates_DeletePeer(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
testAccountManager_NetworkUpdates_DeletePeer(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
|
func testAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
|
||||||
@@ -1482,6 +1490,8 @@ func testAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
|
|||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
defer updateManager.CloseChannel(context.Background(), peer1.ID)
|
defer updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
@@ -1503,7 +1513,9 @@ func testAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
|
func TestAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
|
||||||
testAccountManager_NetworkUpdates_DeleteGroup(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
testAccountManager_NetworkUpdates_DeleteGroup(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
|
func testAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
|
||||||
@@ -1550,6 +1562,8 @@ func testAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
@@ -3582,6 +3596,9 @@ func createManagerWithNetworkMapStore(t testing.TB) (*DefaultAccountManager, *up
|
|||||||
|
|
||||||
nmdataStore, err := networkmapdbfactory.NewNetworkMapDBStore(context.Background(), types.SqliteStoreEngine, dataDir, MockIntegratedValidator{}, newSettingsMockManager(t))
|
nmdataStore, err := networkmapdbfactory.NewNetworkMapDBStore(context.Background(), types.SqliteStoreEngine, dataDir, MockIntegratedValidator{}, newSettingsMockManager(t))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
sqliteStore, ok := nmdataStore.Store.(*networkmap_sqlite.SqliteStore)
|
||||||
|
require.True(t, ok, "network map store is %T, want *networkmap_sqlite.SqliteStore", nmdataStore.Store)
|
||||||
|
t.Cleanup(func() { assert.NoError(t, sqliteStore.Db.Close()) })
|
||||||
|
|
||||||
manager, updateManager, err := buildTestManager(t, store, nmdataStore)
|
manager, updateManager, err := buildTestManager(t, store, nmdataStore)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -3636,7 +3653,8 @@ func buildTestManager(t testing.TB, store store.Store, nmdataStore *networkmapdb
|
|||||||
Return(nil).
|
Return(nil).
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
|
|
||||||
cacheStore, err := cache.NewStore(ctx, 100*time.Millisecond, 300*time.Millisecond, 100)
|
// The go-cache janitor only stops via a GC finalizer and would outlive synctest bubbles.
|
||||||
|
cacheStore, err := cache.NewStore(ctx, 100*time.Millisecond, 0, 100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -3648,8 +3666,11 @@ func buildTestManager(t testing.TB, store store.Store, nmdataStore *networkmapdb
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
cacheManager := manager.cacheManager
|
||||||
|
t.Cleanup(func() { assert.NoError(t, cacheManager.Close()) })
|
||||||
|
|
||||||
proxyGrpcServer := nbgrpc.NewProxyServiceServer(nil, nil, nil, nbgrpc.ProxyOIDCConfig{}, peersManager, nil, nil, proxyManager, nil)
|
proxyGrpcServer := nbgrpc.NewProxyServiceServer(nil, nil, nil, nbgrpc.ProxyOIDCConfig{}, peersManager, nil, nil, proxyManager, nil)
|
||||||
|
t.Cleanup(proxyGrpcServer.Close)
|
||||||
proxyController, err := proxymanager.NewGRPCController(proxyGrpcServer, noop.Meter{})
|
proxyController, err := proxymanager.NewGRPCController(proxyGrpcServer, noop.Meter{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -3743,6 +3764,33 @@ func setupNetworkMapTest(t *testing.T) (*DefaultAccountManager, *update_channel.
|
|||||||
// when the channel delivers.
|
// when the channel delivers.
|
||||||
const peerUpdateTimeout = 5 * time.Second
|
const peerUpdateTimeout = 5 * time.Second
|
||||||
|
|
||||||
|
// peerUpdateSettleTime bounds how far settleAffectedUpdates advances the fake clock. It must exceed
|
||||||
|
// the account request and peer update buffer intervals.
|
||||||
|
const peerUpdateSettleTime = time.Second
|
||||||
|
|
||||||
|
// runPeerUpdateTest runs f inside synctest.Test, so the peer update helpers observe every background
|
||||||
|
// goroutine of the test, and lets the updates still in flight when f returns finish before the bubble
|
||||||
|
// ends, since the bubble's clock stops with it.
|
||||||
|
func runPeerUpdateTest(t *testing.T, f func(t *testing.T)) {
|
||||||
|
synctest.Test(t, func(t *testing.T) {
|
||||||
|
defer settleAffectedUpdates()
|
||||||
|
f(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// settleAffectedUpdates runs the synctest bubble's fake clock past every update buffer interval until
|
||||||
|
// all goroutines are blocked, then discards the updates already delivered to chans, so the next
|
||||||
|
// assertion only observes updates from the action under test. It must be called inside synctest.Test.
|
||||||
|
func settleAffectedUpdates(chans ...<-chan *network_map.UpdateMessage) {
|
||||||
|
time.Sleep(peerUpdateSettleTime)
|
||||||
|
synctest.Wait()
|
||||||
|
for _, ch := range chans {
|
||||||
|
for len(ch) > 0 {
|
||||||
|
<-ch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func drainPeerUpdates(ch <-chan *network_map.UpdateMessage) {
|
func drainPeerUpdates(ch <-chan *network_map.UpdateMessage) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -3756,6 +3804,19 @@ func drainPeerUpdates(ch <-chan *network_map.UpdateMessage) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// step runs f as one named stage of a test inside synctest.Test, which forbids t.Run, and names the
|
||||||
|
// stage when it fails the test. Stages share t, so a fatal failure ends the remaining stages as well.
|
||||||
|
func step(t *testing.T, name string, f func(t *testing.T)) {
|
||||||
|
t.Helper()
|
||||||
|
failedBefore := t.Failed()
|
||||||
|
defer func() {
|
||||||
|
if !failedBefore && t.Failed() {
|
||||||
|
t.Logf("step %q failed", name)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
f(t)
|
||||||
|
}
|
||||||
|
|
||||||
func peerShouldNotReceiveUpdate(t *testing.T, updateMessage <-chan *network_map.UpdateMessage) {
|
func peerShouldNotReceiveUpdate(t *testing.T, updateMessage <-chan *network_map.UpdateMessage) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -87,93 +87,93 @@ func TestAffectedPeers_AllowedUsersChange_RefreshesSSHDestinations(t *testing.T)
|
|||||||
// auto-group change updates only the user's peers and the peers linked to the changed
|
// auto-group change updates only the user's peers and the peers linked to the changed
|
||||||
// group through policies, instead of fanning out to the whole account.
|
// group through policies, instead of fanning out to the whole account.
|
||||||
func TestAffectedPeers_SyncUserJWTGroups_OnlyAffectedPeersUpdated(t *testing.T) {
|
func TestAffectedPeers_SyncUserJWTGroups_OnlyAffectedPeersUpdated(t *testing.T) {
|
||||||
manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
accountID := account.Id
|
ctx := context.Background()
|
||||||
|
accountID := account.Id
|
||||||
|
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
userPeer, _, _, _, err := manager.AddPeer(ctx, accountID, "", userID, &nbpeer.Peer{
|
userPeer, _, _, _, err := manager.AddPeer(ctx, accountID, "", userID, &nbpeer.Peer{
|
||||||
Key: key.PublicKey().String(),
|
Key: key.PublicKey().String(),
|
||||||
Meta: nbpeer.PeerSystemMeta{Hostname: "user-peer"},
|
Meta: nbpeer.PeerSystemMeta{Hostname: "user-peer"},
|
||||||
}, false)
|
}, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
policies, err := manager.Store.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID)
|
policies, err := manager.Store.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for _, p := range policies {
|
for _, p := range policies {
|
||||||
require.NoError(t, manager.Store.DeletePolicy(ctx, accountID, p.ID))
|
require.NoError(t, manager.Store.DeletePolicy(ctx, accountID, p.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err = manager.Store.GetAccount(ctx, accountID)
|
account, err = manager.Store.GetAccount(ctx, accountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
account.Settings.JWTGroupsEnabled = true
|
account.Settings.JWTGroupsEnabled = true
|
||||||
account.Settings.JWTGroupsClaimName = "groups"
|
account.Settings.JWTGroupsClaimName = "groups"
|
||||||
account.Settings.GroupsPropagationEnabled = true
|
account.Settings.GroupsPropagationEnabled = true
|
||||||
require.NoError(t, manager.Store.SaveAccount(ctx, account))
|
require.NoError(t, manager.Store.SaveAccount(ctx, account))
|
||||||
|
|
||||||
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "jwt-grp", Name: "jwt-linked", Issued: types.GroupIssuedJWT, Peers: []string{}}))
|
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "jwt-grp", Name: "jwt-linked", Issued: types.GroupIssuedJWT, Peers: []string{}}))
|
||||||
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "jwt-dest", Name: "jwt-dest", Peers: []string{peer2.ID}}))
|
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "jwt-dest", Name: "jwt-dest", Peers: []string{peer2.ID}}))
|
||||||
|
|
||||||
_, err = manager.SavePolicy(ctx, accountID, userID, &types.Policy{
|
_, err = manager.SavePolicy(ctx, accountID, userID, &types.Policy{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Rules: []*types.PolicyRule{
|
Rules: []*types.PolicyRule{
|
||||||
{
|
{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Sources: []string{"jwt-grp"},
|
Sources: []string{"jwt-grp"},
|
||||||
Destinations: []string{"jwt-dest"},
|
Destinations: []string{"jwt-dest"},
|
||||||
Bidirectional: true,
|
Bidirectional: true,
|
||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}, true)
|
||||||
}, true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
updUser := updateManager.CreateChannel(ctx, userPeer.ID)
|
|
||||||
upd2 := updateManager.CreateChannel(ctx, peer2.ID)
|
|
||||||
upd3 := updateManager.CreateChannel(ctx, peer3.ID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
updateManager.CloseChannel(ctx, userPeer.ID)
|
|
||||||
updateManager.CloseChannel(ctx, peer2.ID)
|
|
||||||
updateManager.CloseChannel(ctx, peer3.ID)
|
|
||||||
})
|
|
||||||
|
|
||||||
userAuth := auth.UserAuth{
|
|
||||||
AccountId: accountID,
|
|
||||||
UserId: userID,
|
|
||||||
Groups: []string{"jwt-linked"},
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("adding JWT group updates only linked peers", func(t *testing.T) {
|
|
||||||
drainPeerUpdates(updUser)
|
|
||||||
drainPeerUpdates(upd2)
|
|
||||||
drainPeerUpdates(upd3)
|
|
||||||
|
|
||||||
require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth))
|
|
||||||
|
|
||||||
peerShouldReceiveUpdate(t, updUser)
|
|
||||||
peerShouldReceiveUpdate(t, upd2)
|
|
||||||
peerShouldNotReceiveUpdate(t, upd3)
|
|
||||||
|
|
||||||
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Contains(t, user.AutoGroups, "jwt-grp")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("removing JWT group updates only linked peers", func(t *testing.T) {
|
updUser := updateManager.CreateChannel(ctx, userPeer.ID)
|
||||||
drainPeerUpdates(updUser)
|
upd2 := updateManager.CreateChannel(ctx, peer2.ID)
|
||||||
drainPeerUpdates(upd2)
|
upd3 := updateManager.CreateChannel(ctx, peer3.ID)
|
||||||
drainPeerUpdates(upd3)
|
t.Cleanup(func() {
|
||||||
|
updateManager.CloseChannel(ctx, userPeer.ID)
|
||||||
|
updateManager.CloseChannel(ctx, peer2.ID)
|
||||||
|
updateManager.CloseChannel(ctx, peer3.ID)
|
||||||
|
})
|
||||||
|
|
||||||
userAuth.Groups = nil
|
userAuth := auth.UserAuth{
|
||||||
require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth))
|
AccountId: accountID,
|
||||||
|
UserId: userID,
|
||||||
|
Groups: []string{"jwt-linked"},
|
||||||
|
}
|
||||||
|
|
||||||
peerShouldReceiveUpdate(t, updUser)
|
step(t, "adding JWT group updates only linked peers", func(t *testing.T) {
|
||||||
peerShouldReceiveUpdate(t, upd2)
|
settleAffectedUpdates(updUser, upd2, upd3)
|
||||||
peerShouldNotReceiveUpdate(t, upd3)
|
|
||||||
|
|
||||||
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
|
require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth))
|
||||||
require.NoError(t, err)
|
|
||||||
assert.NotContains(t, user.AutoGroups, "jwt-grp")
|
peerShouldReceiveUpdate(t, updUser)
|
||||||
|
peerShouldReceiveUpdate(t, upd2)
|
||||||
|
peerShouldNotReceiveUpdate(t, upd3)
|
||||||
|
|
||||||
|
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Contains(t, user.AutoGroups, "jwt-grp")
|
||||||
|
})
|
||||||
|
|
||||||
|
step(t, "removing JWT group updates only linked peers", func(t *testing.T) {
|
||||||
|
drainPeerUpdates(updUser)
|
||||||
|
drainPeerUpdates(upd2)
|
||||||
|
drainPeerUpdates(upd3)
|
||||||
|
|
||||||
|
userAuth.Groups = nil
|
||||||
|
require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth))
|
||||||
|
|
||||||
|
peerShouldReceiveUpdate(t, updUser)
|
||||||
|
peerShouldReceiveUpdate(t, upd2)
|
||||||
|
peerShouldNotReceiveUpdate(t, upd3)
|
||||||
|
|
||||||
|
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotContains(t, user.AutoGroups, "jwt-grp")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,120 +24,124 @@ import (
|
|||||||
// detaching one of them must still refresh that group's policy source peers, even
|
// detaching one of them must still refresh that group's policy source peers, even
|
||||||
// though the post-update resource no longer maps to it.
|
// though the post-update resource no longer maps to it.
|
||||||
func TestAffectedPeers_E2E_UpdateResource_DetachGroup_RefreshesOldGroupSources(t *testing.T) {
|
func TestAffectedPeers_E2E_UpdateResource_DetachGroup_RefreshesOldGroupSources(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
// A second resource group + a second source group/peer that reaches the
|
// A second resource group + a second source group/peer that reaches the
|
||||||
// resource only through that second group.
|
// resource only through that second group.
|
||||||
const detachGroupID = "rs-detach-grp"
|
const detachGroupID = "rs-detach-grp"
|
||||||
require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{ID: detachGroupID, Name: "rs-detach"}))
|
require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{ID: detachGroupID, Name: "rs-detach"}))
|
||||||
|
|
||||||
const secondSourceGroupID = "rs-source-grp-2"
|
const secondSourceGroupID = "rs-source-grp-2"
|
||||||
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-detach-key", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-detach-key", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
secondSourcePeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
|
secondSourcePeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
|
||||||
require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{
|
require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{
|
||||||
ID: secondSourceGroupID, Name: "rs-source-2", Peers: []string{secondSourcePeer.ID},
|
ID: secondSourceGroupID, Name: "rs-source-2", Peers: []string{secondSourcePeer.ID},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
resourcesManager, _, _ := s.managers()
|
resourcesManager, _, _ := s.managers()
|
||||||
|
|
||||||
// Attach the resource to the detach group as well: now in [resourceGroup, detachGroup].
|
// Attach the resource to the detach group as well: now in [resourceGroup, detachGroup].
|
||||||
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
||||||
ID: s.resourceID,
|
ID: s.resourceID,
|
||||||
AccountID: s.accountID,
|
AccountID: s.accountID,
|
||||||
NetworkID: s.networkID,
|
NetworkID: s.networkID,
|
||||||
Name: "rs-resource-host",
|
Name: "rs-resource-host",
|
||||||
Address: "10.20.30.0/24",
|
Address: "10.20.30.0/24",
|
||||||
GroupIDs: []string{s.resourceGroupID, detachGroupID},
|
GroupIDs: []string{s.resourceGroupID, detachGroupID},
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Policy granting the second source group access via the detach group.
|
||||||
|
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(secondSourceGroupID, detachGroupID), true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
secondSrcCh := s.updateManager.CreateChannel(ctx, secondSourcePeer.ID)
|
||||||
|
t.Cleanup(func() { s.updateManager.CloseChannel(ctx, secondSourcePeer.ID) })
|
||||||
|
settleAffectedUpdates(secondSrcCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
// Detaching the resource from detachGroup removes the second source's
|
||||||
|
// access; that source peer must be refreshed even though the post-update
|
||||||
|
// resource no longer maps to detachGroup.
|
||||||
|
peerShouldReceiveUpdate(t, secondSrcCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
||||||
|
ID: s.resourceID,
|
||||||
|
AccountID: s.accountID,
|
||||||
|
NetworkID: s.networkID,
|
||||||
|
Name: "rs-resource-host",
|
||||||
|
Address: "10.20.30.0/24",
|
||||||
|
GroupIDs: []string{s.resourceGroupID}, // detached detachGroup
|
||||||
|
Enabled: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: detaching a resource group did not refresh the old group's policy source peer")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Policy granting the second source group access via the detach group.
|
|
||||||
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(secondSourceGroupID, detachGroupID), true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
secondSrcCh := s.updateManager.CreateChannel(ctx, secondSourcePeer.ID)
|
|
||||||
t.Cleanup(func() { s.updateManager.CloseChannel(ctx, secondSourcePeer.ID) })
|
|
||||||
settleAffectedUpdates(secondSrcCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
// Detaching the resource from detachGroup removes the second source's
|
|
||||||
// access; that source peer must be refreshed even though the post-update
|
|
||||||
// resource no longer maps to detachGroup.
|
|
||||||
peerShouldReceiveUpdate(t, secondSrcCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
|
||||||
ID: s.resourceID,
|
|
||||||
AccountID: s.accountID,
|
|
||||||
NetworkID: s.networkID,
|
|
||||||
Name: "rs-resource-host",
|
|
||||||
Address: "10.20.30.0/24",
|
|
||||||
GroupIDs: []string{s.resourceGroupID}, // detached detachGroup
|
|
||||||
Enabled: true,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: detaching a resource group did not refresh the old group's policy source peer")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAffectedPeers_E2E_UpdateRouter_RepointPeer_RefreshesOldRoutingPeer:
|
// TestAffectedPeers_E2E_UpdateRouter_RepointPeer_RefreshesOldRoutingPeer:
|
||||||
// changing router.Peer within the same network must still refresh the OLD routing
|
// changing router.Peer within the same network must still refresh the OLD routing
|
||||||
// peer, which loses its routing role.
|
// peer, which loses its routing role.
|
||||||
func TestAffectedPeers_E2E_UpdateRouter_RepointPeer_RefreshesOldRoutingPeer(t *testing.T) {
|
func TestAffectedPeers_E2E_UpdateRouter_RepointPeer_RefreshesOldRoutingPeer(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, routersManager, _ := s.managers()
|
_, routersManager, _ := s.managers()
|
||||||
|
|
||||||
routers, err := s.manager.Store.GetNetworkRoutersByNetID(ctx, store.LockingStrengthNone, s.accountID, s.networkID)
|
routers, err := s.manager.Store.GetNetworkRoutersByNetID(ctx, store.LockingStrengthNone, s.accountID, s.networkID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, routers, 1)
|
require.Len(t, routers, 1)
|
||||||
router := routers[0]
|
router := routers[0]
|
||||||
oldRoutingPeer := router.Peer
|
oldRoutingPeer := router.Peer
|
||||||
require.NotEmpty(t, oldRoutingPeer)
|
require.NotEmpty(t, oldRoutingPeer)
|
||||||
|
|
||||||
// A new peer to become the routing peer in place of the old one.
|
// A new peer to become the routing peer in place of the old one.
|
||||||
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-newrouter-key", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-newrouter-key", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
newRoutingPeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
|
newRoutingPeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
|
||||||
|
|
||||||
oldCh := s.updateManager.CreateChannel(ctx, oldRoutingPeer)
|
oldCh := s.updateManager.CreateChannel(ctx, oldRoutingPeer)
|
||||||
t.Cleanup(func() { s.updateManager.CloseChannel(ctx, oldRoutingPeer) })
|
t.Cleanup(func() { s.updateManager.CloseChannel(ctx, oldRoutingPeer) })
|
||||||
settleAffectedUpdates(oldCh)
|
settleAffectedUpdates(oldCh)
|
||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
// The old routing peer stops serving the resource and must be refreshed.
|
// The old routing peer stops serving the resource and must be refreshed.
|
||||||
peerShouldReceiveUpdate(t, oldCh)
|
peerShouldReceiveUpdate(t, oldCh)
|
||||||
close(done)
|
close(done)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
_, err = routersManager.UpdateRouter(ctx, userID, &routerTypes.NetworkRouter{
|
_, err = routersManager.UpdateRouter(ctx, userID, &routerTypes.NetworkRouter{
|
||||||
ID: router.ID,
|
ID: router.ID,
|
||||||
NetworkID: s.networkID,
|
NetworkID: s.networkID,
|
||||||
AccountID: s.accountID,
|
AccountID: s.accountID,
|
||||||
Peer: newRoutingPeer.ID, // repoint within the same network
|
Peer: newRoutingPeer.ID, // repoint within the same network
|
||||||
Masquerade: true,
|
Masquerade: true,
|
||||||
Metric: 9999,
|
Metric: 9999,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: re-pointing the router peer did not refresh the old routing peer")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: re-pointing the router peer did not refresh the old routing peer")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,148 +165,154 @@ func (s *routerScenario) createPostureCheckGatedPolicy(t *testing.T, ctx context
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_E2E_SavePostureCheck_RefreshesRoutingPeer(t *testing.T) {
|
func TestAffectedPeers_E2E_SavePostureCheck_RefreshesRoutingPeer(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
checkID := s.createPostureCheckGatedPolicy(t, ctx, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID))
|
checkID := s.createPostureCheckGatedPolicy(t, ctx, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID))
|
||||||
|
|
||||||
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
||||||
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
||||||
unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID)
|
unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.unrelatedPeerID)
|
s.updateManager.CloseChannel(ctx, s.unrelatedPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, srcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerCh)
|
||||||
|
peerShouldNotReceiveUpdate(t, unrelatedCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := s.manager.SavePostureChecks(ctx, s.accountID, userID, &posture.Checks{
|
||||||
|
ID: checkID,
|
||||||
|
Name: "rs-min-version",
|
||||||
|
Checks: posture.ChecksDefinition{
|
||||||
|
NBVersionCheck: &posture.NBVersionCheck{MinVersion: "0.31.0"},
|
||||||
|
},
|
||||||
|
}, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: editing a posture check did not refresh source + routing peers")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, srcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerCh)
|
|
||||||
peerShouldNotReceiveUpdate(t, unrelatedCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err := s.manager.SavePostureChecks(ctx, s.accountID, userID, &posture.Checks{
|
|
||||||
ID: checkID,
|
|
||||||
Name: "rs-min-version",
|
|
||||||
Checks: posture.ChecksDefinition{
|
|
||||||
NBVersionCheck: &posture.NBVersionCheck{MinVersion: "0.31.0"},
|
|
||||||
},
|
|
||||||
}, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: editing a posture check did not refresh source + routing peers")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_E2E_UpdateResource_DestinationResourcePolicy_RefreshesSourcePeer(t *testing.T) {
|
func TestAffectedPeers_E2E_UpdateResource_DestinationResourcePolicy_RefreshesSourcePeer(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
|
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
resourcesManager, _, _ := s.managers()
|
resourcesManager, _, _ := s.managers()
|
||||||
|
|
||||||
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
||||||
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
||||||
unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID)
|
unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.unrelatedPeerID)
|
s.updateManager.CloseChannel(ctx, s.unrelatedPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, srcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerCh)
|
||||||
|
peerShouldNotReceiveUpdate(t, unrelatedCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
||||||
|
ID: s.resourceID,
|
||||||
|
AccountID: s.accountID,
|
||||||
|
NetworkID: s.networkID,
|
||||||
|
Name: "rs-resource-host",
|
||||||
|
Address: "10.20.30.0/25",
|
||||||
|
GroupIDs: []string{s.resourceGroupID},
|
||||||
|
Enabled: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: updating a DestinationResource-targeted resource did not refresh its policy source peer")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, srcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerCh)
|
|
||||||
peerShouldNotReceiveUpdate(t, unrelatedCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
|
||||||
ID: s.resourceID,
|
|
||||||
AccountID: s.accountID,
|
|
||||||
NetworkID: s.networkID,
|
|
||||||
Name: "rs-resource-host",
|
|
||||||
Address: "10.20.30.0/25",
|
|
||||||
GroupIDs: []string{s.resourceGroupID},
|
|
||||||
Enabled: true,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: updating a DestinationResource-targeted resource did not refresh its policy source peer")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A disabled sibling router routes to nobody, so updating a resource on its network
|
// A disabled sibling router routes to nobody, so updating a resource on its network
|
||||||
// must NOT refresh its peer (the enabled router carries the bridge instead).
|
// must NOT refresh its peer (the enabled router carries the bridge instead).
|
||||||
func TestAffectedPeers_E2E_UpdateResource_DisabledSiblingRouterNotBridged(t *testing.T) {
|
func TestAffectedPeers_E2E_UpdateResource_DisabledSiblingRouterNotBridged(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
resourcesManager, routersManager, _ := s.managers()
|
resourcesManager, routersManager, _ := s.managers()
|
||||||
|
|
||||||
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-key-disabled", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-key-disabled", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
disabledRouterPeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
|
disabledRouterPeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
|
||||||
_, err = routersManager.CreateRouter(ctx, userID, &routerTypes.NetworkRouter{
|
_, err = routersManager.CreateRouter(ctx, userID, &routerTypes.NetworkRouter{
|
||||||
NetworkID: s.networkID,
|
NetworkID: s.networkID,
|
||||||
AccountID: s.accountID,
|
AccountID: s.accountID,
|
||||||
Peer: disabledRouterPeer.ID,
|
Peer: disabledRouterPeer.ID,
|
||||||
Masquerade: true,
|
Masquerade: true,
|
||||||
Metric: 9000,
|
Metric: 9000,
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
disabledCh := s.updateManager.CreateChannel(ctx, disabledRouterPeer.ID)
|
||||||
|
enabledCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
s.updateManager.CloseChannel(ctx, disabledRouterPeer.ID)
|
||||||
|
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(disabledCh, enabledCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, enabledCh)
|
||||||
|
peerShouldNotReceiveUpdate(t, disabledCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
||||||
|
ID: s.resourceID,
|
||||||
|
AccountID: s.accountID,
|
||||||
|
NetworkID: s.networkID,
|
||||||
|
Name: "rs-resource-host",
|
||||||
|
Address: "10.20.30.0/25",
|
||||||
|
GroupIDs: []string{s.resourceGroupID},
|
||||||
|
Enabled: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
disabledCh := s.updateManager.CreateChannel(ctx, disabledRouterPeer.ID)
|
|
||||||
enabledCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
s.updateManager.CloseChannel(ctx, disabledRouterPeer.ID)
|
|
||||||
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
|
||||||
})
|
|
||||||
|
|
||||||
settleAffectedUpdates(disabledCh, enabledCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, enabledCh)
|
|
||||||
peerShouldNotReceiveUpdate(t, disabledCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
|
||||||
ID: s.resourceID,
|
|
||||||
AccountID: s.accountID,
|
|
||||||
NetworkID: s.networkID,
|
|
||||||
Name: "rs-resource-host",
|
|
||||||
Address: "10.20.30.0/25",
|
|
||||||
GroupIDs: []string{s.resourceGroupID},
|
|
||||||
Enabled: true,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_GroupChange_RouterInOtherNetworkNotAffected(t *testing.T) {
|
func TestAffectedPeers_GroupChange_RouterInOtherNetworkNotAffected(t *testing.T) {
|
||||||
@@ -346,8 +352,10 @@ func TestAffectedPeers_PeerChange_RouterInOtherNetworkNotAffected(t *testing.T)
|
|||||||
// shortcut (the denied peer's map holds no router) and the allow direction
|
// shortcut (the denied peer's map holds no router) and the allow direction
|
||||||
// depends on which meta field moved, leaving the routers with a stale map.
|
// depends on which meta field moved, leaving the routers with a stale map.
|
||||||
func TestAffectedPeers_E2E_PostureFlip_RefreshesRoutingPeer(t *testing.T) {
|
func TestAffectedPeers_E2E_PostureFlip_RefreshesRoutingPeer(t *testing.T) {
|
||||||
runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy {
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
return peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID)
|
runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy {
|
||||||
|
return peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,8 +363,10 @@ func TestAffectedPeers_E2E_PostureFlip_RefreshesRoutingPeer(t *testing.T) {
|
|||||||
// scenario with the source peer named directly in the rule: it must receive its posture
|
// scenario with the source peer named directly in the rule: it must receive its posture
|
||||||
// checks and have its flips detected exactly like a group member.
|
// checks and have its flips detected exactly like a group member.
|
||||||
func TestAffectedPeers_E2E_PostureFlip_DirectSourcePeer_RefreshesRoutingPeer(t *testing.T) {
|
func TestAffectedPeers_E2E_PostureFlip_DirectSourcePeer_RefreshesRoutingPeer(t *testing.T) {
|
||||||
runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy {
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
return peerToResourcePolicyByPeer(s.sourcePeerID, s.resourceGroupID)
|
runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy {
|
||||||
|
return peerToResourcePolicyByPeer(s.sourcePeerID, s.resourceGroupID)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/internals/controllers/network_map"
|
|
||||||
"github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel"
|
"github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel"
|
||||||
"github.com/netbirdio/netbird/management/server/affectedpeers"
|
"github.com/netbirdio/netbird/management/server/affectedpeers"
|
||||||
"github.com/netbirdio/netbird/management/server/groups"
|
"github.com/netbirdio/netbird/management/server/groups"
|
||||||
@@ -320,190 +319,189 @@ func TestAffectedPeers_PolicyToResource_UnrelatedPeerNotAffected(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_ResourceSideBridgesToRoutingPeer_DirectRouter(t *testing.T) {
|
func TestAffectedPeers_ResourceSideBridgesToRoutingPeer_DirectRouter(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
// A pre-existing policy grants the source group access to the resource.
|
// A pre-existing policy grants the source group access to the resource.
|
||||||
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Drive an update through the resource manager and assert the routing peer
|
// Drive an update through the resource manager and assert the routing peer
|
||||||
// is among the affected set by observing the channel. This path walks
|
// is among the affected set by observing the channel. This path walks
|
||||||
// policies whose destinations reference the resource's groups, folds in the
|
// policies whose destinations reference the resource's groups, folds in the
|
||||||
// source groups, and loads the network's routers, so it reaches both the
|
// source groups, and loads the network's routers, so it reaches both the
|
||||||
// source peer and the routing peer.
|
// source peer and the routing peer.
|
||||||
permissionsManager := permissions.NewManager(s.manager.Store)
|
permissionsManager := permissions.NewManager(s.manager.Store)
|
||||||
groupsManager := groups.NewManager(s.manager.Store, permissionsManager, s.manager)
|
groupsManager := groups.NewManager(s.manager.Store, permissionsManager, s.manager)
|
||||||
rm := resources.NewManager(s.manager.Store, permissionsManager, groupsManager, s.manager, s.manager.serviceManager)
|
rm := resources.NewManager(s.manager.Store, permissionsManager, groupsManager, s.manager, s.manager.serviceManager)
|
||||||
|
|
||||||
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
||||||
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(srcCh, routerCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, srcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = rm.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
||||||
|
ID: s.resourceID,
|
||||||
|
AccountID: s.accountID,
|
||||||
|
NetworkID: s.networkID,
|
||||||
|
Name: "rs-resource-host",
|
||||||
|
Address: "10.20.30.0/24",
|
||||||
|
GroupIDs: []string{s.resourceGroupID},
|
||||||
|
Enabled: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: resource update did not refresh source peer + routing peer")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, srcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = rm.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
|
|
||||||
ID: s.resourceID,
|
|
||||||
AccountID: s.accountID,
|
|
||||||
NetworkID: s.networkID,
|
|
||||||
Name: "rs-resource-host",
|
|
||||||
Address: "10.20.30.0/24",
|
|
||||||
GroupIDs: []string{s.resourceGroupID},
|
|
||||||
Enabled: true,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: resource update did not refresh source peer + routing peer")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// settleAffectedUpdates waits for in-flight async updates to arrive, then drains
|
|
||||||
// every given channel so subsequent assertions start from a clean slate.
|
|
||||||
//
|
|
||||||
// Setup (CreateNetwork/CreateResource/CreateRouter) fires async UpdateAffectedPeers
|
|
||||||
// goroutines; draining first means the assertion only observes updates from the
|
|
||||||
// action under test, not setup stragglers.
|
|
||||||
func settleAffectedUpdates(chans ...<-chan *network_map.UpdateMessage) {
|
|
||||||
time.Sleep(300 * time.Millisecond)
|
|
||||||
for _, ch := range chans {
|
|
||||||
drainPeerUpdates(ch)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_DirectRouter(t *testing.T) {
|
func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_DirectRouter(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
||||||
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
||||||
unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID)
|
unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.unrelatedPeerID)
|
s.updateManager.CloseChannel(ctx, s.unrelatedPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, srcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerCh)
|
||||||
|
peerShouldNotReceiveUpdate(t, unrelatedCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: creating peer->resource policy did not refresh the routing peer")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, srcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerCh)
|
|
||||||
peerShouldNotReceiveUpdate(t, unrelatedCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: creating peer->resource policy did not refresh the routing peer")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_RouterPeerGroups(t *testing.T) {
|
func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_RouterPeerGroups(t *testing.T) {
|
||||||
s := setupRouterScenario(t, false)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, false)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
||||||
routerCh := s.updateManager.CreateChannel(ctx, s.routerGroupPeerID)
|
routerCh := s.updateManager.CreateChannel(ctx, s.routerGroupPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerGroupPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerGroupPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(srcCh, routerCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, srcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: routing peer (PeerGroups) not refreshed on policy create")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
settleAffectedUpdates(srcCh, routerCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, srcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: routing peer (PeerGroups) not refreshed on policy create")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_E2E_DestResource_RoutingPeer(t *testing.T) {
|
func TestAffectedPeers_E2E_DestResource_RoutingPeer(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
||||||
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(srcCh, routerCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, srcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: routing peer not refreshed when policy targets DestinationResource")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
settleAffectedUpdates(srcCh, routerCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, srcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: routing peer not refreshed when policy targets DestinationResource")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_E2E_DeletePolicy_RoutingPeer(t *testing.T) {
|
func TestAffectedPeers_E2E_DeletePolicy_RoutingPeer(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
||||||
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(srcCh, routerCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, srcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
require.NoError(t, s.manager.DeletePolicy(ctx, s.accountID, policy.ID, userID))
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: deleting peer->resource policy did not refresh the routing peer")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
settleAffectedUpdates(srcCh, routerCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, srcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
require.NoError(t, s.manager.DeletePolicy(ctx, s.accountID, policy.ID, userID))
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: deleting peer->resource policy did not refresh the routing peer")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *routerScenario) managers() (resources.Manager, routers.Manager, networks.Manager) {
|
func (s *routerScenario) managers() (resources.Manager, routers.Manager, networks.Manager) {
|
||||||
@@ -572,113 +570,119 @@ func (s *routerScenario) addSecondTopology(t *testing.T, suffix string) secondTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_E2E_UpdatePolicy_BothRoutingPeers(t *testing.T) {
|
func TestAffectedPeers_E2E_UpdatePolicy_BothRoutingPeers(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
second := s.addSecondTopology(t, "b")
|
s := setupRouterScenario(t, true)
|
||||||
ctx := context.Background()
|
second := s.addSecondTopology(t, "b")
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
||||||
routerACh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
routerACh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
||||||
routerBCh := s.updateManager.CreateChannel(ctx, second.routerPeerID)
|
routerBCh := s.updateManager.CreateChannel(ctx, second.routerPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
||||||
s.updateManager.CloseChannel(ctx, second.routerPeerID)
|
s.updateManager.CloseChannel(ctx, second.routerPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(srcCh, routerACh, routerBCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, srcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerACh)
|
||||||
|
peerShouldReceiveUpdate(t, routerBCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
policy.Rules[0].Destinations = []string{second.resourceGroupID}
|
||||||
|
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, policy, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: re-pointing the policy destination did not refresh both routing peers")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
settleAffectedUpdates(srcCh, routerACh, routerBCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, srcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerACh)
|
|
||||||
peerShouldReceiveUpdate(t, routerBCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policy.Rules[0].Destinations = []string{second.resourceGroupID}
|
|
||||||
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, policy, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: re-pointing the policy destination did not refresh both routing peers")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_E2E_UpdatePolicy_AddSource(t *testing.T) {
|
func TestAffectedPeers_E2E_UpdatePolicy_AddSource(t *testing.T) {
|
||||||
s := setupRouterScenario(t, true)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, true)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
const secondSourceGroupID = "rs-source-grp-2"
|
const secondSourceGroupID = "rs-source-grp-2"
|
||||||
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-key-2", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-key-2", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
secondSourcePeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
|
secondSourcePeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
|
||||||
require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{
|
require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{
|
||||||
ID: secondSourceGroupID, Name: "rs-source-2", Peers: []string{secondSourcePeer.ID},
|
ID: secondSourceGroupID, Name: "rs-source-2", Peers: []string{secondSourcePeer.ID},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
newSrcCh := s.updateManager.CreateChannel(ctx, secondSourcePeer.ID)
|
newSrcCh := s.updateManager.CreateChannel(ctx, secondSourcePeer.ID)
|
||||||
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, secondSourcePeer.ID)
|
s.updateManager.CloseChannel(ctx, secondSourcePeer.ID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(newSrcCh, routerCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, newSrcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
policy.Rules[0].Sources = []string{s.sourceGroupID, secondSourceGroupID}
|
||||||
|
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, policy, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: adding a source group did not refresh the new source peer + routing peer")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
settleAffectedUpdates(newSrcCh, routerCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, newSrcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policy.Rules[0].Sources = []string{s.sourceGroupID, secondSourceGroupID}
|
|
||||||
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, policy, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: adding a source group did not refresh the new source peer + routing peer")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_E2E_DestResource_RouterPeerGroups(t *testing.T) {
|
func TestAffectedPeers_E2E_DestResource_RouterPeerGroups(t *testing.T) {
|
||||||
s := setupRouterScenario(t, false)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
s := setupRouterScenario(t, false)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
|
||||||
routerCh := s.updateManager.CreateChannel(ctx, s.routerGroupPeerID)
|
routerCh := s.updateManager.CreateChannel(ctx, s.routerGroupPeerID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
s.updateManager.CloseChannel(ctx, s.sourcePeerID)
|
||||||
s.updateManager.CloseChannel(ctx, s.routerGroupPeerID)
|
s.updateManager.CloseChannel(ctx, s.routerGroupPeerID)
|
||||||
|
})
|
||||||
|
|
||||||
|
settleAffectedUpdates(srcCh, routerCh)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, srcCh)
|
||||||
|
peerShouldReceiveUpdate(t, routerCh)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout: DestinationResource policy with PeerGroups router did not refresh the routing peer")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
settleAffectedUpdates(srcCh, routerCh)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, srcCh)
|
|
||||||
peerShouldReceiveUpdate(t, routerCh)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout: DestinationResource policy with PeerGroups router did not refresh the routing peer")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAffectedPeers_AllRoutingPeers_Network(t *testing.T) {
|
func TestAffectedPeers_AllRoutingPeers_Network(t *testing.T) {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,156 +17,152 @@ import (
|
|||||||
// A user update refreshes only the peers its auto-group change reaches, and a user
|
// A user update refreshes only the peers its auto-group change reaches, and a user
|
||||||
// update that changes no group membership refreshes nobody.
|
// update that changes no group membership refreshes nobody.
|
||||||
func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) {
|
func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) {
|
||||||
manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
accountID := account.Id
|
ctx := context.Background()
|
||||||
|
accountID := account.Id
|
||||||
|
|
||||||
const targetUserID = "target-user"
|
const targetUserID = "target-user"
|
||||||
require.NoError(t, manager.Store.SaveUser(ctx, &types.User{
|
require.NoError(t, manager.Store.SaveUser(ctx, &types.User{
|
||||||
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
targetPeer, _, _, _, err := manager.AddPeer(ctx, accountID, "", targetUserID, &nbpeer.Peer{
|
targetPeer, _, _, _, err := manager.AddPeer(ctx, accountID, "", targetUserID, &nbpeer.Peer{
|
||||||
Key: key.PublicKey().String(),
|
Key: key.PublicKey().String(),
|
||||||
Meta: nbpeer.PeerSystemMeta{Hostname: "target-peer"},
|
Meta: nbpeer.PeerSystemMeta{Hostname: "target-peer"},
|
||||||
}, false)
|
}, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
policies, err := manager.Store.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID)
|
policies, err := manager.Store.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for _, p := range policies {
|
for _, p := range policies {
|
||||||
require.NoError(t, manager.Store.DeletePolicy(ctx, accountID, p.ID))
|
require.NoError(t, manager.Store.DeletePolicy(ctx, accountID, p.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err = manager.Store.GetAccount(ctx, accountID)
|
account, err = manager.Store.GetAccount(ctx, accountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
account.Settings.GroupsPropagationEnabled = true
|
account.Settings.GroupsPropagationEnabled = true
|
||||||
require.NoError(t, manager.Store.SaveAccount(ctx, account))
|
require.NoError(t, manager.Store.SaveAccount(ctx, account))
|
||||||
|
|
||||||
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-linked", Name: "ug-linked"}))
|
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-linked", Name: "ug-linked"}))
|
||||||
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-dest", Name: "ug-dest", Peers: []string{peer2.ID}}))
|
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-dest", Name: "ug-dest", Peers: []string{peer2.ID}}))
|
||||||
|
|
||||||
_, err = manager.SavePolicy(ctx, accountID, userID, &types.Policy{
|
_, err = manager.SavePolicy(ctx, accountID, userID, &types.Policy{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Rules: []*types.PolicyRule{
|
Rules: []*types.PolicyRule{
|
||||||
{
|
{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Sources: []string{"ug-linked"},
|
Sources: []string{"ug-linked"},
|
||||||
Destinations: []string{"ug-dest"},
|
Destinations: []string{"ug-dest"},
|
||||||
Bidirectional: true,
|
Bidirectional: true,
|
||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}, true)
|
||||||
}, true)
|
require.NoError(t, err)
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
updTarget := updateManager.CreateChannel(ctx, targetPeer.ID)
|
updTarget := updateManager.CreateChannel(ctx, targetPeer.ID)
|
||||||
upd2 := updateManager.CreateChannel(ctx, peer2.ID)
|
upd2 := updateManager.CreateChannel(ctx, peer2.ID)
|
||||||
upd3 := updateManager.CreateChannel(ctx, peer3.ID)
|
upd3 := updateManager.CreateChannel(ctx, peer3.ID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
updateManager.CloseChannel(ctx, targetPeer.ID)
|
updateManager.CloseChannel(ctx, targetPeer.ID)
|
||||||
updateManager.CloseChannel(ctx, peer2.ID)
|
updateManager.CloseChannel(ctx, peer2.ID)
|
||||||
updateManager.CloseChannel(ctx, peer3.ID)
|
updateManager.CloseChannel(ctx, peer3.ID)
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("auto group change updates only linked peers", func(t *testing.T) {
|
|
||||||
drainPeerUpdates(updTarget)
|
|
||||||
drainPeerUpdates(upd2)
|
|
||||||
drainPeerUpdates(upd3)
|
|
||||||
|
|
||||||
_, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
|
|
||||||
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
|
||||||
AutoGroups: []string{"ug-linked"},
|
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
peerShouldReceiveUpdate(t, updTarget)
|
step(t, "auto group change updates only linked peers", func(t *testing.T) {
|
||||||
peerShouldReceiveUpdate(t, upd2)
|
settleAffectedUpdates(updTarget, upd2, upd3)
|
||||||
peerShouldNotReceiveUpdate(t, upd3)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("update without group changes refreshes nobody", func(t *testing.T) {
|
_, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
|
||||||
drainPeerUpdates(updTarget)
|
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
||||||
drainPeerUpdates(upd2)
|
AutoGroups: []string{"ug-linked"},
|
||||||
drainPeerUpdates(upd3)
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
|
peerShouldReceiveUpdate(t, updTarget)
|
||||||
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
peerShouldReceiveUpdate(t, upd2)
|
||||||
AutoGroups: []string{"ug-linked"}, Name: "renamed",
|
peerShouldNotReceiveUpdate(t, upd3)
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
peerShouldNotReceiveUpdate(t, updTarget)
|
step(t, "update without group changes refreshes nobody", func(t *testing.T) {
|
||||||
peerShouldNotReceiveUpdate(t, upd2)
|
drainPeerUpdates(updTarget)
|
||||||
peerShouldNotReceiveUpdate(t, upd3)
|
drainPeerUpdates(upd2)
|
||||||
|
drainPeerUpdates(upd3)
|
||||||
|
|
||||||
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, targetUserID)
|
_, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
|
||||||
require.NoError(t, err)
|
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
||||||
assert.Equal(t, "renamed", user.Name)
|
AutoGroups: []string{"ug-linked"}, Name: "renamed",
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("auto group change reassigning IPv6 refreshes the changed peers and their observers", func(t *testing.T) {
|
peerShouldNotReceiveUpdate(t, updTarget)
|
||||||
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-v6", Name: "ug-v6"}))
|
peerShouldNotReceiveUpdate(t, upd2)
|
||||||
// Apply through the settings API so the reconciliation that strips the other
|
peerShouldNotReceiveUpdate(t, upd3)
|
||||||
|
|
||||||
|
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, targetUserID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "renamed", user.Name)
|
||||||
|
})
|
||||||
|
|
||||||
|
step(t, "auto group change reassigning IPv6 refreshes the changed peers and their observers", func(t *testing.T) {
|
||||||
|
|
||||||
|
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-v6", Name: "ug-v6"}))// Apply through the settings API so the reconciliation that strips the other
|
||||||
// peers' addresses happens here, leaving the target as the only peer the
|
// peers' addresses happens here, leaving the target as the only peer the
|
||||||
// user update reassigns.
|
// user update reassigns.
|
||||||
updateIPv6TestSettings(t, manager, accountID, func(s *types.Settings) {
|
updateIPv6TestSettings(t, manager, accountID, func(s *types.Settings) {
|
||||||
s.IPv6EnabledGroups = []string{"ug-v6"}
|
s.IPv6EnabledGroups = []string{"ug-v6"}
|
||||||
})
|
})
|
||||||
|
|
||||||
drainPeerUpdates(updTarget)
|
settleAffectedUpdates(updTarget, upd2, upd3)
|
||||||
drainPeerUpdates(upd2)
|
|
||||||
drainPeerUpdates(upd3)
|
|
||||||
|
|
||||||
_, err = manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
|
_, err = manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
|
||||||
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
||||||
AutoGroups: []string{"ug-linked", "ug-v6"}, Name: "renamed",
|
AutoGroups: []string{"ug-linked", "ug-v6"}, Name: "renamed",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// The reassigned peer refreshes with everyone it can reach: peer2 via the
|
||||||
|
// policy, but not peer3, which shares no group or policy with it.
|
||||||
|
peerShouldReceiveUpdate(t, updTarget)
|
||||||
|
peerShouldReceiveUpdate(t, upd2)
|
||||||
|
peerShouldNotReceiveUpdate(t, upd3)
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// The reassigned peer refreshes with everyone it can reach: peer2 via the
|
step(t, "unblocking a user refreshes only the SSH rule destinations", func(t *testing.T) {
|
||||||
// policy, but not peer3, which shares no group or policy with it.
|
// An SSH rule that authorizes no group of its own ships the account's
|
||||||
peerShouldReceiveUpdate(t, updTarget)
|
// allowed-user set to its destinations, so those are the peers an unblock
|
||||||
peerShouldReceiveUpdate(t, upd2)
|
// reaches — not the whole account.
|
||||||
peerShouldNotReceiveUpdate(t, upd3)
|
_, err := manager.SavePolicy(ctx, accountID, userID, &types.Policy{
|
||||||
})
|
Enabled: true,
|
||||||
|
Rules: []*types.PolicyRule{{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"ug-linked"},
|
||||||
|
Destinations: []string{"ug-dest"},
|
||||||
|
Protocol: types.PolicyRuleProtocolNetbirdSSH,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
}},
|
||||||
|
}, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("unblocking a user refreshes only the SSH rule destinations", func(t *testing.T) {
|
blocked, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, targetUserID)
|
||||||
// An SSH rule that authorizes no group of its own ships the account's
|
require.NoError(t, err)
|
||||||
// allowed-user set to its destinations, so those are the peers an unblock
|
blocked.Blocked = true
|
||||||
// reaches — not the whole account.
|
require.NoError(t, manager.Store.SaveUser(ctx, blocked))
|
||||||
_, err := manager.SavePolicy(ctx, accountID, userID, &types.Policy{
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{{
|
|
||||||
Enabled: true,
|
|
||||||
Sources: []string{"ug-linked"},
|
|
||||||
Destinations: []string{"ug-dest"},
|
|
||||||
Protocol: types.PolicyRuleProtocolNetbirdSSH,
|
|
||||||
Action: types.PolicyTrafficActionAccept,
|
|
||||||
}},
|
|
||||||
}, true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
blocked, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, targetUserID)
|
settleAffectedUpdates(updTarget, upd2, upd3)
|
||||||
require.NoError(t, err)
|
|
||||||
blocked.Blocked = true
|
|
||||||
require.NoError(t, manager.Store.SaveUser(ctx, blocked))
|
|
||||||
|
|
||||||
drainPeerUpdates(updTarget)
|
// Same auto-groups as the previous subtest left them, so no group change and
|
||||||
drainPeerUpdates(upd2)
|
// no IPv6 reconciliation interferes: the unblock alone drives the refresh.
|
||||||
drainPeerUpdates(upd3)
|
_, err = manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
|
||||||
|
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
||||||
|
AutoGroups: []string{"ug-linked", "ug-v6"}, Name: "renamed",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Same auto-groups as the previous subtest left them, so no group change and
|
peerShouldReceiveUpdate(t, upd2)
|
||||||
// no IPv6 reconciliation interferes: the unblock alone drives the refresh.
|
peerShouldNotReceiveUpdate(t, upd3)
|
||||||
_, err = manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
|
|
||||||
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
|
|
||||||
AutoGroups: []string{"ug-linked", "ug-v6"}, Name: "renamed",
|
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
peerShouldReceiveUpdate(t, upd2)
|
|
||||||
peerShouldNotReceiveUpdate(t, upd3)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+9
-3
@@ -88,7 +88,8 @@ func NewUserDataCache(store store.StoreInterface) *UserDataCacheImpl {
|
|||||||
|
|
||||||
// AccountUserDataCache wraps the basic Get, Set and Delete methods for []*idp.UserData objects.
|
// AccountUserDataCache wraps the basic Get, Set and Delete methods for []*idp.UserData objects.
|
||||||
type AccountUserDataCache struct {
|
type AccountUserDataCache struct {
|
||||||
cache Marshaler
|
cache Marshaler
|
||||||
|
loadable *cache.LoadableCache[any]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AccountUserDataCache) Get(ctx context.Context, key string) ([]*idp.UserData, error) {
|
func (a *AccountUserDataCache) Get(ctx context.Context, key string) ([]*idp.UserData, error) {
|
||||||
@@ -127,13 +128,18 @@ func (a *AccountUserDataCache) Delete(ctx context.Context, key string) error {
|
|||||||
return a.cache.Delete(ctx, key)
|
return a.cache.Delete(ctx, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close stops the goroutine that stores loaded values. The cache must not be used afterwards.
|
||||||
|
func (a *AccountUserDataCache) Close() error {
|
||||||
|
return a.loadable.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// NewAccountUserDataCache creates a new AccountUserDataCache object.
|
// NewAccountUserDataCache creates a new AccountUserDataCache object.
|
||||||
func NewAccountUserDataCache(loadableFunc cache.LoadFunction[any], store store.StoreInterface) *AccountUserDataCache {
|
func NewAccountUserDataCache(loadableFunc cache.LoadFunction[any], store store.StoreInterface) *AccountUserDataCache {
|
||||||
simpleCache := cache.New[any](store)
|
simpleCache := cache.New[any](store)
|
||||||
loadable := cache.NewLoadable[any](loadableFunc, simpleCache)
|
loadable := cache.NewLoadable[any](loadableFunc, simpleCache)
|
||||||
if store.GetType() == redis.RedisType {
|
if store.GetType() == redis.RedisType {
|
||||||
m := marshaler.New(loadable)
|
m := marshaler.New(loadable)
|
||||||
return &AccountUserDataCache{cache: m}
|
return &AccountUserDataCache{cache: m, loadable: loadable}
|
||||||
}
|
}
|
||||||
return &AccountUserDataCache{cache: &marshalerWraper{loadable}}
|
return &AccountUserDataCache{cache: &marshalerWraper{loadable}, loadable: loadable}
|
||||||
}
|
}
|
||||||
|
|||||||
+144
-140
@@ -6,8 +6,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"go.uber.org/mock/gomock"
|
||||||
|
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
|
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
|
||||||
@@ -363,163 +363,167 @@ func initTestDNSAccount(t *testing.T, am *DefaultAccountManager) (*types.Account
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDNSAccountPeersUpdate(t *testing.T) {
|
func TestDNSAccountPeersUpdate(t *testing.T) {
|
||||||
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
|
|
||||||
err := manager.CreateGroups(context.Background(), account.Id, userID, []*types.Group{
|
err := manager.CreateGroups(context.Background(), account.Id, userID, []*types.Group{
|
||||||
{
|
{
|
||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "groupB",
|
ID: "groupB",
|
||||||
Name: "GroupB",
|
Name: "GroupB",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
updateManager.CloseChannel(context.Background(), peer1.ID)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Saving DNS settings with groups that have no peers should not trigger updates to account peers or send peer updates
|
|
||||||
t.Run("saving dns setting with unused groups", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
|
||||||
DisabledManagementGroups: []string{"groupA"},
|
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
case <-done:
|
t.Cleanup(func() {
|
||||||
case <-time.After(time.Second):
|
updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Creating DNS settings with groups that have no peers should not update account peers or send peer update
|
|
||||||
t.Run("creating dns setting with unused groups", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = manager.CreateNameServerGroup(
|
|
||||||
context.Background(), account.Id, "ns-group", "ns-group", []nbdns.NameServer{{
|
|
||||||
IP: netip.MustParseAddr(peer1.IP.String()),
|
|
||||||
NSType: nbdns.UDPNameServerType,
|
|
||||||
Port: nbdns.DefaultDNSPort,
|
|
||||||
}},
|
|
||||||
[]string{"groupB"},
|
|
||||||
true, []string{}, true, userID, false,
|
|
||||||
)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Creating DNS settings with groups that have peers should update account peers and send peer update
|
|
||||||
t.Run("creating dns setting with used groups", func(t *testing.T) {
|
|
||||||
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
|
||||||
ID: "groupA",
|
|
||||||
Name: "GroupA",
|
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
// Saving DNS settings with groups that have no peers should not trigger updates to account peers or send peer updates
|
||||||
go func() {
|
step(t, "saving dns setting with unused groups", func(t *testing.T) {
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
settleAffectedUpdates(updMsg)
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = manager.CreateNameServerGroup(
|
done := make(chan struct{})
|
||||||
context.Background(), account.Id, "ns-group-1", "ns-group-1", []nbdns.NameServer{{
|
go func() {
|
||||||
IP: netip.MustParseAddr(peer1.IP.String()),
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
NSType: nbdns.UDPNameServerType,
|
close(done)
|
||||||
Port: nbdns.DefaultDNSPort,
|
}()
|
||||||
}},
|
|
||||||
[]string{"groupA"},
|
|
||||||
true, []string{}, true, userID, false,
|
|
||||||
)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
||||||
case <-done:
|
DisabledManagementGroups: []string{"groupA"},
|
||||||
case <-time.After(peerUpdateTimeout):
|
})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
assert.NoError(t, err)
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Saving DNS settings with groups that have peers should update account peers and send peer update
|
select {
|
||||||
t.Run("saving dns setting with used groups", func(t *testing.T) {
|
case <-done:
|
||||||
done := make(chan struct{})
|
case <-time.After(time.Second):
|
||||||
go func() {
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
}
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
|
||||||
DisabledManagementGroups: []string{"groupA", "groupB"},
|
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// Creating DNS settings with groups that have no peers should not update account peers or send peer update
|
||||||
case <-done:
|
step(t, "creating dns setting with unused groups", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
})
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
// Removing group with no peers from DNS settings should not trigger updates to account peers or send peer updates
|
_, err = manager.CreateNameServerGroup(
|
||||||
t.Run("removing group with no peers from dns settings", func(t *testing.T) {
|
context.Background(), account.Id, "ns-group", "ns-group", []nbdns.NameServer{{
|
||||||
done := make(chan struct{})
|
IP: netip.MustParseAddr(peer1.IP.String()),
|
||||||
go func() {
|
NSType: nbdns.UDPNameServerType,
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
Port: nbdns.DefaultDNSPort,
|
||||||
close(done)
|
}},
|
||||||
}()
|
[]string{"groupB"},
|
||||||
|
true, []string{}, true, userID, false,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
select {
|
||||||
DisabledManagementGroups: []string{"groupA"},
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// Creating DNS settings with groups that have peers should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "creating dns setting with used groups", func(t *testing.T) {
|
||||||
case <-time.After(time.Second):
|
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
ID: "groupA",
|
||||||
}
|
Name: "GroupA",
|
||||||
})
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Removing group with peers from DNS settings should trigger updates to account peers and send peer updates
|
done := make(chan struct{})
|
||||||
t.Run("removing group with peers from dns settings", func(t *testing.T) {
|
go func() {
|
||||||
done := make(chan struct{})
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
go func() {
|
close(done)
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
}()
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
_, err = manager.CreateNameServerGroup(
|
||||||
DisabledManagementGroups: []string{},
|
context.Background(), account.Id, "ns-group-1", "ns-group-1", []nbdns.NameServer{{
|
||||||
|
IP: netip.MustParseAddr(peer1.IP.String()),
|
||||||
|
NSType: nbdns.UDPNameServerType,
|
||||||
|
Port: nbdns.DefaultDNSPort,
|
||||||
|
}},
|
||||||
|
[]string{"groupA"},
|
||||||
|
true, []string{}, true, userID, false,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// Saving DNS settings with groups that have peers should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "saving dns setting with used groups", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
||||||
|
DisabledManagementGroups: []string{"groupA", "groupB"},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Removing group with no peers from DNS settings should not trigger updates to account peers or send peer updates
|
||||||
|
step(t, "removing group with no peers from dns settings", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
||||||
|
DisabledManagementGroups: []string{"groupA"},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Removing group with peers from DNS settings should trigger updates to account peers and send peer updates
|
||||||
|
step(t, "removing group with peers from dns settings", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
||||||
|
DisabledManagementGroups: []string{},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+331
-304
@@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/groups"
|
"github.com/netbirdio/netbird/management/server/groups"
|
||||||
"github.com/netbirdio/netbird/management/server/networks"
|
"github.com/netbirdio/netbird/management/server/networks"
|
||||||
"github.com/netbirdio/netbird/management/server/networks/resources"
|
"github.com/netbirdio/netbird/management/server/networks/resources"
|
||||||
|
resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types"
|
||||||
"github.com/netbirdio/netbird/management/server/networks/routers"
|
"github.com/netbirdio/netbird/management/server/networks/routers"
|
||||||
routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types"
|
routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types"
|
||||||
networkTypes "github.com/netbirdio/netbird/management/server/networks/types"
|
networkTypes "github.com/netbirdio/netbird/management/server/networks/types"
|
||||||
@@ -685,342 +686,368 @@ func initTestGroupAccount(am *DefaultAccountManager) (*DefaultAccountManager, *t
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGroupAccountPeersUpdate(t *testing.T) {
|
func TestGroupAccountPeersUpdate(t *testing.T) {
|
||||||
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
|
|
||||||
g := []*types.Group{
|
g := []*types.Group{
|
||||||
{
|
|
||||||
ID: "groupA",
|
|
||||||
Name: "GroupA",
|
|
||||||
Peers: []string{peer1.ID, peer2.ID},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupB",
|
|
||||||
Name: "GroupB",
|
|
||||||
Peers: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupC",
|
|
||||||
Name: "GroupC",
|
|
||||||
Peers: []string{peer1.ID, peer3.ID},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupD",
|
|
||||||
Name: "GroupD",
|
|
||||||
Peers: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupE",
|
|
||||||
Name: "GroupE",
|
|
||||||
Peers: []string{peer2.ID},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, group := range g {
|
|
||||||
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
updateManager.CloseChannel(context.Background(), peer1.ID)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Saving a group that is not linked to any resource should not update account peers
|
|
||||||
t.Run("saving unlinked group", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
|
||||||
ID: "groupB",
|
|
||||||
Name: "GroupB",
|
|
||||||
Peers: []string{peer1.ID, peer2.ID},
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Adding a peer to a group that is not linked to any resource should not update account peers
|
|
||||||
// and not send peer update
|
|
||||||
t.Run("adding peer to unlinked group", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.GroupAddPeer(context.Background(), account.Id, "groupB", peer3.ID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Removing a peer from a group that is not linked to any resource should not update account peers
|
|
||||||
// and not send peer update
|
|
||||||
t.Run("removing peer from unliked group", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.GroupDeletePeer(context.Background(), account.Id, "groupB", peer3.ID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deleting group should not update account peers and not send peer update
|
|
||||||
t.Run("deleting group", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.DeleteGroup(context.Background(), account.Id, userID, "groupB")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// adding a group to policy
|
|
||||||
_, err := manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{
|
|
||||||
{
|
{
|
||||||
Enabled: true,
|
ID: "groupA",
|
||||||
Sources: []string{"groupA"},
|
Name: "GroupA",
|
||||||
Destinations: []string{"groupA"},
|
Peers: []string{peer1.ID, peer2.ID},
|
||||||
Bidirectional: true,
|
},
|
||||||
Action: types.PolicyTrafficActionAccept,
|
{
|
||||||
|
ID: "groupB",
|
||||||
|
Name: "GroupB",
|
||||||
|
Peers: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "groupC",
|
||||||
|
Name: "GroupC",
|
||||||
|
Peers: []string{peer1.ID, peer3.ID},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "groupD",
|
||||||
|
Name: "GroupD",
|
||||||
|
Peers: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "groupE",
|
||||||
|
Name: "GroupE",
|
||||||
|
Peers: []string{peer2.ID},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
}, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Saving a group linked to policy should update account peers and send peer update
|
|
||||||
t.Run("saving linked group to policy", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
|
||||||
ID: "groupA",
|
|
||||||
Name: "GroupA",
|
|
||||||
Peers: []string{peer1.ID, peer2.ID},
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
}
|
||||||
})
|
for _, group := range g {
|
||||||
|
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
|
||||||
// adding peer to a used group should update account peers and send peer update
|
assert.NoError(t, err)
|
||||||
t.Run("adding peer to linked group", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.GroupAddPeer(context.Background(), account.Id, "groupA", peer3.ID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
// removing peer from a linked group should update account peers and send peer update
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
t.Run("removing peer from linked group", func(t *testing.T) {
|
t.Cleanup(func() {
|
||||||
done := make(chan struct{})
|
updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
go func() {
|
})
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.GroupDeletePeer(context.Background(), account.Id, "groupA", peer3.ID)
|
// Saving a group that is not linked to any resource should not update account peers
|
||||||
|
step(t, "saving unlinked group", func(t *testing.T) {
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
|
ID: "groupB",
|
||||||
|
Name: "GroupB",
|
||||||
|
Peers: []string{peer1.ID, peer2.ID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Adding a peer to a group that is not linked to any resource should not update account peers
|
||||||
|
// and not send peer update
|
||||||
|
step(t, "adding peer to unlinked group", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.GroupAddPeer(context.Background(), account.Id, "groupB", peer3.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Removing a peer from a group that is not linked to any resource should not update account peers
|
||||||
|
// and not send peer update
|
||||||
|
step(t, "removing peer from unliked group", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.GroupDeletePeer(context.Background(), account.Id, "groupB", peer3.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Deleting group should not update account peers and not send peer update
|
||||||
|
step(t, "deleting group", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.DeleteGroup(context.Background(), account.Id, userID, "groupB")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// adding a group to policy
|
||||||
|
_, err := manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []*types.PolicyRule{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupA"},
|
||||||
|
Destinations: []string{"groupA"},
|
||||||
|
Bidirectional: true,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
// Saving a group linked to policy should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "saving linked group to policy", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
settleAffectedUpdates(updMsg)
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Saving a group linked to name server group should update account peers and send peer update
|
done := make(chan struct{})
|
||||||
t.Run("saving group linked to name server group", func(t *testing.T) {
|
go func() {
|
||||||
_, err = manager.CreateNameServerGroup(
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{
|
close(done)
|
||||||
IP: netip.MustParseAddr("1.1.1.1"),
|
}()
|
||||||
NSType: nbdns.UDPNameServerType,
|
|
||||||
Port: nbdns.DefaultDNSPort,
|
|
||||||
}},
|
|
||||||
[]string{"groupC"},
|
|
||||||
true, nil, true, userID, false,
|
|
||||||
)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
go func() {
|
ID: "groupA",
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
Name: "GroupA",
|
||||||
close(done)
|
Peers: []string{peer1.ID, peer2.ID},
|
||||||
}()
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
select {
|
||||||
ID: "groupC",
|
case <-done:
|
||||||
Name: "GroupC",
|
case <-time.After(peerUpdateTimeout):
|
||||||
Peers: []string{peer1.ID, peer3.ID},
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// adding peer to a used group should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "adding peer to linked group", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
})
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
// Saving a group linked to route should update account peers and send peer update
|
err := manager.GroupAddPeer(context.Background(), account.Id, "groupA", peer3.ID)
|
||||||
t.Run("saving group linked to route", func(t *testing.T) {
|
assert.NoError(t, err)
|
||||||
newRoute := route.Route{
|
|
||||||
ID: "route",
|
|
||||||
Network: netip.MustParsePrefix("192.168.0.0/16"),
|
|
||||||
NetID: "superNet",
|
|
||||||
NetworkType: route.IPv4Network,
|
|
||||||
PeerGroups: []string{"groupA"},
|
|
||||||
Description: "super",
|
|
||||||
Masquerade: false,
|
|
||||||
Metric: 9999,
|
|
||||||
Enabled: true,
|
|
||||||
Groups: []string{"groupC"},
|
|
||||||
}
|
|
||||||
_, err := manager.CreateRoute(
|
|
||||||
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
|
|
||||||
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
|
|
||||||
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, newRoute.SkipAutoApply,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
select {
|
||||||
go func() {
|
case <-done:
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
case <-time.After(peerUpdateTimeout):
|
||||||
close(done)
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
}()
|
}
|
||||||
|
|
||||||
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
|
||||||
ID: "groupA",
|
|
||||||
Name: "GroupA",
|
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// removing peer from a linked group should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "removing peer from linked group", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
})
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
// Saving a group linked to dns settings should update account peers and send peer update
|
err := manager.GroupDeletePeer(context.Background(), account.Id, "groupA", peer3.ID)
|
||||||
t.Run("saving group linked to dns settings", func(t *testing.T) {
|
assert.NoError(t, err)
|
||||||
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
|
||||||
DisabledManagementGroups: []string{"groupD"},
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
// Saving a group linked to name server group should update account peers and send peer update
|
||||||
go func() {
|
step(t, "saving group linked to name server group", func(t *testing.T) {
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
_, err = manager.CreateNameServerGroup(
|
||||||
close(done)
|
context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{
|
||||||
}()
|
IP: netip.MustParseAddr("1.1.1.1"),
|
||||||
|
NSType: nbdns.UDPNameServerType,
|
||||||
|
Port: nbdns.DefaultDNSPort,
|
||||||
|
}},
|
||||||
|
[]string{"groupC"},
|
||||||
|
true, nil, true, userID, false,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
settleAffectedUpdates(updMsg)
|
||||||
ID: "groupD",
|
|
||||||
Name: "GroupD",
|
done := make(chan struct{})
|
||||||
Peers: []string{peer1.ID},
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
|
ID: "groupC",
|
||||||
|
Name: "GroupC",
|
||||||
|
Peers: []string{peer1.ID, peer3.ID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// Saving a group linked to route should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "saving group linked to route", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
newRoute := route.Route{
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
ID: "route",
|
||||||
}
|
Network: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
})
|
NetID: "superNet",
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
PeerGroups: []string{"groupA"},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{"groupC"},
|
||||||
|
}
|
||||||
|
_, err := manager.CreateRoute(
|
||||||
|
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
|
||||||
|
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
|
||||||
|
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, newRoute.SkipAutoApply,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Saving a group linked to network router should update account peers and send peer update
|
settleAffectedUpdates(updMsg)
|
||||||
t.Run("saving group linked to network router", func(t *testing.T) {
|
|
||||||
permissionsManager := permissions.NewManager(manager.Store)
|
|
||||||
groupsManager := groups.NewManager(manager.Store, permissionsManager, manager)
|
|
||||||
resourcesManager := resources.NewManager(manager.Store, permissionsManager, groupsManager, manager, manager.serviceManager)
|
|
||||||
routersManager := routers.NewManager(manager.Store, permissionsManager, manager)
|
|
||||||
networksManager := networks.NewManager(manager.Store, permissionsManager, resourcesManager, routersManager, manager)
|
|
||||||
|
|
||||||
network, err := networksManager.CreateNetwork(context.Background(), userID, &networkTypes.Network{
|
done := make(chan struct{})
|
||||||
ID: "network_test",
|
go func() {
|
||||||
AccountID: account.Id,
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
Name: "network_test",
|
close(done)
|
||||||
Description: "",
|
}()
|
||||||
|
|
||||||
|
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
|
ID: "groupA",
|
||||||
|
Name: "GroupA",
|
||||||
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
_, err = routersManager.CreateRouter(context.Background(), userID, &routerTypes.NetworkRouter{
|
// Saving a group linked to dns settings should update account peers and send peer update
|
||||||
ID: "router_test",
|
step(t, "saving group linked to dns settings", func(t *testing.T) {
|
||||||
NetworkID: network.ID,
|
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
|
||||||
AccountID: account.Id,
|
DisabledManagementGroups: []string{"groupD"},
|
||||||
PeerGroups: []string{"groupE"},
|
})
|
||||||
Masquerade: true,
|
assert.NoError(t, err)
|
||||||
Metric: 9999,
|
|
||||||
Enabled: true,
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
|
ID: "groupD",
|
||||||
|
Name: "GroupD",
|
||||||
|
Peers: []string{peer1.ID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
// Saving a group linked to network router should update account peers and send peer update
|
||||||
go func() {
|
step(t, "saving group linked to network router", func(t *testing.T) {
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
permissionsManager := permissions.NewManager(manager.Store)
|
||||||
close(done)
|
groupsManager := groups.NewManager(manager.Store, permissionsManager, manager)
|
||||||
}()
|
resourcesManager := resources.NewManager(manager.Store, permissionsManager, groupsManager, manager, manager.serviceManager)
|
||||||
|
routersManager := routers.NewManager(manager.Store, permissionsManager, manager)
|
||||||
|
networksManager := networks.NewManager(manager.Store, permissionsManager, resourcesManager, routersManager, manager)
|
||||||
|
|
||||||
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
network, err := networksManager.CreateNetwork(context.Background(), userID, &networkTypes.Network{
|
||||||
ID: "groupE",
|
ID: "network_test",
|
||||||
Name: "GroupE",
|
AccountID: account.Id,
|
||||||
Peers: []string{peer2.ID, peer3.ID},
|
Name: "network_test",
|
||||||
|
Description: "",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = routersManager.CreateRouter(context.Background(), userID, &routerTypes.NetworkRouter{
|
||||||
|
ID: "router_test",
|
||||||
|
NetworkID: network.ID,
|
||||||
|
AccountID: account.Id,
|
||||||
|
PeerGroups: []string{"groupE"},
|
||||||
|
Masquerade: true,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resource, err := resourcesManager.CreateResource(context.Background(), userID, &resourceTypes.NetworkResource{
|
||||||
|
AccountID: account.Id,
|
||||||
|
NetworkID: network.ID,
|
||||||
|
Name: "resource_test",
|
||||||
|
Address: "10.20.30.0/24",
|
||||||
|
Enabled: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, peerToResourcePolicyByResource("groupA", resource.ID), true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
|
ID: "groupE",
|
||||||
|
Name: "GroupE",
|
||||||
|
Peers: []string{peer2.ID, peer3.ID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/mock/gomock"
|
||||||
|
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
|
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
|
||||||
@@ -966,147 +966,151 @@ func TestValidateDomain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNameServerAccountPeersUpdate(t *testing.T) {
|
func TestNameServerAccountPeersUpdate(t *testing.T) {
|
||||||
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
|
|
||||||
var newNameServerGroupA *nbdns.NameServerGroup
|
var newNameServerGroupA *nbdns.NameServerGroup
|
||||||
var newNameServerGroupB *nbdns.NameServerGroup
|
var newNameServerGroupB *nbdns.NameServerGroup
|
||||||
|
|
||||||
err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
|
err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
|
|
||||||
ID: "groupB",
|
|
||||||
Name: "GroupB",
|
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
updateManager.CloseChannel(context.Background(), peer1.ID)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Creating a nameserver group with a distribution group no peers should not update account peers
|
|
||||||
// and not send peer update
|
|
||||||
t.Run("creating nameserver group with distribution group no peers", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
newNameServerGroupA, err = manager.CreateNameServerGroup(
|
|
||||||
context.Background(), account.Id, "nsGroupA", "nsGroupA", []nbdns.NameServer{{
|
|
||||||
IP: netip.MustParseAddr("1.1.1.1"),
|
|
||||||
NSType: nbdns.UDPNameServerType,
|
|
||||||
Port: nbdns.DefaultDNSPort,
|
|
||||||
}},
|
|
||||||
[]string{"groupA"},
|
|
||||||
true, []string{}, true, userID, false,
|
|
||||||
)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
err = manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
case <-done:
|
ID: "groupB",
|
||||||
case <-time.After(time.Second):
|
Name: "GroupB",
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
}
|
})
|
||||||
})
|
|
||||||
|
|
||||||
// saving a nameserver group with a distribution group with no peers should not update account peers
|
|
||||||
// and not send peer update
|
|
||||||
t.Run("saving nameserver group with distribution group no peers", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = manager.SaveNameServerGroup(context.Background(), account.Id, userID, newNameServerGroupA)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
case <-done:
|
t.Cleanup(func() {
|
||||||
case <-time.After(time.Second):
|
updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Creating a nameserver group with a distribution group no peers should update account peers and send peer update
|
// Creating a nameserver group with a distribution group no peers should not update account peers
|
||||||
t.Run("creating nameserver group with distribution group has peers", func(t *testing.T) {
|
// and not send peer update
|
||||||
done := make(chan struct{})
|
step(t, "creating nameserver group with distribution group no peers", func(t *testing.T) {
|
||||||
go func() {
|
settleAffectedUpdates(updMsg)
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
newNameServerGroupB, err = manager.CreateNameServerGroup(
|
done := make(chan struct{})
|
||||||
context.Background(), account.Id, "nsGroupB", "nsGroupB", []nbdns.NameServer{{
|
go func() {
|
||||||
IP: netip.MustParseAddr("1.1.1.1"),
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
NSType: nbdns.UDPNameServerType,
|
close(done)
|
||||||
Port: nbdns.DefaultDNSPort,
|
}()
|
||||||
}},
|
|
||||||
[]string{"groupB"},
|
|
||||||
true, []string{}, true, userID, false,
|
|
||||||
)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
newNameServerGroupA, err = manager.CreateNameServerGroup(
|
||||||
case <-done:
|
context.Background(), account.Id, "nsGroupA", "nsGroupA", []nbdns.NameServer{{
|
||||||
case <-time.After(time.Second):
|
IP: netip.MustParseAddr("1.1.1.1"),
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
NSType: nbdns.UDPNameServerType,
|
||||||
}
|
Port: nbdns.DefaultDNSPort,
|
||||||
})
|
}},
|
||||||
|
[]string{"groupA"},
|
||||||
|
true, []string{}, true, userID, false,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// saving a nameserver group with a distribution group with peers should update account peers and send peer update
|
select {
|
||||||
t.Run("saving nameserver group with distribution group has peers", func(t *testing.T) {
|
case <-done:
|
||||||
done := make(chan struct{})
|
case <-time.After(time.Second):
|
||||||
go func() {
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
}
|
||||||
close(done)
|
})
|
||||||
}()
|
|
||||||
|
|
||||||
newNameServerGroupB.NameServers = []nbdns.NameServer{
|
// saving a nameserver group with a distribution group with no peers should not update account peers
|
||||||
{
|
// and not send peer update
|
||||||
IP: netip.MustParseAddr("1.1.1.2"),
|
step(t, "saving nameserver group with distribution group no peers", func(t *testing.T) {
|
||||||
NSType: nbdns.UDPNameServerType,
|
done := make(chan struct{})
|
||||||
Port: nbdns.DefaultDNSPort,
|
go func() {
|
||||||
},
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
{
|
close(done)
|
||||||
IP: netip.MustParseAddr("8.8.8.8"),
|
}()
|
||||||
NSType: nbdns.UDPNameServerType,
|
|
||||||
Port: nbdns.DefaultDNSPort,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err = manager.SaveNameServerGroup(context.Background(), account.Id, userID, newNameServerGroupB)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
err = manager.SaveNameServerGroup(context.Background(), account.Id, userID, newNameServerGroupA)
|
||||||
case <-done:
|
assert.NoError(t, err)
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deleting a nameserver group should update account peers and send peer update
|
select {
|
||||||
t.Run("deleting nameserver group", func(t *testing.T) {
|
case <-done:
|
||||||
done := make(chan struct{})
|
case <-time.After(time.Second):
|
||||||
go func() {
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
}
|
||||||
close(done)
|
})
|
||||||
}()
|
|
||||||
|
|
||||||
err = manager.DeleteNameServerGroup(context.Background(), account.Id, newNameServerGroupB.ID, userID)
|
// Creating a nameserver group with a distribution group no peers should update account peers and send peer update
|
||||||
assert.NoError(t, err)
|
step(t, "creating nameserver group with distribution group has peers", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
select {
|
newNameServerGroupB, err = manager.CreateNameServerGroup(
|
||||||
case <-done:
|
context.Background(), account.Id, "nsGroupB", "nsGroupB", []nbdns.NameServer{{
|
||||||
case <-time.After(peerUpdateTimeout):
|
IP: netip.MustParseAddr("1.1.1.1"),
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
NSType: nbdns.UDPNameServerType,
|
||||||
}
|
Port: nbdns.DefaultDNSPort,
|
||||||
|
}},
|
||||||
|
[]string{"groupB"},
|
||||||
|
true, []string{}, true, userID, false,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// saving a nameserver group with a distribution group with peers should update account peers and send peer update
|
||||||
|
step(t, "saving nameserver group with distribution group has peers", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
newNameServerGroupB.NameServers = []nbdns.NameServer{
|
||||||
|
{
|
||||||
|
IP: netip.MustParseAddr("1.1.1.2"),
|
||||||
|
NSType: nbdns.UDPNameServerType,
|
||||||
|
Port: nbdns.DefaultDNSPort,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
IP: netip.MustParseAddr("8.8.8.8"),
|
||||||
|
NSType: nbdns.UDPNameServerType,
|
||||||
|
Port: nbdns.DefaultDNSPort,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = manager.SaveNameServerGroup(context.Background(), account.Id, userID, newNameServerGroupB)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Deleting a nameserver group should update account peers and send peer update
|
||||||
|
step(t, "deleting nameserver group", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = manager.DeleteNameServerGroup(context.Background(), account.Id, newNameServerGroupB.ID, userID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+330
-366
@@ -1844,374 +1844,336 @@ func Test_LoginPeer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPeerAccountPeersUpdate(t *testing.T) {
|
func TestPeerAccountPeersUpdate(t *testing.T) {
|
||||||
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
|
|
||||||
err := manager.DeletePolicy(context.Background(), account.Id, account.Policies[0].ID, userID)
|
err := manager.DeletePolicy(context.Background(), account.Id, account.Policies[0].ID, userID)
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
g := []*types.Group{
|
|
||||||
{
|
|
||||||
ID: "groupA",
|
|
||||||
Name: "GroupA",
|
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupB",
|
|
||||||
Name: "GroupB",
|
|
||||||
Peers: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupC",
|
|
||||||
Name: "GroupC",
|
|
||||||
Peers: []string{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, group := range g {
|
|
||||||
err = manager.CreateGroup(context.Background(), account.Id, userID, group)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a user with auto groups
|
|
||||||
_, err = manager.SaveOrAddUsers(context.Background(), account.Id, userID, []*types.User{
|
|
||||||
{
|
|
||||||
Id: "regularUser1",
|
|
||||||
AccountID: account.Id,
|
|
||||||
Role: types.UserRoleAdmin,
|
|
||||||
Issued: types.UserIssuedAPI,
|
|
||||||
AutoGroups: []string{"groupA"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Id: "regularUser2",
|
|
||||||
AccountID: account.Id,
|
|
||||||
Role: types.UserRoleAdmin,
|
|
||||||
Issued: types.UserIssuedAPI,
|
|
||||||
AutoGroups: []string{"groupB"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Id: "regularUser3",
|
|
||||||
AccountID: account.Id,
|
|
||||||
Role: types.UserRoleAdmin,
|
|
||||||
Issued: types.UserIssuedAPI,
|
|
||||||
AutoGroups: []string{"groupC"},
|
|
||||||
},
|
|
||||||
}, true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
var peer4 *nbpeer.Peer
|
|
||||||
var peer5 *nbpeer.Peer
|
|
||||||
var peer6 *nbpeer.Peer
|
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
updateManager.CloseChannel(context.Background(), peer1.ID)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Updating not expired peer and peer expiration is enabled should not update account peers and not send peer update
|
|
||||||
t.Run("updating not expired peer and peer expiration is enabled", func(t *testing.T) {
|
|
||||||
t.Skip("Currently all updates will trigger a network map")
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err := manager.UpdatePeer(context.Background(), account.Id, userID, peer2)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
select {
|
g := []*types.Group{
|
||||||
case <-done:
|
{
|
||||||
case <-time.After(time.Second):
|
ID: "groupA",
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
Name: "GroupA",
|
||||||
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "groupB",
|
||||||
|
Name: "GroupB",
|
||||||
|
Peers: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "groupC",
|
||||||
|
Name: "GroupC",
|
||||||
|
Peers: []string{},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
for _, group := range g {
|
||||||
|
err = manager.CreateGroup(context.Background(), account.Id, userID, group)
|
||||||
// Adding peer to unlinked group should not update account peers and not send peer update
|
require.NoError(t, err)
|
||||||
t.Run("adding peer to unlinked group", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expectedPeerKey := key.PublicKey().String()
|
|
||||||
peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
|
|
||||||
Key: expectedPeerKey,
|
|
||||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
|
||||||
}, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deleting peer with unlinked group should not update account peers and not send peer update
|
|
||||||
t.Run("deleting peer with unlinked group", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = manager.DeletePeer(context.Background(), account.Id, peer4.ID, userID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Updating peer label should update account peers and send peer update
|
|
||||||
t.Run("updating peer label", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
peer1.Name = "peer-1"
|
|
||||||
_, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("validator requires update", func(t *testing.T) {
|
|
||||||
requireUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) {
|
|
||||||
return update, true, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
manager.integratedPeerValidator = MockIntegratedValidator{ValidatePeerFunc: requireUpdateFunc}
|
// create a user with auto groups
|
||||||
done := make(chan struct{})
|
_, err = manager.SaveOrAddUsers(context.Background(), account.Id, userID, []*types.User{
|
||||||
go func() {
|
{
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
Id: "regularUser1",
|
||||||
close(done)
|
AccountID: account.Id,
|
||||||
}()
|
Role: types.UserRoleAdmin,
|
||||||
|
Issued: types.UserIssuedAPI,
|
||||||
_, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1)
|
AutoGroups: []string{"groupA"},
|
||||||
require.NoError(t, err)
|
},
|
||||||
|
{
|
||||||
select {
|
Id: "regularUser2",
|
||||||
case <-done:
|
AccountID: account.Id,
|
||||||
case <-time.After(peerUpdateTimeout):
|
Role: types.UserRoleAdmin,
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
Issued: types.UserIssuedAPI,
|
||||||
}
|
AutoGroups: []string{"groupB"},
|
||||||
})
|
},
|
||||||
|
{
|
||||||
t.Run("validator requires no update", func(t *testing.T) {
|
Id: "regularUser3",
|
||||||
t.Skip("Currently all updates will trigger a network map")
|
AccountID: account.Id,
|
||||||
|
Role: types.UserRoleAdmin,
|
||||||
requireNoUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) {
|
Issued: types.UserIssuedAPI,
|
||||||
return update, false, nil
|
AutoGroups: []string{"groupC"},
|
||||||
}
|
|
||||||
|
|
||||||
manager.integratedPeerValidator = MockIntegratedValidator{ValidatePeerFunc: requireNoUpdateFunc}
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Adding peer to group linked with policy should update account peers and send peer update
|
|
||||||
t.Run("adding peer to group linked with policy", func(t *testing.T) {
|
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
|
||||||
AccountID: account.Id,
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{
|
|
||||||
{
|
|
||||||
Enabled: true,
|
|
||||||
Sources: []string{"groupA"},
|
|
||||||
Destinations: []string{"groupA"},
|
|
||||||
Bidirectional: true,
|
|
||||||
Action: types.PolicyTrafficActionAccept,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}, true)
|
}, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
done := make(chan struct{})
|
var peer4 *nbpeer.Peer
|
||||||
go func() {
|
var peer5 *nbpeer.Peer
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
var peer6 *nbpeer.Peer
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
require.NoError(t, err)
|
t.Cleanup(func() {
|
||||||
|
updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
|
})
|
||||||
|
|
||||||
expectedPeerKey := key.PublicKey().String()
|
// Adding peer to unlinked group should not update account peers and not send peer update
|
||||||
peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
|
step(t, "adding peer to unlinked group", func(t *testing.T) {
|
||||||
Key: expectedPeerKey,
|
settleAffectedUpdates(updMsg)
|
||||||
LoginExpirationEnabled: true,
|
done := make(chan struct{})
|
||||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
go func() {
|
||||||
}, false)
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
require.NoError(t, err)
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
select {
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
case <-done:
|
require.NoError(t, err)
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deleting peer with linked group to policy should update account peers and send peer update
|
expectedPeerKey := key.PublicKey().String()
|
||||||
t.Run("deleting peer with linked group to policy", func(t *testing.T) {
|
peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
|
||||||
done := make(chan struct{})
|
Key: expectedPeerKey,
|
||||||
go func() {
|
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
}, false)
|
||||||
close(done)
|
require.NoError(t, err)
|
||||||
}()
|
|
||||||
|
|
||||||
err = manager.DeletePeer(context.Background(), account.Id, peer4.ID, userID)
|
select {
|
||||||
require.NoError(t, err)
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
select {
|
// Deleting peer with unlinked group should not update account peers and not send peer update
|
||||||
case <-done:
|
step(t, "deleting peer with unlinked group", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
})
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
// drain any buffered updates from previous subtests
|
err = manager.DeletePeer(context.Background(), account.Id, peer4.ID, userID)
|
||||||
drainPeerUpdates(updMsg)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Adding peer to group linked with route should update peers in that group, not unrelated peers
|
select {
|
||||||
t.Run("adding peer to group linked with route", func(t *testing.T) {
|
case <-done:
|
||||||
route := nbroute.Route{
|
case <-time.After(time.Second):
|
||||||
ID: "testingRoute1",
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
Network: netip.MustParsePrefix("100.65.250.202/32"),
|
}
|
||||||
NetID: "superNet",
|
})
|
||||||
NetworkType: nbroute.IPv4Network,
|
|
||||||
PeerGroups: []string{"groupB"},
|
|
||||||
Description: "super",
|
|
||||||
Masquerade: false,
|
|
||||||
Metric: 9999,
|
|
||||||
Enabled: true,
|
|
||||||
Groups: []string{"groupB"},
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := manager.CreateRoute(
|
// Updating peer label should update account peers and send peer update
|
||||||
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
|
step(t, "updating peer label", func(t *testing.T) {
|
||||||
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
|
done := make(chan struct{})
|
||||||
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
|
go func() {
|
||||||
)
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
require.NoError(t, err)
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
done := make(chan struct{})
|
peer1.Name = "peer-1"
|
||||||
go func() {
|
_, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1)
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
require.NoError(t, err)
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
select {
|
||||||
require.NoError(t, err)
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
expectedPeerKey := key.PublicKey().String()
|
step(t, "validator requires update", func(t *testing.T) {
|
||||||
peer5, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
|
requireUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) {
|
||||||
Key: expectedPeerKey,
|
return update, true, nil
|
||||||
LoginExpirationEnabled: true,
|
}
|
||||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
|
||||||
}, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
manager.integratedPeerValidator = MockIntegratedValidator{ValidatePeerFunc: requireUpdateFunc}
|
||||||
case <-done:
|
done := make(chan struct{})
|
||||||
case <-time.After(time.Second):
|
go func() {
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
}
|
close(done)
|
||||||
})
|
}()
|
||||||
|
|
||||||
// Deleting peer with linked group to route should update peers in that group, not unrelated peers
|
_, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1)
|
||||||
t.Run("deleting peer with linked group to route", func(t *testing.T) {
|
require.NoError(t, err)
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = manager.DeletePeer(context.Background(), account.Id, peer5.ID, userID)
|
select {
|
||||||
require.NoError(t, err)
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
select {
|
// Adding peer to group linked with policy should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "adding peer to group linked with policy", func(t *testing.T) {
|
||||||
case <-time.After(time.Second):
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
AccountID: account.Id,
|
||||||
}
|
Enabled: true,
|
||||||
})
|
Rules: []*types.PolicyRule{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupA"},
|
||||||
|
Destinations: []string{"groupA"},
|
||||||
|
Bidirectional: true,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Adding peer to group linked with name server group should update peers in that group, not unrelated peers
|
done := make(chan struct{})
|
||||||
t.Run("adding peer to group linked with name server group", func(t *testing.T) {
|
go func() {
|
||||||
_, err = manager.CreateNameServerGroup(
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{
|
close(done)
|
||||||
IP: netip.MustParseAddr("1.1.1.1"),
|
}()
|
||||||
NSType: nbdns.UDPNameServerType,
|
|
||||||
Port: nbdns.DefaultDNSPort,
|
|
||||||
}},
|
|
||||||
[]string{"groupC"},
|
|
||||||
true, []string{}, true, userID, false,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
go func() {
|
require.NoError(t, err)
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
expectedPeerKey := key.PublicKey().String()
|
||||||
require.NoError(t, err)
|
peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
|
||||||
|
Key: expectedPeerKey,
|
||||||
|
LoginExpirationEnabled: true,
|
||||||
|
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||||
|
}, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
expectedPeerKey := key.PublicKey().String()
|
select {
|
||||||
peer6, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser3", &nbpeer.Peer{
|
case <-done:
|
||||||
Key: expectedPeerKey,
|
case <-time.After(peerUpdateTimeout):
|
||||||
LoginExpirationEnabled: true,
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
}
|
||||||
}, false)
|
})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// Deleting peer with linked group to policy should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "deleting peer with linked group to policy", func(t *testing.T) {
|
||||||
case <-time.After(time.Second):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
})
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
// Deleting peer with linked group to name server group should update peers in that group, not unrelated peers
|
err = manager.DeletePeer(context.Background(), account.Id, peer4.ID, userID)
|
||||||
t.Run("deleting peer with linked group to route", func(t *testing.T) {
|
require.NoError(t, err)
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = manager.DeletePeer(context.Background(), account.Id, peer6.ID, userID)
|
select {
|
||||||
require.NoError(t, err)
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
select {
|
// drain any buffered updates from previous subtests
|
||||||
case <-done:
|
drainPeerUpdates(updMsg)
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
// Adding peer to group linked with route should update peers in that group, not unrelated peers
|
||||||
}
|
step(t, "adding peer to group linked with route", func(t *testing.T) {
|
||||||
|
route := nbroute.Route{
|
||||||
|
ID: "testingRoute1",
|
||||||
|
Network: netip.MustParsePrefix("100.65.250.202/32"),
|
||||||
|
NetID: "superNet",
|
||||||
|
NetworkType: nbroute.IPv4Network,
|
||||||
|
PeerGroups: []string{"groupB"},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{"groupB"},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := manager.CreateRoute(
|
||||||
|
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
|
||||||
|
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
|
||||||
|
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expectedPeerKey := key.PublicKey().String()
|
||||||
|
peer5, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
|
||||||
|
Key: expectedPeerKey,
|
||||||
|
LoginExpirationEnabled: true,
|
||||||
|
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||||
|
}, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Deleting peer with linked group to route should update peers in that group, not unrelated peers
|
||||||
|
step(t, "deleting peer with linked group to route", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = manager.DeletePeer(context.Background(), account.Id, peer5.ID, userID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Adding peer to group linked with name server group should update peers in that group, not unrelated peers
|
||||||
|
step(t, "adding peer to group linked with name server group", func(t *testing.T) {
|
||||||
|
_, err = manager.CreateNameServerGroup(
|
||||||
|
context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{
|
||||||
|
IP: netip.MustParseAddr("1.1.1.1"),
|
||||||
|
NSType: nbdns.UDPNameServerType,
|
||||||
|
Port: nbdns.DefaultDNSPort,
|
||||||
|
}},
|
||||||
|
[]string{"groupC"},
|
||||||
|
true, []string{}, true, userID, false,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expectedPeerKey := key.PublicKey().String()
|
||||||
|
peer6, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser3", &nbpeer.Peer{
|
||||||
|
Key: expectedPeerKey,
|
||||||
|
LoginExpirationEnabled: true,
|
||||||
|
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||||
|
}, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Deleting peer with linked group to name server group should update peers in that group, not unrelated peers
|
||||||
|
step(t, "deleting peer with linked group to name server group", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = manager.DeletePeer(context.Background(), account.Id, peer6.ID, userID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2859,45 +2821,47 @@ func TestPeerWillHaveIPv6(t *testing.T) {
|
|||||||
// flipping --disable-ipv6) without bumping its WtVersion, other account peers
|
// flipping --disable-ipv6) without bumping its WtVersion, other account peers
|
||||||
// receive a fresh network map so their AAAA records for it become unstale.
|
// receive a fresh network map so their AAAA records for it become unstale.
|
||||||
func TestSyncPeer_IPv6CapabilityChangePropagates(t *testing.T) {
|
func TestSyncPeer_IPv6CapabilityChangePropagates(t *testing.T) {
|
||||||
manager, updateManager, _, peer1, peer2, _ := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
manager, updateManager, _, peer1, peer2, _ := setupNetworkMapTest(t)
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
updateManager.CloseChannel(context.Background(), peer1.ID)
|
updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Drain any initial updates from setup.
|
// Drain any initial updates from setup.
|
||||||
drain := func() {
|
drain := func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-updMsg:
|
case <-updMsg:
|
||||||
case <-time.After(200 * time.Millisecond):
|
case <-time.After(200 * time.Millisecond):
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
drain()
|
||||||
drain()
|
|
||||||
|
|
||||||
t.Run("no propagation when capabilities are unchanged", func(t *testing.T) {
|
step(t, "no propagation when capabilities are unchanged", func(t *testing.T) {
|
||||||
_, _, _, _, err := manager.SyncPeer(context.Background(), types.PeerSync{
|
_, _, _, _, err := manager.SyncPeer(context.Background(), types.PeerSync{
|
||||||
WireGuardPubKey: peer2.Key,
|
WireGuardPubKey: peer2.Key,
|
||||||
Meta: peer2.Meta,
|
Meta: peer2.Meta,
|
||||||
}, peer2.AccountID)
|
}, peer2.AccountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("propagation when IPv6 capability is added", func(t *testing.T) {
|
step(t, "propagation when IPv6 capability is added", func(t *testing.T) {
|
||||||
newMeta := peer2.Meta
|
newMeta := peer2.Meta
|
||||||
newMeta.Capabilities = append([]int32{}, peer2.Meta.Capabilities...)
|
newMeta.Capabilities = append([]int32{}, peer2.Meta.Capabilities...)
|
||||||
newMeta.Capabilities = append(newMeta.Capabilities, nbpeer.PeerCapabilityIPv6Overlay)
|
newMeta.Capabilities = append(newMeta.Capabilities, nbpeer.PeerCapabilityIPv6Overlay)
|
||||||
|
|
||||||
_, _, _, _, err := manager.SyncPeer(context.Background(), types.PeerSync{
|
_, _, _, _, err := manager.SyncPeer(context.Background(), types.PeerSync{
|
||||||
WireGuardPubKey: peer2.Key,
|
WireGuardPubKey: peer2.Key,
|
||||||
Meta: newMeta,
|
Meta: newMeta,
|
||||||
}, peer2.AccountID)
|
}, peer2.AccountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+278
-274
@@ -1135,287 +1135,291 @@ func sortFunc() func(a *types.FirewallRule, b *types.FirewallRule) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPolicyAccountPeersUpdate(t *testing.T) {
|
func TestPolicyAccountPeersUpdate(t *testing.T) {
|
||||||
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
|
|
||||||
g := []*types.Group{
|
g := []*types.Group{
|
||||||
{
|
{
|
||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer3.ID},
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupB",
|
|
||||||
Name: "GroupB",
|
|
||||||
Peers: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupC",
|
|
||||||
Name: "GroupC",
|
|
||||||
Peers: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupD",
|
|
||||||
Name: "GroupD",
|
|
||||||
Peers: []string{peer1.ID, peer2.ID},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, group := range g {
|
|
||||||
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
updateManager.CloseChannel(context.Background(), peer1.ID)
|
|
||||||
})
|
|
||||||
|
|
||||||
var policyWithGroupRulesNoPeers *types.Policy
|
|
||||||
var policyWithDestinationPeersOnly *types.Policy
|
|
||||||
var policyWithSourceAndDestinationPeers *types.Policy
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Saving policy with rule groups with no peers should not update account's peers and not send peer update
|
|
||||||
t.Run("saving policy with rule groups with no peers", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policyWithGroupRulesNoPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
|
||||||
AccountID: account.Id,
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{
|
|
||||||
{
|
|
||||||
Enabled: true,
|
|
||||||
Sources: []string{"groupB"},
|
|
||||||
Destinations: []string{"groupC"},
|
|
||||||
Bidirectional: true,
|
|
||||||
Action: types.PolicyTrafficActionAccept,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}, true)
|
{
|
||||||
assert.NoError(t, err)
|
ID: "groupB",
|
||||||
|
Name: "GroupB",
|
||||||
select {
|
Peers: []string{},
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Saving policy with source group containing peers, but destination group without peers should
|
|
||||||
// update account's peers and send peer update
|
|
||||||
t.Run("saving policy where source has peers but destination does not", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
|
||||||
AccountID: account.Id,
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{
|
|
||||||
{
|
|
||||||
Enabled: true,
|
|
||||||
Sources: []string{"groupA"},
|
|
||||||
Destinations: []string{"groupB"},
|
|
||||||
Protocol: types.PolicyRuleProtocolTCP,
|
|
||||||
Bidirectional: true,
|
|
||||||
Action: types.PolicyTrafficActionAccept,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}, true)
|
{
|
||||||
assert.NoError(t, err)
|
ID: "groupC",
|
||||||
|
Name: "GroupC",
|
||||||
select {
|
Peers: []string{},
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Saving policy with destination group containing peers, but source group without peers should
|
|
||||||
// update account's peers and send peer update
|
|
||||||
t.Run("saving policy where destination has peers but source does not", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policyWithDestinationPeersOnly, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
|
||||||
AccountID: account.Id,
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{
|
|
||||||
{
|
|
||||||
Enabled: true,
|
|
||||||
Sources: []string{"groupC"},
|
|
||||||
Destinations: []string{"groupD"},
|
|
||||||
Bidirectional: true,
|
|
||||||
Protocol: types.PolicyRuleProtocolTCP,
|
|
||||||
Action: types.PolicyTrafficActionAccept,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}, true)
|
{
|
||||||
assert.NoError(t, err)
|
ID: "groupD",
|
||||||
|
Name: "GroupD",
|
||||||
select {
|
Peers: []string{peer1.ID, peer2.ID},
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Saving policy with destination and source groups containing peers should update account's peers
|
|
||||||
// and send peer update
|
|
||||||
t.Run("saving policy with source and destination groups with peers", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
|
||||||
AccountID: account.Id,
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{
|
|
||||||
{
|
|
||||||
Enabled: true,
|
|
||||||
Sources: []string{"groupA"},
|
|
||||||
Destinations: []string{"groupD"},
|
|
||||||
Bidirectional: true,
|
|
||||||
Action: types.PolicyTrafficActionAccept,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
}
|
||||||
})
|
for _, group := range g {
|
||||||
|
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
|
||||||
// Disabling policy with destination and source groups containing peers should update account's peers
|
assert.NoError(t, err)
|
||||||
// and send peer update
|
|
||||||
t.Run("disabling policy with source and destination groups with peers", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policyWithSourceAndDestinationPeers.Enabled = false
|
|
||||||
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Updating disabled policy with destination and source groups containing peers should still update account's peers
|
|
||||||
// because affected peer resolution does not filter by policy enabled state
|
|
||||||
t.Run("updating disabled policy with source and destination groups with peers", func(t *testing.T) {
|
|
||||||
drainPeerUpdates(updMsg)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policyWithSourceAndDestinationPeers.Description = "updated description"
|
|
||||||
policyWithSourceAndDestinationPeers.Rules[0].Destinations = []string{"groupA"}
|
|
||||||
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Enabling policy with destination and source groups containing peers should update account's peers
|
|
||||||
// and send peer update
|
|
||||||
t.Run("enabling policy with source and destination groups with peers", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policyWithSourceAndDestinationPeers.Enabled = true
|
|
||||||
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deleting policy should trigger account peers update and send peer update
|
|
||||||
t.Run("deleting policy with source and destination groups with peers", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.DeletePolicy(context.Background(), account.Id, policyWithSourceAndDestinationPeers.ID, userID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
|
})
|
||||||
|
|
||||||
|
var policyWithGroupRulesNoPeers *types.Policy
|
||||||
|
var policyWithDestinationPeersOnly *types.Policy
|
||||||
|
var policyWithSourceAndDestinationPeers *types.Policy
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Saving policy with rule groups with no peers should not update account's peers and not send peer update
|
||||||
|
step(t, "saving policy with rule groups with no peers", func(t *testing.T) {
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
policyWithGroupRulesNoPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
||||||
|
AccountID: account.Id,
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []*types.PolicyRule{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupB"},
|
||||||
|
Destinations: []string{"groupC"},
|
||||||
|
Bidirectional: true,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Saving policy with source group containing peers, but destination group without peers should
|
||||||
|
// update account's peers and send peer update
|
||||||
|
step(t, "saving policy where source has peers but destination does not", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
||||||
|
AccountID: account.Id,
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []*types.PolicyRule{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupA"},
|
||||||
|
Destinations: []string{"groupB"},
|
||||||
|
Protocol: types.PolicyRuleProtocolTCP,
|
||||||
|
Bidirectional: true,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Saving policy with destination group containing peers, but source group without peers should
|
||||||
|
// update account's peers and send peer update
|
||||||
|
step(t, "saving policy where destination has peers but source does not", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
policyWithDestinationPeersOnly, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
||||||
|
AccountID: account.Id,
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []*types.PolicyRule{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupC"},
|
||||||
|
Destinations: []string{"groupD"},
|
||||||
|
Bidirectional: true,
|
||||||
|
Protocol: types.PolicyRuleProtocolTCP,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Saving policy with destination and source groups containing peers should update account's peers
|
||||||
|
// and send peer update
|
||||||
|
step(t, "saving policy with source and destination groups with peers", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
||||||
|
AccountID: account.Id,
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []*types.PolicyRule{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupA"},
|
||||||
|
Destinations: []string{"groupD"},
|
||||||
|
Bidirectional: true,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Disabling policy with destination and source groups containing peers should update account's peers
|
||||||
|
// and send peer update
|
||||||
|
step(t, "disabling policy with source and destination groups with peers", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
policyWithSourceAndDestinationPeers.Enabled = false
|
||||||
|
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Updating disabled policy with destination and source groups containing peers should still update account's peers
|
||||||
|
// because affected peer resolution does not filter by policy enabled state
|
||||||
|
step(t, "updating disabled policy with source and destination groups with peers", func(t *testing.T) {
|
||||||
|
drainPeerUpdates(updMsg)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
policyWithSourceAndDestinationPeers.Description = "updated description"
|
||||||
|
policyWithSourceAndDestinationPeers.Rules[0].Destinations = []string{"groupA"}
|
||||||
|
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Enabling policy with destination and source groups containing peers should update account's peers
|
||||||
|
// and send peer update
|
||||||
|
step(t, "enabling policy with source and destination groups with peers", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
policyWithSourceAndDestinationPeers.Enabled = true
|
||||||
|
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Deleting policy should trigger account peers update and send peer update
|
||||||
|
step(t, "deleting policy with source and destination groups with peers", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.DeletePolicy(context.Background(), account.Id, policyWithSourceAndDestinationPeers.ID, userID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
// Deleting policy with destination group containing peers, but source group without peers should
|
||||||
|
// update account's peers and send peer update
|
||||||
|
step(t, "deleting policy where destination has peers but source does not", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.DeletePolicy(context.Background(), account.Id, policyWithDestinationPeersOnly.ID, userID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Deleting policy with no peers in groups should not update account's peers and not send peer update
|
||||||
|
step(t, "deleting policy with no peers in groups", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.DeletePolicy(context.Background(), account.Id, policyWithGroupRulesNoPeers.ID, userID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Deleting policy with destination group containing peers, but source group without peers should
|
|
||||||
// update account's peers and send peer update
|
|
||||||
t.Run("deleting policy where destination has peers but source does not", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.DeletePolicy(context.Background(), account.Id, policyWithDestinationPeersOnly.ID, userID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deleting policy with no peers in groups should not update account's peers and not send peer update
|
|
||||||
t.Run("deleting policy with no peers in groups", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.DeletePolicy(context.Background(), account.Id, policyWithGroupRulesNoPeers.ID, userID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,324 +123,334 @@ func initTestPostureChecksAccount(am *DefaultAccountManager) (*types.Account, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
||||||
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
|
|
||||||
g := []*types.Group{
|
g := []*types.Group{
|
||||||
{
|
|
||||||
ID: "groupA",
|
|
||||||
Name: "GroupA",
|
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupB",
|
|
||||||
Name: "GroupB",
|
|
||||||
Peers: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "groupC",
|
|
||||||
Name: "GroupC",
|
|
||||||
Peers: []string{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, group := range g {
|
|
||||||
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
updateManager.CloseChannel(context.Background(), peer1.ID)
|
|
||||||
})
|
|
||||||
|
|
||||||
postureCheckA := &posture.Checks{
|
|
||||||
Name: "postureCheckA",
|
|
||||||
AccountID: account.Id,
|
|
||||||
Checks: posture.ChecksDefinition{
|
|
||||||
ProcessCheck: &posture.ProcessCheck{
|
|
||||||
Processes: []posture.Process{
|
|
||||||
{LinuxPath: "/usr/bin/netbird", MacPath: "/usr/local/bin/netbird"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
postureCheckA, err := manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckA, true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
postureCheckB := &posture.Checks{
|
|
||||||
Name: "postureCheckB",
|
|
||||||
AccountID: account.Id,
|
|
||||||
Checks: posture.ChecksDefinition{
|
|
||||||
NBVersionCheck: &posture.NBVersionCheck{
|
|
||||||
MinVersion: "0.28.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Saving unused posture check should not update account peers and not send peer update
|
|
||||||
t.Run("saving unused posture check", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
postureCheckB, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Updating unused posture check should not update account peers and not send peer update
|
|
||||||
t.Run("updating unused posture check", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
postureCheckB.Checks = posture.ChecksDefinition{
|
|
||||||
NBVersionCheck: &posture.NBVersionCheck{
|
|
||||||
MinVersion: "0.29.0",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
policy := &types.Policy{
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{
|
|
||||||
{
|
{
|
||||||
Enabled: true,
|
ID: "groupA",
|
||||||
Sources: []string{"groupA"},
|
Name: "GroupA",
|
||||||
Destinations: []string{"groupA"},
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
Bidirectional: true,
|
|
||||||
Action: types.PolicyTrafficActionAccept,
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
SourcePostureChecks: []string{postureCheckB.ID},
|
ID: "groupB",
|
||||||
}
|
Name: "GroupB",
|
||||||
|
Peers: []string{},
|
||||||
// Linking posture check to policy should trigger update account peers and send peer update
|
|
||||||
t.Run("linking posture check to policy with peers", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policy, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Updating linked posture checks should update account peers and send peer update
|
|
||||||
t.Run("updating linked to posture check with peers", func(t *testing.T) {
|
|
||||||
postureCheckB.Checks = posture.ChecksDefinition{
|
|
||||||
NBVersionCheck: &posture.NBVersionCheck{
|
|
||||||
MinVersion: "0.29.0",
|
|
||||||
},
|
},
|
||||||
ProcessCheck: &posture.ProcessCheck{
|
{
|
||||||
Processes: []posture.Process{
|
ID: "groupC",
|
||||||
{LinuxPath: "/usr/bin/netbird", MacPath: "/usr/local/bin/netbird"},
|
Name: "GroupC",
|
||||||
},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
for _, group := range g {
|
||||||
done := make(chan struct{})
|
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
|
||||||
go func() {
|
assert.NoError(t, err)
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
// Removing posture check from policy should trigger account peers update and send peer update
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
t.Run("removing posture check from policy", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
policy.SourcePostureChecks = []string{}
|
|
||||||
_, err := manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deleting unused posture check should not trigger account peers update and not send peer update
|
|
||||||
t.Run("deleting unused posture check", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.DeletePostureChecks(context.Background(), account.Id, postureCheckA.ID, userID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Updating linked posture check to policy with no peers should not trigger account peers update and not send peer update
|
|
||||||
t.Run("updating linked posture check to policy with no peers", func(t *testing.T) {
|
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{
|
|
||||||
{
|
|
||||||
Enabled: true,
|
|
||||||
Sources: []string{"groupB"},
|
|
||||||
Destinations: []string{"groupC"},
|
|
||||||
Bidirectional: true,
|
|
||||||
Action: types.PolicyTrafficActionAccept,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SourcePostureChecks: []string{postureCheckB.ID},
|
|
||||||
}, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
postureCheckB.Checks = posture.ChecksDefinition{
|
|
||||||
NBVersionCheck: &posture.NBVersionCheck{
|
|
||||||
MinVersion: "0.29.0",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Updating linked posture check to policy where destination has peers but source does not
|
|
||||||
// should trigger account peers update and send peer update
|
|
||||||
t.Run("updating linked posture check to policy where destination has peers but source does not", func(t *testing.T) {
|
|
||||||
updMsg1 := updateManager.CreateChannel(context.Background(), peer2.ID)
|
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
updateManager.CloseChannel(context.Background(), peer2.ID)
|
updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
})
|
})
|
||||||
|
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
postureCheckA := &posture.Checks{
|
||||||
|
Name: "postureCheckA",
|
||||||
|
AccountID: account.Id,
|
||||||
|
Checks: posture.ChecksDefinition{
|
||||||
|
ProcessCheck: &posture.ProcessCheck{
|
||||||
|
Processes: []posture.Process{
|
||||||
|
{LinuxPath: "/usr/bin/netbird", MacPath: "/usr/local/bin/netbird"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
postureCheckA, err := manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckA, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
postureCheckB := &posture.Checks{
|
||||||
|
Name: "postureCheckB",
|
||||||
|
AccountID: account.Id,
|
||||||
|
Checks: posture.ChecksDefinition{
|
||||||
|
NBVersionCheck: &posture.NBVersionCheck{
|
||||||
|
MinVersion: "0.28.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saving unused posture check should not update account peers and not send peer update
|
||||||
|
step(t, "saving unused posture check", func(t *testing.T) {
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
postureCheckB, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Updating unused posture check should not update account peers and not send peer update
|
||||||
|
step(t, "updating unused posture check", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
postureCheckB.Checks = posture.ChecksDefinition{
|
||||||
|
NBVersionCheck: &posture.NBVersionCheck{
|
||||||
|
MinVersion: "0.29.0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
policy := &types.Policy{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Rules: []*types.PolicyRule{
|
Rules: []*types.PolicyRule{
|
||||||
{
|
{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Sources: []string{"groupB"},
|
Sources: []string{"groupA"},
|
||||||
Destinations: []string{"groupA"},
|
Destinations: []string{"groupA"},
|
||||||
Bidirectional: true,
|
Bidirectional: true,
|
||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
SourcePostureChecks: []string{postureCheckB.ID},
|
SourcePostureChecks: []string{postureCheckB.ID},
|
||||||
}, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg1)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
postureCheckB.Checks = posture.ChecksDefinition{
|
|
||||||
NBVersionCheck: &posture.NBVersionCheck{
|
|
||||||
MinVersion: "0.29.0",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// Linking posture check to policy should trigger update account peers and send peer update
|
||||||
case <-done:
|
step(t, "linking posture check to policy with peers", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
})
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
// Updating linked client posture check to policy where source has peers but destination does not,
|
policy, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
||||||
// should trigger account peers update and send peer update
|
assert.NoError(t, err)
|
||||||
t.Run("updating linked posture check to policy where source has peers but destination does not", func(t *testing.T) {
|
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
select {
|
||||||
Enabled: true,
|
case <-done:
|
||||||
Rules: []*types.PolicyRule{
|
case <-time.After(peerUpdateTimeout):
|
||||||
{
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
Enabled: true,
|
}
|
||||||
Sources: []string{"groupA"},
|
})
|
||||||
Destinations: []string{"groupB"},
|
|
||||||
Bidirectional: true,
|
// Updating linked posture checks should update account peers and send peer update
|
||||||
Action: types.PolicyTrafficActionAccept,
|
step(t, "updating linked to posture check with peers", func(t *testing.T) {
|
||||||
|
postureCheckB.Checks = posture.ChecksDefinition{
|
||||||
|
NBVersionCheck: &posture.NBVersionCheck{
|
||||||
|
MinVersion: "0.29.0",
|
||||||
},
|
},
|
||||||
},
|
ProcessCheck: &posture.ProcessCheck{
|
||||||
SourcePostureChecks: []string{postureCheckB.ID},
|
Processes: []posture.Process{
|
||||||
}, true)
|
{LinuxPath: "/usr/bin/netbird", MacPath: "/usr/local/bin/netbird"},
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
postureCheckB.Checks = posture.ChecksDefinition{
|
|
||||||
ProcessCheck: &posture.ProcessCheck{
|
|
||||||
Processes: []posture.Process{
|
|
||||||
{
|
|
||||||
LinuxPath: "/usr/bin/netbird",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Removing posture check from policy should trigger account peers update and send peer update
|
||||||
|
step(t, "removing posture check from policy", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
policy.SourcePostureChecks = []string{}
|
||||||
|
_, err := manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Deleting unused posture check should not trigger account peers update and not send peer update
|
||||||
|
step(t, "deleting unused posture check", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.DeletePostureChecks(context.Background(), account.Id, postureCheckA.ID, userID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
// Updating linked posture check to policy with no peers should not trigger account peers update and not send peer update
|
||||||
case <-done:
|
step(t, "updating linked posture check to policy with no peers", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
Enabled: true,
|
||||||
}
|
Rules: []*types.PolicyRule{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupB"},
|
||||||
|
Destinations: []string{"groupC"},
|
||||||
|
Bidirectional: true,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SourcePostureChecks: []string{postureCheckB.ID},
|
||||||
|
}, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
postureCheckB.Checks = posture.ChecksDefinition{
|
||||||
|
NBVersionCheck: &posture.NBVersionCheck{
|
||||||
|
MinVersion: "0.29.0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Updating linked posture check to policy where destination has peers but source does not
|
||||||
|
// should trigger account peers update and send peer update
|
||||||
|
step(t, "updating linked posture check to policy where destination has peers but source does not", func(t *testing.T) {
|
||||||
|
updMsg1 := updateManager.CreateChannel(context.Background(), peer2.ID)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
updateManager.CloseChannel(context.Background(), peer2.ID)
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []*types.PolicyRule{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupB"},
|
||||||
|
Destinations: []string{"groupA"},
|
||||||
|
Bidirectional: true,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SourcePostureChecks: []string{postureCheckB.ID},
|
||||||
|
}, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg, updMsg1)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg1)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
postureCheckB.Checks = posture.ChecksDefinition{
|
||||||
|
NBVersionCheck: &posture.NBVersionCheck{
|
||||||
|
MinVersion: "0.29.0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Updating linked client posture check to policy where source has peers but destination does not,
|
||||||
|
// should trigger account peers update and send peer update
|
||||||
|
step(t, "updating linked posture check to policy where source has peers but destination does not", func(t *testing.T) {
|
||||||
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []*types.PolicyRule{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupA"},
|
||||||
|
Destinations: []string{"groupB"},
|
||||||
|
Bidirectional: true,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SourcePostureChecks: []string{postureCheckB.ID},
|
||||||
|
}, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
postureCheckB.Checks = posture.ChecksDefinition{
|
||||||
|
ProcessCheck: &posture.ProcessCheck{
|
||||||
|
Processes: []posture.Process{
|
||||||
|
{
|
||||||
|
LinuxPath: "/usr/bin/netbird",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+252
-244
@@ -6,10 +6,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/mock/gomock"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
|
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
|
||||||
"github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel"
|
"github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel"
|
||||||
@@ -1262,7 +1262,10 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, *update_channel.
|
|||||||
}
|
}
|
||||||
eventStore := &activity.InMemoryEventStore{}
|
eventStore := &activity.InMemoryEventStore{}
|
||||||
|
|
||||||
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
|
metrics, err := telemetry.NewDefaultAppMetrics(ctx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
@@ -1290,9 +1293,8 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, *update_channel.
|
|||||||
permissionsManager := permissions.NewManager(store)
|
permissionsManager := permissions.NewManager(store)
|
||||||
peersManager := peers.NewManager(store, permissionsManager)
|
peersManager := peers.NewManager(store, permissionsManager)
|
||||||
|
|
||||||
ctx := context.Background()
|
// A go-cache janitor only stops through a GC finalizer, which would leave synctest bubbles with a goroutine that never exits.
|
||||||
|
cacheStore, err := cache.NewStore(ctx, 100*time.Millisecond, 0, 100)
|
||||||
cacheStore, err := cache.NewStore(ctx, 100*time.Millisecond, 300*time.Millisecond, 100)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -1301,10 +1303,12 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, *update_channel.
|
|||||||
requestBuffer := NewAccountRequestBuffer(ctx, store)
|
requestBuffer := NewAccountRequestBuffer(ctx, store)
|
||||||
networkMapController := controller.NewController(ctx, store, metrics, updateManager, requestBuffer, MockIntegratedValidator{}, settingsMockManager, "netbird.selfhosted", port_forwarding.NewControllerMock(), ephemeral_manager.NewEphemeralManager(store, peers.NewManager(store, permissionsManager)), &config.Config{}, nil)
|
networkMapController := controller.NewController(ctx, store, metrics, updateManager, requestBuffer, MockIntegratedValidator{}, settingsMockManager, "netbird.selfhosted", port_forwarding.NewControllerMock(), ephemeral_manager.NewEphemeralManager(store, peers.NewManager(store, permissionsManager)), &config.Config{}, nil)
|
||||||
|
|
||||||
am, err := BuildManager(context.Background(), nil, store, networkMapController, job.NewJobManager(nil, store, peersManager), nil, "", eventStore, nil, false, MockIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false, cacheStore)
|
am, err := BuildManager(ctx, nil, store, networkMapController, job.NewJobManager(nil, store, peersManager), nil, "", eventStore, nil, false, MockIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false, cacheStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
cacheManager := am.cacheManager
|
||||||
|
t.Cleanup(func() { _ = cacheManager.Close() })
|
||||||
return am, updateManager, nil
|
return am, updateManager, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1893,265 +1897,269 @@ func TestAccount_getPeersRoutesFirewall(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRouteAccountPeersUpdate(t *testing.T) {
|
func TestRouteAccountPeersUpdate(t *testing.T) {
|
||||||
manager, updateManager, err := createRouterManager(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
require.NoError(t, err, "failed to create account manager")
|
manager, updateManager, err := createRouterManager(t)
|
||||||
|
require.NoError(t, err, "failed to create account manager")
|
||||||
|
|
||||||
account, err := initTestRouteAccount(t, manager)
|
account, err := initTestRouteAccount(t, manager)
|
||||||
require.NoError(t, err, "failed to init testing account")
|
require.NoError(t, err, "failed to init testing account")
|
||||||
|
|
||||||
g := []*types.Group{
|
g := []*types.Group{
|
||||||
{
|
{
|
||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "groupB",
|
ID: "groupB",
|
||||||
Name: "GroupB",
|
Name: "GroupB",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "groupC",
|
ID: "groupC",
|
||||||
Name: "GroupC",
|
Name: "GroupC",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, group := range g {
|
for _, group := range g {
|
||||||
err = manager.CreateGroup(context.Background(), account.Id, userID, group)
|
err = manager.CreateGroup(context.Background(), account.Id, userID, group)
|
||||||
require.NoError(t, err, "failed to create group %s", group.Name)
|
require.NoError(t, err, "failed to create group %s", group.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1ID)
|
updMsg := updateManager.CreateChannel(context.Background(), peer1ID)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
updateManager.CloseChannel(context.Background(), peer1ID)
|
updateManager.CloseChannel(context.Background(), peer1ID)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Creating a route with no routing peer and no peers in PeerGroups or Groups should not update account peers and not send peer update
|
// Creating a route with no routing peer and no peers in PeerGroups or Groups should not update account peers and not send peer update
|
||||||
t.Run("creating route no routing peer and no peers in groups", func(t *testing.T) {
|
step(t, "creating route no routing peer and no peers in groups", func(t *testing.T) {
|
||||||
route := route.Route{
|
settleAffectedUpdates(updMsg)
|
||||||
ID: "testingRoute1",
|
|
||||||
Network: netip.MustParsePrefix("100.65.250.202/32"),
|
route := route.Route{
|
||||||
|
ID: "testingRoute1",
|
||||||
|
Network: netip.MustParsePrefix("100.65.250.202/32"),
|
||||||
|
NetID: "superNet",
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
PeerGroups: []string{"groupA"},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{"groupA"},
|
||||||
|
}
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := manager.CreateRoute(
|
||||||
|
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
|
||||||
|
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
|
||||||
|
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
// Creating a route with no routing peer and having peers in groups that don't include peer1 should not send peer1 an update
|
||||||
|
step(t, "creating a route with peers in PeerGroups and Groups", func(t *testing.T) {
|
||||||
|
drainPeerUpdates(updMsg)
|
||||||
|
|
||||||
|
route := route.Route{
|
||||||
|
ID: "testingRoute2",
|
||||||
|
Network: netip.MustParsePrefix("192.0.2.0/32"),
|
||||||
|
NetID: "superNet",
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
PeerGroups: []string{routeGroup3},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup3},
|
||||||
|
}
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := manager.CreateRoute(
|
||||||
|
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
|
||||||
|
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
|
||||||
|
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
baseRoute := route.Route{
|
||||||
|
ID: "testingRoute3",
|
||||||
|
Network: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
NetID: "superNet",
|
NetID: "superNet",
|
||||||
NetworkType: route.IPv4Network,
|
NetworkType: route.IPv4Network,
|
||||||
PeerGroups: []string{"groupA"},
|
Peer: peer1ID,
|
||||||
Description: "super",
|
|
||||||
Masquerade: false,
|
|
||||||
Metric: 9999,
|
|
||||||
Enabled: true,
|
|
||||||
Groups: []string{"groupA"},
|
|
||||||
}
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err := manager.CreateRoute(
|
|
||||||
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
|
|
||||||
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
|
|
||||||
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
// Creating a route with no routing peer and having peers in groups that don't include peer1 should not send peer1 an update
|
|
||||||
t.Run("creating a route with peers in PeerGroups and Groups", func(t *testing.T) {
|
|
||||||
drainPeerUpdates(updMsg)
|
|
||||||
|
|
||||||
route := route.Route{
|
|
||||||
ID: "testingRoute2",
|
|
||||||
Network: netip.MustParsePrefix("192.0.2.0/32"),
|
|
||||||
NetID: "superNet",
|
|
||||||
NetworkType: route.IPv4Network,
|
|
||||||
PeerGroups: []string{routeGroup3},
|
|
||||||
Description: "super",
|
|
||||||
Masquerade: false,
|
|
||||||
Metric: 9999,
|
|
||||||
Enabled: true,
|
|
||||||
Groups: []string{routeGroup3},
|
|
||||||
}
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err := manager.CreateRoute(
|
|
||||||
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
|
|
||||||
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
|
|
||||||
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
baseRoute := route.Route{
|
|
||||||
ID: "testingRoute3",
|
|
||||||
Network: netip.MustParsePrefix("192.168.0.0/16"),
|
|
||||||
NetID: "superNet",
|
|
||||||
NetworkType: route.IPv4Network,
|
|
||||||
Peer: peer1ID,
|
|
||||||
Description: "super",
|
|
||||||
Masquerade: false,
|
|
||||||
Metric: 9999,
|
|
||||||
Enabled: true,
|
|
||||||
Groups: []string{routeGroup1},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating route should update account peers and send peer update
|
|
||||||
t.Run("creating route with a routing peer", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
newRoute, err := manager.CreateRoute(
|
|
||||||
context.Background(), account.Id, baseRoute.Network, baseRoute.NetworkType, baseRoute.Domains, baseRoute.Peer,
|
|
||||||
baseRoute.PeerGroups, baseRoute.Description, baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric,
|
|
||||||
baseRoute.Groups, []string{}, true, userID, baseRoute.KeepRoute, !baseRoute.SkipAutoApply,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
baseRoute = *newRoute
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Updating the route should update account peers and send peer update when there is peers in group
|
|
||||||
t.Run("updating route", func(t *testing.T) {
|
|
||||||
baseRoute.Groups = []string{routeGroup1, routeGroup2}
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.SaveRoute(context.Background(), account.Id, userID, &baseRoute)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deleting the route should update account peers and send peer update
|
|
||||||
t.Run("deleting route", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := manager.DeleteRoute(context.Background(), account.Id, baseRoute.ID, userID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
case <-time.After(peerUpdateTimeout):
|
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Adding peer to route peer groups that do not have any peers should update account peers and send peer update
|
|
||||||
t.Run("adding peer to route peer groups that do not have any peers", func(t *testing.T) {
|
|
||||||
newRoute := route.Route{
|
|
||||||
Network: netip.MustParsePrefix("192.168.12.0/16"),
|
|
||||||
NetID: "superNet",
|
|
||||||
NetworkType: route.IPv4Network,
|
|
||||||
PeerGroups: []string{"groupB"},
|
|
||||||
Description: "super",
|
Description: "super",
|
||||||
Masquerade: false,
|
Masquerade: false,
|
||||||
Metric: 9999,
|
Metric: 9999,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Groups: []string{routeGroup1},
|
Groups: []string{routeGroup1},
|
||||||
}
|
}
|
||||||
_, err := manager.CreateRoute(
|
|
||||||
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
|
|
||||||
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
|
|
||||||
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, !newRoute.SkipAutoApply,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
// Creating route should update account peers and send peer update
|
||||||
go func() {
|
step(t, "creating route with a routing peer", func(t *testing.T) {
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
done := make(chan struct{})
|
||||||
close(done)
|
go func() {
|
||||||
}()
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
newRoute, err := manager.CreateRoute(
|
||||||
ID: "groupB",
|
context.Background(), account.Id, baseRoute.Network, baseRoute.NetworkType, baseRoute.Domains, baseRoute.Peer,
|
||||||
Name: "GroupB",
|
baseRoute.PeerGroups, baseRoute.Description, baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric,
|
||||||
Peers: []string{peer1ID},
|
baseRoute.Groups, []string{}, true, userID, baseRoute.KeepRoute, !baseRoute.SkipAutoApply,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
baseRoute = *newRoute
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// Updating the route should update account peers and send peer update when there is peers in group
|
||||||
case <-done:
|
step(t, "updating route", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
baseRoute.Groups = []string{routeGroup1, routeGroup2}
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Adding peer to route groups that do not have any peers should update account peers and send peer update
|
done := make(chan struct{})
|
||||||
t.Run("adding peer to route groups that do not have any peers", func(t *testing.T) {
|
go func() {
|
||||||
newRoute := route.Route{
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
Network: netip.MustParsePrefix("192.168.13.0/16"),
|
close(done)
|
||||||
NetID: "superNet",
|
}()
|
||||||
NetworkType: route.IPv4Network,
|
|
||||||
PeerGroups: []string{"groupB"},
|
|
||||||
Description: "super",
|
|
||||||
Masquerade: false,
|
|
||||||
Metric: 9999,
|
|
||||||
Enabled: true,
|
|
||||||
Groups: []string{"groupC"},
|
|
||||||
}
|
|
||||||
_, err := manager.CreateRoute(
|
|
||||||
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
|
|
||||||
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
|
|
||||||
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, !newRoute.SkipAutoApply,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
err := manager.SaveRoute(context.Background(), account.Id, userID, &baseRoute)
|
||||||
go func() {
|
require.NoError(t, err)
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
select {
|
||||||
ID: "groupC",
|
case <-done:
|
||||||
Name: "GroupC",
|
case <-time.After(peerUpdateTimeout):
|
||||||
Peers: []string{peer1ID},
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
// Deleting the route should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "deleting route", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := manager.DeleteRoute(context.Background(), account.Id, baseRoute.ID, userID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Adding peer to route peer groups that do not have any peers should update account peers and send peer update
|
||||||
|
step(t, "adding peer to route peer groups that do not have any peers", func(t *testing.T) {
|
||||||
|
newRoute := route.Route{
|
||||||
|
Network: netip.MustParsePrefix("192.168.12.0/16"),
|
||||||
|
NetID: "superNet",
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
PeerGroups: []string{"groupB"},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{routeGroup1},
|
||||||
|
}
|
||||||
|
_, err := manager.CreateRoute(
|
||||||
|
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
|
||||||
|
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
|
||||||
|
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, !newRoute.SkipAutoApply,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
|
ID: "groupB",
|
||||||
|
Name: "GroupB",
|
||||||
|
Peers: []string{peer1ID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Adding peer to route groups that do not have any peers should update account peers and send peer update
|
||||||
|
step(t, "adding peer to route groups that do not have any peers", func(t *testing.T) {
|
||||||
|
newRoute := route.Route{
|
||||||
|
Network: netip.MustParsePrefix("192.168.13.0/16"),
|
||||||
|
NetID: "superNet",
|
||||||
|
NetworkType: route.IPv4Network,
|
||||||
|
PeerGroups: []string{"groupB"},
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{"groupC"},
|
||||||
|
}
|
||||||
|
_, err := manager.CreateRoute(
|
||||||
|
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
|
||||||
|
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
|
||||||
|
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, !newRoute.SkipAutoApply,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
|
ID: "groupC",
|
||||||
|
Name: "GroupC",
|
||||||
|
Peers: []string{peer1ID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -397,75 +397,77 @@ func TestSetupKey_Copy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSetupKeyAccountPeersUpdate(t *testing.T) {
|
func TestSetupKeyAccountPeersUpdate(t *testing.T) {
|
||||||
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
|
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
|
|
||||||
err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
|
err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
policy := &types.Policy{
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*types.PolicyRule{
|
|
||||||
{
|
|
||||||
Enabled: true,
|
|
||||||
Sources: []string{"groupA"},
|
|
||||||
Destinations: []string{"group"},
|
|
||||||
Bidirectional: true,
|
|
||||||
Action: types.PolicyTrafficActionAccept,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
updateManager.CloseChannel(context.Background(), peer1.ID)
|
|
||||||
})
|
|
||||||
|
|
||||||
// The setup policy above dispatches affected-peer updates asynchronously; drain
|
|
||||||
// any in-flight ones so the assertions only observe the setup-key operations.
|
|
||||||
settleAffectedUpdates(updMsg)
|
|
||||||
|
|
||||||
var setupKey *types.SetupKey
|
|
||||||
|
|
||||||
// Creating setup key should not update account peers and not send peer update
|
|
||||||
t.Run("creating setup key", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
setupKey, err = manager.CreateSetupKey(context.Background(), account.Id, "key1", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
policy := &types.Policy{
|
||||||
case <-done:
|
Enabled: true,
|
||||||
case <-time.After(time.Second):
|
Rules: []*types.PolicyRule{
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Sources: []string{"groupA"},
|
||||||
|
Destinations: []string{"group"},
|
||||||
|
Bidirectional: true,
|
||||||
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
||||||
|
|
||||||
// Saving setup key should not update account peers and not send peer update
|
|
||||||
t.Run("saving setup key", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = manager.SaveSetupKey(context.Background(), account.Id, setupKey, userID)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
select {
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
case <-done:
|
t.Cleanup(func() {
|
||||||
case <-time.After(time.Second):
|
updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
})
|
||||||
}
|
|
||||||
|
// The setup policy above dispatches affected-peer updates asynchronously; drain
|
||||||
|
// any in-flight ones so the assertions only observe the setup-key operations.
|
||||||
|
settleAffectedUpdates(updMsg)
|
||||||
|
|
||||||
|
var setupKey *types.SetupKey
|
||||||
|
|
||||||
|
// Creating setup key should not update account peers and not send peer update
|
||||||
|
step(t, "creating setup key", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
setupKey, err = manager.CreateSetupKey(context.Background(), account.Id, "key1", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Saving setup key should not update account peers and not send peer update
|
||||||
|
step(t, "saving setup key", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = manager.SaveSetupKey(context.Background(), account.Id, setupKey, userID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+135
-131
@@ -1544,166 +1544,170 @@ func TestDefaultAccountManager_SaveUser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUserAccountPeersUpdate(t *testing.T) {
|
func TestUserAccountPeersUpdate(t *testing.T) {
|
||||||
// account groups propagation is enabled
|
runPeerUpdateTest(t, func(t *testing.T) {
|
||||||
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
// account groups propagation is enabled
|
||||||
|
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
|
||||||
|
|
||||||
err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
|
err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
|
||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
policy := &types.Policy{
|
policy := &types.Policy{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Rules: []*types.PolicyRule{
|
Rules: []*types.PolicyRule{
|
||||||
{
|
{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Sources: []string{"groupA"},
|
Sources: []string{"groupA"},
|
||||||
Destinations: []string{"groupA"},
|
Destinations: []string{"groupA"},
|
||||||
Bidirectional: true,
|
Bidirectional: true,
|
||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
updateManager.CloseChannel(context.Background(), peer1.ID)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Creating a new regular user should send peer update (as users are not filtered yet)
|
|
||||||
t.Run("creating new regular user with no groups", func(t *testing.T) {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
|
|
||||||
Id: "regularUser1",
|
|
||||||
AccountID: account.Id,
|
|
||||||
Role: types.UserRoleUser,
|
|
||||||
Issued: types.UserIssuedAPI,
|
|
||||||
}, true)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
select {
|
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
case <-done:
|
t.Cleanup(func() {
|
||||||
case <-time.After(time.Second):
|
updateManager.CloseChannel(context.Background(), peer1.ID)
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// updating user with no linked peers should update account peers and send peer update (as users are not filtered yet)
|
// Creating a new regular user should send peer update (as users are not filtered yet)
|
||||||
t.Run("updating user with no linked peers", func(t *testing.T) {
|
step(t, "creating new regular user with no groups", func(t *testing.T) {
|
||||||
done := make(chan struct{})
|
settleAffectedUpdates(updMsg)
|
||||||
go func() {
|
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
|
done := make(chan struct{})
|
||||||
Id: "regularUser1",
|
go func() {
|
||||||
AccountID: account.Id,
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
Role: types.UserRoleUser,
|
close(done)
|
||||||
Issued: types.UserIssuedAPI,
|
}()
|
||||||
}, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
select {
|
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
|
||||||
case <-done:
|
Id: "regularUser1",
|
||||||
case <-time.After(time.Second):
|
AccountID: account.Id,
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
Role: types.UserRoleUser,
|
||||||
}
|
Issued: types.UserIssuedAPI,
|
||||||
})
|
}, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// drain any buffered updates from previous subtests
|
select {
|
||||||
drainPeerUpdates(updMsg)
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// deleting user with no linked peers should not update account peers and not send peer update
|
// saving an unchanged user with no linked peers should not update account peers and not send peer update
|
||||||
t.Run("deleting user with no linked peers", func(t *testing.T) {
|
step(t, "updating user with no linked peers", func(t *testing.T) {
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
peerShouldNotReceiveUpdate(t, updMsg)
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
close(done)
|
close(done)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = manager.DeleteUser(context.Background(), account.Id, userID, "regularUser1")
|
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
|
||||||
require.NoError(t, err)
|
Id: "regularUser1",
|
||||||
|
AccountID: account.Id,
|
||||||
|
Role: types.UserRoleUser,
|
||||||
|
Issued: types.UserIssuedAPI,
|
||||||
|
}, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
case <-time.After(time.Second):
|
case <-time.After(time.Second):
|
||||||
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// create a user and add new peer with the user
|
// drain any buffered updates from previous subtests
|
||||||
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
|
drainPeerUpdates(updMsg)
|
||||||
Id: "regularUser2",
|
|
||||||
AccountID: account.Id,
|
|
||||||
Role: types.UserRoleAdmin,
|
|
||||||
Issued: types.UserIssuedAPI,
|
|
||||||
}, true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
key, err := wgtypes.GeneratePrivateKey()
|
// deleting user with no linked peers should not update account peers and not send peer update
|
||||||
require.NoError(t, err)
|
step(t, "deleting user with no linked peers", func(t *testing.T) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
peerShouldNotReceiveUpdate(t, updMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
expectedPeerKey := key.PublicKey().String()
|
err = manager.DeleteUser(context.Background(), account.Id, userID, "regularUser1")
|
||||||
peer4, _, _, _, err := manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
|
require.NoError(t, err)
|
||||||
Key: expectedPeerKey,
|
|
||||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
|
||||||
}, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// updating user with linked peers should update account peers and send peer update
|
select {
|
||||||
t.Run("updating user with linked peers", func(t *testing.T) {
|
case <-done:
|
||||||
done := make(chan struct{})
|
case <-time.After(time.Second):
|
||||||
go func() {
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
peerShouldReceiveUpdate(t, updMsg)
|
}
|
||||||
close(done)
|
})
|
||||||
}()
|
|
||||||
|
|
||||||
|
// create a user and add new peer with the user
|
||||||
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
|
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
|
||||||
Id: "regularUser2",
|
Id: "regularUser2",
|
||||||
AccountID: account.Id,
|
AccountID: account.Id,
|
||||||
Role: types.UserRoleAdmin,
|
Role: types.UserRoleAdmin,
|
||||||
Issued: types.UserIssuedAPI,
|
Issued: types.UserIssuedAPI,
|
||||||
|
}, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
key, err := wgtypes.GeneratePrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expectedPeerKey := key.PublicKey().String()
|
||||||
|
peer4, _, _, _, err := manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
|
||||||
|
Key: expectedPeerKey,
|
||||||
|
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||||
}, false)
|
}, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
select {
|
// updating user with linked peers should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "updating user with linked peers", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldReceiveUpdate(t, updMsg)
|
||||||
})
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
peer4UpdMsg := updateManager.CreateChannel(context.Background(), peer4.ID)
|
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
|
||||||
t.Cleanup(func() {
|
Id: "regularUser2",
|
||||||
updateManager.CloseChannel(context.Background(), peer4.ID)
|
AccountID: account.Id,
|
||||||
})
|
Role: types.UserRoleAdmin,
|
||||||
|
Issued: types.UserIssuedAPI,
|
||||||
|
}, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// deleting user with linked peers should update account peers and send peer update
|
select {
|
||||||
t.Run("deleting user with linked peers", func(t *testing.T) {
|
case <-done:
|
||||||
done := make(chan struct{})
|
case <-time.After(peerUpdateTimeout):
|
||||||
go func() {
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
peerShouldReceiveUpdate(t, peer4UpdMsg)
|
}
|
||||||
close(done)
|
})
|
||||||
}()
|
|
||||||
|
|
||||||
err = manager.DeleteUser(context.Background(), account.Id, userID, "regularUser2")
|
peer4UpdMsg := updateManager.CreateChannel(context.Background(), peer4.ID)
|
||||||
require.NoError(t, err)
|
t.Cleanup(func() {
|
||||||
|
updateManager.CloseChannel(context.Background(), peer4.ID)
|
||||||
|
})
|
||||||
|
|
||||||
select {
|
// deleting user with linked peers should update account peers and send peer update
|
||||||
case <-done:
|
step(t, "deleting user with linked peers", func(t *testing.T) {
|
||||||
case <-time.After(peerUpdateTimeout):
|
done := make(chan struct{})
|
||||||
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
go func() {
|
||||||
}
|
peerShouldReceiveUpdate(t, peer4UpdMsg)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = manager.DeleteUser(context.Background(), account.Id, userID, "regularUser2")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(peerUpdateTimeout):
|
||||||
|
t.Error("timeout waiting for peerShouldReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user