chore: remove references to SlackMessage._channel_id (#5325)
# What this PR does - As a follow-up to https://github.com/grafana/oncall/pull/5292, and now that `SlackMessage.channel` has been migrated via [`engine/apps/slack/migrations/0007_migrate_slackmessage_channel_id.py`](https://github.com/grafana/oncall/pull/5292/files#diff-8aebe133401715a4262baad9b2c5c9fc59367c18d6bd6ac2b3c462fcdabafd66), this PR removes reads/writes from `SlackMessage._channel_id` to `SlackMessage.channel`. In a separate PR I will focus on dropping that column from the model/db. - Drops `SlackMessage.active_update_task_id`. There're zero references to this column in the codebase. - Removes two Django `manage.py` commands that're no longer needed: - `engine/engine/management/commands/alertmanager_v2_migrate.py` (and it's associated tests) - `engine/engine/management/commands/batch_migrate_slack_message_channel.py` ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] Added the relevant release notes label (see labels prefixed w/ `release:`). These labels dictate how your PR will show up in the autogenerated release notes.
This commit is contained in:
parent
710fb8bbc2
commit
3977c6e9ef
22 changed files with 73 additions and 755 deletions
|
|
@ -417,6 +417,10 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models.
|
|||
)
|
||||
|
||||
prevent_posting_alerts = models.BooleanField(default=False)
|
||||
"""
|
||||
TODO: this column is no longer used, drop it in a subsequent PR/release
|
||||
"""
|
||||
|
||||
maintenance_uuid = models.CharField(max_length=100, unique=True, null=True, default=None)
|
||||
|
||||
raw_escalation_snapshot = JSONField(null=True, default=None)
|
||||
|
|
@ -1983,11 +1987,7 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models.
|
|||
channel_filter = self.channel_filter
|
||||
|
||||
if self.slack_message:
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
#
|
||||
# return self.slack_message.channel.slack_id
|
||||
return self.slack_message._channel_id
|
||||
return self.slack_message.channel.slack_id
|
||||
elif channel_filter and channel_filter.slack_channel_or_org_default:
|
||||
return channel_filter.slack_channel_or_org_default.slack_id
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -827,8 +827,8 @@ class TestAlertGroupSlackChannelID:
|
|||
slack_channel = make_slack_channel(slack_team_identity)
|
||||
slack_message = make_slack_message(slack_channel, alert_group=alert_group)
|
||||
|
||||
# Assert that slack_channel_id returns the _channel_id from slack_message
|
||||
assert alert_group.slack_channel_id == slack_message._channel_id
|
||||
# Assert that slack_channel_id returns the channel.slack_id from slack_message
|
||||
assert alert_group.slack_channel_id == slack_message.channel.slack_id
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_slack_channel_id_with_channel_filter(
|
||||
|
|
|
|||
|
|
@ -6,12 +6,10 @@ import pytest
|
|||
from django.conf import settings
|
||||
from django.db import IntegrityError
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.alerts.models import AlertReceiveChannel
|
||||
from common.api_helpers.utils import create_engine_url
|
||||
from common.exceptions import UnableToSendDemoAlert
|
||||
from engine.management.commands import alertmanager_v2_migrate
|
||||
from settings.base import DatabaseTypes
|
||||
|
||||
|
||||
|
|
@ -306,381 +304,3 @@ def test_create_duplicate_direct_paging_integrations(make_organization, make_tea
|
|||
integration=AlertReceiveChannel.INTEGRATION_DIRECT_PAGING,
|
||||
)
|
||||
super(AlertReceiveChannel, arc).save() # bypass the custom save method, so that IntegrityError is raised
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_alertmanager_v2_migrate_forward(make_organization, make_alert_receive_channel):
|
||||
organization = make_organization()
|
||||
|
||||
legacy_alertmanager = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_LEGACY_ALERTMANAGER,
|
||||
slack_title_template="slack_title_template",
|
||||
web_title_template="web_title_template",
|
||||
grouping_id_template="grouping_id_template",
|
||||
resolve_condition_template="resolve_condition_template",
|
||||
)
|
||||
|
||||
alertmanager = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_ALERTMANAGER,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
legacy_grafana_alerting = make_alert_receive_channel(
|
||||
organization, integration=AlertReceiveChannel.INTEGRATION_LEGACY_GRAFANA_ALERTING
|
||||
)
|
||||
grafana_alerting = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
|
||||
alertmanager_v2_migrate.Command().handle(backward=False)
|
||||
|
||||
legacy_alertmanager.refresh_from_db()
|
||||
alertmanager.refresh_from_db()
|
||||
legacy_grafana_alerting.refresh_from_db()
|
||||
grafana_alerting.refresh_from_db()
|
||||
|
||||
assert legacy_alertmanager.integration == AlertReceiveChannel.INTEGRATION_ALERTMANAGER
|
||||
assert legacy_alertmanager.alertmanager_v2_migrated_at is not None
|
||||
assert legacy_alertmanager.slack_title_template is None
|
||||
assert legacy_alertmanager.web_title_template is None
|
||||
assert legacy_alertmanager.grouping_id_template is None
|
||||
assert legacy_alertmanager.resolve_condition_template is None
|
||||
assert legacy_alertmanager.alertmanager_v2_backup_templates["slack_title_template"] == "slack_title_template"
|
||||
assert legacy_alertmanager.alertmanager_v2_backup_templates["web_title_template"] == "web_title_template"
|
||||
assert legacy_alertmanager.alertmanager_v2_backup_templates["grouping_id_template"] == "grouping_id_template"
|
||||
assert (
|
||||
legacy_alertmanager.alertmanager_v2_backup_templates["resolve_condition_template"]
|
||||
== "resolve_condition_template"
|
||||
)
|
||||
assert legacy_alertmanager.alertmanager_v2_backup_templates["messaging_backends_templates"] is None
|
||||
|
||||
assert legacy_grafana_alerting.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING
|
||||
assert legacy_grafana_alerting.alertmanager_v2_migrated_at is not None
|
||||
assert legacy_grafana_alerting.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert alertmanager.integration == AlertReceiveChannel.INTEGRATION_ALERTMANAGER
|
||||
assert alertmanager.alertmanager_v2_migrated_at is None
|
||||
assert alertmanager.slack_title_template == "slack_title_template"
|
||||
assert alertmanager.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert grafana_alerting.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING
|
||||
assert grafana_alerting.alertmanager_v2_migrated_at is None
|
||||
assert grafana_alerting.slack_title_template == "slack_title_template"
|
||||
assert grafana_alerting.alertmanager_v2_backup_templates is None
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_alertmanager_v2_migrate_backward(make_organization, make_alert_receive_channel):
|
||||
organization = make_organization()
|
||||
|
||||
migrated_alertmanager = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_ALERTMANAGER,
|
||||
alertmanager_v2_migrated_at=timezone.now(),
|
||||
alertmanager_v2_backup_templates={
|
||||
"slack_title_template": "slack_title_template",
|
||||
"web_title_template": "web_title_template",
|
||||
"grouping_id_template": "grouping_id_template",
|
||||
"resolve_condition_template": "resolve_condition_template",
|
||||
},
|
||||
)
|
||||
|
||||
alertmanager = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_ALERTMANAGER,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
migrated_grafana_alerting = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING,
|
||||
alertmanager_v2_migrated_at=timezone.now(),
|
||||
)
|
||||
grafana_alerting = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
|
||||
alertmanager_v2_migrate.Command().handle(backward=True)
|
||||
|
||||
migrated_alertmanager.refresh_from_db()
|
||||
alertmanager.refresh_from_db()
|
||||
migrated_grafana_alerting.refresh_from_db()
|
||||
grafana_alerting.refresh_from_db()
|
||||
|
||||
assert migrated_alertmanager.integration == AlertReceiveChannel.INTEGRATION_LEGACY_ALERTMANAGER
|
||||
assert migrated_alertmanager.alertmanager_v2_migrated_at is None
|
||||
assert migrated_alertmanager.slack_title_template == "slack_title_template"
|
||||
assert migrated_alertmanager.web_title_template == "web_title_template"
|
||||
assert migrated_alertmanager.grouping_id_template == "grouping_id_template"
|
||||
assert migrated_alertmanager.resolve_condition_template == "resolve_condition_template"
|
||||
assert migrated_alertmanager.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert migrated_grafana_alerting.integration == AlertReceiveChannel.INTEGRATION_LEGACY_GRAFANA_ALERTING
|
||||
assert migrated_grafana_alerting.alertmanager_v2_migrated_at is None
|
||||
assert migrated_grafana_alerting.slack_title_template is None
|
||||
assert migrated_grafana_alerting.web_title_template is None
|
||||
assert migrated_grafana_alerting.grouping_id_template is None
|
||||
assert migrated_grafana_alerting.resolve_condition_template is None
|
||||
assert migrated_grafana_alerting.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert alertmanager.integration == AlertReceiveChannel.INTEGRATION_ALERTMANAGER
|
||||
assert alertmanager.alertmanager_v2_migrated_at is None
|
||||
assert alertmanager.slack_title_template == "slack_title_template"
|
||||
assert alertmanager.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert grafana_alerting.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING
|
||||
assert grafana_alerting.alertmanager_v2_migrated_at is None
|
||||
assert grafana_alerting.slack_title_template == "slack_title_template"
|
||||
assert grafana_alerting.alertmanager_v2_backup_templates is None
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_alertmanager_v2_migrate_forward_one(make_organization, make_alert_receive_channel):
|
||||
organization = make_organization()
|
||||
# org which is not going to be migrated
|
||||
organization_2 = make_organization()
|
||||
|
||||
legacy_alertmanager = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_LEGACY_ALERTMANAGER,
|
||||
slack_title_template="slack_title_template",
|
||||
web_title_template="web_title_template",
|
||||
grouping_id_template="grouping_id_template",
|
||||
resolve_condition_template="resolve_condition_template",
|
||||
)
|
||||
alertmanager = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_ALERTMANAGER,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
legacy_grafana_alerting = make_alert_receive_channel(
|
||||
organization, integration=AlertReceiveChannel.INTEGRATION_LEGACY_GRAFANA_ALERTING
|
||||
)
|
||||
grafana_alerting = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
|
||||
# set up same set integrations for second org
|
||||
legacy_alertmanager_2 = make_alert_receive_channel(
|
||||
organization_2,
|
||||
integration=AlertReceiveChannel.INTEGRATION_LEGACY_ALERTMANAGER,
|
||||
slack_title_template="slack_title_template",
|
||||
web_title_template="web_title_template",
|
||||
grouping_id_template="grouping_id_template",
|
||||
resolve_condition_template="resolve_condition_template",
|
||||
)
|
||||
alertmanager_2 = make_alert_receive_channel(
|
||||
organization_2,
|
||||
integration=AlertReceiveChannel.INTEGRATION_ALERTMANAGER,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
legacy_grafana_alerting_2 = make_alert_receive_channel(
|
||||
organization_2, integration=AlertReceiveChannel.INTEGRATION_LEGACY_GRAFANA_ALERTING
|
||||
)
|
||||
grafana_alerting_2 = make_alert_receive_channel(
|
||||
organization_2,
|
||||
integration=AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
|
||||
alertmanager_v2_migrate.Command().handle(backward=False, org_id=organization.id)
|
||||
|
||||
legacy_alertmanager.refresh_from_db()
|
||||
alertmanager.refresh_from_db()
|
||||
legacy_grafana_alerting.refresh_from_db()
|
||||
grafana_alerting.refresh_from_db()
|
||||
|
||||
legacy_alertmanager_2.refresh_from_db()
|
||||
alertmanager_2.refresh_from_db()
|
||||
legacy_grafana_alerting_2.refresh_from_db()
|
||||
grafana_alerting_2.refresh_from_db()
|
||||
|
||||
assert legacy_alertmanager.integration == AlertReceiveChannel.INTEGRATION_ALERTMANAGER
|
||||
assert legacy_alertmanager.alertmanager_v2_migrated_at is not None
|
||||
assert legacy_alertmanager.slack_title_template is None
|
||||
assert legacy_alertmanager.web_title_template is None
|
||||
assert legacy_alertmanager.grouping_id_template is None
|
||||
assert legacy_alertmanager.resolve_condition_template is None
|
||||
assert legacy_alertmanager.alertmanager_v2_backup_templates["slack_title_template"] == "slack_title_template"
|
||||
assert legacy_alertmanager.alertmanager_v2_backup_templates["web_title_template"] == "web_title_template"
|
||||
assert legacy_alertmanager.alertmanager_v2_backup_templates["grouping_id_template"] == "grouping_id_template"
|
||||
assert (
|
||||
legacy_alertmanager.alertmanager_v2_backup_templates["resolve_condition_template"]
|
||||
== "resolve_condition_template"
|
||||
)
|
||||
assert legacy_alertmanager.alertmanager_v2_backup_templates["messaging_backends_templates"] is None
|
||||
|
||||
assert legacy_grafana_alerting.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING
|
||||
assert legacy_grafana_alerting.alertmanager_v2_migrated_at is not None
|
||||
assert legacy_grafana_alerting.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert alertmanager.integration == AlertReceiveChannel.INTEGRATION_ALERTMANAGER
|
||||
assert alertmanager.alertmanager_v2_migrated_at is None
|
||||
assert alertmanager.slack_title_template == "slack_title_template"
|
||||
assert alertmanager.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert grafana_alerting.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING
|
||||
assert grafana_alerting.alertmanager_v2_migrated_at is None
|
||||
assert grafana_alerting.slack_title_template == "slack_title_template"
|
||||
assert grafana_alerting.alertmanager_v2_backup_templates is None
|
||||
|
||||
# check that second org is NOT affected
|
||||
|
||||
# check that legacy alertmanager not affected
|
||||
assert legacy_alertmanager_2.integration == AlertReceiveChannel.INTEGRATION_LEGACY_ALERTMANAGER
|
||||
assert legacy_alertmanager_2.alertmanager_v2_migrated_at is None
|
||||
assert legacy_alertmanager_2.slack_title_template == "slack_title_template"
|
||||
assert legacy_alertmanager_2.web_title_template == "web_title_template"
|
||||
assert legacy_alertmanager_2.grouping_id_template == "grouping_id_template"
|
||||
assert legacy_alertmanager_2.resolve_condition_template == "resolve_condition_template"
|
||||
assert legacy_alertmanager_2.alertmanager_v2_backup_templates is None
|
||||
|
||||
# check that legacy grafana_alerting not affected
|
||||
assert legacy_grafana_alerting_2.integration == AlertReceiveChannel.INTEGRATION_LEGACY_GRAFANA_ALERTING
|
||||
assert legacy_grafana_alerting_2.alertmanager_v2_migrated_at is None
|
||||
assert legacy_grafana_alerting_2.alertmanager_v2_backup_templates is None
|
||||
|
||||
# check that alertmanager which shouldn't be affected even by migration not touched
|
||||
assert alertmanager_2.integration == AlertReceiveChannel.INTEGRATION_ALERTMANAGER
|
||||
assert alertmanager_2.alertmanager_v2_migrated_at is None
|
||||
assert alertmanager_2.slack_title_template == "slack_title_template"
|
||||
assert alertmanager_2.alertmanager_v2_backup_templates is None
|
||||
|
||||
# same fpr grafana alerting
|
||||
assert grafana_alerting_2.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING
|
||||
assert grafana_alerting_2.alertmanager_v2_migrated_at is None
|
||||
assert grafana_alerting_2.slack_title_template == "slack_title_template"
|
||||
assert grafana_alerting_2.alertmanager_v2_backup_templates is None
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_alertmanager_v2_migrate_backward_one(make_organization, make_alert_receive_channel):
|
||||
organization = make_organization()
|
||||
|
||||
migrated_alertmanager = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_ALERTMANAGER,
|
||||
alertmanager_v2_migrated_at=timezone.now(),
|
||||
alertmanager_v2_backup_templates={
|
||||
"slack_title_template": "slack_title_template",
|
||||
"web_title_template": "web_title_template",
|
||||
"grouping_id_template": "grouping_id_template",
|
||||
"resolve_condition_template": "resolve_condition_template",
|
||||
},
|
||||
)
|
||||
|
||||
alertmanager = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_ALERTMANAGER,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
migrated_grafana_alerting = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING,
|
||||
alertmanager_v2_migrated_at=timezone.now(),
|
||||
)
|
||||
grafana_alerting = make_alert_receive_channel(
|
||||
organization,
|
||||
integration=AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
|
||||
organization_2 = make_organization()
|
||||
|
||||
migrated_alertmanager_2 = make_alert_receive_channel(
|
||||
organization_2,
|
||||
integration=AlertReceiveChannel.INTEGRATION_ALERTMANAGER,
|
||||
alertmanager_v2_migrated_at=timezone.now(),
|
||||
alertmanager_v2_backup_templates={
|
||||
"slack_title_template": "slack_title_template",
|
||||
"web_title_template": "web_title_template",
|
||||
"grouping_id_template": "grouping_id_template",
|
||||
"resolve_condition_template": "resolve_condition_template",
|
||||
},
|
||||
)
|
||||
alertmanager_2 = make_alert_receive_channel(
|
||||
organization_2,
|
||||
integration=AlertReceiveChannel.INTEGRATION_ALERTMANAGER,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
migrated_grafana_alerting_2 = make_alert_receive_channel(
|
||||
organization_2,
|
||||
integration=AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING,
|
||||
alertmanager_v2_migrated_at=timezone.now(),
|
||||
)
|
||||
grafana_alerting_2 = make_alert_receive_channel(
|
||||
organization_2,
|
||||
integration=AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING,
|
||||
slack_title_template="slack_title_template",
|
||||
)
|
||||
|
||||
alertmanager_v2_migrate.Command().handle(backward=True, org_id=organization.id)
|
||||
|
||||
migrated_alertmanager.refresh_from_db()
|
||||
alertmanager.refresh_from_db()
|
||||
migrated_grafana_alerting.refresh_from_db()
|
||||
grafana_alerting.refresh_from_db()
|
||||
|
||||
assert migrated_alertmanager.integration == AlertReceiveChannel.INTEGRATION_LEGACY_ALERTMANAGER
|
||||
assert migrated_alertmanager.alertmanager_v2_migrated_at is None
|
||||
assert migrated_alertmanager.slack_title_template == "slack_title_template"
|
||||
assert migrated_alertmanager.web_title_template == "web_title_template"
|
||||
assert migrated_alertmanager.grouping_id_template == "grouping_id_template"
|
||||
assert migrated_alertmanager.resolve_condition_template == "resolve_condition_template"
|
||||
assert migrated_alertmanager.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert migrated_grafana_alerting.integration == AlertReceiveChannel.INTEGRATION_LEGACY_GRAFANA_ALERTING
|
||||
assert migrated_grafana_alerting.alertmanager_v2_migrated_at is None
|
||||
assert migrated_grafana_alerting.slack_title_template is None
|
||||
assert migrated_grafana_alerting.web_title_template is None
|
||||
assert migrated_grafana_alerting.grouping_id_template is None
|
||||
assert migrated_grafana_alerting.resolve_condition_template is None
|
||||
assert migrated_grafana_alerting.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert alertmanager.integration == AlertReceiveChannel.INTEGRATION_ALERTMANAGER
|
||||
assert alertmanager.alertmanager_v2_migrated_at is None
|
||||
assert alertmanager.slack_title_template == "slack_title_template"
|
||||
assert alertmanager.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert grafana_alerting.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING
|
||||
assert grafana_alerting.alertmanager_v2_migrated_at is None
|
||||
assert grafana_alerting.slack_title_template == "slack_title_template"
|
||||
assert grafana_alerting.alertmanager_v2_backup_templates is None
|
||||
|
||||
migrated_alertmanager_2.refresh_from_db()
|
||||
alertmanager_2.refresh_from_db()
|
||||
migrated_grafana_alerting_2.refresh_from_db()
|
||||
grafana_alerting_2.refresh_from_db()
|
||||
|
||||
# check that migrated integrations is second org were not touced by backward migration of other org
|
||||
assert migrated_alertmanager_2.integration == AlertReceiveChannel.INTEGRATION_ALERTMANAGER
|
||||
assert migrated_alertmanager_2.alertmanager_v2_migrated_at is not None
|
||||
assert migrated_alertmanager_2.slack_title_template is None
|
||||
assert migrated_alertmanager_2.web_title_template is None
|
||||
assert migrated_alertmanager_2.grouping_id_template is None
|
||||
assert migrated_alertmanager_2.resolve_condition_template is None
|
||||
assert migrated_alertmanager_2.alertmanager_v2_backup_templates is not None
|
||||
|
||||
assert migrated_grafana_alerting_2.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING
|
||||
assert migrated_grafana_alerting_2.alertmanager_v2_migrated_at is not None
|
||||
assert migrated_grafana_alerting_2.slack_title_template is None
|
||||
assert migrated_grafana_alerting_2.web_title_template is None
|
||||
assert migrated_grafana_alerting_2.grouping_id_template is None
|
||||
assert migrated_grafana_alerting_2.resolve_condition_template is None
|
||||
assert migrated_grafana_alerting_2.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert alertmanager_2.integration == AlertReceiveChannel.INTEGRATION_ALERTMANAGER
|
||||
assert alertmanager_2.alertmanager_v2_migrated_at is None
|
||||
assert alertmanager_2.slack_title_template == "slack_title_template"
|
||||
assert alertmanager_2.alertmanager_v2_backup_templates is None
|
||||
|
||||
assert grafana_alerting_2.integration == AlertReceiveChannel.INTEGRATION_GRAFANA_ALERTING
|
||||
assert grafana_alerting_2.alertmanager_v2_migrated_at is None
|
||||
assert grafana_alerting_2.slack_title_template == "slack_title_template"
|
||||
assert grafana_alerting_2.alertmanager_v2_backup_templates is None
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
# NOTE: this is being left in this directory on purpose, it will be moved to apps/alerts/migrations
|
||||
# in a separate PR/release
|
||||
#
|
||||
# Generated by Django 4.2.16 on 2024-12-04 12:00
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
import common.migrations.remove_field
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("slack", "0008_remove_slackmessage_active_update_task_id_state"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
common.migrations.remove_field.RemoveFieldDB(
|
||||
model_name="SlackMessage",
|
||||
name="active_update_task_id",
|
||||
remove_state_migration=("slack", "0008_remove_slackmessage_active_update_task_id_state"),
|
||||
),
|
||||
]
|
||||
|
|
@ -48,10 +48,7 @@ class AlertGroupSlackService:
|
|||
|
||||
try:
|
||||
result = self._slack_client.chat_postMessage(
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# channel=slack_message.channel.slack_id,
|
||||
channel=slack_message._channel_id,
|
||||
channel=slack_message.channel.slack_id,
|
||||
text=text,
|
||||
attachments=attachments,
|
||||
thread_ts=slack_message.slack_id,
|
||||
|
|
@ -66,11 +63,8 @@ class AlertGroupSlackService:
|
|||
):
|
||||
return
|
||||
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
alert_group.slack_messages.create(
|
||||
slack_id=result["ts"],
|
||||
organization=alert_group.channel.organization,
|
||||
_channel_id=slack_message.channel.slack_id,
|
||||
channel=slack_message.channel,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.2.16 on 2024-12-04 12:00
|
||||
|
||||
import common.migrations.remove_field
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('slack', '0007_migrate_slackmessage_channel_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
common.migrations.remove_field.RemoveFieldState(
|
||||
model_name='SlackMessage',
|
||||
name='active_update_task_id',
|
||||
),
|
||||
]
|
||||
|
|
@ -89,11 +89,6 @@ class SlackMessage(models.Model):
|
|||
related_name="slack_messages",
|
||||
)
|
||||
|
||||
active_update_task_id = models.CharField(max_length=100, null=True, default=None)
|
||||
"""
|
||||
DEPRECATED/TODO: drop this field in a separate PR/release
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
# slack_id is unique within the context of a channel or conversation
|
||||
constraints = [
|
||||
|
|
@ -112,10 +107,7 @@ class SlackMessage(models.Model):
|
|||
|
||||
try:
|
||||
result = SlackClient(self.slack_team_identity).chat_getPermalink(
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# channel=self.channel.slack_id,
|
||||
channel=self._channel_id,
|
||||
channel=self.channel.slack_id,
|
||||
message_ts=self.slack_id,
|
||||
)
|
||||
except SlackAPIError:
|
||||
|
|
@ -128,9 +120,7 @@ class SlackMessage(models.Model):
|
|||
|
||||
@property
|
||||
def deep_link(self) -> str:
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
return f"https://slack.com/app_redirect?channel={self._channel_id}&team={self.slack_team_identity.slack_id}&message={self.slack_id}"
|
||||
return f"https://slack.com/app_redirect?channel={self.channel.slack_id}&team={self.slack_team_identity.slack_id}&message={self.slack_id}"
|
||||
|
||||
@classmethod
|
||||
def send_slack_notification(
|
||||
|
|
@ -232,12 +222,9 @@ class SlackMessage(models.Model):
|
|||
).save()
|
||||
return
|
||||
else:
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
alert_group.slack_messages.create(
|
||||
slack_id=result["ts"],
|
||||
organization=organization,
|
||||
_channel_id=slack_channel.slack_id,
|
||||
channel=slack_channel,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -132,12 +132,9 @@ class SlackUserIdentity(models.Model):
|
|||
"elements": [
|
||||
{
|
||||
"type": "mrkdwn",
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# f"<#{slack_message.channel.slack_id}>.\n"
|
||||
"text": (
|
||||
f"You received this message because you're not a member of "
|
||||
f"<#{slack_message._channel_id}>.\n"
|
||||
f"<#{slack_message.channel.slack_id}>.\n"
|
||||
"Please join the channel to get notified right in the alert group thread."
|
||||
),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,10 +87,7 @@ class UpdateAppearanceStep(scenario_step.ScenarioStep):
|
|||
slack_message = alert_group.slack_message
|
||||
|
||||
self._slack_client.chat_update(
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# channel=slack_message.channel.slack_id,
|
||||
channel=slack_message._channel_id,
|
||||
channel=slack_message.channel.slack_id,
|
||||
ts=slack_message.slack_id,
|
||||
attachments=alert_group.render_slack_attachments(),
|
||||
blocks=alert_group.render_slack_blocks(),
|
||||
|
|
|
|||
|
|
@ -158,12 +158,9 @@ class IncomingAlertStep(scenario_step.ScenarioStep):
|
|||
blocks=alert_group.render_slack_blocks(),
|
||||
)
|
||||
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
alert_group.slack_messages.create(
|
||||
slack_id=result["ts"],
|
||||
organization=alert_group.channel.organization,
|
||||
_channel_id=slack_channel.slack_id,
|
||||
channel=slack_channel,
|
||||
)
|
||||
|
||||
|
|
@ -554,10 +551,7 @@ class AttachGroupStep(AlertGroupActionsMixin, scenario_step.ScenarioStep):
|
|||
|
||||
if slack_user_identity:
|
||||
self._slack_client.chat_postEphemeral(
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# channel=alert_group.slack_message.channel.slack_id,
|
||||
channel=alert_group.slack_message._channel_id,
|
||||
channel=alert_group.slack_message.channel.slack_id,
|
||||
user=slack_user_identity.slack_id,
|
||||
text="{}{}".format(ephemeral_text[:1].upper(), ephemeral_text[1:]),
|
||||
unfurl_links=True,
|
||||
|
|
@ -804,10 +798,7 @@ class UnAcknowledgeGroupStep(AlertGroupActionsMixin, scenario_step.ScenarioStep)
|
|||
if slack_message.ack_reminder_message_ts:
|
||||
try:
|
||||
self._slack_client.chat_update(
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# channel=slack_message.channel.slack_id,
|
||||
channel=slack_message._channel_id,
|
||||
channel=slack_message.channel.slack_id,
|
||||
ts=slack_message.ack_reminder_message_ts,
|
||||
text=text,
|
||||
attachments=message_attachments,
|
||||
|
|
@ -921,12 +912,9 @@ class AcknowledgeConfirmationStep(AcknowledgeGroupStep):
|
|||
except (SlackAPITokenError, SlackAPIChannelArchivedError, SlackAPIChannelNotFoundError):
|
||||
pass
|
||||
else:
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
alert_group.slack_messages.create(
|
||||
slack_id=response["ts"],
|
||||
organization=organization,
|
||||
_channel_id=slack_channel.slack_id,
|
||||
channel=slack_channel,
|
||||
)
|
||||
|
||||
|
|
@ -981,13 +969,7 @@ class DeleteGroupStep(scenario_step.ScenarioStep):
|
|||
# Remove alert group Slack messages
|
||||
for message in alert_group.slack_messages.all():
|
||||
try:
|
||||
self._slack_client.chat_delete(
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# channel=message.channel.slack_id,
|
||||
channel=message._channel_id,
|
||||
ts=message.slack_id,
|
||||
)
|
||||
self._slack_client.chat_delete(channel=message.channel.slack_id, ts=message.slack_id)
|
||||
except SlackAPIRatelimitError:
|
||||
# retries on ratelimit are handled in apps.alerts.tasks.delete_alert_group.delete_alert_group
|
||||
raise
|
||||
|
|
|
|||
|
|
@ -18,11 +18,7 @@ class NotificationDeliveryStep(scenario_step.ScenarioStep):
|
|||
|
||||
user = log_record.author
|
||||
alert_group = log_record.alert_group
|
||||
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# slack_channel_id = alert_group_slack_message.channel.slack_id
|
||||
slack_channel_id = alert_group.slack_message._channel_id
|
||||
slack_channel_id = alert_group.slack_message.channel.slack_id
|
||||
|
||||
user_verbal_with_mention = user.get_username_with_slack_verbal(mention=True)
|
||||
|
||||
|
|
|
|||
|
|
@ -92,13 +92,10 @@ class AddToResolutionNoteStep(scenario_step.ScenarioStep):
|
|||
return
|
||||
|
||||
try:
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
slack_message = SlackMessage.objects.get(
|
||||
slack_id=payload["message"]["thread_ts"],
|
||||
organization__slack_team_identity=slack_team_identity,
|
||||
_channel_id=channel_id,
|
||||
# channel__slack_id=channel_id,
|
||||
channel__slack_id=channel_id,
|
||||
)
|
||||
except SlackMessage.DoesNotExist:
|
||||
if settings.UNIFIED_SLACK_APP_ENABLED:
|
||||
|
|
@ -164,14 +161,10 @@ class AddToResolutionNoteStep(scenario_step.ScenarioStep):
|
|||
slack_channel = SlackChannel.objects.get(
|
||||
slack_id=channel_id, slack_team_identity=slack_team_identity
|
||||
)
|
||||
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
slack_message = SlackMessage.objects.get(
|
||||
slack_id=thread_ts,
|
||||
organization__slack_team_identity=slack_team_identity,
|
||||
# channel__slack_id=channel_id,
|
||||
_channel_id=channel_id,
|
||||
channel__slack_id=channel_id,
|
||||
)
|
||||
alert_group = slack_message.alert_group
|
||||
|
||||
|
|
@ -262,14 +255,10 @@ class UpdateResolutionNoteStep(scenario_step.ScenarioStep):
|
|||
resolution_note_slack_message = resolution_note.resolution_note_slack_message
|
||||
alert_group = resolution_note.alert_group
|
||||
alert_group_slack_message = alert_group.slack_message
|
||||
slack_channel_id = alert_group_slack_message.channel.slack_id
|
||||
|
||||
blocks = self.get_resolution_note_blocks(resolution_note)
|
||||
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# slack_channel_id = alert_group_slack_message.channel.slack_id
|
||||
slack_channel_id = alert_group_slack_message._channel_id
|
||||
|
||||
slack_channel = SlackChannel.objects.get(
|
||||
slack_id=slack_channel_id, slack_team_identity=self.slack_team_identity
|
||||
)
|
||||
|
|
|
|||
|
|
@ -161,12 +161,9 @@ class BaseShiftSwapRequestStep(scenario_step.ScenarioStep):
|
|||
blocks=self._generate_blocks(shift_swap_request),
|
||||
)
|
||||
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
return SlackMessage.objects.create(
|
||||
slack_id=result["ts"],
|
||||
organization=self.organization,
|
||||
_channel_id=shift_swap_request.slack_channel_id,
|
||||
channel=shift_swap_request.slack_channel,
|
||||
)
|
||||
|
||||
|
|
@ -186,11 +183,8 @@ class BaseShiftSwapRequestStep(scenario_step.ScenarioStep):
|
|||
if not shift_swap_request.slack_message:
|
||||
return
|
||||
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
self._slack_client.chat_postMessage(
|
||||
# channel=shift_swap_request.slack_message.channel.slack_id,
|
||||
channel=shift_swap_request.slack_message._channel_id,
|
||||
channel=shift_swap_request.slack_message.channel.slack_id,
|
||||
thread_ts=shift_swap_request.slack_message.slack_id,
|
||||
reply_broadcast=reply_broadcast,
|
||||
blocks=blocks,
|
||||
|
|
|
|||
|
|
@ -66,13 +66,10 @@ class SlackChannelMessageEventStep(scenario_step.ScenarioStep):
|
|||
message_ts = payload["event"]["ts"]
|
||||
|
||||
try:
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
slack_message = SlackMessage.objects.get(
|
||||
slack_id=thread_ts,
|
||||
organization__slack_team_identity=self.slack_team_identity,
|
||||
_channel_id=channel_id,
|
||||
# channel__slack_id=channel_id,
|
||||
channel__slack_id=channel_id,
|
||||
)
|
||||
except SlackMessage.DoesNotExist:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -63,12 +63,9 @@ class AlertGroupActionsMixin:
|
|||
slack_team_identity=slack_team_identity,
|
||||
)
|
||||
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
SlackMessage.objects.create(
|
||||
slack_id=message_id,
|
||||
organization=alert_group.channel.organization,
|
||||
_channel_id=slack_channel.slack_id,
|
||||
channel=slack_channel,
|
||||
alert_group=alert_group,
|
||||
)
|
||||
|
|
@ -179,12 +176,9 @@ class AlertGroupActionsMixin:
|
|||
logger.warning(f"alert_group_pk not found in payload, fetching SlackMessage from DB. message_ts: {message_ts}")
|
||||
|
||||
# Get SlackMessage from DB
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
slack_message = SlackMessage.objects.get(
|
||||
slack_id=message_ts,
|
||||
organization__slack_team_identity=slack_team_identity,
|
||||
_channel_id=channel_id,
|
||||
# channel__slack_id=channel_id,
|
||||
channel__slack_id=channel_id,
|
||||
)
|
||||
return slack_message.alert_group
|
||||
|
|
|
|||
|
|
@ -98,10 +98,7 @@ def update_alert_group_slack_message(slack_message_pk: int) -> None:
|
|||
|
||||
try:
|
||||
slack_client.chat_update(
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p173255546
|
||||
# channel=slack_message.channel.slack_id,
|
||||
channel=slack_message._channel_id,
|
||||
channel=slack_message.channel.slack_id,
|
||||
ts=slack_message.slack_id,
|
||||
attachments=alert_group.render_slack_attachments(),
|
||||
blocks=alert_group.render_slack_blocks(),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from unittest.mock import patch
|
|||
import pytest
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.slack.models import SlackChannel
|
||||
from apps.slack.models import SlackChannel, SlackMessage
|
||||
from apps.slack.scenarios import slack_channel as slack_channel_scenarios
|
||||
|
||||
|
||||
|
|
@ -84,6 +84,7 @@ class TestSlackChannelDeletedEventStep:
|
|||
self,
|
||||
make_organization_and_user_with_slack_identities,
|
||||
make_slack_channel,
|
||||
make_slack_message,
|
||||
) -> None:
|
||||
(
|
||||
organization,
|
||||
|
|
@ -92,6 +93,7 @@ class TestSlackChannelDeletedEventStep:
|
|||
slack_user_identity,
|
||||
) = make_organization_and_user_with_slack_identities()
|
||||
slack_channel = make_slack_channel(slack_team_identity)
|
||||
make_slack_message(slack_channel, organization=organization)
|
||||
slack_channel_id = slack_channel.slack_id
|
||||
|
||||
# Ensure the SlackChannel exists
|
||||
|
|
@ -100,6 +102,8 @@ class TestSlackChannelDeletedEventStep:
|
|||
slack_team_identity=slack_team_identity,
|
||||
).exists()
|
||||
|
||||
assert SlackMessage.objects.count() == 1
|
||||
|
||||
step = slack_channel_scenarios.SlackChannelDeletedEventStep(slack_team_identity, organization, user)
|
||||
step.process_scenario(slack_user_identity, slack_team_identity, {"event": {"channel": slack_channel_id}})
|
||||
|
||||
|
|
@ -109,6 +113,9 @@ class TestSlackChannelDeletedEventStep:
|
|||
slack_team_identity=slack_team_identity,
|
||||
).exists()
|
||||
|
||||
# Slack messages should be cascade deleted when their channel is deleted
|
||||
assert SlackMessage.objects.count() == 0
|
||||
|
||||
def test_process_scenario_channel_does_not_exist(
|
||||
self,
|
||||
make_organization_and_user_with_slack_identities,
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ class TestUpdateAlertGroupSlackMessageTask:
|
|||
|
||||
# Assert that SlackClient.chat_update was called with correct parameters
|
||||
mock_chat_update.assert_called_once_with(
|
||||
channel=slack_message._channel_id,
|
||||
channel=slack_message.channel.slack_id,
|
||||
ts=slack_message.slack_id,
|
||||
attachments=alert_group.render_slack_attachments(),
|
||||
blocks=alert_group.render_slack_blocks(),
|
||||
|
|
|
|||
|
|
@ -516,13 +516,10 @@ class SlackEventApiEndpointView(APIView):
|
|||
return None
|
||||
|
||||
try:
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
slack_message = SlackMessage.objects.get(
|
||||
slack_id=message_ts,
|
||||
organization__slack_team_identity=slack_team_identity,
|
||||
_channel_id=channel_id,
|
||||
# channel__slack_id=channel_id,
|
||||
channel__slack_id=channel_id,
|
||||
)
|
||||
except SlackMessage.DoesNotExist:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -528,12 +528,9 @@ def make_slack_user_identity():
|
|||
@pytest.fixture
|
||||
def make_slack_message():
|
||||
def _make_slack_message(channel, alert_group=None, organization=None, **kwargs):
|
||||
# TODO: once _channel_id has been fully migrated to channel, remove _channel_id
|
||||
# see https://raintank-corp.slack.com/archives/C06K1MQ07GS/p1732555465144099
|
||||
return SlackMessageFactory(
|
||||
alert_group=alert_group,
|
||||
organization=organization or alert_group.channel.organization,
|
||||
_channel_id=channel.slack_id,
|
||||
channel=channel,
|
||||
**kwargs,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,168 +0,0 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.alerts.models import AlertReceiveChannel
|
||||
|
||||
ALERTMANAGER = "alertmanager"
|
||||
LEGACY_ALERTMANAGER = "legacy_alertmanager"
|
||||
GRAFANA_ALERTING = "grafana_alerting"
|
||||
LEGACY_GRAFANA_ALERTING = "legacy_grafana_alerting"
|
||||
TEMPLATE_FIELDS = [
|
||||
"web_title_template",
|
||||
"web_message_template",
|
||||
"web_image_url_template",
|
||||
"sms_title_template",
|
||||
"phone_call_title_template",
|
||||
"source_link_template",
|
||||
"grouping_id_template",
|
||||
"resolve_condition_template",
|
||||
"acknowledge_condition_template",
|
||||
"slack_title_template",
|
||||
"slack_message_template",
|
||||
"slack_image_url_template",
|
||||
"telegram_title_template",
|
||||
"telegram_message_template",
|
||||
"telegram_image_url_template",
|
||||
"messaging_backends_templates",
|
||||
]
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument("--backward", action="store_true", help="Run the migration backward.")
|
||||
parser.add_argument(
|
||||
"--org_id", type=int, help="Org id to perform the migration. " "If not present will migrate all."
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
org_id = options.get("org_id", None)
|
||||
if options["backward"]:
|
||||
self.migrate_backward(org_id)
|
||||
else:
|
||||
self.migrate_forward(org_id)
|
||||
|
||||
@transaction.atomic
|
||||
def migrate_forward(self, org_id=None):
|
||||
now = timezone.now()
|
||||
self.stdout.write(f"Forward migration started at {now}.")
|
||||
|
||||
self.stdout.write(
|
||||
"Migrating legacy Alertmanager integrations "
|
||||
"(updating fields 'integration' and 'alertmanager_v2_migrated_at')."
|
||||
)
|
||||
alertmanager_to_update = AlertReceiveChannel.objects.filter(integration=LEGACY_ALERTMANAGER)
|
||||
if org_id:
|
||||
alertmanager_to_update = alertmanager_to_update.filter(organization_id=org_id)
|
||||
num_updated = alertmanager_to_update.update(integration=ALERTMANAGER, alertmanager_v2_migrated_at=now)
|
||||
self.stdout.write(f"Migrated {num_updated} legacy Alertmanager integrations.")
|
||||
|
||||
self.stdout.write(
|
||||
"Migrating legacy Grafana Alerting integrations "
|
||||
"(updating fields 'integration' and 'alertmanager_v2_migrated_at')."
|
||||
)
|
||||
alerting_to_update = AlertReceiveChannel.objects.filter(integration=LEGACY_GRAFANA_ALERTING)
|
||||
if org_id:
|
||||
alerting_to_update = alerting_to_update.filter(organization_id=org_id)
|
||||
num_updated = alerting_to_update.update(integration=GRAFANA_ALERTING, alertmanager_v2_migrated_at=now)
|
||||
|
||||
self.stdout.write(f"Migrated {num_updated} legacy Grafana Alerting integrations.")
|
||||
|
||||
self.stdout.write("Fetching integrations to back up & reset templates.")
|
||||
alert_receive_channels = AlertReceiveChannel.objects.filter(
|
||||
Q(
|
||||
**{f"{field}__isnull": False for field in TEMPLATE_FIELDS},
|
||||
_connector=Q.OR,
|
||||
),
|
||||
integration__in=[ALERTMANAGER, GRAFANA_ALERTING],
|
||||
alertmanager_v2_migrated_at__isnull=False,
|
||||
)
|
||||
if org_id:
|
||||
alert_receive_channels = alert_receive_channels.filter(organization_id=org_id)
|
||||
|
||||
self.stdout.write(f"Backing up & resetting templates for {len(alert_receive_channels)} integrations.")
|
||||
|
||||
for alert_receive_channel in alert_receive_channels:
|
||||
self.stdout.write(
|
||||
f"Backing up & resetting templates for integration {alert_receive_channel.public_primary_key}."
|
||||
)
|
||||
alert_receive_channel.alertmanager_v2_backup_templates = {
|
||||
field: getattr(alert_receive_channel, field) for field in TEMPLATE_FIELDS
|
||||
}
|
||||
for field in TEMPLATE_FIELDS:
|
||||
setattr(alert_receive_channel, field, None)
|
||||
|
||||
self.stdout.write(f"Bulk updating templates for {len(alert_receive_channels)} integrations.")
|
||||
num_updated = AlertReceiveChannel.objects.bulk_update(
|
||||
alert_receive_channels,
|
||||
fields=[
|
||||
*TEMPLATE_FIELDS,
|
||||
"alertmanager_v2_backup_templates",
|
||||
],
|
||||
batch_size=1000,
|
||||
)
|
||||
self.stdout.write(f"Bulk updated templates for {num_updated} integrations.")
|
||||
|
||||
self.stdout.write("Forward migration finished.")
|
||||
|
||||
@transaction.atomic
|
||||
def migrate_backward(self, org_id=None):
|
||||
now = timezone.now()
|
||||
self.stdout.write(f"Backward migration started at {now}.")
|
||||
|
||||
self.stdout.write(
|
||||
"Backward migrating Alertmanager integrations "
|
||||
"(updating fields 'integration' and 'alertmanager_v2_migrated_at')."
|
||||
)
|
||||
|
||||
alertmanagers_to_restore = AlertReceiveChannel.objects.filter(
|
||||
integration=ALERTMANAGER, alertmanager_v2_migrated_at__isnull=False
|
||||
)
|
||||
if org_id:
|
||||
alertmanagers_to_restore = alertmanagers_to_restore.filter(organization_id=org_id)
|
||||
num_updated = alertmanagers_to_restore.update(integration=LEGACY_ALERTMANAGER, alertmanager_v2_migrated_at=None)
|
||||
self.stdout.write(f"Backward migrated {num_updated} Alertmanager integrations.")
|
||||
|
||||
self.stdout.write(
|
||||
"Backward migrating Grafana Alerting integrations "
|
||||
"(updating fields 'integration' and 'alertmanager_v2_migrated_at')."
|
||||
)
|
||||
|
||||
alerting_to_restore = AlertReceiveChannel.objects.filter(
|
||||
integration=GRAFANA_ALERTING, alertmanager_v2_migrated_at__isnull=False
|
||||
)
|
||||
if org_id:
|
||||
alerting_to_restore = alerting_to_restore.filter(organization_id=org_id)
|
||||
num_updated = alerting_to_restore.update(integration=LEGACY_GRAFANA_ALERTING, alertmanager_v2_migrated_at=None)
|
||||
self.stdout.write(f"Backward migrated {num_updated} Grafana Alerting integrations.")
|
||||
|
||||
self.stdout.write("Fetching integrations to restore templates from backup.")
|
||||
alert_receive_channels = AlertReceiveChannel.objects.filter(
|
||||
integration__in=[LEGACY_ALERTMANAGER, LEGACY_GRAFANA_ALERTING],
|
||||
alertmanager_v2_backup_templates__isnull=False,
|
||||
)
|
||||
if org_id:
|
||||
alert_receive_channels = alert_receive_channels.filter(organization_id=org_id)
|
||||
self.stdout.write(f"Restoring templates for {len(alert_receive_channels)} integrations.")
|
||||
|
||||
for alert_receive_channel in alert_receive_channels:
|
||||
self.stdout.write(f"Restoring templates for integration {alert_receive_channel.public_primary_key}.")
|
||||
if alert_receive_channel.alertmanager_v2_backup_templates is None:
|
||||
continue
|
||||
for field in TEMPLATE_FIELDS:
|
||||
setattr(alert_receive_channel, field, alert_receive_channel.alertmanager_v2_backup_templates.get(field))
|
||||
alert_receive_channel.alertmanager_v2_backup_templates = None
|
||||
|
||||
self.stdout.write(f"Bulk updating templates for {len(alert_receive_channels)} integrations.")
|
||||
num_updated = AlertReceiveChannel.objects.bulk_update(
|
||||
alert_receive_channels,
|
||||
fields=[
|
||||
*TEMPLATE_FIELDS,
|
||||
"alertmanager_v2_backup_templates",
|
||||
],
|
||||
batch_size=1000,
|
||||
)
|
||||
self.stdout.write(f"Bulk updated templates for {num_updated} integrations.")
|
||||
|
||||
self.stdout.write("Backward migration finished.")
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
import time
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connection, transaction
|
||||
|
||||
from apps.slack.models import SlackChannel, SlackMessage
|
||||
from apps.user_management.models import Organization
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Batch updates SlackMessage.channel_id in chunks to avoid locking the table."
|
||||
|
||||
def handle(self, *args, **options):
|
||||
start_time = time.time()
|
||||
self.stdout.write("Starting batch update of SlackMessage.channel_id...")
|
||||
|
||||
# Step 1: Determine the queryset to update
|
||||
# qs is ordered by id to ensure consistent batching
|
||||
# since id is indexed, this ordering operation "should" be more efficient (as opposed to say created_at
|
||||
# which we don't have an index on)
|
||||
qs = SlackMessage.objects.filter(
|
||||
_channel_id__isnull=False, # old column
|
||||
organization__isnull=False,
|
||||
channel_id__isnull=True, # new column
|
||||
).order_by("id")
|
||||
|
||||
total_records = qs.count()
|
||||
if total_records == 0:
|
||||
self.stdout.write("No records to update.")
|
||||
return
|
||||
|
||||
self.stdout.write(f"Total records to update: {total_records}")
|
||||
|
||||
# some considerations here..
|
||||
#
|
||||
# Large IN clauses can be inefficient. Keep BATCH_SIZE reasonable (e.g., 1000)
|
||||
# Fetching large batches of IDs consumes memory. With a BATCH_SIZE of 1000, this "should" be manageable
|
||||
#
|
||||
# references
|
||||
# https://stackoverflow.com/a/5919165
|
||||
BATCH_SIZE = 1000
|
||||
|
||||
total_batches = (total_records + BATCH_SIZE - 1) // BATCH_SIZE
|
||||
self.stdout.write(f"Batch size: {BATCH_SIZE}")
|
||||
self.stdout.write(f"Total batches: {total_batches}")
|
||||
|
||||
records_updated = 0
|
||||
batch_number = 1
|
||||
|
||||
# Process updates in batches
|
||||
while True:
|
||||
# Get the next batch of IDs
|
||||
batch_qs = qs[:BATCH_SIZE]
|
||||
|
||||
# collect the IDs to be updated
|
||||
batch_ids = list(batch_qs.values_list("id", flat=True))
|
||||
|
||||
if not batch_ids:
|
||||
break # No more records to process
|
||||
|
||||
placeholders = ", ".join(["%s"] * len(batch_ids))
|
||||
update_query = f"""
|
||||
UPDATE
|
||||
{SlackMessage._meta.db_table} AS sm
|
||||
INNER JOIN {Organization._meta.db_table} AS org
|
||||
ON org.id = sm.organization_id
|
||||
INNER JOIN {SlackChannel._meta.db_table} AS sc
|
||||
ON sc.slack_id = sm._channel_id
|
||||
AND sc.slack_team_identity_id = org.slack_team_identity_id
|
||||
SET
|
||||
sm.channel_id = sc.id
|
||||
WHERE
|
||||
sm.id IN ({placeholders})
|
||||
"""
|
||||
params = batch_ids
|
||||
|
||||
try:
|
||||
# Execute the update
|
||||
with transaction.atomic():
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(update_query, params)
|
||||
batch_records_updated = cursor.rowcount
|
||||
records_updated += batch_records_updated
|
||||
|
||||
self.stdout.write(f"Batch {batch_number}/{total_batches}: Updated {batch_records_updated} records")
|
||||
except Exception as e:
|
||||
self.stderr.write(f"Error updating batch {batch_number}: {e}")
|
||||
# Optionally, decide whether to continue or abort
|
||||
continue
|
||||
|
||||
# Remove processed records from queryset for next batch
|
||||
qs = qs.exclude(id__in=batch_ids)
|
||||
|
||||
batch_number += 1
|
||||
|
||||
end_time = time.time()
|
||||
total_time = end_time - start_time
|
||||
self.stdout.write(f"Batch update completed successfully. Total records updated: {records_updated}")
|
||||
self.stdout.write(f"Total time taken: {total_time:.2f} seconds")
|
||||
Loading…
Add table
Reference in a new issue