Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions dbm-ui/backend/db_meta/api/cluster/tendbha/detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,11 @@ def scan_cluster(cluster: Cluster) -> Graphic:
dummy_slave_be_node, slave_be_group = graph.add_node(slave_be, to_group=slave_be_group)
graph.add_line(source=slave_be_group, target=receiver_instance_group, label=LineLabel.Bind)

for otr in (
StorageInstanceTuple.objects.filter(ejector=ejector_instance)
.prefetch_related("cluster")
.exclude(receiver__cluster=cluster)
):
for otr in StorageInstanceTuple.objects.filter(ejector=ejector_instance).exclude(receiver__cluster=cluster):
foreign_receiver_cluster = otr.receiver.cluster.get()
graph.add_foreign_cluster(ForeignRelationType.RepTo, foreign_receiver_cluster)

for otr in (
StorageInstanceTuple.objects.filter(receiver=ejector_instance)
.prefetch_related("cluster")
.exclude(ejector__cluster=cluster)
):
for otr in StorageInstanceTuple.objects.filter(receiver=ejector_instance).exclude(ejector__cluster=cluster):
foreign_ejector_cluster = otr.ejector.cluster.get()
graph.add_foreign_cluster(ForeignRelationType.RepFrom, foreign_ejector_cluster)

Expand Down
17 changes: 16 additions & 1 deletion dbm-ui/backend/tests/mock_data/components/itsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ def update_service(cls, *args, **kwargs):
def create_ticket(cls, *args, **kwargs):
response_data = copy.deepcopy(cls.base_info)
response_data["data"] = {"sn": ticket_flow.SN}

return response_data["data"]

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

return response_data["data"]

@classmethod
def get_ticket_logs(cls, *args, **kwargs):
response_data = copy.deepcopy(cls.base_info)
response_data["data"] = {
"sn": "REQ20200831000005",
"title": "测试内置审批日志",
"create_at": "2020-08-31 20:57:22",
"creator": "xxx(xxx)",
"logs": [
{"operator": "xxx", "message": "流程开始"},
{"operator": "xxx", "message": "xxx 处理节点【提单】(提交)"},
{"operator": "admin", "message": "admin 处理节点【审批】(通过)"},
],
}
return response_data["data"]

