mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-29 19:11:28 +02:00
added support for GetAccountSettings to sqlite store
Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
This commit is contained in:
@@ -7,15 +7,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetAccountSettings(t *testing.T) {
|
||||
if engine == string(types.SqliteStoreEngine) {
|
||||
t.Skip()
|
||||
}
|
||||
ctx := context.TODO()
|
||||
|
||||
execQuery(t, ctx,
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
networkmap_pgsql "github.com/netbirdio/netbird/management/internals/network_map_db/pgsql"
|
||||
networkmap_sqlite "github.com/netbirdio/netbird/management/internals/network_map_db/sqlite"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
)
|
||||
|
||||
@@ -21,24 +22,28 @@ import (
|
||||
var baseData string
|
||||
|
||||
var (
|
||||
pgstore *networkmap_pgsql.PgStore
|
||||
engine string
|
||||
pgstore *networkmap_pgsql.PgStore
|
||||
sqlitestore *networkmap_sqlite.SqliteStore
|
||||
engine string
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var cleanup func()
|
||||
kind, _ := os.LookupEnv("NETBIRD_STORE_ENGINE")
|
||||
switch kind {
|
||||
case "":
|
||||
engine = string(types.PostgresStoreEngine)
|
||||
case string(types.PostgresStoreEngine), string(types.SqliteStoreEngine):
|
||||
engine = string(types.SqliteStoreEngine)
|
||||
sqlitestore, cleanup = createSqliteTestStore(baseData)
|
||||
case string(types.PostgresStoreEngine):
|
||||
engine = kind
|
||||
pgstore, cleanup = createPGTestStore(baseData)
|
||||
case string(types.SqliteStoreEngine):
|
||||
engine = kind
|
||||
sqlitestore, cleanup = createSqliteTestStore(baseData)
|
||||
default:
|
||||
log.Fatalf("unsupported db '%s' in NETBIRD_STORE_ENGINE env var", kind)
|
||||
}
|
||||
|
||||
store, cleanup := createPGTestStore(baseData)
|
||||
pgstore = store
|
||||
|
||||
code := m.Run()
|
||||
|
||||
cleanup()
|
||||
@@ -47,15 +52,28 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func conn(t *testing.T, ctx context.Context) networkmapdb.NetworkMapDBStoreConn {
|
||||
t.Helper()
|
||||
c, err := pgstore.Pool.Acquire(ctx)
|
||||
assert.NoError(t, err)
|
||||
return pgstore.UsingConnection(c.Conn())
|
||||
switch engine {
|
||||
case string(types.PostgresStoreEngine):
|
||||
c, err := pgstore.Pool.Acquire(ctx)
|
||||
assert.NoError(t, err)
|
||||
return pgstore.UsingConnection(c.Conn())
|
||||
case string(types.SqliteStoreEngine):
|
||||
return sqlitestore.UsingConn()
|
||||
}
|
||||
log.Fatalf("unknown db engine kind %s", engine)
|
||||
return nil
|
||||
}
|
||||
|
||||
func execQuery(t *testing.T, ctx context.Context, q string) {
|
||||
t.Helper()
|
||||
_, err := pgstore.Pool.Exec(ctx, q)
|
||||
assert.NoError(t, err)
|
||||
switch engine {
|
||||
case string(types.PostgresStoreEngine):
|
||||
_, err := pgstore.Pool.Exec(ctx, q)
|
||||
assert.NoError(t, err)
|
||||
case string(types.SqliteStoreEngine):
|
||||
_, err := sqlitestore.Db.ExecContext(ctx, q)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// use to parse time in time.RFC3339Nano format
|
||||
|
||||
@@ -58,22 +58,17 @@ func createPGTestStore(baseData string) (*networkmap_pgsql.PgStore, func()) {
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
s, err := networkmap_pgsql.NewPostgresqlStore(ctx, dsn)
|
||||
pgstore, err := networkmap_pgsql.NewPostgresqlStore(ctx, dsn)
|
||||
if err != nil {
|
||||
log.Fatal("error creating postgres store %w", err)
|
||||
}
|
||||
|
||||
for _, query := range strings.Split(baseData, ";") {
|
||||
if _, err := s.Pool.Exec(ctx, query); err != nil {
|
||||
if _, err := pgstore.Pool.Exec(ctx, query); err != nil {
|
||||
log.Fatalf("error initializing db: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
pgstore, err := networkmap_pgsql.NewPostgresqlStore(ctx, dsn)
|
||||
if err != nil {
|
||||
log.Fatalf("error creating pg store %v", err.Error())
|
||||
}
|
||||
|
||||
return pgstore, cleanup
|
||||
}
|
||||
|
||||
|
||||
@@ -19,18 +19,15 @@ func TestGetPrivateServicesViaPgxConnection(t *testing.T) {
|
||||
}
|
||||
ctx := context.TODO()
|
||||
|
||||
_, err := pgstore.Pool.Exec(ctx,
|
||||
execQuery(t, ctx,
|
||||
`insert into services (id, account_id, enabled, private, access_groups, proxy_cluster, domain)
|
||||
values('service-1','account-1',true,true,'["group-one-resource-id"]','test-1.com','test-2.com')`)
|
||||
assert.NoError(t, err)
|
||||
execQuery(t, ctx,
|
||||
`insert into services (id, account_id, enabled, private, access_groups, proxy_cluster, domain)
|
||||
values('service-2','account-1',true,true,'["group-one-resource-id","group-two-resources-id"]','test-3.com','test-4.com')`)
|
||||
assert.NoError(t, err)
|
||||
execQuery(t, ctx,
|
||||
`insert into services (id, account_id, enabled, private, access_groups, proxy_cluster, domain)
|
||||
values('service-3','account-1',null,null,null,null,null)`)
|
||||
assert.NoError(t, err)
|
||||
|
||||
services, err := conn(t, ctx).GetPrivateServices(ctx, "account-1")
|
||||
assert.NoError(t, err)
|
||||
@@ -58,6 +55,10 @@ func TestGetPrivateServicesViaPgxConnection(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetProxyTargetedDomainResourceIDsViaPgxConnection(t *testing.T) {
|
||||
if engine == string(types.SqliteStoreEngine) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
execQuery(t, ctx,
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
//go:build integration
|
||||
|
||||
package networkmap_pgsql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
networkmap_sqlite "github.com/netbirdio/netbird/management/internals/network_map_db/sqlite"
|
||||
gormstore "github.com/netbirdio/netbird/management/server/store"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func createSqliteTestStore(baseData string) (*networkmap_sqlite.SqliteStore, func()) {
|
||||
storeSqliteFileName := ":memory:"
|
||||
storeStr := fmt.Sprintf("%s?cache=shared", storeSqliteFileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
// Vo avoid `The process cannot access the file because it is being used by another process` on Windows
|
||||
storeStr = storeSqliteFileName
|
||||
}
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(storeStr), &gorm.Config{})
|
||||
if err != nil {
|
||||
log.Fatalf("error initializing db: %s", err.Error())
|
||||
}
|
||||
_, err = gormstore.NewSqlStore(context.TODO(), db, types.SqliteStoreEngine, nil, false)
|
||||
if err != nil {
|
||||
log.Fatalf("error initializing db: %s", err.Error())
|
||||
}
|
||||
|
||||
sqldb, err := db.DB()
|
||||
if err != nil {
|
||||
log.Fatalf("error initializing db: %s", err.Error())
|
||||
|
||||
}
|
||||
for _, query := range strings.Split(baseData, ";") {
|
||||
if _, err := sqldb.Exec(query); err != nil {
|
||||
log.Fatalf("error initializing db: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return &networkmap_sqlite.SqliteStore{Db: sqldb}, func() {}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ const (
|
||||
NMAP_STRUCT_TAG = "nmap"
|
||||
NMAP_SKIP = "skip"
|
||||
NMAP_MAP_TO = "map_to"
|
||||
NMAP_JSON = "json"
|
||||
)
|
||||
|
||||
type NetworkMapDBStore interface { //nolint:revive // established name across the codebase
|
||||
@@ -164,6 +165,14 @@ func FromSqlTypesToSharedTypes(src reflect.Value, dst reflect.Value) error {
|
||||
if err := json.Unmarshal(s, dstField.Addr().Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
case "[]byte", "[]uint8":
|
||||
s := srcField.Interface().([]byte)
|
||||
if _, ok := fieldTags[NMAP_JSON]; !ok || len(s) == 0 {
|
||||
continue
|
||||
}
|
||||
if err := json.Unmarshal(s, dstField.Addr().Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
case "[]string":
|
||||
if srcField.IsNil() {
|
||||
continue
|
||||
@@ -177,6 +186,23 @@ func FromSqlTypesToSharedTypes(src reflect.Value, dst reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func StructFields(src reflect.Value) []any {
|
||||
toret := make([]any, 0)
|
||||
typ := src.Elem().Type()
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
f := typ.Field(i)
|
||||
if f.PkgPath != "" { // skip unexported fields
|
||||
continue
|
||||
}
|
||||
|
||||
srcField := src.Elem().Field(i)
|
||||
toret = append(toret, srcField.Addr().Interface())
|
||||
}
|
||||
|
||||
return toret
|
||||
}
|
||||
|
||||
type fieldTag struct {
|
||||
Key string
|
||||
Value string
|
||||
|
||||
@@ -124,6 +124,25 @@ func TestEmptyPublicIdsFilled(t *testing.T) {
|
||||
assert.NotEmpty(t, dst.PublicId)
|
||||
}
|
||||
|
||||
// only []byte and []uint8 slices with "json" tag are being parsed
|
||||
func TestByteSliceSupport(t *testing.T) {
|
||||
src := withByteSlice{
|
||||
Field: []byte("[\"one\",\"two\",\"three\"]"),
|
||||
}
|
||||
dst := byteSliceTarget{}
|
||||
assert.NoError(t, networkmapdb.FromSqlTypesToSharedTypes(reflect.ValueOf(&src), reflect.ValueOf(&dst)))
|
||||
assert.Equal(t, []string{"one", "two", "three"}, dst.Field)
|
||||
}
|
||||
|
||||
func TestUint8SliceSupport(t *testing.T) {
|
||||
src := withUint8Slice{
|
||||
Field: []uint8("[\"one\",\"two\",\"three\"]"),
|
||||
}
|
||||
dst := uint8SliceTarget{}
|
||||
assert.NoError(t, networkmapdb.FromSqlTypesToSharedTypes(reflect.ValueOf(&src), reflect.ValueOf(&dst)))
|
||||
assert.Equal(t, []string{"one", "two", "three"}, dst.Field)
|
||||
}
|
||||
|
||||
type withNullString struct {
|
||||
Name sql.NullString
|
||||
}
|
||||
@@ -217,3 +236,19 @@ type emptyPublicIdTarget struct {
|
||||
PublicID string
|
||||
PublicId string
|
||||
}
|
||||
|
||||
type withByteSlice struct {
|
||||
Field []byte `nmap:"json"`
|
||||
}
|
||||
|
||||
type byteSliceTarget struct {
|
||||
Field []string
|
||||
}
|
||||
|
||||
type withUint8Slice struct {
|
||||
Field []byte `nmap:"json"`
|
||||
}
|
||||
|
||||
type uint8SliceTarget struct {
|
||||
Field []string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"reflect"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetAccountSettingsQuery = `
|
||||
select settings_peer_login_expiration_enabled as peer_login_expiration_enabled,
|
||||
settings_peer_login_expiration as peer_login_expiration,
|
||||
settings_peer_inactivity_expiration_enabled as peer_inactivity_expiration_enabled,
|
||||
settings_peer_inactivity_expiration as peer_inactivity_expiration,
|
||||
settings_dns_domain as dns_domain,
|
||||
settings_ipv6_enabled_groups as ipv6_enabled_groups,
|
||||
settings_routing_peer_dns_resolution_enabled as routing_peer_dns_resolution_enabled,
|
||||
settings_lazy_connection_enabled as lazy_connection_enabled,
|
||||
settings_auto_update_version as auto_update_version,
|
||||
settings_auto_update_always as auto_update_always,
|
||||
settings_metrics_push_enabled as metrics_push_enabled
|
||||
from accounts
|
||||
where id=$1
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetAccountSettings(ctx context.Context, accountId string) (nmdata.AccountSettingsInfo, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetAccountSettingsQuery, accountId)
|
||||
if err != nil {
|
||||
return nmdata.AccountSettingsInfo{}, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
rows.Next()
|
||||
a := account{}
|
||||
err = rows.Scan(networkmapdb.StructFields(reflect.ValueOf(&a))...)
|
||||
if err != nil {
|
||||
return nmdata.AccountSettingsInfo{}, err
|
||||
}
|
||||
|
||||
settingsInfo := nmdata.AccountSettingsInfo{}
|
||||
err = networkmapdb.FromSqlTypesToSharedTypes(reflect.ValueOf(&a), reflect.ValueOf(&settingsInfo))
|
||||
if err != nil {
|
||||
return nmdata.AccountSettingsInfo{}, err
|
||||
}
|
||||
|
||||
return settingsInfo, nil
|
||||
}
|
||||
|
||||
type account struct {
|
||||
PeerLoginExpirationEnabled sql.NullBool
|
||||
PeerLoginExpiration sql.NullInt64
|
||||
PeerInactivityExpirationEnabled sql.NullBool
|
||||
PeerInactivityExpiration sql.NullInt64
|
||||
DNSDomain sql.NullString
|
||||
IPv6EnabledGroups []byte `nmap:"json"`
|
||||
RoutingPeerDNSResolutionEnabled sql.NullBool
|
||||
LazyConnectionEnabled sql.NullBool
|
||||
AutoUpdateVersion sql.NullString
|
||||
AutoUpdateAlways sql.NullBool
|
||||
MetricsPushEnabled sql.NullBool
|
||||
}
|
||||
@@ -8,13 +8,26 @@ import (
|
||||
"strings"
|
||||
|
||||
"database/sql"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
type SqliteStore struct {
|
||||
Db *sql.DB
|
||||
}
|
||||
|
||||
func NewSqliteStore(ctx context.Context, storeFile, dataDir, dsn string) (*SqliteStore, error) {
|
||||
type sqliteInterface interface {
|
||||
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
|
||||
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
|
||||
}
|
||||
|
||||
type SqliteStoreConn struct {
|
||||
Conn sqliteInterface
|
||||
}
|
||||
|
||||
func NewSqliteStore(ctx context.Context, storeFile, dataDir string) (*SqliteStore, error) {
|
||||
// storeFile := storeSqliteFileName
|
||||
// if envFile, ok := os.LookupEnv("NB_STORE_ENGINE_SQLITE_FILE"); ok && envFile != "" {
|
||||
// storeFile = envFile
|
||||
@@ -51,9 +64,67 @@ func NewSqliteStore(ctx context.Context, storeFile, dataDir, dsn string) (*Sqlit
|
||||
connStr += "?" + strings.Join(parts, "&")
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite3", "")
|
||||
db, err := sql.Open("sqlite3", connStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SqliteStore{Db: db}, nil
|
||||
}
|
||||
|
||||
func (s *SqliteStore) WithTx(tx *sql.Tx) *SqliteStoreConn {
|
||||
return &SqliteStoreConn{Conn: tx}
|
||||
}
|
||||
|
||||
func (s *SqliteStore) UsingConn() *SqliteStoreConn {
|
||||
return &SqliteStoreConn{Conn: s.Db}
|
||||
}
|
||||
|
||||
func (s *SqliteStoreConn) GetGroups(ctx context.Context, accountId string) ([]nmdata.Group, map[string]map[string]any, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetDomains(ctx context.Context, accountId string) ([]networkmapdb.Domain, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetPeers(ctx context.Context, accountId string) ([]nmdata.Peer, map[string][]*nmdata.Peer, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetPolicies(ctx context.Context, accountId string) ([]nmdata.Policy, map[string]map[string]any, map[string]map[string]any, error) {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetRoutes(ctx context.Context, accountId string) ([]nmdata.Route, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetNameServerGroups(ctx context.Context, accountId string) ([]nmdata.NameServerGroup, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetNetworkResources(ctx context.Context, accountId string) ([]nmdata.NetworkResource, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetNetworkRouters(ctx context.Context, accountId string) (map[string]map[string]*nmdata.NetworkRouter, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetNetwork(ctx context.Context, accountId string) (nmdata.Network, error) {
|
||||
return nmdata.Network{}, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetAppliedZoneCandidates(ctx context.Context, accountId string) ([]networkmap.AppliedZoneCandidate, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetPostureChecks(ctx context.Context, accountId string) ([]nmdata.PostureChecks, map[string]string, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetAllowedUsers(ctx context.Context, accountId string) (map[string]struct{}, map[string][]string, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetDnsSettings(ctx context.Context, accountId string) (nmdata.DNSSettings, error) {
|
||||
return nmdata.DNSSettings{}, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetNetworkXIDToPublicIdMap(ctx context.Context, accountId string) (map[string]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetPrivateServices(ctx context.Context, accountId string) ([]networkmapdb.Service, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *SqliteStoreConn) GetProxyTargetedDomainResourceIDs(ctx context.Context, accountId string) (map[string]struct{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user