Skip to content

Commit

Permalink
fix: bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
iSecloud committed Oct 21, 2024
1 parent 277c153 commit 67eec35
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 94 deletions.
7 changes: 7 additions & 0 deletions dbm-ui/backend/ticket/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ class TicketStatus(str, StructuredEnum):
TicketStatus.RUNNING,
TicketStatus.TIMER,
]
TICKET_TODO_STATUS = [
TicketStatus.APPROVE,
TicketStatus.TODO,
TicketStatus.RESOURCE_REPLENISH,
TicketStatus.FAILED,
TicketStatus.RUNNING,
]
TICKET_FAILED_STATUS = [TicketStatus.REVOKED, TicketStatus.TERMINATED, TicketStatus.FAILED]


Expand Down
31 changes: 30 additions & 1 deletion dbm-ui/backend/ticket/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from backend.db_meta.models import Cluster
from backend.ticket.constants import TODO_RUNNING_STATUS
from backend.ticket.models import ClusterOperateRecord, Ticket
from backend.ticket.models import ClusterOperateRecord, InstanceOperateRecord, Ticket


class TicketListFilter(filters.FilterSet):
Expand Down Expand Up @@ -51,3 +51,32 @@ def filter_todo(self, queryset, name, value):
)
else:
return queryset.filter(todo_of_ticket__done_by=user)


class OpRecordListFilter(filters.FilterSet):
start_time = filters.DateTimeFilter(field_name="create_at", lookup_expr="gte", label=_("开始时间"))
end_time = filters.DateTimeFilter(field_name="create_at", lookup_expr="lte", label=_("开始时间"))
op_type = filters.CharFilter(field_name="op_type", method="filter_op_type", label=_("操作类型"))
op_status = filters.CharFilter(field_name="op_status", method="filter_op_status", label=_("操作状态"))

def filter_op_type(self, queryset, name, value):
return queryset.filter(ticket__ticket_type=value)

def filter_op_status(self, queryset, name, value):
return queryset.filter(ticket__status=value)


class ClusterOpRecordListFilter(OpRecordListFilter):
cluster_id = filters.NumberFilter(field_name="cluster_id", lookup_expr="exact", label=_("集群ID"))

class Meta:
model = ClusterOperateRecord
fields = ["start_time", "end_time", "op_type", "op_status"]


class InstanceOpRecordListFilter(OpRecordListFilter):
instance_id = filters.NumberFilter(field_name="instance_id", lookup_expr="exact", label=_("实例ID"))

class Meta:
model = InstanceOperateRecord
fields = ["start_time", "end_time", "op_type", "op_status"]
49 changes: 46 additions & 3 deletions dbm-ui/backend/ticket/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,21 @@
FLOW_FINISHED_STATUS,
ITSM_FIELD_NAME__ITSM_KEY,
RUNNING_FLOW__TICKET_STATUS,
FlowType,
FlowTypeConfig,
OperateNodeActionType,
TicketFlowStatus,
TicketStatus,
TicketType,
TodoStatus,
TodoType,
)
from backend.ticket.exceptions import TicketFlowsConfigException
from backend.ticket.flow_manager.manager import TicketFlowManager
from backend.ticket.models import Flow, Ticket, TicketFlowsConfig, Todo
from backend.ticket.serializers import TodoSerializer
from backend.ticket.todos import TodoActorFactory
from backend.ticket.todos import BaseTodoContext, TodoActorFactory
from backend.ticket.todos.itsm_todo import ItsmTodoContext

logger = logging.getLogger("root")

Expand Down Expand Up @@ -425,14 +429,53 @@ def ticket_status_standardization(cls):
"""
旧单据状态标准化。TODO: 迁移后此段代码可删除
"""
# 标准化只针对running的单据,其他状态单据不影响
running_tickets = Ticket.objects.filter(status=TicketStatus.RUNNING)
batch = 50

# 标准化只针对running的单据,其他状态单据不影响
running_tickets = Ticket.objects.filter(status=TicketStatus.RUNNING)
for current in range(0, running_tickets.count(), batch):
for ticket in running_tickets[current : current + batch]:
raw_status = ticket.status
ticket.status = RUNNING_FLOW__TICKET_STATUS[ticket.current_flow().flow_type]
ticket.save()
print(f"ticket[{ticket.id}] status {raw_status} ---> {ticket.status}")
time.sleep(1)

