Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backend): 单据状态细化 #6755 #6756

Open
wants to merge 1 commit into
base: v1.5.0
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions dbm-ui/backend/db_services/bigdata/resources/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from backend.db_proxy.models import ClusterExtension
from backend.db_services.dbbase.resources import query
from backend.db_services.ipchooser.query.resource import ResourceQueryHelper
from backend.ticket.constants import TicketFlowStatus
from backend.ticket.constants import TICKET_RUNNING_STATUS
from backend.ticket.models import InstanceOperateRecord
from backend.utils.time import datetime2str

Expand Down Expand Up @@ -65,7 +65,7 @@ def _filter_instance_hook(cls, bk_biz_id, query_params, instances, **kwargs):

# 获取实例的操作与实例记录
records = InstanceOperateRecord.objects.filter(
instance_id__in=instance_ids, ticket__status=TicketFlowStatus.RUNNING
instance_id__in=instance_ids, ticket__status__in=TICKET_RUNNING_STATUS
)
instance_operate_records_map: Dict[int, List] = defaultdict(list)
for record in records:
Expand Down
4 changes: 2 additions & 2 deletions dbm-ui/backend/db_services/mysql/dumper/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from backend.db_meta.enums import InstanceInnerRole
from backend.db_meta.models import Cluster
from backend.db_services.mysql.dumper.models import DumperSubscribeConfig
from backend.ticket.constants import FlowType, TicketFlowStatus, TicketStatus, TicketType
from backend.ticket.constants import TICKET_RUNNING_STATUS, FlowType, TicketFlowStatus, TicketStatus, TicketType
from backend.ticket.models import Flow, Ticket


Expand Down Expand Up @@ -66,7 +66,7 @@ def patch_dumper_list_info(cls, dumper_results: List[Dict], bk_biz_id: int = 0,
dumper_ticket_types.remove(TicketType.TBINLOGDUMPER_INSTALL)
dumper_ticket_types.extend([TicketType.MYSQL_MASTER_SLAVE_SWITCH, TicketType.MYSQL_MASTER_FAIL_OVER])
active_tickets = Ticket.objects.filter(
bk_biz_id=bk_biz_id, status=TicketStatus.RUNNING, ticket_type__in=dumper_ticket_types
bk_biz_id=bk_biz_id, status__in=TICKET_RUNNING_STATUS, ticket_type__in=dumper_ticket_types
)
# 获取每个dumper单据状态与id的映射
dumper_inst_id__ticket: Dict[int, str] = {}
Expand Down
10 changes: 9 additions & 1 deletion dbm-ui/backend/dbm_init/json_files/itsm/itsm_dbm.json
Original file line number Diff line number Diff line change
Expand Up @@ -1398,5 +1398,13 @@
"display_role": "",
"source": "custom",
"project_key": "bk_dbm_dev",
"for_update": false
"for_update": true,
"remark_key": {
"0": "2b188068fc0864e15307933a953ed0b3",
"1": "d33b7919a6805e3e6f9162600b451657"
},
"approve_key": {
"0": "b58ca8d060692fe1fa91a4e9418d545a",
"1": "be937ddce3ec8435c96a8c313bae4836"
}
}
10 changes: 7 additions & 3 deletions dbm-ui/backend/dbm_init/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ def auto_create_itsm_service() -> int:
dbm_service_json["project_key"] = project_key
dbm_service_json["catalog_id"] = dbm_catalog_id
dbm_service_name = dbm_service_json["name"]

for_update = dbm_service_json.pop("for_update", False)
approve_key = dbm_service_json.pop("approve_key")
remark_key = dbm_service_json.pop("remark_key")

dbm_service_id = 0

try:
Expand All @@ -100,9 +104,9 @@ def auto_create_itsm_service() -> int:

# 更新到系统配置中
if dbm_service_id:
SystemSettings.insert_setting_value(
key=SystemSettingsEnum.BK_ITSM_SERVICE_ID.value, value=str(dbm_service_id)
)
SystemSettings.insert_setting_value(key=SystemSettingsEnum.BK_ITSM_SERVICE_ID, value=str(dbm_service_id))
SystemSettings.insert_setting_value(key=SystemSettingsEnum.ITSM_APPROVAL_KEY, value=approve_key)
SystemSettings.insert_setting_value(key=SystemSettingsEnum.ITSM_REMARK_KEY, value=remark_key)
logger.info("服务创建/更新成功")
else:
logger.info("本次更新跳过...")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
from pipeline.core.flow.io import ObjectItemSchema, StringItemSchema

from backend.flow.plugins.components.collections.common.base_service import BaseService
from backend.ticket.constants import TodoType
from backend.ticket.models import Ticket, Todo
from backend.ticket.todos.pipeline_todo import PipelineTodoContext
from backend.ticket.models import Ticket
from backend.ticket.todos.pipeline_todo import PipelineTodo

logger = logging.getLogger("root")

Expand All @@ -34,26 +33,14 @@ def _execute(self, data, parent_data):
self.log_info("execute PauseService")
kwargs = data.get_one_of_inputs("kwargs")
global_data = data.get_one_of_inputs("global_data")

# 获取单据和flow信息
ticket_id = global_data["uid"]
ticket = Ticket.objects.get(id=ticket_id)

