diff --git a/management/internals/network_map_db/db_store.go b/management/internals/network_map_db/db_store.go deleted file mode 100644 index 9c958109d..000000000 --- a/management/internals/network_map_db/db_store.go +++ /dev/null @@ -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, - } -} diff --git a/management/internals/network_map_db/factory/db_store.go b/management/internals/network_map_db/factory/db_store.go new file mode 100644 index 000000000..84161c418 --- /dev/null +++ b/management/internals/network_map_db/factory/db_store.go @@ -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) +} diff --git a/management/internals/network_map_db/network_map_data.go b/management/internals/network_map_db/network_map_data.go index c700a05c3..8d8c033b4 100644 --- a/management/internals/network_map_db/network_map_data.go +++ b/management/internals/network_map_db/network_map_data.go @@ -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 } diff --git a/management/internals/network_map_db/shared_types.go b/management/internals/network_map_db/shared_types.go index eed479e9d..fd3f11e08 100644 --- a/management/internals/network_map_db/shared_types.go +++ b/management/internals/network_map_db/shared_types.go @@ -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, diff --git a/management/internals/network_map_db/sqlite/sqlite_store.go b/management/internals/network_map_db/sqlite/sqlite_store.go index 04d8d467e..7632b065d 100644 --- a/management/internals/network_map_db/sqlite/sqlite_store.go +++ b/management/internals/network_map_db/sqlite/sqlite_store.go @@ -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 diff --git a/management/internals/server/boot.go b/management/internals/server/boot.go index 6a73f6d5a..fc5795ee8 100644 --- a/management/internals/server/boot.go +++ b/management/internals/server/boot.go @@ -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 }) } diff --git a/management/server/store/sql_store.go b/management/server/store/sql_store.go index 67f13a32c..bb0b9627e 100644 --- a/management/server/store/sql_store.go +++ b/management/server/store/sql_store.go @@ -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) } diff --git a/management/server/store/store.go b/management/server/store/store.go index ed0bed9fc..eb747f11c 100644 --- a/management/server/store/store.go +++ b/management/server/store/store.go @@ -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)