Просмотр исходного кода

feat(crons): Initial model for MonitorEnvironment (#45066)

Richard Ortenberg 2 лет назад
Родитель
Сommit
63ee3a3462

+ 1 - 1
migrations_lockfile.txt

@@ -6,5 +6,5 @@ To resolve this, rebase against latest master and regenerate your migration. Thi
 will then be regenerated, and you should be able to merge without conflicts.
 
 nodestore: 0002_nodestore_no_dictfield
-sentry: 0360_authenticator_config_type_change
+sentry: 0361_monitor_environment
 social_auth: 0001_initial

+ 66 - 0
src/sentry/migrations/0361_monitor_environment.py

@@ -0,0 +1,66 @@
+# Generated by Django 2.2.28 on 2023-02-24 00:38
+
+import django.db.models.deletion
+import django.utils.timezone
+from django.db import migrations, models
+
+import sentry.db.models.fields.bounded
+import sentry.db.models.fields.foreignkey
+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. For
+    # the most part, 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 dangerous:
+    # - Large data migrations. Typically we want these to be run manually by ops 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
+    #   have ops run this and not block the deploy. Note that while adding an index is a schema
+    #   change, it's completely safe to run the operation after the code has deployed.
+    is_dangerous = False
+
+    dependencies = [
+        ("sentry", "0360_authenticator_config_type_change"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="MonitorEnvironment",
+            fields=[
+                (
+                    "id",
+                    sentry.db.models.fields.bounded.BoundedBigAutoField(
+                        primary_key=True, serialize=False
+                    ),
+                ),
+                ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)),
+                ("next_checkin", models.DateTimeField(null=True)),
+                ("last_checkin", models.DateTimeField(null=True)),
+                ("date_added", models.DateTimeField(default=django.utils.timezone.now)),
+                (
+                    "environment",
+                    sentry.db.models.fields.foreignkey.FlexibleForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE, to="sentry.Environment"
+                    ),
+                ),
+                (
+                    "monitor",
+                    sentry.db.models.fields.foreignkey.FlexibleForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE, to="sentry.Monitor"
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "sentry_monitorenvironment",
+            },
+        ),
+        migrations.AddIndex(
+            model_name="monitorenvironment",
+            index=models.Index(
+                fields=["monitor", "environment"], name="sentry_moni_monitor_3d7eb9_idx"
+            ),
+        ),
+    ]

+ 1 - 0
src/sentry/models/__init__.py

@@ -63,6 +63,7 @@ from .latestreporeleaseenvironment import *  # NOQA
 from .lostpasswordhash import *  # NOQA
 from .monitor import *  # NOQA
 from .monitorcheckin import *  # NOQA
+from .monitorenvironment import *  # NOQA
 from .monitorlocation import *  # NOQA
 from .notificationsetting import *  # NOQA
 from .options import *  # NOQA

+ 32 - 0
src/sentry/models/monitorenvironment.py

@@ -0,0 +1,32 @@
+from django.db import models
+from django.utils import timezone
+
+from sentry.db.models import (
+    BoundedPositiveIntegerField,
+    FlexibleForeignKey,
+    Model,
+    region_silo_only_model,
+    sane_repr,
+)
+from sentry.models.monitor import MonitorStatus
+
+
+@region_silo_only_model
+class MonitorEnvironment(Model):
+    __include_in_export__ = True
+
+    monitor = FlexibleForeignKey("sentry.Monitor")
+    environment = FlexibleForeignKey("sentry.Environment")
+    status = BoundedPositiveIntegerField(
+        default=MonitorStatus.ACTIVE, choices=MonitorStatus.as_choices()
+    )
+    next_checkin = models.DateTimeField(null=True)
+    last_checkin = models.DateTimeField(null=True)
+    date_added = models.DateTimeField(default=timezone.now)
+
+    class Meta:
+        app_label = "sentry"
+        db_table = "sentry_monitorenvironment"
+        indexes = [models.Index(fields=["monitor", "environment"])]
+
+    __repr__ = sane_repr("monitor_id", "environment_id")

+ 23 - 0
tests/sentry/models/test_monitorenvironment.py

@@ -0,0 +1,23 @@
+from sentry.models import Environment, Monitor, MonitorEnvironment, MonitorType, ScheduleType
+from sentry.testutils import TestCase
+from sentry.testutils.silo import region_silo_test
+
+
+@region_silo_test(stable=True)
+class MonitorEnvironmentTestCase(TestCase):
+    def test_monitor_environment(self):
+        project = self.project
+        environment = Environment.get_or_create(project, "production")
+
+        monitor = Monitor.objects.create(
+            organization_id=self.organization.id,
+            project_id=self.project.id,
+            type=MonitorType.CRON_JOB,
+            config={"schedule": [1, "month"], "schedule_type": ScheduleType.INTERVAL},
+        )
+
+        production_monitor = MonitorEnvironment.objects.create(
+            monitor=monitor, environment=environment
+        )
+
+        assert type(production_monitor) == MonitorEnvironment