Skip to content

Commit e1ce7cc

Browse files
committed
feat(backend): 集群标准化需求新增业务模块导航与mysql单节点、主从集群列表汇总接口 #6628
# Reviewed, transaction id: 22881
1 parent b281ed6 commit e1ce7cc

File tree

13 files changed

+204
-31
lines changed

13 files changed

+204
-31
lines changed

dbm-ui/backend/db_services/cmdb/biz.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
import logging
1313
from typing import Dict, List
1414

15+
from django.db.models import Count
16+
1517
from backend.components import CCApi
1618
from backend.components.dbconfig.constants import DEPLOY_FILE_NAME, ConfType, LevelName
17-
from backend.db_meta.models import AppCache, DBModule
19+
from backend.db_meta.models import AppCache, Cluster, DBModule
1820
from backend.db_services.cmdb.exceptions import BkAppAttrAlreadyExistException
1921
from backend.db_services.dbconfig.dataclass import DBBaseConfig, DBConfigLevelData
2022
from backend.db_services.dbconfig.handlers import DBConfigHandler
@@ -221,3 +223,63 @@ def get_or_create_set_with_name(bk_biz_id: int, bk_set_name: str) -> int:
221223
raise err
222224
else:
223225
return bk_set_id
226+
227+
228+
def filter_by_biz_name(data: list, biz_name: str) -> list:
229+
return [biz for biz in data if biz["bk_biz_name"] == biz_name]
230+
231+
232+
def filter_by_module_name(data: list, module_name: str) -> list:
233+
result = []
234+
for biz in data:
235+
filtered_modules = [module for module in biz["modules"] if module["module_name"] == module_name]
236+
if filtered_modules:
237+
new_biz = biz.copy()
238+
new_biz["modules"] = filtered_modules
239+
result.append(new_biz)
240+
return result
241+
242+
243+
def list_biz_module_trees(cluster_types: str, bk_biz_name: str, module_name: str) -> List[Dict]:
244+
"""
245+
获取业务与模块维度集群数量
246+
"""
247+
248+
clusters = (
249+
Cluster.objects.filter(cluster_type__in=cluster_types.split(","))
250+
.values("db_module_id", "bk_biz_id")
251+
.annotate(count=Count("db_module_id"))
252+
.order_by("-count")
253+
)
254+
255+
db_module_map = DBModule.db_module_map()
256+
id_to_name = AppCache.id_to_name()
257+
258+
nested_data = collections.defaultdict(lambda: {"count": 0, "modules": collections.defaultdict(int)})
259+
for cluster in clusters:
260+
bk_biz_id = cluster["bk_biz_id"]
261+
db_module_id = cluster["db_module_id"]
262+
count = cluster["count"]
263+
nested_data[bk_biz_id]["count"] += count
264+
nested_data[bk_biz_id]["modules"][db_module_id] = count
265+
266+
final_data = []
267+
for bk_biz_id, data in nested_data.items():
268+
modules = [
269+
{"module_name": db_module_map.get(module_id), "module_id": module_id, "count": count}
270+
for module_id, count in data["modules"].items()
271+
]
272+
final_data.append(
273+
{
274+
"bk_biz_name": id_to_name.get(bk_biz_id),
275+
"bk_biz_id": bk_biz_id,
276+
"count": data["count"],
277+
"modules": modules,
278+
}
279+
)
280+
281+
if bk_biz_name:
282+
final_data = filter_by_biz_name(final_data, bk_biz_name)
283+
if module_name:
284+
final_data = filter_by_module_name(final_data, module_name)
285+
return final_data

dbm-ui/backend/db_services/cmdb/serializers.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,21 @@ class ListNodesSerializer(TopoSerializer):
7979
page = serializers.IntegerField(help_text=_("页数"))
8080
module_id = serializers.IntegerField(help_text=_("模块ID"), required=False)
8181
set_id = serializers.IntegerField(help_text=_("集群ID"), required=False)
82+
83+
84+
class ListBIZModulesSLZ(serializers.Serializer):
85+
cluster_types = serializers.CharField(help_text=_("集群类型(逗号分隔)"))
86+
bk_biz_name = serializers.CharField(help_text=_("业务名称"), required=False)
87+
module_name = serializers.CharField(help_text=_("模块名称"), required=False)
88+
89+
90+
class BIZModuleSLZ(serializers.Serializer):
91+
class ModuleClusterCountSLZ(serializers.Serializer):
92+
module_name = serializers.CharField(help_text=_("模块名"))
93+
module_id = serializers.IntegerField(help_text=_("模块ID"))
94+
count = serializers.IntegerField(help_text=_("集群数量"))
95+
96+
bk_biz_name = serializers.CharField(help_text=_("业务名"))
97+
bk_biz_id = serializers.IntegerField(help_text=_("业务ID"))
98+
count = serializers.IntegerField(help_text=_("集群数量"))
99+
modules = serializers.ListField(help_text=_("模块信息"), child=ModuleClusterCountSLZ())

