Skip to content

Commit

Permalink
Revert "fix(hc): Silo fixes for OrganizationAlertRuleAvailableActionI…
Browse files Browse the repository at this point in the history
…ndexEndpoint (#57949)"

This reverts commit 53edebb.
  • Loading branch information
RyanSkonnord committed Oct 13, 2023
1 parent 7748425 commit 66ba35e
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 92 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
from __future__ import annotations

from collections import defaultdict
from typing import Any, DefaultDict, List, Mapping

from rest_framework import status
from rest_framework.request import Request
Expand All @@ -12,24 +9,20 @@
from sentry.api.base import region_silo_endpoint
from sentry.api.bases.organization import OrganizationEndpoint
from sentry.api.exceptions import ResourceDoesNotExist
from sentry.constants import SentryAppStatus
from sentry.incidents.logic import (
get_available_action_integrations_for_org,
get_opsgenie_teams,
get_pagerduty_services,
)
from sentry.incidents.models import AlertRuleTriggerAction
from sentry.incidents.serializers import ACTION_TARGET_TYPE_TO_STRING
from sentry.models.organization import Organization
from sentry.services.hybrid_cloud.app import RpcSentryAppInstallation, app_service
from sentry.services.hybrid_cloud.integration import RpcIntegration
from sentry.models.integrations.sentry_app_installation import SentryAppInstallation


def build_action_response(
registered_type,
integration: RpcIntegration | None = None,
organization: Organization | None = None,
sentry_app_installation: RpcSentryAppInstallation | None = None,
) -> Mapping[str, Any]:
registered_type, integration=None, organization=None, sentry_app_installation=None
):
"""
Build the "available action" objects for the API. Each one can have different fields.
Expand Down Expand Up @@ -64,14 +57,14 @@ def build_action_response(

elif sentry_app_installation:
action_response["sentryAppName"] = sentry_app_installation.sentry_app.name
action_response["sentryAppId"] = sentry_app_installation.sentry_app.id
action_response["sentryAppId"] = sentry_app_installation.sentry_app_id
action_response["sentryAppInstallationUuid"] = sentry_app_installation.uuid
action_response["status"] = sentry_app_installation.sentry_app.status
action_response["status"] = SentryAppStatus.as_str(
sentry_app_installation.sentry_app.status
)

# Sentry Apps can be alertable but not have an Alert Rule UI Component
component = app_service.prepare_sentry_app_components(
installation_id=sentry_app_installation.id, component_type="alert-rule-action"
)
component = sentry_app_installation.prepare_sentry_app_components("alert-rule-action")
if component:
action_response["settings"] = component.schema.get("settings", {})

Expand All @@ -94,7 +87,7 @@ def get(self, request: Request, organization) -> Response:
actions = []

# Cache Integration objects in this data structure to save DB calls.
provider_integrations: DefaultDict[str, List[RpcIntegration]] = defaultdict(list)
provider_integrations = defaultdict(list)
for integration in get_available_action_integrations_for_org(organization):
provider_integrations[integration.provider].append(integration)

Expand All @@ -110,13 +103,13 @@ def get(self, request: Request, organization) -> Response:

# Add all alertable SentryApps to the list.
elif registered_type.type == AlertRuleTriggerAction.Type.SENTRY_APP:
installs = app_service.get_installed_for_organization(
organization_id=organization.id
)
actions += [
build_action_response(registered_type, sentry_app_installation=install)
for install in installs
if install.sentry_app.is_alertable
for install in SentryAppInstallation.objects.get_installed_for_organization(
organization.id
).filter(
sentry_app__is_alertable=True,
)
]

else:
Expand Down
12 changes: 5 additions & 7 deletions src/sentry/incidents/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from sentry import analytics, audit_log, features, quotas
from sentry.auth.access import SystemAccess
from sentry.constants import CRASH_RATE_ALERT_AGGREGATE_ALIAS, ObjectStatus
from sentry.constants import CRASH_RATE_ALERT_AGGREGATE_ALIAS
from sentry.incidents import tasks
from sentry.incidents.models import (
AlertRule,
Expand All @@ -38,6 +38,7 @@
TriggerStatus,
)
from sentry.models.actor import Actor
from sentry.models.integrations.integration import Integration
from sentry.models.integrations.organization_integration import OrganizationIntegration
from sentry.models.notificationaction import ActionService, ActionTarget
from sentry.models.project import Project
Expand Down Expand Up @@ -1457,7 +1458,7 @@ def get_actions_for_trigger(trigger):
return AlertRuleTriggerAction.objects.filter(alert_rule_trigger=trigger)


def get_available_action_integrations_for_org(organization) -> List[RpcIntegration]:
def get_available_action_integrations_for_org(organization):
"""
Returns a list of integrations that the organization has installed. Integrations are
filtered by the list of registered providers.
Expand All @@ -1471,11 +1472,8 @@ def get_available_action_integrations_for_org(organization) -> List[RpcIntegrati
if registration.type != AlertRuleTriggerAction.Type.DISCORD
or features.has("organizations:integrations-discord-metric-alerts", organization)
]
return integration_service.get_integrations(
status=ObjectStatus.ACTIVE,
org_integration_status=ObjectStatus.ACTIVE,
organization_id=organization.id,
providers=providers,
return Integration.objects.get_active_integrations(organization.id).filter(
provider__in=providers
)


Expand Down
28 changes: 17 additions & 11 deletions src/sentry/models/integrations/sentry_app_installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import uuid
from itertools import chain
from typing import TYPE_CHECKING, Any, List, Mapping
from typing import TYPE_CHECKING, Any, List

from django.db import models, router, transaction
from django.db.models import OuterRef, QuerySet, Subquery
Expand All @@ -19,7 +19,6 @@
)
from sentry.db.models.fields.hybrid_cloud_foreign_key import HybridCloudForeignKey
from sentry.services.hybrid_cloud.auth import AuthenticatedToken
from sentry.services.hybrid_cloud.project import RpcProject
from sentry.types.region import find_regions_for_orgs