# todo:这里假设ticket中不会出现并行的flow
flow = ticket.current_flow()

Todo.objects.create(
name=_("【{}】流程待确认,是否继续?").format(ticket.get_ticket_type_display()),
flow=flow,
ticket=ticket,
type=TodoType.INNER_APPROVE,
# todo: 待办人暂定为提单人
operators=[ticket.creator],
context=PipelineTodoContext(
flow.id,
ticket_id,
self.runtime_attrs.get("root_pipeline_id"),
self.runtime_attrs.get("id"),
).to_dict(),
)
# 创建一条代办
PipelineTodo.create(ticket, flow, self.runtime_attrs.get("root_pipeline_id"), self.runtime_attrs.get("id"))

self.log_info("pause kwargs: {}".format(kwargs))
return True
Expand Down
13 changes: 13 additions & 0 deletions dbm-ui/backend/tests/mock_data/ticket/ticket_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@
"ticket_type": "MYSQL_AUTHORIZE_RULES",
}

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"}],
}
},
"remark": "",
"ticket_type": "MYSQL_HA_FULL_BACKUP",
}

MYSQL_PERMISSION_ACCOUNT = {
"items": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@
SCALEUP_POOL_TICKET_DATA,
)
from backend.tests.ticket.server_base import TestFlowBase
from backend.ticket.constants import TicketFlowStatus, TicketStatus
from backend.ticket.constants import TicketFlowStatus

logger = logging.getLogger("test")
pytestmark = pytest.mark.django_db
client = APIClient()

INITIAL_FLOW_FINISHED_STATUS = [TicketFlowStatus.SKIPPED, TicketStatus.SUCCEEDED]
CHANGED_MOCK_STATUS = [TicketFlowStatus.SKIPPED, TicketStatus.SUCCEEDED, TicketFlowStatus.RUNNING]
INITIAL_FLOW_FINISHED_STATUS = [TicketFlowStatus.SKIPPED, TicketFlowStatus.SUCCEEDED]
CHANGED_MOCK_STATUS = [TicketFlowStatus.SKIPPED, TicketFlowStatus.SUCCEEDED, TicketFlowStatus.RUNNING]


@pytest.fixture(autouse=True) # autouse=True 会自动应用这个fixture到所有的测试中
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
pytestmark = pytest.mark.django_db
client = APIClient()

INITIAL_FLOW_FINISHED_STATUS = [TicketFlowStatus.SKIPPED, TicketStatus.SUCCEEDED]
INITIAL_FLOW_FINISHED_STATUS = [TicketFlowStatus.SKIPPED, TicketFlowStatus.SUCCEEDED]
CHANGED_MOCK_STATUS = [TicketFlowStatus.SKIPPED, TicketStatus.SUCCEEDED, TicketFlowStatus.RUNNING]


Expand Down
75 changes: 75 additions & 0 deletions dbm-ui/backend/tests/ticket/test_ticket_revoke.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
"""
TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available.
Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at https://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
import copy
import logging
from unittest.mock import PropertyMock, patch

import pytest
from django.conf import settings
from rest_framework.permissions import AllowAny
from rest_framework.test import APIClient

from backend.constants import DEFAULT_SYSTEM_USER
from backend.tests.mock_data.components.cc import CCApiMock
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.constants import TicketStatus, TodoStatus, TodoType
from backend.ticket.flow_manager.inner import InnerFlow
from backend.ticket.handler import TicketHandler
from backend.ticket.models import Flow, Ticket
from backend.ticket.views import TicketViewSet

logger = logging.getLogger("test")
pytestmark = pytest.mark.django_db
client = APIClient()


@pytest.fixture(autouse=True) # autouse=True 会自动应用这个fixture到所有的测试中
def set_empty_middleware():
with patch.object(settings, "MIDDLEWARE", []):
yield


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("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
):
# 以全库备份为例,测试流程: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")
# 创建单据
sql_import_data = copy.deepcopy(MYSQL_FULL_BACKUP_TICKET_DATA)
ticket = client.post("/apis/tickets/", data=sql_import_data).data

# 在todo流程终止
current_flow = Flow.objects.filter(flow_obj_id=SN).first()
client.post(f"/apis/tickets/{current_flow.ticket_id}/callback/")
TicketHandler.revoke_ticket(ticket_ids=[ticket["id"]], operator=DEFAULT_SYSTEM_USER)
# 验证单据和todo已经终止
revoke_ticket = Ticket.objects.get(id=ticket["id"])
assert revoke_ticket.status == TicketStatus.TERMINATED
assert revoke_ticket.todo_of_ticket.filter(type=TodoType.APPROVE)[0].status == TodoStatus.DONE_FAILED
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,4 @@ class MySQLHaFullBackupFlowParamBuilder(builders.FlowParamBuilder):
class MySQLHaFullBackupFlowBuilder(BaseMySQLHATicketFlowBuilder):
serializer = MySQLHaFullBackupDetailSerializer
inner_flow_builder = MySQLHaFullBackupFlowParamBuilder
inner_flow_name = _("全库备份执行")
retry_type = FlowRetryType.MANUAL_RETRY
retry_type = FlowRetryType.AUTO_RETRY
Loading