Skip to content

Commit 537931c

Browse files
authored
Merge pull request #1153 from ViktorT-11/2025-10-firewalldb-mig-deleted-session-db-fix
[sql-54] firewalldb: handle deleted sessions during the kv stores + privacy mapper migration
2 parents 40d3bdb + 11cb808 commit 537931c

File tree

2 files changed

+266
-44
lines changed

2 files changed

+266
-44
lines changed

firewalldb/sql_migration.go

Lines changed: 85 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,29 @@ func MigrateFirewallDBToSQL(ctx context.Context, kvStore *bbolt.DB,
9393

9494
log.Infof("Starting migration of the rules DB to SQL")
9595

96-
err := migrateKVStoresDBToSQL(ctx, kvStore, sqlTx)
96+
sessions, err := sessionDB.ListSessions(ctx)
97+
if err != nil {
98+
return fmt.Errorf("listing sessions failed: %w", err)
99+
}
100+
101+
sessionMap, err := mapSessions(sessions)
102+
if err != nil {
103+
return fmt.Errorf("mapping sessions failed: %w", err)
104+
}
105+
106+
err = migrateKVStoresDBToSQL(ctx, kvStore, sqlTx, sessionMap)
97107
if err != nil {
98108
return err
99109
}
100110

101-
err = migratePrivacyMapperDBToSQL(ctx, kvStore, sqlTx)
111+
err = migratePrivacyMapperDBToSQL(ctx, kvStore, sqlTx, sessionMap)
102112
if err != nil {
103113
return err
104114
}
105115

106116
err = migrateActionsToSQL(
107117
ctx, kvStore, sqlTx, sessionDB, accountDB, macRootKeyIDs,
118+
sessionMap,
108119
)
109120
if err != nil {
110121
return err
@@ -119,7 +130,7 @@ func MigrateFirewallDBToSQL(ctx context.Context, kvStore *bbolt.DB,
119130
// database to the SQL database. The function also asserts that the
120131
// migrated values match the original values in the KV store.
121132
func migrateKVStoresDBToSQL(ctx context.Context, kvStore *bbolt.DB,
122-
sqlTx SQLQueries) error {
133+
sqlTx SQLQueries, sessMap map[[4]byte]sqlc.Session) error {
123134

124135
log.Infof("Starting migration of the KV stores to SQL")
125136

@@ -128,7 +139,7 @@ func migrateKVStoresDBToSQL(ctx context.Context, kvStore *bbolt.DB,
128139
// 1) Collect all key-value pairs from the KV store.
129140
err := kvStore.View(func(tx *bbolt.Tx) error {
130141
var err error
131-
pairs, err = collectAllPairs(tx)
142+
pairs, err = collectAllPairs(sessMap, tx)
132143
return err
133144
})
134145
if err != nil {
@@ -139,7 +150,7 @@ func migrateKVStoresDBToSQL(ctx context.Context, kvStore *bbolt.DB,
139150

140151
// 2) Insert all collected key-value pairs into the SQL database.
141152
for _, entry := range pairs {
142-
insertedPair, err := insertPair(ctx, sqlTx, entry)
153+
insertedPair, err := insertPair(ctx, sqlTx, sessMap, entry)
143154
if err != nil {
144155
return fmt.Errorf("inserting kv pair %v failed: %w",
145156
entry.key, err)
@@ -187,7 +198,9 @@ func migrateKVStoresDBToSQL(ctx context.Context, kvStore *bbolt.DB,
187198
// designed to iterate over all buckets and values that exist in the KV store.
188199
// That ensures that we find all stores and values that exist in the KV store,
189200
// and can be sure that the kv store actually follows the expected structure.
190-
func collectAllPairs(tx *bbolt.Tx) ([]*kvEntry, error) {
201+
func collectAllPairs(sessMap map[[4]byte]sqlc.Session,
202+
tx *bbolt.Tx) ([]*kvEntry, error) {
203+
191204
var entries []*kvEntry
192205
for _, perm := range []bool{true, false} {
193206
mainBucket, err := getMainBucket(tx, false, perm)
@@ -217,7 +230,7 @@ func collectAllPairs(tx *bbolt.Tx) ([]*kvEntry, error) {
217230
}
218231

219232
pairs, err := collectRulePairs(
220-
ruleBucket, perm, string(rule),
233+
sessMap, ruleBucket, perm, string(rule),
221234
)
222235
if err != nil {
223236
return err
@@ -237,8 +250,8 @@ func collectAllPairs(tx *bbolt.Tx) ([]*kvEntry, error) {
237250

238251
// collectRulePairs processes a single rule bucket, which should contain the
239252
// global and session-kv-store key buckets.
240-
func collectRulePairs(bkt *bbolt.Bucket, perm bool, rule string) ([]*kvEntry,
241-
error) {
253+
func collectRulePairs(sessMap map[[4]byte]sqlc.Session, bkt *bbolt.Bucket,
254+
perm bool, rule string) ([]*kvEntry, error) {
242255

243256
var params []*kvEntry
244257

@@ -270,6 +283,25 @@ func collectRulePairs(bkt *bbolt.Bucket, perm bool, rule string) ([]*kvEntry,
270283
"under %s bucket", sessKVStoreBucketKey)
271284
}
272285

286+
var alias [4]byte
287+
copy(alias[:], groupAlias)
288+
if _, ok := sessMap[alias]; !ok {
289+
// If we can't find the session group in the
290+
// SQL db, that indicates that the session was
291+
// never migrated from KVDB. This likely means
292+
// that the user deleted their session.db file,
293+
// but kept the rules.db file. As the KV entries
294+
// are useless when the session no longer
295+
// exists, we can just skip the migration of the
296+
// KV entries for this group.
297+
log.Warnf("Skipping migration of KV store "+
298+
"entries for session group %x, as the "+
299+
"session group was not found",
300+
groupAlias)
301+
302+
return nil
303+
}
304+
273305
groupBucket := sessBkt.Bucket(groupAlias)
274306
if groupBucket == nil {
275307
return fmt.Errorf("group bucket for group "+
@@ -382,7 +414,7 @@ func collectKVPairs(bkt *bbolt.Bucket, errorOnBuckets, perm bool,
382414

383415
// insertPair inserts a single key-value pair into the SQL database.
384416
func insertPair(ctx context.Context, tx SQLQueries,
385-
entry *kvEntry) (*sqlKvEntry, error) {
417+
sessMap map[[4]byte]sqlc.Session, entry *kvEntry) (*sqlKvEntry, error) {
386418

387419
ruleID, err := tx.GetOrInsertRuleID(ctx, entry.ruleName)
388420
if err != nil {
@@ -397,15 +429,19 @@ func insertPair(ctx context.Context, tx SQLQueries,
397429
}
398430

399431
entry.groupAlias.WhenSome(func(alias []byte) {
400-
var groupID int64
401-
groupID, err = tx.GetSessionIDByAlias(ctx, alias)
402-
if err != nil {
403-
err = fmt.Errorf("getting group id by alias %x "+
404-
"failed: %w", alias, err)
405-
return
432+
var groupAlias [4]byte
433+
copy(groupAlias[:], alias)
434+
435+
sess, ok := sessMap[groupAlias]
436+
if !ok {
437+
// This should be unreachable, as we check for the
438+
// existence of the session group when collecting
439+
// the kv pairs.
440+
err = fmt.Errorf("session group %x not found in map",
441+
alias)
406442
}
407443

408-
p.GroupID = sqldb.SQLInt64(groupID)
444+
p.GroupID = sess.GroupID
409445
})
410446
if err != nil {
411447
return nil, err
@@ -515,12 +551,12 @@ func verifyBktKeys(bkt *bbolt.Bucket, errorOnKeyValues bool,
515551
// from the KV database to the SQL database. The function also asserts that the
516552
// migrated values match the original values in the privacy mapper store.
517553
func migratePrivacyMapperDBToSQL(ctx context.Context, kvStore *bbolt.DB,
518-
sqlTx SQLQueries) error {
554+
sqlTx SQLQueries, sessMap map[[4]byte]sqlc.Session) error {
519555

520556
log.Infof("Starting migration of the privacy mapper store to SQL")
521557

522558
// 1) Collect all privacy pairs from the KV store.
523-
privPairs, err := collectPrivacyPairs(ctx, kvStore, sqlTx)
559+
privPairs, err := collectPrivacyPairs(kvStore, sessMap)
524560
if err != nil {
525561
return fmt.Errorf("error migrating privacy mapper store: %w",
526562
err)
@@ -549,8 +585,8 @@ func migratePrivacyMapperDBToSQL(ctx context.Context, kvStore *bbolt.DB,
549585
}
550586

551587
// collectPrivacyPairs collects all privacy pairs from the KV store.
552-
func collectPrivacyPairs(ctx context.Context, kvStore *bbolt.DB,
553-
sqlTx SQLQueries) (privacyPairs, error) {
588+
func collectPrivacyPairs(kvStore *bbolt.DB,
589+
sessMap map[[4]byte]sqlc.Session) (privacyPairs, error) {
554590

555591
groupPairs := make(privacyPairs)
556592

@@ -576,24 +612,39 @@ func collectPrivacyPairs(ctx context.Context, kvStore *bbolt.DB,
576612
"%s not found", groupId)
577613
}
578614

579-
groupSqlId, err := sqlTx.GetSessionIDByAlias(
580-
ctx, groupId,
581-
)
582-
if errors.Is(err, sql.ErrNoRows) {
583-
return fmt.Errorf("session with group id %x "+
584-
"not found in sql db", groupId)
585-
} else if err != nil {
586-
return err
615+
var groupAlias [4]byte
616+
copy(groupAlias[:], groupId)
617+
618+
sess, ok := sessMap[groupAlias]
619+
if !ok {
620+
// If we can't find the session group in the SQL
621+
// db, that indicates that the session was never
622+
// migrated from KVDB. This likely means that
623+
// the user deleted their session.db file, but
624+
// kept the rules.db file. As the privacy pairs
625+
// are useless when the session no longer
626+
// exists, we can just skip the migration of the
627+
// privacy pairs for this group.
628+
log.Warnf("Skipping migration of privacy "+
629+
"pairs for session group %x, as the "+
630+
"session group was not found", groupId)
631+
632+
return nil
633+
}
634+
635+
if !sess.GroupID.Valid {
636+
return fmt.Errorf("session group id for "+
637+
"session %d is not set ", sess.ID)
587638
}
588639

589640
groupRealToPseudoPairs, err := collectGroupPairs(gBkt)
590641
if err != nil {
591642
return fmt.Errorf("processing group bkt "+
592643
"for group id %s (sqlID %d) failed: %w",
593-
groupId, groupSqlId, err)
644+
groupId, sess.GroupID.Int64, err)
594645
}
595646

596-
groupPairs[groupSqlId] = groupRealToPseudoPairs
647+
groupPairs[sess.GroupID.Int64] = groupRealToPseudoPairs
597648

598649
return nil
599650
})
@@ -794,7 +845,8 @@ func validateGroupPairsMigration(ctx context.Context, sqlTx SQLQueries,
794845
// values match the original values in the actions store.
795846
func migrateActionsToSQL(ctx context.Context, kvStore *bbolt.DB,
796847
sqlTx SQLQueries, sessionDB session.SQLQueries,
797-
accountsDB accounts.SQLQueries, macRootKeyIDs [][]byte) error {
848+
accountsDB accounts.SQLQueries, macRootKeyIDs [][]byte,
849+
sessMap map[[4]byte]sqlc.Session) error {
798850

799851
log.Infof("Starting migration of the actions store to SQL")
800852

@@ -811,16 +863,6 @@ func migrateActionsToSQL(ctx context.Context, kvStore *bbolt.DB,
811863
return fmt.Errorf("mapping accounts failed: %w", err)
812864
}
813865

814-
sessions, err := sessionDB.ListSessions(ctx)
815-
if err != nil {
816-
return fmt.Errorf("listing sessions failed: %w", err)
817-
}
818-
819-
sessionMap, err := mapSessions(sessions)
820-
if err != nil {
821-
return fmt.Errorf("mapping sessions failed: %w", err)
822-
}
823-
824866
// Next, as the kvdb actions only have their last 4 bytes set for the
825867
// MacaroonRootKeyID field, we'll do a best effort attempt fetch the
826868
// full root key ID (all 8 bytes) from lnd when migrating each action.
@@ -927,8 +969,7 @@ func migrateActionsToSQL(ctx context.Context, kvStore *bbolt.DB,
927969
// migrated.
928970
err = migrateActionToSQL(
929971
ctx, sqlTx, sessionDB, accountsDB,
930-
acctsMap, sessionMap, action,
931-
macRootKeyID,
972+
acctsMap, sessMap, action, macRootKeyID,
932973
)
933974
if err != nil {
934975
return fmt.Errorf("migrating action "+

0 commit comments

Comments
 (0)