Skip to content

Commit b790e8d

Browse files
committed
fix(backend): 修复spider异常无法提单问题 #8709
1 parent 999a977 commit b790e8d

File tree

9 files changed

+63
-46
lines changed

9 files changed

+63
-46
lines changed

dbm-ui/backend/db_meta/api/cluster/tendbha/detail.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,11 @@ def scan_cluster(cluster: Cluster) -> Graphic:
5252
dummy_slave_be_node, slave_be_group = graph.add_node(slave_be, to_group=slave_be_group)
5353
graph.add_line(source=slave_be_group, target=receiver_instance_group, label=LineLabel.Bind)
5454

55-
for otr in (
56-
StorageInstanceTuple.objects.filter(ejector=ejector_instance)
57-
.prefetch_related("cluster")
58-
.exclude(receiver__cluster=cluster)
59-
):
55+
for otr in StorageInstanceTuple.objects.filter(ejector=ejector_instance).exclude(receiver__cluster=cluster):
6056
foreign_receiver_cluster = otr.receiver.cluster.get()
6157
graph.add_foreign_cluster(ForeignRelationType.RepTo, foreign_receiver_cluster)
6258

63-
for otr in (
64-
StorageInstanceTuple.objects.filter(receiver=ejector_instance)
65-
.prefetch_related("cluster")
66-
.exclude(ejector__cluster=cluster)
67-
):
59+
for otr in StorageInstanceTuple.objects.filter(receiver=ejector_instance).exclude(ejector__cluster=cluster):
6860
foreign_ejector_cluster = otr.ejector.cluster.get()
6961
graph.add_foreign_cluster(ForeignRelationType.RepFrom, foreign_ejector_cluster)
7062

dbm-ui/backend/tests/mock_data/components/itsm.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ def update_service(cls, *args, **kwargs):
7979
def create_ticket(cls, *args, **kwargs):
8080
response_data = copy.deepcopy(cls.base_info)
8181
response_data["data"] = {"sn": ticket_flow.SN}
82-
8382
return response_data["data"]
8483

8584
@classmethod
@@ -99,6 +98,22 @@ def ticket_approval_result(cls, *args, **kwargs):
9998

10099
return response_data["data"]
101100

101+
@classmethod
102+
def get_ticket_logs(cls, *args, **kwargs):
103+
response_data = copy.deepcopy(cls.base_info)
104+
response_data["data"] = {
105+
"sn": "REQ20200831000005",
106+
"title": "测试内置审批日志",
107+
"create_at": "2020-08-31 20:57:22",
108+
"creator": "xxx(xxx)",
109+
"logs": [
110+
{"operator": "xxx", "message": "流程开始"},
111+
{"operator": "xxx", "message": "xxx 处理节点【提单】(提交)"},
112+
{"operator": "admin", "message": "admin 处理节点【审批】(通过)"},
113+
],
114+
}
115+
return response_data["data"]
116+
102117
@classmethod
103118
def get_ticket_info(cls, *args, **kwargs):
104119
response_data = copy.deepcopy(cls.base_info)

