wired up sqlite store for use in networkmap controller

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
This commit is contained in:
Dmitri Dolguikh
2026-08-13 13:16:23 +02:00
parent 931598e593
commit 4aa123b6ad
8 changed files with 130 additions and 72 deletions

View File

@@ -1,51 +0,0 @@
package networkmapdb
import (
"context"
"github.com/netbirdio/netbird/management/server/integrations/integrated_validator"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/shared/management/networkmap"
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
)
type NetworkMapDBStore interface { //nolint:revive // established name across the codebase
BeginTx(ctx context.Context) (NetworkMapDBStoreConn, error)
}
type NetworkMapDBStoreConn interface { //nolint:revive // established name across the codebase
GetGroups(ctx context.Context, accountId string) ([]nmdata.Group, map[string]map[string]any, error)
GetDomains(ctx context.Context, accountId string) ([]Domain, error)
GetPeers(ctx context.Context, accountId string) ([]nmdata.Peer, map[string][]*nmdata.Peer, error)
GetPolicies(ctx context.Context, accountId string) ([]nmdata.Policy, map[string]map[string]any, map[string]map[string]any, error)
GetRoutes(ctx context.Context, accountId string) ([]nmdata.Route, error)
GetNameServerGroups(ctx context.Context, accountId string) ([]nmdata.NameServerGroup, error)
GetNetworkResources(ctx context.Context, accountId string) ([]nmdata.NetworkResource, error)
GetNetworkRouters(ctx context.Context, accountId string) (map[string]map[string]*nmdata.NetworkRouter, error)
GetNetwork(ctx context.Context, accountId string) (nmdata.Network, error)
GetAppliedZoneCandidates(ctx context.Context, accountId string) ([]networkmap.AppliedZoneCandidate, error)
GetAccountSettings(ctx context.Context, accountId string) (nmdata.AccountSettingsInfo, error)
GetPostureChecks(ctx context.Context, accountId string) ([]nmdata.PostureChecks, map[string]string, error)
GetAllowedUsers(ctx context.Context, accountId string) (map[string]struct{}, map[string][]string, error)
GetDnsSettings(ctx context.Context, accountId string) (nmdata.DNSSettings, error)
GetNetworkXIDToPublicIdMap(ctx context.Context, accountId string) (map[string]string, error)
GetPrivateServices(ctx context.Context, accountId string) ([]Service, error)
GetProxyTargetedDomainResourceIDs(ctx context.Context, accountId string) (map[string]struct{}, error)
CommitTx(ctx context.Context) error
RollbackTx(ctx context.Context) error
}
type NetworkMapDBStoreImpl struct { //nolint:revive // established name across the codebase
store NetworkMapDBStore
integratedPeerValidator integrated_validator.IntegratedValidator
extraSettingsManager settings.Manager
}
func NewNetworkMapDBStoreImpl(store NetworkMapDBStore, integratedPeerValidator integrated_validator.IntegratedValidator, extraSettingsManager settings.Manager) *NetworkMapDBStoreImpl {
return &NetworkMapDBStoreImpl{
store: store,
integratedPeerValidator: integratedPeerValidator,
extraSettingsManager: extraSettingsManager,
}
}

View File

@@ -0,0 +1,73 @@
package networkmapdbfactory
import (
"context"
"fmt"
"os"
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/integrations/integrated_validator"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/types"
log "github.com/sirupsen/logrus"
)
const storeSqliteFileName = "store.db"
func NewNetworkMapDBStore(
ctx context.Context,
kind types.Engine,
dataDir string,
integratedPeerValidator integrated_validator.IntegratedValidator,
extraSettingsManager settings.Manager) (*networkmapdb.NetworkMapDBStoreImpl, error) {
switch kind {
case types.SqliteStoreEngine:
log.WithContext(ctx).Info("networkmap store is using SQLite")
storeFile := storeSqliteFileName
if envFile, ok := os.LookupEnv("NB_STORE_ENGINE_SQLITE_FILE"); ok && envFile != "" {
storeFile = envFile
}
store, err := networkmap_sqlite.NewSqliteStore(storeFile, dataDir)
if err != nil {
return nil, err
}
return &networkmapdb.NetworkMapDBStoreImpl{
Store: store,
IntegratedPeerValidator: integratedPeerValidator,
ExtraSettingsManager: extraSettingsManager,
}, nil
case types.PostgresStoreEngine:
log.WithContext(ctx).Info("using Postgres store engine")
dsn, err := mustLookupDsnEnv()
if err != nil {
return nil, err
}
store, err := networkmap_pgsql.NewPostgresqlStore(ctx, dsn)
if err != nil {
return nil, err
}
return &networkmapdb.NetworkMapDBStoreImpl{
Store: store,
IntegratedPeerValidator: integratedPeerValidator,
ExtraSettingsManager: extraSettingsManager,
}, nil
}
return nil, nil
}
func mustLookupDsnEnv() (string, error) {
if v, ok := os.LookupEnv(store.PostgresDsnEnv); ok {
return v, nil
}
if v, ok := os.LookupEnv(store.PostgresDsnEnvLegacy); ok {
return v, nil
}
return "", fmt.Errorf("%s env var must be set when using postgres networkmap store", store.PostgresDsnEnv)
}