# 失败的单据要增加一条todo关联
failed_tickets = Ticket.objects.prefetch_related("flows").filter(status=TicketStatus.FAILED)
for current in range(0, running_tickets.count(), batch):
for ticket in failed_tickets[current : current + batch]:
inner_flow = ticket.flows.filter(flow_type=FlowType.INNER_FLOW, status=TicketFlowStatus.FAILED).first()
if not inner_flow or inner_flow.todo_of_flow.exists():
continue
Todo.objects.create(
name=_("【{}】单据任务执行失败,待处理").format(ticket.get_ticket_type_display()),
flow=inner_flow,
ticket=ticket,
type=TodoType.INNER_FAILED,
operators=[ticket.creator],
context=BaseTodoContext(inner_flow.id, ticket.id).to_dict(),
status=TodoStatus.TODO,
)
print(f"ticket[{ticket.id}] add a failed todo")
time.sleep(1)

# 待审批的单据要增加一条todo关联
itsm_tickets = Ticket.objects.prefetch_related("flows").filter(status=TicketStatus.FAILED)
for current in range(0, running_tickets.count(), batch):
for ticket in itsm_tickets[current : current + batch]:
itsm_flow = ticket.flows.filter(flow_type=FlowType.BK_ITSM, status=TicketFlowStatus.RUNNING).first()
if not itsm_flow or itsm_flow.todo_of_flow.exists():
continue
itsm_fields = {f["key"]: f["value"] for f in itsm_flow.details["fields"]}
operators = itsm_fields["approver"].split(",")
Todo.objects.create(
name=_("【{}】单据等待审批").format(ticket.get_ticket_type_display()),
flow=itsm_flow,
ticket=ticket,
type=TodoType.ITSM,
operators=operators,
context=ItsmTodoContext(itsm_flow.id, ticket.id).to_dict(),
)
print(f"ticket[{ticket.id}] add a itsm todo")
time.sleep(1)
22 changes: 15 additions & 7 deletions dbm-ui/backend/ticket/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,20 +274,28 @@ class GetTodosSLZ(serializers.Serializer):
)


class ClusterModifyOpSerializer(serializers.Serializer):
cluster_id = serializers.IntegerField(help_text=_("集群ID"))
class OpRecordSerializer(serializers.Serializer):
start_time = serializers.DateTimeField(help_text=_("查询起始时间"), required=False)
end_time = serializers.DateTimeField(help_text=_("查询终止时间"), required=False)
op_type = serializers.ChoiceField(help_text=_("操作类型"), choices=TicketType.get_choices(), required=False)
op_status = serializers.ChoiceField(help_text=_("操作状态"), choices=TicketStatus.get_choices(), required=False)

def to_representation(self, instance):
return {
"create_at": instance.create_at,
"op_type": instance.ticket.ticket_type,
"op_status": instance.ticket.status,
"ticket_id": instance.ticket.id,
"creator": instance.creator,
}


class ClusterModifyOpSerializer(OpRecordSerializer):
cluster_id = serializers.IntegerField(help_text=_("集群ID"))


class InstanceModifyOpSerializer(serializers.Serializer):
class InstanceModifyOpSerializer(OpRecordSerializer):
instance_id = serializers.IntegerField(help_text=_("实例ID"))
start_time = serializers.DateTimeField(help_text=_("查询起始时间"), required=False)
end_time = serializers.DateTimeField(help_text=_("查询终止时间"), required=False)
op_type = serializers.ChoiceField(help_text=_("操作类型"), choices=TicketType.get_choices(), required=False)
op_status = serializers.ChoiceField(help_text=_("操作状态"), choices=TicketStatus.get_choices(), required=False)


class QueryTicketFlowDescribeSerializer(serializers.Serializer):
Expand Down
4 changes: 3 additions & 1 deletion dbm-ui/backend/ticket/todos/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from dataclasses import asdict, dataclass
from typing import Callable

from blueapps.account.models import User
from django.utils.translation import ugettext_lazy as _

from backend.constants import DEFAULT_SYSTEM_USER
Expand All @@ -40,7 +41,8 @@ def name(cls):
return cls.__name__

def process(self, username, action, params):
if username not in self.todo.operators and username != DEFAULT_SYSTEM_USER:
is_superuser = User.objects.get(username=username).is_superuser
if not is_superuser and username not in self.todo.operators and username != DEFAULT_SYSTEM_USER:
raise TodoWrongOperatorException(_("{}不在处理人: {}中,无法处理").format(username, self.todo.operators))
self._process(username, action, params)

