Browse Source

ref(hybrid): Standardize nomenclature around silos (#38277)

Having previously wished to avoid committing to the term "silo" in
production code and instead used the terms "server component" and
"server mode", standardize naming of classes and variables on the terms
"silo" and "silo mode".

Also clean up some related names around silo mode decorators, and use
the terms "Model" and "Endpoint" (in reference to the decorated classes)
in preference to synonyms such as "data", "API", and "view".
Ryan Skonnord 2 years ago
parent
commit
06708a5d2f

+ 1 - 1
mypy.ini

@@ -75,8 +75,8 @@ files = src/sentry/analytics/,
         src/sentry/search/events/types.py,
         src/sentry/search/snuba/,
         src/sentry/sentry_metrics/,
-        src/sentry/servermode.py,
         src/sentry/shared_integrations/,
+        src/sentry/silo.py,
         src/sentry/snuba/entity_subscription.py,
         src/sentry/snuba/outcomes.py,
         src/sentry/snuba/query_subscription_consumer.py,

+ 20 - 20
scripts/servermode/add_mode_limits.py → scripts/silo/add_silo_decorators.py

@@ -17,49 +17,49 @@ Instructions for use:
 1. Commit or stash any Git changes in progress.
 2. Scroll down to "Fill these predicates in..." and write what you want to do.
 3. From the Sentry project root, do
-     ./scripts/servermode/audit_mode_limits.py | ./scripts/servermode/add_mode_limits.py
+     ./scripts/silo/audit_silo_decorators.py | ./scripts/silo/add_silo_decorators.py
 4. Do `git status` or `git diff` to observe the results. Commit if you're happy.
 """
 
 
 class ClassCategory(Enum):
     MODEL = auto()
-    VIEW = auto()
+    ENDPOINT = auto()
 
 
 @dataclass
-class LimitedClass:
-    package: str
+class TargetClass:
+    module: str
     name: str
     category: ClassCategory
     is_decorated: bool
 
 
-def parse_audit(audit) -> Iterable[LimitedClass]:
+def parse_audit(audit) -> Iterable[TargetClass]:
     def split_qualname(value):
         dot_index = value.rindex(".")
-        package = value[:dot_index]
+        module = value[:dot_index]
         name = value[dot_index + 1 :]
-        return package, name
+        return module, name
 
     def parse_group(category, dec_group):
         is_decorated = dec_group["decorator"] is not None
         for value in dec_group["values"]:
-            package, name = split_qualname(value)
-            yield LimitedClass(package, name, category, is_decorated)
+            module, name = split_qualname(value)
+            yield TargetClass(module, name, category, is_decorated)
 
     for dec_group in audit["models"]["decorators"]:
         yield from parse_group(ClassCategory.MODEL, dec_group)
-    for dec_group in audit["views"]["decorators"]:
-        yield from parse_group(ClassCategory.VIEW, dec_group)
+    for dec_group in audit["endpoints"]["decorators"]:
+        yield from parse_group(ClassCategory.ENDPOINT, dec_group)
 
 
 def read_audit():
     pipe_input = sys.stdin.read()
     brace_index = pipe_input.index("{")
     pipe_input = pipe_input[brace_index:]  # strip leading junk
-    server_mode_audit = json.loads(pipe_input)
-    return list(parse_audit(server_mode_audit))
+    silo_audit = json.loads(pipe_input)
+    return list(parse_audit(silo_audit))
 
 
 def find_source_paths():
@@ -91,7 +91,7 @@ def insert_import(src_code: str, import_stmt: str) -> str:
 def apply_decorators(
     decorator_name: str,
     import_stmt: str,
-    target_classes: Iterable[LimitedClass],
+    target_classes: Iterable[TargetClass],
 ) -> None:
     target_names = {c.name for c in target_classes if not c.is_decorated}
     for src_path, class_name in find_class_declarations():
@@ -117,16 +117,16 @@ def main():
     ####################################################################
     # Fill these predicates in with the logic you want to apply
 
-    def control_model_predicate(c: LimitedClass) -> bool:
+    def control_model_predicate(c: TargetClass) -> bool:
         return False
 
-    def customer_model_predicate(c: LimitedClass) -> bool:
+    def customer_model_predicate(c: TargetClass) -> bool:
         return False
 
-    def control_endpoint_predicate(c: LimitedClass) -> bool:
+    def control_endpoint_predicate(c: TargetClass) -> bool:
         return False
 
-    def customer_endpoint_predicate(c: LimitedClass) -> bool:
+    def customer_endpoint_predicate(c: TargetClass) -> bool:
         return False
 
     ####################################################################
@@ -144,12 +144,12 @@ def main():
     apply_decorators(
         "control_silo_endpoint",
         "from sentry.api.base import control_silo_endpoint",
-        filter_classes(ClassCategory.VIEW, control_endpoint_predicate),
+        filter_classes(ClassCategory.ENDPOINT, control_endpoint_predicate),
     )
     apply_decorators(
         "customer_silo_endpoint",
         "from sentry.api.base import customer_silo_endpoint",
-        filter_classes(ClassCategory.VIEW, customer_endpoint_predicate),
+        filter_classes(ClassCategory.ENDPOINT, customer_endpoint_predicate),
     )
 
 

+ 14 - 14
scripts/servermode/audit_mode_limits.py → scripts/silo/audit_silo_decorators.py

@@ -11,24 +11,24 @@ import django.apps
 import django.urls
 
 
-def audit_mode_limits(format="json"):
-    """Lists which classes have had server mode decorators applied."""
+def audit_silo_limits(format="json"):
+    """Lists which classes have had silo decorators applied."""
 
     from sentry.runner import configure
 
     configure()
     model_table = create_model_table()
-    view_table = create_view_table()
+    endpoint_table = create_endpoint_table()
 
     if format == "json":
         json_repr = {
             "models": ModelPresentation().as_json_repr(model_table),
-            "views": ViewPresentation().as_json_repr(view_table),
+            "endpoints": EndpointPresentation().as_json_repr(endpoint_table),
         }
         json.dump(json_repr, sys.stdout, indent=4)
     elif format == "markdown":
         ModelPresentation().print_markdown(model_table)
-        ViewPresentation().print_markdown(view_table)
+        EndpointPresentation().print_markdown(endpoint_table)
     else:
         raise ValueError
 
@@ -38,30 +38,30 @@ def create_model_table():
     for model_class in django.apps.apps.get_models():
         if model_class._meta.app_label != "sentry":
             continue
-        limit = getattr(model_class._meta, "_ModelAvailableOn__mode_limit", None)
+        limit = getattr(model_class._meta, "_ModelSiloLimit__silo_limit", None)
         key = (limit.modes, limit.read_only) if limit else None
         table[key].append(model_class)
     return table
 
 
-def create_view_table():
+def create_endpoint_table():
     from sentry.api.base import Endpoint
 
     def is_endpoint(view_function, bindings):
         view_class = getattr(view_function, "view_class", None)
         return view_class and issubclass(view_class, Endpoint)
 
-    def get_view_classes():
+    def get_endpoint_classes():
         url_mappings = list(django.urls.get_resolver().reverse_dict.items())
         for (view_function, bindings) in url_mappings:
             if is_endpoint(view_function, bindings):
                 yield view_function.view_class
 
     table = defaultdict(list)
-    for view_class in get_view_classes():
-        limit = getattr(view_class, "__mode_limit", None)
+    for endpoint_class in get_endpoint_classes():
+        limit = getattr(endpoint_class, "__silo_limit", None)
         key = limit.modes if limit else None
-        table[key].append(view_class)
+        table[key].append(endpoint_class)
 
     return table
 
@@ -171,13 +171,13 @@ class ModelPresentation(ConsolePresentation):
             return self.format_mode_set(write_modes)
 
 
-class ViewPresentation(ConsolePresentation):
+class EndpointPresentation(ConsolePresentation):
     @property
     def table_label(self):
         return "VIEWS"
 
     def order(self, group):
-        mode_set, _view_group = group
+        mode_set, _endpoint_group = group
         return len(mode_set or ()), self.format_mode_set(mode_set)
 
     def get_group_label(self, key):
@@ -188,4 +188,4 @@ class ViewPresentation(ConsolePresentation):
 
 
 if __name__ == "__main__":
-    audit_mode_limits()
+    audit_silo_limits()

+ 10 - 13
src/sentry/api/base.py

@@ -24,7 +24,7 @@ from sentry.apidocs.hooks import HTTP_METHODS_SET
 from sentry.auth import access
 from sentry.models import Environment
 from sentry.ratelimits.config import DEFAULT_RATE_LIMIT_CONFIG, RateLimitConfig
-from sentry.servermode import ModeLimited, ServerComponentMode
+from sentry.silo import SiloLimit, SiloMode
 from sentry.utils import json
 from sentry.utils.audit import create_audit_entry
 from sentry.utils.cursors import Cursor
@@ -494,7 +494,7 @@ def resolve_region(request: Request):
     return None
 
 
-class ApiAvailableOn(ModeLimited):
+class EndpointSiloLimit(SiloLimit):
     def modify_endpoint_class(self, decorated_class: Type[Endpoint]) -> type:
         dispatch_override = self.create_override(decorated_class.dispatch)
         return type(
@@ -502,21 +502,18 @@ class ApiAvailableOn(ModeLimited):
             (decorated_class,),
             {
                 "dispatch": dispatch_override,
-                "__mode_limit": self,  # For internal tooling only
+                "__silo_limit": self,  # For internal tooling only
             },
         )
 
     def modify_endpoint_method(self, decorated_method: Callable[..., Any]) -> Callable[..., Any]:
         return self.create_override(decorated_method)
 
-    class ApiAvailabilityError(Exception):
-        pass
-
     def handle_when_unavailable(
         self,
         original_method: Callable[..., Any],
-        current_mode: ServerComponentMode,
-        available_modes: Iterable[ServerComponentMode],
+        current_mode: SiloMode,
+        available_modes: Iterable[SiloMode],
     ) -> Callable[..., Any]:
         def handle(obj: Any, request: Request, *args: Any, **kwargs: Any) -> HttpResponse:
             mode_str = ", ".join(str(m) for m in available_modes)
@@ -525,7 +522,7 @@ class ApiAvailableOn(ModeLimited):
                 f"{current_mode} mode. This endpoint is available only in: {mode_str}"
             )
             if settings.FAIL_ON_UNAVAILABLE_API_CALL:
-                raise self.ApiAvailabilityError(message)
+                raise self.AvailabilityError(message)
             else:
                 logger.warning(message)
                 return HttpResponse(status=status.HTTP_404_NOT_FOUND)
@@ -535,14 +532,14 @@ class ApiAvailableOn(ModeLimited):
     def __call__(self, decorated_obj: Any) -> Any:
         if isinstance(decorated_obj, type):
             if not issubclass(decorated_obj, Endpoint):
-                raise ValueError("`@ApiAvailableOn` can decorate only Endpoint subclasses")
+                raise ValueError("`@EndpointSiloLimit` can decorate only Endpoint subclasses")
             return self.modify_endpoint_class(decorated_obj)
 
         if callable(decorated_obj):
             return self.modify_endpoint_method(decorated_obj)
 
-        raise TypeError("`@ApiAvailableOn` must decorate a class or method")
+        raise TypeError("`@EndpointSiloLimit` must decorate a class or method")
 
 
-control_silo_endpoint = ApiAvailableOn(ServerComponentMode.CONTROL)
-customer_silo_endpoint = ApiAvailableOn(ServerComponentMode.CUSTOMER)
+control_silo_endpoint = EndpointSiloLimit(SiloMode.CONTROL)
+customer_silo_endpoint = EndpointSiloLimit(SiloMode.CUSTOMER)

+ 1 - 1
src/sentry/conf/server.py

@@ -2771,7 +2771,7 @@ SENTRY_FUNCTIONS_PROJECT_NAME = None
 
 SENTRY_FUNCTIONS_REGION = "us-central1"
 
-SERVER_COMPONENT_MODE = os.environ.get("SENTRY_SERVER_COMPONENT_MODE", None)
+SILO_MODE = os.environ.get("SENTRY_SILO_MODE", None)
 FAIL_ON_UNAVAILABLE_API_CALL = False
 
 DISALLOWED_CUSTOMER_DOMAINS = []

+ 13 - 20
src/sentry/db/models/base.py

@@ -6,7 +6,7 @@ from django.db import models
 from django.db.models import signals
 from django.utils import timezone
 
-from sentry.servermode import ModeLimited, ServerComponentMode
+from sentry.silo import SiloLimit, SiloMode
 
 from .fields.bounded import BoundedBigAutoField
 from .manager import BaseManager, M
@@ -142,19 +142,14 @@ signals.post_save.connect(__model_post_save)
 signals.class_prepared.connect(__model_class_prepared)
 
 
-class ModelAvailableOn(ModeLimited):
+class ModelSiloLimit(SiloLimit):
     def __init__(
         self,
-        *modes: ServerComponentMode,
-        read_only: ServerComponentMode | Iterable[ServerComponentMode] = (),
+        *modes: SiloMode,
+        read_only: SiloMode | Iterable[SiloMode] = (),
     ) -> None:
         super().__init__(*modes)
-        self.read_only = frozenset(
-            [read_only] if isinstance(read_only, ServerComponentMode) else read_only
-        )
-
-    class DataAvailabilityError(Exception):
-        pass
+        self.read_only = frozenset([read_only] if isinstance(read_only, SiloMode) else read_only)
 
     @staticmethod
     def _recover_model_name(obj: Any) -> str | None:
@@ -169,8 +164,8 @@ class ModelAvailableOn(ModeLimited):
     def handle_when_unavailable(
         self,
         original_method: Callable[..., Any],
-        current_mode: ServerComponentMode,
-        available_modes: Iterable[ServerComponentMode],
+        current_mode: SiloMode,
+        available_modes: Iterable[SiloMode],
     ) -> Callable[..., Any]:
         def handle(obj: Any, *args: Any, **kwargs: Any) -> None:
             model_name = self._recover_model_name(obj)
@@ -180,16 +175,16 @@ class ModelAvailableOn(ModeLimited):
                 f"Called `{method_name}` on server in {current_mode} mode. "
                 f"{model_name or 'The model'} is available only in: {mode_str}"
             )
-            raise self.DataAvailabilityError(message)
+            raise self.AvailabilityError(message)
 
         return handle
 
     def __call__(self, model_class: Any) -> type:
         if not (isinstance(model_class, type) and issubclass(model_class, BaseModel)):
-            raise TypeError("`@ModelAvailableOn ` must decorate a Model class")
+            raise TypeError("`@ModelSiloLimit ` must decorate a Model class")
         assert isinstance(model_class.objects, BaseManager)
 
-        model_class.objects = model_class.objects.create_mode_limited_copy(self, self.read_only)
+        model_class.objects = model_class.objects.create_silo_limited_copy(self, self.read_only)
 
         # On the model (not manager) class itself, find all methods that are tagged
         # with the `alters_data` meta-attribute and replace them with overrides.
@@ -206,12 +201,10 @@ class ModelAvailableOn(ModeLimited):
 
         # For internal tooling only. Having any production logic depend on this is
         # strongly discouraged.
-        model_class._meta.__mode_limit = self
+        model_class._meta.__silo_limit = self
 
         return model_class
 
 
-control_silo_model = ModelAvailableOn(
-    ServerComponentMode.CONTROL, read_only=ServerComponentMode.CUSTOMER
-)
-customer_silo_model = ModelAvailableOn(ServerComponentMode.CUSTOMER)
+control_silo_model = ModelSiloLimit(SiloMode.CONTROL, read_only=SiloMode.CUSTOMER)
+customer_silo_model = ModelSiloLimit(SiloMode.CUSTOMER)

+ 4 - 4
src/sentry/db/models/manager/base.py

@@ -25,7 +25,7 @@ from django.db.models.signals import class_prepared, post_delete, post_init, pos
 from sentry.db.models.manager import M, make_key
 from sentry.db.models.manager.base_query_set import BaseQuerySet
 from sentry.db.models.query import create_or_update
-from sentry.servermode import ModeLimited, ServerComponentMode
+from sentry.silo import SiloLimit, SiloMode
 from sentry.utils.cache import cache
 from sentry.utils.hashlib import md5_text
 
@@ -452,10 +452,10 @@ class BaseManager(DjangoBaseManager.from_queryset(BaseQuerySet), Generic[M]):  #
             return self._queryset_class(self.model, using=self._db, hints=self._hints)
         return self._queryset_class(self.model, using=self._db)
 
-    def create_mode_limited_copy(
-        self, limit: ModeLimited, read_modes: Iterable[ServerComponentMode]
+    def create_silo_limited_copy(
+        self, limit: SiloLimit, read_modes: Iterable[SiloMode]
     ) -> BaseManager[M]:
-        """Create a copy of this manager that enforces server mode limitations."""
+        """Create a copy of this manager that enforces silo limitations."""
 
         # Dynamically create a subclass of this manager's class, adding overrides.
         cls = type(self)

+ 23 - 19
src/sentry/servermode.py → src/sentry/silo.py

@@ -9,19 +9,22 @@ from typing import Any, Callable, Iterable
 from django.conf import settings
 
 
-class ServerComponentMode(Enum):
-    """Defines the component mode of the application to be acting as."""
+class SiloMode(Enum):
+    """Defines which "silo" component the application is acting as.
+
+    The default choice is "monolith", which assumes that the server is the only
+    "silo" in its environment and allows access to all tables and endpoints.
+    """
 
     MONOLITH = "MONOLITH"
     CONTROL = "CONTROL"
     CUSTOMER = "CUSTOMER"
-    FRONTEND = "FRONTEND"
 
     @classmethod
-    def resolve(cls, mode: str | ServerComponentMode | None) -> ServerComponentMode:
+    def resolve(cls, mode: str | SiloMode | None) -> SiloMode:
         if not mode:
             return cls.MONOLITH
-        if isinstance(mode, ServerComponentMode):
+        if isinstance(mode, SiloMode):
             return mode
         return cls[mode]
 
@@ -29,14 +32,14 @@ class ServerComponentMode(Enum):
         return self.value
 
     @classmethod
-    def get_current_mode(cls) -> ServerComponentMode:
-        return cls.resolve(settings.SERVER_COMPONENT_MODE)
+    def get_current_mode(cls) -> SiloMode:
+        return cls.resolve(settings.SILO_MODE)
 
 
-class ModeLimited(abc.ABC):
+class SiloLimit(abc.ABC):
     """Decorator for classes or methods that are limited to certain modes."""
 
-    def __init__(self, *modes: ServerComponentMode) -> None:
+    def __init__(self, *modes: SiloMode) -> None:
         self.modes = frozenset(modes)
         if not self.modes:
             raise ValueError
@@ -46,12 +49,15 @@ class ModeLimited(abc.ABC):
         """Modify the decorated object with appropriate overrides."""
         raise NotImplementedError
 
+    class AvailabilityError(Exception):
+        """Indicate that something in unavailable in the current silo mode."""
+
     @abc.abstractmethod
     def handle_when_unavailable(
         self,
         original_method: Callable[..., Any],
-        current_mode: ServerComponentMode,
-        available_modes: Iterable[ServerComponentMode],
+        current_mode: SiloMode,
+        available_modes: Iterable[SiloMode],
     ) -> Callable[..., Any]:
         """Handle an attempt to access an unavailable element.
 
@@ -64,28 +70,26 @@ class ModeLimited(abc.ABC):
     def create_override(
         self,
         original_method: Callable[..., Any],
-        extra_modes: Iterable[ServerComponentMode] = (),
+        extra_modes: Iterable[SiloMode] = (),
     ) -> Callable[..., Any]:
         """Create a method that conditionally overrides another method.
 
         The returned method passes through to the original only if this server
-        component is in one of the allowed modes.
+        is in one of the allowed silo modes.
 
         :param original_method: the method being conditionally overridden
         :param extra_modes: modes to allow in addition to self.modes
         :return: the conditional method object
         """
 
-        available_modes = frozenset(
-            itertools.chain([ServerComponentMode.MONOLITH], self.modes, extra_modes)
-        )
+        available_modes = frozenset(itertools.chain([SiloMode.MONOLITH], self.modes, extra_modes))
 
         def override(*args: Any, **kwargs: Any) -> Any:
             # It's important to do this check inside the override, so that tests
             # using `override_settings` or a similar context can change the value of
-            # settings.SERVER_COMPONENT_MODE effectively. Otherwise, availability
-            # would be immutably determined when the decorator is first evaluated.
-            current_mode = ServerComponentMode.get_current_mode()
+            # settings.SILO_MODE effectively. Otherwise, availability would be
+            # immutably determined when the decorator is first evaluated.
+            current_mode = SiloMode.get_current_mode()
             is_available = current_mode in available_modes
 
             if is_available:

+ 13 - 13
tests/sentry/api/test_base.py

@@ -5,10 +5,10 @@ from django.test import override_settings
 from pytest import raises
 from rest_framework.response import Response
 
-from sentry.api.base import ApiAvailableOn, Endpoint, resolve_region
+from sentry.api.base import Endpoint, EndpointSiloLimit, resolve_region
 from sentry.api.paginator import GenericOffsetPaginator
 from sentry.models import ApiKey
-from sentry.servermode import ServerComponentMode
+from sentry.silo import SiloMode
 from sentry.testutils import APITestCase
 
 
@@ -208,18 +208,18 @@ class CustomerDomainTest(APITestCase):
         assert request_with_subdomain("sentry") is None
 
 
-class ServerComponentModeTest(APITestCase):
+class SiloModeTest(APITestCase):
     def _test_active_on(self, endpoint_mode, active_mode, expect_to_be_active):
-        @ApiAvailableOn(endpoint_mode)
+        @EndpointSiloLimit(endpoint_mode)
         class DecoratedEndpoint(DummyEndpoint):
             pass
 
         class EndpointWithDecoratedMethod(DummyEndpoint):
-            @ApiAvailableOn(endpoint_mode)
+            @EndpointSiloLimit(endpoint_mode)
             def get(self, request):
                 return super().get(request)
 
-        with override_settings(SERVER_COMPONENT_MODE=active_mode):
+        with override_settings(SILO_MODE=active_mode):
             request = self.make_request(method="GET")
 
             for endpoint_class in (DecoratedEndpoint, EndpointWithDecoratedMethod):
@@ -229,18 +229,18 @@ class ServerComponentModeTest(APITestCase):
 
             if not expect_to_be_active:
                 with override_settings(FAIL_ON_UNAVAILABLE_API_CALL=True):
-                    with raises(ApiAvailableOn.ApiAvailabilityError):
+                    with raises(EndpointSiloLimit.AvailabilityError):
                         DecoratedEndpoint.as_view()(request)
                     # TODO: Make work with EndpointWithDecoratedMethod
 
     def test_with_active_mode(self):
-        self._test_active_on(ServerComponentMode.CUSTOMER, ServerComponentMode.CUSTOMER, True)
-        self._test_active_on(ServerComponentMode.CONTROL, ServerComponentMode.CONTROL, True)
+        self._test_active_on(SiloMode.CUSTOMER, SiloMode.CUSTOMER, True)
+        self._test_active_on(SiloMode.CONTROL, SiloMode.CONTROL, True)
 
     def test_with_inactive_mode(self):
-        self._test_active_on(ServerComponentMode.CUSTOMER, ServerComponentMode.CONTROL, False)
-        self._test_active_on(ServerComponentMode.CONTROL, ServerComponentMode.CUSTOMER, False)
+        self._test_active_on(SiloMode.CUSTOMER, SiloMode.CONTROL, False)
+        self._test_active_on(SiloMode.CONTROL, SiloMode.CUSTOMER, False)
 
     def test_with_monolith_mode(self):
-        self._test_active_on(ServerComponentMode.CUSTOMER, ServerComponentMode.MONOLITH, True)
-        self._test_active_on(ServerComponentMode.CONTROL, ServerComponentMode.MONOLITH, True)
+        self._test_active_on(SiloMode.CUSTOMER, SiloMode.MONOLITH, True)
+        self._test_active_on(SiloMode.CONTROL, SiloMode.MONOLITH, True)

+ 14 - 14
tests/sentry/models/test_base.py

@@ -1,8 +1,8 @@
 from django.test import override_settings
 from pytest import raises
 
-from sentry.db.models.base import Model, ModelAvailableOn
-from sentry.servermode import ServerComponentMode
+from sentry.db.models.base import Model, ModelSiloLimit
+from sentry.silo import SiloMode
 from sentry.testutils import TestCase
 
 
@@ -14,15 +14,15 @@ class AvailableOnTest(TestCase):
             abstract = True
             app_label = "fixtures"
 
-    @ModelAvailableOn(ServerComponentMode.CONTROL)
+    @ModelSiloLimit(SiloMode.CONTROL)
     class ControlModel(TestModel):
         pass
 
-    @ModelAvailableOn(ServerComponentMode.CUSTOMER)
+    @ModelSiloLimit(SiloMode.CUSTOMER)
     class CustomerModel(TestModel):
         pass
 
-    @ModelAvailableOn(ServerComponentMode.CONTROL, read_only=ServerComponentMode.CUSTOMER)
+    @ModelSiloLimit(SiloMode.CONTROL, read_only=SiloMode.CUSTOMER)
     class ReadOnlyModel(TestModel):
         pass
 
@@ -39,7 +39,7 @@ class AvailableOnTest(TestCase):
 
         self.ModelOnMonolith.objects.filter(id=1).delete()
 
-    @override_settings(SERVER_COMPONENT_MODE=ServerComponentMode.CUSTOMER)
+    @override_settings(SILO_MODE=SiloMode.CUSTOMER)
     def test_available_on_same_mode(self):
         assert list(self.CustomerModel.objects.all()) == []
         with raises(self.CustomerModel.DoesNotExist):
@@ -50,24 +50,24 @@ class AvailableOnTest(TestCase):
 
         self.CustomerModel.objects.filter(id=1).delete()
 
-    @override_settings(SERVER_COMPONENT_MODE=ServerComponentMode.CUSTOMER)
+    @override_settings(SILO_MODE=SiloMode.CUSTOMER)
     def test_unavailable_on_other_mode(self):
-        with raises(ModelAvailableOn.DataAvailabilityError):
+        with raises(ModelSiloLimit.AvailabilityError):
             list(self.ControlModel.objects.all())
-        with raises(ModelAvailableOn.DataAvailabilityError):
+        with raises(ModelSiloLimit.AvailabilityError):
             self.ControlModel.objects.get(id=1)
-        with raises(ModelAvailableOn.DataAvailabilityError):
+        with raises(ModelSiloLimit.AvailabilityError):
             self.ControlModel.objects.create()
-        with raises(ModelAvailableOn.DataAvailabilityError):
+        with raises(ModelSiloLimit.AvailabilityError):
             self.ControlModel.objects.filter(id=1).delete()
 
-    @override_settings(SERVER_COMPONENT_MODE=ServerComponentMode.CUSTOMER)
+    @override_settings(SILO_MODE=SiloMode.CUSTOMER)
     def test_available_for_read_only(self):
         assert list(self.ReadOnlyModel.objects.all()) == []
         with raises(self.ReadOnlyModel.DoesNotExist):
             self.ReadOnlyModel.objects.get(id=1)
 
-        with raises(ModelAvailableOn.DataAvailabilityError):
+        with raises(ModelSiloLimit.AvailabilityError):
             self.ReadOnlyModel.objects.create()
-        with raises(ModelAvailableOn.DataAvailabilityError):
+        with raises(ModelSiloLimit.AvailabilityError):
             self.ReadOnlyModel.objects.filter(id=1).delete()