Skip to content

Commit eb80be8

Browse files
committed
firewalldb: handle deleted sessions in kv stores mig
If the user has deleted their session.db file, but kept their rules.db file, there can exist kv entry values that point to a now deleted session ID. Such kv entries should be ignored during the migration, as they are cannot be used anymore. This commit updates the migration to handle this case.
1 parent f456016 commit eb80be8

File tree

2 files changed

+93
-5
lines changed

2 files changed

+93
-5
lines changed

firewalldb/sql_migration.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func migrateKVStoresDBToSQL(ctx context.Context, kvStore *bbolt.DB,
139139
// 1) Collect all key-value pairs from the KV store.
140140
err := kvStore.View(func(tx *bbolt.Tx) error {
141141
var err error
142-
pairs, err = collectAllPairs(tx)
142+
pairs, err = collectAllPairs(sessMap, tx)
143143
return err
144144
})
145145
if err != nil {
@@ -198,7 +198,9 @@ func migrateKVStoresDBToSQL(ctx context.Context, kvStore *bbolt.DB,
198198
// designed to iterate over all buckets and values that exist in the KV store.
199199
// That ensures that we find all stores and values that exist in the KV store,
200200
// and can be sure that the kv store actually follows the expected structure.
201-
func collectAllPairs(tx *bbolt.Tx) ([]*kvEntry, error) {
201+
func collectAllPairs(sessMap map[[4]byte]sqlc.Session,
202+
tx *bbolt.Tx) ([]*kvEntry, error) {
203+
202204
var entries []*kvEntry
203205
for _, perm := range []bool{true, false} {
204206
mainBucket, err := getMainBucket(tx, false, perm)
@@ -228,7 +230,7 @@ func collectAllPairs(tx *bbolt.Tx) ([]*kvEntry, error) {
228230
}
229231

230232
pairs, err := collectRulePairs(
231-
ruleBucket, perm, string(rule),
233+
sessMap, ruleBucket, perm, string(rule),
232234
)
233235
if err != nil {
234236
return err
@@ -248,8 +250,8 @@ func collectAllPairs(tx *bbolt.Tx) ([]*kvEntry, error) {
248250

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

254256
var params []*kvEntry
255257

@@ -281,6 +283,25 @@ func collectRulePairs(bkt *bbolt.Bucket, perm bool, rule string) ([]*kvEntry,
281283
"under %s bucket", sessKVStoreBucketKey)
282284
}
283285

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+
284305
groupBucket := sessBkt.Bucket(groupAlias)
285306
if groupBucket == nil {
286307
return fmt.Errorf("group bucket for group "+
@@ -413,6 +434,9 @@ func insertPair(ctx context.Context, tx SQLQueries,
413434

414435
sess, ok := sessMap[groupAlias]
415436
if !ok {
437+
// This should be unreachable, as we check for the
438+
// existence of the session group when collecting
439+
// the kv pairs.
416440
err = fmt.Errorf("session group %x not found in map",
417441
alias)
418442
}

firewalldb/sql_migration_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,10 +418,18 @@ func TestFirewallDBMigration(t *testing.T) {
418418
name: "session specific kv entries",
419419
populateDB: sessionSpecificEntries,
420420
},
421+
{
422+
name: "session specific kv entries deleted session",
423+
populateDB: sessionSpecificEntriesDeletedSession,
424+
},
421425
{
422426
name: "feature specific kv entries",
423427
populateDB: featureSpecificEntries,
424428
},
429+
{
430+
name: "feature specific kv entries deleted session",
431+
populateDB: featureSpecificEntriesDeletedSession,
432+
},
425433
{
426434
name: "all kv entry combinations",
427435
populateDB: allEntryCombinations,
@@ -585,6 +593,34 @@ func sessionSpecificEntries(t *testing.T, ctx context.Context, boltDB *BoltDB,
585593
)
586594
}
587595

596+
// sessionSpecificEntriesDeletedSession populates the kv store with one session
597+
// specific entry for the local temp store, and one session specific entry for
598+
// the perm local store. Once populated, the session that the entries are linked
599+
// to is deleted. When migrating, we therefore expect that the kv entries linked
600+
// to the deleted session are not migrated.
601+
func sessionSpecificEntriesDeletedSession(t *testing.T, ctx context.Context,
602+
boltDB *BoltDB, sessionStore session.Store, _ accounts.Store,
603+
_ *rootKeyMockStore) *expectedResult {
604+
605+
groupAlias := getNewSessionAlias(t, ctx, sessionStore)
606+
607+
_ = insertTempAndPermEntry(
608+
t, ctx, boltDB, testRuleName, groupAlias, fn.None[string](),
609+
testEntryKey, testEntryValue,
610+
)
611+
612+
err := sessionStore.DeleteReservedSessions(ctx)
613+
require.NoError(t, err)
614+
615+
return &expectedResult{
616+
// Since the session the kx entries were linked to has been
617+
// deleted, we expect no kv entries to be migrated.
618+
kvEntries: []*kvEntry{},
619+
privPairs: make(privacyPairs),
620+
actions: []*Action{},
621+
}
622+
}
623+
588624
// featureSpecificEntries populates the kv store with one feature specific
589625
// entry for the local temp store, and one feature specific entry for the perm
590626
// local store.
@@ -600,6 +636,34 @@ func featureSpecificEntries(t *testing.T, ctx context.Context, boltDB *BoltDB,
600636
)
601637
}
602638

639+
// featureSpecificEntriesDeletedSession populates the kv store with one feature
640+
// specific entry for the local temp store, and one feature specific entry for
641+
// the perm local store. Once populated, the session that the entries are linked
642+
// to is deleted. When migrating, we therefore expect that the kv entries linked
643+
// to the deleted session are not migrated.
644+
func featureSpecificEntriesDeletedSession(t *testing.T, ctx context.Context,
645+
boltDB *BoltDB, sessionStore session.Store, _ accounts.Store,
646+
_ *rootKeyMockStore) *expectedResult {
647+
648+
groupAlias := getNewSessionAlias(t, ctx, sessionStore)
649+
650+
_ = insertTempAndPermEntry(
651+
t, ctx, boltDB, testRuleName, groupAlias,
652+
fn.Some(testFeatureName), testEntryKey, testEntryValue,
653+
)
654+
655+
err := sessionStore.DeleteReservedSessions(ctx)
656+
require.NoError(t, err)
657+
658+
return &expectedResult{
659+
// Since the session the kv entries were linked to has been
660+
// deleted, we expect no kv entries to be migrated.
661+
kvEntries: []*kvEntry{},
662+
privPairs: make(privacyPairs),
663+
actions: []*Action{},
664+
}
665+
}
666+
603667
// allEntryCombinations adds all types of different entries at all possible
604668
// levels of the kvstores, including multple entries with the same
605669
// ruleName, groupAlias and featureName. The test aims to cover all possible

0 commit comments

Comments
 (0)