Expand Down
14 changes: 2 additions & 12 deletions dbm-ui/backend/ticket/todos/pause_todo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,9 @@
"""
from dataclasses import dataclass

from django.utils.translation import gettext as _

from backend.constants import DEFAULT_SYSTEM_USER
from backend.db_meta.models.sqlserver_dts import DtsStatus, SqlserverDtsInfo
from backend.ticket import todos
from backend.ticket.constants import TicketFlowStatus, TicketType, TodoType
from backend.ticket.exceptions import TodoWrongOperatorException
from backend.ticket.flow_manager import manager
from backend.ticket.flow_manager.manager import TicketFlowManager
from backend.ticket.todos import ActionType, BaseTodoContext
Expand All @@ -37,11 +33,8 @@ class ResourceReplenishTodoContext(BaseTodoContext):
class PauseTodo(todos.TodoActor):
"""来自主流程的待办"""

def process(self, username, action, params):
def _process(self, username, action, params):
"""确认/终止"""
if username not in self.todo.operators and username != DEFAULT_SYSTEM_USER:
raise TodoWrongOperatorException(_("{}不在处理人: {}中,无法处理").format(username, self.todo.operators))

if action == ActionType.TERMINATE:
self.todo.set_terminated(username, action)
return
Expand All @@ -63,11 +56,8 @@ def process(self, username, action, params):
class ResourceReplenishTodo(todos.TodoActor):
"""资源补货的代办"""

def process(self, username, action, params):
def _process(self, username, action, params):
"""确认/终止"""
if username not in self.todo.operators and username != DEFAULT_SYSTEM_USER:
raise TodoWrongOperatorException(_("{}不在处理人: {}中,无法处理").format(username, self.todo.operators))

# 终止单据
if action == ActionType.TERMINATE:
self.todo.set_terminated(username, action)
Expand Down
9 changes: 1 addition & 8 deletions dbm-ui/backend/ticket/todos/pipeline_todo.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@
import logging
from dataclasses import dataclass

from django.utils.translation import gettext as _

from backend.constants import DEFAULT_SYSTEM_USER
from backend.flow.engine.bamboo.engine import BambooEngine
from backend.ticket import todos
from backend.ticket.constants import TodoType
from backend.ticket.exceptions import TodoWrongOperatorException
from backend.ticket.models import TodoHistory
from backend.ticket.todos import ActionType, BaseTodoContext

Expand All @@ -34,11 +30,8 @@ class PipelineTodoContext(BaseTodoContext):
class PipelineTodo(todos.TodoActor):
"""来自自动化流程中的待办"""

def process(self, username, action, params):
def _process(self, username, action, params):
"""确认/终止"""
if username not in self.todo.operators and username != DEFAULT_SYSTEM_USER:
raise TodoWrongOperatorException(_("{}不在处理人: {}中,无法处理").format(username, self.todo.operators))

# 从todo的上下文获取pipeline节点信息
root_id, node_id = self.context.get("root_id"), self.context.get("node_id")
engine = BambooEngine(root_id=root_id)
Expand Down
85 changes: 23 additions & 62 deletions dbm-ui/backend/ticket/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@
from backend.ticket.builders.common.base import InfluxdbTicketFlowBuilderPatchMixin, fetch_cluster_ids
from backend.ticket.constants import (
TICKET_RUNNING_STATUS,
TICKET_TODO_STATUS,
TODO_RUNNING_STATUS,
CountType,
TicketStatus,
TicketType,
TodoType,
)
from backend.ticket.contexts import TicketContext
from backend.ticket.exceptions import TicketDuplicationException
from backend.ticket.filters import TicketListFilter
from backend.ticket.filters import ClusterOpRecordListFilter, InstanceOpRecordListFilter, TicketListFilter
from backend.ticket.flow_manager.manager import TicketFlowManager
from backend.ticket.handler import TicketHandler
from backend.ticket.models import ClusterOperateRecord, InstanceOperateRecord, Ticket, TicketFlowsConfig
Expand Down Expand Up @@ -428,10 +428,9 @@ def get_tickets_count(self, request, *args, **kwargs):
# 我的申请
count_map[CountType.MY_APPROVE] = tickets.filter(creator=user).count()
# 我的代办
todo_status = [TicketStatus.APPROVE, TicketStatus.TODO, TicketStatus.RESOURCE_REPLENISH, TicketStatus.FAILED]
my_todo = (
tickets.filter(
status__in=todo_status,
status__in=TICKET_TODO_STATUS,
todo_of_ticket__operators__contains=user,
todo_of_ticket__status__in=TODO_RUNNING_STATUS,
)
Expand All @@ -448,73 +447,35 @@ def get_tickets_count(self, request, *args, **kwargs):

@common_swagger_auto_schema(
operation_summary=_("查询集群变更单据事件"),
query_serializer=ClusterModifyOpSerializer(),
tags=[TICKET_TAG],
)
@action(methods=["GET"], detail=False, serializer_class=ClusterModifyOpSerializer)
@action(
methods=["GET"],
detail=False,
serializer_class=ClusterModifyOpSerializer,
queryset=ClusterOperateRecord.objects.select_related("ticket").order_by("-create_at"),
filter_class=ClusterOpRecordListFilter,
)
def get_cluster_operate_records(self, request, *args, **kwargs):
validated_data = self.params_validate(self.get_serializer_class())
op_filters = Q(cluster_id=validated_data["cluster_id"])
if validated_data.get("start_time"):
op_filters &= Q(create_at__gte=validated_data.get("start_time"))

if validated_data.get("end_time"):
op_filters &= Q(create_at__lte=validated_data.get("end_time"))

if validated_data.get("op_type"):
op_filters &= Q(ticket__ticket_type=validated_data.get("op_type"))

if validated_data.get("op_status"):
op_filters &= Q(ticket__status=validated_data.get("op_status"))

op_records = ClusterOperateRecord.objects.select_related("ticket").filter(op_filters).order_by("-create_at")
op_records_info = [
{
"create_at": record.create_at,
"op_type": TicketType.get_choice_label(record.ticket.ticket_type),
"op_status": record.ticket.status,
"ticket_id": record.ticket.id,
"creator": record.creator,
}
for record in op_records
]
op_records_page = self.paginate_queryset(op_records_info)
return self.get_paginated_response(op_records_page)
op_records_page_qs = self.paginate_queryset(self.filter_queryset(self.queryset))
op_records_page_data = self.serializer_class(op_records_page_qs, many=True).data
return self.get_paginated_response(data=op_records_page_data)

@common_swagger_auto_schema(
operation_summary=_("查询集群实例变更单据事件"),
query_serializer=InstanceModifyOpSerializer(),
tags=[TICKET_TAG],
)
@action(methods=["GET"], detail=False, serializer_class=InstanceModifyOpSerializer)
@action(
methods=["GET"],
detail=False,
serializer_class=InstanceModifyOpSerializer,
queryset=InstanceOperateRecord.objects.select_related("ticket").order_by("-create_at"),
filter_class=InstanceOpRecordListFilter,
)
def get_instance_operate_records(self, request, *args, **kwargs):
validated_data = self.params_validate(self.get_serializer_class())
op_filters = Q(instance_id=validated_data["instance_id"])
if validated_data.get("start_time"):
op_filters &= Q(create_at__gte=validated_data.get("start_time"))

if validated_data.get("end_time"):
op_filters &= Q(create_at__lte=validated_data.get("end_time"))

if validated_data.get("op_type"):
op_filters &= Q(ticket__ticket_type=validated_data.get("op_type"))

if validated_data.get("op_status"):
op_filters &= Q(ticket__status=validated_data.get("op_status"))

op_records = InstanceOperateRecord.objects.select_related("ticket").filter(op_filters).order_by("-create_at")
op_records_info = [
{
"create_at": record.create_at,
"op_type": TicketType.get_choice_label(record.ticket.ticket_type),
"op_status": record.ticket.status,
"ticket_id": record.ticket.id,
"creator": record.creator,
}
for record in op_records
]
op_records_page = self.paginate_queryset(op_records_info)
return self.get_paginated_response(op_records_page)
op_records_page_qs = self.paginate_queryset(self.filter_queryset(self.queryset))
op_records_page_data = self.serializer_class(op_records_page_qs, many=True).data
return self.get_paginated_response(data=op_records_page_data)

@swagger_auto_schema(
operation_summary=_("查询可编辑单据流程描述"),
Expand Down

0 comments on commit 67eec35

Please sign in to comment.