dbm-ui/backend/db_services/cmdb/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
urlpatterns = [
1717
path("bizs/", CMDBViewSet.as_view({"get": "list_bizs"})),
1818
path("bizs/<int:bk_biz_id>/modules/", CMDBViewSet.as_view({"get": "list_modules"})),
19+
path("biz_module_trees/", CMDBViewSet.as_view({"get": "list_biz_module_trees"})),
1920
]
2021

2122
routers = DefaultRouter(trailing_slash=True)

dbm-ui/backend/db_services/cmdb/views.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,19 @@ def set_db_app_abbr(self, request, bk_biz_id):
9898
@action(methods=["GET"], detail=True)
9999
def list_cc_obj_user(self, request, bk_biz_id):
100100
return Response(biz.list_cc_obj_user(bk_biz_id))
101+
102+
@common_swagger_auto_schema(
103+
operation_summary=_("业务模块树信息"),
104+
query_serializer=serializers.ListBIZModulesSLZ(),
105+
responses={status.HTTP_200_OK: serializers.BIZModuleSLZ(label=_("业务模块树信息"), many=True)},
106+
tags=[SWAGGER_TAG],
107+
)
108+
@action(methods=["GET"], detail=False, serializer_class=serializers.ListBIZModulesSLZ)
109+
def list_biz_module_trees(self, request):
110+
cluster_types = self.params_validate(self.get_serializer_class()).get("cluster_types")
111+
bk_biz_name = self.params_validate(self.get_serializer_class()).get("bk_biz_name")
112+
module_name = self.params_validate(self.get_serializer_class()).get("module_name")
113+
serializer = serializers.BIZModuleSLZ(
114+
biz.list_biz_module_trees(cluster_types, bk_biz_name, module_name), many=True
115+
)
116+
return Response(serializer.data)

dbm-ui/backend/db_services/dbbase/serializers.py

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,18 @@
1717
from backend.configuration.constants import DBType
1818
from backend.db_dirty.models import DirtyMachine
1919
from backend.db_meta.enums import ClusterPhase, ClusterType
20+
from backend.db_meta.models import DBModule
2021
from backend.db_services.dbbase.constants import ResourceType
22+
from backend.db_services.dbbase.resources.query_base import build_q_for_domain_by_cluster
2123
from backend.db_services.dbbase.resources.serializers import ListResourceSLZ
2224
from backend.db_services.ipchooser.query.resource import ResourceQueryHelper
2325
from backend.db_services.redis.resources.redis_cluster.query import RedisListRetrieveResource
2426
from backend.dbm_init.constants import CC_APP_ABBR_ATTR
2527
from backend.ticket.constants import TicketType
2628

29+
db_module_id_name_map = DBModule.db_module_map()
30+
db_module_name_id_map = {module_name: module_id for module_id, module_name in db_module_id_name_map.items()}
31+
2732

2833
class IsClusterDuplicatedSerializer(serializers.Serializer):
2934
cluster_type = serializers.ChoiceField(help_text=_("集群类型"), choices=ClusterType.get_choices())
@@ -37,23 +42,57 @@ class Meta:
3742

3843

