Skip to content

Commit a11952b

Browse files
committed
condition -> type, add action.types, update tests
1 parent b058303 commit a11952b

File tree

3 files changed

+164
-34
lines changed

3 files changed

+164
-34
lines changed

src/sentry/workflow_engine/migration_helpers/alert_rule.py

+29-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
AlertRuleTrigger,
88
AlertRuleTriggerAction,
99
)
10+
from sentry.integrations.services.integration import integration_service
1011
from sentry.snuba.models import QuerySubscription, SnubaQuery
1112
from sentry.users.services.user import RpcUser
1213
from sentry.workflow_engine.models import (
@@ -24,12 +25,28 @@
2425
Workflow,
2526
WorkflowDataConditionGroup,
2627
)
27-
from sentry.workflow_engine.models.data_condition import Condition, ConditionType
28+
from sentry.workflow_engine.models.data_condition import Condition
2829
from sentry.workflow_engine.types import DetectorPriorityLevel
2930

3031
logger = logging.getLogger(__name__)
3132

3233

34+
def get_action_type(alert_rule_trigger_action: AlertRuleTriggerAction) -> str | None:
35+
if alert_rule_trigger_action.sentry_app_id:
36+
return Action.Type.SENTRY_APP
37+
38+
elif alert_rule_trigger_action.integration_id:
39+
integration = integration_service.get_integration(
40+
integration_id=alert_rule_trigger_action.integration_id
41+
)
42+
for type in Action.Type.choices:
43+
if type[0] == integration.provider:
44+
return type[1]
45+
return None
46+
else:
47+
return Action.Type.EMAIL
48+
49+
3350
def migrate_metric_action(
3451
alert_rule_trigger_action: AlertRuleTriggerAction,
3552
) -> tuple[Action, DataConditionGroupAction] | None:
@@ -44,19 +61,28 @@ def migrate_metric_action(
4461
)
4562
return None
4663

