-
Notifications
You must be signed in to change notification settings - Fork 291
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix duplicate orders on routes and escalation policies (#2568)
# What this PR does Fix duplicate `order` values for models `EscalationPolicy` and `ChannelFilter` using the same approach as #2278. - Make internal API action `move_to_position` a part of [OrderedModelViewSet](https://github.com/grafana/oncall/pull/2568/files#diff-eb62521ccbcb072d1bd2156adeadae3b5895bce6d0d54432a23db3948b0ada54R11-R34), so all ordered model views use the same logic. - Make public API serializers for ordered models inherit from [OrderedModelSerializer](https://github.com/grafana/oncall/pull/2568/files#diff-d749f94af5a49adaf5074325cdfad10ddd5a52dbfd78b49582867ebb9c92fae5R6-R38), so ordered model views are consistent with each other in public API. - Remove `order` from plugin fronted, since it's not being used anywhere. The frontend uses step indices & `move_to_position` action instead. - Make escalation snapshot use step indices instead of orders, since orders are not guaranteed to be sequential (+fix a minor off-by-one bug) ## Which issue(s) this PR fixes grafana/oncall-private#1680 ## 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] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
- Loading branch information
Showing
35 changed files
with
442 additions
and
344 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Generated by Django 3.2.20 on 2023-07-18 09:53 | ||
|
||
from django.db import migrations, models | ||
import django_migration_linter as linter | ||
from django.db.models import Count | ||
|
||
from common.database import get_random_readonly_database_key_if_present_otherwise_default | ||
|
||
|
||
def fix_duplicate_orders(apps, schema_editor): | ||
EscalationPolicy = apps.get_model('alerts', 'EscalationPolicy') | ||
|
||
# it should be safe to use a readonly database because duplicates are pretty infrequent | ||
db = get_random_readonly_database_key_if_present_otherwise_default() | ||
|
||
# find all (escalation_chain_id, order) tuples that have more than one entry (meaning duplicates) | ||
items_with_duplicate_orders = EscalationPolicy.objects.using(db).values( | ||
"escalation_chain_id", "order" | ||
).annotate(count=Count("order")).order_by().filter(count__gt=1) # use order_by() to reset any existing ordering | ||
|
||
# make sure we don't fix the same escalation chain more than once | ||
escalation_chain_ids = set(item["escalation_chain_id"] for item in items_with_duplicate_orders) | ||
|
||
for escalation_chain_id in escalation_chain_ids: | ||
policies = EscalationPolicy.objects.filter(escalation_chain_id=escalation_chain_id).order_by("order", "id") | ||
# assign correct sequential order for each policy starting from 0 | ||
for idx, policy in enumerate(policies): | ||
policy.order = idx | ||
EscalationPolicy.objects.bulk_update(policies, fields=["order"]) | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('alerts', '0023_auto_20230718_0952'), | ||
] | ||
|
||
operations = [ | ||
linter.IgnoreMigration(), # adding a unique constraint after fixing duplicates should be fine | ||
migrations.AlterModelOptions( | ||
name='escalationpolicy', | ||
options={'ordering': ['order']}, | ||
), | ||
migrations.AlterField( | ||
model_name='escalationpolicy', | ||
name='order', | ||
field=models.PositiveIntegerField(db_index=True, editable=False, null=True), | ||
), | ||
migrations.RunPython(fix_duplicate_orders, migrations.RunPython.noop), | ||
migrations.AddConstraint( | ||
model_name='escalationpolicy', | ||
constraint=models.UniqueConstraint(fields=('escalation_chain_id', 'order'), name='unique_escalation_policy_order'), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Generated by Django 3.2.20 on 2023-07-18 10:42 | ||
|
||
from django.db import migrations, models | ||
import django_migration_linter as linter | ||
from django.db.models import Count | ||
|
||
from common.database import get_random_readonly_database_key_if_present_otherwise_default | ||
|
||
|
||
def fix_duplicate_orders(apps, schema_editor): | ||
ChannelFilter = apps.get_model('alerts', 'ChannelFilter') | ||
|
||
# it should be safe to use a readonly database because duplicates are pretty infrequent | ||
db = get_random_readonly_database_key_if_present_otherwise_default() | ||
|
||
# find all (alert_receive_channel_id, is_default, order) tuples that have more than one entry (meaning duplicates) | ||
items_with_duplicate_orders = ChannelFilter.objects.using(db).values( | ||
"alert_receive_channel_id", "is_default", "order" | ||
).annotate(count=Count("order")).order_by().filter(count__gt=1) # use order_by() to reset any existing ordering | ||
|
||
# make sure we don't fix the same (alert_receive_channel_id, is_default) pair more than once | ||
values_to_fix = set((item["alert_receive_channel_id"], item["is_default"]) for item in items_with_duplicate_orders) | ||
|
||
for alert_receive_channel_id, is_default in values_to_fix: | ||
channel_filters = ChannelFilter.objects.filter( | ||
alert_receive_channel_id=alert_receive_channel_id, is_default=is_default | ||
).order_by("order", "id") | ||
# assign correct sequential order for each route starting from 0 | ||
for idx, channel_filter in enumerate(channel_filters): | ||
channel_filter.order = idx | ||
ChannelFilter.objects.bulk_update(channel_filters, fields=["order"]) | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('alerts', '0024_auto_20230718_0953'), | ||
] | ||
|
||
operations = [ | ||
linter.IgnoreMigration(), # adding a unique constraint after fixing duplicates should be fine | ||
migrations.AlterModelOptions( | ||
name='channelfilter', | ||
options={'ordering': ['alert_receive_channel_id', 'is_default', 'order']}, | ||
), | ||
migrations.AlterField( | ||
model_name='channelfilter', | ||
name='order', | ||
field=models.PositiveIntegerField(db_index=True, editable=False, null=True), | ||
), | ||
migrations.RunPython(fix_duplicate_orders, migrations.RunPython.noop), | ||
migrations.AddConstraint( | ||
model_name='channelfilter', | ||
constraint=models.UniqueConstraint(fields=('alert_receive_channel_id', 'is_default', 'order'), name='unique_channel_filter_order'), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.