@classmethod
def get_ticket_info(cls, *args, **kwargs):
response_data = copy.deepcopy(cls.base_info)
Expand Down
4 changes: 2 additions & 2 deletions dbm-ui/backend/tests/mock_data/ticket/sqlserver_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,12 @@
"bk_cloud_id": 0,
"city_code": "深圳",
"db_module_id": DB_MODULE_ID + 1,
"cluster_count": 1,
"cluster_count": 2,
"inst_num": 1,
"ip_source": "resource_pool",
"nodes": {"backend": []},
"resource_spec": {
"sqlserver_ha": {
"backend_group": {
"spec_id": 102,
"spec_name": "2核_4G_10G",
"spec_cluster_type": "sqlserver_ha",
Expand Down
8 changes: 3 additions & 5 deletions dbm-ui/backend/tests/mock_data/ticket/ticket_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,9 @@
MYSQL_FULL_BACKUP_TICKET_DATA = {
"bk_biz_id": constant.BK_BIZ_ID,
"details": {
"infos": {
"backup_type": "logical",
"file_tag": "DBFILE1M",
"clusters": [{"cluster_id": 1, "backup_local": "master"}],
}
"backup_type": "logical",
"file_tag": "DBFILE1M",
"infos": [{"cluster_id": 1, "backup_local": "master"}],
},
"remark": "",
"ticket_type": "MYSQL_HA_FULL_BACKUP",
Expand Down
9 changes: 3 additions & 6 deletions dbm-ui/backend/tests/ticket/test_ticket_revoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from backend.tests.mock_data.components.itsm import ItsmApiMock
from backend.tests.mock_data.iam_app.permission import PermissionMock
from backend.tests.mock_data.ticket.ticket_flow import MYSQL_FULL_BACKUP_TICKET_DATA, SN
from backend.ticket.builders.mysql.mysql_ha_full_backup import MySQLHaFullBackupDetailSerializer
from backend.ticket.builders.mysql.mysql_full_backup import MySQLFullBackupDetailSerializer
from backend.ticket.constants import TicketStatus, TodoStatus, TodoType
from backend.ticket.flow_manager.inner import InnerFlow
from backend.ticket.handler import TicketHandler
Expand All @@ -46,19 +46,16 @@ class TestTicketRevoke:
"""

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

client.login(username="admin")
# 创建单据
Expand Down
20 changes: 14 additions & 6 deletions dbm-ui/backend/ticket/builders/sqlserver/sqlserver_ha_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,30 @@ def format_cluster_domains(self) -> List[Dict[str, str]]:

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


class SQLServerHaApplyResourceParamBuilder(SQLServerSingleApplyResourceParamBuilder):
def format(self):
super().format()

@classmethod
def insert_ip_into_apply_infos(cls, ticket_data, infos: List[Dict]):
backend_nodes = ticket_data["nodes"]["backend_group"]
for index, apply_info in enumerate(infos):
# 每组集群需要两个后端 IP 和两个 Proxy IP
apply_info["mssql_master_host"] = backend_nodes[index]["master"]
apply_info["mssql_slave_host"] = backend_nodes[index]["slave"]

def post_callback(self):
next_flow = self.ticket.next_flow()
infos = next_flow.details["ticket_data"]["infos"]
SQLServerHAApplyFlowParamBuilder.insert_ip_into_apply_infos(self.ticket.details, infos)
self.insert_ip_into_apply_infos(self.ticket.details, infos)
next_flow.details["ticket_data"]["resource_spec"]["sqlserver_ha"] = next_flow.details["ticket_data"][
"resource_spec"
]["master"]
Expand Down
6 changes: 2 additions & 4 deletions dbm-ui/backend/ticket/builders/tendbcluster/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ class TendbBaseOperateDetailSerializer(MySQLBaseOperateDetailSerializer):

# 实例不可用时,还能正常提单类型的白名单
# spider 接入层异常, 只允许修复接入层异常的单据 1. 踢出故障 spider 2. 上架 (扩容) 新的 spider
# slave或者 spider 不可用不影响分区单据
SPIDER_UNAVAILABLE_WHITELIST = [
TicketType.TENDBCLUSTER_PARTITION.value,
]
# slave或者 spider 不可用不影响分区单据。TODO:暂时放开spider异常限制
SPIDER_UNAVAILABLE_WHITELIST = TicketType.get_values()
# 存储层 master 异常 (dbha 因为某些问题未正常介入),只有切换单据可用
REMOTE_MASTER_UNAVAILABLE_WHITELIST = [
TicketType.TENDBCLUSTER_MASTER_SLAVE_SWITCH,
Expand Down
Binary file modified dbm-ui/backend/ticket/exclusive_ticket.xlsx
Binary file not shown.
33 changes: 21 additions & 12 deletions dbm-ui/backend/ticket/flow_manager/itsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,34 @@ def __init__(self, flow_obj: Flow):
@property
def ticket_approval_result(self):
# 优先读取缓存,避免同一个对象内多次请求 ITSM
# TODO: ITSM接口请求比较缓慢
if getattr(self, "_ticket_approval_result", None):
return self._ticket_approval_result

# 调用ITSM接口查询审批状态
data = ItsmApi.ticket_approval_result({"sn": [self.flow_obj.flow_obj_id]}, use_admin=True)
try:
data = ItsmApi.ticket_approval_result({"sn": [self.flow_obj.flow_obj_id]}, use_admin=True)
itsm_ticket_result = data[0]
except IndexError:
except (IndexError, ApiResultError):
itsm_ticket_result = None

setattr(self, "_ticket_approval_result", itsm_ticket_result)
return itsm_ticket_result

@property
def ticket_logs(self):
# 同ticket_approval_result,优先读取缓存
if getattr(self, "_ticket_logs", None):
return self._ticket_logs

try:
itsm_logs = ItsmApi.get_ticket_logs({"sn": [self.flow_obj.flow_obj_id]}, use_admin=True)
ticket_logs = itsm_logs["logs"]
except (KeyError, ApiResultError):
ticket_logs = []

setattr(self, "_ticket_logs", ticket_logs)
return ticket_logs

@property
def _start_time(self) -> str:
return datetime2str(self.flow_obj.create_at)
Expand All @@ -58,23 +72,18 @@ def _end_time(self) -> Union[datetime, Any]:

@property
def _summary(self) -> dict:
try:
logs = ItsmApi.get_ticket_logs({"sn": [self.flow_obj.flow_obj_id]})
except ApiResultError:
return _("未知单据")

# 获取单据审批状态
current_status = self.ticket_approval_result["current_status"]
approve_result = self.ticket_approval_result["approve_result"]
summary = {"status": current_status, "approve_result": approve_result}

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

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

todo = self.flow_obj.todo_of_flow.first()
updater = self.ticket_approval_result["updated_by"]

# 非进行中的单据,肯定已经来到了第三个节点,否则也无法处理todo
updater = self.ticket_logs[2]["operator"]
# 撤单
if current_status == ItsmTicketStatus.REVOKED:
todo.set_status(username=updater, status=TodoStatus.DONE_FAILED)
Expand Down
Loading