View File

@@ -14,7 +14,7 @@ import (
)
func (s *NetworkMapDBStoreImpl) GetNetworkMapData(ctx context.Context, accountId string) (*networkmap.NetworkMapData, error) {
tx, err := s.store.BeginTx(ctx)
tx, err := s.Store.BeginTx(ctx)
if err != nil {
return nil, err
}
@@ -139,12 +139,12 @@ func (s *NetworkMapDBStoreImpl) GetNetworkMapData(ctx context.Context, accountId
ProxyTargetedDomainResourceIDs: proxyTargetedDomainResourceIDs,
}
extraSettings, err := s.extraSettingsManager.GetExtraSettings(ctx, accountId)
extraSettings, err := s.ExtraSettingsManager.GetExtraSettings(ctx, accountId)
if err != nil {
return nil, err
}
toret.ValidatedPeers, err = s.integratedPeerValidator.GetValidatedPeers(ctx, accountId, maps.Values(toret.Groups), maps.Values(toret.Peers), extraSettings)
toret.ValidatedPeers, err = s.IntegratedPeerValidator.GetValidatedPeers(ctx, accountId, maps.Values(toret.Groups), maps.Values(toret.Peers), extraSettings)
if err != nil {
return nil, err
}

View File

@@ -1,6 +1,7 @@
package networkmapdb
import (
"context"
"database/sql"
"encoding/json"
"errors"
@@ -8,12 +9,47 @@ import (
"reflect"
"github.com/miekg/dns"
"github.com/netbirdio/netbird/management/server/integrations/integrated_validator"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/shared/management/networkmap"
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
)
var ErrDnsUnsupportedRecordType = errors.New("unsupported record type")
type NetworkMapDBStore interface { //nolint:revive // established name across the codebase
BeginTx(ctx context.Context) (NetworkMapDBStoreConn, error)
}
type NetworkMapDBStoreConn interface { //nolint:revive // established name across the codebase
GetGroups(ctx context.Context, accountId string) ([]nmdata.Group, map[string]map[string]any, error)
GetDomains(ctx context.Context, accountId string) ([]Domain, error)
GetPeers(ctx context.Context, accountId string) ([]nmdata.Peer, map[string][]*nmdata.Peer, error)
GetPolicies(ctx context.Context, accountId string) ([]nmdata.Policy, map[string]map[string]any, map[string]map[string]any, error)
GetRoutes(ctx context.Context, accountId string) ([]nmdata.Route, error)
GetNameServerGroups(ctx context.Context, accountId string) ([]nmdata.NameServerGroup, error)
GetNetworkResources(ctx context.Context, accountId string) ([]nmdata.NetworkResource, error)
GetNetworkRouters(ctx context.Context, accountId string) (map[string]map[string]*nmdata.NetworkRouter, error)
GetNetwork(ctx context.Context, accountId string) (nmdata.Network, error)
GetAppliedZoneCandidates(ctx context.Context, accountId string) ([]networkmap.AppliedZoneCandidate, error)
GetAccountSettings(ctx context.Context, accountId string) (nmdata.AccountSettingsInfo, error)
GetPostureChecks(ctx context.Context, accountId string) ([]nmdata.PostureChecks, map[string]string, error)
GetAllowedUsers(ctx context.Context, accountId string) (map[string]struct{}, map[string][]string, error)
GetDnsSettings(ctx context.Context, accountId string) (nmdata.DNSSettings, error)
GetNetworkXIDToPublicIdMap(ctx context.Context, accountId string) (map[string]string, error)
GetPrivateServices(ctx context.Context, accountId string) ([]Service, error)
GetProxyTargetedDomainResourceIDs(ctx context.Context, accountId string) (map[string]struct{}, error)
CommitTx(ctx context.Context) error
RollbackTx(ctx context.Context) error
}
type NetworkMapDBStoreImpl struct { //nolint:revive // established name across the codebase
Store NetworkMapDBStore
IntegratedPeerValidator integrated_validator.IntegratedValidator
ExtraSettingsManager settings.Manager
}
// The order of fields in these structs is important.
// Mapping of results of sqlite queries relies on the order
// of the fields in these structs, when a query or a struct changes,

View File

@@ -31,7 +31,7 @@ type SqliteStoreConn struct {
Conn sqliteInterface
}
func NewSqliteStore(ctx context.Context, storeFile, dataDir string) (*SqliteStore, error) {
func NewSqliteStore(storeFile, dataDir string) (*SqliteStore, error) {
dbfile := storeFile
if envFile, ok := os.LookupEnv("NB_STORE_ENGINE_SQLITE_FILE"); ok && envFile != "" {
dbfile = envFile
@@ -76,7 +76,7 @@ func NewSqliteStore(ctx context.Context, storeFile, dataDir string) (*SqliteStor
return &SqliteStore{Db: db}, nil
}
func (s *SqliteStore) BeginTx(ctx context.Context) (*SqliteStoreConn, error) {
func (s *SqliteStore) BeginTx(ctx context.Context) (networkmapdb.NetworkMapDBStoreConn, error) {
tx, err := s.Db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true, Isolation: sql.LevelRepeatableRead})
if err != nil {
return nil, err

View File

@@ -7,7 +7,6 @@ import (
"crypto/tls"
"net/http"
"net/netip"
"os"
"slices"
"time"
@@ -30,7 +29,7 @@ import (
accesslogsmanager "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs/manager"
rpservice "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/service"
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
networkmap_pgsql "github.com/netbirdio/netbird/management/internals/network_map_db/pgsql"
networkmapdbfactory "github.com/netbirdio/netbird/management/internals/network_map_db/factory"
nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc"
"github.com/netbirdio/netbird/management/server/activity"
activitystore "github.com/netbirdio/netbird/management/server/activity/store"
@@ -102,19 +101,20 @@ func (s *BaseServer) Store() store.Store {
})
}
// TODO dmitri: move all validation checks (e.g. config+env vars) from runtime to base server creation
// this way we don't need to spread defensive checks throughout the codebase
func (s *BaseServer) NetworkMapStore() *networkmapdb.NetworkMapDBStoreImpl {
return Create(s, func() *networkmapdb.NetworkMapDBStoreImpl {
dsn := os.Getenv("NETBIRD_NMAP_STORE_DSN") // Todo: this needs to be hoocked up properly
if dsn == "" {
return nil
}
store, err := networkmap_pgsql.NewPostgresqlStore(context.Background(), dsn)
store, err := networkmapdbfactory.NewNetworkMapDBStore(
context.Background(),
s.Config.StoreConfig.Engine,
s.Config.Datadir,
s.IntegratedValidator(),
s.SettingsManager())
if err != nil {
log.Fatalf("failed to create network map store: %v", err)
}
return networkmapdb.NewNetworkMapDBStoreImpl(store, s.IntegratedValidator(), s.SettingsManager())
return store
})
}

View File

@@ -3138,9 +3138,9 @@ func getGormConfig() *gorm.Config {
// newPostgresStore initializes a new Postgres store.
func newPostgresStore(ctx context.Context, metrics telemetry.AppMetrics, skipMigration bool) (Store, error) {
dsn, ok := lookupDSNEnv(postgresDsnEnv, postgresDsnEnvLegacy)
dsn, ok := lookupDSNEnv(PostgresDsnEnv, PostgresDsnEnvLegacy)
if !ok {
return nil, fmt.Errorf("%s is not set", postgresDsnEnv)
return nil, fmt.Errorf("%s is not set", PostgresDsnEnv)
}
return NewPostgresqlStore(ctx, dsn, metrics, skipMigration)
}

View File

@@ -428,8 +428,8 @@ type AgentNetworkMetrics struct {
}
const (
postgresDsnEnv = "NB_STORE_ENGINE_POSTGRES_DSN"
postgresDsnEnvLegacy = "NETBIRD_STORE_ENGINE_POSTGRES_DSN"
PostgresDsnEnv = "NB_STORE_ENGINE_POSTGRES_DSN"
PostgresDsnEnvLegacy = "NETBIRD_STORE_ENGINE_POSTGRES_DSN"
mysqlDsnEnv = "NB_STORE_ENGINE_MYSQL_DSN"
mysqlDsnEnvLegacy = "NETBIRD_STORE_ENGINE_MYSQL_DSN"
)
@@ -773,7 +773,7 @@ func getSqlStoreEngine(ctx context.Context, store *SqlStore, kind types.Engine)
}
func newReusedPostgresStore(ctx context.Context, store *SqlStore, kind types.Engine) (*SqlStore, func(), error) {
dsn, ok := lookupDSNEnv(postgresDsnEnv, postgresDsnEnvLegacy)
dsn, ok := lookupDSNEnv(PostgresDsnEnv, PostgresDsnEnvLegacy)
if !ok || dsn == "" {
var err error
_, dsn, err = testutil.CreatePostgresTestContainer()
@@ -783,7 +783,7 @@ func newReusedPostgresStore(ctx context.Context, store *SqlStore, kind types.Eng
}
if dsn == "" {
return nil, nil, fmt.Errorf("%s is not set", postgresDsnEnv)
return nil, nil, fmt.Errorf("%s is not set", PostgresDsnEnv)
}
db, err := openDBWithRetry(dsn, kind, 5)