From c280abd8a1d6fb7a36385464d1e822e9efb54dbc Mon Sep 17 00:00:00 2001 From: neko12583 <1258375097@qq.com> Date: Thu, 15 Jun 2023 14:21:11 +0800 Subject: [PATCH] =?UTF-8?q?feature:=20=E8=AE=A2=E9=98=85=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=8C=89=E6=93=8D=E4=BD=9C=E7=B3=BB=E7=BB=9F=E7=AD=89=E4=B8=BB?= =?UTF-8?q?=E6=9C=BA=E5=B1=9E=E6=80=A7=E8=BF=9B=E8=A1=8C=E8=8C=83=E5=9B=B4?= =?UTF-8?q?=E7=AD=9B(closed=20#1452)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/backend/subscription/serializers.py | 10 +++- apps/backend/subscription/tools.py | 46 +++++++++++++++++-- apps/backend/subscription/views.py | 1 + apps/node_man/handlers/policy.py | 3 +- .../migrations/0070_auto_20230625_1733.py | 28 +++++++++++ apps/node_man/models.py | 2 + apps/node_man/serializers/base.py | 11 ++++- 7 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 apps/node_man/migrations/0070_auto_20230625_1733.py diff --git a/apps/backend/subscription/serializers.py b/apps/backend/subscription/serializers.py index 15a032880..e619a01bf 100644 --- a/apps/backend/subscription/serializers.py +++ b/apps/backend/subscription/serializers.py @@ -21,12 +21,20 @@ from apps.utils import basic +class SubscriptionScopeInstanceSelectorSerializer(serializers.Serializer): + instance_selector = serializers.ListField( + child=serializers.DictField(), + required=False, + label="实例筛选器" + ) + + class GatewaySerializer(serializers.Serializer): bk_username = serializers.CharField() bk_app_code = serializers.CharField() -class ScopeSerializer(serializers.Serializer): +class ScopeSerializer(SubscriptionScopeInstanceSelectorSerializer): bk_biz_id = serializers.IntegerField(required=False, default=None) # TODO: 是否取消掉这个范围内的scope bk_biz_scope = serializers.ListField(required=False) diff --git a/apps/backend/subscription/tools.py b/apps/backend/subscription/tools.py index 4310d9957..805565c1c 100644 --- a/apps/backend/subscription/tools.py +++ b/apps/backend/subscription/tools.py @@ -41,6 +41,7 @@ from apps.utils.batch_request import batch_request, request_multi_thread from apps.utils.cache import func_cache_decorator from apps.utils.time_handler import strftime_local +from apps.core.ipchooser.tools.base import HostQuerySqlHelper logger = logging.getLogger("app") @@ -680,6 +681,7 @@ def wrapper(scope: Dict[str, Union[Dict, Any]], *args, **kwargs) -> Dict[str, Di "object_type": scope["object_type"], "node_type": scope["node_type"], "nodes": list(nodes), + "instance_selector": scope.get("instance_selector") }, **kwargs, } @@ -727,6 +729,9 @@ def get_instances_by_scope(scope: Dict[str, Union[Dict, int, Any]]) -> Dict[str, "host|instance|host|yyyy": {...}, } """ + if scope.get("instance_selector") == []: + return {} + instances = [] bk_biz_id = scope["bk_biz_id"] if bk_biz_id: @@ -808,13 +813,46 @@ def get_instances_by_scope(scope: Dict[str, Union[Dict, int, Any]]) -> Dict[str, "object_type": scope["object_type"], "node_type": models.Subscription.NodeType.INSTANCE, } + + bk_host_id_list = [] + for instance in instances: - if data["object_type"] == models.Subscription.ObjectType.HOST: - data.update(instance["host"]) - else: - data.update(instance["service"]) + instance_data = instance[ + "host" + ] if data["object_type"] == models.Subscription.ObjectType.HOST else instance["service"] + + data.update(instance_data) + bk_host_id_list.append(instance_data.get("bk_host_id")) instances_dict[create_node_id(data)] = instance + # 对 instances 进行二次过滤 + if scope.get("instance_selector") and bk_host_id_list: + conditions = [ + { + "key": key, "value": value + } for selector_param in scope["instance_selector"] for key, value in selector_param.items() + ] + + host_queryset = HostQuerySqlHelper.multiple_cond_sql( + params={"bk_host_id": bk_host_id_list, "conditions": conditions}, + biz_scope=[bk_biz_id], + return_all_node_type=True + ) + instance_selector_host_id_set = {host.bk_host_id for host in host_queryset} + + selector_instances_dict = {} + for node_id, instance in instances_dict.items(): + instance_data = instance[ + "host" + ] if data["object_type"] == models.Subscription.ObjectType.HOST else instance["service"] + + if instance_data["bk_host_id"] in instance_selector_host_id_set: + selector_instances_dict[ + node_id + ] = instance if data["object_type"] == models.Subscription.ObjectType.HOST else instance["service"] + + return selector_instances_dict + return instances_dict diff --git a/apps/backend/subscription/views.py b/apps/backend/subscription/views.py index d59f2d052..356736941 100644 --- a/apps/backend/subscription/views.py +++ b/apps/backend/subscription/views.py @@ -84,6 +84,7 @@ def create_subscription(self, request): object_type=scope["object_type"], node_type=scope["node_type"], nodes=scope["nodes"], + instance_selector=scope.get("instance_selector"), target_hosts=params.get("target_hosts"), from_system=params["bk_app_code"] or "blueking", enable=enable, diff --git a/apps/node_man/handlers/policy.py b/apps/node_man/handlers/policy.py index 983fa87a9..04f683584 100644 --- a/apps/node_man/handlers/policy.py +++ b/apps/node_man/handlers/policy.py @@ -395,6 +395,7 @@ def migrate_preview(cls, query_params: Dict[str, Any]) -> List[Dict[str, Any]]: object_type=scope["object_type"], node_type=scope["node_type"], nodes=scope["nodes"], + instance_selector=scope.get("instance_selector"), target_hosts=query_params.get("target_hosts"), # SaaS侧均为主程序部署 is_main=True, @@ -467,7 +468,7 @@ def migrate_preview(cls, query_params: Dict[str, Any]) -> List[Dict[str, Any]]: step_obj.subscription = subscription subscription.steps = step_objs preview_result = tasks.run_subscription_task_and_create_instance( - subscription, subscription_task, preview_only=True + subscription, subscription_task, scope, preview_only=True ) action_instance_map = defaultdict(list) instance_actions = preview_result["instance_actions"] diff --git a/apps/node_man/migrations/0070_auto_20230625_1733.py b/apps/node_man/migrations/0070_auto_20230625_1733.py new file mode 100644 index 000000000..9d14045f1 --- /dev/null +++ b/apps/node_man/migrations/0070_auto_20230625_1733.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.4 on 2023-06-25 09:33 + +from django.db import migrations, models +import django_mysql.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('node_man', '0069_merge_20230425_1727'), + ] + + operations = [ + migrations.AlterModelOptions( + name='cloud', + options={'verbose_name': '管控区域(BK-Net)', 'verbose_name_plural': '管控区域(BK-Net)'}, + ), + migrations.AddField( + model_name='subscription', + name='instance_selector', + field=django_mysql.models.JSONField(blank=True, default=dict, null=True, verbose_name='订阅任务范围主机属性筛选'), + ), + migrations.AlterField( + model_name='job', + name='job_type', + field=models.CharField(choices=[('INSTALL_AGENT', 'INSTALL_AGENT'), ('RESTART_AGENT', 'RESTART_AGENT'), ('REINSTALL_AGENT', 'REINSTALL_AGENT'), ('UNINSTALL_AGENT', 'UNINSTALL_AGENT'), ('REMOVE_AGENT', 'REMOVE_AGENT'), ('UPGRADE_AGENT', 'UPGRADE_AGENT'), ('IMPORT_AGENT', 'IMPORT_AGENT'), ('RESTART_AGENT', 'RESTART_AGENT'), ('RELOAD_AGENT', 'RELOAD_AGENT'), ('ACTIVATE_AGENT', 'ACTIVATE_AGENT'), ('MAIN_START_PLUGIN', 'MAIN_START_PLUGIN'), ('MAIN_STOP_PLUGIN', 'MAIN_STOP_PLUGIN'), ('MAIN_RESTART_PLUGIN', 'MAIN_RESTART_PLUGIN'), ('MAIN_RELOAD_PLUGIN', 'MAIN_RELOAD_PLUGIN'), ('MAIN_DELEGATE_PLUGIN', 'MAIN_DELEGATE_PLUGIN'), ('MAIN_UNDELEGATE_PLUGIN', 'MAIN_UNDELEGATE_PLUGIN'), ('MAIN_INSTALL_PLUGIN', 'MAIN_INSTALL_PLUGIN'), ('MAIN_STOP_AND_DELETE_PLUGIN', 'MAIN_STOP_AND_DELETE_PLUGIN'), ('DEBUG_PLUGIN', 'DEBUG_PLUGIN'), ('STOP_DEBUG_PLUGIN', 'STOP_DEBUG_PLUGIN'), ('PUSH_CONFIG_PLUGIN', 'PUSH_CONFIG_PLUGIN'), ('REMOVE_CONFIG_PLUGIN', 'REMOVE_CONFIG_PLUGIN'), ('PACKING_PLUGIN', 'PACKING_PLUGIN'), ('INSTALL_PROXY', 'INSTALL_PROXY'), ('RESTART_PROXY', 'RESTART_PROXY'), ('REINSTALL_PROXY', 'REINSTALL_PROXY'), ('REPLACE_PROXY', 'REPLACE_PROXY'), ('UNINSTALL_PROXY', 'UNINSTALL_PROXY'), ('UPGRADE_PROXY', 'UPGRADE_PROXY'), ('IMPORT_PROXY', 'IMPORT_PROXY'), ('RESTART_PROXY', 'RESTART_PROXY'), ('RELOAD_PROXY', 'RELOAD_PROXY')], default='INSTALL_PROXY', max_length=45, verbose_name='作业类型'), + ), + ] diff --git a/apps/node_man/models.py b/apps/node_man/models.py index 8eaff7679..48ee88bc2 100644 --- a/apps/node_man/models.py +++ b/apps/node_man/models.py @@ -1891,6 +1891,7 @@ class CategoryType(object): object_type = models.CharField(_("对象类型"), max_length=20, choices=OBJECT_TYPE_CHOICES, db_index=True) node_type = models.CharField(_("节点类型"), max_length=20, choices=NODE_TYPE_CHOICES, db_index=True) nodes = JSONField(_("节点"), default=list) + instance_selector = JSONField(_("订阅任务范围主机属性筛选"), null=True, blank=True) target_hosts = JSONField(_("下发的目标机器"), default=None, null=True) from_system = models.CharField(_("所属系统"), max_length=30) update_time = models.DateTimeField(_("更新时间"), auto_now=True, db_index=True) @@ -1934,6 +1935,7 @@ def scope(self): "node_type": self.node_type, "nodes": self.nodes, "need_register": need_register, + "instance_selector": self.instance_selector, } @classmethod diff --git a/apps/node_man/serializers/base.py b/apps/node_man/serializers/base.py index a019beab2..c6e055cc5 100644 --- a/apps/node_man/serializers/base.py +++ b/apps/node_man/serializers/base.py @@ -45,8 +45,17 @@ def validate(self, data): return data +# 订阅任务范围主机属性筛选 +class SubscriptionScopeInstanceSelectorSerializer(serializers.Serializer): + instance_selector = serializers.ListField( + child=serializers.DictField(), + required=False, + label="实例筛选器" + ) + + # 策略范围 -class ScopeSerializer(serializers.Serializer): +class ScopeSerializer(SubscriptionScopeInstanceSelectorSerializer): class NodeSerializer(serializers.Serializer): bk_biz_id = serializers.IntegerField(label="业务ID") bk_inst_id = serializers.IntegerField(required=False, label="实例ID")