Skip to content

Commit

Permalink
feature: 提供 Agent 包管理后台接口 (closed TencentBlueKing#1683)
Browse files Browse the repository at this point in the history
  • Loading branch information
wyyalt committed Oct 13, 2023
1 parent 4df96c0 commit 781da34
Show file tree
Hide file tree
Showing 7 changed files with 476 additions and 61 deletions.
4 changes: 4 additions & 0 deletions apps/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ def get_serializer_class(self, *args, **kwargs):
return type(self.serializer_class.__name__, (self.serializer_class,), {"Meta": self.serializer_meta})


class ApiMixinModelViewSet(ApiMixin, _ModelViewSet):
pagination_class = DataPageNumberPagination


def custom_exception_handler(exc, context):
"""
自定义错误处理方式
Expand Down
52 changes: 52 additions & 0 deletions apps/node_man/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2441,3 +2441,55 @@ class Meta:

def __str__(self) -> str:
return f"{self.name}-{self.version}-{self.agent_name}-{self.os}-{self.cpu_arch}"


class AgentPackages(models.Model):
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(
_("系统类型"),
max_length=32,
choices=constants.PLUGIN_OS_CHOICES,
default=constants.PluginOsType.linux,
db_index=True,
)
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)

version_log = models.TextField(_("版本日志"), null=True, blank=True)
version_log_en = models.TextField(_("英文版本日志"), null=True, blank=True)

class Meta:
verbose_name = _("Agent包(AgentPackages)")
verbose_name_plural = _("Agent包(AgentPackages)")


class AgentPackageDesc(models.Model):
"""
Agent包信息表
"""

# 安装包名需要全局唯一,防止冲突
name = 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)")
77 changes: 48 additions & 29 deletions apps/node_man/serializers/packager_manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +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__"


class TagsSerializer(serializers.Serializer):
Expand All @@ -24,34 +31,48 @@ class ConditionsSerializer(serializers.Serializer):
values = serializers.ListField()


class PKGSortSerializer(serializers.Serializer):
head = serializers.ChoiceField(choices=["version", "host_count"])
sort_type = serializers.ChoiceField(choices=["ASC", "DEC"])
class SearchSerializer(serializers.Serializer):
os_cpu_arch = serializers.CharField(required=False)
tags = serializers.ListField(required=False)


class SearchSerializer(serializers.Serializer):
page = serializers.IntegerField()
pagesize = serializers.IntegerField()
module = serializers.ChoiceField(choices=["agent", "proxy"])
conditions = ConditionsSerializer(many=True)
sort = PKGSortSerializer(many=True)
class PackageDescSearchSerializer(serializers.Serializer):
os_cpu_arch = serializers.CharField(required=False)


class SearchResponseSerializer(serializers.Serializer):
class PackageSerializer(serializers.Serializer):
id = serializers.IntegerField()
pkg_name = serializers.CharField()
version = serializers.CharField()
os_cpu_arch = serializers.CharField()
os = serializers.CharField()
cpu_arch = serializers.CharField()
tags = TagsSerializer(many=True)
creator = serializers.CharField()
pkg_ctime = serializers.DateTimeField()
host_count = serializers.IntegerField()
is_ready = serializers.BooleanField()


class OperateSerializer(serializers.Serializer):
class PackageDescSerializer(serializers.Serializer):
id = serializers.IntegerField()
action = serializers.ChoiceField(choices=["enable", "disable", "delete"])
version = serializers.CharField()
tags = TagsSerializer(many=True)
packages = PackageSerializer(many=True)
is_ready = serializers.BooleanField()


class SearchResponseSerializer(serializers.Serializer):
total = serializers.IntegerField()
list = PackageSerializer(many=True)


class PackageDescResponseSerialiaer(serializers.Serializer):
total = serializers.IntegerField()
list = PackageDescSerializer(many=True)


class OperateSerializer(serializers.Serializer):
is_ready = serializers.BooleanField()


# TODO 与plugin相同可抽取公共Serializer
Expand All @@ -78,27 +99,25 @@ class ParseSerializer(serializers.Serializer):
file_name = serializers.CharField()


class PackageSerializer(serializers.Serializer):
module = serializers.ChoiceField(choices=["agent", "proxy"])
pkg_name = serializers.CharField()
pkg_abs_path = serializers.CharField()
version = serializers.CharField()
os = serializers.CharField()
cpu_arch = serializers.CharField()
config_templates = serializers.ListField()


class ParseResponseSerializer(serializers.Serializer):
description = serializers.CharField()
packages = PackageSerializer(many=True)

class ParsePackageSerializer(serializers.Serializer):
module = serializers.ChoiceField(choices=["agent", "proxy"])
pkg_name = serializers.CharField()
pkg_abs_path = serializers.CharField()
version = serializers.CharField()
os = serializers.CharField()
cpu_arch = serializers.CharField()
config_templates = serializers.ListField()

class RegisterPackageSerializer(serializers.Serializer):
pkg_abs_path = serializers.CharField()
tags = serializers.ListField()
description = serializers.CharField()
packages = ParsePackageSerializer(many=True)


class AgentRegisterSerializer(serializers.Serializer):
class RegisterPackageSerializer(serializers.Serializer):
pkg_abs_path = serializers.CharField()
tags = serializers.ListField()

is_release = serializers.BooleanField()
packages = RegisterPackageSerializer(many=True)

Expand Down
6 changes: 5 additions & 1 deletion apps/node_man/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@
)
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 PackageManageViewSet
from apps.node_man.views.package_manage import (
AgentPackageDescViewSet,
PackageManageViewSet,
)
from apps.node_man.views.plugin import GsePluginViewSet
from apps.node_man.views.plugin_v2 import PluginV2ViewSet
from apps.node_man.views.sync_task import SyncTaskViewSet
Expand Down Expand Up @@ -69,6 +72,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")

biz_dispatcher = DjangoBasicResourceApiDispatcher(iam, settings.BK_IAM_SYSTEM_ID)
biz_dispatcher.register("biz", BusinessResourceProvider())
Expand Down
125 changes: 94 additions & 31 deletions apps/node_man/views/package_manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,39 @@
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 drf_yasg.utils import swagger_auto_schema
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK

from apps.generic import ModelViewSet
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 common.utils.drf_utils import swagger_auto_schema

PACKAGE_MANAGE_VIEW_TAGS = ["PKG_Manager"]
PACKAGE_DES_VIEW_TAGS = ["PKG_Desc"]


class PackageManageViewSet(ModelViewSet):
model = models.Packages
http_method_names = ["get", "post"]
# queryset = models.Packages.objects.filter(module__in=["gse_proxy", "gse_agent"])
queryset = models.AgentPackages.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(
operation_summary="查询安装包列表",
query_serializer=pkg_manage.SearchSerializer,
responses={200: pkg_manage.SearchResponseSerializer},
operation_summary="安装包列表",
tags=PACKAGE_MANAGE_VIEW_TAGS,
responses={HTTP_200_OK: pkg_manage.SearchResponseSerializer},
)
@action(detail=False, methods=["POST"], serializer_class=pkg_manage.SearchSerializer)
def search(self, request, *args, **kwargs):
# data = self.validated_data
def list(self, request, *args, **kwargs):
mock_data = {
"total": 2,
"list": [
Expand Down Expand Up @@ -62,6 +71,37 @@ def search(self, request, *args, **kwargs):
],
}
return Response(mock_data)
# return super().list(request, *args, **kwargs)

@swagger_auto_schema(
operation_summary="操作类动作:启用/停用",
body_in=pkg_manage.OperateSerializer,
responses={200: pkg_manage.SearchResponseSerializer},
tags=PACKAGE_MANAGE_VIEW_TAGS,
)
def update(self, request, validated_data, *args, **kwargs):
mock_data = {
"id": 1,
"pkg_name": "pkg_name",
"version": "1.1.1",
"os": "Linux",
"cpu_arch": "x86_64",
"tags": [{"id": "stable", "name": "稳定版本"}],
"creator": "string",
"pkg_ctime": "2019-08-24 14:15:22",
"host_count": 100,
"is_ready": True,
}

return Response(mock_data)

@swagger_auto_schema(
operation_summary="删除安装包",
tags=PACKAGE_MANAGE_VIEW_TAGS,
)
def destroy(self, request, *args, **kwargs):

return Response()

@swagger_auto_schema(
operation_summary="获取快速筛选信息",
Expand All @@ -88,23 +128,6 @@ def quick_search_condition(self, request, *args, **kwargs):

return Response(mock_data)

# @swagger_auto_schema(
# operation_summary="删除安装包",
# tags=PACKAGE_MANAGE_VIEW_TAGS,
# )
# def destroy(self, request, *args, **kwargs):

# return Response(status=HTTP_204_NO_CONTENT)

@swagger_auto_schema(
operation_summary="操作类动作:启用/停用/删除",
tags=PACKAGE_MANAGE_VIEW_TAGS,
)
@action(detail=False, methods=["POST"], serializer_class=pkg_manage.OperateSerializer)
def operate(self, request, *args, **kwargs):
# data = self.validated_data
return Response(status=HTTP_200_OK)

@swagger_auto_schema(
operation_summary="Agent包上传",
tags=PACKAGE_MANAGE_VIEW_TAGS,
Expand Down Expand Up @@ -163,11 +186,11 @@ def create_register_task(self, request):
@swagger_auto_schema(
operation_summary="查询Agent包注册任务",
tags=PACKAGE_MANAGE_VIEW_TAGS,
query_serializer=pkg_manage.AgentRegisterTaskSerializer,
query_in=pkg_manage.AgentRegisterTaskSerializer,
responses={HTTP_200_OK: pkg_manage.AgentRegisterTaskResponseSerializer},
)
@action(detail=False, methods=["GET"], serializer_class=pkg_manage.AgentRegisterTaskSerializer)
def query_register_task(self, request):
@action(detail=False, methods=["GET"])
def query_register_task(self, request, validated_data):

mock_data = {
"is_finish": True,
Expand Down Expand Up @@ -198,10 +221,50 @@ def tags(self, request):
return Response(mock_data)

@swagger_auto_schema(
operation_summary="获取Agent包标签",
operation_summary="获取Agent包版本",
tags=PACKAGE_MANAGE_VIEW_TAGS,
responses={HTTP_200_OK: pkg_manage.TagsSerializer(many=True)},
)
@action(detail=False, methods=["GET"])
def get_agent_version(self, request):
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": [
{
"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)
Loading

0 comments on commit 781da34

Please sign in to comment.