From b52a22e1e4611569c8d899f944cb4e12d22f6643 Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Tue, 4 Jun 2024 09:33:44 -0500 Subject: [PATCH 01/10] resolve migration lockfile merge conflict --- migrations_lockfile.txt | 2 +- .../0726_apitoken_backfill_hashes.py | 58 +++++++++++++++++++ .../test_0726_apitoken_backfill_hashes.py | 19 ++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/sentry/migrations/0726_apitoken_backfill_hashes.py create mode 100644 tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py diff --git a/migrations_lockfile.txt b/migrations_lockfile.txt index 6b8c4544f1a014..2e9909274337e6 100644 --- a/migrations_lockfile.txt +++ b/migrations_lockfile.txt @@ -9,5 +9,5 @@ feedback: 0004_index_together hybridcloud: 0016_add_control_cacheversion nodestore: 0002_nodestore_no_dictfield replays: 0004_index_together -sentry: 0725_create_sentry_groupsearchview_table +sentry: 0726_apitoken_backfill_hashes social_auth: 0002_default_auto_field diff --git a/src/sentry/migrations/0726_apitoken_backfill_hashes.py b/src/sentry/migrations/0726_apitoken_backfill_hashes.py new file mode 100644 index 00000000000000..ecfcaec85e6267 --- /dev/null +++ b/src/sentry/migrations/0726_apitoken_backfill_hashes.py @@ -0,0 +1,58 @@ +# Generated by Django 5.0.6 on 2024-05-29 21:28 + +import hashlib + +from django.db import migrations +from django.db.backends.base.schema import BaseDatabaseSchemaEditor +from django.db.migrations.state import StateApps + +from sentry.new_migrations.migrations import CheckedMigration + + +def backfill_hash_values(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: + ApiToken = apps.get_model("sentry", "ApiToken") + + for api_token in ApiToken.objects.all(): + if not api_token.hashed_token: + hashed_token = hashlib.sha256(api_token.token.encode()).hexdigest() + + # if there's a refresh token make sure it is hashed as well + hashed_refresh_token = None + if api_token.refresh_token: + hashed_refresh_token = hashlib.sha256(api_token.refresh_token.encode()).hexdigest() + + api_token.hashed_token = hashed_token + api_token.hashed_refresh_token = hashed_refresh_token + api_token.save(update_fields=["hashed_token", "hashed_refresh_token"]) + + +class Migration(CheckedMigration): + # This flag is used to mark that a migration shouldn't be automatically run in production. + # This should only be used for operations where it's safe to run the migration after your + # code has deployed. So this should not be used for most operations that alter the schema + # of a table. + # Here are some things that make sense to mark as post deployment: + # - Large data migrations. Typically we want these to be run manually so that they can be + # monitored and not block the deploy for a long period of time while they run. + # - Adding indexes to large tables. Since this can take a long time, we'd generally prefer to + # run this outside deployments so that we don't block them. Note that while adding an index + # is a schema change, it's completely safe to run the operation after the code has deployed. + # Once deployed, run these manually via: https://develop.sentry.dev/database-migrations/#migration-deployment + + is_post_deployment = True + + dependencies = [ + ("sentry", "0725_create_sentry_groupsearchview_table"), + ] + + operations = [ + migrations.RunPython( + backfill_hash_values, + migrations.RunPython.noop, + hints={ + "tables": [ + "sentry_apitoken", + ] + }, + ) + ] diff --git a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py new file mode 100644 index 00000000000000..c0f43620fb9b64 --- /dev/null +++ b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py @@ -0,0 +1,19 @@ +from sentry.testutils.cases import TestMigrations +from sentry.testutils.helpers import override_options + + +class TestBackfillApiTokenHashesMigration(TestMigrations): + migrate_from = "0725_create_sentry_groupsearchview_table" + migrate_to = "0726_apitoken_backfill_hashes" + connection = "control" + + @override_options({"apitoken.save-hash-on-create": False}) + def setup_initial_state(self): + self.user_1 = self.create_user() + self.user_1_auth_token = self.create_user_auth_token(user=self.user_1) + + assert self.user_1_auth_token.hashed_token is None + + def test(self): + self.user_1_auth_token.refresh_from_db() + assert self.user_1_auth_token.hashed_token From 3f8c25a2242f2d0d26e8143a0132ab58682d75d8 Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Wed, 29 May 2024 17:57:48 -0500 Subject: [PATCH 02/10] fix merge conflicts --- src/sentry/migrations/0726_apitoken_backfill_hashes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/migrations/0726_apitoken_backfill_hashes.py b/src/sentry/migrations/0726_apitoken_backfill_hashes.py index ecfcaec85e6267..91481fadc399a7 100644 --- a/src/sentry/migrations/0726_apitoken_backfill_hashes.py +++ b/src/sentry/migrations/0726_apitoken_backfill_hashes.py @@ -13,7 +13,7 @@ def backfill_hash_values(apps: StateApps, schema_editor: BaseDatabaseSchemaEdito ApiToken = apps.get_model("sentry", "ApiToken") for api_token in ApiToken.objects.all(): - if not api_token.hashed_token: + if api_token.hashed_token is None: hashed_token = hashlib.sha256(api_token.token.encode()).hexdigest() # if there's a refresh token make sure it is hashed as well From 0a82f8e8fcfdb61e0f845216fcf146523a1365c6 Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Thu, 30 May 2024 14:00:58 -0500 Subject: [PATCH 03/10] fix migration test --- .../migrations/0726_apitoken_backfill_hashes.py | 8 ++++---- .../migrations/test_0726_apitoken_backfill_hashes.py | 11 +++++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/sentry/migrations/0726_apitoken_backfill_hashes.py b/src/sentry/migrations/0726_apitoken_backfill_hashes.py index 91481fadc399a7..a616bb5dfcb95e 100644 --- a/src/sentry/migrations/0726_apitoken_backfill_hashes.py +++ b/src/sentry/migrations/0726_apitoken_backfill_hashes.py @@ -16,10 +16,10 @@ def backfill_hash_values(apps: StateApps, schema_editor: BaseDatabaseSchemaEdito if api_token.hashed_token is None: hashed_token = hashlib.sha256(api_token.token.encode()).hexdigest() - # if there's a refresh token make sure it is hashed as well - hashed_refresh_token = None - if api_token.refresh_token: - hashed_refresh_token = hashlib.sha256(api_token.refresh_token.encode()).hexdigest() + # if there's a refresh token make sure it is hashed as well + hashed_refresh_token = None + if api_token.refresh_token: + hashed_refresh_token = hashlib.sha256(api_token.refresh_token.encode()).hexdigest() api_token.hashed_token = hashed_token api_token.hashed_refresh_token = hashed_refresh_token diff --git a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py index c0f43620fb9b64..e47293c4a4e482 100644 --- a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py +++ b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py @@ -1,5 +1,7 @@ +from sentry.silo.base import SiloMode from sentry.testutils.cases import TestMigrations from sentry.testutils.helpers import override_options +from sentry.testutils.silo import assume_test_silo_mode class TestBackfillApiTokenHashesMigration(TestMigrations): @@ -15,5 +17,10 @@ def setup_initial_state(self): assert self.user_1_auth_token.hashed_token is None def test(self): - self.user_1_auth_token.refresh_from_db() - assert self.user_1_auth_token.hashed_token + + with assume_test_silo_mode(SiloMode.CONTROL): + from sentry.models.apitoken import ApiToken + + api_tokens = ApiToken.objects.all() + for api_token in api_tokens: + assert api_token.hashed_token is not None From 44bb3b572a393e493e709a115bc34c62138ea341 Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Tue, 4 Jun 2024 09:36:00 -0500 Subject: [PATCH 04/10] resolve migration lockfile merge conflict --- .../migrations/test_0726_apitoken_backfill_hashes.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py index e47293c4a4e482..e4b95c27249047 100644 --- a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py +++ b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py @@ -1,7 +1,5 @@ -from sentry.silo.base import SiloMode from sentry.testutils.cases import TestMigrations from sentry.testutils.helpers import override_options -from sentry.testutils.silo import assume_test_silo_mode class TestBackfillApiTokenHashesMigration(TestMigrations): @@ -17,10 +15,5 @@ def setup_initial_state(self): assert self.user_1_auth_token.hashed_token is None def test(self): - - with assume_test_silo_mode(SiloMode.CONTROL): - from sentry.models.apitoken import ApiToken - - api_tokens = ApiToken.objects.all() - for api_token in api_tokens: - assert api_token.hashed_token is not None + self.user_1_auth_token.refresh_from_db() + assert self.user_1_auth_token.hashed_token is not None From fd02ccebe5b239c318feff915c1b6b801ee96e3a Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Fri, 31 May 2024 15:15:54 -0500 Subject: [PATCH 05/10] use control_silo_test --- .../migrations/0726_apitoken_backfill_hashes.py | 6 +++--- .../migrations/test_0726_apitoken_backfill_hashes.py | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/sentry/migrations/0726_apitoken_backfill_hashes.py b/src/sentry/migrations/0726_apitoken_backfill_hashes.py index a616bb5dfcb95e..ae2276c41ee465 100644 --- a/src/sentry/migrations/0726_apitoken_backfill_hashes.py +++ b/src/sentry/migrations/0726_apitoken_backfill_hashes.py @@ -21,9 +21,9 @@ def backfill_hash_values(apps: StateApps, schema_editor: BaseDatabaseSchemaEdito if api_token.refresh_token: hashed_refresh_token = hashlib.sha256(api_token.refresh_token.encode()).hexdigest() - api_token.hashed_token = hashed_token - api_token.hashed_refresh_token = hashed_refresh_token - api_token.save(update_fields=["hashed_token", "hashed_refresh_token"]) + api_token.hashed_token = hashed_token + api_token.hashed_refresh_token = hashed_refresh_token + api_token.save(update_fields=["hashed_token", "hashed_refresh_token"]) class Migration(CheckedMigration): diff --git a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py index e4b95c27249047..4a061e57af7ef4 100644 --- a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py +++ b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py @@ -1,7 +1,10 @@ from sentry.testutils.cases import TestMigrations from sentry.testutils.helpers import override_options +from sentry.testutils.outbox import outbox_runner +from sentry.testutils.silo import control_silo_test +@control_silo_test class TestBackfillApiTokenHashesMigration(TestMigrations): migrate_from = "0725_create_sentry_groupsearchview_table" migrate_to = "0726_apitoken_backfill_hashes" @@ -9,11 +12,12 @@ class TestBackfillApiTokenHashesMigration(TestMigrations): @override_options({"apitoken.save-hash-on-create": False}) def setup_initial_state(self): - self.user_1 = self.create_user() - self.user_1_auth_token = self.create_user_auth_token(user=self.user_1) + with outbox_runner(): + self.user_1 = self.create_user() + self.user_1_auth_token = self.create_user_auth_token(user=self.user_1) - assert self.user_1_auth_token.hashed_token is None + assert self.user_1_auth_token.hashed_token is None - def test(self): + def test_for_hashed_value(self): self.user_1_auth_token.refresh_from_db() assert self.user_1_auth_token.hashed_token is not None From 37ecafc8fa51dfda7c70878a20009befc87f19b0 Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Fri, 31 May 2024 17:39:40 -0500 Subject: [PATCH 06/10] explicit outbox control in migration --- .../0726_apitoken_backfill_hashes.py | 32 ++++++++++++++++--- .../test_0726_apitoken_backfill_hashes.py | 18 ++++++++--- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/sentry/migrations/0726_apitoken_backfill_hashes.py b/src/sentry/migrations/0726_apitoken_backfill_hashes.py index ae2276c41ee465..c74efc935c5995 100644 --- a/src/sentry/migrations/0726_apitoken_backfill_hashes.py +++ b/src/sentry/migrations/0726_apitoken_backfill_hashes.py @@ -1,29 +1,53 @@ # Generated by Django 5.0.6 on 2024-05-29 21:28 import hashlib +import logging -from django.db import migrations +from django.db import migrations, router from django.db.backends.base.schema import BaseDatabaseSchemaEditor from django.db.migrations.state import StateApps from sentry.new_migrations.migrations import CheckedMigration +logger = logging.getLogger(__name__) + def backfill_hash_values(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: ApiToken = apps.get_model("sentry", "ApiToken") + ControlOutbox = apps.get_model("sentry", "ControlOutbox") + try: + from sentry.models.outbox import OutboxCategory, OutboxScope + from sentry.silo.safety import unguarded_write + from sentry.types.region import find_regions_for_user + except ImportError: + logger.exception("Cannot execute migration. Required symbols could not be imported") + return for api_token in ApiToken.objects.all(): + hashed_token = None if api_token.hashed_token is None: hashed_token = hashlib.sha256(api_token.token.encode()).hexdigest() + api_token.hashed_token = hashed_token # if there's a refresh token make sure it is hashed as well hashed_refresh_token = None if api_token.refresh_token: hashed_refresh_token = hashlib.sha256(api_token.refresh_token.encode()).hexdigest() + api_token.hashed_refresh_token = hashed_refresh_token - api_token.hashed_token = hashed_token - api_token.hashed_refresh_token = hashed_refresh_token - api_token.save(update_fields=["hashed_token", "hashed_refresh_token"]) + # only save if we've actually had to hash values + if hashed_token or hashed_refresh_token: + with unguarded_write(using=router.db_for_write(ApiToken)): + api_token.save(update_fields=["hashed_token", "hashed_refresh_token"]) + user_regions = find_regions_for_user(api_token.user_id) + for region in user_regions: + ControlOutbox.objects.create( + shard_scope=OutboxScope.USER_SCOPE, + shard_identifier=api_token.user_id, + category=OutboxCategory.API_TOKEN_UPDATE, + region_name=region, + object_identifier=api_token.id, + ) class Migration(CheckedMigration): diff --git a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py index 4a061e57af7ef4..953a72870f1943 100644 --- a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py +++ b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py @@ -1,6 +1,6 @@ +from sentry.models.outbox import ControlOutbox, OutboxCategory, OutboxScope from sentry.testutils.cases import TestMigrations from sentry.testutils.helpers import override_options -from sentry.testutils.outbox import outbox_runner from sentry.testutils.silo import control_silo_test @@ -12,12 +12,20 @@ class TestBackfillApiTokenHashesMigration(TestMigrations): @override_options({"apitoken.save-hash-on-create": False}) def setup_initial_state(self): - with outbox_runner(): - self.user_1 = self.create_user() - self.user_1_auth_token = self.create_user_auth_token(user=self.user_1) + self.user_1 = self.create_user() + self.user_1_auth_token = self.create_user_auth_token(user=self.user_1) - assert self.user_1_auth_token.hashed_token is None + # Put the user in an org so we have membership + self.create_organization(owner=self.user_1) + + assert self.user_1_auth_token.hashed_token is None def test_for_hashed_value(self): self.user_1_auth_token.refresh_from_db() assert self.user_1_auth_token.hashed_token is not None + assert ControlOutbox.objects.get( + shard_scope=OutboxScope.USER_SCOPE, + category=OutboxCategory.API_TOKEN_UPDATE, + object_identifier=self.user_1_auth_token.id, + shard_identifier=self.user_1_auth_token.user_id, + ) From e42148b5855fba8920805402d6bcea2f8e8e9f3c Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Fri, 31 May 2024 17:55:01 -0500 Subject: [PATCH 07/10] expand test for api application related tokens --- .../test_0726_apitoken_backfill_hashes.py | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py index 953a72870f1943..c67072de6b70cc 100644 --- a/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py +++ b/tests/sentry/migrations/test_0726_apitoken_backfill_hashes.py @@ -12,20 +12,42 @@ class TestBackfillApiTokenHashesMigration(TestMigrations): @override_options({"apitoken.save-hash-on-create": False}) def setup_initial_state(self): - self.user_1 = self.create_user() - self.user_1_auth_token = self.create_user_auth_token(user=self.user_1) + user = self.create_user() + self.user_auth_token = self.create_user_auth_token(user=user) # Put the user in an org so we have membership - self.create_organization(owner=self.user_1) + organization = self.create_organization(owner=user) - assert self.user_1_auth_token.hashed_token is None + app = self.create_sentry_app(user=user, organization_id=organization.id) + self.app_install = self.create_sentry_app_installation( + organization=organization, user=user, slug=app.slug + ) + + assert self.user_auth_token.hashed_token is None + # user auth tokens do not have refresh tokens + assert self.user_auth_token.refresh_token is None + + assert self.app_install.api_token.hashed_token is None + assert self.app_install.api_token.hashed_refresh_token is None + # tokens related to sentry apps do have refresh tokens + assert self.app_install.api_token.refresh_token is not None def test_for_hashed_value(self): - self.user_1_auth_token.refresh_from_db() - assert self.user_1_auth_token.hashed_token is not None + self.user_auth_token.refresh_from_db() + assert self.user_auth_token.hashed_token is not None + assert ControlOutbox.objects.get( + shard_scope=OutboxScope.USER_SCOPE, + category=OutboxCategory.API_TOKEN_UPDATE, + object_identifier=self.user_auth_token.id, + shard_identifier=self.user_auth_token.user_id, + ) + + self.app_install.refresh_from_db() + assert self.app_install.api_token.hashed_token is not None + assert self.app_install.api_token.hashed_refresh_token is not None assert ControlOutbox.objects.get( shard_scope=OutboxScope.USER_SCOPE, category=OutboxCategory.API_TOKEN_UPDATE, - object_identifier=self.user_1_auth_token.id, - shard_identifier=self.user_1_auth_token.user_id, + object_identifier=self.app_install.api_token.id, + shard_identifier=self.app_install.api_token.user_id, ) From 1abcaf23dab1e7836d4c01216a6858a285d78c61 Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Fri, 31 May 2024 18:09:15 -0500 Subject: [PATCH 08/10] use progress bar wrapper --- src/sentry/migrations/0726_apitoken_backfill_hashes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sentry/migrations/0726_apitoken_backfill_hashes.py b/src/sentry/migrations/0726_apitoken_backfill_hashes.py index c74efc935c5995..1aef5c486cb6fe 100644 --- a/src/sentry/migrations/0726_apitoken_backfill_hashes.py +++ b/src/sentry/migrations/0726_apitoken_backfill_hashes.py @@ -8,6 +8,7 @@ from django.db.migrations.state import StateApps from sentry.new_migrations.migrations import CheckedMigration +from sentry.utils.query import RangeQuerySetWrapperWithProgressBar logger = logging.getLogger(__name__) @@ -23,7 +24,7 @@ def backfill_hash_values(apps: StateApps, schema_editor: BaseDatabaseSchemaEdito logger.exception("Cannot execute migration. Required symbols could not be imported") return - for api_token in ApiToken.objects.all(): + for api_token in RangeQuerySetWrapperWithProgressBar(ApiToken.objects.all()): hashed_token = None if api_token.hashed_token is None: hashed_token = hashlib.sha256(api_token.token.encode()).hexdigest() From a5a3ba2b3c71efac7dcc258d670baffb99681f66 Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Tue, 4 Jun 2024 17:20:05 -0500 Subject: [PATCH 09/10] use apps.get_model(..) where possible --- .../0726_apitoken_backfill_hashes.py | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/sentry/migrations/0726_apitoken_backfill_hashes.py b/src/sentry/migrations/0726_apitoken_backfill_hashes.py index 1aef5c486cb6fe..2159d057ae5c09 100644 --- a/src/sentry/migrations/0726_apitoken_backfill_hashes.py +++ b/src/sentry/migrations/0726_apitoken_backfill_hashes.py @@ -16,14 +16,51 @@ def backfill_hash_values(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: ApiToken = apps.get_model("sentry", "ApiToken") ControlOutbox = apps.get_model("sentry", "ControlOutbox") + OrganizationMemberMapping = apps.get_model("sentry", "OrganizationMemberMapping") + OrganizationMapping = apps.get_model("sentry", "OrganizationMapping") + try: + from collections.abc import Container + + from django.conf import settings + from sentry.models.outbox import OutboxCategory, OutboxScope + from sentry.services.hybrid_cloud.util import control_silo_function + from sentry.silo.base import SiloMode from sentry.silo.safety import unguarded_write - from sentry.types.region import find_regions_for_user except ImportError: logger.exception("Cannot execute migration. Required symbols could not be imported") return + @control_silo_function + def _find_orgs_for_user(user_id: int) -> set[int]: + return { + m["organization_id"] + for m in OrganizationMemberMapping.objects.filter(user_id=user_id).values( + "organization_id" + ) + } + + @control_silo_function + def find_regions_for_orgs(org_ids: Container[int]) -> set[str]: + + if SiloMode.get_current_mode() == SiloMode.MONOLITH: + return {settings.SENTRY_MONOLITH_REGION} + else: + return set( + OrganizationMapping.objects.filter(organization_id__in=org_ids).values_list( + "region_name", flat=True + ) + ) + + @control_silo_function + def find_regions_for_user(user_id: int) -> set[str]: + if SiloMode.get_current_mode() == SiloMode.MONOLITH: + return {settings.SENTRY_MONOLITH_REGION} + + org_ids = _find_orgs_for_user(user_id) + return find_regions_for_orgs(org_ids) + for api_token in RangeQuerySetWrapperWithProgressBar(ApiToken.objects.all()): hashed_token = None if api_token.hashed_token is None: From c3f4410f139d2ca4e3956429cfd047dc6a6bfed9 Mon Sep 17 00:00:00 2001 From: mdtro <20070360+mdtro@users.noreply.github.com> Date: Mon, 10 Jun 2024 10:24:45 -0500 Subject: [PATCH 10/10] import additional classes per review suggestion --- .../0726_apitoken_backfill_hashes.py | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/sentry/migrations/0726_apitoken_backfill_hashes.py b/src/sentry/migrations/0726_apitoken_backfill_hashes.py index 2159d057ae5c09..bd4d7234804333 100644 --- a/src/sentry/migrations/0726_apitoken_backfill_hashes.py +++ b/src/sentry/migrations/0726_apitoken_backfill_hashes.py @@ -2,6 +2,7 @@ import hashlib import logging +from enum import IntEnum from django.db import migrations, router from django.db.backends.base.schema import BaseDatabaseSchemaEditor @@ -24,7 +25,6 @@ def backfill_hash_values(apps: StateApps, schema_editor: BaseDatabaseSchemaEdito from django.conf import settings - from sentry.models.outbox import OutboxCategory, OutboxScope from sentry.services.hybrid_cloud.util import control_silo_function from sentry.silo.base import SiloMode from sentry.silo.safety import unguarded_write @@ -32,6 +32,41 @@ def backfill_hash_values(apps: StateApps, schema_editor: BaseDatabaseSchemaEdito logger.exception("Cannot execute migration. Required symbols could not be imported") return + # copied from src/sentry/models/outbox.py + class OutboxCategory(IntEnum): + USER_UPDATE = 0 + UNUSED_TWO = 4 + UNUSUED_THREE = 13 + UNUSED_ONE = 19 + AUTH_IDENTITY_UPDATE = 25 + API_TOKEN_UPDATE = 32 + + # copied from src/sentry/models/outbox.py + _outbox_categories_for_scope: dict[int, set[OutboxCategory]] = {} + _used_categories: set[OutboxCategory] = set() + + # copied from src/sentry/models/outbox.py + def scope_categories(enum_value: int, categories: set[OutboxCategory]) -> int: + _outbox_categories_for_scope[enum_value] = categories + inter = _used_categories.intersection(categories) + assert not inter, f"OutboxCategories {inter} were already registered to a different scope" + _used_categories.update(categories) + return enum_value + + # copied from src/sentry/models/outbox.py + class OutboxScope(IntEnum): + USER_SCOPE = scope_categories( + 1, + { + OutboxCategory.USER_UPDATE, + OutboxCategory.API_TOKEN_UPDATE, + OutboxCategory.UNUSED_ONE, + OutboxCategory.UNUSED_TWO, + OutboxCategory.UNUSUED_THREE, + OutboxCategory.AUTH_IDENTITY_UPDATE, + }, + ) + @control_silo_function def _find_orgs_for_user(user_id: int) -> set[int]: return { @@ -43,7 +78,6 @@ def _find_orgs_for_user(user_id: int) -> set[int]: @control_silo_function def find_regions_for_orgs(org_ids: Container[int]) -> set[str]: - if SiloMode.get_current_mode() == SiloMode.MONOLITH: return {settings.SENTRY_MONOLITH_REGION} else: