Skip to content

[sql-44] firewalldb: add migration code for privacy mapper from kvdb to SQL #1092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: kvstores-migration-PR
Choose a base branch
from

Conversation

ViktorTigerstrom
Copy link
Contributor

@ViktorTigerstrom ViktorTigerstrom commented Jun 17, 2025

Based on the branch of #1079, to only show the relevant commits.

This PR introduces the migration logic for transitioning the privacy mapper from kvdb to SQL.

Note that as of this PR, the migration is not yet triggered by any production code, i.e. only tests execute the migration logic.

I will rebase this on the new version of #1079, once the current feedback has been addressed after we agree on the approach there.

As this PR is heavily dependent on #1079, this is blocked on the dependent PR until it has been merged. This is therefore not ready for review.

Part of #917

@ViktorTigerstrom ViktorTigerstrom added the no-changelog This PR is does not require a release notes entry label Jun 17, 2025
@ViktorTigerstrom ViktorTigerstrom self-assigned this Jun 17, 2025
@ellemouton
Copy link
Member

ellemouton commented Jun 18, 2025

@ViktorTigerstrom - feel free to push a base branch to upstream & then target that so that this pr can just contain the commits that are relevant

As the firewalldb migration will include more than just the migration
of the kvstore data, we rename the migration tests that only migrate
the kvstore data to make it clearer which tests only focus on migrating
kv entries.
Currently, the migration tests for firewalldb only migrates the kv
stores. In future commits, we will also migrate the privacy mapper
and the actions in the firewalldb,. Before this commit, the expected
results of the migrations tests could only be kv records, which will not
be the case when we also migrate the privacy mapper and the actions.

Therefore, we prepare the migration tests to expect more than just kv
records. This commit introduces a new type of `expectedResult` type
which the prep of the migration tests will use, which can specify more
than just one type of expected result.
This commit introduces the migration logic for transitioning the
privacy mapper store from kvdb to SQL.

Note that as of this commit, the migration is not yet triggered by any
production code, i.e. only tests execute the migration logic.
@ViktorTigerstrom ViktorTigerstrom force-pushed the 2025-06-migrate-privacy-mapper branch from bbe2b90 to 9715313 Compare July 11, 2025 22:45
@ViktorTigerstrom
Copy link
Contributor Author

Rebased this on the latest version of #1079, as that PR feels good to go, and this PR is therefore close to not being blocked by that PR (and therefore ready to review).

@ViktorTigerstrom ViktorTigerstrom changed the base branch from master to kvstores-migration-PR July 11, 2025 22:50
@ViktorTigerstrom
Copy link
Contributor Author

Requested a review by both of you @ellemouton & @bitromortac, even though #1079 isn't merged yet, just so you know that it is ready for review once that's been merged.

Copy link
Member

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really really great work. Very clean 🔥

@@ -34,6 +34,11 @@ var (
testEntryValue = []byte{1, 2, 3}
)

// expectedResult represents the expected result of a migration test.
type expectedResult struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nice 🙏

Comment on lines +509 to +517
privPairs, err := collectPrivacyPairs(ctx, kvStore, sqlTx)
if err != nil {
return fmt.Errorf("error migrating privacy mapper store: %w",
err)
}

// 2) Insert all collected privacy pairs into the SQL database.
err = insertPrivacyPairs(ctx, sqlTx, privPairs)
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may want to tests the performance of this one as i think unlike the kv-store db, this one could be quite populated.

So for this one it might make sense to migrate on the fly instead of collecting everything in memory first.

Comment on lines +686 to +719
_, err := sqlTx.GetPseudoForReal(
ctx, sqlc.GetPseudoForRealParams{
GroupID: groupID,
RealVal: realVal,
},
)
if err == nil {
return fmt.Errorf("duplicate privacy pair %s:%s: %w",
realVal, pseudoVal, ErrDuplicatePseudoValue)
} else if !errors.Is(err, sql.ErrNoRows) {
return err
}

