Skip to content

Commit

Permalink
feat(workflow_engine): Add Detector model (#77298)
Browse files Browse the repository at this point in the history
This adds in the Detector model and boilerplate needed to create it

<!-- Describe your PR here. -->
  • Loading branch information
wedamija authored Sep 11, 2024
1 parent c2d3da9 commit 0aed6c4
Show file tree
Hide file tree
Showing 16 changed files with 233 additions and 9 deletions.
33 changes: 33 additions & 0 deletions fixtures/backup/model_dependencies/detailed.json
Original file line number Diff line number Diff line change
Expand Up @@ -6218,6 +6218,39 @@
"table_name": "workflow_engine_datasource",
"uniques": []
},
"workflow_engine.detector": {
"dangling": false,
"foreign_keys": {
"organization": {
"kind": "FlexibleForeignKey",
"model": "sentry.organization",
"nullable": false
},
"owner_team": {
"kind": "FlexibleForeignKey",
"model": "sentry.team",
"nullable": true
},
"owner_user_id": {
"kind": "HybridCloudForeignKey",
"model": "sentry.user",
"nullable": true
}
},
"model": "workflow_engine.detector",
"relocation_dependencies": [],
"relocation_scope": "Organization",
"silos": [
"Region"
],
"table_name": "workflow_engine_detector",
"uniques": [
[
"name",
"organization"
]
]
},
"workflow_engine.workflow": {
"dangling": false,
"foreign_keys": {
Expand Down
5 changes: 5 additions & 0 deletions fixtures/backup/model_dependencies/flat.json
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,11 @@
"workflow_engine.datasource": [
"sentry.organization"
],
"workflow_engine.detector": [
"sentry.organization",
"sentry.team",
"sentry.user"
],
"workflow_engine.workflow": [
"sentry.organization"
]
Expand Down
1 change: 1 addition & 0 deletions fixtures/backup/model_dependencies/sorted.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"social_auth.usersocialauth",
"uptime.uptimesubscription",
"workflow_engine.datasource",
"workflow_engine.detector",
"workflow_engine.workflow",
"sentry.savedsearch",
"sentry.relocation",
Expand Down
1 change: 1 addition & 0 deletions fixtures/backup/model_dependencies/truncate.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"social_auth_usersocialauth",
"uptime_uptimesubscription",
"workflow_engine_datasource",
"workflow_engine_detector",
"workflow_engine_workflow",
"sentry_savedsearch",
"sentry_relocation",
Expand Down
2 changes: 1 addition & 1 deletion migrations_lockfile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ replays: 0004_index_together
sentry: 0759_remove_spanattributeextraction_tables
social_auth: 0002_default_auto_field
uptime: 0008_uptime_url_suffix
workflow_engine: 0002_data_source
workflow_engine: 0003_detector
1 change: 1 addition & 0 deletions src/sentry/backup/comparators.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@ def get_default_comparators() -> dict[str, list[JSONScrubbingComparator]]:
"sentry.userrole": [DateUpdatedComparator("date_updated")],
"sentry.userroleuser": [DateUpdatedComparator("date_updated")],
"workflow_engine.datasource": [DateUpdatedComparator("date_updated", "date_added")],
"workflow_engine.detector": [DateUpdatedComparator("date_updated", "date_added")],
"workflow_engine.workflow": [DateUpdatedComparator("date_updated", "date_added")],
},
)
Expand Down
36 changes: 36 additions & 0 deletions src/sentry/models/owner_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from __future__ import annotations

from django.conf import settings
from django.db import models
from django.db.models import BaseConstraint

from sentry.db.models import FlexibleForeignKey, Model
from sentry.db.models.fields.hybrid_cloud_foreign_key import HybridCloudForeignKey
from sentry.types.actor import Actor


class OwnerModel(Model):
"""
A base model that adds ownership fields to existing models.
"""

owner_user_id = HybridCloudForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete="SET_NULL")
owner_team = FlexibleForeignKey("sentry.Team", null=True, on_delete=models.SET_NULL)

class Meta:
abstract = True

