From 24965a083a6bbdd8421a1d437ab013f22b23fc89 Mon Sep 17 00:00:00 2001 From: wyyalt Date: Fri, 10 Nov 2023 16:38:35 +0800 Subject: [PATCH] =?UTF-8?q?feature:=20=20=E6=8F=90=E4=BE=9B=20Agent=20?= =?UTF-8?q?=E5=8C=85=E7=AE=A1=E7=90=86=E5=90=8E=E5=8F=B0=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=20(closed=20#1683)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/node_man/models.py | 22 ++-- apps/node_man/permissions/__init__.py | 10 ++ apps/node_man/permissions/package_manage.py | 27 +++++ .../{packager_manage.py => package_manage.py} | 25 ++--- apps/node_man/urls.py | 5 +- apps/node_man/utils/filters.py | 30 +++++ apps/node_man/views/package_manage.py | 104 +++++++++++------- 7 files changed, 146 insertions(+), 77 deletions(-) create mode 100644 apps/node_man/permissions/__init__.py create mode 100644 apps/node_man/permissions/package_manage.py rename apps/node_man/serializers/{packager_manage.py => package_manage.py} (88%) create mode 100644 apps/node_man/utils/filters.py diff --git a/apps/node_man/models.py b/apps/node_man/models.py index 9312d85c4..a66395ecb 100644 --- a/apps/node_man/models.py +++ b/apps/node_man/models.py @@ -2489,16 +2489,13 @@ class Meta: ] -class AgentPackages(models.Model): +class GsePackages(orm.OperateRecordModel): pkg_name = models.CharField(_("压缩包名"), max_length=128) version = models.CharField(_("版本号"), max_length=128) - module = models.CharField(_("所属服务"), max_length=32) project = models.CharField(_("工程名"), max_length=32, db_index=True) pkg_size = models.IntegerField(_("包大小")) pkg_path = models.CharField(_("包路径"), max_length=128) md5 = models.CharField(_("md5值"), max_length=32) - pkg_mtime = models.CharField(_("包更新时间"), max_length=48) - pkg_ctime = models.CharField(_("包创建时间"), max_length=48) location = models.CharField(_("安装包链接"), max_length=512) os = models.CharField( _("系统类型"), @@ -2510,9 +2507,7 @@ class AgentPackages(models.Model): cpu_arch = models.CharField( _("CPU类型"), max_length=32, choices=constants.CPU_CHOICES, default=constants.CpuType.x86_64, db_index=True ) - creator = models.CharField(_("操作人"), max_length=45, default="admin") - is_release_version = models.BooleanField(_("是否已经发布版本"), default=True, db_index=True) # 由于创建记录时,文件可能仍然在传输过程中,因此需要标志位判断是否已经可用 is_ready = models.BooleanField(_("插件是否可用"), default=True) @@ -2520,22 +2515,21 @@ class AgentPackages(models.Model): version_log_en = models.TextField(_("英文版本日志"), null=True, blank=True) class Meta: - verbose_name = _("Agent包(AgentPackages)") - verbose_name_plural = _("Agent包(AgentPackages)") + verbose_name = _("Gse包(GsePackages)") + verbose_name_plural = _("Gse包(GsePackages)") -class AgentPackageDesc(models.Model): +class GsePackageDesc(orm.OperateRecordModel): """ - Agent包信息表 + Gse包描述表 """ # 安装包名需要全局唯一,防止冲突 - name = models.CharField(_("安装包名"), max_length=32, unique=True, db_index=True) + project = models.CharField(_("工程名"), max_length=32, unique=True, db_index=True) description = models.TextField(_("安装包描述")) - module = models.CharField(_("所属服务"), max_length=32) description_en = models.TextField(_("英文插件描述"), null=True, blank=True) category = models.CharField(_("所属范围"), max_length=32, choices=constants.CATEGORY_CHOICES) class Meta: - verbose_name = _("Agent信息(AgentPackageDesc)") - verbose_name_plural = _("Agent信息(AgentPackageDesc)") + verbose_name = _("Gse包描述(GsePackageDesc)") + verbose_name_plural = _("Gse包描述(GsePackageDesc)") diff --git a/apps/node_man/permissions/__init__.py b/apps/node_man/permissions/__init__.py new file mode 100644 index 000000000..29ed269e0 --- /dev/null +++ b/apps/node_man/permissions/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-节点管理(BlueKing-BK-NODEMAN) available. +Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" diff --git a/apps/node_man/permissions/package_manage.py b/apps/node_man/permissions/package_manage.py new file mode 100644 index 000000000..bc8ae81d8 --- /dev/null +++ b/apps/node_man/permissions/package_manage.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-节点管理(BlueKing-BK-NODEMAN) available. +Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +from django.utils.translation import ugettext_lazy as _ +from rest_framework import permissions + +from apps.node_man.handlers.iam import IamHandler +from apps.utils.local import get_request_username + + +class PackageManagePermission(permissions.BasePermission): + message = _("您没有该操作的权限") + + def has_permission(self, request, view): + + if IamHandler().is_superuser(get_request_username()): + return True + + return False diff --git a/apps/node_man/serializers/packager_manage.py b/apps/node_man/serializers/package_manage.py similarity index 88% rename from apps/node_man/serializers/packager_manage.py rename to apps/node_man/serializers/package_manage.py index 40247351b..177f6c644 100644 --- a/apps/node_man/serializers/packager_manage.py +++ b/apps/node_man/serializers/package_manage.py @@ -12,18 +12,13 @@ from rest_framework import serializers from apps.exceptions import ValidationError -from apps.node_man.models import AgentPackages - - -class AgentPackageSerializer(serializers.ModelSerializer): - class meta: - model = AgentPackages - fields = "__all__" +from apps.node_man.constants import GsePackageCode class TagsSerializer(serializers.Serializer): id = serializers.CharField() name = serializers.CharField() + children = serializers.ListField() class ConditionsSerializer(serializers.Serializer): @@ -31,15 +26,6 @@ class ConditionsSerializer(serializers.Serializer): values = serializers.ListField() -class SearchSerializer(serializers.Serializer): - os_cpu_arch = serializers.CharField(required=False) - tags = serializers.ListField(required=False) - - -class PackageDescSearchSerializer(serializers.Serializer): - os_cpu_arch = serializers.CharField(required=False) - - class PackageSerializer(serializers.Serializer): id = serializers.IntegerField() pkg_name = serializers.CharField() @@ -49,7 +35,6 @@ class PackageSerializer(serializers.Serializer): tags = TagsSerializer(many=True) creator = serializers.CharField() pkg_ctime = serializers.DateTimeField() - host_count = serializers.IntegerField() is_ready = serializers.BooleanField() @@ -61,7 +46,7 @@ class PackageDescSerializer(serializers.Serializer): is_ready = serializers.BooleanField() -class SearchResponseSerializer(serializers.Serializer): +class ListResponseSerializer(serializers.Serializer): total = serializers.IntegerField() list = PackageSerializer(many=True) @@ -75,6 +60,10 @@ class OperateSerializer(serializers.Serializer): is_ready = serializers.BooleanField() +class QuickSearchSerializer(serializers.Serializer): + project = serializers.ChoiceField(choices=GsePackageCode.list_choices()) + + # TODO 与plugin相同可抽取公共Serializer class UploadSerializer(serializers.Serializer): class PkgFileField(serializers.FileField): diff --git a/apps/node_man/urls.py b/apps/node_man/urls.py index 5605ef5a6..554c027bc 100644 --- a/apps/node_man/urls.py +++ b/apps/node_man/urls.py @@ -40,8 +40,7 @@ ) from apps.node_man.views.healthz import HealthzViewSet from apps.node_man.views.host_v2 import HostV2ViewSet -from apps.node_man.views.package_manage import ( - AgentPackageDescViewSet, +from apps.node_man.views.package_manage import ( # AgentPackageDescViewSet, PackageManageViewSet, ) from apps.node_man.views.plugin import GsePluginViewSet @@ -72,7 +71,7 @@ router.register(r"healthz", HealthzViewSet, basename="healthz") router.register(r"sync_task", SyncTaskViewSet, basename="sync_task") router.register(r"agent/package", PackageManageViewSet, basename="package_manage") -router.register(r"agent/package_desc", AgentPackageDescViewSet, basename="package_desc") +# router.register(r"agent/package_desc", AgentPackageDescViewSet, basename="package_desc") biz_dispatcher = DjangoBasicResourceApiDispatcher(iam, settings.BK_IAM_SYSTEM_ID) biz_dispatcher.register("biz", BusinessResourceProvider()) diff --git a/apps/node_man/utils/filters.py b/apps/node_man/utils/filters.py new file mode 100644 index 000000000..722985b0a --- /dev/null +++ b/apps/node_man/utils/filters.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-节点管理(BlueKing-BK-NODEMAN) available. +Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +import django_filters +from django_filters.rest_framework import FilterSet + +from apps.node_man.models import GsePackages + + +class GsePackageFilter(FilterSet): + tags = django_filters.CharFilter(name="tags", method="filter_tags") + os_cpu_arch = django_filters.CharFilter(name="os_cpu_arch", method="filter_os_cpu_arch") + + def filter_tags(self, queryset, name, value): + pass + + def filter_os_cpu_arch(self, queryset, name, value): + pass + + class Meta: + model = GsePackages + fields = ["os_cpu_arch", "tags", "project", "created_by", "is_ready", "version"] diff --git a/apps/node_man/views/package_manage.py b/apps/node_man/views/package_manage.py index 1278233a1..b4793495e 100644 --- a/apps/node_man/views/package_manage.py +++ b/apps/node_man/views/package_manage.py @@ -9,6 +9,7 @@ specific language governing permissions and limitations under the License. """ from django_filters.rest_framework import DjangoFilterBackend +from drf_yasg import openapi from rest_framework import filters from rest_framework.decorators import action from rest_framework.response import Response @@ -16,7 +17,9 @@ from apps.generic import ApiMixinModelViewSet as ModelViewSet from apps.node_man import models -from apps.node_man.serializers import packager_manage as pkg_manage +from apps.node_man.permissions import package_manage as pkg_permission +from apps.node_man.serializers import package_manage as pkg_manage +from apps.node_man.utils.filters import GsePackageFilter from common.utils.drf_utils import swagger_auto_schema PACKAGE_MANAGE_VIEW_TAGS = ["PKG_Manager"] @@ -24,19 +27,16 @@ class PackageManageViewSet(ModelViewSet): - # queryset = models.Packages.objects.filter(module__in=["gse_proxy", "gse_agent"]) - queryset = models.AgentPackages.objects.all() - # model = models.Packages + queryset = models.GsePackages.objects.all() # http_method_names = ["get", "post"] # ordering_fields = ("module",) serializer_class = pkg_manage.PackageSerializer + permission_classes = (pkg_permission.PackageManagePermission,) filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) - - filter_fields = ("module", "creator", "is_ready", "version") + filter_class = GsePackageFilter @swagger_auto_schema( - query_serializer=pkg_manage.SearchSerializer, - responses={200: pkg_manage.SearchResponseSerializer}, + responses={200: pkg_manage.ListResponseSerializer}, operation_summary="安装包列表", tags=PACKAGE_MANAGE_VIEW_TAGS, ) @@ -53,7 +53,6 @@ def list(self, request, *args, **kwargs): "tags": [{"id": "stable", "name": "稳定版本"}], "creator": "string", "pkg_ctime": "2019-08-24 14:15:22", - "host_count": 100, "is_ready": True, }, { @@ -65,7 +64,6 @@ def list(self, request, *args, **kwargs): "tags": [{"id": "stable", "name": "稳定版本"}], "creator": "string", "pkg_ctime": "2019-08-24 14:15:22", - "host_count": 100, "is_ready": True, }, ], @@ -76,7 +74,7 @@ def list(self, request, *args, **kwargs): @swagger_auto_schema( operation_summary="操作类动作:启用/停用", body_in=pkg_manage.OperateSerializer, - responses={200: pkg_manage.SearchResponseSerializer}, + responses={200: pkg_manage.PackageSerializer}, tags=PACKAGE_MANAGE_VIEW_TAGS, ) def update(self, request, validated_data, *args, **kwargs): @@ -89,7 +87,6 @@ def update(self, request, validated_data, *args, **kwargs): "tags": [{"id": "stable", "name": "稳定版本"}], "creator": "string", "pkg_ctime": "2019-08-24 14:15:22", - "host_count": 100, "is_ready": True, } @@ -105,20 +102,25 @@ def destroy(self, request, *args, **kwargs): @swagger_auto_schema( operation_summary="获取快速筛选信息", + manual_parameters=[ + openapi.Parameter( + "project", in_=openapi.TYPE_STRING, description="区分gse_agent, gse_proxy", type=openapi.TYPE_STRING + ) + ], tags=PACKAGE_MANAGE_VIEW_TAGS, ) @action(detail=False, methods=["GET"]) def quick_search_condition(self, request, *args, **kwargs): mock_version = [ - {"name": "2.1.8", "id": "2.1.8", "host_count": 10}, - {"name": "2.1.7", "id": "2.1.7", "host_count": 10}, - {"name": "ALL", "id": "all", "host_count": 20}, + {"name": "2.1.8", "id": "2.1.8", "count": 10}, + {"name": "2.1.7", "id": "2.1.7", "count": 10}, + {"name": "ALL", "id": "all", "count": 20}, ] mock_os_cpu_arch = [ - {"name": "Linux_x86_64", "id": "linux_x86_64", "host_count": 10}, - {"name": "Linux_x86", "id": "linux_x86", "host_count": 10}, - {"name": "ALL", "id": "all", "host_count": 20}, + {"name": "Linux_x86_64", "id": "linux_x86_64", "count": 10}, + {"name": "Linux_x86", "id": "linux_x86", "count": 10}, + {"name": "ALL", "id": "all", "count": 20}, ] mock_data = [ @@ -223,31 +225,10 @@ def tags(self, request): @swagger_auto_schema( operation_summary="获取Agent包版本", tags=PACKAGE_MANAGE_VIEW_TAGS, - responses={HTTP_200_OK: pkg_manage.TagsSerializer(many=True)}, + responses={HTTP_200_OK: pkg_manage.PackageDescResponseSerialiaer}, ) @action(detail=False, methods=["GET"]) def version(self, request): - pass - - -class AgentPackageDescViewSet(ModelViewSet): - queryset = models.AgentPackageDesc.objects.all() - # model = models.Packages - # http_method_names = ["get", "post"] - # ordering_fields = ("module",) - # serializer_class = pkg_manage.PackageSerializer - # filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) - - # filter_fields = ("module", "creator", "is_ready", "version") - - @swagger_auto_schema( - query_in=pkg_manage.PackageDescSearchSerializer, - responses={200: pkg_manage.PackageDescResponseSerialiaer}, - operation_summary="Agent版本列表", - tags=PACKAGE_DES_VIEW_TAGS, - ) - def list(self, request, *args, **kwargs): - mock_data = { "total": 10, "list": [ @@ -259,7 +240,7 @@ def list(self, request, *args, **kwargs): "description": "我是描述", "packages": [ { - "" "pkg_name": "gseagent-2.1.2.tgz", + "pkg_name": "gseagent-2.1.2.tgz", "tags": [{"id": "stable", "name": "稳定版本"}, {"id": "latest", "name": "最新版本"}], } ], @@ -267,4 +248,43 @@ def list(self, request, *args, **kwargs): ], } return Response(mock_data) - # return super().list(request, *args, **kwargs) + + +# class AgentPackageDescViewSet(ModelViewSet): +# queryset = models.AgentPackageDesc.objects.all() +# # model = models.Packages +# # http_method_names = ["get", "post"] +# # ordering_fields = ("module",) +# # serializer_class = pkg_manage.PackageSerializer +# # filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) + +# # filter_fields = ("module", "creator", "is_ready", "version") + +# @swagger_auto_schema( +# query_in=pkg_manage.PackageDescSearchSerializer, +# responses={200: pkg_manage.PackageDescResponseSerialiaer}, +# operation_summary="Agent版本列表", +# tags=PACKAGE_DES_VIEW_TAGS, +# ) +# def list(self, request, *args, **kwargs): + +# mock_data = { +# "total": 10, +# "list": [ +# { +# "id": 1, +# "version": "2.1.2", +# "tags": [{"id": "stable", "name": "稳定版本"}], +# "is_ready": True, +# "description": "我是描述", +# "packages": [ +# { +# "pkg_name": "gseagent-2.1.2.tgz", +# "tags": [{"id": "stable", "name": "稳定版本"}, {"id": "latest", "name": "最新版本"}], +# } +# ], +# } +# ], +# } +# return Response(mock_data) +# # return super().list(request, *args, **kwargs)