_, err = sqlTx.GetRealForPseudo(
ctx, sqlc.GetRealForPseudoParams{
GroupID: groupID,
PseudoVal: pseudoVal,
},
)
if err == nil {
return fmt.Errorf("duplicate privacy pair %s:%s: %w",
realVal, pseudoVal, ErrDuplicatePseudoValue)
} else if !errors.Is(err, sql.ErrNoRows) {
return err
}

err = sqlTx.InsertPrivacyPair(
ctx, sqlc.InsertPrivacyPairParams{
GroupID: groupID,
RealVal: realVal,
PseudoVal: pseudoVal,
},
)
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we not potentially do this in one go with a single query that has a conflict rule?

Comment on lines +604 to +605
if realBkt := bkt.Bucket(realToPseudoKey); realBkt != nil {
realToPseudoRes, err = collectPairs(realBkt)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just checking: do we have a test somewhere that makes sure that things dont fail on an empty kvdb?

Comment on lines 735 to 737
kvEntries: fn.Some(insertedEntries),
// No privacy pairs are inserted in this test.
privPairs: fn.None[privacyPairs](),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should have a test that includes both

Copy link
Contributor

@bitromortac bitromortac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Only have a couple of nits 🚀

@@ -34,6 +34,11 @@ var (
testEntryValue = []byte{1, 2, 3}
)

// expectedResult represents the expected result of a migration test.
type expectedResult struct {
kvEntries fn.Option[[]*kvEntry]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it necessary to have an option type here, as an empty []*kvEntry already signals that, not? (also for the pair data)

@@ -213,6 +218,20 @@ func TestFirewallDBMigration(t *testing.T) {
}
}

// The assertMigrationResults function will currently assert that
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd rather not put comments of what will happen in the future, because it may add confusion for somebody who's not involved in the process and it also may never happen, or we forget to update the comment

@@ -87,10 +92,14 @@ func MigrateFirewallDBToSQL(ctx context.Context, kvStore *bbolt.DB,
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Note that this migration currently only migrates the kvstores, but will be
// extended in the future to also migrate the privacy mapper and action stores.

this is also an example of a "future" comment, where the comment wasn't updated

}

// collectPrivacyPairs collects all privacy pairs from the KV store and
// returns them as the privacyPairs type alias.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitty: and returns them as the privacyPairs type alias. I'd leave that away, as it's obvious from the function signature

Comment on lines +686 to +710
_, err := sqlTx.GetPseudoForReal(
ctx, sqlc.GetPseudoForRealParams{
GroupID: groupID,
RealVal: realVal,
},
)
if err == nil {
return fmt.Errorf("duplicate privacy pair %s:%s: %w",
realVal, pseudoVal, ErrDuplicatePseudoValue)
} else if !errors.Is(err, sql.ErrNoRows) {
return err
}

_, err = sqlTx.GetRealForPseudo(
ctx, sqlc.GetRealForPseudoParams{
GroupID: groupID,
PseudoVal: pseudoVal,
},
)
if err == nil {
return fmt.Errorf("duplicate privacy pair %s:%s: %w",
realVal, pseudoVal, ErrDuplicatePseudoValue)
} else if !errors.Is(err, sql.ErrNoRows) {
return err
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are those checks necessary as they look to be covered by collectGroupPairs?


// multiSessionsOnePrivPairs inserts 1 session with 1 privacy pair into the
// boltDB.
func oneSessionAndPrivPair(t *testing.T, ctx context.Context,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we could use createPrivacyPairs directly

Comment on lines +794 to +795
realKey := fmt.Sprintf("real-%d-%d", i, j)
pseudoKey := fmt.Sprintf("pseudo-%d-%d", i, j)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it add anything if we'd let real/pseudo keys be the same for the sessions, to leave i away?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-changelog This PR is does not require a release notes entry
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants