From 3e24299ed645a5a20edb1feec4f2f0040d001800 Mon Sep 17 00:00:00 2001 From: xy <1803352740@qq.com> Date: Tue, 2 Apr 2024 18:28:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(backend):=20=E6=90=9C=E7=B4=A2=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E9=AA=8C=E6=94=B6=E9=97=AE=E9=A2=98=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=20#3804?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db_services/dbbase/resources/query.py | 88 +++++++++++-------- .../dbbase/resources/serializers.py | 27 +++--- .../db_services/dbbase/resources/viewsets.py | 4 +- dbm-ui/backend/db_services/dbbase/views.py | 2 +- 4 files changed, 69 insertions(+), 52 deletions(-) diff --git a/dbm-ui/backend/db_services/dbbase/resources/query.py b/dbm-ui/backend/db_services/dbbase/resources/query.py index 6c832d220a..a0e5df4733 100644 --- a/dbm-ui/backend/db_services/dbbase/resources/query.py +++ b/dbm-ui/backend/db_services/dbbase/resources/query.py @@ -9,9 +9,7 @@ specific language governing permissions and limitations under the License. """ import abc -import operator from collections import defaultdict -from functools import reduce from typing import Any, Callable, Dict, List, Tuple, Union import attr @@ -264,9 +262,9 @@ def list_instances(cls, bk_biz_id: int, query_params: Dict, limit: int, offset: return resource_list @classmethod - def retrieve_instance(cls, bk_biz_id: int, cluster_id: int, ip: str, port: int) -> dict: + def retrieve_instance(cls, bk_biz_id: int, cluster_id: int, instance: str) -> dict: """查询实例详情. 具体方法可在子类中自定义""" - instance_details = cls.list_instances(bk_biz_id, {"ip": ip, "port": port}, limit=1, offset=0).data[0] + instance_details = cls.list_instances(bk_biz_id, {"instance": instance}, limit=1, offset=0).data[0] return cls._retrieve_instance(instance_details, cluster_id) @classmethod @@ -355,10 +353,6 @@ def _list_clusters( query_filters &= filter_params_map[param] cluster_queryset = Cluster.objects.filter(query_filters).order_by("create_at") - # 部署时间表头排序 - if query_params.get("ordering"): - cluster_queryset = cluster_queryset.order_by(query_params.get("ordering")) - def filter_inst_queryset(_cluster_queryset, _proxy_queryset, _storage_queryset, _filters): # 注意这里用新的变量获取过滤后的queryset,不要用原queryset过滤,会影响后续集群关联实例的获取 _proxy_filter_queryset = _proxy_queryset.filter(_filters) @@ -369,28 +363,21 @@ def filter_inst_queryset(_cluster_queryset, _proxy_queryset, _storage_queryset, ).distinct() return _cluster_queryset - # ip筛选 - def filter_ip_func(_query_params, _cluster_queryset, _proxy_queryset, _storage_queryset): - """实例过滤ip""" - filter_ip = Q(machine__ip__in=_query_params.get("ip").split(",")) - _cluster_queryset = filter_inst_queryset(_cluster_queryset, _proxy_queryset, _storage_queryset, filter_ip) - return _cluster_queryset - # 实例筛选 def filter_instance_func(_query_params, _cluster_queryset, _proxy_queryset, _storage_queryset): - """实例过滤ip:port""" - insts = _query_params.get("instance").split(",") - filter_inst = reduce( - operator.or_, [Q(machine__ip=inst.split(":")[0], port=inst.split(":")[1]) for inst in insts] - ) + """实例过滤ip:port 以及 ip 两种情况""" + # 应用过滤条件并返回查询集 _cluster_queryset = filter_inst_queryset( - _cluster_queryset, _proxy_queryset, _storage_queryset, filter_inst + _cluster_queryset, _proxy_queryset, _storage_queryset, cls.build_q_for_instance_filter(_query_params) ) + # 部署时间表头排序 + if query_params.get("ordering"): + _cluster_queryset = _cluster_queryset.order_by(query_params.get("ordering")) + return _cluster_queryset filter_func_map = filter_func_map or {} filter_func_map = { - "ip": filter_ip_func, "instance": filter_instance_func, **filter_func_map, } @@ -514,6 +501,23 @@ def _to_cluster_representation( "update_at": datetime2str(cluster.update_at), } + @staticmethod + def build_q_for_instance_filter(params_data: dict) -> Q: + instance_list = params_data.get("instance", "").split(",") + # 初始化两个空的Q对象,稍后用于构造过滤条件 + q_ip = Q() + q_ip_port = Q() + # 对筛选条件进行区分ip,还是ip:port + for instance in instance_list: + if IP_PORT_DIVIDER in instance: + ip, port = instance.split(IP_PORT_DIVIDER) + q_ip_port |= Q(machine__ip=ip, port=port) + else: + q_ip |= Q(machine__ip=instance) + + # 合并两种过滤条件 + return q_ip | q_ip_port + @classmethod def _list_instances( cls, @@ -534,6 +538,28 @@ def _list_instances( """ query_filters = Q(bk_biz_id=bk_biz_id, cluster_type__in=cls.cluster_types) + def build_q_for_domain_filter(_query_params): + domain_list = _query_params.get("domain", "").split(",") + # 初始化列表和Q查询对象 + q_ip_list = [] + q_ip_port_query = Q() + + # 基础查询条件 + base_query = Q(cluster__clusterentry__cluster_entry_type=ClusterEntryType.DNS.value) + + for domain in domain_list: + if IP_PORT_DIVIDER in domain: + ip, port = domain.split(IP_PORT_DIVIDER) + # 为带端口的IP构造查询条件 + q_ip_port_query |= Q(cluster__clusterentry__entry=ip, port=port) + else: + q_ip_list.append(domain) + + # 构造不带端口号的域名查询条件(如果q_ip不为空) + q_ip_query = Q(cluster__clusterentry__entry__in=q_ip_list) if q_ip_list else Q() + + return base_query & (q_ip_query | q_ip_port_query) + # 定义内置的过滤参数map inner_filter_params_map = { "ip": Q(machine__ip__in=query_params.get("ip", "").split(",")), @@ -543,23 +569,9 @@ def _list_instances( "region": Q(region=query_params.get("region")), "role": Q(role__in=query_params.get("role", "").split(",")), "name": Q(cluster__name__in=query_params.get("name", "").split(",")), - "domain": Q( - cluster__clusterentry__cluster_entry_type=ClusterEntryType.DNS.value, - cluster__clusterentry__entry__in=query_params.get("domain", "").split(","), - ), + "domain": build_q_for_domain_filter(query_params), + "instance": cls.build_q_for_instance_filter(query_params), } - - def join_instance_by_q(instances: str) -> Q: - insts = instances.split(",") - filter_inst = reduce( - operator.or_, [Q(machine__ip=inst.split(":")[0], port=inst.split(":")[1]) for inst in insts] - ) - return filter_inst - - # 判断是否需要实例过滤 - if query_params.get("instance"): - filter_params_map.update({"instance": join_instance_by_q(query_params.get("instance"))}) - filter_params_map = filter_params_map or {} filter_params_map.update(inner_filter_params_map) # 通过基础过滤参数进行instance过滤 diff --git a/dbm-ui/backend/db_services/dbbase/resources/serializers.py b/dbm-ui/backend/db_services/dbbase/resources/serializers.py index 593f6626b2..231cfd54ee 100644 --- a/dbm-ui/backend/db_services/dbbase/resources/serializers.py +++ b/dbm-ui/backend/db_services/dbbase/resources/serializers.py @@ -61,22 +61,29 @@ class InstanceAddressSerializer(serializers.Serializer): port = serializers.CharField(help_text=_("端口"), required=False) def to_internal_value(self, data): + + all_ports_valid = True + """获取根据address获取ip和port,优先考虑从address获取""" if "instance_address" not in data: return data instance_address = data["instance_address"] - if IP_PORT_DIVIDER not in instance_address: - data["ip"] = instance_address or data.get("ip", "") - return data - - ip, port = instance_address.split(IP_PORT_DIVIDER, maxsplit=1) - data["ip"] = ip - try: - data["port"] = int(port) - except ValueError: - # 非法端口,不进行查询过滤 + # 用于分隔IP地址和端口号的部分 + parts = instance_address.split(",") + for part in parts: + if IP_PORT_DIVIDER in part: + # 存在端口号,进行验证 + ip, port = part.split(IP_PORT_DIVIDER, maxsplit=1) + if not port.isdigit(): + # 非法端口 + all_ports_valid = False + break + + if not all_ports_valid: pass + # 如果所有端口都有效,则将instance_address保存到data字典 + data = {"instance": instance_address} return data diff --git a/dbm-ui/backend/db_services/dbbase/resources/viewsets.py b/dbm-ui/backend/db_services/dbbase/resources/viewsets.py index 7a325d3991..78e309a27f 100644 --- a/dbm-ui/backend/db_services/dbbase/resources/viewsets.py +++ b/dbm-ui/backend/db_services/dbbase/resources/viewsets.py @@ -56,9 +56,7 @@ def retrieve_instance(self, request, bk_biz_id: int): """查询实例详情""" query_params = self.params_validate(self.retrieve_instances_slz) return Response( - self.query_class.retrieve_instance( - bk_biz_id, query_params.get("cluster_id"), query_params["ip"], query_params["port"] - ) + self.query_class.retrieve_instance(bk_biz_id, query_params.get("cluster_id"), query_params["instance"]) ) @action(methods=["GET"], detail=False, url_path="get_table_fields") diff --git a/dbm-ui/backend/db_services/dbbase/views.py b/dbm-ui/backend/db_services/dbbase/views.py index d205f7d7f3..63df13a8a3 100644 --- a/dbm-ui/backend/db_services/dbbase/views.py +++ b/dbm-ui/backend/db_services/dbbase/views.py @@ -115,7 +115,7 @@ def query_biz_cluster_attrs(self, request, *args, **kwargs): if db_modules: db_module_names_map = {module.db_module_id: module.db_module_name for module in db_modules} cluster_attrs["db_module_id"] = [ - {"value": module, "text": db_module_names_map.get(module)} + {"value": module, "text": db_module_names_map.get(module, "--")} for module in existing_values["db_module_id"] ] else: