diff --git a/src/sentry/api/endpoints/organization_fork.py b/src/sentry/api/endpoints/organization_fork.py index 863a0e98f16f00..4f06dd1abc0df0 100644 --- a/src/sentry/api/endpoints/organization_fork.py +++ b/src/sentry/api/endpoints/organization_fork.py @@ -22,7 +22,7 @@ ) from sentry.relocation.models.relocation import Relocation from sentry.relocation.tasks.process import uploading_start -from sentry.types.cell import get_local_cell +from sentry.types.cell import get_global_directory, get_local_cell from sentry.utils.db import atomic_transaction ERR_DUPLICATE_ORGANIZATION_FORK = Template( @@ -35,12 +35,12 @@ ERR_CANNOT_FORK_INTO_SAME_REGION = Template( "The organization already lives in region `$region`, so it cannot be forked into that region." ) -ERR_CANNOT_FORK_FROM_REGION = Template( - "Forking an organization from region `$region` is forbidden." +ERR_CANNOT_FORK_FROM_LOCALITY = Template( + "Forking an organization from locality `$locality` is forbidden." ) -# For legal reasons, there are certain regions from which forking is disallowed. -CANNOT_FORK_FROM_REGION = {"de"} +# For legal reasons, there are certain localities from which forking is disallowed. +CANNOT_FORK_FROM_LOCALITY = {"de"} logger = logging.getLogger(__name__) @@ -99,23 +99,29 @@ def post(self, request: Request, organization_id_or_slug) -> Response: status=status.HTTP_400_BAD_REQUEST, ) - # Figure out which region the organization being forked lives in. - requesting_region_name = get_local_cell().name - replying_region_name = org_mapping.cell_name - if replying_region_name in CANNOT_FORK_FROM_REGION: + # Figure out which cell the organization being forked lives in. + requesting_cell_name = get_local_cell().name + replying_cell_name = org_mapping.cell_name + + # Resolve the locality for the exporting cell. In environments without locality + # config (e.g. monolith, tests), falls back to the cell name. + replying_locality = get_global_directory().get_locality_for_cell(replying_cell_name) + replying_locality_name = replying_locality.name if replying_locality else replying_cell_name + + if replying_locality_name in CANNOT_FORK_FROM_LOCALITY: return Response( { - "detail": ERR_CANNOT_FORK_FROM_REGION.substitute( - region=replying_region_name, + "detail": ERR_CANNOT_FORK_FROM_LOCALITY.substitute( + locality=replying_locality_name, ) }, status=status.HTTP_403_FORBIDDEN, ) - if replying_region_name == requesting_region_name: + if replying_cell_name == requesting_cell_name: return Response( { "detail": ERR_CANNOT_FORK_INTO_SAME_REGION.substitute( - region=requesting_region_name, + region=requesting_cell_name, ) }, status=status.HTTP_400_BAD_REQUEST, @@ -164,7 +170,7 @@ def post(self, request: Request, organization_id_or_slug) -> Response: # When we received this back (via RPC call), we'll be able to continue with the usual # relocation flow, picking up from the `uploading_complete` task. uploading_start.apply_async( - args=[new_relocation.uuid, replying_region_name, org_mapping.slug] + args=[new_relocation.uuid, replying_cell_name, org_mapping.slug] ) try: @@ -174,8 +180,8 @@ def post(self, request: Request, organization_id_or_slug) -> Response: owner_id=owner.id, uuid=str(new_relocation.uuid), from_org_slug=org_mapping.slug, - requesting_region_name=requesting_region_name, - replying_region_name=replying_region_name, + requesting_region_name=requesting_cell_name, + replying_region_name=replying_cell_name, ) ) except Exception as e: diff --git a/tests/sentry/api/endpoints/test_organization_fork.py b/tests/sentry/api/endpoints/test_organization_fork.py index 4115540715e9d2..a68e3e1de7c0ea 100644 --- a/tests/sentry/api/endpoints/test_organization_fork.py +++ b/tests/sentry/api/endpoints/test_organization_fork.py @@ -3,7 +3,7 @@ from sentry.analytics.events.relocation_forked import RelocationForkedEvent from sentry.api.endpoints.organization_fork import ( - ERR_CANNOT_FORK_FROM_REGION, + ERR_CANNOT_FORK_FROM_LOCALITY, ERR_CANNOT_FORK_INTO_SAME_REGION, ERR_DUPLICATE_ORGANIZATION_FORK, ERR_ORGANIZATION_INACTIVE, @@ -394,7 +394,8 @@ def test_bad_cannot_fork_deleted_organization( @override_options({"relocation.enabled": True, "relocation.daily-limit.small": 1}) @assume_test_silo_mode(SiloMode.CELL, cell_name=REQUESTING_TEST_REGION) @patch( - "sentry.api.endpoints.organization_fork.CANNOT_FORK_FROM_REGION", {EXPORTING_TEST_REGION} + "sentry.api.endpoints.organization_fork.CANNOT_FORK_FROM_LOCALITY", + {EXPORTING_TEST_REGION}, ) def test_bad_organization_in_forbidden_region( self, @@ -408,8 +409,8 @@ def test_bad_organization_in_forbidden_region( response = self.get_error_response(self.existing_org.slug, status_code=403) assert response.data.get("detail") is not None - assert response.data.get("detail") == ERR_CANNOT_FORK_FROM_REGION.substitute( - region=EXPORTING_TEST_REGION, + assert response.data.get("detail") == ERR_CANNOT_FORK_FROM_LOCALITY.substitute( + locality=EXPORTING_TEST_REGION, ) assert uploading_start_mock.call_count == 0 assert analytics_record_mock.call_count == 0