Skip to content

Commit 1a49a70

Browse files
committed
feat(backend): 轮值策略可包含/排除指定业务 #8893
1 parent 31b2ec6 commit 1a49a70

File tree

5 files changed

+101
-15
lines changed

5 files changed

+101
-15
lines changed

dbm-ui/backend/db_monitor/exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,9 @@ class AutofixException(DBMonitorBaseException):
4040
ERROR_CODE = "203"
4141
MESSAGE = _("故障自愈异常")
4242
MESSAGE_TPL = _("故障自愈异常: {message}")
43+
44+
45+
class DutyRuleSaveException(DBMonitorBaseException):
46+
ERROR_CODE = "204"
47+
MESSAGE = _("轮值策略保存失败")
48+
MESSAGE_TPL = _("轮值策略保存失败: {message}")
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 3.2.25 on 2025-01-02 11:46
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("db_monitor", "0020_auto_20240621_1216"),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name="dutyrule",
15+
name="biz_config",
16+
field=models.JSONField(default=dict, verbose_name="业务设置(包含业务include/排除业务exclude)"),
17+
),
18+
]

dbm-ui/backend/db_monitor/models/alarm.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@
4747
BkMonitorDeleteAlarmException,
4848
BkMonitorSaveAlarmException,
4949
BuiltInNotAllowDeleteException,
50+
DutyRuleSaveException,
5051
)
51-
from backend.db_monitor.tasks import update_app_policy
52+
from backend.db_monitor.tasks import delete_monitor_duty_rule, update_app_policy, update_db_notice_group
5253
from backend.db_monitor.utils import (
5354
bkm_delete_alarm_strategy,
5455
bkm_save_alarm_strategy,
@@ -167,12 +168,8 @@ def save_monitor_group(self) -> int:
167168
resp = BKMonitorV3Api.save_duty_rule(save_duty_rule_params, use_admin=True, raw=True)
168169
if resp.get("result"):
169170
self.monitor_duty_rule_id = resp["data"]["id"]
170-
monitor_duty_rule_ids = (
171-
DutyRule.objects.filter(db_type=self.db_type)
172-
.exclude(monitor_duty_rule_id=0)
173-
.order_by("-priority")
174-
.values_list("monitor_duty_rule_id", flat=True)
175-
)
171+
duty_rules = DutyRule.get_biz_db_duty_rules(self.bk_biz_id, self.db_type)
172+
monitor_duty_rule_ids = [rule.monitor_duty_rule_id for rule in duty_rules]
176173
save_monitor_group_params["need_duty"] = True
177174
save_monitor_group_params["duty_rules"] = list(monitor_duty_rule_ids) + [self.monitor_duty_rule_id]
178175
else:
@@ -275,11 +272,15 @@ class DutyRule(AuditedModel):
275272
category = models.CharField(verbose_name=_("轮值类型"), choices=DutyRuleCategory.get_choices(), max_length=LEN_SHORT)
276273
db_type = models.CharField(_("数据库类型"), choices=DBType.get_choices(), max_length=LEN_SHORT)
277274
duty_arranges = models.JSONField(_("轮值人员设置"))
275+
biz_config = models.JSONField(_("业务设置(包含业务include/排除业务exclude)"), default=dict)
278276

279277
def save(self, *args, **kwargs):
280278
"""
281279
保存轮值
282280
"""
281+
# 0. (前置校验)不允许同时存在包含业务和排除业务两个设置
282+
if self.biz_config.get("include") and self.biz_config.get("exclude"):
283+
raise DutyRuleSaveException(_("不允许通知存在包含业务和排除业务配置"))
283284
# 1. 新建监控轮值
284285
params = {
285286
"name": f"{self.db_type}_{self.name}",
@@ -343,26 +344,43 @@ def save(self, *args, **kwargs):
343344
# 3. 判断是否需要变更用户组
344345
# 3.1 非老规则(即新建的规则)
345346
need_update_user_group = not is_old_rule
346-
# 3.2 调整了优先级的规则
347+
# 3.2 调整了优先级的规则,或者调整了业务配置
347348
if self.pk:
348349
old_rule = DutyRule.objects.get(pk=self.pk)
349-
if old_rule.priority != self.priority:
350+
if old_rule.priority != self.priority or old_rule.biz_config != self.biz_config:
350351
need_update_user_group = True
351352
# 4. 保存本地轮值规则
352353
super().save(*args, **kwargs)
353-
# 5. 变更告警组
354+
# 5. 变更告警组-异步执行
354355
if need_update_user_group:
355-
for notice_group in NoticeGroup.objects.filter(is_built_in=True, db_type=self.db_type):
356-
notice_group.save()
356+
update_db_notice_group.delay(self.db_type)
357357

358358
def delete(self, using=None, keep_parents=False):
359-
BKMonitorV3Api.delete_duty_rules({"ids": [self.monitor_duty_rule_id], "bk_biz_ids": [env.DBA_APP_BK_BIZ_ID]})
359+
"""删除轮值"""
360360
super().delete()
361+
delete_monitor_duty_rule.delay(self.db_type, self.monitor_duty_rule_id)
361362

362363
@classmethod
363364
def priority_distinct(cls) -> list:
364365
return list(cls.objects.values_list("priority", flat=True).distinct().order_by("-priority"))
365366

367+
@classmethod
368+
def get_biz_db_duty_rules(cls, bk_biz_id: int, db_type: str):
369+
"""获取指定业务DB组件的轮值策略"""
370+
duty_rules = DutyRule.objects.filter(db_type=db_type).exclude(monitor_duty_rule_id=0).order_by("-priority")
371+
active_biz_duty_rules: list = []
372+
373+
for rule in duty_rules:
374+
# 如果业务不在包含名单,或者业务在排除名单,则本策略不属于该业务下
375+
if rule.biz_config:
376+
include, exclude = rule.biz_config.get("include"), rule.biz_config.get("exclude")
377+
if (include and bk_biz_id not in include) or (exclude and bk_biz_id in exclude):
378+
continue
379+
# 添加该业务下的轮值策略
380+
active_biz_duty_rules.append(rule)
381+
382+
return active_biz_duty_rules
383+
366384
class Meta:
367385
verbose_name_plural = verbose_name = _("轮值规则(DutyRule)")
368386

dbm-ui/backend/db_monitor/serializers.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
specific language governing permissions and limitations under the License.
1010
"""
1111
import urllib.parse
12+
from collections import defaultdict
1213

1314
from django.utils.translation import gettext_lazy as _
1415
from rest_framework import serializers
@@ -17,6 +18,7 @@
1718
from backend.bk_web.serializers import AuditedSerializer
1819
from backend.configuration.constants import DBType
1920
from backend.db_meta.enums import ClusterType
21+
from backend.db_meta.models import AppCache
2022
from backend.db_monitor import mock_data
2123
from backend.db_monitor.constants import AlertLevelEnum, DetectAlgEnum, OperatorEnum, TargetLevel
2224
from backend.db_monitor.exceptions import AutofixException
@@ -64,21 +66,36 @@ class Meta:
6466

6567

6668
class DutyRuleSerializer(AuditedSerializer, serializers.ModelSerializer):
69+
biz_config_display = serializers.SerializerMethodField(help_text=_("业务配置信息"))
70+
71+
@property
72+
def biz_name_map(self):
73+
if not hasattr(self, "_biz_name_map"):
74+
setattr(self, "_biz_name_map", AppCache.get_appcache(key="appcache_dict"))
75+
return self._biz_name_map
76+
6777
class Meta:
6878
model = DutyRule
6979
fields = "__all__"
7080

81+
def get_biz_config_display(self, obj):
82+
biz_config_display = defaultdict(dict)
83+
for key, bizs in obj.biz_config.items():
84+
infos = [{"bk_biz_id": biz, "bk_biz_name": self.biz_name_map[str(biz)]["bk_biz_name"]} for biz in bizs]
85+
biz_config_display[key] = infos
86+
return biz_config_display
87+
7188

7289
class DutyRuleCreateSerializer(DutyRuleSerializer):
7390
class Meta:
74-
model = NoticeGroup
91+
model = DutyRule
7592
fields = "__all__"
7693
swagger_schema_fields = {"example": mock_data.CREATE_HANDOFF_DUTY_RULE}
7794

7895

7996
class DutyRuleUpdateSerializer(DutyRuleSerializer):
8097
class Meta:
81-
model = NoticeGroup
98+
model = DutyRule
8299
fields = "__all__"
83100
swagger_schema_fields = {"example": mock_data.CREATE_CUSTOM_DUTY_RULE}
84101

dbm-ui/backend/db_monitor/tasks.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
from celery import shared_task
1515

16+
from backend import env
17+
from backend.components import BKMonitorV3Api
1618
from backend.configuration.constants import PLAT_BIZ_ID
19+
from backend.exceptions import ApiResultError
1720

1821
logger = logging.getLogger("celery")
1922

@@ -85,3 +88,27 @@ def update_app_policy(bk_biz_id, notify_group_id, db_type):
8588
notify_group_id,
8689
db_type,
8790
)
91+
92+
93+
@shared_task
94+
def update_db_notice_group(db_type: str):
95+
"""更新DB类型的告警组"""
96+
from backend.db_monitor.models import NoticeGroup
97+
98+
for notice_group in NoticeGroup.objects.filter(is_built_in=True, db_type=db_type):
99+
logger.info("[local_notice_group] update notice group: %s", notice_group.name)
100+
notice_group.save()
101+
102+
103+
@shared_task
104+
def delete_monitor_duty_rule(db_type: str, monitor_duty_rule_id):
105+
"""解绑相关告警组,删除轮值策略,调用此函数之前保证轮值已从DBM中删除"""
106+
update_db_notice_group(db_type)
107+
108+
logger.info("[duty_rule] delete duty rule: %s", monitor_duty_rule_id)
109+
110+
try:
111+
BKMonitorV3Api.delete_duty_rules({"ids": [monitor_duty_rule_id], "bk_biz_ids": [env.DBA_APP_BK_BIZ_ID]})
112+
except (ApiResultError, Exception) as e:
113+
# 轮值删除错误暂可忽略,因为删除之前已经停用不会生效,并且在DBM数据也清理。只是会在监控平台留下一条脏数据
114+
logger.error("[duty_rule] error in deleting duty: %s", e)

0 commit comments

Comments
 (0)