3944
class QueryAllTypeClusterSerializer(serializers.Serializer):
40-
bk_biz_id = serializers.IntegerField(help_text=_("业务ID"))
45+
bk_biz_id = serializers.IntegerField(help_text=_("业务ID"), required=False)
4146
cluster_types = serializers.CharField(help_text=_("集群类型(逗号分隔)"), required=False)
4247
immute_domain = serializers.CharField(help_text=_("集群域名"), required=False)
4348
# 额外过滤参数
4449
phase = serializers.ChoiceField(help_text=_("集群阶段状态"), required=False, choices=ClusterPhase.get_choices())
50+
name = serializers.CharField(help_text=_("集群英文名"), required=False)
51+
alias = serializers.CharField(help_text=_("集群别名"), required=False)
52+
db_module_id = serializers.IntegerField(help_text=_("模块id"), required=False)
53+
major_version = serializers.CharField(help_text=_("主版本号"), required=False)
54+
status = serializers.CharField(help_text=_("状态"), required=False)
55+
bk_cloud_id = serializers.IntegerField(help_text=_("云区域 ID"), required=False)
56+
region = serializers.CharField(help_text=_("地域"), required=False)
57+
db_module_name = serializers.CharField(help_text=_("模块名"), required=False)
58+
cluster_type = serializers.CharField(help_text=_("集群类型"), required=False)
4559

4660
def get_conditions(self, attr):
47-
conditions = {"bk_biz_id": attr["bk_biz_id"]}
61+
conditions = Q()
62+
4863
if attr.get("cluster_types"):
49-
conditions["cluster_type__in"] = attr["cluster_types"].split(",")
64+
conditions &= Q(cluster_type__in=attr["cluster_types"].split(","))
65+
attr.pop("cluster_types")
66+
67+
if attr.get("db_module_name"):
68+
db_module_id = db_module_name_id_map.get(attr["db_module_name"])
69+
if db_module_id is not None:
70+
conditions &= Q(db_module_id=db_module_id)
71+
attr.pop("db_module_name")
72+
5073
if attr.get("immute_domain"):
51-
conditions["immute_domain__icontains"] = attr["immute_domain"]
52-
# 额外过滤参数
53-
if attr.get("phase"):
54-
conditions["phase"] = attr["phase"]
74+
# 支持从域名查询
75+
conditions &= build_q_for_domain_by_cluster(domains=attr.get("immute_domain", "").split(","))
76+
attr.pop("immute_domain")
77+
78+
for field in self.fields.keys():
79+
if field in attr:
80+
conditions &= Q(**{field: attr[field]})
81+
5582
return conditions
5683

84+
def to_representation(self, instance):
85+
representation = super().to_representation(instance)
86+
db_module_id = representation.get("db_module_id")
87+
cloud_info = ResourceQueryHelper.search_cc_cloud(get_cache=True)
88+
representation["db_module_name"] = db_module_id_name_map.get(db_module_id, "")
89+
try:
90+
representation["bk_cloud_name"] = cloud_info[str(representation["bk_cloud_id"])]["bk_cloud_name"]
91+
except Exception:
92+
representation["bk_cloud_name"] = ""
93+
94+
return representation
95+
5796

5897
class QueryAllTypeClusterResponseSerializer(serializers.Serializer):
5998
class Meta:

dbm-ui/backend/db_services/dbbase/views.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
WebConsoleSerializer,
4646
)
4747
from backend.db_services.ipchooser.query.resource import ResourceQueryHelper
48-
from backend.iam_app.handlers.drf_perm.base import DBManagePermission
48+
from backend.iam_app.handlers.drf_perm.base import DBManagePermission, ListResourcePermission
4949
from backend.iam_app.handlers.drf_perm.cluster import ClusterWebconsolePermission
5050

5151
SWAGGER_TAG = _("集群通用接口")
@@ -60,11 +60,9 @@ class DBBaseViewSet(viewsets.SystemViewSet):
6060

6161
action_permission_map = {
6262
("verify_duplicated_cluster_name",): [],
63-
(
64-
"simple_query_cluster",
65-
"common_query_cluster",
66-
): [DBManagePermission()],
63+
("common_query_cluster",): [DBManagePermission()],
6764
("webconsole",): [ClusterWebconsolePermission()],
65+
("simple_query_cluster",): [ListResourcePermission()],
6866
}
6967
default_permission_class = [DBManagePermission()]
7068

@@ -92,9 +90,19 @@ def verify_duplicated_cluster_name(self, request, *args, **kwargs):
9290
def simple_query_cluster(self, request, *args, **kwargs):
9391
data = self.params_validate(self.get_serializer_class())
9492
conditions = self.get_serializer().get_conditions(data)
95-
cluster_queryset = Cluster.objects.filter(**conditions)
96-
cluster_infos = [cluster.simple_desc for cluster in cluster_queryset]
97-
return Response(cluster_infos)
93+
cluster_queryset = Cluster.objects.filter(conditions)
94+
# 兼容旧的不分页数据格式
95+
if not request.query_params.get("limit"):
96+
cluster_infos = [cluster.simple_desc for cluster in cluster_queryset]
97+
return Response(cluster_infos)
98+
99+
page = self.paginate_queryset(cluster_queryset)
100+
if page is not None:
101+
serializer = self.get_serializer(page, many=True)
102+
return self.get_paginated_response(serializer.data)
103+
104+
serializer = self.get_serializer(cluster_queryset, many=True)
105+
return Response(serializer.data)
98106