constraints: list[BaseConstraint] = [
models.CheckConstraint(
condition=(
models.Q(owner_user_id__isnull=True, owner_team__isnull=False)
| models.Q(owner_user_id__isnull=False, owner_team__isnull=True)
| models.Q(owner_user_id__isnull=True, owner_team__isnull=True)
),
name="%(app_label)s_%(class)s_owner_constraints",
),
]

@property
def owner(self) -> Actor | None:
return Actor.from_id(user_id=self.owner_user_id, team_id=self.owner_team_id)
23 changes: 20 additions & 3 deletions src/sentry/testutils/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
from sentry.users.services.user import RpcUser
from sentry.utils import loremipsum
from sentry.utils.performance_issues.performance_problem import PerformanceProblem
from sentry.workflow_engine.models import DataSource, Workflow
from sentry.workflow_engine.models import DataSource, Detector, Workflow
from social_auth.models import UserSocialAuth


Expand Down Expand Up @@ -2038,7 +2038,7 @@ def create_workflow(
name: str | None = None,
organization: Organization | None = None,
**kwargs,
):
) -> Workflow:
if organization is None:
organization = Factories.create_organization()
if name is None:
Expand All @@ -2052,11 +2052,28 @@ def create_datasource(
query_id: int | None = None,
type: DataSource.Type | None = None,
**kwargs,
):
) -> DataSource:
if organization is None:
organization = Factories.create_organization()
if query_id is None:
query_id = random.randint(1, 10000)
if type is None:
type = DataSource.Type.SNUBA_QUERY_SUBSCRIPTION
return DataSource.objects.create(organization=organization, query_id=query_id, type=type)

@staticmethod
@assume_test_silo_mode(SiloMode.REGION)
def create_detector(
organization: Organization | None = None,
name: str | None = None,
owner_user_id: int | None = None,
owner_team: Team | None = None,
**kwargs,
) -> Detector:
if organization is None:
organization = Factories.create_organization()
if name is None:
name = petname.generate(2, " ", letters=10).title()
return Detector.objects.create(
organization=organization, name=name, owner_user_id=owner_user_id, owner_team=owner_team
)
3 changes: 3 additions & 0 deletions src/sentry/testutils/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,9 @@ def create_workflow(self, *args, **kwargs):
def create_datasource(self, *args, **kwargs):
return Factories.create_datasource(*args, **kwargs)

def create_detector(self, *args, **kwargs):
return Factories.create_detector(*args, **kwargs)

