Skip to content

Commit

Permalink
feat: API 自动注册到 APIGW (closed TencentBlueKing#1851)
Browse files Browse the repository at this point in the history
  • Loading branch information
CohleRustW committed Mar 12, 2024
1 parent 3c866ca commit dbcb7df
Show file tree
Hide file tree
Showing 65 changed files with 3,957 additions and 47 deletions.
132 changes: 132 additions & 0 deletions apps/backend/management/commands/generate_api_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# -*- 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 logging
import os
import typing
from dataclasses import dataclass

from django.conf import settings
from django.core.management.base import BaseCommand
from drf_spectacular.generators import EndpointEnumerator

from apps.node_man.management.commands.generate_api_js import esb_json2apigw_yaml
from env import BK_NDOEMAN_APIGTW_TIMEOUT

logger = logging.getLogger("app")


class EndPointIndex:
PATH = 0
PATTERN = 1
METHOD = 2
ACTION_FUNC = 3


class ActionFuncIndex:
# action指定url_path时方法名称不为path
FUNC_NAME = 0
FUNC = 1


@dataclass
class Action:
request_method: str
action_name: str
request_path: str
tags: typing.List[str]
description: str
api_name: str = ""

def __str__(self):
return (
f"<{self.tags[0]} | {self.action_name}: {self.request_method}>"
f"- {self.request_path} - {self.description}"
)


class Command(BaseCommand):
def handle(self, *args, **options):
action_list: typing.List[Action] = []
invalid_list: typing.List[str] = []
for endpoint in EndpointEnumerator().get_api_endpoints():
method_lower = endpoint[EndPointIndex.METHOD].lower()
action_name = endpoint[EndPointIndex.ACTION_FUNC].actions[method_lower]
action_func = endpoint[EndPointIndex.ACTION_FUNC]
# TODO 接口的元数据(tags、描述等)统一从 swagger_auto_schema 获取,如果需要更多的元数据,也应该补充到 swagger_auto_schema 上
swagger_auto_schema = getattr(action_func, "_swagger_auto_schema", None) or (
getattr(getattr(action_func.cls, action_name), "_swagger_auto_schema", None)
)

if not swagger_auto_schema:
invalid_list.append(f"{action_func} / {action_name} need [swagger_auto_schema]")
continue
need_registe_apigtw = swagger_auto_schema.get("registe_apigtw", False) or swagger_auto_schema.get(
method_lower, {}
).get("registe_apigtw", False)

if not need_registe_apigtw:
continue

try:
swagger_auto_schema = swagger_auto_schema[method_lower]
except Exception:
pass

is_check_paas: bool = True
for required_key in ["tags", "operation_summary"]:
try:
swagger_auto_schema[required_key]
except KeyError:
invalid_list.append(f"{action_func} / {action_name} need [{required_key}]")
is_check_paas = False
break

if not is_check_paas:
continue

action: Action = Action(
request_path=endpoint[EndPointIndex.PATH],
request_method=method_lower,
action_name=action_name,
tags=swagger_auto_schema["tags"],
description=swagger_auto_schema["operation_summary"],
api_name=swagger_auto_schema.get("api_name"),
)
action_list.append(action)

for action in action_list:
logger.debug(f"action -> {action}")
logger.debug("\n".join(invalid_list))

logger.info(f"action -> {len(action_list)}, invalid_list -> {len(invalid_list)}")
output = []

for action in action_list:
data = {
"path": action.request_path,
"resource_name": action.api_name or action.action_name,
"registed_http_method": action.request_method,
"description": f"{action.description}",
"dest_url": f"{settings.BK_NODEMAN_API_URL}/{action.request_path}",
"timeout": BK_NDOEMAN_APIGTW_TIMEOUT,
"headers": "{}",
"resource_classification": action.tags[0],
}
output.append(data)

save_file_path: str = os.path.join(settings.PROJECT_ROOT, "support-files/apigateway/bk-nodeman.yaml")
logger.info(f"Save yaml file to {save_file_path}")

esb_json2apigw_yaml(
apigw_yaml_save_path=save_file_path,
json_content=output,
)
logger.info(f"Save endpoint to yaml file -> [{save_file_path}] success")
50 changes: 50 additions & 0 deletions apps/backend/management/commands/register_apigtw.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
"""
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017 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
http://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 os
import traceback

from django.conf import settings
from django.core.management import call_command
from django.core.management.base import BaseCommand


class Command(BaseCommand):
def handle(self, *args, **kwargs):
definition_file_path = os.path.join(settings.PROJECT_ROOT, "support-files/apigateway/definition.yaml")
resources_file_path = os.path.join(settings.PROJECT_ROOT, "support-files/apigateway/bk-nodeman.yaml")

print("[bk-nodeman]call sync_apigw_config with definition: %s" % definition_file_path)
call_command("sync_apigw_config", file=definition_file_path)

print("[bk-nodeman]call sync_apigw_stage with definition: %s" % definition_file_path)
call_command("sync_apigw_stage", file=definition_file_path)

print("[bk-nodeman]call sync_apigw_resources with resources: %s" % resources_file_path)
call_command("sync_apigw_resources", "--delete", file=resources_file_path)

print("[bk-nodeman]call sync_resource_docs_by_archive with definition: %s" % definition_file_path)
call_command("sync_resource_docs_by_archive", f"--file={definition_file_path}")

print("[bk-nodeman]call create_version_and_release_apigw with definition: %s" % definition_file_path)
call_command("create_version_and_release_apigw", "--generate-sdks", file=definition_file_path)

print("[bk-nodeman]call fetch_apigw_public_key")
call_command("fetch_apigw_public_key")

print("[bk-nodeman]call fetch_esb_public_key")
try:
call_command("fetch_esb_public_key")
except Exception:
print("[bk-nodeman]this env has not bk-nodeman esb api,skip fetch_esb_public_key ")
traceback.print_exc()
47 changes: 43 additions & 4 deletions apps/backend/plugin/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class PluginViewSet(APIViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin

# permission_classes = (BackendBasePermission,)
@swagger_auto_schema(
registe_apigtw=True,
api_name="create_register_task",
operation_summary="创建注册任务",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -129,6 +131,8 @@ def create_plugin_register_task(self, request):
return Response({"job_id": job.id})

@swagger_auto_schema(
registe_apigtw=True,
api_name="query_register_task",
operation_summary="查询插件注册任务",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -175,6 +179,8 @@ def query_plugin_register_task(self, request):
)

@swagger_auto_schema(
registe_apigtw=True,
api_name="query_plugin_info",
operation_summary="查询插件信息",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -202,6 +208,8 @@ def info(self, request):
return Response(package_infos)

@swagger_auto_schema(
registe_apigtw=True,
api_name="release_package",
operation_summary="发布插件包",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -250,6 +258,7 @@ def release(self, request):
return Response([package.id for package in plugin_packages])

@swagger_auto_schema(
registe_apigtw=True,
operation_summary="插件包状态类操作",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -293,10 +302,7 @@ def package_status_operation(self, request):
plugin_packages.update(**status_field_map[operation], creator=operator)
return Response([package.id for package in plugin_packages])

@swagger_auto_schema(
operation_summary="删除插件",
tags=PLUGIN_VIEW_TAGS,
)
@swagger_auto_schema(registe_apigtw=True, operation_summary="删除插件", tags=PLUGIN_VIEW_TAGS, api_name="delete_plugin")
@action(detail=False, methods=["POST"], serializer_class=serializers.DeletePluginSerializer)
def delete(self, request):
"""
Expand Down Expand Up @@ -327,6 +333,8 @@ def delete(self, request):
return Response()

@swagger_auto_schema(
registe_apigtw=True,
api_name="create_plugin_config_template",
operation_summary="创建配置模板",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -377,6 +385,8 @@ def create_config_template(self, request):
return Response(params)

@swagger_auto_schema(
registe_apigtw=True,
api_name="release_plugin_config_template",
operation_summary="发布配置模板",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -420,6 +430,8 @@ def release_config_template(self, request):
return Response(result)

@swagger_auto_schema(
registe_apigtw=True,
api_name="render_plugin_config_template",
operation_summary="渲染配置模板",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -455,6 +467,8 @@ def render_config_template(self, request):
)

@swagger_auto_schema(
registe_apigtw=True,
api_name="query_plugin_config_template",
operation_summary="查询配置模板",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -495,6 +509,8 @@ def query_config_template(self, request):
return Response(result)

@swagger_auto_schema(
registe_apigtw=True,
api_name="query_plugin_config_instance",
operation_summary="查询配置模板实例",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -538,6 +554,7 @@ def query_config_instance(self, request):
return Response(result)

@swagger_auto_schema(
registe_apigtw=True,
operation_summary="开始调试",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -664,6 +681,7 @@ def start_debug(self, request):
return Response({"task_id": subscription_task.id})

@swagger_auto_schema(
registe_apigtw=True,
operation_summary="停止调试",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -707,6 +725,7 @@ def stop_debug(self, request):
return Response()

@swagger_auto_schema(
registe_apigtw=True,
operation_summary="查询调试结果",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -746,6 +765,8 @@ def query_debug(self, request):
return Response({"status": status, "step": step_name, "message": "\n".join(log_content)})

@swagger_auto_schema(
registe_apigtw=True,
api_name="create_export_plugin_task",
operation_summary="触发插件打包导出",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -799,6 +820,8 @@ def create_export_task(self, request):
return Response({"job_id": record.id})

@swagger_auto_schema(
registe_apigtw=True,
api_name="query_export_plugin_task",
operation_summary="获取一个导出任务结果",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -854,6 +877,8 @@ def query_export_task(self, request):
return Response(response_data)

@swagger_auto_schema(
registe_apigtw=True,
api_name="plugin_parse",
operation_summary="解析插件包",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -937,6 +962,8 @@ def parse(self, request):
return Response(pkg_parse_results)

@swagger_auto_schema(
registe_apigtw=True,
api_name="list_plugin",
operation_summary="查询插件列表",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -1033,6 +1060,8 @@ def list(self, request, *args, **kwargs):
return Response({"total": len(plugins), "list": ret_plugins})

@swagger_auto_schema(
registe_apigtw=True,
api_name="retrieve_plugin",
operation_summary="插件详情",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -1094,6 +1123,7 @@ def retrieve(self, request, *args, **kwargs):
return Response(PluginHandler.retrieve(kwargs["pk"]))

@swagger_auto_schema(
registe_apigtw=True,
operation_summary="插件状态类操作",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -1123,6 +1153,8 @@ def plugin_status_operation(self, request):
return Response([plugin.id for plugin in update_plugins])

@swagger_auto_schema(
registe_apigtw=True,
api_name="plugin_history",
operation_summary="查询插件包历史",
methods=["GET"],
tags=PLUGIN_VIEW_TAGS,
Expand Down Expand Up @@ -1196,6 +1228,7 @@ def history(self, request, pk):
)

@swagger_auto_schema(
registe_apigtw=True,
operation_summary="上传文件接口",
tags=PLUGIN_VIEW_TAGS,
)
Expand Down Expand Up @@ -1240,6 +1273,12 @@ def upload(self, request, *args, **kwargs):
return Response(upload_result)


@swagger_auto_schema(
registe_apigtw=True,
api_name="upload_file",
operation_summary="上传文件接口",
tags=PLUGIN_VIEW_TAGS,
)
@csrf_exempt
@login_exempt
def upload_package(request):
Expand Down
Loading

0 comments on commit dbcb7df

Please sign in to comment.