99107
@common_swagger_auto_schema(
100108
operation_summary=_("查询业务下集群通用信息"),

dbm-ui/backend/flow/engine/bamboo/scene/mysql/mysql_ha_standardize_flow.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,11 @@ def standardize(self):
6363
增加单据临时ADMIN账号的添加和删除逻辑
6464
"""
6565
cluster_ids = self.data["infos"]["cluster_ids"]
66-
bk_biz_id = self.data["bk_biz_id"]
66+
# 支持跨业务
67+
# bk_biz_id = self.data["bk_biz_id"]
6768

6869
cluster_objects = Cluster.objects.filter(
69-
pk__in=cluster_ids, bk_biz_id=bk_biz_id, cluster_type=ClusterType.TenDBHA.value
70+
pk__in=cluster_ids, cluster_type=ClusterType.TenDBHA.value
7071
).prefetch_related(
7172
"proxyinstance_set", "storageinstance_set", "proxyinstance_set__machine", "storageinstance_set__machine"
7273
)

dbm-ui/backend/flow/engine/bamboo/scene/spider/spider_cluster_standardize_flow.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,11 @@ def standardize(self):
6161
}
6262
"""
6363
cluster_ids = self.data["infos"]["cluster_ids"]
64-
bk_biz_id = self.data["bk_biz_id"]
64+
# 支持跨业务
65+
# bk_biz_id = self.data["bk_biz_id"]
6566

6667
cluster_objects = Cluster.objects.filter(
67-
pk__in=cluster_ids, bk_biz_id=bk_biz_id, cluster_type=ClusterType.TenDBCluster.value
68+
pk__in=cluster_ids, cluster_type=ClusterType.TenDBCluster.value
6869
).prefetch_related(
6970
"proxyinstance_set",
7071
"storageinstance_set",

dbm-ui/backend/flow/engine/bamboo/scene/tendbsingle/standardize.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ def __init__(self, root_id: str, data: Optional[Dict]):
5050

5151
def standardize(self):
5252
cluster_ids = self.data["infos"]["cluster_ids"]
53-
bk_biz_id = self.data["bk_biz_id"]
53+
# 支持跨业务
54+
# bk_biz_id = self.data["bk_biz_id"]
5455

5556
cluster_objects = Cluster.objects.filter(
56-
pk__in=cluster_ids, bk_biz_id=bk_biz_id, cluster_type=ClusterType.TenDBSingle.value
57+
pk__in=cluster_ids, cluster_type=ClusterType.TenDBSingle.value
5758
).prefetch_related("storageinstance_set", "storageinstance_set__machine")
5859
if cluster_objects.count() != len(cluster_ids):
5960
raise DBMetaException(

dbm-ui/backend/iam_app/handlers/drf_perm/base.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,26 @@ def has_authenticated_permission(self, request, view):
276276

277277
def has_permission(self, request, view):
278278
return permissions.IsAuthenticated().has_permission(request, view)
279+
280+
281+
class ListResourcePermission(ResourceActionPermission):
282+
"""
283+
业务相关动作的鉴权
284+
"""
285+
286+
def __init__(
287+
self, actions: List[ActionMeta] = None, resource_meta: ResourceMeta = None, bk_biz_id: int = None
288+
) -> None:
289+
self.bk_biz_id = bk_biz_id
290+
if not self.bk_biz_id:
291+
self.actions = ActionEnum.GLOBAL_MANAGE
292+
self.resource_meta = None
293+
else:
294+
self.actions = actions or [ActionEnum.DB_MANAGE]
295+
self.resource_meta = resource_meta or ResourceEnum.BUSINESS
296+
super().__init__(self.actions, self.resource_meta, instance_ids_getter=self.instance_biz_id_getter)
297+
298+
def instance_biz_id_getter(self, request, view):
299+
if not self.resource_meta:
300+
return []
301+
return self.get_key_id(request, view, self.resource_meta.id, many=True)

0 commit comments

Comments
 (0)