mirror of
https://github.com/netbirdio/netbird.git
synced 2025-02-16 10:20:09 +01:00
[management] Remove file store (#2689)
This commit is contained in:
parent
8934453b30
commit
158936fb15
@ -3,7 +3,6 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -34,18 +33,12 @@ func startTestingServices(t *testing.T) string {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
testDir := t.TempDir()
|
|
||||||
config.Datadir = testDir
|
|
||||||
err = util.CopyFileContents("../testdata/store.json", filepath.Join(testDir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, signalLis := startSignal(t)
|
_, signalLis := startSignal(t)
|
||||||
signalAddr := signalLis.Addr().String()
|
signalAddr := signalLis.Addr().String()
|
||||||
config.Signal.URI = signalAddr
|
config.Signal.URI = signalAddr
|
||||||
|
|
||||||
_, mgmLis := startManagement(t, config)
|
_, mgmLis := startManagement(t, config, "../testdata/store.sqlite")
|
||||||
mgmAddr := mgmLis.Addr().String()
|
mgmAddr := mgmLis.Addr().String()
|
||||||
return mgmAddr
|
return mgmAddr
|
||||||
}
|
}
|
||||||
@ -70,7 +63,7 @@ func startSignal(t *testing.T) (*grpc.Server, net.Listener) {
|
|||||||
return s, lis
|
return s, lis
|
||||||
}
|
}
|
||||||
|
|
||||||
func startManagement(t *testing.T, config *mgmt.Config) (*grpc.Server, net.Listener) {
|
func startManagement(t *testing.T, config *mgmt.Config, testFile string) (*grpc.Server, net.Listener) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
lis, err := net.Listen("tcp", ":0")
|
lis, err := net.Listen("tcp", ":0")
|
||||||
@ -78,7 +71,7 @@ func startManagement(t *testing.T, config *mgmt.Config) (*grpc.Server, net.Liste
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
store, cleanUp, err := mgmt.NewTestStoreFromJson(context.Background(), config.Datadir)
|
store, cleanUp, err := mgmt.NewTestStoreFromSqlite(context.Background(), testFile, t.TempDir())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -824,20 +823,6 @@ func TestEngine_UpdateNetworkMapWithDNSUpdate(t *testing.T) {
|
|||||||
func TestEngine_MultiplePeers(t *testing.T) {
|
func TestEngine_MultiplePeers(t *testing.T) {
|
||||||
// log.SetLevel(log.DebugLevel)
|
// log.SetLevel(log.DebugLevel)
|
||||||
|
|
||||||
dir := t.TempDir()
|
|
||||||
|
|
||||||
err := util.CopyFileContents("../testdata/store.json", filepath.Join(dir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
err = os.Remove(filepath.Join(dir, "store.json")) //nolint
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(CtxInitState(context.Background()))
|
ctx, cancel := context.WithCancel(CtxInitState(context.Background()))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@ -847,7 +832,7 @@ func TestEngine_MultiplePeers(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer sigServer.Stop()
|
defer sigServer.Stop()
|
||||||
mgmtServer, mgmtAddr, err := startManagement(t, dir)
|
mgmtServer, mgmtAddr, err := startManagement(t, t.TempDir(), "../testdata/store.sqlite")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
return
|
return
|
||||||
@ -1070,7 +1055,7 @@ func startSignal(t *testing.T) (*grpc.Server, string, error) {
|
|||||||
return s, lis.Addr().String(), nil
|
return s, lis.Addr().String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startManagement(t *testing.T, dataDir string) (*grpc.Server, string, error) {
|
func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, string, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
config := &server.Config{
|
config := &server.Config{
|
||||||
@ -1095,7 +1080,7 @@ func startManagement(t *testing.T, dataDir string) (*grpc.Server, string, error)
|
|||||||
}
|
}
|
||||||
s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
|
s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
|
||||||
|
|
||||||
store, cleanUp, err := server.NewTestStoreFromJson(context.Background(), config.Datadir)
|
store, cleanUp, err := server.NewTestStoreFromSqlite(context.Background(), testFile, config.Datadir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ func startManagement(t *testing.T, signalAddr string, counter *int) (*grpc.Serve
|
|||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
|
s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
|
||||||
store, cleanUp, err := server.NewTestStoreFromJson(context.Background(), config.Datadir)
|
store, cleanUp, err := server.NewTestStoreFromSqlite(context.Background(), "", config.Datadir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
38
client/testdata/store.json
vendored
38
client/testdata/store.json
vendored
@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"Accounts": {
|
|
||||||
"bf1c8084-ba50-4ce7-9439-34653001fc3b": {
|
|
||||||
"Id": "bf1c8084-ba50-4ce7-9439-34653001fc3b",
|
|
||||||
"SetupKeys": {
|
|
||||||
"A2C8E62B-38F5-4553-B31E-DD66C696CEBB": {
|
|
||||||
"Key": "A2C8E62B-38F5-4553-B31E-DD66C696CEBB",
|
|
||||||
"Name": "Default key",
|
|
||||||
"Type": "reusable",
|
|
||||||
"CreatedAt": "2021-08-19T20:46:20.005936822+02:00",
|
|
||||||
"ExpiresAt": "2321-09-18T20:46:20.005936822+02:00",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 0
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Network": {
|
|
||||||
"Id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
|
|
||||||
"Net": {
|
|
||||||
"IP": "100.64.0.0",
|
|
||||||
"Mask": "//8AAA=="
|
|
||||||
},
|
|
||||||
"Dns": null
|
|
||||||
},
|
|
||||||
"Peers": {},
|
|
||||||
"Users": {
|
|
||||||
"edafee4e-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"Role": "admin"
|
|
||||||
},
|
|
||||||
"f4f6d672-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "f4f6d672-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"Role": "user"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
BIN
client/testdata/store.sqlite
vendored
Normal file
BIN
client/testdata/store.sqlite
vendored
Normal file
Binary file not shown.
@ -47,25 +47,18 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
|
|||||||
level, _ := log.ParseLevel("debug")
|
level, _ := log.ParseLevel("debug")
|
||||||
log.SetLevel(level)
|
log.SetLevel(level)
|
||||||
|
|
||||||
testDir := t.TempDir()
|
|
||||||
|
|
||||||
config := &mgmt.Config{}
|
config := &mgmt.Config{}
|
||||||
_, err := util.ReadJson("../server/testdata/management.json", config)
|
_, err := util.ReadJson("../server/testdata/management.json", config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
config.Datadir = testDir
|
|
||||||
err = util.CopyFileContents("../server/testdata/store.json", filepath.Join(testDir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
lis, err := net.Listen("tcp", ":0")
|
lis, err := net.Listen("tcp", ":0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
store, cleanUp, err := mgmt.NewTestStoreFromJson(context.Background(), config.Datadir)
|
store, cleanUp, err := NewSqliteTestStore(t, context.Background(), "../server/testdata/store.sqlite")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -521,3 +514,22 @@ func Test_GetPKCEAuthorizationFlow(t *testing.T) {
|
|||||||
assert.Equal(t, expectedFlowInfo.ProviderConfig.ClientID, flowInfo.ProviderConfig.ClientID, "provider configured client ID should match")
|
assert.Equal(t, expectedFlowInfo.ProviderConfig.ClientID, flowInfo.ProviderConfig.ClientID, "provider configured client ID should match")
|
||||||
assert.Equal(t, expectedFlowInfo.ProviderConfig.ClientSecret, flowInfo.ProviderConfig.ClientSecret, "provider configured client secret should match")
|
assert.Equal(t, expectedFlowInfo.ProviderConfig.ClientSecret, flowInfo.ProviderConfig.ClientSecret, "provider configured client secret should match")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewSqliteTestStore(t *testing.T, ctx context.Context, testFile string) (mgmt.Store, func(), error) {
|
||||||
|
t.Helper()
|
||||||
|
dataDir := t.TempDir()
|
||||||
|
err := util.CopyFileContents(testFile, filepath.Join(dataDir, "store.db"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := mgmt.NewSqliteStore(ctx, dataDir, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return store, func() {
|
||||||
|
store.Close(ctx)
|
||||||
|
os.Remove(filepath.Join(dataDir, "store.db"))
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
@ -2366,7 +2366,7 @@ func createManager(t TB) (*DefaultAccountManager, error) {
|
|||||||
func createStore(t TB) (Store, error) {
|
func createStore(t TB) (Store, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
dataDir := t.TempDir()
|
dataDir := t.TempDir()
|
||||||
store, cleanUp, err := NewTestStoreFromJson(context.Background(), dataDir)
|
store, cleanUp, err := NewTestStoreFromSqlite(context.Background(), "", dataDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ func createDNSManager(t *testing.T) (*DefaultAccountManager, error) {
|
|||||||
func createDNSStore(t *testing.T) (Store, error) {
|
func createDNSStore(t *testing.T) (Store, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
dataDir := t.TempDir()
|
dataDir := t.TempDir()
|
||||||
store, cleanUp, err := NewTestStoreFromJson(context.Background(), dataDir)
|
store, cleanUp, err := NewTestStoreFromSqlite(context.Background(), "", dataDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -2,24 +2,18 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/dns"
|
|
||||||
nbgroup "github.com/netbirdio/netbird/management/server/group"
|
|
||||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
|
||||||
"github.com/netbirdio/netbird/management/server/posture"
|
|
||||||
"github.com/netbirdio/netbird/management/server/status"
|
|
||||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
|
||||||
"github.com/netbirdio/netbird/route"
|
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
nbgroup "github.com/netbirdio/netbird/management/server/group"
|
||||||
|
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||||
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||||
"github.com/netbirdio/netbird/util"
|
"github.com/netbirdio/netbird/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,167 +36,9 @@ type FileStore struct {
|
|||||||
mux sync.Mutex `json:"-"`
|
mux sync.Mutex `json:"-"`
|
||||||
storeFile string `json:"-"`
|
storeFile string `json:"-"`
|
||||||
|
|
||||||
// sync.Mutex indexed by resource ID
|
|
||||||
resourceLocks sync.Map `json:"-"`
|
|
||||||
globalAccountLock sync.Mutex `json:"-"`
|
|
||||||
|
|
||||||
metrics telemetry.AppMetrics `json:"-"`
|
metrics telemetry.AppMetrics `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FileStore) ExecuteInTransaction(ctx context.Context, f func(store Store) error) error {
|
|
||||||
return f(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) IncrementSetupKeyUsage(ctx context.Context, setupKeyID string) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.SetupKeyID2AccountID[strings.ToUpper(setupKeyID)]
|
|
||||||
if !ok {
|
|
||||||
return status.NewSetupKeyNotFoundError()
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
account.SetupKeys[setupKeyID].UsedTimes++
|
|
||||||
|
|
||||||
return s.SaveAccount(ctx, account)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) AddPeerToAllGroup(ctx context.Context, accountID string, peerID string) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
allGroup, err := account.GetGroupAll()
|
|
||||||
if err != nil || allGroup == nil {
|
|
||||||
return errors.New("all group not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
allGroup.Peers = append(allGroup.Peers, peerID)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) AddPeerToGroup(ctx context.Context, accountId string, peerId string, groupID string) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
account.Groups[groupID].Peers = append(account.Groups[groupID].Peers, peerId)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) AddPeerToAccount(ctx context.Context, peer *nbpeer.Peer) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, ok := s.Accounts[peer.AccountID]
|
|
||||||
if !ok {
|
|
||||||
return status.NewAccountNotFoundError(peer.AccountID)
|
|
||||||
}
|
|
||||||
|
|
||||||
account.Peers[peer.ID] = peer
|
|
||||||
return s.SaveAccount(ctx, account)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) IncrementNetworkSerial(ctx context.Context, accountId string) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, ok := s.Accounts[accountId]
|
|
||||||
if !ok {
|
|
||||||
return status.NewAccountNotFoundError(accountId)
|
|
||||||
}
|
|
||||||
|
|
||||||
account.Network.Serial++
|
|
||||||
|
|
||||||
return s.SaveAccount(ctx, account)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetSetupKeyBySecret(ctx context.Context, lockStrength LockingStrength, key string) (*SetupKey, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.SetupKeyID2AccountID[strings.ToUpper(key)]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewSetupKeyNotFoundError()
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
setupKey, ok := account.SetupKeys[key]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.Errorf(status.NotFound, "setup key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return setupKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetTakenIPs(ctx context.Context, lockStrength LockingStrength, accountID string) ([]net.IP, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var takenIps []net.IP
|
|
||||||
for _, existingPeer := range account.Peers {
|
|
||||||
takenIps = append(takenIps, existingPeer.IP)
|
|
||||||
}
|
|
||||||
|
|
||||||
return takenIps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetPeerLabelsInAccount(ctx context.Context, lockStrength LockingStrength, accountID string) ([]string, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
existingLabels := []string{}
|
|
||||||
for _, peer := range account.Peers {
|
|
||||||
if peer.DNSLabel != "" {
|
|
||||||
existingLabels = append(existingLabels, peer.DNSLabel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return existingLabels, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountNetwork(ctx context.Context, lockStrength LockingStrength, accountID string) (*Network, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Network, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type StoredAccount struct{}
|
|
||||||
|
|
||||||
// NewFileStore restores a store from the file located in the datadir
|
// NewFileStore restores a store from the file located in the datadir
|
||||||
func NewFileStore(ctx context.Context, dataDir string, metrics telemetry.AppMetrics) (*FileStore, error) {
|
func NewFileStore(ctx context.Context, dataDir string, metrics telemetry.AppMetrics) (*FileStore, error) {
|
||||||
fs, err := restore(ctx, filepath.Join(dataDir, storeFileName))
|
fs, err := restore(ctx, filepath.Join(dataDir, storeFileName))
|
||||||
@ -213,25 +49,6 @@ func NewFileStore(ctx context.Context, dataDir string, metrics telemetry.AppMetr
|
|||||||
return fs, nil
|
return fs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFilestoreFromSqliteStore restores a store from Sqlite and stores to Filestore json in the file located in datadir
|
|
||||||
func NewFilestoreFromSqliteStore(ctx context.Context, sqlStore *SqlStore, dataDir string, metrics telemetry.AppMetrics) (*FileStore, error) {
|
|
||||||
store, err := NewFileStore(ctx, dataDir, metrics)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = store.SaveInstallationID(ctx, sqlStore.GetInstallationID())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, account := range sqlStore.GetAllAccounts(ctx) {
|
|
||||||
store.Accounts[account.Id] = account
|
|
||||||
}
|
|
||||||
|
|
||||||
return store, store.persist(ctx, store.storeFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore the state of the store from the file.
|
// restore the state of the store from the file.
|
||||||
// Creates a new empty store file if doesn't exist
|
// Creates a new empty store file if doesn't exist
|
||||||
func restore(ctx context.Context, file string) (*FileStore, error) {
|
func restore(ctx context.Context, file string) (*FileStore, error) {
|
||||||
@ -240,7 +57,6 @@ func restore(ctx context.Context, file string) (*FileStore, error) {
|
|||||||
s := &FileStore{
|
s := &FileStore{
|
||||||
Accounts: make(map[string]*Account),
|
Accounts: make(map[string]*Account),
|
||||||
mux: sync.Mutex{},
|
mux: sync.Mutex{},
|
||||||
globalAccountLock: sync.Mutex{},
|
|
||||||
SetupKeyID2AccountID: make(map[string]string),
|
SetupKeyID2AccountID: make(map[string]string),
|
||||||
PeerKeyID2AccountID: make(map[string]string),
|
PeerKeyID2AccountID: make(map[string]string),
|
||||||
UserID2AccountID: make(map[string]string),
|
UserID2AccountID: make(map[string]string),
|
||||||
@ -416,252 +232,6 @@ func (s *FileStore) persist(ctx context.Context, file string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcquireGlobalLock acquires global lock across all the accounts and returns a function that releases the lock
|
|
||||||
func (s *FileStore) AcquireGlobalLock(ctx context.Context) (unlock func()) {
|
|
||||||
log.WithContext(ctx).Debugf("acquiring global lock")
|
|
||||||
start := time.Now()
|
|
||||||
s.globalAccountLock.Lock()
|
|
||||||
|
|
||||||
unlock = func() {
|
|
||||||
s.globalAccountLock.Unlock()
|
|
||||||
log.WithContext(ctx).Debugf("released global lock in %v", time.Since(start))
|
|
||||||
}
|
|
||||||
|
|
||||||
took := time.Since(start)
|
|
||||||
log.WithContext(ctx).Debugf("took %v to acquire global lock", took)
|
|
||||||
if s.metrics != nil {
|
|
||||||
s.metrics.StoreMetrics().CountGlobalLockAcquisitionDuration(took)
|
|
||||||
}
|
|
||||||
|
|
||||||
return unlock
|
|
||||||
}
|
|
||||||
|
|
||||||
// AcquireWriteLockByUID acquires an ID lock for writing to a resource and returns a function that releases the lock
|
|
||||||
func (s *FileStore) AcquireWriteLockByUID(ctx context.Context, uniqueID string) (unlock func()) {
|
|
||||||
log.WithContext(ctx).Debugf("acquiring lock for ID %s", uniqueID)
|
|
||||||
start := time.Now()
|
|
||||||
value, _ := s.resourceLocks.LoadOrStore(uniqueID, &sync.Mutex{})
|
|
||||||
mtx := value.(*sync.Mutex)
|
|
||||||
mtx.Lock()
|
|
||||||
|
|
||||||
unlock = func() {
|
|
||||||
mtx.Unlock()
|
|
||||||
log.WithContext(ctx).Debugf("released lock for ID %s in %v", uniqueID, time.Since(start))
|
|
||||||
}
|
|
||||||
|
|
||||||
return unlock
|
|
||||||
}
|
|
||||||
|
|
||||||
// AcquireReadLockByUID acquires an ID lock for reading a resource and returns a function that releases the lock
|
|
||||||
// This method is still returns a write lock as file store can't handle read locks
|
|
||||||
func (s *FileStore) AcquireReadLockByUID(ctx context.Context, uniqueID string) (unlock func()) {
|
|
||||||
return s.AcquireWriteLockByUID(ctx, uniqueID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) SaveAccount(ctx context.Context, account *Account) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
if account.Id == "" {
|
|
||||||
return status.Errorf(status.InvalidArgument, "account id should not be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
accountCopy := account.Copy()
|
|
||||||
|
|
||||||
s.Accounts[accountCopy.Id] = accountCopy
|
|
||||||
|
|
||||||
// todo check that account.Id and keyId are not exist already
|
|
||||||
// because if keyId exists for other accounts this can be bad
|
|
||||||
for keyID := range accountCopy.SetupKeys {
|
|
||||||
s.SetupKeyID2AccountID[strings.ToUpper(keyID)] = accountCopy.Id
|
|
||||||
}
|
|
||||||
|
|
||||||
// enforce peer to account index and delete peer to route indexes for rebuild
|
|
||||||
for _, peer := range accountCopy.Peers {
|
|
||||||
s.PeerKeyID2AccountID[peer.Key] = accountCopy.Id
|
|
||||||
s.PeerID2AccountID[peer.ID] = accountCopy.Id
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range accountCopy.Users {
|
|
||||||
s.UserID2AccountID[user.Id] = accountCopy.Id
|
|
||||||
for _, pat := range user.PATs {
|
|
||||||
s.TokenID2UserID[pat.ID] = user.Id
|
|
||||||
s.HashedPAT2TokenID[pat.HashedToken] = pat.ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if accountCopy.DomainCategory == PrivateCategory && accountCopy.IsDomainPrimaryAccount {
|
|
||||||
s.PrivateDomain2AccountID[accountCopy.Domain] = accountCopy.Id
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.persist(ctx, s.storeFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) DeleteAccount(ctx context.Context, account *Account) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
if account.Id == "" {
|
|
||||||
return status.Errorf(status.InvalidArgument, "account id should not be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
for keyID := range account.SetupKeys {
|
|
||||||
delete(s.SetupKeyID2AccountID, strings.ToUpper(keyID))
|
|
||||||
}
|
|
||||||
|
|
||||||
// enforce peer to account index and delete peer to route indexes for rebuild
|
|
||||||
for _, peer := range account.Peers {
|
|
||||||
delete(s.PeerKeyID2AccountID, peer.Key)
|
|
||||||
delete(s.PeerID2AccountID, peer.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range account.Users {
|
|
||||||
for _, pat := range user.PATs {
|
|
||||||
delete(s.TokenID2UserID, pat.ID)
|
|
||||||
delete(s.HashedPAT2TokenID, pat.HashedToken)
|
|
||||||
}
|
|
||||||
delete(s.UserID2AccountID, user.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
if account.DomainCategory == PrivateCategory && account.IsDomainPrimaryAccount {
|
|
||||||
delete(s.PrivateDomain2AccountID, account.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(s.Accounts, account.Id)
|
|
||||||
|
|
||||||
return s.persist(ctx, s.storeFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteHashedPAT2TokenIDIndex removes an entry from the indexing map HashedPAT2TokenID
|
|
||||||
func (s *FileStore) DeleteHashedPAT2TokenIDIndex(hashedToken string) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
delete(s.HashedPAT2TokenID, hashedToken)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteTokenID2UserIDIndex removes an entry from the indexing map TokenID2UserID
|
|
||||||
func (s *FileStore) DeleteTokenID2UserIDIndex(tokenID string) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
delete(s.TokenID2UserID, tokenID)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccountByPrivateDomain returns account by private domain
|
|
||||||
func (s *FileStore) GetAccountByPrivateDomain(_ context.Context, domain string) (*Account, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.PrivateDomain2AccountID[strings.ToLower(domain)]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.Errorf(status.NotFound, "account not found: provided domain is not registered or is not private")
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Copy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccountBySetupKey returns account by setup key id
|
|
||||||
func (s *FileStore) GetAccountBySetupKey(_ context.Context, setupKey string) (*Account, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.SetupKeyID2AccountID[strings.ToUpper(setupKey)]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewSetupKeyNotFoundError()
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Copy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTokenIDByHashedToken returns the id of a personal access token by its hashed secret
|
|
||||||
func (s *FileStore) GetTokenIDByHashedToken(_ context.Context, token string) (string, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
tokenID, ok := s.HashedPAT2TokenID[token]
|
|
||||||
if !ok {
|
|
||||||
return "", status.Errorf(status.NotFound, "tokenID not found: provided token doesn't exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenID, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserByTokenID returns a User object a tokenID belongs to
|
|
||||||
func (s *FileStore) GetUserByTokenID(_ context.Context, tokenID string) (*User, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
userID, ok := s.TokenID2UserID[tokenID]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.Errorf(status.NotFound, "user not found: provided tokenID doesn't exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
accountID, ok := s.UserID2AccountID[userID]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.Errorf(status.NotFound, "accountID not found: provided userID doesn't exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Users[userID].Copy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetUserByUserID(_ context.Context, _ LockingStrength, userID string) (*User, error) {
|
|
||||||
accountID, ok := s.UserID2AccountID[userID]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.Errorf(status.NotFound, "accountID not found: provided userID doesn't exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
user := account.Users[userID].Copy()
|
|
||||||
pat := make([]PersonalAccessToken, 0, len(user.PATs))
|
|
||||||
for _, token := range user.PATs {
|
|
||||||
if token != nil {
|
|
||||||
pat = append(pat, *token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
user.PATsG = pat
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountGroups(_ context.Context, accountID string) ([]*nbgroup.Group, error) {
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
groupsSlice := make([]*nbgroup.Group, 0, len(account.Groups))
|
|
||||||
|
|
||||||
for _, group := range account.Groups {
|
|
||||||
groupsSlice = append(groupsSlice, group)
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupsSlice, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllAccounts returns all accounts
|
// GetAllAccounts returns all accounts
|
||||||
func (s *FileStore) GetAllAccounts(_ context.Context) (all []*Account) {
|
func (s *FileStore) GetAllAccounts(_ context.Context) (all []*Account) {
|
||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
@ -673,278 +243,6 @@ func (s *FileStore) GetAllAccounts(_ context.Context) (all []*Account) {
|
|||||||
return all
|
return all
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAccount returns a reference to the Account. Should not return a copy.
|
|
||||||
func (s *FileStore) getAccount(accountID string) (*Account, error) {
|
|
||||||
account, ok := s.Accounts[accountID]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewAccountNotFoundError(accountID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return account, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccount returns an account for ID
|
|
||||||
func (s *FileStore) GetAccount(_ context.Context, accountID string) (*Account, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Copy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccountByUser returns a user account
|
|
||||||
func (s *FileStore) GetAccountByUser(_ context.Context, userID string) (*Account, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.UserID2AccountID[userID]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewUserNotFoundError(userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Copy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccountByPeerID returns an account for a given peer ID
|
|
||||||
func (s *FileStore) GetAccountByPeerID(ctx context.Context, peerID string) (*Account, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.PeerID2AccountID[peerID]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.Errorf(status.NotFound, "provided peer ID doesn't exists %s", peerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// this protection is needed because when we delete a peer, we don't really remove index peerID -> accountID.
|
|
||||||
// check Account.Peers for a match
|
|
||||||
if _, ok := account.Peers[peerID]; !ok {
|
|
||||||
delete(s.PeerID2AccountID, peerID)
|
|
||||||
log.WithContext(ctx).Warnf("removed stale peerID %s to accountID %s index", peerID, accountID)
|
|
||||||
return nil, status.NewPeerNotFoundError(peerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Copy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccountByPeerPubKey returns an account for a given peer WireGuard public key
|
|
||||||
func (s *FileStore) GetAccountByPeerPubKey(ctx context.Context, peerKey string) (*Account, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.PeerKeyID2AccountID[peerKey]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewPeerNotFoundError(peerKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// this protection is needed because when we delete a peer, we don't really remove index peerKey -> accountID.
|
|
||||||
// check Account.Peers for a match
|
|
||||||
stale := true
|
|
||||||
for _, peer := range account.Peers {
|
|
||||||
if peer.Key == peerKey {
|
|
||||||
stale = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if stale {
|
|
||||||
delete(s.PeerKeyID2AccountID, peerKey)
|
|
||||||
log.WithContext(ctx).Warnf("removed stale peerKey %s to accountID %s index", peerKey, accountID)
|
|
||||||
return nil, status.NewPeerNotFoundError(peerKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Copy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountIDByPeerPubKey(_ context.Context, peerKey string) (string, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.PeerKeyID2AccountID[peerKey]
|
|
||||||
if !ok {
|
|
||||||
return "", status.NewPeerNotFoundError(peerKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
return accountID, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountIDByUserID(userID string) (string, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.UserID2AccountID[userID]
|
|
||||||
if !ok {
|
|
||||||
return "", status.NewUserNotFoundError(userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return accountID, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountIDBySetupKey(_ context.Context, setupKey string) (string, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.SetupKeyID2AccountID[strings.ToUpper(setupKey)]
|
|
||||||
if !ok {
|
|
||||||
return "", status.NewSetupKeyNotFoundError()
|
|
||||||
}
|
|
||||||
|
|
||||||
return accountID, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetPeerByPeerPubKey(_ context.Context, _ LockingStrength, peerKey string) (*nbpeer.Peer, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountID, ok := s.PeerKeyID2AccountID[peerKey]
|
|
||||||
if !ok {
|
|
||||||
return nil, status.NewPeerNotFoundError(peerKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, peer := range account.Peers {
|
|
||||||
if peer.Key == peerKey {
|
|
||||||
return peer.Copy(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, status.NewPeerNotFoundError(peerKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountSettings(_ context.Context, _ LockingStrength, accountID string) (*Settings, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Settings.Copy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInstallationID returns the installation ID from the store
|
|
||||||
func (s *FileStore) GetInstallationID() string {
|
|
||||||
return s.InstallationID
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveInstallationID saves the installation ID
|
|
||||||
func (s *FileStore) SaveInstallationID(ctx context.Context, ID string) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
s.InstallationID = ID
|
|
||||||
|
|
||||||
return s.persist(ctx, s.storeFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SavePeer saves the peer in the account
|
|
||||||
func (s *FileStore) SavePeer(_ context.Context, accountID string, peer *nbpeer.Peer) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newPeer := peer.Copy()
|
|
||||||
|
|
||||||
account.Peers[peer.ID] = newPeer
|
|
||||||
|
|
||||||
s.PeerKeyID2AccountID[peer.Key] = accountID
|
|
||||||
s.PeerID2AccountID[peer.ID] = accountID
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SavePeerStatus stores the PeerStatus in memory. It doesn't attempt to persist data to speed up things.
|
|
||||||
// PeerStatus will be saved eventually when some other changes occur.
|
|
||||||
func (s *FileStore) SavePeerStatus(accountID, peerID string, peerStatus nbpeer.PeerStatus) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
peer := account.Peers[peerID]
|
|
||||||
if peer == nil {
|
|
||||||
return status.Errorf(status.NotFound, "peer %s not found", peerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
peer.Status = &peerStatus
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SavePeerLocation stores the PeerStatus in memory. It doesn't attempt to persist data to speed up things.
|
|
||||||
// Peer.Location will be saved eventually when some other changes occur.
|
|
||||||
func (s *FileStore) SavePeerLocation(accountID string, peerWithLocation *nbpeer.Peer) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
peer := account.Peers[peerWithLocation.ID]
|
|
||||||
if peer == nil {
|
|
||||||
return status.Errorf(status.NotFound, "peer %s not found", peerWithLocation.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
peer.Location = peerWithLocation.Location
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveUserLastLogin stores the last login time for a user in memory. It doesn't attempt to persist data to speed up things.
|
|
||||||
func (s *FileStore) SaveUserLastLogin(_ context.Context, accountID, userID string, lastLogin time.Time) error {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
peer := account.Users[userID]
|
|
||||||
if peer == nil {
|
|
||||||
return status.Errorf(status.NotFound, "user %s not found", userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
peer.LastLogin = lastLogin
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetPostureCheckByChecksDefinition(_ string, _ *posture.ChecksDefinition) (*posture.Checks, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetPostureCheckByChecksDefinition is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the FileStore persisting data to disk
|
// Close the FileStore persisting data to disk
|
||||||
func (s *FileStore) Close(ctx context.Context) error {
|
func (s *FileStore) Close(ctx context.Context) error {
|
||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
@ -959,86 +257,3 @@ func (s *FileStore) Close(ctx context.Context) error {
|
|||||||
func (s *FileStore) GetStoreEngine() StoreEngine {
|
func (s *FileStore) GetStoreEngine() StoreEngine {
|
||||||
return FileStoreEngine
|
return FileStoreEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FileStore) SaveUsers(_ string, _ map[string]*User) error {
|
|
||||||
return status.Errorf(status.Internal, "SaveUsers is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) SaveGroups(_ string, _ map[string]*nbgroup.Group) error {
|
|
||||||
return status.Errorf(status.Internal, "SaveGroups is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountIDByPrivateDomain(_ context.Context, _ LockingStrength, _ string) (string, error) {
|
|
||||||
return "", status.Errorf(status.Internal, "GetAccountIDByPrivateDomain is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountDomainAndCategory(_ context.Context, _ LockingStrength, accountID string) (string, string, error) {
|
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
account, err := s.getAccount(accountID)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.Domain, account.DomainCategory, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccountExists checks whether an account exists by the given ID.
|
|
||||||
func (s *FileStore) AccountExists(_ context.Context, _ LockingStrength, id string) (bool, error) {
|
|
||||||
_, exists := s.Accounts[id]
|
|
||||||
return exists, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountDNSSettings(_ context.Context, _ LockingStrength, _ string) (*DNSSettings, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetAccountDNSSettings is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetGroupByID(_ context.Context, _ LockingStrength, _, _ string) (*nbgroup.Group, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetGroupByID is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetGroupByName(_ context.Context, _ LockingStrength, _, _ string) (*nbgroup.Group, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetGroupByName is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountPolicies(_ context.Context, _ LockingStrength, _ string) ([]*Policy, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetPolicyByID is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetPolicyByID(_ context.Context, _ LockingStrength, _ string, _ string) (*Policy, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetPolicyByID is not implemented")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountPostureChecks(_ context.Context, _ LockingStrength, _ string) ([]*posture.Checks, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetAccountPostureChecks is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetPostureChecksByID(_ context.Context, _ LockingStrength, _ string, _ string) (*posture.Checks, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetPostureChecksByID is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountRoutes(_ context.Context, _ LockingStrength, _ string) ([]*route.Route, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetAccountRoutes is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetRouteByID(_ context.Context, _ LockingStrength, _ string, _ string) (*route.Route, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetRouteByID is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountSetupKeys(_ context.Context, _ LockingStrength, _ string) ([]*SetupKey, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetAccountSetupKeys is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetSetupKeyByID(_ context.Context, _ LockingStrength, _ string, _ string) (*SetupKey, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetSetupKeyByID is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetAccountNameServerGroups(_ context.Context, _ LockingStrength, _ string) ([]*dns.NameServerGroup, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetAccountNameServerGroups is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FileStore) GetNameServerGroupByID(_ context.Context, _ LockingStrength, _ string, _ string) (*dns.NameServerGroup, error) {
|
|
||||||
return nil, status.Errorf(status.Internal, "GetNameServerGroupByID is not implemented")
|
|
||||||
}
|
|
||||||
|
@ -1,655 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/sha256"
|
|
||||||
"net"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/group"
|
|
||||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
|
||||||
"github.com/netbirdio/netbird/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
type accounts struct {
|
|
||||||
Accounts map[string]*Account
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStalePeerIndices(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
|
|
||||||
err := util.CopyFileContents("testdata/store.json", filepath.Join(storeDir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
peerID := "some_peer"
|
|
||||||
peerKey := "some_peer_key"
|
|
||||||
account.Peers[peerID] = &nbpeer.Peer{
|
|
||||||
ID: peerID,
|
|
||||||
Key: peerKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = store.SaveAccount(context.Background(), account)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
account.DeletePeer(peerID)
|
|
||||||
|
|
||||||
err = store.SaveAccount(context.Background(), account)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
_, err = store.GetAccountByPeerID(context.Background(), peerID)
|
|
||||||
require.Error(t, err, "expecting to get an error when found stale index")
|
|
||||||
|
|
||||||
_, err = store.GetAccountByPeerPubKey(context.Background(), peerKey)
|
|
||||||
require.Error(t, err, "expecting to get an error when found stale index")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewStore(t *testing.T) {
|
|
||||||
store := newStore(t)
|
|
||||||
defer store.Close(context.Background())
|
|
||||||
|
|
||||||
if store.Accounts == nil || len(store.Accounts) != 0 {
|
|
||||||
t.Errorf("expected to create a new empty Accounts map when creating a new FileStore")
|
|
||||||
}
|
|
||||||
|
|
||||||
if store.SetupKeyID2AccountID == nil || len(store.SetupKeyID2AccountID) != 0 {
|
|
||||||
t.Errorf("expected to create a new empty SetupKeyID2AccountID map when creating a new FileStore")
|
|
||||||
}
|
|
||||||
|
|
||||||
if store.PeerKeyID2AccountID == nil || len(store.PeerKeyID2AccountID) != 0 {
|
|
||||||
t.Errorf("expected to create a new empty PeerKeyID2AccountID map when creating a new FileStore")
|
|
||||||
}
|
|
||||||
|
|
||||||
if store.UserID2AccountID == nil || len(store.UserID2AccountID) != 0 {
|
|
||||||
t.Errorf("expected to create a new empty UserID2AccountID map when creating a new FileStore")
|
|
||||||
}
|
|
||||||
|
|
||||||
if store.HashedPAT2TokenID == nil || len(store.HashedPAT2TokenID) != 0 {
|
|
||||||
t.Errorf("expected to create a new empty HashedPAT2TokenID map when creating a new FileStore")
|
|
||||||
}
|
|
||||||
|
|
||||||
if store.TokenID2UserID == nil || len(store.TokenID2UserID) != 0 {
|
|
||||||
t.Errorf("expected to create a new empty TokenID2UserID map when creating a new FileStore")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSaveAccount(t *testing.T) {
|
|
||||||
store := newStore(t)
|
|
||||||
defer store.Close(context.Background())
|
|
||||||
|
|
||||||
account := newAccountWithId(context.Background(), "account_id", "testuser", "")
|
|
||||||
setupKey := GenerateDefaultSetupKey()
|
|
||||||
account.SetupKeys[setupKey.Key] = setupKey
|
|
||||||
account.Peers["testpeer"] = &nbpeer.Peer{
|
|
||||||
Key: "peerkey",
|
|
||||||
SetupKey: "peerkeysetupkey",
|
|
||||||
IP: net.IP{127, 0, 0, 1},
|
|
||||||
Meta: nbpeer.PeerSystemMeta{},
|
|
||||||
Name: "peer name",
|
|
||||||
Status: &nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()},
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveAccount should trigger persist
|
|
||||||
err := store.SaveAccount(context.Background(), account)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if store.Accounts[account.Id] == nil {
|
|
||||||
t.Errorf("expecting Account to be stored after SaveAccount()")
|
|
||||||
}
|
|
||||||
|
|
||||||
if store.PeerKeyID2AccountID["peerkey"] == "" {
|
|
||||||
t.Errorf("expecting PeerKeyID2AccountID index updated after SaveAccount()")
|
|
||||||
}
|
|
||||||
|
|
||||||
if store.UserID2AccountID["testuser"] == "" {
|
|
||||||
t.Errorf("expecting UserID2AccountID index updated after SaveAccount()")
|
|
||||||
}
|
|
||||||
|
|
||||||
if store.SetupKeyID2AccountID[setupKey.Key] == "" {
|
|
||||||
t.Errorf("expecting SetupKeyID2AccountID index updated after SaveAccount()")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteAccount(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
storeFile := filepath.Join(storeDir, "store.json")
|
|
||||||
err := util.CopyFileContents("testdata/store.json", storeFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer store.Close(context.Background())
|
|
||||||
|
|
||||||
var account *Account
|
|
||||||
for _, a := range store.Accounts {
|
|
||||||
account = a
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NotNil(t, account, "failed to restore a FileStore file and get at least one account")
|
|
||||||
|
|
||||||
err = store.DeleteAccount(context.Background(), account)
|
|
||||||
require.NoError(t, err, "failed to delete account, error: %v", err)
|
|
||||||
|
|
||||||
_, ok := store.Accounts[account.Id]
|
|
||||||
require.False(t, ok, "failed to delete account")
|
|
||||||
|
|
||||||
for id := range account.Users {
|
|
||||||
_, ok := store.UserID2AccountID[id]
|
|
||||||
assert.False(t, ok, "failed to delete UserID2AccountID index")
|
|
||||||
for _, pat := range account.Users[id].PATs {
|
|
||||||
_, ok := store.HashedPAT2TokenID[pat.HashedToken]
|
|
||||||
assert.False(t, ok, "failed to delete HashedPAT2TokenID index")
|
|
||||||
_, ok = store.TokenID2UserID[pat.ID]
|
|
||||||
assert.False(t, ok, "failed to delete TokenID2UserID index")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range account.Peers {
|
|
||||||
_, ok := store.PeerKeyID2AccountID[p.Key]
|
|
||||||
assert.False(t, ok, "failed to delete PeerKeyID2AccountID index")
|
|
||||||
_, ok = store.PeerID2AccountID[p.ID]
|
|
||||||
assert.False(t, ok, "failed to delete PeerID2AccountID index")
|
|
||||||
}
|
|
||||||
|
|
||||||
for id := range account.SetupKeys {
|
|
||||||
_, ok := store.SetupKeyID2AccountID[id]
|
|
||||||
assert.False(t, ok, "failed to delete SetupKeyID2AccountID index")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, ok = store.PrivateDomain2AccountID[account.Domain]
|
|
||||||
assert.False(t, ok, "failed to delete PrivateDomain2AccountID index")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStore(t *testing.T) {
|
|
||||||
store := newStore(t)
|
|
||||||
defer store.Close(context.Background())
|
|
||||||
|
|
||||||
account := newAccountWithId(context.Background(), "account_id", "testuser", "")
|
|
||||||
account.Peers["testpeer"] = &nbpeer.Peer{
|
|
||||||
Key: "peerkey",
|
|
||||||
SetupKey: "peerkeysetupkey",
|
|
||||||
IP: net.IP{127, 0, 0, 1},
|
|
||||||
Meta: nbpeer.PeerSystemMeta{},
|
|
||||||
Name: "peer name",
|
|
||||||
Status: &nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()},
|
|
||||||
}
|
|
||||||
account.Groups["all"] = &group.Group{
|
|
||||||
ID: "all",
|
|
||||||
Name: "all",
|
|
||||||
Peers: []string{"testpeer"},
|
|
||||||
}
|
|
||||||
account.Policies = append(account.Policies, &Policy{
|
|
||||||
ID: "all",
|
|
||||||
Name: "all",
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*PolicyRule{
|
|
||||||
{
|
|
||||||
ID: "all",
|
|
||||||
Name: "all",
|
|
||||||
Sources: []string{"all"},
|
|
||||||
Destinations: []string{"all"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
account.Policies = append(account.Policies, &Policy{
|
|
||||||
ID: "dmz",
|
|
||||||
Name: "dmz",
|
|
||||||
Enabled: true,
|
|
||||||
Rules: []*PolicyRule{
|
|
||||||
{
|
|
||||||
ID: "dmz",
|
|
||||||
Name: "dmz",
|
|
||||||
Enabled: true,
|
|
||||||
Sources: []string{"all"},
|
|
||||||
Destinations: []string{"all"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// SaveAccount should trigger persist
|
|
||||||
err := store.SaveAccount(context.Background(), account)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
restored, err := NewFileStore(context.Background(), store.storeFile, nil)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
restoredAccount := restored.Accounts[account.Id]
|
|
||||||
if restoredAccount == nil {
|
|
||||||
t.Errorf("failed to restore a FileStore file - missing Account %s", account.Id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if restoredAccount.Peers["testpeer"] == nil {
|
|
||||||
t.Errorf("failed to restore a FileStore file - missing Peer testpeer")
|
|
||||||
}
|
|
||||||
|
|
||||||
if restoredAccount.CreatedBy != "testuser" {
|
|
||||||
t.Errorf("failed to restore a FileStore file - missing Account CreatedBy")
|
|
||||||
}
|
|
||||||
|
|
||||||
if restoredAccount.Users["testuser"] == nil {
|
|
||||||
t.Errorf("failed to restore a FileStore file - missing User testuser")
|
|
||||||
}
|
|
||||||
|
|
||||||
if restoredAccount.Network == nil {
|
|
||||||
t.Errorf("failed to restore a FileStore file - missing Network")
|
|
||||||
}
|
|
||||||
|
|
||||||
if restoredAccount.Groups["all"] == nil {
|
|
||||||
t.Errorf("failed to restore a FileStore file - missing Group all")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(restoredAccount.Policies) != 2 {
|
|
||||||
t.Errorf("failed to restore a FileStore file - missing Policies")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, account.Policies[0], restoredAccount.Policies[0], "failed to restore a FileStore file - missing Policy all")
|
|
||||||
assert.Equal(t, account.Policies[1], restoredAccount.Policies[1], "failed to restore a FileStore file - missing Policy dmz")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRestore(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
|
|
||||||
err := util.CopyFileContents("testdata/store.json", filepath.Join(storeDir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
account := store.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"]
|
|
||||||
|
|
||||||
require.NotNil(t, account, "failed to restore a FileStore file - missing account bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
|
||||||
|
|
||||||
require.NotNil(t, account.Users["edafee4e-63fb-11ec-90d6-0242ac120003"], "failed to restore a FileStore file - missing Account User edafee4e-63fb-11ec-90d6-0242ac120003")
|
|
||||||
|
|
||||||
require.NotNil(t, account.Users["f4f6d672-63fb-11ec-90d6-0242ac120003"], "failed to restore a FileStore file - missing Account User f4f6d672-63fb-11ec-90d6-0242ac120003")
|
|
||||||
|
|
||||||
require.NotNil(t, account.Network, "failed to restore a FileStore file - missing Account Network")
|
|
||||||
|
|
||||||
require.NotNil(t, account.SetupKeys["A2C8E62B-38F5-4553-B31E-DD66C696CEBB"], "failed to restore a FileStore file - missing Account SetupKey A2C8E62B-38F5-4553-B31E-DD66C696CEBB")
|
|
||||||
|
|
||||||
require.NotNil(t, account.Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs["9dj38s35-63fb-11ec-90d6-0242ac120003"], "failed to restore a FileStore wrong PATs length")
|
|
||||||
|
|
||||||
require.Len(t, store.UserID2AccountID, 2, "failed to restore a FileStore wrong UserID2AccountID mapping length")
|
|
||||||
|
|
||||||
require.Len(t, store.SetupKeyID2AccountID, 1, "failed to restore a FileStore wrong SetupKeyID2AccountID mapping length")
|
|
||||||
|
|
||||||
require.Len(t, store.PrivateDomain2AccountID, 1, "failed to restore a FileStore wrong PrivateDomain2AccountID mapping length")
|
|
||||||
|
|
||||||
require.Len(t, store.HashedPAT2TokenID, 1, "failed to restore a FileStore wrong HashedPAT2TokenID mapping length")
|
|
||||||
|
|
||||||
require.Len(t, store.TokenID2UserID, 1, "failed to restore a FileStore wrong TokenID2UserID mapping length")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRestoreGroups_Migration(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
|
|
||||||
err := util.CopyFileContents("testdata/store.json", filepath.Join(storeDir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// create default group
|
|
||||||
account := store.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"]
|
|
||||||
account.Groups = map[string]*group.Group{
|
|
||||||
"cfefqs706sqkneg59g3g": {
|
|
||||||
ID: "cfefqs706sqkneg59g3g",
|
|
||||||
Name: "All",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err = store.SaveAccount(context.Background(), account)
|
|
||||||
require.NoError(t, err, "failed to save account")
|
|
||||||
|
|
||||||
// restore account with default group with empty Issue field
|
|
||||||
if store, err = NewFileStore(context.Background(), storeDir, nil); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
account = store.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"]
|
|
||||||
|
|
||||||
require.Contains(t, account.Groups, "cfefqs706sqkneg59g3g", "failed to restore a FileStore file - missing Account Groups")
|
|
||||||
require.Equal(t, group.GroupIssuedAPI, account.Groups["cfefqs706sqkneg59g3g"].Issued, "default group should has API issued mark")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAccountByPrivateDomain(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
|
|
||||||
err := util.CopyFileContents("testdata/store.json", filepath.Join(storeDir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
existingDomain := "test.com"
|
|
||||||
|
|
||||||
account, err := store.GetAccountByPrivateDomain(context.Background(), existingDomain)
|
|
||||||
require.NoError(t, err, "should found account")
|
|
||||||
require.Equal(t, existingDomain, account.Domain, "domains should match")
|
|
||||||
|
|
||||||
_, err = store.GetAccountByPrivateDomain(context.Background(), "missing-domain.com")
|
|
||||||
require.Error(t, err, "should return error on domain lookup")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileStore_GetAccount(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
storeFile := filepath.Join(storeDir, "store.json")
|
|
||||||
err := util.CopyFileContents("testdata/store.json", storeFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts := &accounts{}
|
|
||||||
_, err = util.ReadJson(storeFile, accounts)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"]
|
|
||||||
if expected == nil {
|
|
||||||
t.Fatalf("expected account doesn't exist")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := store.GetAccount(context.Background(), expected.Id)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, expected.IsDomainPrimaryAccount, account.IsDomainPrimaryAccount)
|
|
||||||
assert.Equal(t, expected.DomainCategory, account.DomainCategory)
|
|
||||||
assert.Equal(t, expected.Domain, account.Domain)
|
|
||||||
assert.Equal(t, expected.CreatedBy, account.CreatedBy)
|
|
||||||
assert.Equal(t, expected.Network.Identifier, account.Network.Identifier)
|
|
||||||
assert.Len(t, account.Peers, len(expected.Peers))
|
|
||||||
assert.Len(t, account.Users, len(expected.Users))
|
|
||||||
assert.Len(t, account.SetupKeys, len(expected.SetupKeys))
|
|
||||||
assert.Len(t, account.Routes, len(expected.Routes))
|
|
||||||
assert.Len(t, account.NameServerGroups, len(expected.NameServerGroups))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileStore_GetTokenIDByHashedToken(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
storeFile := filepath.Join(storeDir, "store.json")
|
|
||||||
err := util.CopyFileContents("testdata/store.json", storeFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts := &accounts{}
|
|
||||||
_, err = util.ReadJson(storeFile, accounts)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hashedToken := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"].Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs["9dj38s35-63fb-11ec-90d6-0242ac120003"].HashedToken
|
|
||||||
tokenID, err := store.GetTokenIDByHashedToken(context.Background(), hashedToken)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedTokenID := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"].Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs["9dj38s35-63fb-11ec-90d6-0242ac120003"].ID
|
|
||||||
assert.Equal(t, expectedTokenID, tokenID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileStore_DeleteHashedPAT2TokenIDIndex(t *testing.T) {
|
|
||||||
store := newStore(t)
|
|
||||||
defer store.Close(context.Background())
|
|
||||||
store.HashedPAT2TokenID["someHashedToken"] = "someTokenId"
|
|
||||||
|
|
||||||
err := store.DeleteHashedPAT2TokenIDIndex("someHashedToken")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Empty(t, store.HashedPAT2TokenID["someHashedToken"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileStore_DeleteTokenID2UserIDIndex(t *testing.T) {
|
|
||||||
store := newStore(t)
|
|
||||||
store.TokenID2UserID["someTokenId"] = "someUserId"
|
|
||||||
|
|
||||||
err := store.DeleteTokenID2UserIDIndex("someTokenId")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Empty(t, store.TokenID2UserID["someTokenId"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileStore_GetTokenIDByHashedToken_Failure(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
storeFile := filepath.Join(storeDir, "store.json")
|
|
||||||
err := util.CopyFileContents("testdata/store.json", storeFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts := &accounts{}
|
|
||||||
_, err = util.ReadJson(storeFile, accounts)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
wrongToken := sha256.Sum256([]byte("someNotValidTokenThatFails1234"))
|
|
||||||
_, err = store.GetTokenIDByHashedToken(context.Background(), string(wrongToken[:]))
|
|
||||||
|
|
||||||
assert.Error(t, err, "GetTokenIDByHashedToken should throw error if token invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileStore_GetUserByTokenID(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
storeFile := filepath.Join(storeDir, "store.json")
|
|
||||||
err := util.CopyFileContents("testdata/store.json", storeFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts := &accounts{}
|
|
||||||
_, err = util.ReadJson(storeFile, accounts)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenID := accounts.Accounts["bf1c8084-ba50-4ce7-9439-34653001fc3b"].Users["f4f6d672-63fb-11ec-90d6-0242ac120003"].PATs["9dj38s35-63fb-11ec-90d6-0242ac120003"].ID
|
|
||||||
user, err := store.GetUserByTokenID(context.Background(), tokenID)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, "f4f6d672-63fb-11ec-90d6-0242ac120003", user.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileStore_GetUserByTokenID_Failure(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
storeFile := filepath.Join(storeDir, "store.json")
|
|
||||||
err := util.CopyFileContents("testdata/store.json", storeFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts := &accounts{}
|
|
||||||
_, err = util.ReadJson(storeFile, accounts)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
wrongTokenID := "someNonExistingTokenID"
|
|
||||||
_, err = store.GetUserByTokenID(context.Background(), wrongTokenID)
|
|
||||||
|
|
||||||
assert.Error(t, err, "GetUserByTokenID should throw error if tokenID invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileStore_SavePeerStatus(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
|
|
||||||
err := util.CopyFileContents("testdata/store.json", filepath.Join(storeDir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := store.getAccount("bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// save status of non-existing peer
|
|
||||||
newStatus := nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()}
|
|
||||||
err = store.SavePeerStatus(account.Id, "non-existing-peer", newStatus)
|
|
||||||
assert.Error(t, err)
|
|
||||||
|
|
||||||
// save new status of existing peer
|
|
||||||
account.Peers["testpeer"] = &nbpeer.Peer{
|
|
||||||
Key: "peerkey",
|
|
||||||
ID: "testpeer",
|
|
||||||
SetupKey: "peerkeysetupkey",
|
|
||||||
IP: net.IP{127, 0, 0, 1},
|
|
||||||
Meta: nbpeer.PeerSystemMeta{},
|
|
||||||
Name: "peer name",
|
|
||||||
Status: &nbpeer.PeerStatus{Connected: false, LastSeen: time.Now().UTC()},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = store.SaveAccount(context.Background(), account)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = store.SavePeerStatus(account.Id, "testpeer", newStatus)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
account, err = store.getAccount(account.Id)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
actual := account.Peers["testpeer"].Status
|
|
||||||
assert.Equal(t, newStatus, *actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileStore_SavePeerLocation(t *testing.T) {
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
|
|
||||||
err := util.CopyFileContents("testdata/store.json", filepath.Join(storeDir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
store, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
peer := &nbpeer.Peer{
|
|
||||||
AccountID: account.Id,
|
|
||||||
ID: "testpeer",
|
|
||||||
Location: nbpeer.Location{
|
|
||||||
ConnectionIP: net.ParseIP("10.0.0.0"),
|
|
||||||
CountryCode: "YY",
|
|
||||||
CityName: "City",
|
|
||||||
GeoNameID: 1,
|
|
||||||
},
|
|
||||||
Meta: nbpeer.PeerSystemMeta{},
|
|
||||||
}
|
|
||||||
// error is expected as peer is not in store yet
|
|
||||||
err = store.SavePeerLocation(account.Id, peer)
|
|
||||||
assert.Error(t, err)
|
|
||||||
|
|
||||||
account.Peers[peer.ID] = peer
|
|
||||||
err = store.SaveAccount(context.Background(), account)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
peer.Location.ConnectionIP = net.ParseIP("35.1.1.1")
|
|
||||||
peer.Location.CountryCode = "DE"
|
|
||||||
peer.Location.CityName = "Berlin"
|
|
||||||
peer.Location.GeoNameID = 2950159
|
|
||||||
|
|
||||||
err = store.SavePeerLocation(account.Id, account.Peers[peer.ID])
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
account, err = store.GetAccount(context.Background(), account.Id)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
actual := account.Peers[peer.ID].Location
|
|
||||||
assert.Equal(t, peer.Location, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStore(t *testing.T) *FileStore {
|
|
||||||
t.Helper()
|
|
||||||
store, err := NewFileStore(context.Background(), t.TempDir(), nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed creating a new store")
|
|
||||||
}
|
|
||||||
|
|
||||||
return store
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -89,14 +88,7 @@ func getServerKey(client mgmtProto.ManagementServiceClient) (*wgtypes.Key, error
|
|||||||
|
|
||||||
func Test_SyncProtocol(t *testing.T) {
|
func Test_SyncProtocol(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
err := util.CopyFileContents("testdata/store_with_expired_peers.json", filepath.Join(dir, "store.json"))
|
mgmtServer, _, mgmtAddr, cleanup, err := startManagementForTest(t, "testdata/store_with_expired_peers.sqlite", &Config{
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
os.Remove(filepath.Join(dir, "store.json")) //nolint
|
|
||||||
}()
|
|
||||||
mgmtServer, _, mgmtAddr, err := startManagementForTest(t, &Config{
|
|
||||||
Stuns: []*Host{{
|
Stuns: []*Host{{
|
||||||
Proto: "udp",
|
Proto: "udp",
|
||||||
URI: "stun:stun.wiretrustee.com:3468",
|
URI: "stun:stun.wiretrustee.com:3468",
|
||||||
@ -117,6 +109,7 @@ func Test_SyncProtocol(t *testing.T) {
|
|||||||
Datadir: dir,
|
Datadir: dir,
|
||||||
HttpConfig: nil,
|
HttpConfig: nil,
|
||||||
})
|
})
|
||||||
|
defer cleanup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
return
|
return
|
||||||
@ -412,18 +405,18 @@ func TestServer_GetDeviceAuthorizationFlow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func startManagementForTest(t TestingT, config *Config) (*grpc.Server, *DefaultAccountManager, string, error) {
|
func startManagementForTest(t *testing.T, testFile string, config *Config) (*grpc.Server, *DefaultAccountManager, string, func(), error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
lis, err := net.Listen("tcp", "localhost:0")
|
lis, err := net.Listen("tcp", "localhost:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, "", err
|
return nil, nil, "", nil, err
|
||||||
}
|
}
|
||||||
s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
|
s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
|
||||||
store, cleanUp, err := NewTestStoreFromJson(context.Background(), config.Datadir)
|
|
||||||
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), testFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, "", err
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
|
||||||
|
|
||||||
peersUpdateManager := NewPeersUpdateManager(nil)
|
peersUpdateManager := NewPeersUpdateManager(nil)
|
||||||
eventStore := &activity.InMemoryEventStore{}
|
eventStore := &activity.InMemoryEventStore{}
|
||||||
@ -437,7 +430,8 @@ func startManagementForTest(t TestingT, config *Config) (*grpc.Server, *DefaultA
|
|||||||
eventStore, nil, false, MocIntegratedValidator{}, metrics)
|
eventStore, nil, false, MocIntegratedValidator{}, metrics)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, "", err
|
cleanup()
|
||||||
|
return nil, nil, "", cleanup, err
|
||||||
}
|
}
|
||||||
|
|
||||||
secretsManager := NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay)
|
secretsManager := NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay)
|
||||||
@ -445,7 +439,7 @@ func startManagementForTest(t TestingT, config *Config) (*grpc.Server, *DefaultA
|
|||||||
ephemeralMgr := NewEphemeralManager(store, accountManager)
|
ephemeralMgr := NewEphemeralManager(store, accountManager)
|
||||||
mgmtServer, err := NewServer(context.Background(), config, accountManager, peersUpdateManager, secretsManager, nil, ephemeralMgr)
|
mgmtServer, err := NewServer(context.Background(), config, accountManager, peersUpdateManager, secretsManager, nil, ephemeralMgr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, "", err
|
return nil, nil, "", cleanup, err
|
||||||
}
|
}
|
||||||
mgmtProto.RegisterManagementServiceServer(s, mgmtServer)
|
mgmtProto.RegisterManagementServiceServer(s, mgmtServer)
|
||||||
|
|
||||||
@ -455,7 +449,7 @@ func startManagementForTest(t TestingT, config *Config) (*grpc.Server, *DefaultA
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return s, accountManager, lis.Addr().String(), nil
|
return s, accountManager, lis.Addr().String(), cleanup, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.ClientConn, error) {
|
func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.ClientConn, error) {
|
||||||
@ -475,6 +469,7 @@ func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.Clie
|
|||||||
|
|
||||||
return mgmtProto.NewManagementServiceClient(conn), conn, nil
|
return mgmtProto.NewManagementServiceClient(conn), conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_SyncStatusRace(t *testing.T) {
|
func Test_SyncStatusRace(t *testing.T) {
|
||||||
if os.Getenv("CI") == "true" && os.Getenv("NETBIRD_STORE_ENGINE") == "postgres" {
|
if os.Getenv("CI") == "true" && os.Getenv("NETBIRD_STORE_ENGINE") == "postgres" {
|
||||||
t.Skip("Skipping on CI and Postgres store")
|
t.Skip("Skipping on CI and Postgres store")
|
||||||
@ -488,15 +483,8 @@ func Test_SyncStatusRace(t *testing.T) {
|
|||||||
func testSyncStatusRace(t *testing.T) {
|
func testSyncStatusRace(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
err := util.CopyFileContents("testdata/store_with_expired_peers.json", filepath.Join(dir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
os.Remove(filepath.Join(dir, "store.json")) //nolint
|
|
||||||
}()
|
|
||||||
|
|
||||||
mgmtServer, am, mgmtAddr, err := startManagementForTest(t, &Config{
|
mgmtServer, am, mgmtAddr, cleanup, err := startManagementForTest(t, "testdata/store_with_expired_peers.sqlite", &Config{
|
||||||
Stuns: []*Host{{
|
Stuns: []*Host{{
|
||||||
Proto: "udp",
|
Proto: "udp",
|
||||||
URI: "stun:stun.wiretrustee.com:3468",
|
URI: "stun:stun.wiretrustee.com:3468",
|
||||||
@ -517,6 +505,7 @@ func testSyncStatusRace(t *testing.T) {
|
|||||||
Datadir: dir,
|
Datadir: dir,
|
||||||
HttpConfig: nil,
|
HttpConfig: nil,
|
||||||
})
|
})
|
||||||
|
defer cleanup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
return
|
return
|
||||||
@ -665,15 +654,8 @@ func Test_LoginPerformance(t *testing.T) {
|
|||||||
t.Run(bc.name, func(t *testing.T) {
|
t.Run(bc.name, func(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
err := util.CopyFileContents("testdata/store_with_expired_peers.json", filepath.Join(dir, "store.json"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
os.Remove(filepath.Join(dir, "store.json")) //nolint
|
|
||||||
}()
|
|
||||||
|
|
||||||
mgmtServer, am, _, err := startManagementForTest(t, &Config{
|
mgmtServer, am, _, cleanup, err := startManagementForTest(t, "testdata/store_with_expired_peers.sqlite", &Config{
|
||||||
Stuns: []*Host{{
|
Stuns: []*Host{{
|
||||||
Proto: "udp",
|
Proto: "udp",
|
||||||
URI: "stun:stun.wiretrustee.com:3468",
|
URI: "stun:stun.wiretrustee.com:3468",
|
||||||
@ -694,6 +676,7 @@ func Test_LoginPerformance(t *testing.T) {
|
|||||||
Datadir: dir,
|
Datadir: dir,
|
||||||
HttpConfig: nil,
|
HttpConfig: nil,
|
||||||
})
|
})
|
||||||
|
defer cleanup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
return
|
return
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
sync2 "sync"
|
sync2 "sync"
|
||||||
"time"
|
"time"
|
||||||
@ -52,8 +51,6 @@ var _ = Describe("Management service", func() {
|
|||||||
dataDir, err = os.MkdirTemp("", "wiretrustee_mgmt_test_tmp_*")
|
dataDir, err = os.MkdirTemp("", "wiretrustee_mgmt_test_tmp_*")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
err = util.CopyFileContents("testdata/store.json", filepath.Join(dataDir, "store.json"))
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
var listener net.Listener
|
var listener net.Listener
|
||||||
|
|
||||||
config := &server.Config{}
|
config := &server.Config{}
|
||||||
@ -61,7 +58,7 @@ var _ = Describe("Management service", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
config.Datadir = dataDir
|
config.Datadir = dataDir
|
||||||
|
|
||||||
s, listener = startServer(config)
|
s, listener = startServer(config, dataDir, "testdata/store.sqlite")
|
||||||
addr = listener.Addr().String()
|
addr = listener.Addr().String()
|
||||||
client, conn = createRawClient(addr)
|
client, conn = createRawClient(addr)
|
||||||
|
|
||||||
@ -530,12 +527,12 @@ func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.Clie
|
|||||||
return mgmtProto.NewManagementServiceClient(conn), conn
|
return mgmtProto.NewManagementServiceClient(conn), conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func startServer(config *server.Config) (*grpc.Server, net.Listener) {
|
func startServer(config *server.Config, dataDir string, testFile string) (*grpc.Server, net.Listener) {
|
||||||
lis, err := net.Listen("tcp", ":0")
|
lis, err := net.Listen("tcp", ":0")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
|
|
||||||
store, _, err := server.NewTestStoreFromJson(context.Background(), config.Datadir)
|
store, _, err := server.NewTestStoreFromSqlite(context.Background(), testFile, dataDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed creating a store: %s: %v", config.Datadir, err)
|
log.Fatalf("failed creating a store: %s: %v", config.Datadir, err)
|
||||||
}
|
}
|
||||||
|
@ -773,7 +773,7 @@ func createNSManager(t *testing.T) (*DefaultAccountManager, error) {
|
|||||||
func createNSStore(t *testing.T) (Store, error) {
|
func createNSStore(t *testing.T) (Store, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
dataDir := t.TempDir()
|
dataDir := t.TempDir()
|
||||||
store, cleanUp, err := NewTestStoreFromJson(context.Background(), dataDir)
|
store, cleanUp, err := NewTestStoreFromSqlite(context.Background(), "", dataDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +1004,11 @@ func Test_RegisterPeerByUser(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/extended-store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/extended-store.sqlite")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
eventStore := &activity.InMemoryEventStore{}
|
eventStore := &activity.InMemoryEventStore{}
|
||||||
|
|
||||||
@ -1065,7 +1069,11 @@ func Test_RegisterPeerBySetupKey(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/extended-store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/extended-store.sqlite")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
eventStore := &activity.InMemoryEventStore{}
|
eventStore := &activity.InMemoryEventStore{}
|
||||||
|
|
||||||
@ -1127,7 +1135,11 @@ func Test_RegisterPeerRollbackOnFailure(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/extended-store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/extended-store.sqlite")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
eventStore := &activity.InMemoryEventStore{}
|
eventStore := &activity.InMemoryEventStore{}
|
||||||
|
|
||||||
|
@ -1257,7 +1257,7 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, error) {
|
|||||||
func createRouterStore(t *testing.T) (Store, error) {
|
func createRouterStore(t *testing.T) (Store, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
dataDir := t.TempDir()
|
dataDir := t.TempDir()
|
||||||
store, cleanUp, err := NewTestStoreFromJson(context.Background(), dataDir)
|
store, cleanUp, err := NewTestStoreFromSqlite(context.Background(), "", dataDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1737,7 +1737,7 @@ func TestAccount_getPeersRoutesFirewall(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.ElementsMatch(t, routesFirewallRules, expectedRoutesFirewallRules)
|
assert.ElementsMatch(t, routesFirewallRules, expectedRoutesFirewallRules)
|
||||||
|
|
||||||
//peerD is also the routing peer for route1, should contain same routes firewall rules as peerA
|
// peerD is also the routing peer for route1, should contain same routes firewall rules as peerA
|
||||||
routesFirewallRules = account.getPeerRoutesFirewallRules(context.Background(), "peerD", validatedPeers)
|
routesFirewallRules = account.getPeerRoutesFirewallRules(context.Background(), "peerD", validatedPeers)
|
||||||
assert.Len(t, routesFirewallRules, 2)
|
assert.Len(t, routesFirewallRules, 2)
|
||||||
assert.ElementsMatch(t, routesFirewallRules, expectedRoutesFirewallRules)
|
assert.ElementsMatch(t, routesFirewallRules, expectedRoutesFirewallRules)
|
||||||
|
@ -915,6 +915,28 @@ func NewPostgresqlStoreFromFileStore(ctx context.Context, fileStore *FileStore,
|
|||||||
return store, nil
|
return store, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewPostgresqlStoreFromSqlStore restores a store from SqlStore and stores Postgres DB.
|
||||||
|
func NewPostgresqlStoreFromSqlStore(ctx context.Context, sqliteStore *SqlStore, dsn string, metrics telemetry.AppMetrics) (*SqlStore, error) {
|
||||||
|
store, err := NewPostgresqlStore(ctx, dsn, metrics)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = store.SaveInstallationID(ctx, sqliteStore.GetInstallationID())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, account := range sqliteStore.GetAllAccounts(ctx) {
|
||||||
|
err := store.SaveAccount(ctx, account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return store, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SqlStore) GetSetupKeyBySecret(ctx context.Context, lockStrength LockingStrength, key string) (*SetupKey, error) {
|
func (s *SqlStore) GetSetupKeyBySecret(ctx context.Context, lockStrength LockingStrength, key string) (*SetupKey, error) {
|
||||||
var setupKey SetupKey
|
var setupKey SetupKey
|
||||||
result := s.db.WithContext(ctx).Clauses(clause.Locking{Strength: string(lockStrength)}).
|
result := s.db.WithContext(ctx).Clauses(clause.Locking{Strength: string(lockStrength)}).
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -25,7 +24,6 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
|
|
||||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||||
"github.com/netbirdio/netbird/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSqlite_NewStore(t *testing.T) {
|
func TestSqlite_NewStore(t *testing.T) {
|
||||||
@ -347,7 +345,11 @@ func TestSqlite_GetAccount(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/store.sqlite")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
id := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
id := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
|
|
||||||
@ -367,7 +369,11 @@ func TestSqlite_SavePeer(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/store.sqlite")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -415,7 +421,11 @@ func TestSqlite_SavePeerStatus(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/store.sqlite")
|
||||||
|
defer cleanup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -468,8 +478,11 @@ func TestSqlite_SavePeerLocation(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/store.sqlite")
|
||||||
|
defer cleanup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -519,8 +532,11 @@ func TestSqlite_TestGetAccountByPrivateDomain(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/store.sqlite")
|
||||||
|
defer cleanup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
existingDomain := "test.com"
|
existingDomain := "test.com"
|
||||||
|
|
||||||
account, err := store.GetAccountByPrivateDomain(context.Background(), existingDomain)
|
account, err := store.GetAccountByPrivateDomain(context.Background(), existingDomain)
|
||||||
@ -539,8 +555,11 @@ func TestSqlite_GetTokenIDByHashedToken(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/store.sqlite")
|
||||||
|
defer cleanup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
hashed := "SoMeHaShEdToKeN"
|
hashed := "SoMeHaShEdToKeN"
|
||||||
id := "9dj38s35-63fb-11ec-90d6-0242ac120003"
|
id := "9dj38s35-63fb-11ec-90d6-0242ac120003"
|
||||||
|
|
||||||
@ -560,8 +579,11 @@ func TestSqlite_GetUserByTokenID(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/store.sqlite")
|
||||||
|
defer cleanup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
id := "9dj38s35-63fb-11ec-90d6-0242ac120003"
|
id := "9dj38s35-63fb-11ec-90d6-0242ac120003"
|
||||||
|
|
||||||
user, err := store.GetUserByTokenID(context.Background(), id)
|
user, err := store.GetUserByTokenID(context.Background(), id)
|
||||||
@ -668,24 +690,9 @@ func newSqliteStore(t *testing.T) *SqlStore {
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
store, err := NewSqliteStore(context.Background(), t.TempDir(), nil)
|
store, err := NewSqliteStore(context.Background(), t.TempDir(), nil)
|
||||||
require.NoError(t, err)
|
t.Cleanup(func() {
|
||||||
require.NotNil(t, store)
|
store.Close(context.Background())
|
||||||
|
})
|
||||||
return store
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSqliteStoreFromFile(t *testing.T, filename string) *SqlStore {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
storeDir := t.TempDir()
|
|
||||||
|
|
||||||
err := util.CopyFileContents(filename, filepath.Join(storeDir, "store.json"))
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
fStore, err := NewFileStore(context.Background(), storeDir, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
store, err := NewSqliteStoreFromFileStore(context.Background(), fStore, storeDir, nil)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, store)
|
require.NotNil(t, store)
|
||||||
|
|
||||||
@ -733,32 +740,31 @@ func newPostgresqlStore(t *testing.T) *SqlStore {
|
|||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPostgresqlStoreFromFile(t *testing.T, filename string) *SqlStore {
|
func newPostgresqlStoreFromSqlite(t *testing.T, filename string) *SqlStore {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
storeDir := t.TempDir()
|
store, cleanUpQ, err := NewSqliteTestStore(context.Background(), t.TempDir(), filename)
|
||||||
err := util.CopyFileContents(filename, filepath.Join(storeDir, "store.json"))
|
t.Cleanup(cleanUpQ)
|
||||||
require.NoError(t, err)
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
fStore, err := NewFileStore(context.Background(), storeDir, nil)
|
cleanUpP, err := testutil.CreatePGDB()
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
cleanUp, err := testutil.CreatePGDB()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUpP)
|
||||||
|
|
||||||
postgresDsn, ok := os.LookupEnv(postgresDsnEnv)
|
postgresDsn, ok := os.LookupEnv(postgresDsnEnv)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("could not initialize postgresql store: %s is not set", postgresDsnEnv)
|
t.Fatalf("could not initialize postgresql store: %s is not set", postgresDsnEnv)
|
||||||
}
|
}
|
||||||
|
|
||||||
store, err := NewPostgresqlStoreFromFileStore(context.Background(), fStore, postgresDsn, nil)
|
pstore, err := NewPostgresqlStoreFromSqlStore(context.Background(), store, postgresDsn, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, store)
|
require.NotNil(t, store)
|
||||||
|
|
||||||
return store
|
return pstore
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPostgresql_NewStore(t *testing.T) {
|
func TestPostgresql_NewStore(t *testing.T) {
|
||||||
@ -924,7 +930,7 @@ func TestPostgresql_SavePeerStatus(t *testing.T) {
|
|||||||
t.Skipf("The PostgreSQL store is not properly supported by %s yet", runtime.GOOS)
|
t.Skipf("The PostgreSQL store is not properly supported by %s yet", runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newPostgresqlStoreFromFile(t, "testdata/store.json")
|
store := newPostgresqlStoreFromSqlite(t, "testdata/store.sqlite")
|
||||||
|
|
||||||
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
account, err := store.GetAccount(context.Background(), "bf1c8084-ba50-4ce7-9439-34653001fc3b")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -963,7 +969,7 @@ func TestPostgresql_TestGetAccountByPrivateDomain(t *testing.T) {
|
|||||||
t.Skipf("The PostgreSQL store is not properly supported by %s yet", runtime.GOOS)
|
t.Skipf("The PostgreSQL store is not properly supported by %s yet", runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newPostgresqlStoreFromFile(t, "testdata/store.json")
|
store := newPostgresqlStoreFromSqlite(t, "testdata/store.sqlite")
|
||||||
|
|
||||||
existingDomain := "test.com"
|
existingDomain := "test.com"
|
||||||
|
|
||||||
@ -980,7 +986,7 @@ func TestPostgresql_GetTokenIDByHashedToken(t *testing.T) {
|
|||||||
t.Skipf("The PostgreSQL store is not properly supported by %s yet", runtime.GOOS)
|
t.Skipf("The PostgreSQL store is not properly supported by %s yet", runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newPostgresqlStoreFromFile(t, "testdata/store.json")
|
store := newPostgresqlStoreFromSqlite(t, "testdata/store.sqlite")
|
||||||
|
|
||||||
hashed := "SoMeHaShEdToKeN"
|
hashed := "SoMeHaShEdToKeN"
|
||||||
id := "9dj38s35-63fb-11ec-90d6-0242ac120003"
|
id := "9dj38s35-63fb-11ec-90d6-0242ac120003"
|
||||||
@ -995,7 +1001,7 @@ func TestPostgresql_GetUserByTokenID(t *testing.T) {
|
|||||||
t.Skipf("The PostgreSQL store is not properly supported by %s yet", runtime.GOOS)
|
t.Skipf("The PostgreSQL store is not properly supported by %s yet", runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newPostgresqlStoreFromFile(t, "testdata/store.json")
|
store := newPostgresqlStoreFromSqlite(t, "testdata/store.sqlite")
|
||||||
|
|
||||||
id := "9dj38s35-63fb-11ec-90d6-0242ac120003"
|
id := "9dj38s35-63fb-11ec-90d6-0242ac120003"
|
||||||
|
|
||||||
@ -1009,12 +1015,15 @@ func TestSqlite_GetTakenIPs(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/extended-store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/extended-store.sqlite")
|
||||||
defer store.Close(context.Background())
|
defer cleanup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
|
|
||||||
_, err := store.GetAccount(context.Background(), existingAccountID)
|
_, err = store.GetAccount(context.Background(), existingAccountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
takenIPs, err := store.GetTakenIPs(context.Background(), LockingStrengthShare, existingAccountID)
|
takenIPs, err := store.GetTakenIPs(context.Background(), LockingStrengthShare, existingAccountID)
|
||||||
@ -1054,12 +1063,15 @@ func TestSqlite_GetPeerLabelsInAccount(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/extended-store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/extended-store.sqlite")
|
||||||
defer store.Close(context.Background())
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
|
|
||||||
_, err := store.GetAccount(context.Background(), existingAccountID)
|
_, err = store.GetAccount(context.Background(), existingAccountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
labels, err := store.GetPeerLabelsInAccount(context.Background(), LockingStrengthShare, existingAccountID)
|
labels, err := store.GetPeerLabelsInAccount(context.Background(), LockingStrengthShare, existingAccountID)
|
||||||
@ -1096,12 +1108,15 @@ func TestSqlite_GetAccountNetwork(t *testing.T) {
|
|||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
store := newSqliteStoreFromFile(t, "testdata/extended-store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/extended-store.sqlite")
|
||||||
defer store.Close(context.Background())
|
t.Cleanup(cleanup)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
|
|
||||||
_, err := store.GetAccount(context.Background(), existingAccountID)
|
_, err = store.GetAccount(context.Background(), existingAccountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
network, err := store.GetAccountNetwork(context.Background(), LockingStrengthShare, existingAccountID)
|
network, err := store.GetAccountNetwork(context.Background(), LockingStrengthShare, existingAccountID)
|
||||||
@ -1118,12 +1133,15 @@ func TestSqlite_GetSetupKeyBySecret(t *testing.T) {
|
|||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
store := newSqliteStoreFromFile(t, "testdata/extended-store.json")
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/extended-store.sqlite")
|
||||||
defer store.Close(context.Background())
|
t.Cleanup(cleanup)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
|
|
||||||
_, err := store.GetAccount(context.Background(), existingAccountID)
|
_, err = store.GetAccount(context.Background(), existingAccountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
setupKey, err := store.GetSetupKeyBySecret(context.Background(), LockingStrengthShare, "A2C8E62B-38F5-4553-B31E-DD66C696CEBB")
|
setupKey, err := store.GetSetupKeyBySecret(context.Background(), LockingStrengthShare, "A2C8E62B-38F5-4553-B31E-DD66C696CEBB")
|
||||||
@ -1137,12 +1155,16 @@ func TestSqlite_incrementSetupKeyUsage(t *testing.T) {
|
|||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
t.Skip("The SQLite store is not properly supported by Windows yet")
|
t.Skip("The SQLite store is not properly supported by Windows yet")
|
||||||
}
|
}
|
||||||
store := newSqliteStoreFromFile(t, "testdata/extended-store.json")
|
|
||||||
defer store.Close(context.Background())
|
store, cleanup, err := NewSqliteTestStore(context.Background(), t.TempDir(), "testdata/extended-store.sqlite")
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
|
|
||||||
_, err := store.GetAccount(context.Background(), existingAccountID)
|
_, err = store.GetAccount(context.Background(), existingAccountID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
setupKey, err := store.GetSetupKeyBySecret(context.Background(), LockingStrengthShare, "A2C8E62B-38F5-4553-B31E-DD66C696CEBB")
|
setupKey, err := store.GetSetupKeyBySecret(context.Background(), LockingStrengthShare, "A2C8E62B-38F5-4553-B31E-DD66C696CEBB")
|
||||||
|
@ -12,10 +12,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/dns"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/dns"
|
||||||
|
|
||||||
nbgroup "github.com/netbirdio/netbird/management/server/group"
|
nbgroup "github.com/netbirdio/netbird/management/server/group"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||||
@ -236,23 +237,29 @@ func getMigrations(ctx context.Context) []migrationFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTestStoreFromJson is only used in tests
|
// NewTestStoreFromSqlite is only used in tests
|
||||||
func NewTestStoreFromJson(ctx context.Context, dataDir string) (Store, func(), error) {
|
func NewTestStoreFromSqlite(ctx context.Context, filename string, dataDir string) (Store, func(), error) {
|
||||||
fstore, err := NewFileStore(ctx, dataDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if store engine is not set in the config we first try to evaluate NETBIRD_STORE_ENGINE
|
// if store engine is not set in the config we first try to evaluate NETBIRD_STORE_ENGINE
|
||||||
kind := getStoreEngineFromEnv()
|
kind := getStoreEngineFromEnv()
|
||||||
if kind == "" {
|
if kind == "" {
|
||||||
kind = SqliteStoreEngine
|
kind = SqliteStoreEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var store *SqlStore
|
||||||
store Store
|
var err error
|
||||||
cleanUp func()
|
var cleanUp func()
|
||||||
)
|
|
||||||
|
if filename == "" {
|
||||||
|
store, err = NewSqliteStore(ctx, dataDir, nil)
|
||||||
|
cleanUp = func() {
|
||||||
|
store.Close(ctx)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
store, cleanUp, err = NewSqliteTestStore(ctx, dataDir, filename)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if kind == PostgresStoreEngine {
|
if kind == PostgresStoreEngine {
|
||||||
cleanUp, err = testutil.CreatePGDB()
|
cleanUp, err = testutil.CreatePGDB()
|
||||||
@ -265,21 +272,32 @@ func NewTestStoreFromJson(ctx context.Context, dataDir string) (Store, func(), e
|
|||||||
return nil, nil, fmt.Errorf("%s is not set", postgresDsnEnv)
|
return nil, nil, fmt.Errorf("%s is not set", postgresDsnEnv)
|
||||||
}
|
}
|
||||||
|
|
||||||
store, err = NewPostgresqlStoreFromFileStore(ctx, fstore, dsn, nil)
|
store, err = NewPostgresqlStoreFromSqlStore(ctx, store, dsn, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
store, err = NewSqliteStoreFromFileStore(ctx, fstore, dataDir, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
cleanUp = func() { store.Close(ctx) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return store, cleanUp, nil
|
return store, cleanUp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewSqliteTestStore(ctx context.Context, dataDir string, testFile string) (*SqlStore, func(), error) {
|
||||||
|
err := util.CopyFileContents(testFile, filepath.Join(dataDir, "store.db"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := NewSqliteStore(ctx, dataDir, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return store, func() {
|
||||||
|
store.Close(ctx)
|
||||||
|
os.Remove(filepath.Join(dataDir, "store.db"))
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// MigrateFileStoreToSqlite migrates the file store to the SQLite store.
|
// MigrateFileStoreToSqlite migrates the file store to the SQLite store.
|
||||||
func MigrateFileStoreToSqlite(ctx context.Context, dataDir string) error {
|
func MigrateFileStoreToSqlite(ctx context.Context, dataDir string) error {
|
||||||
fileStorePath := path.Join(dataDir, storeFileName)
|
fileStorePath := path.Join(dataDir, storeFileName)
|
||||||
|
@ -14,12 +14,6 @@ type benchCase struct {
|
|||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
var newFs = func(b *testing.B) Store {
|
|
||||||
b.Helper()
|
|
||||||
store, _ := NewFileStore(context.Background(), b.TempDir(), nil)
|
|
||||||
return store
|
|
||||||
}
|
|
||||||
|
|
||||||
var newSqlite = func(b *testing.B) Store {
|
var newSqlite = func(b *testing.B) Store {
|
||||||
b.Helper()
|
b.Helper()
|
||||||
store, _ := NewSqliteStore(context.Background(), b.TempDir(), nil)
|
store, _ := NewSqliteStore(context.Background(), b.TempDir(), nil)
|
||||||
@ -28,13 +22,9 @@ var newSqlite = func(b *testing.B) Store {
|
|||||||
|
|
||||||
func BenchmarkTest_StoreWrite(b *testing.B) {
|
func BenchmarkTest_StoreWrite(b *testing.B) {
|
||||||
cases := []benchCase{
|
cases := []benchCase{
|
||||||
{name: "FileStore_Write", storeFn: newFs, size: 100},
|
|
||||||
{name: "SqliteStore_Write", storeFn: newSqlite, size: 100},
|
{name: "SqliteStore_Write", storeFn: newSqlite, size: 100},
|
||||||
{name: "FileStore_Write", storeFn: newFs, size: 500},
|
|
||||||
{name: "SqliteStore_Write", storeFn: newSqlite, size: 500},
|
{name: "SqliteStore_Write", storeFn: newSqlite, size: 500},
|
||||||
{name: "FileStore_Write", storeFn: newFs, size: 1000},
|
|
||||||
{name: "SqliteStore_Write", storeFn: newSqlite, size: 1000},
|
{name: "SqliteStore_Write", storeFn: newSqlite, size: 1000},
|
||||||
{name: "FileStore_Write", storeFn: newFs, size: 2000},
|
|
||||||
{name: "SqliteStore_Write", storeFn: newSqlite, size: 2000},
|
{name: "SqliteStore_Write", storeFn: newSqlite, size: 2000},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,11 +51,8 @@ func BenchmarkTest_StoreWrite(b *testing.B) {
|
|||||||
|
|
||||||
func BenchmarkTest_StoreRead(b *testing.B) {
|
func BenchmarkTest_StoreRead(b *testing.B) {
|
||||||
cases := []benchCase{
|
cases := []benchCase{
|
||||||
{name: "FileStore_Read", storeFn: newFs, size: 100},
|
|
||||||
{name: "SqliteStore_Read", storeFn: newSqlite, size: 100},
|
{name: "SqliteStore_Read", storeFn: newSqlite, size: 100},
|
||||||
{name: "FileStore_Read", storeFn: newFs, size: 500},
|
|
||||||
{name: "SqliteStore_Read", storeFn: newSqlite, size: 500},
|
{name: "SqliteStore_Read", storeFn: newSqlite, size: 500},
|
||||||
{name: "FileStore_Read", storeFn: newFs, size: 1000},
|
|
||||||
{name: "SqliteStore_Read", storeFn: newSqlite, size: 1000},
|
{name: "SqliteStore_Read", storeFn: newSqlite, size: 1000},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,3 +76,11 @@ func BenchmarkTest_StoreRead(b *testing.B) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newStore(t *testing.T) Store {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
store := newSqliteStore(t)
|
||||||
|
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
120
management/server/testdata/extended-store.json
vendored
120
management/server/testdata/extended-store.json
vendored
@ -1,120 +0,0 @@
|
|||||||
{
|
|
||||||
"Accounts": {
|
|
||||||
"bf1c8084-ba50-4ce7-9439-34653001fc3b": {
|
|
||||||
"Id": "bf1c8084-ba50-4ce7-9439-34653001fc3b",
|
|
||||||
"CreatedBy": "",
|
|
||||||
"Domain": "test.com",
|
|
||||||
"DomainCategory": "private",
|
|
||||||
"IsDomainPrimaryAccount": true,
|
|
||||||
"SetupKeys": {
|
|
||||||
"A2C8E62B-38F5-4553-B31E-DD66C696CEBB": {
|
|
||||||
"Id": "A2C8E62B-38F5-4553-B31E-DD66C696CEBB",
|
|
||||||
"AccountID": "",
|
|
||||||
"Key": "A2C8E62B-38F5-4553-B31E-DD66C696CEBB",
|
|
||||||
"Name": "Default key",
|
|
||||||
"Type": "reusable",
|
|
||||||
"CreatedAt": "2021-08-19T20:46:20.005936822+02:00",
|
|
||||||
"ExpiresAt": "2321-09-18T20:46:20.005936822+02:00",
|
|
||||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 0,
|
|
||||||
"LastUsed": "0001-01-01T00:00:00Z",
|
|
||||||
"AutoGroups": ["cfefqs706sqkneg59g2g"],
|
|
||||||
"UsageLimit": 0,
|
|
||||||
"Ephemeral": false
|
|
||||||
},
|
|
||||||
"A2C8E62B-38F5-4553-B31E-DD66C696CEBC": {
|
|
||||||
"Id": "A2C8E62B-38F5-4553-B31E-DD66C696CEBC",
|
|
||||||
"AccountID": "",
|
|
||||||
"Key": "A2C8E62B-38F5-4553-B31E-DD66C696CEBC",
|
|
||||||
"Name": "Faulty key with non existing group",
|
|
||||||
"Type": "reusable",
|
|
||||||
"CreatedAt": "2021-08-19T20:46:20.005936822+02:00",
|
|
||||||
"ExpiresAt": "2321-09-18T20:46:20.005936822+02:00",
|
|
||||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 0,
|
|
||||||
"LastUsed": "0001-01-01T00:00:00Z",
|
|
||||||
"AutoGroups": ["abcd"],
|
|
||||||
"UsageLimit": 0,
|
|
||||||
"Ephemeral": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Network": {
|
|
||||||
"id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
|
|
||||||
"Net": {
|
|
||||||
"IP": "100.64.0.0",
|
|
||||||
"Mask": "//8AAA=="
|
|
||||||
},
|
|
||||||
"Dns": "",
|
|
||||||
"Serial": 0
|
|
||||||
},
|
|
||||||
"Peers": {},
|
|
||||||
"Users": {
|
|
||||||
"edafee4e-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"AccountID": "",
|
|
||||||
"Role": "admin",
|
|
||||||
"IsServiceUser": false,
|
|
||||||
"ServiceUserName": "",
|
|
||||||
"AutoGroups": ["cfefqs706sqkneg59g3g"],
|
|
||||||
"PATs": {},
|
|
||||||
"Blocked": false,
|
|
||||||
"LastLogin": "0001-01-01T00:00:00Z"
|
|
||||||
},
|
|
||||||
"f4f6d672-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "f4f6d672-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"AccountID": "",
|
|
||||||
"Role": "user",
|
|
||||||
"IsServiceUser": false,
|
|
||||||
"ServiceUserName": "",
|
|
||||||
"AutoGroups": null,
|
|
||||||
"PATs": {
|
|
||||||
"9dj38s35-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"ID": "9dj38s35-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"UserID": "",
|
|
||||||
"Name": "",
|
|
||||||
"HashedToken": "SoMeHaShEdToKeN",
|
|
||||||
"ExpirationDate": "2023-02-27T00:00:00Z",
|
|
||||||
"CreatedBy": "user",
|
|
||||||
"CreatedAt": "2023-01-01T00:00:00Z",
|
|
||||||
"LastUsed": "2023-02-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Blocked": false,
|
|
||||||
"LastLogin": "0001-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Groups": {
|
|
||||||
"cfefqs706sqkneg59g4g": {
|
|
||||||
"ID": "cfefqs706sqkneg59g4g",
|
|
||||||
"Name": "All",
|
|
||||||
"Peers": []
|
|
||||||
},
|
|
||||||
"cfefqs706sqkneg59g3g": {
|
|
||||||
"ID": "cfefqs706sqkneg59g3g",
|
|
||||||
"Name": "AwesomeGroup1",
|
|
||||||
"Peers": []
|
|
||||||
},
|
|
||||||
"cfefqs706sqkneg59g2g": {
|
|
||||||
"ID": "cfefqs706sqkneg59g2g",
|
|
||||||
"Name": "AwesomeGroup2",
|
|
||||||
"Peers": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Rules": null,
|
|
||||||
"Policies": [],
|
|
||||||
"Routes": null,
|
|
||||||
"NameServerGroups": null,
|
|
||||||
"DNSSettings": null,
|
|
||||||
"Settings": {
|
|
||||||
"PeerLoginExpirationEnabled": false,
|
|
||||||
"PeerLoginExpiration": 86400000000000,
|
|
||||||
"GroupsPropagationEnabled": false,
|
|
||||||
"JWTGroupsEnabled": false,
|
|
||||||
"JWTGroupsClaimName": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"InstallationID": ""
|
|
||||||
}
|
|
BIN
management/server/testdata/extended-store.sqlite
vendored
Normal file
BIN
management/server/testdata/extended-store.sqlite
vendored
Normal file
Binary file not shown.
88
management/server/testdata/store.json
vendored
88
management/server/testdata/store.json
vendored
@ -1,88 +0,0 @@
|
|||||||
{
|
|
||||||
"Accounts": {
|
|
||||||
"bf1c8084-ba50-4ce7-9439-34653001fc3b": {
|
|
||||||
"Id": "bf1c8084-ba50-4ce7-9439-34653001fc3b",
|
|
||||||
"CreatedBy": "",
|
|
||||||
"Domain": "test.com",
|
|
||||||
"DomainCategory": "private",
|
|
||||||
"IsDomainPrimaryAccount": true,
|
|
||||||
"SetupKeys": {
|
|
||||||
"A2C8E62B-38F5-4553-B31E-DD66C696CEBB": {
|
|
||||||
"Id": "",
|
|
||||||
"AccountID": "",
|
|
||||||
"Key": "A2C8E62B-38F5-4553-B31E-DD66C696CEBB",
|
|
||||||
"Name": "Default key",
|
|
||||||
"Type": "reusable",
|
|
||||||
"CreatedAt": "2021-08-19T20:46:20.005936822+02:00",
|
|
||||||
"ExpiresAt": "2321-09-18T20:46:20.005936822+02:00",
|
|
||||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 0,
|
|
||||||
"LastUsed": "0001-01-01T00:00:00Z",
|
|
||||||
"AutoGroups": null,
|
|
||||||
"UsageLimit": 0,
|
|
||||||
"Ephemeral": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Network": {
|
|
||||||
"id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
|
|
||||||
"Net": {
|
|
||||||
"IP": "100.64.0.0",
|
|
||||||
"Mask": "//8AAA=="
|
|
||||||
},
|
|
||||||
"Dns": "",
|
|
||||||
"Serial": 0
|
|
||||||
},
|
|
||||||
"Peers": {},
|
|
||||||
"Users": {
|
|
||||||
"edafee4e-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"AccountID": "",
|
|
||||||
"Role": "admin",
|
|
||||||
"IsServiceUser": false,
|
|
||||||
"ServiceUserName": "",
|
|
||||||
"AutoGroups": null,
|
|
||||||
"PATs": {},
|
|
||||||
"Blocked": false,
|
|
||||||
"LastLogin": "0001-01-01T00:00:00Z"
|
|
||||||
},
|
|
||||||
"f4f6d672-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "f4f6d672-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"AccountID": "",
|
|
||||||
"Role": "user",
|
|
||||||
"IsServiceUser": false,
|
|
||||||
"ServiceUserName": "",
|
|
||||||
"AutoGroups": null,
|
|
||||||
"PATs": {
|
|
||||||
"9dj38s35-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"ID": "9dj38s35-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"UserID": "",
|
|
||||||
"Name": "",
|
|
||||||
"HashedToken": "SoMeHaShEdToKeN",
|
|
||||||
"ExpirationDate": "2023-02-27T00:00:00Z",
|
|
||||||
"CreatedBy": "user",
|
|
||||||
"CreatedAt": "2023-01-01T00:00:00Z",
|
|
||||||
"LastUsed": "2023-02-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Blocked": false,
|
|
||||||
"LastLogin": "0001-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Groups": null,
|
|
||||||
"Rules": null,
|
|
||||||
"Policies": [],
|
|
||||||
"Routes": null,
|
|
||||||
"NameServerGroups": null,
|
|
||||||
"DNSSettings": null,
|
|
||||||
"Settings": {
|
|
||||||
"PeerLoginExpirationEnabled": false,
|
|
||||||
"PeerLoginExpiration": 86400000000000,
|
|
||||||
"GroupsPropagationEnabled": false,
|
|
||||||
"JWTGroupsEnabled": false,
|
|
||||||
"JWTGroupsClaimName": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"InstallationID": ""
|
|
||||||
}
|
|
BIN
management/server/testdata/store.sqlite
vendored
Normal file
BIN
management/server/testdata/store.sqlite
vendored
Normal file
Binary file not shown.
116
management/server/testdata/store_policy_migrate.json
vendored
116
management/server/testdata/store_policy_migrate.json
vendored
@ -1,116 +0,0 @@
|
|||||||
{
|
|
||||||
"Accounts": {
|
|
||||||
"bf1c8084-ba50-4ce7-9439-34653001fc3b": {
|
|
||||||
"Id": "bf1c8084-ba50-4ce7-9439-34653001fc3b",
|
|
||||||
"Domain": "test.com",
|
|
||||||
"DomainCategory": "private",
|
|
||||||
"IsDomainPrimaryAccount": true,
|
|
||||||
"SetupKeys": {
|
|
||||||
"A2C8E62B-38F5-4553-B31E-DD66C696CEBB": {
|
|
||||||
"Key": "A2C8E62B-38F5-4553-B31E-DD66C696CEBB",
|
|
||||||
"Name": "Default key",
|
|
||||||
"Type": "reusable",
|
|
||||||
"CreatedAt": "2021-08-19T20:46:20.005936822+02:00",
|
|
||||||
"ExpiresAt": "2321-09-18T20:46:20.005936822+02:00",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Network": {
|
|
||||||
"Id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
|
|
||||||
"Net": {
|
|
||||||
"IP": "100.64.0.0",
|
|
||||||
"Mask": "//8AAA=="
|
|
||||||
},
|
|
||||||
"Dns": null
|
|
||||||
},
|
|
||||||
"Peers": {
|
|
||||||
"cfefqs706sqkneg59g4g": {
|
|
||||||
"ID": "cfefqs706sqkneg59g4g",
|
|
||||||
"Key": "MI5mHfJhbggPfD3FqEIsXm8X5bSWeUI2LhO9MpEEtWA=",
|
|
||||||
"SetupKey": "",
|
|
||||||
"IP": "100.103.179.238",
|
|
||||||
"Meta": {
|
|
||||||
"Hostname": "Ubuntu-2204-jammy-amd64-base",
|
|
||||||
"GoOS": "linux",
|
|
||||||
"Kernel": "Linux",
|
|
||||||
"Core": "22.04",
|
|
||||||
"Platform": "x86_64",
|
|
||||||
"OS": "Ubuntu",
|
|
||||||
"WtVersion": "development",
|
|
||||||
"UIVersion": ""
|
|
||||||
},
|
|
||||||
"Name": "crocodile",
|
|
||||||
"DNSLabel": "crocodile",
|
|
||||||
"Status": {
|
|
||||||
"LastSeen": "2023-02-13T12:37:12.635454796Z",
|
|
||||||
"Connected": true
|
|
||||||
},
|
|
||||||
"UserID": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"SSHKey": "AAAAC3NzaC1lZDI1NTE5AAAAIJN1NM4bpB9K",
|
|
||||||
"SSHEnabled": false
|
|
||||||
},
|
|
||||||
"cfeg6sf06sqkneg59g50": {
|
|
||||||
"ID": "cfeg6sf06sqkneg59g50",
|
|
||||||
"Key": "zMAOKUeIYIuun4n0xPR1b3IdYZPmsyjYmB2jWCuloC4=",
|
|
||||||
"SetupKey": "",
|
|
||||||
"IP": "100.103.26.180",
|
|
||||||
"Meta": {
|
|
||||||
"Hostname": "borg",
|
|
||||||
"GoOS": "linux",
|
|
||||||
"Kernel": "Linux",
|
|
||||||
"Core": "22.04",
|
|
||||||
"Platform": "x86_64",
|
|
||||||
"OS": "Ubuntu",
|
|
||||||
"WtVersion": "development",
|
|
||||||
"UIVersion": ""
|
|
||||||
},
|
|
||||||
"Name": "dingo",
|
|
||||||
"DNSLabel": "dingo",
|
|
||||||
"Status": {
|
|
||||||
"LastSeen": "2023-02-21T09:37:42.565899199Z",
|
|
||||||
"Connected": false
|
|
||||||
},
|
|
||||||
"UserID": "f4f6d672-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"SSHKey": "AAAAC3NzaC1lZDI1NTE5AAAAILHW",
|
|
||||||
"SSHEnabled": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Groups": {
|
|
||||||
"cfefqs706sqkneg59g3g": {
|
|
||||||
"ID": "cfefqs706sqkneg59g3g",
|
|
||||||
"Name": "All",
|
|
||||||
"Peers": [
|
|
||||||
"cfefqs706sqkneg59g4g",
|
|
||||||
"cfeg6sf06sqkneg59g50"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Rules": {
|
|
||||||
"cfefqs706sqkneg59g40": {
|
|
||||||
"ID": "cfefqs706sqkneg59g40",
|
|
||||||
"Name": "Default",
|
|
||||||
"Description": "This is a default rule that allows connections between all the resources",
|
|
||||||
"Disabled": false,
|
|
||||||
"Source": [
|
|
||||||
"cfefqs706sqkneg59g3g"
|
|
||||||
],
|
|
||||||
"Destination": [
|
|
||||||
"cfefqs706sqkneg59g3g"
|
|
||||||
],
|
|
||||||
"Flow": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Users": {
|
|
||||||
"edafee4e-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"Role": "admin"
|
|
||||||
},
|
|
||||||
"f4f6d672-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "f4f6d672-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"Role": "user"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
BIN
management/server/testdata/store_policy_migrate.sqlite
vendored
Normal file
BIN
management/server/testdata/store_policy_migrate.sqlite
vendored
Normal file
Binary file not shown.
@ -1,130 +0,0 @@
|
|||||||
{
|
|
||||||
"Accounts": {
|
|
||||||
"bf1c8084-ba50-4ce7-9439-34653001fc3b": {
|
|
||||||
"Id": "bf1c8084-ba50-4ce7-9439-34653001fc3b",
|
|
||||||
"Domain": "test.com",
|
|
||||||
"DomainCategory": "private",
|
|
||||||
"IsDomainPrimaryAccount": true,
|
|
||||||
"Settings": {
|
|
||||||
"PeerLoginExpirationEnabled": true,
|
|
||||||
"PeerLoginExpiration": 3600000000000
|
|
||||||
},
|
|
||||||
"SetupKeys": {
|
|
||||||
"A2C8E62B-38F5-4553-B31E-DD66C696CEBB": {
|
|
||||||
"Key": "A2C8E62B-38F5-4553-B31E-DD66C696CEBB",
|
|
||||||
"Name": "Default key",
|
|
||||||
"Type": "reusable",
|
|
||||||
"CreatedAt": "2021-08-19T20:46:20.005936822+02:00",
|
|
||||||
"ExpiresAt": "2321-09-18T20:46:20.005936822+02:00",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 0
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Network": {
|
|
||||||
"Id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
|
|
||||||
"Net": {
|
|
||||||
"IP": "100.64.0.0",
|
|
||||||
"Mask": "//8AAA=="
|
|
||||||
},
|
|
||||||
"Dns": null
|
|
||||||
},
|
|
||||||
"Peers": {
|
|
||||||
"cfvprsrlo1hqoo49ohog": {
|
|
||||||
"ID": "cfvprsrlo1hqoo49ohog",
|
|
||||||
"Key": "5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=",
|
|
||||||
"SetupKey": "72546A29-6BC8-4311-BCFC-9CDBF33F1A48",
|
|
||||||
"IP": "100.64.114.31",
|
|
||||||
"Meta": {
|
|
||||||
"Hostname": "f2a34f6a4731",
|
|
||||||
"GoOS": "linux",
|
|
||||||
"Kernel": "Linux",
|
|
||||||
"Core": "11",
|
|
||||||
"Platform": "unknown",
|
|
||||||
"OS": "Debian GNU/Linux",
|
|
||||||
"WtVersion": "0.12.0",
|
|
||||||
"UIVersion": ""
|
|
||||||
},
|
|
||||||
"Name": "f2a34f6a4731",
|
|
||||||
"DNSLabel": "f2a34f6a4731",
|
|
||||||
"Status": {
|
|
||||||
"LastSeen": "2023-03-02T09:21:02.189035775+01:00",
|
|
||||||
"Connected": false,
|
|
||||||
"LoginExpired": false
|
|
||||||
},
|
|
||||||
"UserID": "",
|
|
||||||
"SSHKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk",
|
|
||||||
"SSHEnabled": false,
|
|
||||||
"LoginExpirationEnabled": true,
|
|
||||||
"LastLogin": "2023-03-01T19:48:19.817799698+01:00"
|
|
||||||
},
|
|
||||||
"cg05lnblo1hkg2j514p0": {
|
|
||||||
"ID": "cg05lnblo1hkg2j514p0",
|
|
||||||
"Key": "RlSy2vzoG2HyMBTUImXOiVhCBiiBa5qD5xzMxkiFDW4=",
|
|
||||||
"SetupKey": "",
|
|
||||||
"IP": "100.64.39.54",
|
|
||||||
"Meta": {
|
|
||||||
"Hostname": "expiredhost",
|
|
||||||
"GoOS": "linux",
|
|
||||||
"Kernel": "Linux",
|
|
||||||
"Core": "22.04",
|
|
||||||
"Platform": "x86_64",
|
|
||||||
"OS": "Ubuntu",
|
|
||||||
"WtVersion": "development",
|
|
||||||
"UIVersion": ""
|
|
||||||
},
|
|
||||||
"Name": "expiredhost",
|
|
||||||
"DNSLabel": "expiredhost",
|
|
||||||
"Status": {
|
|
||||||
"LastSeen": "2023-03-02T09:19:57.276717255+01:00",
|
|
||||||
"Connected": false,
|
|
||||||
"LoginExpired": true
|
|
||||||
},
|
|
||||||
"UserID": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"SSHKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMbK5ZXJsGOOWoBT4OmkPtgdPZe2Q7bDuS/zjn2CZxhK",
|
|
||||||
"SSHEnabled": false,
|
|
||||||
"LoginExpirationEnabled": true,
|
|
||||||
"LastLogin": "2023-03-02T09:14:21.791679181+01:00"
|
|
||||||
},
|
|
||||||
"cg3161rlo1hs9cq94gdg": {
|
|
||||||
"ID": "cg3161rlo1hs9cq94gdg",
|
|
||||||
"Key": "mVABSKj28gv+JRsf7e0NEGKgSOGTfU/nPB2cpuG56HU=",
|
|
||||||
"SetupKey": "",
|
|
||||||
"IP": "100.64.117.96",
|
|
||||||
"Meta": {
|
|
||||||
"Hostname": "testhost",
|
|
||||||
"GoOS": "linux",
|
|
||||||
"Kernel": "Linux",
|
|
||||||
"Core": "22.04",
|
|
||||||
"Platform": "x86_64",
|
|
||||||
"OS": "Ubuntu",
|
|
||||||
"WtVersion": "development",
|
|
||||||
"UIVersion": ""
|
|
||||||
},
|
|
||||||
"Name": "testhost",
|
|
||||||
"DNSLabel": "testhost",
|
|
||||||
"Status": {
|
|
||||||
"LastSeen": "2023-03-06T18:21:27.252010027+01:00",
|
|
||||||
"Connected": false,
|
|
||||||
"LoginExpired": false
|
|
||||||
},
|
|
||||||
"UserID": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"SSHKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINWvvUkFFcrj48CWTkNUb/do/n52i1L5dH4DhGu+4ZuM",
|
|
||||||
"SSHEnabled": false,
|
|
||||||
"LoginExpirationEnabled": false,
|
|
||||||
"LastLogin": "2023-03-07T09:02:47.442857106+01:00"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Users": {
|
|
||||||
"edafee4e-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "edafee4e-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"Role": "admin"
|
|
||||||
},
|
|
||||||
"f4f6d672-63fb-11ec-90d6-0242ac120003": {
|
|
||||||
"Id": "f4f6d672-63fb-11ec-90d6-0242ac120003",
|
|
||||||
"Role": "user"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
BIN
management/server/testdata/store_with_expired_peers.sqlite
vendored
Normal file
BIN
management/server/testdata/store_with_expired_peers.sqlite
vendored
Normal file
Binary file not shown.
154
management/server/testdata/storev1.json
vendored
154
management/server/testdata/storev1.json
vendored
@ -1,154 +0,0 @@
|
|||||||
{
|
|
||||||
"Accounts": {
|
|
||||||
"auth0|61bf82ddeab084006aa1bccd": {
|
|
||||||
"Id": "auth0|61bf82ddeab084006aa1bccd",
|
|
||||||
"SetupKeys": {
|
|
||||||
"1B2B50B0-B3E8-4B0C-A426-525EDB8481BD": {
|
|
||||||
"Id": "831727121",
|
|
||||||
"Key": "1B2B50B0-B3E8-4B0C-A426-525EDB8481BD",
|
|
||||||
"Name": "One-off key",
|
|
||||||
"Type": "one-off",
|
|
||||||
"CreatedAt": "2021-12-24T16:09:45.926075752+01:00",
|
|
||||||
"ExpiresAt": "2022-01-23T16:09:45.926075752+01:00",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 1,
|
|
||||||
"LastUsed": "2021-12-24T16:12:45.763424077+01:00"
|
|
||||||
},
|
|
||||||
"EB51E9EB-A11F-4F6E-8E49-C982891B405A": {
|
|
||||||
"Id": "1769568301",
|
|
||||||
"Key": "EB51E9EB-A11F-4F6E-8E49-C982891B405A",
|
|
||||||
"Name": "Default key",
|
|
||||||
"Type": "reusable",
|
|
||||||
"CreatedAt": "2021-12-24T16:09:45.926073628+01:00",
|
|
||||||
"ExpiresAt": "2022-01-23T16:09:45.926073628+01:00",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 1,
|
|
||||||
"LastUsed": "2021-12-24T16:13:06.236748538+01:00"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Network": {
|
|
||||||
"Id": "a443c07a-5765-4a78-97fc-390d9c1d0e49",
|
|
||||||
"Net": {
|
|
||||||
"IP": "100.64.0.0",
|
|
||||||
"Mask": "/8AAAA=="
|
|
||||||
},
|
|
||||||
"Dns": ""
|
|
||||||
},
|
|
||||||
"Peers": {
|
|
||||||
"oMNaI8qWi0CyclSuwGR++SurxJyM3pQEiPEHwX8IREo=": {
|
|
||||||
"Key": "oMNaI8qWi0CyclSuwGR++SurxJyM3pQEiPEHwX8IREo=",
|
|
||||||
"SetupKey": "EB51E9EB-A11F-4F6E-8E49-C982891B405A",
|
|
||||||
"IP": "100.64.0.2",
|
|
||||||
"Meta": {
|
|
||||||
"Hostname": "braginini",
|
|
||||||
"GoOS": "linux",
|
|
||||||
"Kernel": "Linux",
|
|
||||||
"Core": "21.04",
|
|
||||||
"Platform": "x86_64",
|
|
||||||
"OS": "Ubuntu",
|
|
||||||
"WtVersion": ""
|
|
||||||
},
|
|
||||||
"Name": "braginini",
|
|
||||||
"Status": {
|
|
||||||
"LastSeen": "2021-12-24T16:13:11.244342541+01:00",
|
|
||||||
"Connected": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"xlx9/9D8+ibnRiIIB8nHGMxGOzxV17r8ShPHgi4aYSM=": {
|
|
||||||
"Key": "xlx9/9D8+ibnRiIIB8nHGMxGOzxV17r8ShPHgi4aYSM=",
|
|
||||||
"SetupKey": "1B2B50B0-B3E8-4B0C-A426-525EDB8481BD",
|
|
||||||
"IP": "100.64.0.1",
|
|
||||||
"Meta": {
|
|
||||||
"Hostname": "braginini",
|
|
||||||
"GoOS": "linux",
|
|
||||||
"Kernel": "Linux",
|
|
||||||
"Core": "21.04",
|
|
||||||
"Platform": "x86_64",
|
|
||||||
"OS": "Ubuntu",
|
|
||||||
"WtVersion": ""
|
|
||||||
},
|
|
||||||
"Name": "braginini",
|
|
||||||
"Status": {
|
|
||||||
"LastSeen": "2021-12-24T16:12:49.089339333+01:00",
|
|
||||||
"Connected": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"google-oauth2|103201118415301331038": {
|
|
||||||
"Id": "google-oauth2|103201118415301331038",
|
|
||||||
"SetupKeys": {
|
|
||||||
"5AFB60DB-61F2-4251-8E11-494847EE88E9": {
|
|
||||||
"Id": "2485964613",
|
|
||||||
"Key": "5AFB60DB-61F2-4251-8E11-494847EE88E9",
|
|
||||||
"Name": "Default key",
|
|
||||||
"Type": "reusable",
|
|
||||||
"CreatedAt": "2021-12-24T16:10:02.238476+01:00",
|
|
||||||
"ExpiresAt": "2022-01-23T16:10:02.238476+01:00",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 1,
|
|
||||||
"LastUsed": "2021-12-24T16:12:05.994307717+01:00"
|
|
||||||
},
|
|
||||||
"A72E4DC2-00DE-4542-8A24-62945438104E": {
|
|
||||||
"Id": "3504804807",
|
|
||||||
"Key": "A72E4DC2-00DE-4542-8A24-62945438104E",
|
|
||||||
"Name": "One-off key",
|
|
||||||
"Type": "one-off",
|
|
||||||
"CreatedAt": "2021-12-24T16:10:02.238478209+01:00",
|
|
||||||
"ExpiresAt": "2022-01-23T16:10:02.238478209+01:00",
|
|
||||||
"Revoked": false,
|
|
||||||
"UsedTimes": 1,
|
|
||||||
"LastUsed": "2021-12-24T16:11:27.015741738+01:00"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Network": {
|
|
||||||
"Id": "b6d0b152-364e-40c1-a8a1-fa7bcac2267f",
|
|
||||||
"Net": {
|
|
||||||
"IP": "100.64.0.0",
|
|
||||||
"Mask": "/8AAAA=="
|
|
||||||
},
|
|
||||||
"Dns": ""
|
|
||||||
},
|
|
||||||
"Peers": {
|
|
||||||
"6kjbmVq1hmucVzvBXo5OucY5OYv+jSsB1jUTLq291Dw=": {
|
|
||||||
"Key": "6kjbmVq1hmucVzvBXo5OucY5OYv+jSsB1jUTLq291Dw=",
|
|
||||||
"SetupKey": "5AFB60DB-61F2-4251-8E11-494847EE88E9",
|
|
||||||
"IP": "100.64.0.2",
|
|
||||||
"Meta": {
|
|
||||||
"Hostname": "braginini",
|
|
||||||
"GoOS": "linux",
|
|
||||||
"Kernel": "Linux",
|
|
||||||
"Core": "21.04",
|
|
||||||
"Platform": "x86_64",
|
|
||||||
"OS": "Ubuntu",
|
|
||||||
"WtVersion": ""
|
|
||||||
},
|
|
||||||
"Name": "braginini",
|
|
||||||
"Status": {
|
|
||||||
"LastSeen": "2021-12-24T16:12:05.994305438+01:00",
|
|
||||||
"Connected": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Ok+5QMdt/UjoktNOvicGYj+IX2g98p+0N2PJ3vJ45RI=": {
|
|
||||||
"Key": "Ok+5QMdt/UjoktNOvicGYj+IX2g98p+0N2PJ3vJ45RI=",
|
|
||||||
"SetupKey": "A72E4DC2-00DE-4542-8A24-62945438104E",
|
|
||||||
"IP": "100.64.0.1",
|
|
||||||
"Meta": {
|
|
||||||
"Hostname": "braginini",
|
|
||||||
"GoOS": "linux",
|
|
||||||
"Kernel": "Linux",
|
|
||||||
"Core": "21.04",
|
|
||||||
"Platform": "x86_64",
|
|
||||||
"OS": "Ubuntu",
|
|
||||||
"WtVersion": ""
|
|
||||||
},
|
|
||||||
"Name": "braginini",
|
|
||||||
"Status": {
|
|
||||||
"LastSeen": "2021-12-24T16:11:27.015739803+01:00",
|
|
||||||
"Connected": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
BIN
management/server/testdata/storev1.sqlite
vendored
Normal file
BIN
management/server/testdata/storev1.sqlite
vendored
Normal file
Binary file not shown.
@ -59,8 +59,10 @@ func TestUser_CreatePAT_ForSameUser(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, pat.CreatedBy, mockUserID)
|
assert.Equal(t, pat.CreatedBy, mockUserID)
|
||||||
|
|
||||||
fileStore := am.Store.(*FileStore)
|
tokenID, err := am.Store.GetTokenIDByHashedToken(context.Background(), pat.HashedToken)
|
||||||
tokenID := fileStore.HashedPAT2TokenID[pat.HashedToken]
|
if err != nil {
|
||||||
|
t.Fatalf("Error when getting token ID by hashed token: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
if tokenID == "" {
|
if tokenID == "" {
|
||||||
t.Fatal("GetTokenIDByHashedToken failed after adding PAT")
|
t.Fatal("GetTokenIDByHashedToken failed after adding PAT")
|
||||||
@ -68,11 +70,12 @@ func TestUser_CreatePAT_ForSameUser(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, pat.ID, tokenID)
|
assert.Equal(t, pat.ID, tokenID)
|
||||||
|
|
||||||
userID := fileStore.TokenID2UserID[tokenID]
|
user, err := am.Store.GetUserByTokenID(context.Background(), tokenID)
|
||||||
if userID == "" {
|
if err != nil {
|
||||||
t.Fatal("GetUserByTokenId failed after adding PAT")
|
t.Fatalf("Error when getting user by token ID: %s", err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, mockUserID, userID)
|
|
||||||
|
assert.Equal(t, mockUserID, user.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUser_CreatePAT_ForDifferentUser(t *testing.T) {
|
func TestUser_CreatePAT_ForDifferentUser(t *testing.T) {
|
||||||
@ -189,9 +192,12 @@ func TestUser_DeletePAT(t *testing.T) {
|
|||||||
t.Fatalf("Error when adding PAT to user: %s", err)
|
t.Fatalf("Error when adding PAT to user: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Nil(t, store.Accounts[mockAccountID].Users[mockUserID].PATs[mockTokenID1])
|
account, err = store.GetAccount(context.Background(), mockAccountID)
|
||||||
assert.Empty(t, store.HashedPAT2TokenID[mockToken1])
|
if err != nil {
|
||||||
assert.Empty(t, store.TokenID2UserID[mockTokenID1])
|
t.Fatalf("Error when getting account: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, account.Users[mockUserID].PATs[mockTokenID1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUser_GetPAT(t *testing.T) {
|
func TestUser_GetPAT(t *testing.T) {
|
||||||
@ -350,13 +356,16 @@ func TestUser_CreateServiceUser(t *testing.T) {
|
|||||||
t.Fatalf("Error when creating service user: %s", err)
|
t.Fatalf("Error when creating service user: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, 2, len(store.Accounts[mockAccountID].Users))
|
account, err = store.GetAccount(context.Background(), mockAccountID)
|
||||||
assert.NotNil(t, store.Accounts[mockAccountID].Users[user.ID])
|
assert.NoError(t, err)
|
||||||
assert.True(t, store.Accounts[mockAccountID].Users[user.ID].IsServiceUser)
|
|
||||||
assert.Equal(t, mockServiceUserName, store.Accounts[mockAccountID].Users[user.ID].ServiceUserName)
|
assert.Equal(t, 2, len(account.Users))
|
||||||
assert.Equal(t, UserRole(mockRole), store.Accounts[mockAccountID].Users[user.ID].Role)
|
assert.NotNil(t, account.Users[user.ID])
|
||||||
assert.Equal(t, []string{"group1", "group2"}, store.Accounts[mockAccountID].Users[user.ID].AutoGroups)
|
assert.True(t, account.Users[user.ID].IsServiceUser)
|
||||||
assert.Equal(t, map[string]*PersonalAccessToken{}, store.Accounts[mockAccountID].Users[user.ID].PATs)
|
assert.Equal(t, mockServiceUserName, account.Users[user.ID].ServiceUserName)
|
||||||
|
assert.Equal(t, UserRole(mockRole), account.Users[user.ID].Role)
|
||||||
|
assert.Equal(t, []string{"group1", "group2"}, account.Users[user.ID].AutoGroups)
|
||||||
|
assert.Equal(t, map[string]*PersonalAccessToken{}, account.Users[user.ID].PATs)
|
||||||
|
|
||||||
assert.Zero(t, user.Email)
|
assert.Zero(t, user.Email)
|
||||||
assert.True(t, user.IsServiceUser)
|
assert.True(t, user.IsServiceUser)
|
||||||
@ -394,12 +403,15 @@ func TestUser_CreateUser_ServiceUser(t *testing.T) {
|
|||||||
t.Fatalf("Error when creating user: %s", err)
|
t.Fatalf("Error when creating user: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
account, err = store.GetAccount(context.Background(), mockAccountID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.True(t, user.IsServiceUser)
|
assert.True(t, user.IsServiceUser)
|
||||||
assert.Equal(t, 2, len(store.Accounts[mockAccountID].Users))
|
assert.Equal(t, 2, len(account.Users))
|
||||||
assert.True(t, store.Accounts[mockAccountID].Users[user.ID].IsServiceUser)
|
assert.True(t, account.Users[user.ID].IsServiceUser)
|
||||||
assert.Equal(t, mockServiceUserName, store.Accounts[mockAccountID].Users[user.ID].ServiceUserName)
|
assert.Equal(t, mockServiceUserName, account.Users[user.ID].ServiceUserName)
|
||||||
assert.Equal(t, UserRole(mockRole), store.Accounts[mockAccountID].Users[user.ID].Role)
|
assert.Equal(t, UserRole(mockRole), account.Users[user.ID].Role)
|
||||||
assert.Equal(t, []string{"group1", "group2"}, store.Accounts[mockAccountID].Users[user.ID].AutoGroups)
|
assert.Equal(t, []string{"group1", "group2"}, account.Users[user.ID].AutoGroups)
|
||||||
|
|
||||||
assert.Equal(t, mockServiceUserName, user.Name)
|
assert.Equal(t, mockServiceUserName, user.Name)
|
||||||
assert.Equal(t, mockRole, user.Role)
|
assert.Equal(t, mockRole, user.Role)
|
||||||
@ -550,12 +562,15 @@ func TestUser_DeleteUser_ServiceUser(t *testing.T) {
|
|||||||
err = am.DeleteUser(context.Background(), mockAccountID, mockUserID, mockServiceUserID)
|
err = am.DeleteUser(context.Background(), mockAccountID, mockUserID, mockServiceUserID)
|
||||||
tt.assertErrFunc(t, err, tt.assertErrMessage)
|
tt.assertErrFunc(t, err, tt.assertErrMessage)
|
||||||
|
|
||||||
|
account, err2 := store.GetAccount(context.Background(), mockAccountID)
|
||||||
|
assert.NoError(t, err2)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
assert.Equal(t, 2, len(store.Accounts[mockAccountID].Users))
|
assert.Equal(t, 2, len(account.Users))
|
||||||
assert.NotNil(t, store.Accounts[mockAccountID].Users[mockServiceUserID])
|
assert.NotNil(t, account.Users[mockServiceUserID])
|
||||||
} else {
|
} else {
|
||||||
assert.Equal(t, 1, len(store.Accounts[mockAccountID].Users))
|
assert.Equal(t, 1, len(account.Users))
|
||||||
assert.Nil(t, store.Accounts[mockAccountID].Users[mockServiceUserID])
|
assert.Nil(t, account.Users[mockServiceUserID])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user