if TYPE_CHECKING:
Expand Down Expand Up @@ -196,12 +195,19 @@ def outboxes_for_update(self) -> List[ControlOutbox]:
for region_name in find_regions_for_orgs([self.organization_id])
]

def prepare_ui_component(
self,
component: SentryAppComponent,
project: Project | RpcProject | None = None,
values: Any = None,
) -> SentryAppComponent | None:
def prepare_sentry_app_components(self, component_type, project=None, values=None):
from sentry.models.integrations.sentry_app_component import SentryAppComponent

try:
component = SentryAppComponent.objects.get(
sentry_app_id=self.sentry_app_id, type=component_type
)
except SentryAppComponent.DoesNotExist:
return None

return self.prepare_ui_component(component, project, values)

def prepare_ui_component(self, component, project=None, values=None):
return prepare_ui_component(
self, component, project_slug=project.slug if project else None, values=values
)
Expand All @@ -211,8 +217,8 @@ def prepare_sentry_app_components(
installation: SentryAppInstallation,
component_type: str,
project_slug: str | None = None,
values: List[Mapping[str, Any]] | None = None,
) -> SentryAppComponent | None:
values: Any = None,
):
from sentry.models.integrations.sentry_app_component import SentryAppComponent

try:
Expand All @@ -229,7 +235,7 @@ def prepare_ui_component(
installation: SentryAppInstallation,
component: SentryAppComponent,
project_slug: str | None = None,
values: List[Mapping[str, Any]] | None = None,
values: Any = None,
) -> SentryAppComponent | None:
from sentry.coreapi import APIError
from sentry.sentry_apps.components import SentryAppComponentPreparer
Expand Down
17 changes: 6 additions & 11 deletions src/sentry/services/hybrid_cloud/app/impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
)
from sentry.services.hybrid_cloud.app.serial import (
serialize_sentry_app,
serialize_sentry_app_component,
serialize_sentry_app_installation,
)
from sentry.services.hybrid_cloud.auth import AuthenticationContext
Expand Down Expand Up @@ -56,7 +55,12 @@ def get_many(

def find_app_components(self, *, app_id: int) -> List[RpcSentryAppComponent]:
return [
serialize_sentry_app_component(c)
RpcSentryAppComponent(
uuid=str(c.uuid),
sentry_app_id=c.sentry_app_id,
type=c.type,
app_schema=c.schema,
)
for c in SentryAppComponent.objects.filter(sentry_app_id=app_id)
]

Expand Down Expand Up @@ -249,12 +253,3 @@ def create_internal_integration_for_channel_request(
installation = SentryAppInstallation.objects.get(sentry_app=sentry_app)

return serialize_sentry_app_installation(installation=installation, app=sentry_app)

def prepare_sentry_app_components(
self, *, installation_id: int, component_type: str, project_slug: Optional[str] = None
) -> Optional[RpcSentryAppComponent]:
from sentry.models.integrations.sentry_app_installation import prepare_sentry_app_components

installation = SentryAppInstallation.objects.get(id=installation_id)
component = prepare_sentry_app_components(installation, component_type, project_slug)
return serialize_sentry_app_component(component) if component else None
1 change: 0 additions & 1 deletion src/sentry/services/hybrid_cloud/app/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ class RpcSentryApp(RpcModel):
uuid: str = ""
events: List[str] = Field(default_factory=list)
webhook_url: Optional[str] = None
is_alertable: bool = False
is_published: bool = False
is_unpublished: bool = False
is_internal: bool = True
Expand Down
14 changes: 1 addition & 13 deletions src/sentry/services/hybrid_cloud/app/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

from sentry.constants import SentryAppStatus
from sentry.models.apiapplication import ApiApplication
from sentry.models.integrations import SentryAppComponent
from sentry.models.integrations.sentry_app import SentryApp
from sentry.models.integrations.sentry_app_installation import SentryAppInstallation
from sentry.services.hybrid_cloud.app import (
RpcApiApplication,
RpcSentryApp,
RpcSentryAppComponent,
RpcSentryAppInstallation,
)

Expand Down Expand Up @@ -36,12 +34,11 @@ def serialize_sentry_app(app: SentryApp) -> RpcSentryApp:
uuid=app.uuid,
events=app.events,
webhook_url=app.webhook_url,
is_alertable=app.is_alertable,
is_published=app.status == SentryAppStatus.PUBLISHED,
is_unpublished=app.status == SentryAppStatus.UNPUBLISHED,
is_internal=app.status == SentryAppStatus.INTERNAL,
is_publish_request_inprogress=app.status == SentryAppStatus.PUBLISH_REQUEST_INPROGRESS,
status=SentryAppStatus.as_str(app.status),
status=app.status,
)


Expand All @@ -61,12 +58,3 @@ def serialize_sentry_app_installation(
uuid=installation.uuid,
api_token=installation.api_token.token if installation.api_token else None,
)


def serialize_sentry_app_component(component: SentryAppComponent) -> RpcSentryAppComponent:
return RpcSentryAppComponent(
uuid=str(component.uuid),
sentry_app_id=component.sentry_app_id,
type=component.type,
app_schema=component.schema,
)
7 changes: 0 additions & 7 deletions src/sentry/services/hybrid_cloud/app/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,5 @@ def create_internal_integration_for_channel_request(
) -> RpcSentryAppInstallation:
pass

@rpc_method
@abc.abstractmethod
def prepare_sentry_app_components(
self, *, installation_id: int, component_type: str, project_slug: Optional[str] = None
) -> Optional[RpcSentryAppComponent]:
pass


app_service = cast(AppService, AppService.create_delegation())
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from sentry.incidents.models import AlertRuleTriggerAction
from sentry.models.integrations.integration import Integration
from sentry.models.integrations.organization_integration import OrganizationIntegration
from sentry.services.hybrid_cloud.app.serial import serialize_sentry_app_installation
from sentry.silo import SiloMode
from sentry.testutils.cases import APITestCase
from sentry.testutils.silo import assume_test_silo_mode, region_silo_test
Expand All @@ -26,7 +25,7 @@
}