64+
action_type = get_action_type(alert_rule_trigger_action)
65+
if not action_type:
66+
logger.warning(
67+
"Could not find a matching Action.Type for the trigger action",
68+
extra={"alert_rule_trigger_action_id": alert_rule_trigger_action.id},
69+
)
70+
return None
71+
4772
data = {
4873
"type": alert_rule_trigger_action.type,
4974
"sentry_app_id": alert_rule_trigger_action.sentry_app_id,
5075
"sentry_app_config": alert_rule_trigger_action.sentry_app_config,
5176
}
5277
action = Action.objects.create(
5378
required=False,
54-
type=Action.Type.NOTIFICATION, # TODO: this is going to change to be the delivery method
79+
type=action_type,
5580
data=data,
5681
integration_id=alert_rule_trigger_action.integration_id,
5782
target_display=alert_rule_trigger_action.target_display,
5883
target_identifier=alert_rule_trigger_action.target_identifier,
5984
target_type=alert_rule_trigger_action.target_type,
85+
legacy_notification_type=Action.LegacyNotificationType.METRIC_ALERT,
6086
)
6187
data_condition_group_action = DataConditionGroupAction.objects.create(
6288
condition_group_id=alert_rule_trigger_data_condition.data_condition.condition_group.id,
@@ -109,10 +135,9 @@ def migrate_metric_data_condition(
109135
return None
110136

111137
data_condition = DataCondition.objects.create(
112-
condition=threshold_to_condition.get(threshold_type, AlertRuleThresholdType.ABOVE.value),
113138
comparison=alert_rule_trigger.alert_threshold,
114139
condition_result=condition_result,
115-
type=ConditionType.METRIC_CONDITION,
140+
type=threshold_to_condition.get(threshold_type, AlertRuleThresholdType.ABOVE.value),
116141
condition_group=data_condition_group,
117142
)
118143
alert_rule_trigger_data_condition = AlertRuleTriggerDataCondition.objects.create(

src/sentry/workflow_engine/models/action.py

+4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ class Action(DefaultFieldsModel):
3232
class Type(models.TextChoices):
3333
EMAIL = "email"
3434
SLACK = "slack"
35+
MSTEAMS = "msteams"
3536
PAGERDUTY = "pagerduty"
37+
OPSGENIE = "opsgenie"
38+
DISCORD = "discord"
39+
SENTRY_APP = "sentry_app"
3640
WEBHOOK = "webhook"
3741

3842
class LegacyNotificationType(models.TextChoices):

tests/sentry/workflow_engine/migration_helpers/test_migrate_alert_rule.py

+131-30
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
from unittest import mock
22

33
from sentry.incidents.grouptype import MetricAlertFire
4+
from sentry.incidents.models.alert_rule import AlertRuleTriggerAction
5+
from sentry.integrations.models.integration import Integration, OrganizationIntegration
46
from sentry.snuba.models import QuerySubscription
57
from sentry.testutils.cases import APITestCase
8+
from sentry.testutils.silo import assume_test_silo_mode_of
69
from sentry.users.services.user.service import user_service
710
from sentry.workflow_engine.migration_helpers.alert_rule import (
811
create_data_condition_group,
@@ -34,12 +37,58 @@
3437

3538
class AlertRuleMigrationHelpersTest(APITestCase):
3639
def setUp(self):
40+
METADATA = {
41+
"api_key": "1234-ABCD",
42+
"base_url": "https://api.opsgenie.com/",
43+
"domain_name": "test-app.app.opsgenie.com",
44+
}
45+
self.rpc_user = user_service.get_user(user_id=self.user.id)
46+
self.og_team = {"id": "123-id", "team": "cool-team", "integration_key": "1234-5678"}
47+
self.integration = self.create_provider_integration(
48+
provider="opsgenie", name="hello-world", external_id="hello-world", metadata=METADATA
49+
)
50+
self.sentry_app = self.create_sentry_app(
51+
name="foo",
52+
organization=self.organization,
53+
is_alertable=True,
54+
verify_install=False,
55+
)
56+
self.create_sentry_app_installation(
57+
slug=self.sentry_app.slug, organization=self.organization, user=self.rpc_user
58+
)
59+
with assume_test_silo_mode_of(Integration, OrganizationIntegration):
60+
self.integration.add_organization(self.organization, self.user)
61+
self.org_integration = OrganizationIntegration.objects.get(
62+
organization_id=self.organization.id, integration_id=self.integration.id
63+
)
64+
self.org_integration.config = {"team_table": [self.og_team]}
65+
self.org_integration.save()
66+
3767
self.metric_alert = self.create_alert_rule()
38-
self.alert_rule_trigger = self.create_alert_rule_trigger(alert_rule=self.metric_alert)
39-
self.alert_rule_trigger_action = self.create_alert_rule_trigger_action(
40-
alert_rule_trigger=self.alert_rule_trigger
68+
self.alert_rule_trigger_warning = self.create_alert_rule_trigger(
69+
alert_rule=self.metric_alert, label="warning"
70+
)
71+
self.alert_rule_trigger_critical = self.create_alert_rule_trigger(
72+
alert_rule=self.metric_alert, label="critical"
73+
)
74+
self.alert_rule_trigger_action_email = self.create_alert_rule_trigger_action(
75+
alert_rule_trigger=self.alert_rule_trigger_warning
76+
)
77+
self.alert_rule_trigger_action_integration = self.create_alert_rule_trigger_action(
78+
target_identifier=self.og_team["id"],
79+
type=AlertRuleTriggerAction.Type.OPSGENIE,
80+
target_type=AlertRuleTriggerAction.TargetType.SPECIFIC,
81+
integration=self.integration,
82+
alert_rule_trigger=self.alert_rule_trigger_critical,
83+
)
84+
85+
self.alert_rule_trigger_action_sentry_app = self.create_alert_rule_trigger_action(
86+
target_identifier=self.sentry_app.id,
87+
type=AlertRuleTriggerAction.Type.SENTRY_APP,
88+
target_type=AlertRuleTriggerAction.TargetType.SENTRY_APP,
89+
sentry_app=self.sentry_app,
90+
alert_rule_trigger=self.alert_rule_trigger_critical,
4191
)
42-
self.rpc_user = user_service.get_user(user_id=self.user.id)
4392

4493
def test_create_metric_alert(self):
4594
"""
@@ -92,25 +141,37 @@ def test_create_metric_alert(self):
92141

93142
def test_create_metric_alert_trigger(self):
94143
"""
95-
Test that when we call the helper methods we create all the ACI models correctly for an alert rule trigger
144+
Test that when we call the helper methods we create all the ACI models correctly for alert rule triggers
96145
"""
97146
migrate_alert_rule(self.metric_alert, self.rpc_user)
98-
migrate_metric_data_condition(self.alert_rule_trigger)
99-
alert_rule_trigger_data_condition = AlertRuleTriggerDataCondition.objects.get(
100-
alert_rule_trigger=self.alert_rule_trigger
101-
)
102-
data_condition_group_id = (
103-
alert_rule_trigger_data_condition.data_condition.condition_group.id
147+
migrate_metric_data_condition(self.alert_rule_trigger_warning)
148+
migrate_metric_data_condition(self.alert_rule_trigger_critical)
149+
150+
alert_rule_trigger_data_conditions = AlertRuleTriggerDataCondition.objects.filter(
151+
alert_rule_trigger__in=[
152+
self.alert_rule_trigger_critical,
153+
self.alert_rule_trigger_warning,
154+
]
104155
)
105-
data_condition = DataCondition.objects.get(condition_group=data_condition_group_id)
156+
assert len(alert_rule_trigger_data_conditions) == 2
157+
data_condition_group_id = alert_rule_trigger_data_conditions[
158+
0
159+
].data_condition.condition_group.id
160+
data_conditions = DataCondition.objects.filter(condition_group=data_condition_group_id)
161+
assert len(data_conditions) == 2
106162
alert_rule_workflow = AlertRuleWorkflow.objects.get(alert_rule=self.metric_alert)
107163
workflow = Workflow.objects.get(id=alert_rule_workflow.workflow.id)
108164
data_condition_group = workflow.when_condition_group
109165

110-
assert data_condition.condition == Condition.GREATER
111-
assert data_condition.comparison == self.alert_rule_trigger.alert_threshold
112-
assert data_condition.condition_result == DetectorPriorityLevel.HIGH
113-
assert data_condition.condition_group == data_condition_group
166+
assert data_conditions[0].type == Condition.GREATER
167+
assert data_conditions[0].comparison == self.alert_rule_trigger_warning.alert_threshold
168+
assert data_conditions[0].condition_result == DetectorPriorityLevel.MEDIUM
169+
assert data_conditions[0].condition_group == data_condition_group
170+
171+
assert data_conditions[1].type == Condition.GREATER
172+
assert data_conditions[1].comparison == self.alert_rule_trigger_critical.alert_threshold
173+
assert data_conditions[1].condition_result == DetectorPriorityLevel.HIGH
174+
assert data_conditions[1].condition_group == data_condition_group
114175

115176
@mock.patch("sentry.workflow_engine.migration_helpers.alert_rule.logger")
116177
def test_create_metric_alert_trigger_no_alert_rule_detector(self, mock_logger):
@@ -121,45 +182,85 @@ def test_create_metric_alert_trigger_no_alert_rule_detector(self, mock_logger):
121182
)
122183
create_detector(self.metric_alert, self.project.id, data_condition_group, self.rpc_user)
123184
# skip creating lookup tables
124-
migrate_metric_data_condition(self.alert_rule_trigger)
185+
migrate_metric_data_condition(self.alert_rule_trigger_critical)
125186
mock_logger.exception.assert_called_with(
126187
"AlertRuleDetector does not exist",
127188
extra={
128-
"alert_rule_id": self.alert_rule_trigger.alert_rule.id,
189+
"alert_rule_id": self.alert_rule_trigger_critical.alert_rule.id,
129190
},
130191
)
131192

132193
def test_create_metric_alert_trigger_action(self):
133194
"""
134-
Test that when we call the helper methods we create all the ACI models correctly for an alert rule trigger action
195+
Test that when we call the helper methods we create all the ACI models correctly for alert rule trigger actions
135196
"""
136197
migrate_alert_rule(self.metric_alert, self.rpc_user)
137-
migrate_metric_data_condition(self.alert_rule_trigger)
138-
migrate_metric_action(self.alert_rule_trigger_action)
139-
alert_rule_trigger_data_condition = AlertRuleTriggerDataCondition.objects.get(
140-
alert_rule_trigger=self.alert_rule_trigger
141-
)
142-
data_condition_group_id = (
143-
alert_rule_trigger_data_condition.data_condition.condition_group.id
198+
199+
migrate_metric_data_condition(self.alert_rule_trigger_warning)
200+
migrate_metric_data_condition(self.alert_rule_trigger_critical)
201+
202+
migrate_metric_action(self.alert_rule_trigger_action_email)
203+
migrate_metric_action(self.alert_rule_trigger_action_integration)
204+
migrate_metric_action(self.alert_rule_trigger_action_sentry_app)
205+
206+
alert_rule_trigger_data_condition = AlertRuleTriggerDataCondition.objects.filter(
207+
alert_rule_trigger__in=[
208+
self.alert_rule_trigger_warning,
209+
self.alert_rule_trigger_critical,
210+
]
144211
)
145-
data_condition_group_action = DataConditionGroupAction.objects.get(
212+
data_condition_group_id = alert_rule_trigger_data_condition[
213+
0
214+
].data_condition.condition_group.id
215+
data_condition_group_actions = DataConditionGroupAction.objects.filter(
146216
condition_group_id=data_condition_group_id
147217
)
148-
assert Action.objects.filter(id=data_condition_group_action.action.id).exists()
218+
action = Action.objects.filter(
219+
id__in=[item.action.id for item in data_condition_group_actions]
220+
)
221+
assert len(action) == 3
222+
223+
assert action[0].type.lower() == Action.Type.EMAIL
224+
assert action[1].type.lower() == Action.Type.OPSGENIE
225+
assert action[2].type.lower() == Action.Type.SENTRY_APP
149226

150227
@mock.patch("sentry.workflow_engine.migration_helpers.alert_rule.logger")
151228
def test_create_metric_alert_trigger_action_no_alert_rule_trigger_data_condition(
152229
self, mock_logger
153230
):
231+
"""
232+
Test that if the AlertRuleTriggerDataCondition doesn't exist we return None and log.
233+
"""
154234
other_metric_alert = self.create_alert_rule()
155235
other_alert_rule_trigger = self.create_alert_rule_trigger(alert_rule=other_metric_alert)
156236

157237
migrate_alert_rule(other_metric_alert, self.rpc_user)
158238
migrate_metric_data_condition(other_alert_rule_trigger)
159-
migrate_metric_action(self.alert_rule_trigger_action)
239+
migrated_action = migrate_metric_action(self.alert_rule_trigger_action_email)
240+
assert migrated_action is None
160241
mock_logger.exception.assert_called_with(
161242
"AlertRuleTriggerDataCondition does not exist",
162243
extra={
163-
"alert_rule_trigger_id": self.alert_rule_trigger.id,
244+
"alert_rule_trigger_id": self.alert_rule_trigger_warning.id,
245+
},
246+
)
247+
248+
@mock.patch("sentry.workflow_engine.migration_helpers.alert_rule.logger")
249+
def test_create_metric_alert_trigger_action_no_type(self, mock_logger):
250+
"""
251+
Test that if for some reason we don't find a match for Action.Type for the integratio provider we return None and log.
252+
"""
253+
with assume_test_silo_mode_of(Integration, OrganizationIntegration):
254+
self.integration.update(provider="hellboy")
255+
self.integration.save()
256+
257+
migrate_alert_rule(self.metric_alert, self.rpc_user)
258+
migrate_metric_data_condition(self.alert_rule_trigger_critical)
259+
migrated = migrate_metric_action(self.alert_rule_trigger_action_integration)
260+
assert migrated is None
261+
mock_logger.warning.assert_called_with(
262+
"Could not find a matching Action.Type for the trigger action",
263+
extra={
264+
"alert_rule_trigger_action_id": self.alert_rule_trigger_action_integration.id,
164265
},
165266
)

0 commit comments

Comments
 (0)