From d10f9b123d2e72f58f7ca40de9886ff25391032f Mon Sep 17 00:00:00 2001 From: Gabe Villalobos Date: Mon, 17 Jul 2023 12:19:48 -0700 Subject: [PATCH 1/3] test(hybrid-cloud): Marks sentry app installation test as stable --- .../test_organization_sentry_app_installation_details.py | 2 +- tests/sentry/deletions/test_sentry_app_installations.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/sentry/api/endpoints/test_organization_sentry_app_installation_details.py b/tests/sentry/api/endpoints/test_organization_sentry_app_installation_details.py index 6d41893f98d7a6..b576527a938cb8 100644 --- a/tests/sentry/api/endpoints/test_organization_sentry_app_installation_details.py +++ b/tests/sentry/api/endpoints/test_organization_sentry_app_installation_details.py @@ -56,7 +56,7 @@ def setUp(self): ) -@control_silo_test() +@control_silo_test(stable=True) class GetSentryAppInstallationDetailsTest(SentryAppInstallationDetailsTest): def test_access_within_installs_organization(self): self.login_as(user=self.user) diff --git a/tests/sentry/deletions/test_sentry_app_installations.py b/tests/sentry/deletions/test_sentry_app_installations.py index 47893107bbfab3..5a4465cbadf8f3 100644 --- a/tests/sentry/deletions/test_sentry_app_installations.py +++ b/tests/sentry/deletions/test_sentry_app_installations.py @@ -16,7 +16,7 @@ from sentry.testutils.outbox import outbox_runner -class TestSentryAppIntallationDeletionTask(TestCase): +class TestSentryAppInstallationDeletionTask(TestCase): def setUp(self): self.user = self.create_user() self.org = self.create_organization() From 53965bca8afd5842f346b869ff5ba2dd85b5f5f2 Mon Sep 17 00:00:00 2001 From: Gabe Villalobos Date: Mon, 17 Jul 2023 13:28:38 -0700 Subject: [PATCH 2/3] Fixes unguarded write decorator routing for org member --- src/sentry/services/hybrid_cloud/organization/impl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sentry/services/hybrid_cloud/organization/impl.py b/src/sentry/services/hybrid_cloud/organization/impl.py index bb451a9017e956..091d99337ee3c6 100644 --- a/src/sentry/services/hybrid_cloud/organization/impl.py +++ b/src/sentry/services/hybrid_cloud/organization/impl.py @@ -2,7 +2,7 @@ from typing import Any, Iterable, List, Mapping, Optional, Set, Union, cast -from django.db import IntegrityError, models, transaction +from django.db import IntegrityError, models, router, transaction from django.dispatch import Signal from sentry import roles @@ -491,7 +491,7 @@ def update_region_user(self, *, user: RpcRegionUser, region_name: str) -> None: # Normally, calling update on a QS for organization member fails because we need to ensure that updates to # OrganizationMember objects produces outboxes. In this case, it is safe to do the update directly because # the attribute we are changing never needs to produce an outbox. - with unguarded_write(): + with unguarded_write(using=router.db_for_write(OrganizationMember)): OrganizationMember.objects.filter(user_id=user.id).update( user_is_active=user.is_active, user_email=user.email ) From 1f8a6446b0efb54fcbf25d3ed6e2dd115325d49d Mon Sep 17 00:00:00 2001 From: Gabe Villalobos Date: Mon, 17 Jul 2023 13:34:37 -0700 Subject: [PATCH 3/3] Adds transaction routing for user, organization member modifications --- src/sentry/models/organizationmember.py | 4 ++-- src/sentry/models/user.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sentry/models/organizationmember.py b/src/sentry/models/organizationmember.py index c67bcd6d5c0df5..86c8761bd7a0b1 100644 --- a/src/sentry/models/organizationmember.py +++ b/src/sentry/models/organizationmember.py @@ -251,7 +251,7 @@ class Meta: __org_roles_from_teams = None def delete(self, *args, **kwds): - with outbox_context(transaction.atomic()): + with outbox_context(transaction.atomic(using=router.db_for_write(OrganizationMember))): self.save_outbox_for_update() return super().delete(*args, **kwds) @@ -587,7 +587,7 @@ def approve_member_invitation( from sentry import audit_log from sentry.utils.audit import create_audit_entry_from_user - with transaction.atomic(): + with transaction.atomic(using=router.db_for_write(OrganizationMember)): self.approve_invite() self.save() diff --git a/src/sentry/models/user.py b/src/sentry/models/user.py index 6394bbdf958342..e3736974c9629f 100644 --- a/src/sentry/models/user.py +++ b/src/sentry/models/user.py @@ -5,7 +5,7 @@ from django.contrib.auth.models import AbstractBaseUser from django.contrib.auth.models import UserManager as DjangoUserManager from django.contrib.auth.signals import user_logged_out -from django.db import IntegrityError, models, transaction +from django.db import IntegrityError, models, router, transaction from django.db.models import Count, Subquery from django.db.models.query import QuerySet from django.dispatch import receiver @@ -162,7 +162,7 @@ def class_name(self): def delete(self): if self.username == "sentry": raise Exception('You cannot delete the "sentry" user as it is required by Sentry.') - with outbox_context(transaction.atomic(), flush=False): + with outbox_context(transaction.atomic(using=router.db_for_write(User)), flush=False): avatar = self.avatar.first() if avatar: avatar.delete() @@ -171,13 +171,13 @@ def delete(self): return super().delete() def update(self, *args, **kwds): - with outbox_context(transaction.atomic(), flush=False): + with outbox_context(transaction.atomic(using=router.db_for_write(User)), flush=False): for outbox in self.outboxes_for_update(): outbox.save() return super().update(*args, **kwds) def save(self, *args, **kwargs): - with outbox_context(transaction.atomic(), flush=False): + with outbox_context(transaction.atomic(using=router.db_for_write(User)), flush=False): if not self.username: self.username = self.email result = super().save(*args, **kwargs) @@ -323,7 +323,7 @@ def merge_to(from_user, to_user): for model in model_list: for obj in model.objects.filter(user_id=from_user.id): try: - with transaction.atomic(): + with transaction.atomic(using=router.db_for_write(User)): obj.update(user_id=to_user.id) except IntegrityError: pass