@region_silo_test(stable=True)
@region_silo_test
class OrganizationAlertRuleAvailableActionIndexEndpointTest(APITestCase):
endpoint = "sentry-api-0-organization-alert-rule-available-actions"
email = AlertRuleTriggerAction.get_registered_type(AlertRuleTriggerAction.Type.EMAIL)
Expand Down Expand Up @@ -110,9 +109,7 @@ def test_build_action_response_pagerduty(self):
def test_build_action_response_sentry_app(self):
installation = self.install_new_sentry_app("foo")

data = build_action_response(
self.sentry_app, sentry_app_installation=serialize_sentry_app_installation(installation)
)
data = build_action_response(self.sentry_app, sentry_app_installation=installation)

assert data["type"] == "sentry_app"
assert data["allowedTargetTypes"] == ["sentry_app"]
Expand Down Expand Up @@ -183,10 +180,7 @@ def test_sentry_apps(self):
assert len(response.data) == 2
assert build_action_response(self.email) in response.data
assert (
build_action_response(
self.sentry_app,
sentry_app_installation=serialize_sentry_app_installation(installation),
)
build_action_response(self.sentry_app, sentry_app_installation=installation)
in response.data
)

Expand All @@ -199,10 +193,7 @@ def test_published_sentry_apps(self):

assert len(response.data) == 2
assert (
build_action_response(
self.sentry_app,
sentry_app_installation=serialize_sentry_app_installation(installation),
)
build_action_response(self.sentry_app, sentry_app_installation=installation)
in response.data
)

Expand Down
9 changes: 2 additions & 7 deletions tests/sentry/incidents/test_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
from sentry.models.actor import ActorTuple, get_actor_id_for_user
from sentry.models.integrations.integration import Integration
from sentry.models.integrations.organization_integration import OrganizationIntegration
from sentry.services.hybrid_cloud.integration.serial import serialize_integration
from sentry.shared_integrations.exceptions import ApiError, ApiRateLimitedError, ApiTimeoutError
from sentry.snuba.dataset import Dataset
from sentry.snuba.models import QuerySubscription, SnubaQuery, SnubaQueryEventType
Expand Down Expand Up @@ -1998,18 +1997,14 @@ def test_unregistered(self):
def test_registered(self):
integration = Integration.objects.create(external_id="1", provider="slack")
integration.add_organization(self.organization)
assert list(get_available_action_integrations_for_org(self.organization)) == [
serialize_integration(integration)
]
assert list(get_available_action_integrations_for_org(self.organization)) == [integration]

def test_mixed(self):
integration = Integration.objects.create(external_id="1", provider="slack")
integration.add_organization(self.organization)
other_integration = Integration.objects.create(external_id="12345", provider="random")
other_integration.add_organization(self.organization)
assert list(get_available_action_integrations_for_org(self.organization)) == [
serialize_integration(integration)
]
assert list(get_available_action_integrations_for_org(self.organization)) == [integration]

def test_disabled_integration(self):
integration = Integration.objects.create(
Expand Down

0 comments on commit 66ba35e

Please sign in to comment.