Skip to content

Commit

Permalink
fix(backend): 搜索增强验收问题解决 #3804
Browse files Browse the repository at this point in the history
  • Loading branch information
Xydezb authored and iSecloud committed Apr 3, 2024
1 parent 80f08ee commit 3e24299
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 52 deletions.
88 changes: 50 additions & 38 deletions dbm-ui/backend/db_services/dbbase/resources/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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,
}
Expand Down Expand Up @@ -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,
Expand All @@ -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(",")),
Expand All @@ -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过滤
Expand Down
27 changes: 17 additions & 10 deletions dbm-ui/backend/db_services/dbbase/resources/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
4 changes: 1 addition & 3 deletions dbm-ui/backend/db_services/dbbase/resources/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion dbm-ui/backend/db_services/dbbase/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit 3e24299

Please sign in to comment.