diff --git a/dbm-ui/backend/db_services/bigdata/resources/query.py b/dbm-ui/backend/db_services/bigdata/resources/query.py index 51417b0c5f..a1adece1aa 100644 --- a/dbm-ui/backend/db_services/bigdata/resources/query.py +++ b/dbm-ui/backend/db_services/bigdata/resources/query.py @@ -105,7 +105,7 @@ def _to_cluster_representation( cls, cluster: Cluster, cluster_entry: List[Dict[str, str]], - db_module_names_map: Dict[int, str], + db_module_config_map: Dict[int, Dict[str, str]], cluster_entry_map: Dict[int, Dict[str, str]], cluster_operate_records_map: Dict[int, List], cloud_info: Dict[str, Any], @@ -118,7 +118,7 @@ def _to_cluster_representation( cluster_info = super()._to_cluster_representation( cluster, cluster_entry, - db_module_names_map, + db_module_config_map, cluster_entry_map, cluster_operate_records_map, cloud_info, diff --git a/dbm-ui/backend/db_services/dbbase/resources/query.py b/dbm-ui/backend/db_services/dbbase/resources/query.py index 356d5dbd62..f3ad93a95f 100644 --- a/dbm-ui/backend/db_services/dbbase/resources/query.py +++ b/dbm-ui/backend/db_services/dbbase/resources/query.py @@ -16,10 +16,12 @@ from django.http import HttpResponse from django.utils.translation import ugettext_lazy as _ +from backend.configuration.constants import DBType from backend.constants import IP_PORT_DIVIDER from backend.db_meta.enums import ClusterEntryType, ClusterType, InstanceRole from backend.db_meta.enums.comm import SystemTagEnum from backend.db_meta.models import AppCache, Cluster, ClusterEntry, DBModule, Machine, ProxyInstance, StorageInstance +from backend.db_services.cmdb.biz import list_modules_by_biz from backend.db_services.dbbase.instances.handlers import InstanceHandler from backend.db_services.dbbase.resources.query_base import ( build_q_for_domain_by_cluster, @@ -485,7 +487,11 @@ def _filter_cluster_hook( # 预取proxy_queryset,storage_queryset,clusterentry_set,加块查询效率 cluster_list = cluster_queryset[offset : limit + offset].prefetch_related( Prefetch("proxyinstance_set", queryset=proxy_queryset.select_related("machine"), to_attr="proxies"), - Prefetch("storageinstance_set", queryset=storage_queryset.select_related("machine"), to_attr="storages"), + Prefetch( + "storageinstance_set", + queryset=storage_queryset.select_related("machine").prefetch_related("as_ejector", "as_receiver"), + to_attr="storages", + ), Prefetch("clusterentry_set", to_attr="entries"), "tag_set", ) @@ -496,14 +502,26 @@ def _filter_cluster_hook( # 获取集群与访问入口的映射 cluster_entry_map = ClusterEntry.get_cluster_entry_map(cluster_ids) - # 获取DB模块的映射信息 - db_module_names_map = { - module["db_module_id"]: module["db_module_name"] + # 获取DB模块dbconfig的映射信息 + db_module_config_map = { + module["db_module_id"]: { + "bk_biz_id": module["bk_biz_id"], + "db_module_id": module["db_module_id"], + "name": module["db_module_name"], + "alias_name": module["alias_name"], + } for module in DBModule.objects.filter(bk_biz_id=bk_biz_id, cluster_type__in=cls.cluster_types).values( - "db_module_id", "db_module_name" + "bk_biz_id", "db_module_id", "db_module_name", "alias_name" ) } + # 补充db类型为mysql、tendbcluster、sqlserver的dbconfig信息 + for cluster_type in cls.cluster_types: + db_type = ClusterType.cluster_type_to_db_type(cluster_type) + if db_type in [DBType.MySQL, DBType.TenDBCluster, DBType.Sqlserver]: + list_module = list_modules_by_biz(bk_biz_id, cluster_type) + db_module_config_map.update({module["db_module_id"]: module for module in list_module}) + # 获取集群操作记录的映射关系 cluster_operate_records_map = ClusterOperateRecord.get_cluster_records_map(cluster_ids) @@ -523,7 +541,7 @@ def _filter_cluster_hook( {"cluster_entry_type": entry.cluster_entry_type, "entry": entry.entry, "role": entry.role} for entry in cluster.entries ], - db_module_names_map=db_module_names_map, + db_module_config_map=db_module_config_map, cluster_entry_map=cluster_entry_map, cluster_operate_records_map=cluster_operate_records_map, cloud_info=cloud_info, @@ -540,7 +558,7 @@ def _to_cluster_representation( cls, cluster: Cluster, cluster_entry: List[Dict[str, str]], - db_module_names_map: Dict[int, str], + db_module_config_map: Dict[int, Dict[str, str]], cluster_entry_map: Dict[int, Dict[str, str]], cluster_operate_records_map: Dict[int, List], cloud_info: Dict[str, Any], @@ -552,7 +570,7 @@ def _to_cluster_representation( 将集群对象转为可序列化的 dict 结构 @param cluster: model Cluster 对象, 增加了 storages 和 proxies 属性 @param cluster_entry: 集群的访问入口列表 - @param db_module_names_map: key 是 db_module_id, value 是 db_module_name + @param db_module_config_map: key 是 db_module_id, value 是 当前集群对应的 dbconfig 映射 @param cluster_entry_map: key 是 cluster.id, value 是当前集群对应的 entry 映射 @param cluster_operate_records_map: key 是 cluster.id, value 是当前集群对应的 操作记录 映射 """ @@ -583,7 +601,7 @@ def _to_cluster_representation( "major_version": cluster.major_version, "region": cluster.region, "city": cluster.region, - "db_module_name": db_module_names_map.get(cluster.db_module_id, ""), + "db_module_infos": db_module_config_map.get(cluster.db_module_id, {}), "db_module_id": cluster.db_module_id, "creator": cluster.creator, "updater": cluster.updater, diff --git a/dbm-ui/backend/db_services/dbbase/serializers.py b/dbm-ui/backend/db_services/dbbase/serializers.py index 68d14e01b9..778977bfc3 100644 --- a/dbm-ui/backend/db_services/dbbase/serializers.py +++ b/dbm-ui/backend/db_services/dbbase/serializers.py @@ -17,6 +17,7 @@ from backend.configuration.constants import DBType from backend.db_dirty.models import DirtyMachine from backend.db_meta.enums import ClusterPhase, ClusterType +from backend.db_meta.models import Cluster from backend.db_services.dbbase.constants import ResourceType from backend.db_services.dbbase.resources.serializers import ListClusterEntriesSLZ, ListResourceSLZ from backend.db_services.ipchooser.query.resource import ResourceQueryHelper @@ -211,3 +212,25 @@ class QueryClusterCapSerializer(serializers.Serializer): class QueryClusterCapResponseSerializer(serializers.Serializer): class Meta: swagger_schema_fields = {"example": {"cluster1": {"used": 1, "total": 2, "in_use": 50}}} + + +class UpdateClusterAliasSerializer(serializers.Serializer): + bk_biz_id = serializers.IntegerField(help_text=_("业务ID")) + cluster_id = serializers.IntegerField(help_text=_("集群ID")) + new_alias = serializers.CharField(help_text=_("新集群别名")) + + def validate(self, attrs): + bk_biz_id = attrs.get("bk_biz_id") + cluster_id = attrs.get("cluster_id") + new_alias = attrs.get("new_alias") + + try: + cluster = Cluster.objects.get(bk_biz_id=bk_biz_id, id=cluster_id) + except Cluster.DoesNotExist: + raise serializers.ValidationError(_("Cluster with the given ID does not exist.")) + + # 验证新别名不能与原集群名相同 + if cluster.alias == new_alias: + raise serializers.ValidationError(_("The new alias cannot be the same as the current alias.")) + + return attrs diff --git a/dbm-ui/backend/db_services/dbbase/views.py b/dbm-ui/backend/db_services/dbbase/views.py index f0ff3fa507..c28f681bfe 100644 --- a/dbm-ui/backend/db_services/dbbase/views.py +++ b/dbm-ui/backend/db_services/dbbase/views.py @@ -29,6 +29,7 @@ from backend.db_services.dbbase.instances.yasg_slz import CheckInstancesResSLZ, CheckInstancesSLZ from backend.db_services.dbbase.resources import register from backend.db_services.dbbase.resources.query import ListRetrieveResource, ResourceList +from backend.db_services.dbbase.resources.serializers import ClusterSLZ from backend.db_services.dbbase.serializers import ( ClusterDbTypeSerializer, ClusterEntryFilterSerializer, @@ -45,6 +46,7 @@ QueryClusterCapSerializer, QueryClusterInstanceCountSerializer, ResourceAdministrationSerializer, + UpdateClusterAliasSerializer, WebConsoleResponseSerializer, WebConsoleSerializer, ) @@ -407,3 +409,18 @@ def query_cluster_stat(self, request, *args, **kwargs): cluster_stat_map = {cluster_domain_map[domain]: cap for domain, cap in cluster_stat_map.items()} return Response(cluster_stat_map) + + @common_swagger_auto_schema( + operation_summary=_("更新集群别名"), + request_body=UpdateClusterAliasSerializer(), + tags=[SWAGGER_TAG], + ) + @action(methods=["POST"], detail=False, serializer_class=UpdateClusterAliasSerializer) + def update_cluster_alias(self, request): + validated_data = self.params_validate(self.get_serializer_class()) + """更新集群别名""" + cluster = Cluster.objects.get(bk_biz_id=validated_data["bk_biz_id"], id=validated_data["cluster_id"]) + cluster.alias = validated_data["new_alias"] + cluster.save(update_fields=["alias"]) + serializer = ClusterSLZ(cluster) + return Response(serializer.data) diff --git a/dbm-ui/backend/db_services/mongodb/resources/query.py b/dbm-ui/backend/db_services/mongodb/resources/query.py index 3018ea1bfa..68af4fa0a8 100644 --- a/dbm-ui/backend/db_services/mongodb/resources/query.py +++ b/dbm-ui/backend/db_services/mongodb/resources/query.py @@ -113,7 +113,7 @@ def _to_cluster_representation( cls, cluster: Cluster, cluster_entry: List[Dict[str, str]], - db_module_names_map: Dict[int, str], + db_module_config_map: Dict[int, Dict[str, str]], cluster_entry_map: Dict[int, Dict[str, str]], cluster_operate_records_map: Dict[int, List], cloud_info: Dict[str, Any], @@ -204,7 +204,7 @@ def _to_cluster_representation( cluster_info = super()._to_cluster_representation( cluster, cluster_entry, - db_module_names_map, + db_module_config_map, cluster_entry_map, cluster_operate_records_map, cloud_info, diff --git a/dbm-ui/backend/db_services/mongodb/resources/views.py b/dbm-ui/backend/db_services/mongodb/resources/views.py index 31cc38c4d7..61a7449bfd 100644 --- a/dbm-ui/backend/db_services/mongodb/resources/views.py +++ b/dbm-ui/backend/db_services/mongodb/resources/views.py @@ -31,6 +31,7 @@ ) from backend.db_services.mongodb.resources import constants, yasg_slz from backend.db_services.mongodb.resources.query import MongoDBListRetrieveResource +from backend.iam_app.dataclass import ResourceEnum from backend.iam_app.dataclass.actions import ActionEnum from backend.iam_app.handlers.drf_perm.base import DBManagePermission @@ -103,6 +104,14 @@ class MongoDBViewSet(ResourceViewSet): list_perm_actions = [ActionEnum.MONGODB_VIEW, ActionEnum.MONGODB_ENABLE_DISABLE, ActionEnum.MONGODB_DESTROY] list_instance_perm_actions = [ActionEnum.MONGODB_VIEW] + list_external_perm_actions = [ActionEnum.ACCESS_ENTRY_EDIT] + + @staticmethod + def _external_perm_param_field(kwargs): + return { + ResourceEnum.BUSINESS.id: kwargs["bk_biz_id"], + ResourceEnum.DBTYPE.id: kwargs["view_class"].db_type.value, + } @common_swagger_auto_schema( operation_summary=_("获取实例的角色类型"), diff --git a/dbm-ui/backend/db_services/mysql/resources/tendbcluster/query.py b/dbm-ui/backend/db_services/mysql/resources/tendbcluster/query.py index 1200065629..6caaef5ffc 100644 --- a/dbm-ui/backend/db_services/mysql/resources/tendbcluster/query.py +++ b/dbm-ui/backend/db_services/mysql/resources/tendbcluster/query.py @@ -105,7 +105,7 @@ def _to_cluster_representation( cls, cluster: Cluster, cluster_entry: List[Dict[str, str]], - db_module_names_map: Dict[int, str], + db_module_config_map: Dict[int, Dict[str, str]], cluster_entry_map: Dict[int, Dict[str, str]], cluster_operate_records_map: Dict[int, List], cloud_info: Dict[str, Any], @@ -162,7 +162,7 @@ def get_remote_infos(insts: List[StorageInstance]): cluster_info = super()._to_cluster_representation( cluster, cluster_entry, - db_module_names_map, + db_module_config_map, cluster_entry_map, cluster_operate_records_map, cloud_info, diff --git a/dbm-ui/backend/db_services/mysql/resources/tendbha/query.py b/dbm-ui/backend/db_services/mysql/resources/tendbha/query.py index 60df864877..e0e351decf 100644 --- a/dbm-ui/backend/db_services/mysql/resources/tendbha/query.py +++ b/dbm-ui/backend/db_services/mysql/resources/tendbha/query.py @@ -120,7 +120,7 @@ def _to_cluster_representation( cls, cluster: Cluster, cluster_entry: List[Dict[str, str]], - db_module_names_map: Dict[int, str], + db_module_config_map: Dict[int, Dict[str, str]], cluster_entry_map: Dict[int, Dict[str, str]], cluster_operate_records_map: Dict[int, List], cloud_info: Dict[str, Any], @@ -155,7 +155,7 @@ def _to_cluster_representation( cluster_info = super()._to_cluster_representation( cluster, cluster_entry, - db_module_names_map, + db_module_config_map, cluster_entry_map, cluster_operate_records_map, cloud_info, diff --git a/dbm-ui/backend/db_services/mysql/resources/tendbsingle/query.py b/dbm-ui/backend/db_services/mysql/resources/tendbsingle/query.py index 571db3c3dc..c62aabff35 100644 --- a/dbm-ui/backend/db_services/mysql/resources/tendbsingle/query.py +++ b/dbm-ui/backend/db_services/mysql/resources/tendbsingle/query.py @@ -48,7 +48,7 @@ def _to_cluster_representation( cls, cluster: Cluster, cluster_entry: List[Dict[str, str]], - db_module_names_map: Dict[int, str], + db_module_config_map: Dict[int, Dict[str, str]], cluster_entry_map: Dict[int, Dict[str, str]], cluster_operate_records_map: Dict[int, List], cloud_info: Dict[str, Any], @@ -63,7 +63,7 @@ def _to_cluster_representation( cluster_info = super()._to_cluster_representation( cluster, cluster_entry, - db_module_names_map, + db_module_config_map, cluster_entry_map, cluster_operate_records_map, cloud_info, diff --git a/dbm-ui/backend/db_services/redis/resources/redis_cluster/query.py b/dbm-ui/backend/db_services/redis/resources/redis_cluster/query.py index 60f16b244a..50cc1f6ebc 100644 --- a/dbm-ui/backend/db_services/redis/resources/redis_cluster/query.py +++ b/dbm-ui/backend/db_services/redis/resources/redis_cluster/query.py @@ -123,7 +123,7 @@ def _to_cluster_representation( cls, cluster: Cluster, cluster_entry: List[Dict[str, str]], - db_module_names_map: Dict[int, str], + db_module_config_map: Dict[int, Dict[str, str]], cluster_entry_map: Dict[int, Dict[str, str]], cluster_operate_records_map: Dict[int, List], cloud_info: Dict[str, Any], @@ -132,9 +132,44 @@ def _to_cluster_representation( **kwargs, ) -> Dict[str, Any]: """集群序列化""" - redis_master = [m.simple_desc for m in cluster.storages if m.instance_role == InstanceRole.REDIS_MASTER] - redis_slave = [m.simple_desc for m in cluster.storages if m.instance_role == InstanceRole.REDIS_SLAVE] - machine_list = list(set([inst["bk_host_id"] for inst in [*redis_master, *redis_slave]])) + # 创建一个字典来存储 ejector_id 到cluster.storages下标的映射 + ejector_id_to_index = {} + + # 遍历 cluster.storages,获取每个 StorageInstance 的下标和 id + for index, storage_instance in enumerate(cluster.storages): + ejector_id_to_index[storage_instance.id] = index + + remote_infos = {InstanceRole.REDIS_MASTER.value: [], InstanceRole.REDIS_SLAVE.value: []} + for inst in cluster.storages: + try: + seg_range = inst.nosqlstoragesetdtl_set.all()[0].seg_range + except IndexError: + # 异常处理 因nosqlstoragesetdtl的分片数据只有redis为master才有seg_range值 以下处理是slave找出对应master seg_range并赋予值 供主从对应排序处理 + ejector_id = inst.as_receiver.first().ejector_id + index = ejector_id_to_index.get(ejector_id) + if index is not None: + seg_range = cluster.storages[index].nosqlstoragesetdtl_set.all()[0].seg_range + else: + seg_range = "-1:-1" + except Exception: + # 如果无法找到seg_range,则默认为-1:-1。有可能实例处于restoring状态(比如集群容量变更时) + seg_range = "-1:-1" + + remote_infos[inst.instance_role].append({**inst.simple_desc, "seg_range": seg_range}) + + remote_infos[InstanceRole.REDIS_MASTER.value].sort(key=lambda x: int(x.get("seg_range", -1).split("-")[0])) + remote_infos[InstanceRole.REDIS_SLAVE.value].sort(key=lambda x: int(x.get("seg_range", -1).split("-")[0])) + machine_list = list( + set( + [ + inst["bk_host_id"] + for inst in [ + *remote_infos[InstanceRole.REDIS_MASTER.value], + *remote_infos[InstanceRole.REDIS_SLAVE.value], + ] + ] + ) + ) machine_pair_cnt = len(machine_list) / 2 # 补充集群的规格和容量信息 @@ -163,16 +198,16 @@ def _to_cluster_representation( "cluster_capacity": cluster_capacity, "dns_to_clb": dns_to_clb, "proxy": [m.simple_desc for m in cluster.proxies], - "redis_master": redis_master, - "redis_slave": redis_slave, - "cluster_shard_num": len(redis_master), + "redis_master": remote_infos[InstanceRole.REDIS_MASTER.value], + "redis_slave": remote_infos[InstanceRole.REDIS_SLAVE.value], + "cluster_shard_num": len(remote_infos[InstanceRole.REDIS_MASTER.value]), "machine_pair_cnt": machine_pair_cnt, "module_names": module_names, } cluster_info = super()._to_cluster_representation( cluster, cluster_entry, - db_module_names_map, + db_module_config_map, cluster_entry_map, cluster_operate_records_map, cloud_info, diff --git a/dbm-ui/backend/db_services/sqlserver/resources/sqlserver_ha/query.py b/dbm-ui/backend/db_services/sqlserver/resources/sqlserver_ha/query.py index 1dabe55f5c..fb6fbd82b0 100644 --- a/dbm-ui/backend/db_services/sqlserver/resources/sqlserver_ha/query.py +++ b/dbm-ui/backend/db_services/sqlserver/resources/sqlserver_ha/query.py @@ -49,7 +49,7 @@ def _to_cluster_representation( cls, cluster: Cluster, cluster_entry: List[Dict[str, str]], - db_module_names_map: Dict[int, str], + db_module_config_map: Dict[int, Dict[str, str]], cluster_entry_map: Dict[int, Dict[str, str]], cluster_operate_records_map: Dict[int, List], cloud_info: Dict[str, Any], @@ -65,7 +65,7 @@ def _to_cluster_representation( cluster_info = super()._to_cluster_representation( cluster, cluster_entry, - db_module_names_map, + db_module_config_map, cluster_entry_map, cluster_operate_records_map, cloud_info, diff --git a/dbm-ui/backend/db_services/sqlserver/resources/sqlserver_single/query.py b/dbm-ui/backend/db_services/sqlserver/resources/sqlserver_single/query.py index 7b4e483aa9..bc7404309b 100644 --- a/dbm-ui/backend/db_services/sqlserver/resources/sqlserver_single/query.py +++ b/dbm-ui/backend/db_services/sqlserver/resources/sqlserver_single/query.py @@ -46,7 +46,7 @@ def _to_cluster_representation( cls, cluster: Cluster, cluster_entry: List[Dict[str, str]], - db_module_names_map: Dict[int, str], + db_module_config_map: Dict[int, Dict[str, str]], cluster_entry_map: Dict[int, Dict[str, str]], cluster_operate_records_map: Dict[int, List], cloud_info: Dict[str, Any], @@ -61,7 +61,7 @@ def _to_cluster_representation( cluster_info = super()._to_cluster_representation( cluster, cluster_entry, - db_module_names_map, + db_module_config_map, cluster_entry_map, cluster_operate_records_map, cloud_info,