def create_uptime_subscription(
self,
type: str = "test",
Expand Down
1 change: 1 addition & 0 deletions src/sentry/testutils/helpers/backups.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ def create_exhaustive_organization(

self.create_workflow(organization=org)
self.create_datasource(organization=org)
self.create_detector(organization=org)

return org

Expand Down
86 changes: 86 additions & 0 deletions src/sentry/workflow_engine/migrations/0003_detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Generated by Django 5.1.1 on 2024-09-11 21:13

import django.db.models.deletion
from django.db import migrations, models

import sentry.db.models.fields.bounded
import sentry.db.models.fields.foreignkey
import sentry.db.models.fields.hybrid_cloud_foreign_key
from sentry.new_migrations.migrations import CheckedMigration


class Migration(CheckedMigration):
# This flag is used to mark that a migration shouldn't be automatically run in production.
# This should only be used for operations where it's safe to run the migration after your
# code has deployed. So this should not be used for most operations that alter the schema
# of a table.
# Here are some things that make sense to mark as post deployment:
# - Large data migrations. Typically we want these to be run manually so that they can be
# monitored and not block the deploy for a long period of time while they run.
# - Adding indexes to large tables. Since this can take a long time, we'd generally prefer to
# run this outside deployments so that we don't block them. Note that while adding an index
# is a schema change, it's completely safe to run the operation after the code has deployed.
# Once deployed, run these manually via: https://develop.sentry.dev/database-migrations/#migration-deployment

is_post_deployment = False

dependencies = [
("sentry", "0759_remove_spanattributeextraction_tables"),
("workflow_engine", "0002_data_source"),
]

operations = [
migrations.CreateModel(
name="Detector",
fields=[
(
"id",
sentry.db.models.fields.bounded.BoundedBigAutoField(
primary_key=True, serialize=False
),
),
("date_updated", models.DateTimeField(auto_now=True)),
("date_added", models.DateTimeField(auto_now_add=True)),
(
"owner_user_id",
sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey(
"sentry.User", db_index=True, null=True, on_delete="SET_NULL"
),
),
("name", models.CharField(max_length=200)),
(
"organization",
sentry.db.models.fields.foreignkey.FlexibleForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="sentry.organization"
),
),
(
"owner_team",
sentry.db.models.fields.foreignkey.FlexibleForeignKey(
null=True, on_delete=django.db.models.deletion.SET_NULL, to="sentry.team"
),
),
],
options={
"abstract": False,
"constraints": [
models.CheckConstraint(
condition=models.Q(
models.Q(
("owner_team__isnull", False), ("owner_user_id__isnull", True)
),
models.Q(
("owner_team__isnull", True), ("owner_user_id__isnull", False)
),
models.Q(("owner_team__isnull", True), ("owner_user_id__isnull", True)),
_connector="OR",
),
name="workflow_engine_detector_owner_constraints",
),
models.UniqueConstraint(
fields=("organization", "name"), name="workflow_engine_detector_org_name"
),
],
},
),
]
3 changes: 2 additions & 1 deletion src/sentry/workflow_engine/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
__all__ = ["DataSource", "Workflow"]
__all__ = ["DataSource", "Detector", "Workflow"]

from .data_source import DataSource
from .detector import Detector
from .workflow import Workflow
22 changes: 22 additions & 0 deletions src/sentry/workflow_engine/models/detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from django.db import models
from django.db.models import UniqueConstraint

from sentry.backup.scopes import RelocationScope
from sentry.db.models import DefaultFieldsModel, FlexibleForeignKey, region_silo_model
from sentry.models.owner_base import OwnerModel


@region_silo_model
class Detector(DefaultFieldsModel, OwnerModel):
__relocation_scope__ = RelocationScope.Organization

organization = FlexibleForeignKey("sentry.Organization")
name = models.CharField(max_length=200)

class Meta(OwnerModel.Meta):
constraints = OwnerModel.Meta.constraints + [
UniqueConstraint(
fields=["organization", "name"],
name="workflow_engine_detector_org_name",
)
]
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
created: '2024-09-10T22:26:24.920905+00:00'
created: '2024-09-10T23:34:32.337196+00:00'
creator: sentry
source: tests/sentry/backup/test_sanitize.py
---
Expand Down Expand Up @@ -217,6 +217,12 @@ source: tests/sentry/backup/test_sanitize.py
sanitized_fields:
- date_added
- date_updated
- model_name: workflow_engine.detector
ordinal: 1
sanitized_fields:
- date_added
- date_updated
- name
- model_name: workflow_engine.workflow
ordinal: 1
sanitized_fields:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
created: '2024-09-10T22:25:01.144002+00:00'
created: '2024-09-10T23:35:41.229560+00:00'
creator: sentry
source: tests/sentry/backup/test_comparators.py
---
Expand Down Expand Up @@ -1616,6 +1616,17 @@ source: tests/sentry/backup/test_comparators.py
fields:
- organization
model_name: workflow_engine.datasource
- comparators:
- class: DateUpdatedComparator
fields:
- date_added
- date_updated
- class: ForeignKeyComparator
fields:
- organization
- owner_team
- owner_user_id
model_name: workflow_engine.detector
- comparators:
- class: DateUpdatedComparator
fields:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
created: '2024-09-10T22:24:28.399110+00:00'
created: '2024-09-10T23:35:05.993533+00:00'
creator: sentry
source: tests/sentry/tasks/test_relocation.py
---
Expand Down Expand Up @@ -96,7 +96,7 @@ steps:
- -U
- postgres
- -c
- TRUNCATE sentry_controloption,sentry_integration,sentry_option,sentry_organization,sentry_organizationintegration,sentry_organizationoptions,sentry_projecttemplate,sentry_projecttemplateoption,sentry_relay,sentry_relayusage,sentry_repository,sentry_team,auth_user,sentry_userip,sentry_userpermission,sentry_userrole,sentry_userrole_users,workflow_engine_datasource,workflow_engine_workflow,sentry_savedsearch,sentry_recentsearch,sentry_project,sentry_orgauthtoken,sentry_organizationmember,sentry_organizationaccessrequest,sentry_monitor,sentry_groupsearchview,sentry_environment,sentry_email,sentry_datasecrecywaiver,sentry_dashboardtombstone,sentry_dashboard,sentry_customdynamicsamplingrule,sentry_projectcounter,sentry_authprovider,sentry_authidentity,auth_authenticator,sentry_apikey,sentry_apiapplication,sentry_useroption,sentry_useremail,sentry_snubaquery,sentry_sentryapp,sentry_rule,sentry_querysubscription,sentry_projectteam,sentry_projectredirect,sentry_projectownership,sentry_projectoptions,sentry_projectkey,sentry_projectintegration,sentry_projectbookmark,sentry_organizationmember_teams,sentry_notificationaction,sentry_neglectedrule,sentry_environmentproject,sentry_dashboardwidget,sentry_customdynamicsamplingruleproject,sentry_apitoken,sentry_apigrant,sentry_apiauthorization,sentry_alertrule,sentry_snubaqueryeventtype,sentry_sentryappinstallation,sentry_sentryappcomponent,sentry_rulesnooze,sentry_ruleactivity,sentry_notificationactionproject,sentry_dashboardwidgetquery,sentry_alertruletrigger,sentry_alertruleprojects,sentry_alertruleexcludedprojects,sentry_alertruleactivity,sentry_alertruleactivationcondition,sentry_servicehook,sentry_incident,sentry_dashboardwidgetqueryondemand,sentry_alertruletriggerexclusion,sentry_alertruletriggeraction,sentry_timeseriessnapshot,sentry_pendingincidentsnapshot,sentry_incidenttrigger,sentry_incidentsubscription,sentry_incidentsnapshot,sentry_incidentactivity
- TRUNCATE sentry_controloption,sentry_integration,sentry_option,sentry_organization,sentry_organizationintegration,sentry_organizationoptions,sentry_projecttemplate,sentry_projecttemplateoption,sentry_relay,sentry_relayusage,sentry_repository,sentry_team,auth_user,sentry_userip,sentry_userpermission,sentry_userrole,sentry_userrole_users,workflow_engine_datasource,workflow_engine_detector,workflow_engine_workflow,sentry_savedsearch,sentry_recentsearch,sentry_project,sentry_orgauthtoken,sentry_organizationmember,sentry_organizationaccessrequest,sentry_monitor,sentry_groupsearchview,sentry_environment,sentry_email,sentry_datasecrecywaiver,sentry_dashboardtombstone,sentry_dashboard,sentry_customdynamicsamplingrule,sentry_projectcounter,sentry_authprovider,sentry_authidentity,auth_authenticator,sentry_apikey,sentry_apiapplication,sentry_useroption,sentry_useremail,sentry_snubaquery,sentry_sentryapp,sentry_rule,sentry_querysubscription,sentry_projectteam,sentry_projectredirect,sentry_projectownership,sentry_projectoptions,sentry_projectkey,sentry_projectintegration,sentry_projectbookmark,sentry_organizationmember_teams,sentry_notificationaction,sentry_neglectedrule,sentry_environmentproject,sentry_dashboardwidget,sentry_customdynamicsamplingruleproject,sentry_apitoken,sentry_apigrant,sentry_apiauthorization,sentry_alertrule,sentry_snubaqueryeventtype,sentry_sentryappinstallation,sentry_sentryappcomponent,sentry_rulesnooze,sentry_ruleactivity,sentry_notificationactionproject,sentry_dashboardwidgetquery,sentry_alertruletrigger,sentry_alertruleprojects,sentry_alertruleexcludedprojects,sentry_alertruleactivity,sentry_alertruleactivationcondition,sentry_servicehook,sentry_incident,sentry_dashboardwidgetqueryondemand,sentry_alertruletriggerexclusion,sentry_alertruletriggeraction,sentry_timeseriessnapshot,sentry_pendingincidentsnapshot,sentry_incidenttrigger,sentry_incidentsubscription,sentry_incidentsnapshot,sentry_incidentactivity
RESTART IDENTITY CASCADE;
id: clear-database
name: gcr.io/cloud-builders/docker
Expand Down

0 comments on commit 0aed6c4

Please sign in to comment.