dbm-ui/backend/tests/mock_data/ticket/sqlserver_flow.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,12 @@
140140
"bk_cloud_id": 0,
141141
"city_code": "深圳",
142142
"db_module_id": DB_MODULE_ID + 1,
143-
"cluster_count": 1,
143+
"cluster_count": 2,
144144
"inst_num": 1,
145145
"ip_source": "resource_pool",
146146
"nodes": {"backend": []},
147147
"resource_spec": {
148-
"sqlserver_ha": {
148+
"backend_group": {
149149
"spec_id": 102,
150150
"spec_name": "2核_4G_10G",
151151
"spec_cluster_type": "sqlserver_ha",

dbm-ui/backend/tests/mock_data/ticket/ticket_flow.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,9 @@
4343
MYSQL_FULL_BACKUP_TICKET_DATA = {
4444
"bk_biz_id": constant.BK_BIZ_ID,
4545
"details": {
46-
"infos": {
47-
"backup_type": "logical",
48-
"file_tag": "DBFILE1M",
49-
"clusters": [{"cluster_id": 1, "backup_local": "master"}],
50-
}
46+
"backup_type": "logical",
47+
"file_tag": "DBFILE1M",
48+
"infos": [{"cluster_id": 1, "backup_local": "master"}],
5149
},
5250
"remark": "",
5351
"ticket_type": "MYSQL_HA_FULL_BACKUP",

dbm-ui/backend/tests/ticket/test_ticket_revoke.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from backend.tests.mock_data.components.itsm import ItsmApiMock
2323
from backend.tests.mock_data.iam_app.permission import PermissionMock
2424
from backend.tests.mock_data.ticket.ticket_flow import MYSQL_FULL_BACKUP_TICKET_DATA, SN
25-
from backend.ticket.builders.mysql.mysql_ha_full_backup import MySQLHaFullBackupDetailSerializer
25+
from backend.ticket.builders.mysql.mysql_full_backup import MySQLFullBackupDetailSerializer
2626
from backend.ticket.constants import TicketStatus, TodoStatus, TodoType
2727
from backend.ticket.flow_manager.inner import InnerFlow
2828
from backend.ticket.handler import TicketHandler
@@ -46,19 +46,16 @@ class TestTicketRevoke:
4646
"""
4747

4848
@patch.object(TicketViewSet, "permission_classes")
49-
@patch.object(MySQLHaFullBackupDetailSerializer, "validate")
5049
@patch.object(InnerFlow, "status", new_callable=PropertyMock)
5150
@patch.object(TicketViewSet, "get_permissions", lambda x: [])
51+
@patch.object(MySQLFullBackupDetailSerializer, "validate", lambda self, attrs: attrs)
5252
@patch("backend.ticket.flow_manager.itsm.ItsmApi", ItsmApiMock())
5353
@patch("backend.db_services.cmdb.biz.CCApi", CCApiMock())
5454
@patch("backend.db_services.cmdb.biz.Permission", PermissionMock)
55-
def test_ticket_revoke(
56-
self, mocked_status, mocked_validate, mocked_permission_classes, query_fixture, db, init_app
57-
):
55+
def test_ticket_revoke(self, mocked_status, mocked_permission_classes, db, init_app):
5856
# 以全库备份为例,测试流程:start --> itsm --> inner --> end
5957
mocked_status.return_value = TicketStatus.SUCCEEDED
6058
mocked_permission_classes.return_value = [AllowAny]
61-
mocked_validate.return_value = MYSQL_FULL_BACKUP_TICKET_DATA
6259

6360
client.login(username="admin")
6461
# 创建单据

dbm-ui/backend/ticket/builders/sqlserver/sqlserver_ha_apply.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,22 +85,30 @@ def format_cluster_domains(self) -> List[Dict[str, str]]:
8585

8686
@classmethod
8787
def insert_ip_into_apply_infos(cls, ticket_data, infos: List[Dict]):
88-
backend_nodes = ticket_data["nodes"]["backend_group"]
88+
backend_nodes = ticket_data["nodes"][MachineType.SQLSERVER_HA.value]
8989
for index, apply_info in enumerate(infos):
90-
# # 每组集群需要两个后端 IP 和两个 Proxy IP
91-
# start, end = index * 2, (index + 1) * 2
92-
apply_info["mssql_master_host"] = backend_nodes[index]["master"]
93-
apply_info["mssql_slave_host"] = backend_nodes[index]["slave"]
90+
# 每组集群需要两个后端 IP 和两个 Proxy IP
91+
start, end = index * 2, (index + 1) * 2
92+
apply_info["mssql_master_host"] = backend_nodes[start:end][0]
93+
apply_info["mssql_slave_host"] = backend_nodes[start:end][1]
9494

9595

9696
class SQLServerHaApplyResourceParamBuilder(SQLServerSingleApplyResourceParamBuilder):
9797
def format(self):
9898
super().format()
9999

100+
@classmethod
101+
def insert_ip_into_apply_infos(cls, ticket_data, infos: List[Dict]):
102+
backend_nodes = ticket_data["nodes"]["backend_group"]
103+
for index, apply_info in enumerate(infos):
104+
# 每组集群需要两个后端 IP 和两个 Proxy IP
105+
apply_info["mssql_master_host"] = backend_nodes[index]["master"]
106+
apply_info["mssql_slave_host"] = backend_nodes[index]["slave"]
107+
100108
def post_callback(self):
101109
next_flow = self.ticket.next_flow()
102110
infos = next_flow.details["ticket_data"]["infos"]
103-
SQLServerHAApplyFlowParamBuilder.insert_ip_into_apply_infos(self.ticket.details, infos)
111+
self.insert_ip_into_apply_infos(self.ticket.details, infos)
104112
next_flow.details["ticket_data"]["resource_spec"]["sqlserver_ha"] = next_flow.details["ticket_data"][
105113
"resource_spec"
106114
]["master"]

dbm-ui/backend/ticket/builders/tendbcluster/base.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,8 @@ class TendbBaseOperateDetailSerializer(MySQLBaseOperateDetailSerializer):
5151

5252
# 实例不可用时,还能正常提单类型的白名单
5353
# spider 接入层异常, 只允许修复接入层异常的单据 1. 踢出故障 spider 2. 上架 (扩容) 新的 spider
54-
# slave或者 spider 不可用不影响分区单据
55-
SPIDER_UNAVAILABLE_WHITELIST = [
56-
TicketType.TENDBCLUSTER_PARTITION.value,
57-
]
54+
# slave或者 spider 不可用不影响分区单据。TODO:暂时放开spider异常限制
55+
SPIDER_UNAVAILABLE_WHITELIST = TicketType.get_values()
5856
# 存储层 master 异常 (dbha 因为某些问题未正常介入),只有切换单据可用
5957
REMOTE_MASTER_UNAVAILABLE_WHITELIST = [
6058
TicketType.TENDBCLUSTER_MASTER_SLAVE_SWITCH,
3.58 KB
Binary file not shown.

dbm-ui/backend/ticket/flow_manager/itsm.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,34 @@ def __init__(self, flow_obj: Flow):
3131
@property
3232
def ticket_approval_result(self):
3333
# 优先读取缓存,避免同一个对象内多次请求 ITSM
34-
# TODO: ITSM接口请求比较缓慢
3534
if getattr(self, "_ticket_approval_result", None):
3635
return self._ticket_approval_result
3736

3837
# 调用ITSM接口查询审批状态
39-
data = ItsmApi.ticket_approval_result({"sn": [self.flow_obj.flow_obj_id]}, use_admin=True)
4038
try:
39+
data = ItsmApi.ticket_approval_result({"sn": [self.flow_obj.flow_obj_id]}, use_admin=True)
4140
itsm_ticket_result = data[0]
42-
except IndexError:
41+
except (IndexError, ApiResultError):
4342
itsm_ticket_result = None
4443

4544
setattr(self, "_ticket_approval_result", itsm_ticket_result)
4645
return itsm_ticket_result
4746

47+
@property
48+
def ticket_logs(self):
49+
# 同ticket_approval_result,优先读取缓存
50+
if getattr(self, "_ticket_logs", None):
51+
return self._ticket_logs
52+
53+
try:
54+
itsm_logs = ItsmApi.get_ticket_logs({"sn": [self.flow_obj.flow_obj_id]}, use_admin=True)
55+
ticket_logs = itsm_logs["logs"]
56+
except (KeyError, ApiResultError):
57+
ticket_logs = []
58+
59+
setattr(self, "_ticket_logs", ticket_logs)
60+
return ticket_logs
61+
4862
@property
4963
def _start_time(self) -> str:
5064
return datetime2str(self.flow_obj.create_at)
@@ -58,23 +72,18 @@ def _end_time(self) -> Union[datetime, Any]:
5872

5973
@property
6074
def _summary(self) -> dict:
61-
try:
62-
logs = ItsmApi.get_ticket_logs({"sn": [self.flow_obj.flow_obj_id]})
63-
except ApiResultError:
64-
return _("未知单据")
65-
6675
# 获取单据审批状态
6776
current_status = self.ticket_approval_result["current_status"]
6877
approve_result = self.ticket_approval_result["approve_result"]
6978
summary = {"status": current_status, "approve_result": approve_result}
7079

7180
# 目前审批流程是固定的,取流程中第三个节点的日志作为概览即可
7281
try:
73-
summary.update(operator=logs["logs"][2]["operator"], message=logs["logs"][2]["message"])
82+
summary.update(operator=self.ticket_logs[2]["operator"], message=self.ticket_logs[2]["message"])
7483
except (IndexError, KeyError):
7584
# 异常时根据状态取默认的概览
7685
msg = TicketStatus.get_choice_label(self.status)
77-
summary.update(operator=logs["logs"][-1]["operator"], status=self.status, message=msg)
86+
summary.update(operator=self.ticket_logs[-1]["operator"], status=self.status, message=msg)
7887
return summary
7988

8089
@property
@@ -88,8 +97,8 @@ def _status(self) -> str:
8897
return self.flow_obj.update_status(TicketFlowStatus.RUNNING)
8998

9099
todo = self.flow_obj.todo_of_flow.first()
91-
updater = self.ticket_approval_result["updated_by"]
92-
100+
# 非进行中的单据,肯定已经来到了第三个节点,否则也无法处理todo
101+
updater = self.ticket_logs[2]["operator"]
93102
# 撤单
94103
if current_status == ItsmTicketStatus.REVOKED:
95104
todo.set_status(username=updater, status=TodoStatus.DONE_FAILED)

0 commit comments

Comments
 (0)