From dc03ec8eba6f92f6de543371b5af23ce22ce7f31 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 14:40:52 +0800 Subject: [PATCH 01/21] =?UTF-8?q?fix:=20=E8=B0=83=E6=95=B4=E8=93=9D?= =?UTF-8?q?=E9=B2=B8=E6=8F=92=E4=BB=B6=E6=8E=A5=E5=8F=A3=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=88=B0=E7=BD=91=E5=85=B3=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20&&=20=E8=93=9D=E9=B2=B8=E6=8F=92=E4=BB=B6=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E4=BC=98=E5=8C=96=20--story=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bk_plugin_framework/kit/__init__.py | 2 +- .../bk_plugin_framework/kit/plugin.py | 5 +- .../runtime/callback/celery/tasks.py | 6 +- .../bk_plugin_framework/runtime/executor.py | 9 +- .../bk_plugin_framework/serializers.py | 19 + .../services/bpf_service/api/callback.py | 32 +- .../services/bpf_service/api/detail.py | 26 +- .../services/bpf_service/api/invoke.py | 32 +- .../services/bpf_service/api/logs.py | 26 +- .../services/bpf_service/api/meta.py | 26 +- .../bpf_service/api/plugin_api_dispatch.py | 32 +- .../services/bpf_service/api/schedule.py | 31 +- .../commands/data/api-definition.yml | 35 -- .../commands/data/api-resources.yml | 146 ------- .../commands/data/api-strategy-cors.yml | 13 - .../commands/support-files/resources.yaml | 377 ++++++++++++++++++ .../commands/sync_apigateway_if_changed.py | 311 +++++++++++++++ .../management/commands/sync_plugin_apigw.py | 40 -- .../bpf_service/migrations/0001_initial.py | 63 +++ .../services/bpf_service/models.py | 35 ++ .../services/bpf_service/urls.py | 8 +- .../bin/post_compile | 7 - .../bin/sync_apigateway.sh | 26 ++ 23 files changed, 1015 insertions(+), 292 deletions(-) create mode 100644 bk-plugin-framework/bk_plugin_framework/serializers.py delete mode 100644 bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-definition.yml delete mode 100644 bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-resources.yml delete mode 100644 bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-strategy-cors.yml create mode 100644 bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/support-files/resources.yaml create mode 100644 bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py delete mode 100644 bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_plugin_apigw.py create mode 100644 bk-plugin-framework/bk_plugin_framework/services/bpf_service/migrations/0001_initial.py create mode 100644 bk-plugin-framework/bk_plugin_framework/services/bpf_service/models.py delete mode 100644 template/{{cookiecutter.project_name}}/bin/post_compile create mode 100755 template/{{cookiecutter.project_name}}/bin/sync_apigateway.sh diff --git a/bk-plugin-framework/bk_plugin_framework/kit/__init__.py b/bk-plugin-framework/bk_plugin_framework/kit/__init__.py index fe6e59a..644678a 100644 --- a/bk-plugin-framework/bk_plugin_framework/kit/__init__.py +++ b/bk-plugin-framework/bk_plugin_framework/kit/__init__.py @@ -14,9 +14,9 @@ except ImportError: from pydantic import Field # noqa -from bk_plugin_framework.kit.plugin import Context # noqa from bk_plugin_framework.kit.plugin import ( # noqa Callback, + Context, ContextRequire, FormModel, InputsModel, diff --git a/bk-plugin-framework/bk_plugin_framework/kit/plugin.py b/bk-plugin-framework/bk_plugin_framework/kit/plugin.py index 5d24958..ca776b2 100644 --- a/bk-plugin-framework/bk_plugin_framework/kit/plugin.py +++ b/bk-plugin-framework/bk_plugin_framework/kit/plugin.py @@ -20,7 +20,10 @@ from bk_plugin_framework.constants import State from bk_plugin_framework.hub import VersionHub -from bk_plugin_framework.runtime.callback.api import CallbackPreparation, prepare_callback +from bk_plugin_framework.runtime.callback.api import ( + CallbackPreparation, + prepare_callback, +) VALID_VERSION_PATTERN = re.compile(r"^[0-9]+\.[0-9]+\.[0-9][a-z0-9]*$") diff --git a/bk-plugin-framework/bk_plugin_framework/runtime/callback/celery/tasks.py b/bk-plugin-framework/bk_plugin_framework/runtime/callback/celery/tasks.py index 52e21d4..b7510f6 100644 --- a/bk-plugin-framework/bk_plugin_framework/runtime/callback/celery/tasks.py +++ b/bk-plugin-framework/bk_plugin_framework/runtime/callback/celery/tasks.py @@ -19,7 +19,11 @@ from bk_plugin_framework.envs import settings from bk_plugin_framework.hub import VersionHub from bk_plugin_framework.kit import State -from bk_plugin_framework.metrics import BK_PLUGIN_CALLBACK_EXCEPTION_COUNT, BK_PLUGIN_CALLBACK_TIME, HOSTNAME +from bk_plugin_framework.metrics import ( + BK_PLUGIN_CALLBACK_EXCEPTION_COUNT, + BK_PLUGIN_CALLBACK_TIME, + HOSTNAME, +) from bk_plugin_framework.runtime.executor import BKPluginExecutor from bk_plugin_framework.runtime.schedule.models import Schedule from bk_plugin_framework.runtime.schedule.utils import get_schedule_lock diff --git a/bk-plugin-framework/bk_plugin_framework/runtime/executor.py b/bk-plugin-framework/bk_plugin_framework/runtime/executor.py index 1e07e0d..6f6938a 100644 --- a/bk-plugin-framework/bk_plugin_framework/runtime/executor.py +++ b/bk-plugin-framework/bk_plugin_framework/runtime/executor.py @@ -22,7 +22,14 @@ from django.utils.timezone import now -from bk_plugin_framework.kit import Callback, Context, ContextRequire, InputsModel, Plugin, State +from bk_plugin_framework.kit import ( + Callback, + Context, + ContextRequire, + InputsModel, + Plugin, + State, +) from bk_plugin_framework.kit.plugin import PluginCallbackModel from bk_plugin_framework.metrics import ( BK_PLUGIN_EXECUTE_EXCEPTION_COUNT, diff --git a/bk-plugin-framework/bk_plugin_framework/serializers.py b/bk-plugin-framework/bk_plugin_framework/serializers.py new file mode 100644 index 0000000..817f64b --- /dev/null +++ b/bk-plugin-framework/bk_plugin_framework/serializers.py @@ -0,0 +1,19 @@ +from drf_spectacular.utils import extend_schema_serializer +from rest_framework import serializers + + +def standard_response_enveloper(serializer_class, many: bool = False): + """统一响应包装器""" + component_name = "Enveloped{}{}".format( + serializer_class.__name__.replace("Serializer", ""), + "List" if many else "", + ) + + @extend_schema_serializer(many=False, component_name=component_name) + class EnvelopeSerializer(serializers.Serializer): + code = serializers.IntegerField(help_text="状态码,0表示成功") + data = serializer_class(many=many) + message = serializers.CharField(help_text="响应消息") + result = serializers.BooleanField(help_text="操作结果") + + return EnvelopeSerializer diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/callback.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/callback.py index 0a10b6b..6de6af1 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/callback.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/callback.py @@ -14,26 +14,50 @@ import traceback from apigw_manager.apigw.decorators import apigw_require +from apigw_manager.drf.utils import gen_apigateway_resource_config from blueapps.account.decorators import login_exempt from django.utils.decorators import method_decorator -from drf_yasg.utils import swagger_auto_schema +from drf_spectacular.utils import extend_schema +from rest_framework import serializers from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.views import APIView from bk_plugin_framework.runtime.callback.api import callback, parse_callback_token +from bk_plugin_framework.serializers import standard_response_enveloper logger = logging.getLogger("bk_plugin") +class PluginCallbackParamsSerializer(serializers.Serializer): + token = serializers.CharField(help_text="插件回调token", required=True) + + +class PluginCallbackResponseSerializer(serializers.Serializer): + result = serializers.BooleanField(help_text="回调结果,True表示成功,False表示失败") + message = serializers.CharField(help_text="回调结果信息", required=False) + + @method_decorator(login_exempt, name="dispatch") @method_decorator(apigw_require, name="dispatch") class PluginCallback(APIView): authentication_classes = [] # csrf exempt - @swagger_auto_schema( - method="POST", - operation_summary="plugin callback", + @extend_schema( + exclude=True, + summary="插件回调", + operation_id="callback", + request=PluginCallbackParamsSerializer, + responses={200: standard_response_enveloper(PluginCallbackResponseSerializer)}, + extensions=gen_apigateway_resource_config( + is_public=True, + allow_apply_permission=True, + user_verified_required=False, + app_verified_required=True, + resource_permission_required=True, + description_en="plugin callback", + match_subpath=False, + ), ) @action(methods=["POST"], detail=True) def post(self, request, token): diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/detail.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/detail.py index 7adc250..09371e7 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/detail.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/detail.py @@ -11,16 +11,20 @@ import logging +from apigw_manager.drf.utils import gen_apigateway_resource_config from blueapps.account.decorators import login_exempt from django.utils.decorators import method_decorator -from drf_yasg.utils import swagger_auto_schema +from drf_spectacular.utils import extend_schema from rest_framework import permissions, serializers, status from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.views import APIView from bk_plugin_framework.hub import VersionHub -from bk_plugin_framework.services.bpf_service.api.serializers import StandardResponseSerializer +from bk_plugin_framework.serializers import standard_response_enveloper +from bk_plugin_framework.services.bpf_service.api.serializers import ( + StandardResponseSerializer, +) logger = logging.getLogger("root") @@ -64,10 +68,20 @@ class DetailFormsSerializer(serializers.Serializer): class Detail(APIView): permission_classes = [permissions.AllowAny] - @swagger_auto_schema( - method="GET", - operation_summary="Get plugin detail for specific version", - responses={200: DetailResponseSerializer}, + @extend_schema( + exclude=True, + summary="获取指定版本的插件详情", + operation_id="plugin_detail", + responses={200: standard_response_enveloper(DetailResponseSerializer)}, + extensions=gen_apigateway_resource_config( + is_public=True, + allow_apply_permission=True, + user_verified_required=True, + app_verified_required=True, + resource_permission_required=True, + description_en="Get plugin detail for specific version", + match_subpath=False, + ), ) @action(methods=["GET"], detail=True) def get(self, request, version): diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/invoke.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/invoke.py index edc6221..5135d21 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/invoke.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/invoke.py @@ -12,9 +12,10 @@ import logging from apigw_manager.apigw.decorators import apigw_require +from apigw_manager.drf.utils import gen_apigateway_resource_config from blueapps.account.decorators import login_exempt from django.utils.decorators import method_decorator -from drf_yasg.utils import swagger_auto_schema +from drf_spectacular.utils import extend_schema from rest_framework import serializers, status from rest_framework.decorators import action from rest_framework.exceptions import ValidationError @@ -23,8 +24,13 @@ from bk_plugin_framework.hub import VersionHub from bk_plugin_framework.runtime.executor import BKPluginExecutor -from bk_plugin_framework.services.bpf_service.api.permissions import ScopeAllowPermission -from bk_plugin_framework.services.bpf_service.api.serializers import StandardResponseSerializer +from bk_plugin_framework.serializers import standard_response_enveloper +from bk_plugin_framework.services.bpf_service.api.permissions import ( + ScopeAllowPermission, +) +from bk_plugin_framework.services.bpf_service.api.serializers import ( + StandardResponseSerializer, +) logger = logging.getLogger("bk_plugin") @@ -52,11 +58,21 @@ class Invoke(APIView): authentication_classes = [] # csrf exempt permission_classes = [ScopeAllowPermission] - @swagger_auto_schema( - method="POST", - operation_summary="Invoke specific version plugin", - request_body=InvokeParamsSerializer, - responses={200: InvokeResponseSerializer}, + @extend_schema( + exclude=True, + summary="调用指定版本插件", + operation_id="invoke", + request=InvokeParamsSerializer, + responses={200: standard_response_enveloper(InvokeResponseSerializer)}, + extensions=gen_apigateway_resource_config( + is_public=True, + allow_apply_permission=True, + user_verified_required=False, + app_verified_required=True, + resource_permission_required=True, + description_en="Invoke specific version plugin", + match_subpath=False, + ), ) @action(methods=["POST"], detail=True) def post(self, request, version): diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/logs.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/logs.py index 289d7fa..adaeb82 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/logs.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/logs.py @@ -11,16 +11,20 @@ import logging +from apigw_manager.drf.utils import gen_apigateway_resource_config from blueapps.account.decorators import login_exempt from django.utils.decorators import method_decorator -from drf_yasg.utils import swagger_auto_schema +from drf_spectacular.utils import extend_schema from rest_framework import permissions, serializers from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.views import APIView from bk_plugin_framework.runtime.loghub.models import LogEntry -from bk_plugin_framework.services.bpf_service.api.serializers import StandardResponseSerializer +from bk_plugin_framework.serializers import standard_response_enveloper +from bk_plugin_framework.services.bpf_service.api.serializers import ( + StandardResponseSerializer, +) logger = logging.getLogger("root") @@ -40,10 +44,20 @@ class Logs(APIView): permission_classes = [permissions.AllowAny] - @swagger_auto_schema( - method="GET", - operation_summary="Get plugin execution log with trace_id", - responses={200: LogsResponseSerializer}, + @extend_schema( + exclude=True, + summary="获取插件执行日志", + operation_id="plugin_logs", + responses={200: standard_response_enveloper(LogsResponseSerializer)}, + extensions=gen_apigateway_resource_config( + is_public=True, + allow_apply_permission=True, + user_verified_required=True, + app_verified_required=True, + resource_permission_required=True, + description_en="Get plugin execution log with trace_id", + match_subpath=False, + ), ) @action(methods=["GET"], detail=True) def get(self, request, trace_id): diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/meta.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/meta.py index 4377d06..4b027dc 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/meta.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/meta.py @@ -12,10 +12,11 @@ import logging from importlib import import_module +from apigw_manager.drf.utils import gen_apigateway_resource_config from blueapps.account.decorators import login_exempt from django.conf import settings from django.utils.decorators import method_decorator -from drf_yasg.utils import swagger_auto_schema +from drf_spectacular.utils import extend_schema from rest_framework import permissions, serializers from rest_framework.decorators import action from rest_framework.response import Response @@ -23,7 +24,10 @@ from bk_plugin_framework import __version__ as bpf_version from bk_plugin_framework.hub import VersionHub -from bk_plugin_framework.services.bpf_service.api.serializers import StandardResponseSerializer +from bk_plugin_framework.serializers import standard_response_enveloper +from bk_plugin_framework.services.bpf_service.api.serializers import ( + StandardResponseSerializer, +) logger = logging.getLogger("root") @@ -58,10 +62,20 @@ class Meta(APIView): permission_classes = [permissions.AllowAny] - @swagger_auto_schema( - method="GET", - operation_summary="Get plugin meta info", - responses={200: MetaResponseSerializer}, + @extend_schema( + exclude=True, + summary="获取插件元信息", + operation_id="plugin_meta_info", + responses={200: standard_response_enveloper(MetaResponseSerializer)}, + extensions=gen_apigateway_resource_config( + is_public=True, + allow_apply_permission=True, + user_verified_required=True, + app_verified_required=True, + resource_permission_required=True, + description_en="Get plugin meta info", + match_subpath=False, + ), ) @action(methods=["GET"], detail=True) def get(self, request): diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/plugin_api_dispatch.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/plugin_api_dispatch.py index 61697f2..3835850 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/plugin_api_dispatch.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/plugin_api_dispatch.py @@ -15,19 +15,25 @@ from urllib.parse import urlsplit from apigw_manager.apigw.decorators import apigw_require +from apigw_manager.drf.utils import gen_apigateway_resource_config from blueapps.account.decorators import login_exempt from django.test import RequestFactory from django.urls import Resolver404, resolve from django.utils.decorators import method_decorator -from drf_yasg.utils import swagger_auto_schema +from drf_spectacular.utils import extend_schema from rest_framework import serializers, status from rest_framework.decorators import action from rest_framework.exceptions import ValidationError from rest_framework.response import Response from rest_framework.views import APIView -from bk_plugin_framework.services.bpf_service.api.permissions import ScopeAllowPermission -from bk_plugin_framework.services.bpf_service.api.serializers import StandardResponseSerializer +from bk_plugin_framework.serializers import standard_response_enveloper +from bk_plugin_framework.services.bpf_service.api.permissions import ( + ScopeAllowPermission, +) +from bk_plugin_framework.services.bpf_service.api.serializers import ( + StandardResponseSerializer, +) logger = logging.getLogger("bk_plugin") @@ -73,11 +79,21 @@ class PluginAPIDispatch(APIView): authentication_classes = [] # csrf exempt permission_classes = [ScopeAllowPermission] - @swagger_auto_schema( - method="POST", - operation_summary="Plugin API dispatch", - request_body=PluginAPIDispatchParamsSerializer, - responses={200: PluginAPIDispatchResponseSerializer}, + @extend_schema( + exclude=True, + summary="插件API分发", + operation_id="plugin_api_dispatch", + request=PluginAPIDispatchParamsSerializer, + responses={200: standard_response_enveloper(PluginAPIDispatchResponseSerializer)}, + extensions=gen_apigateway_resource_config( + is_public=True, + allow_apply_permission=True, + user_verified_required=False, + app_verified_required=True, + resource_permission_required=True, + description_en="Plugin API dispatch", + match_subpath=False, + ), ) @action(methods=["POST"], detail=True) def post(self, request): diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/schedule.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/schedule.py index 2025097..031be58 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/schedule.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/api/schedule.py @@ -12,20 +12,28 @@ import json import logging +from apigw_manager.drf.utils import gen_apigateway_resource_config from blueapps.account.decorators import login_exempt from django.utils.decorators import method_decorator -from drf_yasg.utils import swagger_auto_schema +from drf_spectacular.utils import extend_schema from rest_framework import permissions, serializers from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.views import APIView from bk_plugin_framework.runtime.schedule.models import Schedule as ScheduleModel -from bk_plugin_framework.services.bpf_service.api.serializers import StandardResponseSerializer +from bk_plugin_framework.serializers import standard_response_enveloper +from bk_plugin_framework.services.bpf_service.api.serializers import ( + StandardResponseSerializer, +) logger = logging.getLogger("root") +class ScheduleParamsSerializer(serializers.Serializer): + trace_id = serializers.CharField(help_text="插件调用 trace id") + + class ScheduleResponseSerializer(StandardResponseSerializer): class ScheduleDataSerializer(serializers.Serializer): class Meta: @@ -47,10 +55,21 @@ class Schedule(APIView): permission_classes = [permissions.AllowAny] - @swagger_auto_schema( - method="GET", - operation_summary="Get plugin schedule detail with trace_id", - responses={200: ScheduleResponseSerializer}, + @extend_schema( + exclude=True, + summary="获取插件调度详情", + operation_id="plugin_schedule", + parameters=[ScheduleParamsSerializer], + responses={200: standard_response_enveloper(ScheduleResponseSerializer)}, + extensions=gen_apigateway_resource_config( + is_public=True, + allow_apply_permission=True, + user_verified_required=True, + app_verified_required=True, + resource_permission_required=True, + description_en="Get plugin schedule detail with trace_id", + match_subpath=False, + ), ) @action(methods=["GET"], detail=True) def get(self, request, trace_id): diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-definition.yml b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-definition.yml deleted file mode 100644 index 3bfdd5d..0000000 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-definition.yml +++ /dev/null @@ -1,35 +0,0 @@ -stage: - name: {{ settings.BK_PLUGIN_APIGW_STAGE_NAME }} - {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} - vars: - api_sub_path: {{ settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH }} - {% else %} - vars: {} - {% endif %} - proxy_http: - timeout: {{ settings.BK_APIGW_DEFAULT_TIMEOUT }} - upstreams: - loadbalance: "roundrobin" - hosts: - - host: "{{ settings.BK_PLUGIN_APIGW_BACKEND_SCHEME }}://{{ settings.BK_PLUGIN_APIGW_BACKEND_NETLOC }}/" - weight: 100 - plugin_configs: - - type: bk-cors - yaml: |- - allow_origins: '{{ settings.BK_APIGW_CORS_ALLOW_ORIGINS }}' - allow_methods: '{{ settings.BK_APIGW_CORS_ALLOW_METHODS }}' - allow_headers: '{{ settings.BK_APIGW_CORS_ALLOW_HEADERS }}' - expose_headers: '' - max_age: 86400 - allow_credential: true - -{% if settings.BK_APIGW_GRANTED_APPS %} -grant_permissions: - {% for app_code in settings.BK_APIGW_GRANTED_APPS %} - - bk_app_code: {{ app_code }} - grant_dimension: "gateway" - {% endfor %} -{% endif %} - -release: - comment: "auto release by bk-plugin-runtime" diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-resources.yml b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-resources.yml deleted file mode 100644 index edf3422..0000000 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-resources.yml +++ /dev/null @@ -1,146 +0,0 @@ -swagger: '2.0' -basePath: / -info: - version: '0.1' - title: API Gateway Resources - description: '' -schemes: -- http -paths: - /invoke/{version}/: - post: - operationId: invoke - description: invoke plugin - tags: [] - responses: - default: - description: '' - x-bk-apigateway-resource: - isPublic: true - allowApplyPermission: true - matchSubpath: false - backend: - type: HTTP - method: post - {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} - path: /{env.api_sub_path}bk_plugin/invoke/{version} - {% else %} - path: /bk_plugin/invoke/{version} - {% endif %} - matchSubpath: false - timeout: 0 - upstreams: {} - transformHeaders: {} - authConfig: - userVerifiedRequired: false - disabledStages: [] - /plugin_api_dispatch: - post: - operationId: plugin_api_dispatch - description: '' - tags: [] - responses: - default: - description: '' - x-bk-apigateway-resource: - isPublic: true - allowApplyPermission: true - matchSubpath: false - backend: - type: HTTP - method: post - {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} - path: /{env.api_sub_path}bk_plugin/plugin_api_dispatch/ - {% else %} - path: /bk_plugin/plugin_api_dispatch/ - {% endif %} - matchSubpath: false - timeout: 0 - upstreams: {} - transformHeaders: {} - authConfig: - userVerifiedRequired: false - disabledStages: [] - /bk_plugin/plugin_api/: - x-bk-apigateway-method-any: - operationId: plugin_api - description: '' - tags: [] - responses: - default: - description: '' - x-bk-apigateway-resource: - isPublic: true - allowApplyPermission: true - matchSubpath: true - backend: - type: HTTP - method: any - {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} - path: /{env.api_sub_path}bk_plugin/plugin_api/ - {% else %} - path: /bk_plugin/plugin_api/ - {% endif %} - matchSubpath: true - timeout: 0 - upstreams: {} - transformHeaders: {} - authConfig: - userVerifiedRequired: true - appVerifiedRequired: false - disabledStages: [] - /bk_plugin/openapi/: - x-bk-apigateway-method-any: - operationId: plugin_openapi - description: '' - tags: [] - responses: - default: - description: '' - x-bk-apigateway-resource: - isPublic: true - allowApplyPermission: true - matchSubpath: true - backend: - type: HTTP - method: any - {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} - path: /{env.api_sub_path}bk_plugin/openapi/ - {% else %} - path: /bk_plugin/openapi/ - {% endif %} - matchSubpath: true - timeout: 0 - upstreams: {} - transformHeaders: {} - authConfig: - userVerifiedRequired: false - appVerifiedRequired: true - disabledStages: [] - /callback/{token}/: - post: - operationId: callback - description: callback plugin - tags: [] - responses: - default: - description: '' - x-bk-apigateway-resource: - isPublic: true - allowApplyPermission: true - matchSubpath: false - backend: - type: HTTP - method: post - {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} - path: /{env.api_sub_path}bk_plugin/callback/{token}/ - {% else %} - path: /bk_plugin/callback/{token}/ - {% endif %} - matchSubpath: false - timeout: 0 - upstreams: {} - transformHeaders: {} - authConfig: - userVerifiedRequired: false - disabledStages: [] diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-strategy-cors.yml b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-strategy-cors.yml deleted file mode 100644 index 01ad279..0000000 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/data/api-strategy-cors.yml +++ /dev/null @@ -1,13 +0,0 @@ -strategies: - - type: "cors" - comment: "" - name: "跨域资源共享(CORS)" - - config: - allowed_origins: {{ settings.BK_APIGW_CORS_ALLOW_ORIGINS }} - allowed_methods: {{ settings.BK_APIGW_CORS_ALLOW_METHODS }} - allowed_headers: {{ settings.BK_APIGW_CORS_ALLOW_HEADERS }} - exposed_headers: [] - max_age: 86400 - allow_credentials: true - option_passthrough: false \ No newline at end of file diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/support-files/resources.yaml b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/support-files/resources.yaml new file mode 100644 index 0000000..591551e --- /dev/null +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/support-files/resources.yaml @@ -0,0 +1,377 @@ +openapi: 3.0.3 +info: + title: 'BK Plugin API' + version: '1.0.0' + description: '蓝鲸插件服务 API' + +paths: + + + /callback/{token}/: + post: + operationId: callback + summary: 插件回调 + description: 插件异步执行完成后的回调接口 + tags: + - callback + parameters: + - in: path + name: token + schema: + type: string + required: true + description: 回调令牌 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PluginCallbackParams' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PluginCallbackParams' + multipart/form-data: + schema: + $ref: '#/components/schemas/PluginCallbackParams' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EnvelopedPluginCallbackResponse' + description: '回调成功' + x-bk-apigateway-resource: + isPublic: true + matchSubpath: false + backend: + name: default + method: post + path: /bk_plugin/callback/{token}/ + matchSubpath: false + timeout: 0 + pluginConfigs: [] + allowApplyPermission: true + authConfig: + userVerifiedRequired: false + appVerifiedRequired: true + resourcePermissionRequired: true + descriptionEn: plugin callback + + /invoke/{version}: + post: + operationId: invoke + summary: 调用指定版本插件 + description: 调用指定版本的插件执行任务 + tags: + - invoke + parameters: + - in: path + name: version + schema: + type: string + required: true + description: 插件版本号 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/InvokeParams' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/InvokeParams' + multipart/form-data: + schema: + $ref: '#/components/schemas/InvokeParams' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EnvelopedInvokeResponse' + description: '调用成功' + x-bk-apigateway-resource: + isPublic: true + matchSubpath: false + backend: + name: default + method: post + path: /bk_plugin/invoke/{version} + matchSubpath: false + timeout: 0 + pluginConfigs: [] + allowApplyPermission: true + authConfig: + userVerifiedRequired: false + appVerifiedRequired: true + resourcePermissionRequired: true + descriptionEn: Invoke specific version plugin + /bk_plugin/plugin_api/: + x-bk-apigateway-method-any: + operationId: plugin_api + summary: 插件自定义API + description: 插件自定义 API 入口,支持子路径匹配 + tags: + - plugin_api + responses: + default: + description: '插件自定义响应' + x-bk-apigateway-resource: + isPublic: true + allowApplyPermission: true + matchSubpath: true + backend: + type: HTTP + name: default + method: any + path: /bk_plugin/plugin_api/ + matchSubpath: true + timeout: 0 + upstreams: { } + transformHeaders: { } + authConfig: + userVerifiedRequired: true + appVerifiedRequired: false + disabledStages: [ ] + descriptionEn: Plugin custom API entry + + /plugin_api_dispatch/: + post: + operationId: plugin_api_dispatch + summary: 插件API分发 + description: 分发请求到插件的自定义 API + tags: + - plugin_api_dispatch + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PluginAPIDispatchParams' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PluginAPIDispatchParams' + multipart/form-data: + schema: + $ref: '#/components/schemas/PluginAPIDispatchParams' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EnvelopedPluginAPIDispatchResponse' + description: '分发成功' + x-bk-apigateway-resource: + isPublic: true + matchSubpath: false + backend: + name: default + method: post + path: /bk_plugin/plugin_api_dispatch/ + matchSubpath: false + timeout: 0 + pluginConfigs: [] + allowApplyPermission: true + authConfig: + userVerifiedRequired: false + appVerifiedRequired: true + resourcePermissionRequired: true + descriptionEn: Plugin API dispatch + +components: + schemas: + # ==================== 请求参数 ==================== + InvokeParams: + type: object + description: 插件调用请求参数 + properties: + inputs: + type: object + additionalProperties: {} + description: 插件调用参数 + context: + type: object + additionalProperties: {} + description: 插件执行上下文 + required: + - context + - inputs + + PluginCallbackParams: + type: object + description: 插件回调请求参数 + properties: + token: + type: string + description: 插件回调token + required: + - token + + PluginAPIDispatchParams: + type: object + description: 插件API分发请求参数 + properties: + url: + type: string + description: 数据接口 URL + method: + type: string + description: 调用方法 + username: + type: string + description: 用户名 + data: + type: object + additionalProperties: {} + default: {} + description: 接口数据 + dumped_data: + type: string + description: json dumps后的接口数据 + required: + - method + - url + - username + + # ==================== 响应数据 ==================== + InvokeData: + type: object + description: 插件调用返回数据 + properties: + outputs: + type: object + additionalProperties: {} + description: 插件输出数据 + state: + type: integer + description: '插件执行状态(2: POLL 3:CALLBACK 4:SUCCESS 5:FAIL)' + err: + type: string + description: 错误信息 + required: + - err + - outputs + - state + + InvokeResponse: + type: object + description: 插件调用响应 + properties: + result: + type: boolean + description: 请求是否成功 + message: + type: string + description: 请求额外信息,result 为 false 时读取 + trace_id: + type: string + description: 调用跟踪 ID + data: + allOf: + - $ref: '#/components/schemas/InvokeData' + description: 接口数据 + required: + - data + - message + - result + - trace_id + + PluginCallbackResponse: + type: object + description: 插件回调响应 + properties: + result: + type: boolean + description: 回调结果,True表示成功,False表示失败 + message: + type: string + description: 回调结果信息 + required: + - result + + PluginAPIDispatchResponse: + type: object + description: 插件API分发响应 + properties: + result: + type: boolean + description: 请求是否成功 + message: + type: string + description: 请求额外信息,result 为 false 时读取 + trace_id: + type: string + description: 调用跟踪 ID + data: + type: object + additionalProperties: {} + description: DATA API 返回的数据 + required: + - data + - message + - result + - trace_id + + # ==================== 统一响应封装 ==================== + EnvelopedInvokeResponse: + type: object + description: 插件调用统一响应封装 + properties: + code: + type: integer + description: 状态码,0表示成功 + data: + $ref: '#/components/schemas/InvokeResponse' + message: + type: string + description: 响应消息 + result: + type: boolean + description: 操作结果 + required: + - code + - data + - message + - result + + EnvelopedPluginCallbackResponse: + type: object + description: 插件回调统一响应封装 + properties: + code: + type: integer + description: 状态码,0表示成功 + data: + $ref: '#/components/schemas/PluginCallbackResponse' + message: + type: string + description: 响应消息 + result: + type: boolean + description: 操作结果 + required: + - code + - data + - message + - result + + EnvelopedPluginAPIDispatchResponse: + type: object + description: 插件API分发统一响应封装 + properties: + code: + type: integer + description: 状态码,0表示成功 + data: + $ref: '#/components/schemas/PluginAPIDispatchResponse' + message: + type: string + description: 响应消息 + result: + type: boolean + description: 操作结果 + required: + - code + - data + - message + - result \ No newline at end of file diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py new file mode 100644 index 0000000..fdf557d --- /dev/null +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py @@ -0,0 +1,311 @@ +""" +Tencent is pleased to support the open source community by making 蓝鲸智云 - PaaS平台 (BlueKing - PaaS System) available. +Copyright (C) 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 +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 hashlib +import os +import time + +import yaml +from django.conf import settings +from django.core.management import call_command +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + help = "仅在接口定义发生变化时同步到API网关" + + def add_arguments(self, parser): + parser.add_argument( + "--force", + action="store_true", + default=False, + help="强制同步,忽略哈希值对比", + ) + + def handle(self, *args, **options): + force_sync = options.get("force", False) + + # 用于记录各步骤耗时(毫秒) + step_timings = {} + + # 1. 生成 yaml 文件 + step_start = time.time() + self.stdout.write("[Sync] generate definition.yaml") + try: + call_command("generate_definition_yaml") + except Exception as e: + self.stderr.write( + self.style.ERROR( + f"run generate_definition_yaml fail: {e}, " + "please run this command on your development env to find out the reason" + ) + ) + raise SystemExit(1) + + self.stdout.write("[Sync] generate resources.yaml") + try: + call_command("generate_resources_yaml") + except Exception as e: + self.stderr.write( + self.style.ERROR( + f"run generate_resources_yaml fail: {e}, " + "please run this command on your development env to find out the reason" + ) + ) + raise SystemExit(1) + + # 输出生成的文件路径 + resources_yaml_path = os.path.join(settings.BASE_DIR, "resources.yaml") + definition_yaml_path = os.path.join(settings.BASE_DIR, "definition.yaml") + self.stdout.write(f"[Sync] Generated resources.yaml path: {resources_yaml_path}") + self.stdout.write(f"[Sync] Generated definition.yaml path: {definition_yaml_path}") + + step_timings["1. 生成 yaml 文件"] = (time.time() - step_start) * 1000 + + # 1.1 合并 support-files/resources.yaml 中的资源配置 + step_start = time.time() + self._merge_support_files_resources() + step_timings["1.1 合并 support-files 资源配置"] = (time.time() - step_start) * 1000 + + # 2. 计算当前哈希值(仅计算 resources.yaml) + step_start = time.time() + current_hash = self._calculate_resources_hash() + self.stdout.write(f"[Sync] Current resources.yaml hash: {current_hash[:16]}...") + step_timings["2. 计算当前哈希值"] = (time.time() - step_start) * 1000 + + # 3. 获取上次同步的哈希值 + step_start = time.time() + last_hash = self._get_last_sync_hash() + if last_hash: + self.stdout.write(f"[Sync] Last sync hash: {last_hash[:16]}...") + else: + self.stdout.write("[Sync] No previous sync record found") + step_timings["3. 获取上次同步的哈希值"] = (time.time() - step_start) * 1000 + + # 4. 对比决定是否同步 + step_start = time.time() + need_sync = force_sync or current_hash != last_hash + if not need_sync: + self.stdout.write(self.style.SUCCESS("[Sync] API definition unchanged, skip sync to apigateway")) + # 仍然获取公钥,确保公钥是最新的 + self._fetch_public_key() + step_timings["4. 对比决定是否同步"] = (time.time() - step_start) * 1000 + # 打印耗时统计 + self._print_timing_stats(step_timings) + return + step_timings["4. 对比决定是否同步"] = (time.time() - step_start) * 1000 + + if force_sync: + self.stdout.write(self.style.WARNING("[Sync] Force sync enabled")) + else: + self.stdout.write(self.style.WARNING("[Sync] API definition changed, start syncing...")) + + # 5. 执行同步 + step_start = time.time() + self.stdout.write("[Sync] sync to apigateway") + try: + call_command("sync_drf_apigateway") + except Exception as e: + self.stderr.write(self.style.ERROR(f"run sync_drf_apigateway fail: {e}")) + # 同步失败时更新状态 + self._save_sync_hash(current_hash, success=False) + raise SystemExit(1) + step_timings["5. 执行同步"] = (time.time() - step_start) * 1000 + + # 6. 获取公钥 + step_start = time.time() + self._fetch_public_key() + step_timings["6. 获取公钥"] = (time.time() - step_start) * 1000 + + # 7. 更新哈希值 + step_start = time.time() + self._save_sync_hash(current_hash, success=True) + self.stdout.write(self.style.SUCCESS("[Sync] API gateway sync completed successfully")) + step_timings["7. 更新哈希值"] = (time.time() - step_start) * 1000 + + # 打印耗时统计 + self._print_timing_stats(step_timings) + + def _print_timing_stats(self, step_timings): + """打印各步骤耗时统计""" + self.stdout.write("\n" + "=" * 50) + self.stdout.write(self.style.SUCCESS("[Sync] 各步骤耗时统计(毫秒):")) + self.stdout.write("=" * 50) + total_time = 0 + for step_name, duration in step_timings.items(): + self.stdout.write(f" {step_name}: {duration:.2f} ms") + total_time += duration + self.stdout.write("-" * 50) + self.stdout.write(f" 总耗时: {total_time:.2f} ms") + self.stdout.write("=" * 50 + "\n") + + def _merge_support_files_resources(self): + """ + 将 support-files/resources.yaml 中的资源配置合并到生成的 resources.yaml 中 + + 合并逻辑: + 1. 读取自动生成的 resources.yaml + 2. 读取 support-files/resources.yaml(手动维护的补充配置) + 3. 将 support-files 中的 paths 追加到生成的 paths 中 + 4. 将 support-files 中的 components/schemas 合并到生成的 components 中 + 5. 写回合并后的 resources.yaml + """ + generated_filepath = os.path.join(settings.BASE_DIR, "resources.yaml") + support_files_dir = os.path.join(os.path.dirname(__file__), "support-files") + support_filepath = os.path.join(support_files_dir, "resources.yaml") + + # 检查生成的文件是否存在 + if not os.path.exists(generated_filepath): + self.stdout.write(self.style.WARNING(f"[Sync] Generated resources.yaml not found: {generated_filepath}")) + return + + # 检查 support-files/resources.yaml 是否存在 + if not os.path.exists(support_filepath): + self.stdout.write( + self.style.WARNING(f"[Sync] support-files/resources.yaml not found: {support_filepath}, skip merging") + ) + return + + try: + # 读取自动生成的 resources.yaml + with open(generated_filepath, encoding="utf-8") as f: + generated_data = yaml.safe_load(f) + + # 读取 support-files/resources.yaml + with open(support_filepath, encoding="utf-8") as f: + support_data = yaml.safe_load(f) + + if not generated_data: + self.stdout.write(self.style.WARNING("[Sync] Generated resources.yaml is empty")) + return + + if not support_data: + self.stdout.write(self.style.WARNING("[Sync] support-files/resources.yaml is empty, skip merging")) + return + + merged_paths_count = 0 + merged_schemas_count = 0 + + # 合并 paths + if "paths" in support_data: + if "paths" not in generated_data: + generated_data["paths"] = {} + + for path, path_config in support_data["paths"].items(): + if path in generated_data["paths"]: + self.stdout.write( + self.style.WARNING( + f"[Sync] Path '{path}' already exists, will be overwritten by support-files config" + ) + ) + generated_data["paths"][path] = path_config + merged_paths_count += 1 + self.stdout.write(f"[Sync] Merged path: {path}") + + # 合并 components/schemas + if "components" in support_data and "schemas" in support_data.get("components", {}): + if "components" not in generated_data: + generated_data["components"] = {} + if "schemas" not in generated_data["components"]: + generated_data["components"]["schemas"] = {} + + for schema_name, schema_config in support_data["components"]["schemas"].items(): + if schema_name in generated_data["components"]["schemas"]: + self.stdout.write( + self.style.WARNING(f"[Sync] Schema '{schema_name}' already exists, will be overwritten") + ) + generated_data["components"]["schemas"][schema_name] = schema_config + merged_schemas_count += 1 + + # 写回合并后的文件 + with open(generated_filepath, "w", encoding="utf-8") as f: + yaml.dump(generated_data, f, default_flow_style=False, allow_unicode=True, sort_keys=False) + + self.stdout.write( + self.style.SUCCESS( + f"[Sync] Merged support-files/resources.yaml: " + f"{merged_paths_count} paths, {merged_schemas_count} schemas" + ) + ) + + except Exception as e: + self.stderr.write(self.style.ERROR(f"[Sync] Failed to merge support-files/resources.yaml: {e}")) + + def _calculate_resources_hash(self): + """ + 计算 resources.yaml 的哈希值 + + 注意:为了避免 YAML 内容顺序变化导致的 hash 不一致问题, + 这里先将 YAML 解析为字典,然后用 sort_keys=True 重新序列化, + 确保相同内容的 YAML 文件总是产生相同的 hash 值。 + """ + filepath = os.path.join(settings.BASE_DIR, "resources.yaml") + if os.path.exists(filepath): + try: + with open(filepath, encoding="utf-8") as f: + data = yaml.safe_load(f) + + if data: + # 使用 sort_keys=True 确保输出顺序一致 + # 这样即使原始文件中 A,B,C 和 B,C,A 的顺序不同, + # 规范化后的内容也会相同,从而产生相同的 hash + normalized_content = yaml.dump( + data, default_flow_style=False, allow_unicode=True, sort_keys=True # 关键:排序所有 key + ) + return hashlib.sha256(normalized_content.encode()).hexdigest() + except Exception as e: + self.stdout.write( + self.style.WARNING( + f"[Sync] Failed to normalize resources.yaml for hash: {e}, fallback to raw content hash" + ) + ) + # 回退到原始方式 + with open(filepath, encoding="utf-8") as f: + content = f.read() + return hashlib.sha256(content.encode()).hexdigest() + return "" + + def _get_last_sync_hash(self): + """从数据库获取上次同步的哈希值""" + try: + from bk_plugin_framework.services.bpf_service.models import ( + APIGatewaySyncState, + ) + + state = APIGatewaySyncState.objects.filter(sync_success=True).first() + return state.api_hash if state else "" + except Exception as e: + self.stdout.write(self.style.WARNING(f"[Sync] Failed to get last sync hash: {e}")) + return "" + + def _save_sync_hash(self, hash_value, success=True): + """保存哈希值到数据库""" + try: + from bk_plugin_framework.services.bpf_service.models import ( + APIGatewaySyncState, + ) + + # 使用 update_or_create,保证只有一条记录 + APIGatewaySyncState.objects.update_or_create( + pk=1, defaults={"api_hash": hash_value, "sync_success": success} + ) + self.stdout.write(f"[Sync] Sync state saved (success={success})") + except Exception as e: + self.stdout.write(self.style.WARNING(f"[Sync] Failed to save sync hash: {e}")) + + def _fetch_public_key(self): + """获取 API 网关公钥""" + self.stdout.write("[Sync] fetch the public key") + try: + call_command("fetch_apigw_public_key") + except Exception as e: + self.stderr.write(self.style.ERROR(f"run fetch_apigw_public_key fail: {e}")) + raise SystemExit(1) diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_plugin_apigw.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_plugin_apigw.py deleted file mode 100644 index 46c246b..0000000 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_plugin_apigw.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Tencent is pleased to support the open source community by making 蓝鲸智云 - PaaS平台 (BlueKing - PaaS System) available. -Copyright (C) 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 -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 - -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(__file__.rsplit("/", 1)[0], "data/api-definition.yml") - resources_file_path = os.path.join(__file__.rsplit("/", 1)[0], "data/api-resources.yml") - print("[bk-plugin-framework]call sync_apigw_stage with definition: %s" % definition_file_path) - call_command("sync_apigw_stage", file=definition_file_path) - print("[bk-plugin-framework]call sync_apigw_resources with resources: %s" % resources_file_path) - call_command("sync_apigw_resources", file=resources_file_path) - print("[bk-plugin-framework]call sync_apigw_strategies with definition: %s" % definition_file_path) - call_command("sync_apigw_strategies", file=definition_file_path) - print("[bk-plugin-framework]call grant_apigw_permissions with definition: %s" % definition_file_path) - call_command("grant_apigw_permissions", file=definition_file_path) - - # if getattr(settings, "BK_APIGW_CORS_ALLOW_ORIGINS"): - # strategy_cors_file_path = os.path.join(__file__.rsplit("/", 1)[0], "data/api-strategy-cors.yml") - # print("[bk-plugin-framework]call sync_apigw_strategies cors with strategy: %s" % strategy_cors_file_path) - # call_command("sync_apigw_strategies", file=strategy_cors_file_path) - - print("[bk-plugin-framework]call create_version_and_release_apigw with definition: %s" % definition_file_path) - call_command( - "create_version_and_release_apigw", file=definition_file_path, stage=[settings.BK_PLUGIN_APIGW_STAGE_NAME] - ) diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/migrations/0001_initial.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/migrations/0001_initial.py new file mode 100644 index 0000000..1ac1731 --- /dev/null +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/migrations/0001_initial.py @@ -0,0 +1,63 @@ +""" +Tencent is pleased to support the open source community by making 蓝鲸智云 - PaaS平台 (BlueKing - PaaS System) available. +Copyright (C) 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 +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. +""" + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="APIGatewaySyncState", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "api_hash", + models.CharField( + default="", + max_length=64, + verbose_name="接口定义哈希值", + ), + ), + ( + "last_sync_at", + models.DateTimeField( + auto_now=True, + verbose_name="上次同步时间", + ), + ), + ( + "sync_success", + models.BooleanField( + default=False, + verbose_name="同步是否成功", + ), + ), + ], + options={ + "verbose_name": "API网关同步状态", + "verbose_name_plural": "API网关同步状态", + "db_table": "bpf_apigateway_sync_state", + }, + ), + ] diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/models.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/models.py new file mode 100644 index 0000000..330845c --- /dev/null +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/models.py @@ -0,0 +1,35 @@ +""" +Tencent is pleased to support the open source community by making 蓝鲸智云 - PaaS平台 (BlueKing - PaaS System) available. +Copyright (C) 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 +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. +""" + +from django.db import models + + +class APIGatewaySyncState(models.Model): + """API网关同步状态记录 + + 用于存储上次成功同步时的接口定义哈希值, + 通过对比哈希值判断是否需要重新同步。 + """ + + # resources.yaml 的哈希值 + api_hash = models.CharField(max_length=64, default="", verbose_name="接口定义哈希值") + # 上次同步时间 + last_sync_at = models.DateTimeField(auto_now=True, verbose_name="上次同步时间") + # 同步是否成功 + sync_success = models.BooleanField(default=False, verbose_name="同步是否成功") + + class Meta: + db_table = "bpf_apigateway_sync_state" + verbose_name = "API网关同步状态" + verbose_name_plural = "API网关同步状态" + + def __str__(self): + return f"APIGatewaySyncState(hash={self.api_hash[:16]}..., success={self.sync_success})" diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/urls.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/urls.py index 07c8dec..f67660b 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/urls.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/urls.py @@ -21,12 +21,14 @@ PLUGIN_OPENAPI_URLS_MODULE = "bk_plugin.openapi.urls" urlpatterns = [ + # 协议层接口(与平台方对接) + path(r"plugin_api_dispatch/", api.PluginAPIDispatch.as_view()), + path(r"callback//", api.PluginCallback.as_view()), + path(r"invoke/", api.Invoke.as_view()), + # 插件信息接口 path(r"meta/", api.Meta.as_view()), path(r"detail/", api.Detail.as_view()), - path(r"invoke/", api.Invoke.as_view()), path(r"schedule/", api.Schedule.as_view()), - path(r"plugin_api_dispatch/", api.PluginAPIDispatch.as_view()), - path(r"callback//", api.PluginCallback.as_view()), ] # add log api diff --git a/template/{{cookiecutter.project_name}}/bin/post_compile b/template/{{cookiecutter.project_name}}/bin/post_compile deleted file mode 100644 index 19c7a3c..0000000 --- a/template/{{cookiecutter.project_name}}/bin/post_compile +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -# DO NOT MODIFY THIS SECTION !!! -env -python bin/manage.py migrate -python bin/manage.py sync_plugin_apigw -python bin/manage.py fetch_apigw_public_key -# DO NOT MODIFY THIS SECTION !!! \ No newline at end of file diff --git a/template/{{cookiecutter.project_name}}/bin/sync_apigateway.sh b/template/{{cookiecutter.project_name}}/bin/sync_apigateway.sh new file mode 100755 index 0000000..f4c3fa2 --- /dev/null +++ b/template/{{cookiecutter.project_name}}/bin/sync_apigateway.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# DO NOT MODIFY THIS SECTION !!! +echo "do migrate" +python bin/manage.py migrate --no-input + +echo "[Sync] BEGIN =====================" + +# 使用智能同步命令,仅在接口定义发生变化时才同步到API网关 +# 该命令会自动: +# 1. 生成 definition.yaml 和 resources.yaml +# 2. 计算文件哈希值并与上次同步的哈希值对比 +# 3. 仅在哈希值变化时执行 sync_drf_apigateway +# 4. 获取 API 网关公钥 +# +# 如需强制同步,可添加 --force 参数: +# python bin/manage.py sync_apigateway_if_changed --force + +python bin/manage.py sync_apigateway_if_changed +if [ $? -ne 0 ] +then + echo "sync_apigateway_if_changed fail" + exit 1 +fi + +echo "[Sync] DONE =====================" +# DO NOT MODIFY THIS SECTION !!! \ No newline at end of file From 1d8862222293a6323c1065155092fc178ac72de5 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 15:09:50 +0800 Subject: [PATCH 02/21] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9bk=5Fplugin=5Ffr?= =?UTF-8?q?amework=E7=9A=84pyproject.toml=E6=96=87=E4=BB=B6=20--story=3D13?= =?UTF-8?q?0029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bk-plugin-framework/pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bk-plugin-framework/pyproject.toml b/bk-plugin-framework/pyproject.toml index d6f5405..0745c8a 100644 --- a/bk-plugin-framework/pyproject.toml +++ b/bk-plugin-framework/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-framework" -version = "2.3.3" +version = "2.3.4rc1" description = "bk plugin python framework" authors = ["Your Name "] license = "MIT" @@ -10,7 +10,7 @@ python = "^3.8.0,<4.0" pydantic = ">=1.0,<3" werkzeug = ">=2.0.0, <4.0" apigw-manager = {version = ">=1.0.6, <4", extras = ["extra"]} -bk-plugin-runtime = "2.1.2" +bk-plugin-runtime = "2.1.3rc1" jsonschema = ">=2.5.0,<5.0.0" [tool.poetry.dev-dependencies] From c1656196b86ce58531e590a18f3556575dad020e Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 15:27:22 +0800 Subject: [PATCH 03/21] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9bk=5Fplugin=5Fru?= =?UTF-8?q?ntime=E7=9A=84=20pyproject.toml=E7=9B=B8=E5=85=B3=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=20--story=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- runtime/bk-plugin-runtime/poetry.lock | 404 +++++++---------------- runtime/bk-plugin-runtime/pyproject.toml | 10 +- 2 files changed, 117 insertions(+), 297 deletions(-) diff --git a/runtime/bk-plugin-runtime/poetry.lock b/runtime/bk-plugin-runtime/poetry.lock index f31cb08..4d1da90 100644 --- a/runtime/bk-plugin-runtime/poetry.lock +++ b/runtime/bk-plugin-runtime/poetry.lock @@ -1,19 +1,19 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "amqp" -version = "5.3.1" +version = "2.6.1" description = "Low-level AMQP client for Python (fork of amqplib)." optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" groups = ["main"] files = [ - {file = "amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2"}, - {file = "amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432"}, + {file = "amqp-2.6.1-py2.py3-none-any.whl", hash = "sha256:aa7f313fb887c91f15474c1229907a04dac0b8135822d6603437803424c0aa59"}, + {file = "amqp-2.6.1.tar.gz", hash = "sha256:70cdb10628468ff14e57ec2f751c7aa9e48e7e3651cfd62d431213c0c4e58f21"}, ] [package.dependencies] -vine = ">=5.0.0,<6.0.0" +vine = ">=1.1.3,<5.0.0a1" [[package]] name = "asgiref" @@ -73,22 +73,19 @@ files = [ {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, ] -[package.dependencies] -tzdata = {version = "*", optional = true, markers = "extra == \"tzdata\""} - [package.extras] tzdata = ["tzdata"] [[package]] name = "billiard" -version = "4.2.1" +version = "3.6.4.0" description = "Python multiprocessing fork with improvements and bugfixes" optional = false -python-versions = ">=3.7" +python-versions = "*" groups = ["main"] files = [ - {file = "billiard-4.2.1-py3-none-any.whl", hash = "sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb"}, - {file = "billiard-4.2.1.tar.gz", hash = "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f"}, + {file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"}, + {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, ] [[package]] @@ -153,61 +150,55 @@ opentelemetry = ["django-prometheus (>=2.1.0,<3.0.0)", "opentelemetry-api (>=1.6 [[package]] name = "celery" -version = "5.5.3" +version = "4.4.7" description = "Distributed Task Queue." optional = false -python-versions = ">=3.8" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" groups = ["main"] files = [ - {file = "celery-5.5.3-py3-none-any.whl", hash = "sha256:0b5761a07057acee94694464ca482416b959568904c9dfa41ce8413a7d65d525"}, - {file = "celery-5.5.3.tar.gz", hash = "sha256:6c972ae7968c2b5281227f01c3a3f984037d21c5129d07bf3550cc2afc6b10a5"}, + {file = "celery-4.4.7-py2.py3-none-any.whl", hash = "sha256:a92e1d56e650781fb747032a3997d16236d037c8199eacd5217d1a72893bca45"}, + {file = "celery-4.4.7.tar.gz", hash = "sha256:d220b13a8ed57c78149acf82c006785356071844afe0b27012a4991d44026f9f"}, ] [package.dependencies] -"backports.zoneinfo" = {version = ">=0.2.1", extras = ["tzdata"], markers = "python_version < \"3.9\""} -billiard = ">=4.2.1,<5.0" -click = ">=8.1.2,<9.0" -click-didyoumean = ">=0.3.0" -click-plugins = ">=1.1.1" -click-repl = ">=0.2.0" -kombu = ">=5.5.2,<5.6" -python-dateutil = ">=2.8.2" -vine = ">=5.1.0,<6.0" +billiard = ">=3.6.3.0,<4.0" +kombu = ">=4.6.10,<4.7" +pytz = ">0.0-dev" +vine = "1.3.0" [package.extras] -arangodb = ["pyArango (>=2.0.2)"] -auth = ["cryptography (==44.0.2)"] -azureblockblob = ["azure-identity (>=1.19.0)", "azure-storage-blob (>=12.15.0)"] +arangodb = ["pyArango (>=1.3.2)"] +auth = ["cryptography"] +azureblockblob = ["azure-common (==1.1.5)", "azure-storage (==0.36.0)", "azure-storage-common (==1.1.0)"] brotli = ["brotli (>=1.0.0) ; platform_python_implementation == \"CPython\"", "brotlipy (>=0.7.0) ; platform_python_implementation == \"PyPy\""] -cassandra = ["cassandra-driver (>=3.25.0,<4)"] -consul = ["python-consul2 (==0.1.5)"] -cosmosdbsql = ["pydocumentdb (==2.3.5)"] -couchbase = ["couchbase (>=3.0.0) ; platform_python_implementation != \"PyPy\" and (platform_system != \"Windows\" or python_version < \"3.10\")"] -couchdb = ["pycouchdb (==1.16.0)"] -django = ["Django (>=2.2.28)"] -dynamodb = ["boto3 (>=1.26.143)"] -elasticsearch = ["elastic-transport (<=8.17.1)", "elasticsearch (<=8.17.2)"] -eventlet = ["eventlet (>=0.32.0) ; python_version < \"3.10\""] -gcs = ["google-cloud-firestore (==2.20.1)", "google-cloud-storage (>=2.10.0)", "grpcio (==1.67.0)"] -gevent = ["gevent (>=1.5.0)"] -librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] -memcache = ["pylibmc (==1.6.3) ; platform_system != \"Windows\""] -mongodb = ["kombu[mongodb]"] -msgpack = ["kombu[msgpack]"] -pydantic = ["pydantic (>=2.4)"] -pymemcache = ["python-memcached (>=1.61)"] -pyro = ["pyro4 (==4.82) ; python_version < \"3.11\""] -pytest = ["pytest-celery[all] (>=1.2.0,<1.3.0)"] -redis = ["kombu[redis]"] -s3 = ["boto3 (>=1.26.143)"] -slmq = ["softlayer_messaging (>=1.0.3)"] -solar = ["ephem (==4.2) ; platform_python_implementation != \"PyPy\""] -sqlalchemy = ["kombu[sqlalchemy]"] -sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.5.0)", "urllib3 (>=1.26.16)"] +cassandra = ["cassandra-driver (<3.21.0)"] +consul = ["python-consul"] +cosmosdbsql = ["pydocumentdb (==2.3.2)"] +couchbase = ["couchbase (<3.0.0) ; platform_system != \"Windows\"", "couchbase-cffi (<3.0.0) ; platform_python_implementation == \"PyPy\""] +couchdb = ["pycouchdb"] +django = ["Django (>=1.11)"] +dynamodb = ["boto3 (>=1.9.178)"] +elasticsearch = ["elasticsearch"] +eventlet = ["eventlet (>=0.24.1)"] +gevent = ["gevent"] +librabbitmq = ["librabbitmq (>=1.5.0)"] +lzma = ["backports.lzma ; python_version < \"3.3\""] +memcache = ["pylibmc ; platform_system != \"Windows\""] +mongodb = ["pymongo[srv] (>=3.3.0)"] +msgpack = ["msgpack"] +pymemcache = ["python-memcached"] +pyro = ["pyro4"] +redis = ["redis (>=3.2.0)"] +riak = ["riak (>=2.0)"] +s3 = ["boto3 (>=1.9.125)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +solar = ["ephem"] +sqlalchemy = ["sqlalchemy"] +sqs = ["boto3 (>=1.9.125)", "pycurl (==7.43.0.5)"] tblib = ["tblib (>=1.3.0) ; python_version < \"3.8.0\"", "tblib (>=1.5.0) ; python_version >= \"3.8.0\""] -yaml = ["kombu[yaml]"] +yaml = ["PyYAML (>=3.10)"] zookeeper = ["kazoo (>=1.3.1)"] -zstd = ["zstandard (==0.23.0)"] +zstd = ["zstandard"] [[package]] name = "certifi" @@ -391,101 +382,6 @@ files = [ {file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"}, ] -[[package]] -name = "click" -version = "8.1.8" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, - {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "click-didyoumean" -version = "0.3.1" -description = "Enables git-like *did-you-mean* feature in click" -optional = false -python-versions = ">=3.6.2" -groups = ["main"] -files = [ - {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, - {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, -] - -[package.dependencies] -click = ">=7" - -[[package]] -name = "click-plugins" -version = "1.1.1.2" -description = "An extension module for click to enable registering CLI commands via setuptools entry-points." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6"}, - {file = "click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261"}, -] - -[package.dependencies] -click = ">=4.0" - -[package.extras] -dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] - -[[package]] -name = "click-repl" -version = "0.3.0" -description = "REPL plugin for Click" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, - {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, -] - -[package.dependencies] -click = ">=7.0" -prompt-toolkit = ">=3.0.36" - -[package.extras] -testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main"] -markers = "platform_system == \"Windows\"" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "cron-descriptor" -version = "1.4.5" -description = "A Python library that converts cron expressions into human readable strings." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "cron_descriptor-1.4.5-py3-none-any.whl", hash = "sha256:736b3ae9d1a99bc3dbfc5b55b5e6e7c12031e7ba5de716625772f8b02dcd6013"}, - {file = "cron_descriptor-1.4.5.tar.gz", hash = "sha256:f51ce4ffc1d1f2816939add8524f206c376a42c87a5fca3091ce26725b3b1bca"}, -] - -[package.extras] -dev = ["polib"] - [[package]] name = "cryptography" version = "43.0.3" @@ -574,21 +470,20 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version [[package]] name = "django" -version = "4.2.23" -description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +version = "3.2.25" +description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" groups = ["main"] files = [ - {file = "django-4.2.23-py3-none-any.whl", hash = "sha256:dafbfaf52c2f289bd65f4ab935791cb4fb9a198f2a5ba9faf35d7338a77e9803"}, - {file = "django-4.2.23.tar.gz", hash = "sha256:42fdeaba6e6449d88d4f66de47871015097dc6f1b87910db00a91946295cfae4"}, + {file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"}, + {file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"}, ] [package.dependencies] -asgiref = ">=3.6.0,<4" -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -sqlparse = ">=0.3.1" -tzdata = {version = "*", markers = "sys_platform == \"win32\""} +asgiref = ">=3.3.2,<4" +pytz = "*" +sqlparse = ">=0.2.2" [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] @@ -596,56 +491,51 @@ bcrypt = ["bcrypt"] [[package]] name = "django-celery-beat" -version = "2.8.1" +version = "2.2.0" description = "Database-backed Periodic Tasks." optional = false -python-versions = ">=3.8" +python-versions = "*" groups = ["main"] files = [ - {file = "django_celery_beat-2.8.1-py3-none-any.whl", hash = "sha256:da2b1c6939495c05a551717509d6e3b79444e114a027f7b77bf3727c2a39d171"}, - {file = "django_celery_beat-2.8.1.tar.gz", hash = "sha256:dfad0201c0ac50c91a34700ef8fa0a10ee098cc7f3375fe5debed79f2204f80a"}, + {file = "django-celery-beat-2.2.0.tar.gz", hash = "sha256:b8a13afb15e7c53fc04f4f847ac71a6d32088959aba701eb7c4a59f0c28ba543"}, + {file = "django_celery_beat-2.2.0-py2.py3-none-any.whl", hash = "sha256:c4c72a9579f20eff4c4ccf1b58ebdca5ef940f4210065057db1754ea5f8dffdc"}, ] [package.dependencies] -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -celery = ">=5.2.3,<6.0" -cron-descriptor = ">=1.2.32" -Django = ">=2.2,<6.0" -django-timezone-field = ">=5.0" +celery = ">=4.4,<6.0" +Django = ">=2.2,<4.0" +django-timezone-field = ">=4.1.0,<5.0" python-crontab = ">=2.3.4" -tzdata = "*" [[package]] name = "django-celery-results" -version = "2.6.0" +version = "1.2.1" description = "Celery result backends for Django." optional = false python-versions = "*" groups = ["main"] files = [ - {file = "django_celery_results-2.6.0-py3-none-any.whl", hash = "sha256:b9ccdca2695b98c7cbbb8dea742311ba9a92773d71d7b4944a676e69a7df1c73"}, - {file = "django_celery_results-2.6.0.tar.gz", hash = "sha256:9abcd836ae6b61063779244d8887a88fe80bbfaba143df36d3cb07034671277c"}, + {file = "django_celery_results-1.2.1-py2.py3-none-any.whl", hash = "sha256:a29ab580f0e38c66c39f51cc426bbdbb2a391b8cc0867df9dea748db2c961db2"}, + {file = "django_celery_results-1.2.1.tar.gz", hash = "sha256:e390f70cc43bbc2cd7c8e4607dc29ab6211a2ab968f93677583f0160921f670c"}, ] [package.dependencies] -celery = ">=5.2.7,<6.0" -Django = ">=3.2.25" +celery = ">=4.4,<5.0" [[package]] name = "django-cors-headers" -version = "4.4.0" +version = "3.14.0" description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" groups = ["main"] files = [ - {file = "django_cors_headers-4.4.0-py3-none-any.whl", hash = "sha256:5c6e3b7fe870876a1efdfeb4f433782c3524078fa0dc9e0195f6706ce7a242f6"}, - {file = "django_cors_headers-4.4.0.tar.gz", hash = "sha256:92cf4633e22af67a230a1456cb1b7a02bb213d6536d2dcb2a4a24092ea9cebc2"}, + {file = "django_cors_headers-3.14.0-py3-none-any.whl", hash = "sha256:684180013cc7277bdd8702b80a3c5a4b3fcae4abb2bf134dceb9f5dfe300228e"}, + {file = "django_cors_headers-3.14.0.tar.gz", hash = "sha256:5fbd58a6fb4119d975754b2bc090f35ec160a8373f276612c675b00e8a138739"}, ] [package.dependencies] -asgiref = ">=3.6" -django = ">=3.2" +Django = ">=3.2" [[package]] name = "django-dbconn-retry" @@ -660,51 +550,53 @@ files = [ [[package]] name = "django-prometheus" -version = "2.4.1" +version = "2.4.0" description = "Django middlewares to monitor your application with Prometheus.io." optional = false python-versions = "*" groups = ["main"] files = [ - {file = "django_prometheus-2.4.1-py2.py3-none-any.whl", hash = "sha256:7fe5af7f7c9ad9cd8a429fe0f3f1bf651f0e244f77162147869eab7ec09cc5e7"}, - {file = "django_prometheus-2.4.1.tar.gz", hash = "sha256:073628243d2a6de6a8a8c20e5b512872dfb85d66e1b60b28bcf1eca0155dad95"}, + {file = "django_prometheus-2.4.0-py2.py3-none-any.whl", hash = "sha256:5b46b5f07b02ba8dd7abdb03a3c39073e8fd9120e2293a1ecb949bbb865378ac"}, + {file = "django_prometheus-2.4.0.tar.gz", hash = "sha256:67da5c73d8e859aa73f6e11f52341c482691b17f8bd9844157cff6cdf51ce9bc"}, ] [package.dependencies] -Django = ">=4.2,<6.0" prometheus-client = ">=0.7" [[package]] name = "django-timezone-field" -version = "7.1" -description = "A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects." +version = "4.2.3" +description = "A Django app providing database and form fields for pytz timezone objects." optional = false -python-versions = "<4.0,>=3.8" +python-versions = ">=3.5" groups = ["main"] files = [ - {file = "django_timezone_field-7.1-py3-none-any.whl", hash = "sha256:93914713ed882f5bccda080eda388f7006349f25930b6122e9b07bf8db49c4b4"}, - {file = "django_timezone_field-7.1.tar.gz", hash = "sha256:b3ef409d88a2718b566fabe10ea996f2838bc72b22d3a2900c0aa905c761380c"}, + {file = "django-timezone-field-4.2.3.tar.gz", hash = "sha256:5dd5bd9249382bef8847d3e7e4c32b7be182a4b538f354130d1252ed228892f8"}, + {file = "django_timezone_field-4.2.3-py3-none-any.whl", hash = "sha256:7552d2b0f145684b7de3fb5046101c7efd600cc6ba951b15c630fa1e1b83558e"}, ] [package.dependencies] -"backports.zoneinfo" = {version = ">=0.2.1,<0.3.0", markers = "python_version < \"3.9\""} -Django = ">=3.2,<6.0" +django = ">=2.2" +pytz = "*" + +[package.extras] +rest-framework = ["djangorestframework (>=3.0.0)"] [[package]] name = "djangorestframework" -version = "3.15.2" +version = "3.15.1" description = "Web APIs for Django, made easy." optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" groups = ["main"] files = [ - {file = "djangorestframework-3.15.2-py3-none-any.whl", hash = "sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20"}, - {file = "djangorestframework-3.15.2.tar.gz", hash = "sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad"}, + {file = "djangorestframework-3.15.1-py3-none-any.whl", hash = "sha256:3ccc0475bce968608cf30d07fb17d8e52d1d7fc8bfe779c905463200750cbca6"}, + {file = "djangorestframework-3.15.1.tar.gz", hash = "sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1"}, ] [package.dependencies] "backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -django = ">=4.2" +django = ">=3.0" [[package]] name = "drf-yasg" @@ -958,40 +850,34 @@ files = [ [[package]] name = "kombu" -version = "5.5.4" +version = "4.6.11" description = "Messaging library for Python." optional = false -python-versions = ">=3.8" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" groups = ["main"] files = [ - {file = "kombu-5.5.4-py3-none-any.whl", hash = "sha256:a12ed0557c238897d8e518f1d1fdf84bd1516c5e305af2dacd85c2015115feb8"}, - {file = "kombu-5.5.4.tar.gz", hash = "sha256:886600168275ebeada93b888e831352fe578168342f0d1d5833d88ba0d847363"}, + {file = "kombu-4.6.11-py2.py3-none-any.whl", hash = "sha256:be48cdffb54a2194d93ad6533d73f69408486483d189fe9f5990ee24255b0e0a"}, + {file = "kombu-4.6.11.tar.gz", hash = "sha256:ca1b45faac8c0b18493d02a8571792f3c40291cf2bcf1f55afed3d8f3aa7ba74"}, ] [package.dependencies] -amqp = ">=5.1.1,<6.0.0" -"backports.zoneinfo" = {version = ">=0.2.1", extras = ["tzdata"], markers = "python_version < \"3.9\""} -packaging = "*" -tzdata = {version = ">=2025.2", markers = "python_version >= \"3.9\""} -vine = "5.1.0" +amqp = ">=2.6.0,<2.7" [package.extras] -azureservicebus = ["azure-servicebus (>=7.10.0)"] -azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] -confluentkafka = ["confluent-kafka (>=2.2.0)"] -consul = ["python-consul2 (==0.1.5)"] -gcpubsub = ["google-cloud-monitoring (>=2.16.0)", "google-cloud-pubsub (>=2.18.4)", "grpcio (==1.67.0)", "protobuf (==4.25.5)"] -librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] -mongodb = ["pymongo (==4.10.1)"] -msgpack = ["msgpack (==1.1.0)"] -pyro = ["pyro4 (==4.82)"] +azureservicebus = ["azure-servicebus (>=0.21.1)"] +azurestoragequeues = ["azure-storage-queue"] +consul = ["python-consul (>=0.6.0)"] +librabbitmq = ["librabbitmq (>=1.5.2)"] +mongodb = ["pymongo (>=3.3.0)"] +msgpack = ["msgpack"] +pyro = ["pyro4"] qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] -redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<=5.2.1)"] -slmq = ["softlayer_messaging (>=1.0.3)"] -sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] -sqs = ["boto3 (>=1.26.143)", "urllib3 (>=1.26.16)"] +redis = ["redis (>=3.3.11)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy"] +sqs = ["boto3 (>=1.4.4)", "pycurl (==7.43.0.2)"] yaml = ["PyYAML (>=3.10)"] -zookeeper = ["kazoo (>=2.8.0)"] +zookeeper = ["kazoo (>=1.3.1)"] [[package]] name = "mako" @@ -1479,21 +1365,6 @@ files = [ [package.extras] twisted = ["twisted"] -[[package]] -name = "prompt-toolkit" -version = "3.0.51" -description = "Library for building powerful interactive command lines in Python" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"}, - {file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"}, -] - -[package.dependencies] -wcwidth = "*" - [[package]] name = "protobuf" version = "5.29.5" @@ -1629,21 +1500,6 @@ files = [ cron-description = ["cron-descriptor"] cron-schedule = ["croniter"] -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main"] -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - [[package]] name = "python-json-logger" version = "3.3.0" @@ -1795,18 +1651,6 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "six" -version = "1.17.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main"] -files = [ - {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, - {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, -] - [[package]] name = "sqlparse" version = "0.5.3" @@ -1851,18 +1695,6 @@ files = [ {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] -[[package]] -name = "tzdata" -version = "2025.2" -description = "Provider of IANA time zone data" -optional = false -python-versions = ">=2" -groups = ["main"] -files = [ - {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, - {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, -] - [[package]] name = "uritemplate" version = "4.1.1" @@ -1895,26 +1727,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "vine" -version = "5.1.0" -description = "Python promises." -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, - {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, -] - -[[package]] -name = "wcwidth" -version = "0.2.13" -description = "Measures the displayed width of unicode strings in a terminal" +version = "1.3.0" +description = "Promises, promises, promises." optional = false -python-versions = "*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" groups = ["main"] files = [ - {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, - {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, + {file = "vine-1.3.0-py2.py3-none-any.whl", hash = "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"}, + {file = "vine-1.3.0.tar.gz", hash = "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87"}, ] [[package]] @@ -2064,4 +1884,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.8.0,<4.0" -content-hash = "ac0d1626509d1ed8b924db0e6f917c748714b1038531f493ccfebf3df1153fb1" +content-hash = "330ace9c21c35e52a1c7114683d6fedbdd35718a1822e17bf5982f08cb074730" diff --git a/runtime/bk-plugin-runtime/pyproject.toml b/runtime/bk-plugin-runtime/pyproject.toml index d848a5d..ff7ff98 100644 --- a/runtime/bk-plugin-runtime/pyproject.toml +++ b/runtime/bk-plugin-runtime/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-runtime" -version = "2.1.2" +version = "2.1.3rc1" description = "bk plugin python django runtime" authors = ["Your Name "] license = "MIT" @@ -15,13 +15,13 @@ djangorestframework = "^3.15" drf-yasg = "^1.21.5" raven = "^6.5.0" ddtrace = "^0.14.1" -django-cors-headers = "^4.0.0" +django-cors-headers = "^3.8.0" django-dbconn-retry = "^0.1.5" blueapps = {version = ">=4.15.1, <5.0", extras = ["opentelemetry"]} protobuf=">=3.19.4,<6.0" -celery = "^5.4.0" -django-celery-beat = "^2.7.0" -django-celery-results = "^2.5.1" +celery = "^4.4.0" +django-celery-beat = "^2.2.0" +django-celery-results = "^1.2.1" [tool.poetry.dev-dependencies] From d5499bf19f1a6df8cd2360db20744d7c6e1eff13 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 16:03:16 +0800 Subject: [PATCH 04/21] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0drf=5Fspectacula?= =?UTF-8?q?r=E7=AC=AC=E4=B8=89=E6=96=B9=E4=BE=9D=E8=B5=96=E5=8C=85?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8F=AF=E7=BC=96=E7=A8=8B=E7=BD=91=E5=85=B3?= =?UTF-8?q?=20--story=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bk-plugin-framework/poetry.lock | 451 +++++++++-------------------- bk-plugin-framework/pyproject.toml | 1 + 2 files changed, 141 insertions(+), 311 deletions(-) diff --git a/bk-plugin-framework/poetry.lock b/bk-plugin-framework/poetry.lock index 2681369..a879289 100644 --- a/bk-plugin-framework/poetry.lock +++ b/bk-plugin-framework/poetry.lock @@ -1,19 +1,19 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "amqp" -version = "5.3.1" +version = "2.6.1" description = "Low-level AMQP client for Python (fork of amqplib)." optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" groups = ["main"] files = [ - {file = "amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2"}, - {file = "amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432"}, + {file = "amqp-2.6.1-py2.py3-none-any.whl", hash = "sha256:aa7f313fb887c91f15474c1229907a04dac0b8135822d6603437803424c0aa59"}, + {file = "amqp-2.6.1.tar.gz", hash = "sha256:70cdb10628468ff14e57ec2f751c7aa9e48e7e3651cfd62d431213c0c4e58f21"}, ] [package.dependencies] -vine = ">=5.0.0,<6.0.0" +vine = ">=1.1.3,<5.0.0a1" [[package]] name = "annotated-types" @@ -180,44 +180,41 @@ files = [ {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, ] -[package.dependencies] -tzdata = {version = "*", optional = true, markers = "extra == \"tzdata\""} - [package.extras] tzdata = ["tzdata"] [[package]] name = "billiard" -version = "4.2.2" +version = "3.6.4.0" description = "Python multiprocessing fork with improvements and bugfixes" optional = false -python-versions = ">=3.7" +python-versions = "*" groups = ["main"] files = [ - {file = "billiard-4.2.2-py3-none-any.whl", hash = "sha256:4bc05dcf0d1cc6addef470723aac2a6232f3c7ed7475b0b580473a9145829457"}, - {file = "billiard-4.2.2.tar.gz", hash = "sha256:e815017a062b714958463e07ba15981d802dc53d41c5b69d28c5a7c238f8ecf3"}, + {file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"}, + {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, ] [[package]] name = "bk-plugin-runtime" -version = "2.1.2" +version = "2.1.3rc1" description = "bk plugin python django runtime" optional = false python-versions = "<4.0.0,>=3.8.0" groups = ["main"] files = [ - {file = "bk_plugin_runtime-2.1.2-py3-none-any.whl", hash = "sha256:dd7b195baa8e3868902803dcca07638c6d855ca14f711c2627e2e7c3572df6b8"}, - {file = "bk_plugin_runtime-2.1.2.tar.gz", hash = "sha256:206297d4f45787703fcf77408408fbc2c80be0ad67f0bda3dd5d2399a0f1eb67"}, + {file = "bk_plugin_runtime-2.1.3rc1-py3-none-any.whl", hash = "sha256:7a8e5a54d8edb03f6e45ea953939d483cd515251491ef3004437c61e18a3a701"}, + {file = "bk_plugin_runtime-2.1.3rc1.tar.gz", hash = "sha256:ecd821bd570dda80f0a7686d43cc44759b57e79aa87d44c6cfb54aa1749663c1"}, ] [package.dependencies] blueapps = {version = ">=4.15.1,<5.0", extras = ["opentelemetry"]} -celery = ">=5.4.0,<6.0.0" +celery = ">=4.4.0,<5.0.0" ddtrace = ">=0.14.1,<0.15.0" Django = ">=2.2.6,<5" -django-celery-beat = ">=2.7.0,<3.0.0" -django-celery-results = ">=2.5.1,<3.0.0" -django-cors-headers = ">=4.0.0,<5.0.0" +django-celery-beat = ">=2.2.0,<3.0.0" +django-celery-results = ">=1.2.1,<2.0.0" +django-cors-headers = ">=3.8.0,<4.0.0" django-dbconn-retry = ">=0.1.5,<0.2.0" djangorestframework = ">=3.15,<4.0" drf-yasg = ">=1.21.5,<2.0.0" @@ -352,61 +349,55 @@ opentelemetry = ["django-prometheus (>=2.1.0,<3.0.0)", "opentelemetry-api (>=1.6 [[package]] name = "celery" -version = "5.5.3" +version = "4.4.7" description = "Distributed Task Queue." optional = false -python-versions = ">=3.8" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" groups = ["main"] files = [ - {file = "celery-5.5.3-py3-none-any.whl", hash = "sha256:0b5761a07057acee94694464ca482416b959568904c9dfa41ce8413a7d65d525"}, - {file = "celery-5.5.3.tar.gz", hash = "sha256:6c972ae7968c2b5281227f01c3a3f984037d21c5129d07bf3550cc2afc6b10a5"}, + {file = "celery-4.4.7-py2.py3-none-any.whl", hash = "sha256:a92e1d56e650781fb747032a3997d16236d037c8199eacd5217d1a72893bca45"}, + {file = "celery-4.4.7.tar.gz", hash = "sha256:d220b13a8ed57c78149acf82c006785356071844afe0b27012a4991d44026f9f"}, ] [package.dependencies] -"backports.zoneinfo" = {version = ">=0.2.1", extras = ["tzdata"], markers = "python_version < \"3.9\""} -billiard = ">=4.2.1,<5.0" -click = ">=8.1.2,<9.0" -click-didyoumean = ">=0.3.0" -click-plugins = ">=1.1.1" -click-repl = ">=0.2.0" -kombu = ">=5.5.2,<5.6" -python-dateutil = ">=2.8.2" -vine = ">=5.1.0,<6.0" +billiard = ">=3.6.3.0,<4.0" +kombu = ">=4.6.10,<4.7" +pytz = ">0.0-dev" +vine = "1.3.0" [package.extras] -arangodb = ["pyArango (>=2.0.2)"] -auth = ["cryptography (==44.0.2)"] -azureblockblob = ["azure-identity (>=1.19.0)", "azure-storage-blob (>=12.15.0)"] +arangodb = ["pyArango (>=1.3.2)"] +auth = ["cryptography"] +azureblockblob = ["azure-common (==1.1.5)", "azure-storage (==0.36.0)", "azure-storage-common (==1.1.0)"] brotli = ["brotli (>=1.0.0) ; platform_python_implementation == \"CPython\"", "brotlipy (>=0.7.0) ; platform_python_implementation == \"PyPy\""] -cassandra = ["cassandra-driver (>=3.25.0,<4)"] -consul = ["python-consul2 (==0.1.5)"] -cosmosdbsql = ["pydocumentdb (==2.3.5)"] -couchbase = ["couchbase (>=3.0.0) ; platform_python_implementation != \"PyPy\" and (platform_system != \"Windows\" or python_version < \"3.10\")"] -couchdb = ["pycouchdb (==1.16.0)"] -django = ["Django (>=2.2.28)"] -dynamodb = ["boto3 (>=1.26.143)"] -elasticsearch = ["elastic-transport (<=8.17.1)", "elasticsearch (<=8.17.2)"] -eventlet = ["eventlet (>=0.32.0) ; python_version < \"3.10\""] -gcs = ["google-cloud-firestore (==2.20.1)", "google-cloud-storage (>=2.10.0)", "grpcio (==1.67.0)"] -gevent = ["gevent (>=1.5.0)"] -librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] -memcache = ["pylibmc (==1.6.3) ; platform_system != \"Windows\""] -mongodb = ["kombu[mongodb]"] -msgpack = ["kombu[msgpack]"] -pydantic = ["pydantic (>=2.4)"] -pymemcache = ["python-memcached (>=1.61)"] -pyro = ["pyro4 (==4.82) ; python_version < \"3.11\""] -pytest = ["pytest-celery[all] (>=1.2.0,<1.3.0)"] -redis = ["kombu[redis]"] -s3 = ["boto3 (>=1.26.143)"] -slmq = ["softlayer_messaging (>=1.0.3)"] -solar = ["ephem (==4.2) ; platform_python_implementation != \"PyPy\""] -sqlalchemy = ["kombu[sqlalchemy]"] -sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.5.0)", "urllib3 (>=1.26.16)"] +cassandra = ["cassandra-driver (<3.21.0)"] +consul = ["python-consul"] +cosmosdbsql = ["pydocumentdb (==2.3.2)"] +couchbase = ["couchbase (<3.0.0) ; platform_system != \"Windows\"", "couchbase-cffi (<3.0.0) ; platform_python_implementation == \"PyPy\""] +couchdb = ["pycouchdb"] +django = ["Django (>=1.11)"] +dynamodb = ["boto3 (>=1.9.178)"] +elasticsearch = ["elasticsearch"] +eventlet = ["eventlet (>=0.24.1)"] +gevent = ["gevent"] +librabbitmq = ["librabbitmq (>=1.5.0)"] +lzma = ["backports.lzma ; python_version < \"3.3\""] +memcache = ["pylibmc ; platform_system != \"Windows\""] +mongodb = ["pymongo[srv] (>=3.3.0)"] +msgpack = ["msgpack"] +pymemcache = ["python-memcached"] +pyro = ["pyro4"] +redis = ["redis (>=3.2.0)"] +riak = ["riak (>=2.0)"] +s3 = ["boto3 (>=1.9.125)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +solar = ["ephem"] +sqlalchemy = ["sqlalchemy"] +sqs = ["boto3 (>=1.9.125)", "pycurl (==7.43.0.5)"] tblib = ["tblib (>=1.3.0) ; python_version < \"3.8.0\"", "tblib (>=1.5.0) ; python_version >= \"3.8.0\""] -yaml = ["kombu[yaml]"] +yaml = ["PyYAML (>=3.10)"] zookeeper = ["kazoo (>=1.3.1)"] -zstd = ["zstandard (==0.23.0)"] +zstd = ["zstandard"] [[package]] name = "certifi" @@ -694,7 +685,7 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] +groups = ["dev"] markers = "python_version < \"3.13\"" files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, @@ -710,7 +701,7 @@ version = "8.3.0" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.10" -groups = ["main", "dev"] +groups = ["dev"] markers = "python_version >= \"3.13\"" files = [ {file = "click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc"}, @@ -720,70 +711,18 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -[[package]] -name = "click-didyoumean" -version = "0.3.1" -description = "Enables git-like *did-you-mean* feature in click" -optional = false -python-versions = ">=3.6.2" -groups = ["main"] -files = [ - {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, - {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, -] - -[package.dependencies] -click = ">=7" - -[[package]] -name = "click-plugins" -version = "1.1.1.2" -description = "An extension module for click to enable registering CLI commands via setuptools entry-points." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6"}, - {file = "click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261"}, -] - -[package.dependencies] -click = ">=4.0" - -[package.extras] -dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] - -[[package]] -name = "click-repl" -version = "0.3.0" -description = "REPL plugin for Click" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, - {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, -] - -[package.dependencies] -click = ">=7.0" -prompt-toolkit = ">=3.0.36" - -[package.extras] -testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] - [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] +groups = ["dev"] +markers = "sys_platform == \"win32\" or platform_system == \"Windows\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {main = "platform_system == \"Windows\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\""} [[package]] name = "coverage" @@ -848,42 +787,6 @@ files = [ [package.extras] toml = ["tomli ; python_full_version <= \"3.11.0a6\""] -[[package]] -name = "cron-descriptor" -version = "1.4.5" -description = "A Python library that converts cron expressions into human readable strings." -optional = false -python-versions = "*" -groups = ["main"] -markers = "python_full_version == \"3.8.*\" or platform_python_implementation == \"PyPy\" and python_version < \"3.13\"" -files = [ - {file = "cron_descriptor-1.4.5-py3-none-any.whl", hash = "sha256:736b3ae9d1a99bc3dbfc5b55b5e6e7c12031e7ba5de716625772f8b02dcd6013"}, - {file = "cron_descriptor-1.4.5.tar.gz", hash = "sha256:f51ce4ffc1d1f2816939add8524f206c376a42c87a5fca3091ce26725b3b1bca"}, -] - -[package.extras] -dev = ["polib"] - -[[package]] -name = "cron-descriptor" -version = "2.0.6" -description = "A Python library that converts cron expressions into human readable strings." -optional = false -python-versions = ">=3.9" -groups = ["main"] -markers = "python_version >= \"3.9\" and platform_python_implementation != \"PyPy\" or python_version >= \"3.13\"" -files = [ - {file = "cron_descriptor-2.0.6-py3-none-any.whl", hash = "sha256:3a1c0d837c0e5a32e415f821b36cf758eb92d510e6beff8fbfe4fa16573d93d6"}, - {file = "cron_descriptor-2.0.6.tar.gz", hash = "sha256:e39d2848e1d8913cfb6e3452e701b5eec662ee18bea8cc5aa53ee1a7bb217157"}, -] - -[package.dependencies] -typing_extensions = "*" - -[package.extras] -dev = ["mypy", "polib", "ruff"] -test = ["pytest"] - [[package]] name = "cryptography" version = "43.0.3" @@ -1071,21 +974,20 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version [[package]] name = "django" -version = "4.2.24" -description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +version = "3.2.25" +description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" groups = ["main"] files = [ - {file = "django-4.2.24-py3-none-any.whl", hash = "sha256:a6527112c58821a0dfc5ab73013f0bdd906539790a17196658e36e66af43c350"}, - {file = "django-4.2.24.tar.gz", hash = "sha256:40cd7d3f53bc6cd1902eadce23c337e97200888df41e4a73b42d682f23e71d80"}, + {file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"}, + {file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"}, ] [package.dependencies] -asgiref = ">=3.6.0,<4" -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -sqlparse = ">=0.3.1" -tzdata = {version = "*", markers = "sys_platform == \"win32\""} +asgiref = ">=3.3.2,<4" +pytz = "*" +sqlparse = ">=0.2.2" [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] @@ -1093,74 +995,51 @@ bcrypt = ["bcrypt"] [[package]] name = "django-celery-beat" -version = "2.8.1" +version = "2.2.0" description = "Database-backed Periodic Tasks." optional = false -python-versions = ">=3.8" +python-versions = "*" groups = ["main"] files = [ - {file = "django_celery_beat-2.8.1-py3-none-any.whl", hash = "sha256:da2b1c6939495c05a551717509d6e3b79444e114a027f7b77bf3727c2a39d171"}, - {file = "django_celery_beat-2.8.1.tar.gz", hash = "sha256:dfad0201c0ac50c91a34700ef8fa0a10ee098cc7f3375fe5debed79f2204f80a"}, + {file = "django-celery-beat-2.2.0.tar.gz", hash = "sha256:b8a13afb15e7c53fc04f4f847ac71a6d32088959aba701eb7c4a59f0c28ba543"}, + {file = "django_celery_beat-2.2.0-py2.py3-none-any.whl", hash = "sha256:c4c72a9579f20eff4c4ccf1b58ebdca5ef940f4210065057db1754ea5f8dffdc"}, ] [package.dependencies] -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -celery = ">=5.2.3,<6.0" -cron-descriptor = ">=1.2.32" -Django = ">=2.2,<6.0" -django-timezone-field = ">=5.0" +celery = ">=4.4,<6.0" +Django = ">=2.2,<4.0" +django-timezone-field = ">=4.1.0,<5.0" python-crontab = ">=2.3.4" -tzdata = "*" [[package]] name = "django-celery-results" -version = "2.6.0" +version = "1.2.1" description = "Celery result backends for Django." optional = false python-versions = "*" groups = ["main"] files = [ - {file = "django_celery_results-2.6.0-py3-none-any.whl", hash = "sha256:b9ccdca2695b98c7cbbb8dea742311ba9a92773d71d7b4944a676e69a7df1c73"}, - {file = "django_celery_results-2.6.0.tar.gz", hash = "sha256:9abcd836ae6b61063779244d8887a88fe80bbfaba143df36d3cb07034671277c"}, -] - -[package.dependencies] -celery = ">=5.2.7,<6.0" -Django = ">=3.2.25" - -[[package]] -name = "django-cors-headers" -version = "4.4.0" -description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." -optional = false -python-versions = ">=3.8" -groups = ["main"] -markers = "python_full_version == \"3.8.*\" or platform_python_implementation == \"PyPy\" and python_version < \"3.13\"" -files = [ - {file = "django_cors_headers-4.4.0-py3-none-any.whl", hash = "sha256:5c6e3b7fe870876a1efdfeb4f433782c3524078fa0dc9e0195f6706ce7a242f6"}, - {file = "django_cors_headers-4.4.0.tar.gz", hash = "sha256:92cf4633e22af67a230a1456cb1b7a02bb213d6536d2dcb2a4a24092ea9cebc2"}, + {file = "django_celery_results-1.2.1-py2.py3-none-any.whl", hash = "sha256:a29ab580f0e38c66c39f51cc426bbdbb2a391b8cc0867df9dea748db2c961db2"}, + {file = "django_celery_results-1.2.1.tar.gz", hash = "sha256:e390f70cc43bbc2cd7c8e4607dc29ab6211a2ab968f93677583f0160921f670c"}, ] [package.dependencies] -asgiref = ">=3.6" -django = ">=3.2" +celery = ">=4.4,<5.0" [[package]] name = "django-cors-headers" -version = "4.9.0" +version = "3.14.0" description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." optional = false -python-versions = ">=3.9" +python-versions = ">=3.7" groups = ["main"] -markers = "python_version >= \"3.9\" and platform_python_implementation != \"PyPy\" or python_version >= \"3.13\"" files = [ - {file = "django_cors_headers-4.9.0-py3-none-any.whl", hash = "sha256:15c7f20727f90044dcee2216a9fd7303741a864865f0c3657e28b7056f61b449"}, - {file = "django_cors_headers-4.9.0.tar.gz", hash = "sha256:fe5d7cb59fdc2c8c646ce84b727ac2bca8912a247e6e68e1fb507372178e59e8"}, + {file = "django_cors_headers-3.14.0-py3-none-any.whl", hash = "sha256:684180013cc7277bdd8702b80a3c5a4b3fcae4abb2bf134dceb9f5dfe300228e"}, + {file = "django_cors_headers-3.14.0.tar.gz", hash = "sha256:5fbd58a6fb4119d975754b2bc090f35ec160a8373f276612c675b00e8a138739"}, ] [package.dependencies] -asgiref = ">=3.6" -django = ">=4.2" +Django = ">=3.2" [[package]] name = "django-dbconn-retry" @@ -1175,68 +1054,78 @@ files = [ [[package]] name = "django-prometheus" -version = "2.4.1" +version = "2.4.0" description = "Django middlewares to monitor your application with Prometheus.io." optional = false python-versions = "*" groups = ["main"] files = [ - {file = "django_prometheus-2.4.1-py2.py3-none-any.whl", hash = "sha256:7fe5af7f7c9ad9cd8a429fe0f3f1bf651f0e244f77162147869eab7ec09cc5e7"}, - {file = "django_prometheus-2.4.1.tar.gz", hash = "sha256:073628243d2a6de6a8a8c20e5b512872dfb85d66e1b60b28bcf1eca0155dad95"}, + {file = "django_prometheus-2.4.0-py2.py3-none-any.whl", hash = "sha256:5b46b5f07b02ba8dd7abdb03a3c39073e8fd9120e2293a1ecb949bbb865378ac"}, + {file = "django_prometheus-2.4.0.tar.gz", hash = "sha256:67da5c73d8e859aa73f6e11f52341c482691b17f8bd9844157cff6cdf51ce9bc"}, ] [package.dependencies] -Django = ">=4.2,<6.0" prometheus-client = ">=0.7" [[package]] name = "django-timezone-field" -version = "7.1" -description = "A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects." +version = "4.2.3" +description = "A Django app providing database and form fields for pytz timezone objects." optional = false -python-versions = "<4.0,>=3.8" +python-versions = ">=3.5" groups = ["main"] files = [ - {file = "django_timezone_field-7.1-py3-none-any.whl", hash = "sha256:93914713ed882f5bccda080eda388f7006349f25930b6122e9b07bf8db49c4b4"}, - {file = "django_timezone_field-7.1.tar.gz", hash = "sha256:b3ef409d88a2718b566fabe10ea996f2838bc72b22d3a2900c0aa905c761380c"}, + {file = "django-timezone-field-4.2.3.tar.gz", hash = "sha256:5dd5bd9249382bef8847d3e7e4c32b7be182a4b538f354130d1252ed228892f8"}, + {file = "django_timezone_field-4.2.3-py3-none-any.whl", hash = "sha256:7552d2b0f145684b7de3fb5046101c7efd600cc6ba951b15c630fa1e1b83558e"}, ] [package.dependencies] -"backports.zoneinfo" = {version = ">=0.2.1,<0.3.0", markers = "python_version < \"3.9\""} -Django = ">=3.2,<6.0" +django = ">=2.2" +pytz = "*" + +[package.extras] +rest-framework = ["djangorestframework (>=3.0.0)"] [[package]] name = "djangorestframework" -version = "3.15.2" +version = "3.15.1" description = "Web APIs for Django, made easy." optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" groups = ["main"] -markers = "python_full_version == \"3.8.*\" or platform_python_implementation == \"PyPy\" and python_version < \"3.13\"" files = [ - {file = "djangorestframework-3.15.2-py3-none-any.whl", hash = "sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20"}, - {file = "djangorestframework-3.15.2.tar.gz", hash = "sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad"}, + {file = "djangorestframework-3.15.1-py3-none-any.whl", hash = "sha256:3ccc0475bce968608cf30d07fb17d8e52d1d7fc8bfe779c905463200750cbca6"}, + {file = "djangorestframework-3.15.1.tar.gz", hash = "sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1"}, ] [package.dependencies] "backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -django = ">=4.2" +django = ">=3.0" [[package]] -name = "djangorestframework" -version = "3.16.1" -description = "Web APIs for Django, made easy." +name = "drf-spectacular" +version = "0.29.0" +description = "Sane and flexible OpenAPI 3 schema generation for Django REST framework" optional = false -python-versions = ">=3.9" +python-versions = ">=3.7" groups = ["main"] -markers = "python_version >= \"3.9\" and platform_python_implementation != \"PyPy\" or python_version >= \"3.13\"" files = [ - {file = "djangorestframework-3.16.1-py3-none-any.whl", hash = "sha256:33a59f47fb9c85ede792cbf88bde71893bcda0667bc573f784649521f1102cec"}, - {file = "djangorestframework-3.16.1.tar.gz", hash = "sha256:166809528b1aced0a17dc66c24492af18049f2c9420dbd0be29422029cfc3ff7"}, + {file = "drf_spectacular-0.29.0-py3-none-any.whl", hash = "sha256:d1ee7c9535d89848affb4427347f7c4a22c5d22530b8842ef133d7b72e19b41a"}, + {file = "drf_spectacular-0.29.0.tar.gz", hash = "sha256:0a069339ea390ce7f14a75e8b5af4a0860a46e833fd4af027411a3e94fc1a0cc"}, ] [package.dependencies] -django = ">=4.2" +Django = ">=2.2" +djangorestframework = ">=3.10.3" +inflection = ">=0.3.1" +jsonschema = ">=2.6.0" +PyYAML = ">=5.1" +typing-extensions = {version = "*", markers = "python_version < \"3.10\""} +uritemplate = ">=2.0.0" + +[package.extras] +offline = ["drf-spectacular-sidecar"] +sidecar = ["drf-spectacular-sidecar"] [[package]] name = "drf-yasg" @@ -1687,40 +1576,34 @@ referencing = ">=0.31.0" [[package]] name = "kombu" -version = "5.5.4" +version = "4.6.11" description = "Messaging library for Python." optional = false -python-versions = ">=3.8" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" groups = ["main"] files = [ - {file = "kombu-5.5.4-py3-none-any.whl", hash = "sha256:a12ed0557c238897d8e518f1d1fdf84bd1516c5e305af2dacd85c2015115feb8"}, - {file = "kombu-5.5.4.tar.gz", hash = "sha256:886600168275ebeada93b888e831352fe578168342f0d1d5833d88ba0d847363"}, + {file = "kombu-4.6.11-py2.py3-none-any.whl", hash = "sha256:be48cdffb54a2194d93ad6533d73f69408486483d189fe9f5990ee24255b0e0a"}, + {file = "kombu-4.6.11.tar.gz", hash = "sha256:ca1b45faac8c0b18493d02a8571792f3c40291cf2bcf1f55afed3d8f3aa7ba74"}, ] [package.dependencies] -amqp = ">=5.1.1,<6.0.0" -"backports.zoneinfo" = {version = ">=0.2.1", extras = ["tzdata"], markers = "python_version < \"3.9\""} -packaging = "*" -tzdata = {version = ">=2025.2", markers = "python_version >= \"3.9\""} -vine = "5.1.0" +amqp = ">=2.6.0,<2.7" [package.extras] -azureservicebus = ["azure-servicebus (>=7.10.0)"] -azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] -confluentkafka = ["confluent-kafka (>=2.2.0)"] -consul = ["python-consul2 (==0.1.5)"] -gcpubsub = ["google-cloud-monitoring (>=2.16.0)", "google-cloud-pubsub (>=2.18.4)", "grpcio (==1.67.0)", "protobuf (==4.25.5)"] -librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] -mongodb = ["pymongo (==4.10.1)"] -msgpack = ["msgpack (==1.1.0)"] -pyro = ["pyro4 (==4.82)"] +azureservicebus = ["azure-servicebus (>=0.21.1)"] +azurestoragequeues = ["azure-storage-queue"] +consul = ["python-consul (>=0.6.0)"] +librabbitmq = ["librabbitmq (>=1.5.2)"] +mongodb = ["pymongo (>=3.3.0)"] +msgpack = ["msgpack"] +pyro = ["pyro4"] qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] -redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<=5.2.1)"] -slmq = ["softlayer_messaging (>=1.0.3)"] -sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] -sqs = ["boto3 (>=1.26.143)", "urllib3 (>=1.26.16)"] +redis = ["redis (>=3.3.11)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy"] +sqs = ["boto3 (>=1.4.4)", "pycurl (==7.43.0.2)"] yaml = ["PyYAML (>=3.10)"] -zookeeper = ["kazoo (>=2.8.0)"] +zookeeper = ["kazoo (>=1.3.1)"] [[package]] name = "mako" @@ -2619,21 +2502,6 @@ files = [ [package.extras] twisted = ["twisted"] -[[package]] -name = "prompt-toolkit" -version = "3.0.52" -description = "Library for building powerful interactive command lines in Python" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, - {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, -] - -[package.dependencies] -wcwidth = "*" - [[package]] name = "protobuf" version = "4.25.8" @@ -3126,21 +2994,6 @@ files = [ cron-description = ["cron-descriptor"] cron-schedule = ["croniter"] -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main"] -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - [[package]] name = "python-json-logger" version = "3.3.0" @@ -4098,18 +3951,6 @@ files = [ [package.dependencies] typing-extensions = ">=4.12.0" -[[package]] -name = "tzdata" -version = "2025.2" -description = "Provider of IANA time zone data" -optional = false -python-versions = ">=2" -groups = ["main"] -files = [ - {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, - {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, -] - [[package]] name = "uritemplate" version = "4.1.1" @@ -4176,26 +4017,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "vine" -version = "5.1.0" -description = "Python promises." -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, - {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, -] - -[[package]] -name = "wcwidth" -version = "0.2.14" -description = "Measures the displayed width of unicode strings in a terminal" +version = "1.3.0" +description = "Promises, promises, promises." optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" groups = ["main"] files = [ - {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, - {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, + {file = "vine-1.3.0-py2.py3-none-any.whl", hash = "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"}, + {file = "vine-1.3.0.tar.gz", hash = "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87"}, ] [[package]] @@ -4404,4 +4233,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.8.0,<4.0" -content-hash = "1164524473a272e2ef48520906ad465781ddae26f408c996b9596ff5b11c77fb" +content-hash = "acebc7ab36d1531c1dfc81c0b5380c5b34e714970cf06ddc8f8131136cd1120b" diff --git a/bk-plugin-framework/pyproject.toml b/bk-plugin-framework/pyproject.toml index 0745c8a..534987f 100644 --- a/bk-plugin-framework/pyproject.toml +++ b/bk-plugin-framework/pyproject.toml @@ -12,6 +12,7 @@ werkzeug = ">=2.0.0, <4.0" apigw-manager = {version = ">=1.0.6, <4", extras = ["extra"]} bk-plugin-runtime = "2.1.3rc1" jsonschema = ">=2.5.0,<5.0.0" +drf-spectacular = "^0.29.0" [tool.poetry.dev-dependencies] pytest = "^7.0.0" From 2fa87ae4a13f647cb44501b61a2824cc2303c17d Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 16:07:13 +0800 Subject: [PATCH 05/21] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9bk-plugin-framew?= =?UTF-8?q?ork=20=E7=9A=84=20tag=20=E7=89=88=E6=9C=AC=20--story=3D13002940?= =?UTF-8?q?1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bk-plugin-framework/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bk-plugin-framework/pyproject.toml b/bk-plugin-framework/pyproject.toml index 534987f..4b5e8b8 100644 --- a/bk-plugin-framework/pyproject.toml +++ b/bk-plugin-framework/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-framework" -version = "2.3.4rc1" +version = "2.3.4rc2" description = "bk plugin python framework" authors = ["Your Name "] license = "MIT" From f562014bd9b5e726770f314c3d41abc492058928 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 16:45:37 +0800 Subject: [PATCH 06/21] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4django-environ?= =?UTF-8?q?=20=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bk_plugin_runtime/config/default.py | 81 ++++++++++++++++--- .../app_desc.yml | 3 + 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py index 9fb36b8..cde5649 100644 --- a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py +++ b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py @@ -12,24 +12,29 @@ import json import os import urllib +from urllib.parse import urlparse + from blueapps.conf.default_settings import * # noqa from blueapps.conf.log import get_logging_config_dict + BKPAAS_ENVIRONMENT = os.getenv("BKPAAS_ENVIRONMENT", "dev") -# 默认关闭可观侧性 +# 默认关闭可观测性 ENABLE_OTEL_METRICS = os.getenv("ENABLE_METRICS", False) # 请在这里加入你的自定义 APP INSTALLED_APPS += ( # noqa - "rest_framework", - "drf_yasg", + "bk_plugin_framework.runtime.loghub", "bk_plugin_framework.runtime.schedule", "bk_plugin_framework.runtime.callback", "bk_plugin_framework.services.bpf_service", - "apigw_manager.apigw", + "rest_framework", + "drf_spectacular", "django_dbconn_retry", + "apigw_manager.drf", + "apigw_manager.apigw", ) if ENABLE_OTEL_METRICS: INSTALLED_APPS += ("blueapps.opentelemetry.instrument_app",) # noqa @@ -37,8 +42,12 @@ if BKPAAS_ENVIRONMENT == "dev": INSTALLED_APPS += ("bk_plugin_framework.services.debug_panel",) # noqa -from bk_plugin_framework.runtime.callback.celery import queues as callback_queues # noqa -from bk_plugin_framework.runtime.schedule.celery import queues as schedule_queues # noqa +from bk_plugin_framework.runtime.callback.celery import ( # noqa + queues as callback_queues, +) +from bk_plugin_framework.runtime.schedule.celery import ( # noqa + queues as schedule_queues, +) CELERY_QUEUES = schedule_queues.CELERY_QUEUES CELERY_QUEUES.extend(callback_queues.CELERY_QUEUES) @@ -75,8 +84,6 @@ "apigw_manager.apigw.authentication.ApiGatewayJWTUserMiddleware", # JWT 透传的用户信息 ) -# 用户认证 -AUTHENTICATION_BACKENDS += ("bk_plugin_runtime.packages.apigw.backends.APIGWUserModelBackend",) # noqa # 所有环境的日志级别可以在这里配置 # LOG_LEVEL = 'INFO' @@ -170,9 +177,8 @@ ROOT_URLCONF = "bk_plugin_runtime.urls" -from blueapps.core.celery import celery_app # noqa - from bk_plugin_framework.runtime.schedule.celery.beat import SCHEDULE # noqa +from blueapps.core.celery import celery_app # noqa celery_app.conf.beat_schedule = SCHEDULE @@ -217,7 +223,60 @@ def logging_addition_settings(logging_dict): {"format": logging_dict["formatters"]["verbose"][kw].strip() + " [trace_id]: %(trace_id)s"} ) break - +# drf settings +REST_FRAMEWORK = { + "DEFAULT_AUTHENTICATION_CLASSES": [ + "apigw_manager.drf.authentication.ApiGatewayJWTAuthentication", + ], + "DEFAULT_PERMISSION_CLASSES": [ + "apigw_manager.drf.permission.ApiGatewayPermission", + ], + "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", +} + + +# 网关是否公开,公开则其他开发者可见/可申请权限 +BK_APIGW_IS_PUBLIC = os.getenv("BK_APIGW_IS_PUBLIC", "true").lower() +# if BK_APIGW_IS_OFFICIAL is True, the BK_APIGW_NAME should be start with `bk-` +BK_APIGW_IS_OFFICIAL = 1 if os.getenv("BK_APIGW_IS_OFFICIAL", "false").lower() == "true" else 10 +# 网关管理员,请将负责人加入列表中 +BK_APIGW_MAINTAINERS = [m.strip() for m in os.getenv("BK_APIGW_MAINTAINERS", "admin").split(",") if m.strip()] +# 网关接口最大超时时间 +BK_APIGW_STAG_BACKEND_TIMEOUT = 60 + + +# analysis the app environment and address via bkpaas env vars +bkpaas_default_preallocated_urls = json.loads(os.getenv("BKPAAS_DEFAULT_PREALLOCATED_URLS", "{}")) +bkpaas_environment = os.getenv("BKPAAS_ENVIRONMENT", "dev") +app_address = bkpaas_default_preallocated_urls.get(bkpaas_environment) +parsed_url = urlparse(app_address) +app_scheme = parsed_url.scheme +app_domain = parsed_url.netloc +app_subpath = parsed_url.path.rstrip("/") + +BK_APIGW_STAGE_BACKEND_HOST = f"{app_scheme}://{app_domain}" +BK_APIGW_STAGE_BACKEND_SUBPATH = app_subpath + + + +# while deploy app on staging env, it would sync to the stage=stag of the gateway +# while deploy app on production env, it would sync to the stage=prod of the gateway +BK_APIGW_STAGE_NAME = bkpaas_environment +BK_APIGW_STAGE_DESCRIPTION = "生产环境" if bkpaas_environment == "prod" else "预发布环境" +BK_APIGW_STAGE_DESCRIPTION_EN = "Production Env" if bkpaas_environment == "prod" else "Staging Env" +# 声明网关不同环境的环境变量 +stag_env_vars = { + "foo": "bar" +} +prod_env_vars = { + # "foo": "bar" +} +BK_APIGW_STAGE_ENV_VARS = prod_env_vars if bkpaas_environment == "prod" else stag_env_vars + +# 网关同步 API 文档语言, zh/en, 如果配置了BK_APIGW_RESOURCE_DOCS_BASE_DIR(使用自定义文档), 那么必须将这个变量置空 +BK_APIGW_RELEASE_DOC_LANGUAGE = os.getenv("BK_APIGW_RELEASE_DOC_LANGUAGE", "") +# 在项目 docs目录下,通过 markdown文档自动化导入中英文文档; 注意markdown文件名必须等于接口的 operation_id; 见 demo 示例 +# BK_APIGW_RESOURCE_DOCS_BASE_DIR = env.str("BK_APIGW_RESOURCE_DOCS_BASE_DIR", default=BASE_DIR / "docs") # BK SOPS RELATE BK_SOPS_APP_CODE = os.getenv("BK_SOPS_APP_CODE") diff --git a/template/{{cookiecutter.project_name}}/app_desc.yml b/template/{{cookiecutter.project_name}}/app_desc.yml index cb71b87..d433cb4 100644 --- a/template/{{cookiecutter.project_name}}/app_desc.yml +++ b/template/{{cookiecutter.project_name}}/app_desc.yml @@ -4,6 +4,9 @@ modules: isDefault: true language: python spec: + hooks: + preRelease: + procCommand: "bash bin/sync_apigateway.sh" processes: - name: web procCommand: gunicorn bk_plugin_runtime.wsgi --timeout 120 -k gthread --threads 16 -w 8 --max-requests=1000 --env prometheus_multiproc_dir=/tmp/ From 921a12b621141e04d239affc7d043e8fae1fd644 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 16:49:07 +0800 Subject: [PATCH 07/21] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=20runtime=20?= =?UTF-8?q?=E7=9A=84pyproject.toml=E6=96=87=E4=BB=B6=20--story=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- runtime/bk-plugin-runtime/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/bk-plugin-runtime/pyproject.toml b/runtime/bk-plugin-runtime/pyproject.toml index ff7ff98..84b00cd 100644 --- a/runtime/bk-plugin-runtime/pyproject.toml +++ b/runtime/bk-plugin-runtime/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-runtime" -version = "2.1.3rc1" +version = "2.1.3rc2" description = "bk plugin python django runtime" authors = ["Your Name "] license = "MIT" From 0fda61dfe701d175335dfaa691030c78987f4c5a Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 17:05:23 +0800 Subject: [PATCH 08/21] minor: framework release 2.3.4rc3 --- bk-plugin-framework/poetry.lock | 8 ++++---- bk-plugin-framework/pyproject.toml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bk-plugin-framework/poetry.lock b/bk-plugin-framework/poetry.lock index a879289..e3b4aae 100644 --- a/bk-plugin-framework/poetry.lock +++ b/bk-plugin-framework/poetry.lock @@ -197,14 +197,14 @@ files = [ [[package]] name = "bk-plugin-runtime" -version = "2.1.3rc1" +version = "2.1.3rc2" description = "bk plugin python django runtime" optional = false python-versions = "<4.0.0,>=3.8.0" groups = ["main"] files = [ - {file = "bk_plugin_runtime-2.1.3rc1-py3-none-any.whl", hash = "sha256:7a8e5a54d8edb03f6e45ea953939d483cd515251491ef3004437c61e18a3a701"}, - {file = "bk_plugin_runtime-2.1.3rc1.tar.gz", hash = "sha256:ecd821bd570dda80f0a7686d43cc44759b57e79aa87d44c6cfb54aa1749663c1"}, + {file = "bk_plugin_runtime-2.1.3rc2-py3-none-any.whl", hash = "sha256:a2c9d68243adac46b551bdde36b9e7fab578f5643496519b80ba0befa48374de"}, + {file = "bk_plugin_runtime-2.1.3rc2.tar.gz", hash = "sha256:812849e720c45122bdb5bcb59323e4f49750045adeeee6e17b6a509141f96df9"}, ] [package.dependencies] @@ -4233,4 +4233,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.8.0,<4.0" -content-hash = "acebc7ab36d1531c1dfc81c0b5380c5b34e714970cf06ddc8f8131136cd1120b" +content-hash = "17900d595ebf72774c30a031d2e2c5736cc5fbd73ccd0c0c5f69f2bfe86a3bfc" diff --git a/bk-plugin-framework/pyproject.toml b/bk-plugin-framework/pyproject.toml index 4b5e8b8..7d07d0f 100644 --- a/bk-plugin-framework/pyproject.toml +++ b/bk-plugin-framework/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-framework" -version = "2.3.4rc2" +version = "2.3.4rc3" description = "bk plugin python framework" authors = ["Your Name "] license = "MIT" @@ -10,7 +10,7 @@ python = "^3.8.0,<4.0" pydantic = ">=1.0,<3" werkzeug = ">=2.0.0, <4.0" apigw-manager = {version = ">=1.0.6, <4", extras = ["extra"]} -bk-plugin-runtime = "2.1.3rc1" +bk-plugin-runtime = "2.1.3rc2" jsonschema = ">=2.5.0,<5.0.0" drf-spectacular = "^0.29.0" From d875aaa7bb3416ca99dd88ba0a66653d9aa4472d Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 18:03:44 +0800 Subject: [PATCH 09/21] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E6=A1=86=E6=9E=B6=E4=B8=AD=E7=9A=84bk-plugin-framewor?= =?UTF-8?q?k=E7=89=88=E6=9C=AC=20--story=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/{{cookiecutter.project_name}}/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/{{cookiecutter.project_name}}/requirements.txt b/template/{{cookiecutter.project_name}}/requirements.txt index 5dd69ee..16c3eb9 100644 --- a/template/{{cookiecutter.project_name}}/requirements.txt +++ b/template/{{cookiecutter.project_name}}/requirements.txt @@ -1,6 +1,6 @@ # base # DO NOT DELETE ANY PACKAGE IN base SECTION !!! -bk-plugin-framework==2.2.9 +bk-plugin-framework==2.3.4rc3 # opentelemetry celery-prometheus-exporter==1.7.0 celery>=4.4.0,<5.0.0 # Explicit celery version constraint to resolve pip 25.x dependency conflict From bbfd28af68dc22af346a13237e76f08ea25eed06 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 18:07:44 +0800 Subject: [PATCH 10/21] =?UTF-8?q?fix:=20pre-commit=20=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F=E8=A7=84=E8=8C=83=20--stor?= =?UTF-8?q?y=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bk_plugin_runtime/config/default.py | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py index cde5649..2dbfcc0 100644 --- a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py +++ b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py @@ -14,18 +14,15 @@ import urllib from urllib.parse import urlparse - from blueapps.conf.default_settings import * # noqa from blueapps.conf.log import get_logging_config_dict - BKPAAS_ENVIRONMENT = os.getenv("BKPAAS_ENVIRONMENT", "dev") # 默认关闭可观测性 ENABLE_OTEL_METRICS = os.getenv("ENABLE_METRICS", False) # 请在这里加入你的自定义 APP INSTALLED_APPS += ( # noqa - "bk_plugin_framework.runtime.loghub", "bk_plugin_framework.runtime.schedule", "bk_plugin_framework.runtime.callback", @@ -42,12 +39,8 @@ if BKPAAS_ENVIRONMENT == "dev": INSTALLED_APPS += ("bk_plugin_framework.services.debug_panel",) # noqa -from bk_plugin_framework.runtime.callback.celery import ( # noqa - queues as callback_queues, -) -from bk_plugin_framework.runtime.schedule.celery import ( # noqa - queues as schedule_queues, -) +from bk_plugin_framework.runtime.callback.celery import queues as callback_queues # noqa +from bk_plugin_framework.runtime.schedule.celery import queues as schedule_queues # noqa CELERY_QUEUES = schedule_queues.CELERY_QUEUES CELERY_QUEUES.extend(callback_queues.CELERY_QUEUES) @@ -177,9 +170,10 @@ ROOT_URLCONF = "bk_plugin_runtime.urls" -from bk_plugin_framework.runtime.schedule.celery.beat import SCHEDULE # noqa from blueapps.core.celery import celery_app # noqa +from bk_plugin_framework.runtime.schedule.celery.beat import SCHEDULE # noqa + celery_app.conf.beat_schedule = SCHEDULE @@ -223,6 +217,8 @@ def logging_addition_settings(logging_dict): {"format": logging_dict["formatters"]["verbose"][kw].strip() + " [trace_id]: %(trace_id)s"} ) break + + # drf settings REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ @@ -258,16 +254,13 @@ def logging_addition_settings(logging_dict): BK_APIGW_STAGE_BACKEND_SUBPATH = app_subpath - # while deploy app on staging env, it would sync to the stage=stag of the gateway # while deploy app on production env, it would sync to the stage=prod of the gateway BK_APIGW_STAGE_NAME = bkpaas_environment BK_APIGW_STAGE_DESCRIPTION = "生产环境" if bkpaas_environment == "prod" else "预发布环境" BK_APIGW_STAGE_DESCRIPTION_EN = "Production Env" if bkpaas_environment == "prod" else "Staging Env" # 声明网关不同环境的环境变量 -stag_env_vars = { - "foo": "bar" -} +stag_env_vars = {"foo": "bar"} prod_env_vars = { # "foo": "bar" } From c8fef64bf38b55e591e12f80112bdf46779efc76 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 21:20:49 +0800 Subject: [PATCH 11/21] minor: runtime release 2.1.3rc3 --- runtime/bk-plugin-runtime/poetry.lock | 541 +++++++++++++++++++---- runtime/bk-plugin-runtime/pyproject.toml | 10 +- 2 files changed, 451 insertions(+), 100 deletions(-) diff --git a/runtime/bk-plugin-runtime/poetry.lock b/runtime/bk-plugin-runtime/poetry.lock index 4d1da90..913196a 100644 --- a/runtime/bk-plugin-runtime/poetry.lock +++ b/runtime/bk-plugin-runtime/poetry.lock @@ -2,18 +2,18 @@ [[package]] name = "amqp" -version = "2.6.1" +version = "5.3.1" description = "Low-level AMQP client for Python (fork of amqplib)." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" groups = ["main"] files = [ - {file = "amqp-2.6.1-py2.py3-none-any.whl", hash = "sha256:aa7f313fb887c91f15474c1229907a04dac0b8135822d6603437803424c0aa59"}, - {file = "amqp-2.6.1.tar.gz", hash = "sha256:70cdb10628468ff14e57ec2f751c7aa9e48e7e3651cfd62d431213c0c4e58f21"}, + {file = "amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2"}, + {file = "amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432"}, ] [package.dependencies] -vine = ">=1.1.3,<5.0.0a1" +vine = ">=5.0.0,<6.0.0" [[package]] name = "asgiref" @@ -73,19 +73,22 @@ files = [ {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, ] +[package.dependencies] +tzdata = {version = "*", optional = true, markers = "extra == \"tzdata\""} + [package.extras] tzdata = ["tzdata"] [[package]] name = "billiard" -version = "3.6.4.0" +version = "4.2.4" description = "Python multiprocessing fork with improvements and bugfixes" optional = false -python-versions = "*" +python-versions = ">=3.7" groups = ["main"] files = [ - {file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"}, - {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, + {file = "billiard-4.2.4-py3-none-any.whl", hash = "sha256:525b42bdec68d2b983347ac312f892db930858495db601b5836ac24e6477cde5"}, + {file = "billiard-4.2.4.tar.gz", hash = "sha256:55f542c371209e03cd5862299b74e52e4fbcba8250ba611ad94276b369b6a85f"}, ] [[package]] @@ -150,55 +153,121 @@ opentelemetry = ["django-prometheus (>=2.1.0,<3.0.0)", "opentelemetry-api (>=1.6 [[package]] name = "celery" -version = "4.4.7" +version = "5.5.3" description = "Distributed Task Queue." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.8" groups = ["main"] +markers = "python_version < \"3.13\"" files = [ - {file = "celery-4.4.7-py2.py3-none-any.whl", hash = "sha256:a92e1d56e650781fb747032a3997d16236d037c8199eacd5217d1a72893bca45"}, - {file = "celery-4.4.7.tar.gz", hash = "sha256:d220b13a8ed57c78149acf82c006785356071844afe0b27012a4991d44026f9f"}, + {file = "celery-5.5.3-py3-none-any.whl", hash = "sha256:0b5761a07057acee94694464ca482416b959568904c9dfa41ce8413a7d65d525"}, + {file = "celery-5.5.3.tar.gz", hash = "sha256:6c972ae7968c2b5281227f01c3a3f984037d21c5129d07bf3550cc2afc6b10a5"}, ] [package.dependencies] -billiard = ">=3.6.3.0,<4.0" -kombu = ">=4.6.10,<4.7" -pytz = ">0.0-dev" -vine = "1.3.0" +"backports.zoneinfo" = {version = ">=0.2.1", extras = ["tzdata"], markers = "python_version < \"3.9\""} +billiard = ">=4.2.1,<5.0" +click = ">=8.1.2,<9.0" +click-didyoumean = ">=0.3.0" +click-plugins = ">=1.1.1" +click-repl = ">=0.2.0" +kombu = ">=5.5.2,<5.6" +python-dateutil = ">=2.8.2" +vine = ">=5.1.0,<6.0" [package.extras] -arangodb = ["pyArango (>=1.3.2)"] -auth = ["cryptography"] -azureblockblob = ["azure-common (==1.1.5)", "azure-storage (==0.36.0)", "azure-storage-common (==1.1.0)"] +arangodb = ["pyArango (>=2.0.2)"] +auth = ["cryptography (==44.0.2)"] +azureblockblob = ["azure-identity (>=1.19.0)", "azure-storage-blob (>=12.15.0)"] brotli = ["brotli (>=1.0.0) ; platform_python_implementation == \"CPython\"", "brotlipy (>=0.7.0) ; platform_python_implementation == \"PyPy\""] -cassandra = ["cassandra-driver (<3.21.0)"] -consul = ["python-consul"] -cosmosdbsql = ["pydocumentdb (==2.3.2)"] -couchbase = ["couchbase (<3.0.0) ; platform_system != \"Windows\"", "couchbase-cffi (<3.0.0) ; platform_python_implementation == \"PyPy\""] -couchdb = ["pycouchdb"] -django = ["Django (>=1.11)"] -dynamodb = ["boto3 (>=1.9.178)"] -elasticsearch = ["elasticsearch"] -eventlet = ["eventlet (>=0.24.1)"] -gevent = ["gevent"] -librabbitmq = ["librabbitmq (>=1.5.0)"] -lzma = ["backports.lzma ; python_version < \"3.3\""] -memcache = ["pylibmc ; platform_system != \"Windows\""] -mongodb = ["pymongo[srv] (>=3.3.0)"] -msgpack = ["msgpack"] -pymemcache = ["python-memcached"] -pyro = ["pyro4"] -redis = ["redis (>=3.2.0)"] -riak = ["riak (>=2.0)"] -s3 = ["boto3 (>=1.9.125)"] -slmq = ["softlayer-messaging (>=1.0.3)"] -solar = ["ephem"] -sqlalchemy = ["sqlalchemy"] -sqs = ["boto3 (>=1.9.125)", "pycurl (==7.43.0.5)"] +cassandra = ["cassandra-driver (>=3.25.0,<4)"] +consul = ["python-consul2 (==0.1.5)"] +cosmosdbsql = ["pydocumentdb (==2.3.5)"] +couchbase = ["couchbase (>=3.0.0) ; platform_python_implementation != \"PyPy\" and (platform_system != \"Windows\" or python_version < \"3.10\")"] +couchdb = ["pycouchdb (==1.16.0)"] +django = ["Django (>=2.2.28)"] +dynamodb = ["boto3 (>=1.26.143)"] +elasticsearch = ["elastic-transport (<=8.17.1)", "elasticsearch (<=8.17.2)"] +eventlet = ["eventlet (>=0.32.0) ; python_version < \"3.10\""] +gcs = ["google-cloud-firestore (==2.20.1)", "google-cloud-storage (>=2.10.0)", "grpcio (==1.67.0)"] +gevent = ["gevent (>=1.5.0)"] +librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] +memcache = ["pylibmc (==1.6.3) ; platform_system != \"Windows\""] +mongodb = ["kombu[mongodb]"] +msgpack = ["kombu[msgpack]"] +pydantic = ["pydantic (>=2.4)"] +pymemcache = ["python-memcached (>=1.61)"] +pyro = ["pyro4 (==4.82) ; python_version < \"3.11\""] +pytest = ["pytest-celery[all] (>=1.2.0,<1.3.0)"] +redis = ["kombu[redis]"] +s3 = ["boto3 (>=1.26.143)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +solar = ["ephem (==4.2) ; platform_python_implementation != \"PyPy\""] +sqlalchemy = ["kombu[sqlalchemy]"] +sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.5.0)", "urllib3 (>=1.26.16)"] tblib = ["tblib (>=1.3.0) ; python_version < \"3.8.0\"", "tblib (>=1.5.0) ; python_version >= \"3.8.0\""] -yaml = ["PyYAML (>=3.10)"] +yaml = ["kombu[yaml]"] +zookeeper = ["kazoo (>=1.3.1)"] +zstd = ["zstandard (==0.23.0)"] + +[[package]] +name = "celery" +version = "5.6.2" +description = "Distributed Task Queue." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.13\"" +files = [ + {file = "celery-5.6.2-py3-none-any.whl", hash = "sha256:3ffafacbe056951b629c7abcf9064c4a2366de0bdfc9fdba421b97ebb68619a5"}, + {file = "celery-5.6.2.tar.gz", hash = "sha256:4a8921c3fcf2ad76317d3b29020772103581ed2454c4c042cc55dcc43585009b"}, +] + +[package.dependencies] +billiard = ">=4.2.1,<5.0" +click = ">=8.1.2,<9.0" +click-didyoumean = ">=0.3.0" +click-plugins = ">=1.1.1" +click-repl = ">=0.2.0" +kombu = ">=5.6.0" +python-dateutil = ">=2.8.2" +tzlocal = "*" +vine = ">=5.1.0,<6.0" + +[package.extras] +arangodb = ["pyArango (>=2.0.2)"] +auth = ["cryptography (==46.0.3)"] +azureblockblob = ["azure-identity (>=1.19.0)", "azure-storage-blob (>=12.15.0)"] +brotli = ["brotli (>=1.0.0) ; platform_python_implementation == \"CPython\"", "brotlipy (>=0.7.0) ; platform_python_implementation == \"PyPy\""] +cassandra = ["cassandra-driver (>=3.25.0,<4)"] +consul = ["python-consul2 (==0.1.5)"] +cosmosdbsql = ["pydocumentdb (==2.3.5)"] +couchbase = ["couchbase (>=3.0.0) ; platform_python_implementation != \"PyPy\" and (platform_system != \"Windows\" or python_version < \"3.10\")"] +couchdb = ["pycouchdb (==1.16.0)"] +django = ["Django (>=2.2.28)"] +dynamodb = ["boto3 (>=1.26.143)"] +elasticsearch = ["elastic-transport (<=9.1.0)", "elasticsearch (<=9.1.2)"] +eventlet = ["eventlet (>=0.32.0) ; python_version < \"3.10\""] +gcs = ["google-cloud-firestore (==2.22.0)", "google-cloud-storage (>=2.10.0)", "grpcio (==1.75.1)"] +gevent = ["gevent (>=1.5.0)"] +librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] +memcache = ["pylibmc (==1.6.3) ; platform_system != \"Windows\""] +mongodb = ["kombu[mongodb]"] +msgpack = ["kombu[msgpack]"] +pydantic = ["pydantic (>=2.12.0a1) ; python_version >= \"3.14\"", "pydantic (>=2.4) ; python_version < \"3.14\""] +pymemcache = ["python-memcached (>=1.61)"] +pyro = ["pyro4 (==4.82) ; python_version < \"3.11\""] +pytest = ["pytest-celery[all] (>=1.2.0,<1.3.0)"] +redis = ["kombu[redis]"] +s3 = ["boto3 (>=1.26.143)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +solar = ["ephem (==4.2) ; platform_python_implementation != \"PyPy\""] +sqlalchemy = ["kombu[sqlalchemy]"] +sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.5.0)", "pycurl (>=7.43.0.5,<7.45.4) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\" and python_version < \"3.9\"", "pycurl (>=7.45.4) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "urllib3 (>=1.26.16)"] +tblib = ["tblib (==3.2.2)"] +yaml = ["kombu[yaml]"] zookeeper = ["kazoo (>=1.3.1)"] -zstd = ["zstandard"] +zstd = ["zstandard (==0.23.0)"] [[package]] name = "certifi" @@ -382,6 +451,139 @@ files = [ {file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"}, ] +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "python_version < \"3.13\"" +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "click" +version = "8.3.1" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.13\"" +files = [ + {file = "click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6"}, + {file = "click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "click-didyoumean" +version = "0.3.1" +description = "Enables git-like *did-you-mean* feature in click" +optional = false +python-versions = ">=3.6.2" +groups = ["main"] +files = [ + {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, + {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, +] + +[package.dependencies] +click = ">=7" + +[[package]] +name = "click-plugins" +version = "1.1.1.2" +description = "An extension module for click to enable registering CLI commands via setuptools entry-points." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6"}, + {file = "click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261"}, +] + +[package.dependencies] +click = ">=4.0" + +[package.extras] +dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] + +[[package]] +name = "click-repl" +version = "0.3.0" +description = "REPL plugin for Click" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, + {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, +] + +[package.dependencies] +click = ">=7.0" +prompt-toolkit = ">=3.0.36" + +[package.extras] +testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +markers = "platform_system == \"Windows\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cron-descriptor" +version = "1.4.5" +description = "A Python library that converts cron expressions into human readable strings." +optional = false +python-versions = "*" +groups = ["main"] +markers = "python_version < \"3.13\"" +files = [ + {file = "cron_descriptor-1.4.5-py3-none-any.whl", hash = "sha256:736b3ae9d1a99bc3dbfc5b55b5e6e7c12031e7ba5de716625772f8b02dcd6013"}, + {file = "cron_descriptor-1.4.5.tar.gz", hash = "sha256:f51ce4ffc1d1f2816939add8524f206c376a42c87a5fca3091ce26725b3b1bca"}, +] + +[package.extras] +dev = ["polib"] + +[[package]] +name = "cron-descriptor" +version = "2.0.6" +description = "A Python library that converts cron expressions into human readable strings." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.13\"" +files = [ + {file = "cron_descriptor-2.0.6-py3-none-any.whl", hash = "sha256:3a1c0d837c0e5a32e415f821b36cf758eb92d510e6beff8fbfe4fa16573d93d6"}, + {file = "cron_descriptor-2.0.6.tar.gz", hash = "sha256:e39d2848e1d8913cfb6e3452e701b5eec662ee18bea8cc5aa53ee1a7bb217157"}, +] + +[package.dependencies] +typing_extensions = "*" + +[package.extras] +dev = ["mypy", "polib", "ruff"] +test = ["pytest"] + [[package]] name = "cryptography" version = "43.0.3" @@ -491,51 +693,74 @@ bcrypt = ["bcrypt"] [[package]] name = "django-celery-beat" -version = "2.2.0" +version = "2.8.1" description = "Database-backed Periodic Tasks." optional = false -python-versions = "*" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "django-celery-beat-2.2.0.tar.gz", hash = "sha256:b8a13afb15e7c53fc04f4f847ac71a6d32088959aba701eb7c4a59f0c28ba543"}, - {file = "django_celery_beat-2.2.0-py2.py3-none-any.whl", hash = "sha256:c4c72a9579f20eff4c4ccf1b58ebdca5ef940f4210065057db1754ea5f8dffdc"}, + {file = "django_celery_beat-2.8.1-py3-none-any.whl", hash = "sha256:da2b1c6939495c05a551717509d6e3b79444e114a027f7b77bf3727c2a39d171"}, + {file = "django_celery_beat-2.8.1.tar.gz", hash = "sha256:dfad0201c0ac50c91a34700ef8fa0a10ee098cc7f3375fe5debed79f2204f80a"}, ] [package.dependencies] -celery = ">=4.4,<6.0" -Django = ">=2.2,<4.0" -django-timezone-field = ">=4.1.0,<5.0" +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +celery = ">=5.2.3,<6.0" +cron-descriptor = ">=1.2.32" +Django = ">=2.2,<6.0" +django-timezone-field = ">=5.0" python-crontab = ">=2.3.4" +tzdata = "*" [[package]] name = "django-celery-results" -version = "1.2.1" +version = "2.6.0" description = "Celery result backends for Django." optional = false python-versions = "*" groups = ["main"] files = [ - {file = "django_celery_results-1.2.1-py2.py3-none-any.whl", hash = "sha256:a29ab580f0e38c66c39f51cc426bbdbb2a391b8cc0867df9dea748db2c961db2"}, - {file = "django_celery_results-1.2.1.tar.gz", hash = "sha256:e390f70cc43bbc2cd7c8e4607dc29ab6211a2ab968f93677583f0160921f670c"}, + {file = "django_celery_results-2.6.0-py3-none-any.whl", hash = "sha256:b9ccdca2695b98c7cbbb8dea742311ba9a92773d71d7b4944a676e69a7df1c73"}, + {file = "django_celery_results-2.6.0.tar.gz", hash = "sha256:9abcd836ae6b61063779244d8887a88fe80bbfaba143df36d3cb07034671277c"}, ] [package.dependencies] -celery = ">=4.4,<5.0" +celery = ">=5.2.7,<6.0" +Django = ">=3.2.25" [[package]] name = "django-cors-headers" -version = "3.14.0" +version = "4.4.0" description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] +markers = "python_version < \"3.13\"" files = [ - {file = "django_cors_headers-3.14.0-py3-none-any.whl", hash = "sha256:684180013cc7277bdd8702b80a3c5a4b3fcae4abb2bf134dceb9f5dfe300228e"}, - {file = "django_cors_headers-3.14.0.tar.gz", hash = "sha256:5fbd58a6fb4119d975754b2bc090f35ec160a8373f276612c675b00e8a138739"}, + {file = "django_cors_headers-4.4.0-py3-none-any.whl", hash = "sha256:5c6e3b7fe870876a1efdfeb4f433782c3524078fa0dc9e0195f6706ce7a242f6"}, + {file = "django_cors_headers-4.4.0.tar.gz", hash = "sha256:92cf4633e22af67a230a1456cb1b7a02bb213d6536d2dcb2a4a24092ea9cebc2"}, ] [package.dependencies] -Django = ">=3.2" +asgiref = ">=3.6" +django = ">=3.2" + +[[package]] +name = "django-cors-headers" +version = "4.5.0" +description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.13\"" +files = [ + {file = "django_cors_headers-4.5.0-py3-none-any.whl", hash = "sha256:28c1ded847aa70208798de3e42422a782f427b8b720e8d7319d34b654b5978e6"}, + {file = "django_cors_headers-4.5.0.tar.gz", hash = "sha256:6c01a85cf1ec779a7bde621db853aa3ce5c065a5ba8e27df7a9f9e8dac310f4f"}, +] + +[package.dependencies] +asgiref = ">=3.6" +django = ">=3.2" [[package]] name = "django-dbconn-retry" @@ -565,22 +790,19 @@ prometheus-client = ">=0.7" [[package]] name = "django-timezone-field" -version = "4.2.3" -description = "A Django app providing database and form fields for pytz timezone objects." +version = "7.2.1" +description = "A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects." optional = false -python-versions = ">=3.5" +python-versions = "<4.0,>=3.8" groups = ["main"] files = [ - {file = "django-timezone-field-4.2.3.tar.gz", hash = "sha256:5dd5bd9249382bef8847d3e7e4c32b7be182a4b538f354130d1252ed228892f8"}, - {file = "django_timezone_field-4.2.3-py3-none-any.whl", hash = "sha256:7552d2b0f145684b7de3fb5046101c7efd600cc6ba951b15c630fa1e1b83558e"}, + {file = "django_timezone_field-7.2.1-py3-none-any.whl", hash = "sha256:276915b72c5816f57c3baf9e43f816c695ef940d1b21f91ebf6203c09bf4ad44"}, + {file = "django_timezone_field-7.2.1.tar.gz", hash = "sha256:def846f9e7200b7b8f2a28fcce2b78fb2d470f6a9f272b07c4e014f6ba4c6d2e"}, ] [package.dependencies] -django = ">=2.2" -pytz = "*" - -[package.extras] -rest-framework = ["djangorestframework (>=3.0.0)"] +"backports.zoneinfo" = {version = ">=0.2.1,<0.3.0", markers = "python_version < \"3.9\""} +Django = ">=3.2,<6.1" [[package]] name = "djangorestframework" @@ -850,34 +1072,78 @@ files = [ [[package]] name = "kombu" -version = "4.6.11" +version = "5.5.4" description = "Messaging library for Python." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.8" groups = ["main"] +markers = "python_version < \"3.13\"" files = [ - {file = "kombu-4.6.11-py2.py3-none-any.whl", hash = "sha256:be48cdffb54a2194d93ad6533d73f69408486483d189fe9f5990ee24255b0e0a"}, - {file = "kombu-4.6.11.tar.gz", hash = "sha256:ca1b45faac8c0b18493d02a8571792f3c40291cf2bcf1f55afed3d8f3aa7ba74"}, + {file = "kombu-5.5.4-py3-none-any.whl", hash = "sha256:a12ed0557c238897d8e518f1d1fdf84bd1516c5e305af2dacd85c2015115feb8"}, + {file = "kombu-5.5.4.tar.gz", hash = "sha256:886600168275ebeada93b888e831352fe578168342f0d1d5833d88ba0d847363"}, ] [package.dependencies] -amqp = ">=2.6.0,<2.7" +amqp = ">=5.1.1,<6.0.0" +"backports.zoneinfo" = {version = ">=0.2.1", extras = ["tzdata"], markers = "python_version < \"3.9\""} +packaging = "*" +tzdata = {version = ">=2025.2", markers = "python_version >= \"3.9\""} +vine = "5.1.0" [package.extras] -azureservicebus = ["azure-servicebus (>=0.21.1)"] -azurestoragequeues = ["azure-storage-queue"] -consul = ["python-consul (>=0.6.0)"] -librabbitmq = ["librabbitmq (>=1.5.2)"] -mongodb = ["pymongo (>=3.3.0)"] -msgpack = ["msgpack"] -pyro = ["pyro4"] +azureservicebus = ["azure-servicebus (>=7.10.0)"] +azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] +consul = ["python-consul2 (==0.1.5)"] +gcpubsub = ["google-cloud-monitoring (>=2.16.0)", "google-cloud-pubsub (>=2.18.4)", "grpcio (==1.67.0)", "protobuf (==4.25.5)"] +librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] +mongodb = ["pymongo (==4.10.1)"] +msgpack = ["msgpack (==1.1.0)"] +pyro = ["pyro4 (==4.82)"] qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] -redis = ["redis (>=3.3.11)"] -slmq = ["softlayer-messaging (>=1.0.3)"] -sqlalchemy = ["sqlalchemy"] -sqs = ["boto3 (>=1.4.4)", "pycurl (==7.43.0.2)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<=5.2.1)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "urllib3 (>=1.26.16)"] yaml = ["PyYAML (>=3.10)"] -zookeeper = ["kazoo (>=1.3.1)"] +zookeeper = ["kazoo (>=2.8.0)"] + +[[package]] +name = "kombu" +version = "5.6.2" +description = "Messaging library for Python." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.13\"" +files = [ + {file = "kombu-5.6.2-py3-none-any.whl", hash = "sha256:efcfc559da324d41d61ca311b0c64965ea35b4c55cc04ee36e55386145dace93"}, + {file = "kombu-5.6.2.tar.gz", hash = "sha256:8060497058066c6f5aed7c26d7cd0d3b574990b09de842a8c5aaed0b92cc5a55"}, +] + +[package.dependencies] +amqp = ">=5.1.1,<6.0.0" +packaging = "*" +tzdata = ">=2025.2" +vine = "5.1.0" + +[package.extras] +azureservicebus = ["azure-servicebus (>=7.10.0)"] +azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] +consul = ["python-consul2 (==0.1.5)"] +gcpubsub = ["google-cloud-monitoring (>=2.16.0)", "google-cloud-pubsub (>=2.18.4)", "grpcio (==1.75.1)", "protobuf (==6.32.1)"] +librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] +mongodb = ["pymongo (==4.15.3)"] +msgpack = ["msgpack (==1.1.2)"] +pyro = ["pyro4 (==4.82)"] +qpid = ["qpid-python (==1.36.0-1)", "qpid-tools (==1.36.0-1)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<6.5)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\"", "urllib3 (>=1.26.16)"] +yaml = ["PyYAML (>=3.10)"] +zookeeper = ["kazoo (>=2.8.0)"] [[package]] name = "mako" @@ -1365,6 +1631,21 @@ files = [ [package.extras] twisted = ["twisted"] +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, + {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, +] + +[package.dependencies] +wcwidth = "*" + [[package]] name = "protobuf" version = "5.29.5" @@ -1500,6 +1781,21 @@ files = [ cron-description = ["cron-descriptor"] cron-schedule = ["croniter"] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + [[package]] name = "python-json-logger" version = "3.3.0" @@ -1651,6 +1947,18 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + [[package]] name = "sqlparse" version = "0.5.3" @@ -1695,6 +2003,37 @@ files = [ {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] +[[package]] +name = "tzdata" +version = "2025.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +groups = ["main"] +files = [ + {file = "tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1"}, + {file = "tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7"}, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +description = "tzinfo object for the local timezone" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.13\"" +files = [ + {file = "tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d"}, + {file = "tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd"}, +] + +[package.dependencies] +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] + [[package]] name = "uritemplate" version = "4.1.1" @@ -1727,14 +2066,26 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "vine" -version = "1.3.0" -description = "Promises, promises, promises." +version = "5.1.0" +description = "Python promises." +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, +] + +[[package]] +name = "wcwidth" +version = "0.2.14" +description = "Measures the displayed width of unicode strings in a terminal" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" groups = ["main"] files = [ - {file = "vine-1.3.0-py2.py3-none-any.whl", hash = "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"}, - {file = "vine-1.3.0.tar.gz", hash = "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87"}, + {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, + {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, ] [[package]] @@ -1884,4 +2235,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.8.0,<4.0" -content-hash = "330ace9c21c35e52a1c7114683d6fedbdd35718a1822e17bf5982f08cb074730" +content-hash = "ac0d1626509d1ed8b924db0e6f917c748714b1038531f493ccfebf3df1153fb1" diff --git a/runtime/bk-plugin-runtime/pyproject.toml b/runtime/bk-plugin-runtime/pyproject.toml index 84b00cd..849ac45 100644 --- a/runtime/bk-plugin-runtime/pyproject.toml +++ b/runtime/bk-plugin-runtime/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-runtime" -version = "2.1.3rc2" +version = "2.1.3rc3" description = "bk plugin python django runtime" authors = ["Your Name "] license = "MIT" @@ -15,13 +15,13 @@ djangorestframework = "^3.15" drf-yasg = "^1.21.5" raven = "^6.5.0" ddtrace = "^0.14.1" -django-cors-headers = "^3.8.0" +django-cors-headers = "^4.0.0" django-dbconn-retry = "^0.1.5" blueapps = {version = ">=4.15.1, <5.0", extras = ["opentelemetry"]} protobuf=">=3.19.4,<6.0" -celery = "^4.4.0" -django-celery-beat = "^2.2.0" -django-celery-results = "^1.2.1" +celery = "^5.4.0" +django-celery-beat = "^2.7.0" +django-celery-results = "^2.5.1" [tool.poetry.dev-dependencies] From b323bbdbd65ae6d2ba95e33a39c7b9e8d74d3e6e Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 21:26:41 +0800 Subject: [PATCH 12/21] minor: framework release 2.1.4rc4 --- bk-plugin-framework/poetry.lock | 511 +++++++++++++++++++++++------ bk-plugin-framework/pyproject.toml | 4 +- 2 files changed, 405 insertions(+), 110 deletions(-) diff --git a/bk-plugin-framework/poetry.lock b/bk-plugin-framework/poetry.lock index e3b4aae..9e07651 100644 --- a/bk-plugin-framework/poetry.lock +++ b/bk-plugin-framework/poetry.lock @@ -2,18 +2,18 @@ [[package]] name = "amqp" -version = "2.6.1" +version = "5.3.1" description = "Low-level AMQP client for Python (fork of amqplib)." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" groups = ["main"] files = [ - {file = "amqp-2.6.1-py2.py3-none-any.whl", hash = "sha256:aa7f313fb887c91f15474c1229907a04dac0b8135822d6603437803424c0aa59"}, - {file = "amqp-2.6.1.tar.gz", hash = "sha256:70cdb10628468ff14e57ec2f751c7aa9e48e7e3651cfd62d431213c0c4e58f21"}, + {file = "amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2"}, + {file = "amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432"}, ] [package.dependencies] -vine = ">=1.1.3,<5.0.0a1" +vine = ">=5.0.0,<6.0.0" [[package]] name = "annotated-types" @@ -180,41 +180,44 @@ files = [ {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, ] +[package.dependencies] +tzdata = {version = "*", optional = true, markers = "extra == \"tzdata\""} + [package.extras] tzdata = ["tzdata"] [[package]] name = "billiard" -version = "3.6.4.0" +version = "4.2.4" description = "Python multiprocessing fork with improvements and bugfixes" optional = false -python-versions = "*" +python-versions = ">=3.7" groups = ["main"] files = [ - {file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"}, - {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, + {file = "billiard-4.2.4-py3-none-any.whl", hash = "sha256:525b42bdec68d2b983347ac312f892db930858495db601b5836ac24e6477cde5"}, + {file = "billiard-4.2.4.tar.gz", hash = "sha256:55f542c371209e03cd5862299b74e52e4fbcba8250ba611ad94276b369b6a85f"}, ] [[package]] name = "bk-plugin-runtime" -version = "2.1.3rc2" +version = "2.1.3rc3" description = "bk plugin python django runtime" optional = false python-versions = "<4.0.0,>=3.8.0" groups = ["main"] files = [ - {file = "bk_plugin_runtime-2.1.3rc2-py3-none-any.whl", hash = "sha256:a2c9d68243adac46b551bdde36b9e7fab578f5643496519b80ba0befa48374de"}, - {file = "bk_plugin_runtime-2.1.3rc2.tar.gz", hash = "sha256:812849e720c45122bdb5bcb59323e4f49750045adeeee6e17b6a509141f96df9"}, + {file = "bk_plugin_runtime-2.1.3rc3-py3-none-any.whl", hash = "sha256:20b3055a526b7e9c3099b59b1fae9a71622efa20ef4dcb20dd419b1938cb4b00"}, + {file = "bk_plugin_runtime-2.1.3rc3.tar.gz", hash = "sha256:72a852d145dfa403621eff63619052724f7d976695e1bc853a17e4d5ac0378cb"}, ] [package.dependencies] blueapps = {version = ">=4.15.1,<5.0", extras = ["opentelemetry"]} -celery = ">=4.4.0,<5.0.0" +celery = ">=5.4.0,<6.0.0" ddtrace = ">=0.14.1,<0.15.0" Django = ">=2.2.6,<5" -django-celery-beat = ">=2.2.0,<3.0.0" -django-celery-results = ">=1.2.1,<2.0.0" -django-cors-headers = ">=3.8.0,<4.0.0" +django-celery-beat = ">=2.7.0,<3.0.0" +django-celery-results = ">=2.5.1,<3.0.0" +django-cors-headers = ">=4.0.0,<5.0.0" django-dbconn-retry = ">=0.1.5,<0.2.0" djangorestframework = ">=3.15,<4.0" drf-yasg = ">=1.21.5,<2.0.0" @@ -349,55 +352,122 @@ opentelemetry = ["django-prometheus (>=2.1.0,<3.0.0)", "opentelemetry-api (>=1.6 [[package]] name = "celery" -version = "4.4.7" +version = "5.5.3" description = "Distributed Task Queue." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.8" groups = ["main"] +markers = "python_full_version == \"3.8.*\" or platform_python_implementation == \"PyPy\" and python_version < \"3.13\"" files = [ - {file = "celery-4.4.7-py2.py3-none-any.whl", hash = "sha256:a92e1d56e650781fb747032a3997d16236d037c8199eacd5217d1a72893bca45"}, - {file = "celery-4.4.7.tar.gz", hash = "sha256:d220b13a8ed57c78149acf82c006785356071844afe0b27012a4991d44026f9f"}, + {file = "celery-5.5.3-py3-none-any.whl", hash = "sha256:0b5761a07057acee94694464ca482416b959568904c9dfa41ce8413a7d65d525"}, + {file = "celery-5.5.3.tar.gz", hash = "sha256:6c972ae7968c2b5281227f01c3a3f984037d21c5129d07bf3550cc2afc6b10a5"}, ] [package.dependencies] -billiard = ">=3.6.3.0,<4.0" -kombu = ">=4.6.10,<4.7" -pytz = ">0.0-dev" -vine = "1.3.0" +"backports.zoneinfo" = {version = ">=0.2.1", extras = ["tzdata"], markers = "python_version < \"3.9\""} +billiard = ">=4.2.1,<5.0" +click = ">=8.1.2,<9.0" +click-didyoumean = ">=0.3.0" +click-plugins = ">=1.1.1" +click-repl = ">=0.2.0" +kombu = ">=5.5.2,<5.6" +python-dateutil = ">=2.8.2" +vine = ">=5.1.0,<6.0" [package.extras] -arangodb = ["pyArango (>=1.3.2)"] -auth = ["cryptography"] -azureblockblob = ["azure-common (==1.1.5)", "azure-storage (==0.36.0)", "azure-storage-common (==1.1.0)"] +arangodb = ["pyArango (>=2.0.2)"] +auth = ["cryptography (==44.0.2)"] +azureblockblob = ["azure-identity (>=1.19.0)", "azure-storage-blob (>=12.15.0)"] brotli = ["brotli (>=1.0.0) ; platform_python_implementation == \"CPython\"", "brotlipy (>=0.7.0) ; platform_python_implementation == \"PyPy\""] -cassandra = ["cassandra-driver (<3.21.0)"] -consul = ["python-consul"] -cosmosdbsql = ["pydocumentdb (==2.3.2)"] -couchbase = ["couchbase (<3.0.0) ; platform_system != \"Windows\"", "couchbase-cffi (<3.0.0) ; platform_python_implementation == \"PyPy\""] -couchdb = ["pycouchdb"] -django = ["Django (>=1.11)"] -dynamodb = ["boto3 (>=1.9.178)"] -elasticsearch = ["elasticsearch"] -eventlet = ["eventlet (>=0.24.1)"] -gevent = ["gevent"] -librabbitmq = ["librabbitmq (>=1.5.0)"] -lzma = ["backports.lzma ; python_version < \"3.3\""] -memcache = ["pylibmc ; platform_system != \"Windows\""] -mongodb = ["pymongo[srv] (>=3.3.0)"] -msgpack = ["msgpack"] -pymemcache = ["python-memcached"] -pyro = ["pyro4"] -redis = ["redis (>=3.2.0)"] -riak = ["riak (>=2.0)"] -s3 = ["boto3 (>=1.9.125)"] -slmq = ["softlayer-messaging (>=1.0.3)"] -solar = ["ephem"] -sqlalchemy = ["sqlalchemy"] -sqs = ["boto3 (>=1.9.125)", "pycurl (==7.43.0.5)"] +cassandra = ["cassandra-driver (>=3.25.0,<4)"] +consul = ["python-consul2 (==0.1.5)"] +cosmosdbsql = ["pydocumentdb (==2.3.5)"] +couchbase = ["couchbase (>=3.0.0) ; platform_python_implementation != \"PyPy\" and (platform_system != \"Windows\" or python_version < \"3.10\")"] +couchdb = ["pycouchdb (==1.16.0)"] +django = ["Django (>=2.2.28)"] +dynamodb = ["boto3 (>=1.26.143)"] +elasticsearch = ["elastic-transport (<=8.17.1)", "elasticsearch (<=8.17.2)"] +eventlet = ["eventlet (>=0.32.0) ; python_version < \"3.10\""] +gcs = ["google-cloud-firestore (==2.20.1)", "google-cloud-storage (>=2.10.0)", "grpcio (==1.67.0)"] +gevent = ["gevent (>=1.5.0)"] +librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] +memcache = ["pylibmc (==1.6.3) ; platform_system != \"Windows\""] +mongodb = ["kombu[mongodb]"] +msgpack = ["kombu[msgpack]"] +pydantic = ["pydantic (>=2.4)"] +pymemcache = ["python-memcached (>=1.61)"] +pyro = ["pyro4 (==4.82) ; python_version < \"3.11\""] +pytest = ["pytest-celery[all] (>=1.2.0,<1.3.0)"] +redis = ["kombu[redis]"] +s3 = ["boto3 (>=1.26.143)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +solar = ["ephem (==4.2) ; platform_python_implementation != \"PyPy\""] +sqlalchemy = ["kombu[sqlalchemy]"] +sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.5.0)", "urllib3 (>=1.26.16)"] tblib = ["tblib (>=1.3.0) ; python_version < \"3.8.0\"", "tblib (>=1.5.0) ; python_version >= \"3.8.0\""] -yaml = ["PyYAML (>=3.10)"] +yaml = ["kombu[yaml]"] +zookeeper = ["kazoo (>=1.3.1)"] +zstd = ["zstandard (==0.23.0)"] + +[[package]] +name = "celery" +version = "5.6.2" +description = "Distributed Task Queue." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.9\" and platform_python_implementation != \"PyPy\" or python_version >= \"3.13\"" +files = [ + {file = "celery-5.6.2-py3-none-any.whl", hash = "sha256:3ffafacbe056951b629c7abcf9064c4a2366de0bdfc9fdba421b97ebb68619a5"}, + {file = "celery-5.6.2.tar.gz", hash = "sha256:4a8921c3fcf2ad76317d3b29020772103581ed2454c4c042cc55dcc43585009b"}, +] + +[package.dependencies] +billiard = ">=4.2.1,<5.0" +click = ">=8.1.2,<9.0" +click-didyoumean = ">=0.3.0" +click-plugins = ">=1.1.1" +click-repl = ">=0.2.0" +exceptiongroup = {version = ">=1.3.0", markers = "python_version < \"3.11\""} +kombu = ">=5.6.0" +python-dateutil = ">=2.8.2" +tzlocal = "*" +vine = ">=5.1.0,<6.0" + +[package.extras] +arangodb = ["pyArango (>=2.0.2)"] +auth = ["cryptography (==46.0.3)"] +azureblockblob = ["azure-identity (>=1.19.0)", "azure-storage-blob (>=12.15.0)"] +brotli = ["brotli (>=1.0.0) ; platform_python_implementation == \"CPython\"", "brotlipy (>=0.7.0) ; platform_python_implementation == \"PyPy\""] +cassandra = ["cassandra-driver (>=3.25.0,<4)"] +consul = ["python-consul2 (==0.1.5)"] +cosmosdbsql = ["pydocumentdb (==2.3.5)"] +couchbase = ["couchbase (>=3.0.0) ; platform_python_implementation != \"PyPy\" and (platform_system != \"Windows\" or python_version < \"3.10\")"] +couchdb = ["pycouchdb (==1.16.0)"] +django = ["Django (>=2.2.28)"] +dynamodb = ["boto3 (>=1.26.143)"] +elasticsearch = ["elastic-transport (<=9.1.0)", "elasticsearch (<=9.1.2)"] +eventlet = ["eventlet (>=0.32.0) ; python_version < \"3.10\""] +gcs = ["google-cloud-firestore (==2.22.0)", "google-cloud-storage (>=2.10.0)", "grpcio (==1.75.1)"] +gevent = ["gevent (>=1.5.0)"] +librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] +memcache = ["pylibmc (==1.6.3) ; platform_system != \"Windows\""] +mongodb = ["kombu[mongodb]"] +msgpack = ["kombu[msgpack]"] +pydantic = ["pydantic (>=2.12.0a1) ; python_version >= \"3.14\"", "pydantic (>=2.4) ; python_version < \"3.14\""] +pymemcache = ["python-memcached (>=1.61)"] +pyro = ["pyro4 (==4.82) ; python_version < \"3.11\""] +pytest = ["pytest-celery[all] (>=1.2.0,<1.3.0)"] +redis = ["kombu[redis]"] +s3 = ["boto3 (>=1.26.143)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +solar = ["ephem (==4.2) ; platform_python_implementation != \"PyPy\""] +sqlalchemy = ["kombu[sqlalchemy]"] +sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.5.0)", "pycurl (>=7.43.0.5,<7.45.4) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\" and python_version < \"3.9\"", "pycurl (>=7.45.4) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "urllib3 (>=1.26.16)"] +tblib = ["tblib (==3.2.2)"] +yaml = ["kombu[yaml]"] zookeeper = ["kazoo (>=1.3.1)"] -zstd = ["zstandard"] +zstd = ["zstandard (==0.23.0)"] [[package]] name = "certifi" @@ -685,7 +755,7 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" -groups = ["dev"] +groups = ["main", "dev"] markers = "python_version < \"3.13\"" files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, @@ -701,7 +771,7 @@ version = "8.3.0" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.10" -groups = ["dev"] +groups = ["main", "dev"] markers = "python_version >= \"3.13\"" files = [ {file = "click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc"}, @@ -711,18 +781,70 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "click-didyoumean" +version = "0.3.1" +description = "Enables git-like *did-you-mean* feature in click" +optional = false +python-versions = ">=3.6.2" +groups = ["main"] +files = [ + {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, + {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, +] + +[package.dependencies] +click = ">=7" + +[[package]] +name = "click-plugins" +version = "1.1.1.2" +description = "An extension module for click to enable registering CLI commands via setuptools entry-points." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6"}, + {file = "click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261"}, +] + +[package.dependencies] +click = ">=4.0" + +[package.extras] +dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] + +[[package]] +name = "click-repl" +version = "0.3.0" +description = "REPL plugin for Click" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, + {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, +] + +[package.dependencies] +click = ">=7.0" +prompt-toolkit = ">=3.0.36" + +[package.extras] +testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] + [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["dev"] -markers = "sys_platform == \"win32\" or platform_system == \"Windows\"" +groups = ["main", "dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {main = "platform_system == \"Windows\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\""} [[package]] name = "coverage" @@ -787,6 +909,42 @@ files = [ [package.extras] toml = ["tomli ; python_full_version <= \"3.11.0a6\""] +[[package]] +name = "cron-descriptor" +version = "1.4.5" +description = "A Python library that converts cron expressions into human readable strings." +optional = false +python-versions = "*" +groups = ["main"] +markers = "python_full_version == \"3.8.*\" or platform_python_implementation == \"PyPy\" and python_version < \"3.13\"" +files = [ + {file = "cron_descriptor-1.4.5-py3-none-any.whl", hash = "sha256:736b3ae9d1a99bc3dbfc5b55b5e6e7c12031e7ba5de716625772f8b02dcd6013"}, + {file = "cron_descriptor-1.4.5.tar.gz", hash = "sha256:f51ce4ffc1d1f2816939add8524f206c376a42c87a5fca3091ce26725b3b1bca"}, +] + +[package.extras] +dev = ["polib"] + +[[package]] +name = "cron-descriptor" +version = "2.0.6" +description = "A Python library that converts cron expressions into human readable strings." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.9\" and platform_python_implementation != \"PyPy\" or python_version >= \"3.13\"" +files = [ + {file = "cron_descriptor-2.0.6-py3-none-any.whl", hash = "sha256:3a1c0d837c0e5a32e415f821b36cf758eb92d510e6beff8fbfe4fa16573d93d6"}, + {file = "cron_descriptor-2.0.6.tar.gz", hash = "sha256:e39d2848e1d8913cfb6e3452e701b5eec662ee18bea8cc5aa53ee1a7bb217157"}, +] + +[package.dependencies] +typing_extensions = "*" + +[package.extras] +dev = ["mypy", "polib", "ruff"] +test = ["pytest"] + [[package]] name = "cryptography" version = "43.0.3" @@ -995,51 +1153,74 @@ bcrypt = ["bcrypt"] [[package]] name = "django-celery-beat" -version = "2.2.0" +version = "2.8.1" description = "Database-backed Periodic Tasks." optional = false -python-versions = "*" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "django-celery-beat-2.2.0.tar.gz", hash = "sha256:b8a13afb15e7c53fc04f4f847ac71a6d32088959aba701eb7c4a59f0c28ba543"}, - {file = "django_celery_beat-2.2.0-py2.py3-none-any.whl", hash = "sha256:c4c72a9579f20eff4c4ccf1b58ebdca5ef940f4210065057db1754ea5f8dffdc"}, + {file = "django_celery_beat-2.8.1-py3-none-any.whl", hash = "sha256:da2b1c6939495c05a551717509d6e3b79444e114a027f7b77bf3727c2a39d171"}, + {file = "django_celery_beat-2.8.1.tar.gz", hash = "sha256:dfad0201c0ac50c91a34700ef8fa0a10ee098cc7f3375fe5debed79f2204f80a"}, ] [package.dependencies] -celery = ">=4.4,<6.0" -Django = ">=2.2,<4.0" -django-timezone-field = ">=4.1.0,<5.0" +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +celery = ">=5.2.3,<6.0" +cron-descriptor = ">=1.2.32" +Django = ">=2.2,<6.0" +django-timezone-field = ">=5.0" python-crontab = ">=2.3.4" +tzdata = "*" [[package]] name = "django-celery-results" -version = "1.2.1" +version = "2.6.0" description = "Celery result backends for Django." optional = false python-versions = "*" groups = ["main"] files = [ - {file = "django_celery_results-1.2.1-py2.py3-none-any.whl", hash = "sha256:a29ab580f0e38c66c39f51cc426bbdbb2a391b8cc0867df9dea748db2c961db2"}, - {file = "django_celery_results-1.2.1.tar.gz", hash = "sha256:e390f70cc43bbc2cd7c8e4607dc29ab6211a2ab968f93677583f0160921f670c"}, + {file = "django_celery_results-2.6.0-py3-none-any.whl", hash = "sha256:b9ccdca2695b98c7cbbb8dea742311ba9a92773d71d7b4944a676e69a7df1c73"}, + {file = "django_celery_results-2.6.0.tar.gz", hash = "sha256:9abcd836ae6b61063779244d8887a88fe80bbfaba143df36d3cb07034671277c"}, ] [package.dependencies] -celery = ">=4.4,<5.0" +celery = ">=5.2.7,<6.0" +Django = ">=3.2.25" [[package]] name = "django-cors-headers" -version = "3.14.0" +version = "4.4.0" description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] +markers = "python_full_version == \"3.8.*\" or platform_python_implementation == \"PyPy\" and python_version < \"3.13\"" +files = [ + {file = "django_cors_headers-4.4.0-py3-none-any.whl", hash = "sha256:5c6e3b7fe870876a1efdfeb4f433782c3524078fa0dc9e0195f6706ce7a242f6"}, + {file = "django_cors_headers-4.4.0.tar.gz", hash = "sha256:92cf4633e22af67a230a1456cb1b7a02bb213d6536d2dcb2a4a24092ea9cebc2"}, +] + +[package.dependencies] +asgiref = ">=3.6" +django = ">=3.2" + +[[package]] +name = "django-cors-headers" +version = "4.5.0" +description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." +optional = false +python-versions = ">=3.9" groups = ["main"] +markers = "python_version >= \"3.9\" and platform_python_implementation != \"PyPy\" or python_version >= \"3.13\"" files = [ - {file = "django_cors_headers-3.14.0-py3-none-any.whl", hash = "sha256:684180013cc7277bdd8702b80a3c5a4b3fcae4abb2bf134dceb9f5dfe300228e"}, - {file = "django_cors_headers-3.14.0.tar.gz", hash = "sha256:5fbd58a6fb4119d975754b2bc090f35ec160a8373f276612c675b00e8a138739"}, + {file = "django_cors_headers-4.5.0-py3-none-any.whl", hash = "sha256:28c1ded847aa70208798de3e42422a782f427b8b720e8d7319d34b654b5978e6"}, + {file = "django_cors_headers-4.5.0.tar.gz", hash = "sha256:6c01a85cf1ec779a7bde621db853aa3ce5c065a5ba8e27df7a9f9e8dac310f4f"}, ] [package.dependencies] -Django = ">=3.2" +asgiref = ">=3.6" +django = ">=3.2" [[package]] name = "django-dbconn-retry" @@ -1069,22 +1250,19 @@ prometheus-client = ">=0.7" [[package]] name = "django-timezone-field" -version = "4.2.3" -description = "A Django app providing database and form fields for pytz timezone objects." +version = "7.2.1" +description = "A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects." optional = false -python-versions = ">=3.5" +python-versions = "<4.0,>=3.8" groups = ["main"] files = [ - {file = "django-timezone-field-4.2.3.tar.gz", hash = "sha256:5dd5bd9249382bef8847d3e7e4c32b7be182a4b538f354130d1252ed228892f8"}, - {file = "django_timezone_field-4.2.3-py3-none-any.whl", hash = "sha256:7552d2b0f145684b7de3fb5046101c7efd600cc6ba951b15c630fa1e1b83558e"}, + {file = "django_timezone_field-7.2.1-py3-none-any.whl", hash = "sha256:276915b72c5816f57c3baf9e43f816c695ef940d1b21f91ebf6203c09bf4ad44"}, + {file = "django_timezone_field-7.2.1.tar.gz", hash = "sha256:def846f9e7200b7b8f2a28fcce2b78fb2d470f6a9f272b07c4e014f6ba4c6d2e"}, ] [package.dependencies] -django = ">=2.2" -pytz = "*" - -[package.extras] -rest-framework = ["djangorestframework (>=3.0.0)"] +"backports.zoneinfo" = {version = ">=0.2.1,<0.3.0", markers = "python_version < \"3.9\""} +Django = ">=3.2,<6.1" [[package]] name = "djangorestframework" @@ -1158,12 +1336,12 @@ version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" -groups = ["dev"] -markers = "python_version < \"3.11\"" +groups = ["main", "dev"] files = [ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] +markers = {main = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\" and python_version < \"3.11\"", dev = "python_version < \"3.11\""} [package.dependencies] typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} @@ -1576,34 +1754,78 @@ referencing = ">=0.31.0" [[package]] name = "kombu" -version = "4.6.11" +version = "5.5.4" description = "Messaging library for Python." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.8" groups = ["main"] +markers = "python_full_version == \"3.8.*\" or platform_python_implementation == \"PyPy\" and python_version < \"3.13\"" files = [ - {file = "kombu-4.6.11-py2.py3-none-any.whl", hash = "sha256:be48cdffb54a2194d93ad6533d73f69408486483d189fe9f5990ee24255b0e0a"}, - {file = "kombu-4.6.11.tar.gz", hash = "sha256:ca1b45faac8c0b18493d02a8571792f3c40291cf2bcf1f55afed3d8f3aa7ba74"}, + {file = "kombu-5.5.4-py3-none-any.whl", hash = "sha256:a12ed0557c238897d8e518f1d1fdf84bd1516c5e305af2dacd85c2015115feb8"}, + {file = "kombu-5.5.4.tar.gz", hash = "sha256:886600168275ebeada93b888e831352fe578168342f0d1d5833d88ba0d847363"}, ] [package.dependencies] -amqp = ">=2.6.0,<2.7" +amqp = ">=5.1.1,<6.0.0" +"backports.zoneinfo" = {version = ">=0.2.1", extras = ["tzdata"], markers = "python_version < \"3.9\""} +packaging = "*" +tzdata = {version = ">=2025.2", markers = "python_version >= \"3.9\""} +vine = "5.1.0" [package.extras] -azureservicebus = ["azure-servicebus (>=0.21.1)"] -azurestoragequeues = ["azure-storage-queue"] -consul = ["python-consul (>=0.6.0)"] -librabbitmq = ["librabbitmq (>=1.5.2)"] -mongodb = ["pymongo (>=3.3.0)"] -msgpack = ["msgpack"] -pyro = ["pyro4"] +azureservicebus = ["azure-servicebus (>=7.10.0)"] +azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] +consul = ["python-consul2 (==0.1.5)"] +gcpubsub = ["google-cloud-monitoring (>=2.16.0)", "google-cloud-pubsub (>=2.18.4)", "grpcio (==1.67.0)", "protobuf (==4.25.5)"] +librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] +mongodb = ["pymongo (==4.10.1)"] +msgpack = ["msgpack (==1.1.0)"] +pyro = ["pyro4 (==4.82)"] qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] -redis = ["redis (>=3.3.11)"] -slmq = ["softlayer-messaging (>=1.0.3)"] -sqlalchemy = ["sqlalchemy"] -sqs = ["boto3 (>=1.4.4)", "pycurl (==7.43.0.2)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<=5.2.1)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "urllib3 (>=1.26.16)"] yaml = ["PyYAML (>=3.10)"] -zookeeper = ["kazoo (>=1.3.1)"] +zookeeper = ["kazoo (>=2.8.0)"] + +[[package]] +name = "kombu" +version = "5.6.2" +description = "Messaging library for Python." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.9\" and platform_python_implementation != \"PyPy\" or python_version >= \"3.13\"" +files = [ + {file = "kombu-5.6.2-py3-none-any.whl", hash = "sha256:efcfc559da324d41d61ca311b0c64965ea35b4c55cc04ee36e55386145dace93"}, + {file = "kombu-5.6.2.tar.gz", hash = "sha256:8060497058066c6f5aed7c26d7cd0d3b574990b09de842a8c5aaed0b92cc5a55"}, +] + +[package.dependencies] +amqp = ">=5.1.1,<6.0.0" +packaging = "*" +tzdata = ">=2025.2" +vine = "5.1.0" + +[package.extras] +azureservicebus = ["azure-servicebus (>=7.10.0)"] +azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] +consul = ["python-consul2 (==0.1.5)"] +gcpubsub = ["google-cloud-monitoring (>=2.16.0)", "google-cloud-pubsub (>=2.18.4)", "grpcio (==1.75.1)", "protobuf (==6.32.1)"] +librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] +mongodb = ["pymongo (==4.15.3)"] +msgpack = ["msgpack (==1.1.2)"] +pyro = ["pyro4 (==4.82)"] +qpid = ["qpid-python (==1.36.0-1)", "qpid-tools (==1.36.0-1)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<6.5)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5) ; sys_platform != \"win32\" and platform_python_implementation == \"CPython\"", "urllib3 (>=1.26.16)"] +yaml = ["PyYAML (>=3.10)"] +zookeeper = ["kazoo (>=2.8.0)"] [[package]] name = "mako" @@ -2502,6 +2724,21 @@ files = [ [package.extras] twisted = ["twisted"] +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, + {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, +] + +[package.dependencies] +wcwidth = "*" + [[package]] name = "protobuf" version = "4.25.8" @@ -2994,6 +3231,21 @@ files = [ cron-description = ["cron-descriptor"] cron-schedule = ["croniter"] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + [[package]] name = "python-json-logger" version = "3.3.0" @@ -3951,6 +4203,37 @@ files = [ [package.dependencies] typing-extensions = ">=4.12.0" +[[package]] +name = "tzdata" +version = "2025.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +groups = ["main"] +files = [ + {file = "tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1"}, + {file = "tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7"}, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +description = "tzinfo object for the local timezone" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.9\" and platform_python_implementation != \"PyPy\" or python_version >= \"3.13\"" +files = [ + {file = "tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d"}, + {file = "tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd"}, +] + +[package.dependencies] +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] + [[package]] name = "uritemplate" version = "4.1.1" @@ -4017,14 +4300,26 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "vine" -version = "1.3.0" -description = "Promises, promises, promises." +version = "5.1.0" +description = "Python promises." +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, +] + +[[package]] +name = "wcwidth" +version = "0.2.14" +description = "Measures the displayed width of unicode strings in a terminal" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" groups = ["main"] files = [ - {file = "vine-1.3.0-py2.py3-none-any.whl", hash = "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"}, - {file = "vine-1.3.0.tar.gz", hash = "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87"}, + {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, + {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, ] [[package]] @@ -4233,4 +4528,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.8.0,<4.0" -content-hash = "17900d595ebf72774c30a031d2e2c5736cc5fbd73ccd0c0c5f69f2bfe86a3bfc" +content-hash = "4f1c1ef5d68ab0be6cbdd06c75e1f30ca6a901dd27bc0412a3540f39e6b26f2e" diff --git a/bk-plugin-framework/pyproject.toml b/bk-plugin-framework/pyproject.toml index 7d07d0f..f3f7232 100644 --- a/bk-plugin-framework/pyproject.toml +++ b/bk-plugin-framework/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-framework" -version = "2.3.4rc3" +version = "2.3.4rc4" description = "bk plugin python framework" authors = ["Your Name "] license = "MIT" @@ -10,7 +10,7 @@ python = "^3.8.0,<4.0" pydantic = ">=1.0,<3" werkzeug = ">=2.0.0, <4.0" apigw-manager = {version = ">=1.0.6, <4", extras = ["extra"]} -bk-plugin-runtime = "2.1.3rc2" +bk-plugin-runtime = "2.1.3rc3" jsonschema = ">=2.5.0,<5.0.0" drf-spectacular = "^0.29.0" From 9ee447b7a84ae4f1d6006e76a3b668b0973f8585 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 21:29:03 +0800 Subject: [PATCH 13/21] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E8=84=9A?= =?UTF-8?q?=E6=89=8B=E6=9E=B6=E4=B8=AD=E5=A4=9A=E4=BD=99=E7=9A=84=20celery?= =?UTF-8?q?=20=E7=89=88=E6=9C=AC=E6=8C=87=E5=AE=9A=20--story=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/{{cookiecutter.project_name}}/requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/template/{{cookiecutter.project_name}}/requirements.txt b/template/{{cookiecutter.project_name}}/requirements.txt index 16c3eb9..1d7ce4b 100644 --- a/template/{{cookiecutter.project_name}}/requirements.txt +++ b/template/{{cookiecutter.project_name}}/requirements.txt @@ -3,7 +3,6 @@ bk-plugin-framework==2.3.4rc3 # opentelemetry celery-prometheus-exporter==1.7.0 -celery>=4.4.0,<5.0.0 # Explicit celery version constraint to resolve pip 25.x dependency conflict opentelemetry-api==1.25.0 opentelemetry-exporter-jaeger==1.21.0 opentelemetry-exporter-jaeger-proto-grpc==1.21.0 From 74e3c9f5d9488f8fccf001821ea4623fae99878b Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Mon, 19 Jan 2026 22:11:41 +0800 Subject: [PATCH 14/21] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E8=84=9A?= =?UTF-8?q?=E6=89=8B=E6=9E=B6=E4=B8=AD=E7=9A=84=20app=5Fdesc.yaml=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=20--story=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/{{cookiecutter.project_name}}/app_desc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/template/{{cookiecutter.project_name}}/app_desc.yml b/template/{{cookiecutter.project_name}}/app_desc.yml index d433cb4..2a88355 100644 --- a/template/{{cookiecutter.project_name}}/app_desc.yml +++ b/template/{{cookiecutter.project_name}}/app_desc.yml @@ -17,9 +17,9 @@ modules: targetPort: 5000 port: 80 - name: schedule - procCommand: celery worker -A blueapps.core.celery -P threads -n schedule_worker@%h -c 500 -Q plugin_schedule,plugin_callback,schedule_delete -l INFO + procCommand: celery worker -A blueapps.core.celery -P prefork -n schedule_worker@%h -c 50 -Q plugin_schedule,plugin_callback,schedule_delete -l INFO --max-tasks-per-child=1000 --time-limit=300 - name: beat - procCommand: celery beat -A blueapps.core.celery -l INFO + procCommand: celery beat -A blueapps.core.celery -l INFO --pidfile=/tmp/celerybeat.pid --schedule=/tmp/celerybeat-schedule - name: c-monitor procCommand: celery-prometheus-exporter --broker amqp://$RABBITMQ_USER:$RABBITMQ_PASSWORD@$RABBITMQ_HOST:$RABBITMQ_PORT/$RABBITMQ_VHOST --addr 0.0.0.0:5001 --queue-list plugin_schedule plugin_callback schedule_delete configuration: From 53506e959ff75c7f1080b2970f48d5157694f546 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Tue, 20 Jan 2026 11:06:59 +0800 Subject: [PATCH 15/21] =?UTF-8?q?fix:=20=E8=B0=83=E6=95=B4=E8=84=9A?= =?UTF-8?q?=E6=89=8B=E6=9E=B6=E7=9A=84app=5Fdesc=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=20--story=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/{{cookiecutter.project_name}}/app_desc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/template/{{cookiecutter.project_name}}/app_desc.yml b/template/{{cookiecutter.project_name}}/app_desc.yml index 2a88355..dee99b0 100644 --- a/template/{{cookiecutter.project_name}}/app_desc.yml +++ b/template/{{cookiecutter.project_name}}/app_desc.yml @@ -17,9 +17,9 @@ modules: targetPort: 5000 port: 80 - name: schedule - procCommand: celery worker -A blueapps.core.celery -P prefork -n schedule_worker@%h -c 50 -Q plugin_schedule,plugin_callback,schedule_delete -l INFO --max-tasks-per-child=1000 --time-limit=300 + procCommand: celery -A blueapps.core.celery worker -P threads -n schedule_worker@%h -c 500 -Q plugin_schedule,plugin_callback,schedule_delete -l INFO - name: beat - procCommand: celery beat -A blueapps.core.celery -l INFO --pidfile=/tmp/celerybeat.pid --schedule=/tmp/celerybeat-schedule + procCommand: celery -A blueapps.core.celery beat -l INFO - name: c-monitor procCommand: celery-prometheus-exporter --broker amqp://$RABBITMQ_USER:$RABBITMQ_PASSWORD@$RABBITMQ_HOST:$RABBITMQ_PORT/$RABBITMQ_VHOST --addr 0.0.0.0:5001 --queue-list plugin_schedule plugin_callback schedule_delete configuration: From a7dbe785dc012bf6524f5d6a6ce0f6f901ec1be1 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Tue, 20 Jan 2026 11:57:33 +0800 Subject: [PATCH 16/21] =?UTF-8?q?fix:=20=E8=B0=83=E6=95=B4=E7=BD=91?= =?UTF-8?q?=E5=85=B3=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E9=83=A8=E7=BD=B2=E7=8E=AF=E5=A2=83=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E5=BC=95=E5=85=A5=20--story=3D130029401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bk_plugin_runtime/config/default.py | 13 ------------- .../bk_plugin_runtime/config/prod.py | 10 ++++++++++ .../bk_plugin_runtime/config/stag.py | 8 ++++++++ 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py index 2dbfcc0..bca1e59 100644 --- a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py +++ b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/default.py @@ -253,19 +253,6 @@ def logging_addition_settings(logging_dict): BK_APIGW_STAGE_BACKEND_HOST = f"{app_scheme}://{app_domain}" BK_APIGW_STAGE_BACKEND_SUBPATH = app_subpath - -# while deploy app on staging env, it would sync to the stage=stag of the gateway -# while deploy app on production env, it would sync to the stage=prod of the gateway -BK_APIGW_STAGE_NAME = bkpaas_environment -BK_APIGW_STAGE_DESCRIPTION = "生产环境" if bkpaas_environment == "prod" else "预发布环境" -BK_APIGW_STAGE_DESCRIPTION_EN = "Production Env" if bkpaas_environment == "prod" else "Staging Env" -# 声明网关不同环境的环境变量 -stag_env_vars = {"foo": "bar"} -prod_env_vars = { - # "foo": "bar" -} -BK_APIGW_STAGE_ENV_VARS = prod_env_vars if bkpaas_environment == "prod" else stag_env_vars - # 网关同步 API 文档语言, zh/en, 如果配置了BK_APIGW_RESOURCE_DOCS_BASE_DIR(使用自定义文档), 那么必须将这个变量置空 BK_APIGW_RELEASE_DOC_LANGUAGE = os.getenv("BK_APIGW_RELEASE_DOC_LANGUAGE", "") # 在项目 docs目录下,通过 markdown文档自动化导入中英文文档; 注意markdown文件名必须等于接口的 operation_id; 见 demo 示例 diff --git a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/prod.py b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/prod.py index 42da106..7adc4e4 100644 --- a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/prod.py +++ b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/prod.py @@ -16,6 +16,16 @@ else: from blueapps.patch.settings_paas_services import * # noqa +# 生产环境网关配置 +BK_APIGW_STAGE_NAME = "prod" +BK_APIGW_STAGE_DESCRIPTION = "生产环境" +BK_APIGW_STAGE_DESCRIPTION_EN = "Production Env" + +# 生产环境网关环境变量 +BK_APIGW_STAGE_ENV_VARS = { + # "foo": "bar" +} + # 正式环境 RUN_MODE = "PRODUCT" diff --git a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/stag.py b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/stag.py index 7bf5260..118df04 100644 --- a/runtime/bk-plugin-runtime/bk_plugin_runtime/config/stag.py +++ b/runtime/bk-plugin-runtime/bk_plugin_runtime/config/stag.py @@ -18,6 +18,14 @@ else: from blueapps.patch.settings_paas_services import * # noqa +# 开发环境网关配置 +BK_APIGW_STAGE_NAME = "dev" +BK_APIGW_STAGE_DESCRIPTION = "开发环境" +BK_APIGW_STAGE_DESCRIPTION_EN = "Development Env" + +# 预发布环境网关环境变量 +BK_APIGW_STAGE_ENV_VARS = {"foo": "bar"} + # 预发布环境 RUN_MODE = "STAGING" From 5374d2e450e24372effd13ba72833281dedd5c43 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Tue, 20 Jan 2026 12:49:52 +0800 Subject: [PATCH 17/21] minor: framework release V2.3.4rc5 --- bk-plugin-framework/poetry.lock | 8 ++++---- bk-plugin-framework/pyproject.toml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bk-plugin-framework/poetry.lock b/bk-plugin-framework/poetry.lock index 9e07651..38aef85 100644 --- a/bk-plugin-framework/poetry.lock +++ b/bk-plugin-framework/poetry.lock @@ -200,14 +200,14 @@ files = [ [[package]] name = "bk-plugin-runtime" -version = "2.1.3rc3" +version = "2.1.3rc4" description = "bk plugin python django runtime" optional = false python-versions = "<4.0.0,>=3.8.0" groups = ["main"] files = [ - {file = "bk_plugin_runtime-2.1.3rc3-py3-none-any.whl", hash = "sha256:20b3055a526b7e9c3099b59b1fae9a71622efa20ef4dcb20dd419b1938cb4b00"}, - {file = "bk_plugin_runtime-2.1.3rc3.tar.gz", hash = "sha256:72a852d145dfa403621eff63619052724f7d976695e1bc853a17e4d5ac0378cb"}, + {file = "bk_plugin_runtime-2.1.3rc4-py3-none-any.whl", hash = "sha256:7eb012c168d130e1a65756b31ecc01ed3e0b7717d88524bdfdcb8cbc3a8b9892"}, + {file = "bk_plugin_runtime-2.1.3rc4.tar.gz", hash = "sha256:9154012561dc7715921773413e1216e218257e7fa011c982910848e8024a0ff8"}, ] [package.dependencies] @@ -4528,4 +4528,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.8.0,<4.0" -content-hash = "4f1c1ef5d68ab0be6cbdd06c75e1f30ca6a901dd27bc0412a3540f39e6b26f2e" +content-hash = "a9367238448a88e32a86a32ff94cd48a3c96cc6f4f67df603cc55d7b75b205e8" diff --git a/bk-plugin-framework/pyproject.toml b/bk-plugin-framework/pyproject.toml index f3f7232..a9cc2f9 100644 --- a/bk-plugin-framework/pyproject.toml +++ b/bk-plugin-framework/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-framework" -version = "2.3.4rc4" +version = "2.3.4rc5" description = "bk plugin python framework" authors = ["Your Name "] license = "MIT" @@ -10,7 +10,7 @@ python = "^3.8.0,<4.0" pydantic = ">=1.0,<3" werkzeug = ">=2.0.0, <4.0" apigw-manager = {version = ">=1.0.6, <4", extras = ["extra"]} -bk-plugin-runtime = "2.1.3rc3" +bk-plugin-runtime = "2.1.3rc4" jsonschema = ">=2.5.0,<5.0.0" drf-spectacular = "^0.29.0" From 03a80b9edd8f0422c2ef7f1879001510b6a5e163 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Tue, 20 Jan 2026 17:17:02 +0800 Subject: [PATCH 18/21] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E7=9A=84=E8=A7=86=E5=9B=BE=E6=8E=A5=E5=8F=A3=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=88=B0=E7=BD=91=E5=85=B3=E7=9A=84=E9=80=BB=E8=BE=91?= =?UTF-8?q?=20--story=3D130029514?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commands/support-files/resources.yaml | 68 +++++++- .../commands/sync_apigateway_if_changed.py | 161 ++++++------------ 2 files changed, 117 insertions(+), 112 deletions(-) diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/support-files/resources.yaml b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/support-files/resources.yaml index 591551e..d4d5fc4 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/support-files/resources.yaml +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/support-files/resources.yaml @@ -6,7 +6,6 @@ info: paths: - /callback/{token}/: post: operationId: callback @@ -44,17 +43,25 @@ paths: isPublic: true matchSubpath: false backend: + type: HTTP name: default method: post + {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} + path: /{env.api_sub_path}bk_plugin/callback/{token}/ + {% else %} path: /bk_plugin/callback/{token}/ + {% endif %} matchSubpath: false timeout: 0 + upstreams: {} + transformHeaders: {} pluginConfigs: [] allowApplyPermission: true authConfig: userVerifiedRequired: false appVerifiedRequired: true resourcePermissionRequired: true + disabledStages: [] descriptionEn: plugin callback /invoke/{version}: @@ -94,17 +101,25 @@ paths: isPublic: true matchSubpath: false backend: + type: HTTP name: default method: post + {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} + path: /{env.api_sub_path}bk_plugin/invoke/{version} + {% else %} path: /bk_plugin/invoke/{version} + {% endif %} matchSubpath: false timeout: 0 + upstreams: {} + transformHeaders: {} pluginConfigs: [] allowApplyPermission: true authConfig: userVerifiedRequired: false appVerifiedRequired: true resourcePermissionRequired: true + disabledStages: [] descriptionEn: Invoke specific version plugin /bk_plugin/plugin_api/: x-bk-apigateway-method-any: @@ -124,17 +139,54 @@ paths: type: HTTP name: default method: any + {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} + path: /{env.api_sub_path}bk_plugin/plugin_api/ + {% else %} path: /bk_plugin/plugin_api/ + {% endif %} matchSubpath: true timeout: 0 - upstreams: { } - transformHeaders: { } + upstreams: {} + transformHeaders: {} authConfig: userVerifiedRequired: true appVerifiedRequired: false - disabledStages: [ ] + disabledStages: [] descriptionEn: Plugin custom API entry + /bk_plugin/openapi/: + x-bk-apigateway-method-any: + operationId: plugin_openapi + summary: 插件开放API + description: 插件开放 API 入口,支持子路径匹配 + tags: + - openapi + responses: + default: + description: '插件开放API响应' + x-bk-apigateway-resource: + isPublic: true + allowApplyPermission: true + matchSubpath: true + backend: + type: HTTP + name: default + method: any + {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} + path: /{env.api_sub_path}bk_plugin/openapi/ + {% else %} + path: /bk_plugin/openapi/ + {% endif %} + matchSubpath: true + timeout: 0 + upstreams: {} + transformHeaders: {} + authConfig: + userVerifiedRequired: false + appVerifiedRequired: true + disabledStages: [] + descriptionEn: Plugin open API entry + /plugin_api_dispatch/: post: operationId: plugin_api_dispatch @@ -165,17 +217,25 @@ paths: isPublic: true matchSubpath: false backend: + type: HTTP name: default method: post + {% if settings.BK_PLUGIN_APIGW_BACKEND_SUB_PATH %} + path: /{env.api_sub_path}bk_plugin/plugin_api_dispatch/ + {% else %} path: /bk_plugin/plugin_api_dispatch/ + {% endif %} matchSubpath: false timeout: 0 + upstreams: {} + transformHeaders: {} pluginConfigs: [] allowApplyPermission: true authConfig: userVerifiedRequired: false appVerifiedRequired: true resourcePermissionRequired: true + disabledStages: [] descriptionEn: Plugin API dispatch components: diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py index fdf557d..2ba65b4 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py @@ -11,6 +11,7 @@ import hashlib import os +import shutil import time import yaml @@ -36,7 +37,7 @@ def handle(self, *args, **options): # 用于记录各步骤耗时(毫秒) step_timings = {} - # 1. 生成 yaml 文件 + # 1. 生成 definition.yaml 文件 step_start = time.time() self.stdout.write("[Sync] generate definition.yaml") try: @@ -50,30 +51,20 @@ def handle(self, *args, **options): ) raise SystemExit(1) - self.stdout.write("[Sync] generate resources.yaml") - try: - call_command("generate_resources_yaml") - except Exception as e: - self.stderr.write( - self.style.ERROR( - f"run generate_resources_yaml fail: {e}, " - "please run this command on your development env to find out the reason" - ) - ) - raise SystemExit(1) - # 输出生成的文件路径 resources_yaml_path = os.path.join(settings.BASE_DIR, "resources.yaml") definition_yaml_path = os.path.join(settings.BASE_DIR, "definition.yaml") - self.stdout.write(f"[Sync] Generated resources.yaml path: {resources_yaml_path}") self.stdout.write(f"[Sync] Generated definition.yaml path: {definition_yaml_path}") - step_timings["1. 生成 yaml 文件"] = (time.time() - step_start) * 1000 + step_timings["1. 生成 definition.yaml 文件"] = (time.time() - step_start) * 1000 - # 1.1 合并 support-files/resources.yaml 中的资源配置 + # 1.1 复制 support-files/resources.yaml 到项目根目录 + # 注意:不再使用 generate_resources_yaml 命令扫描 URL 模块 + # plugin_api/ 和 openapi/ 等接口已在 support-files/resources.yaml 中通过子路径匹配方式定义 step_start = time.time() - self._merge_support_files_resources() - step_timings["1.1 合并 support-files 资源配置"] = (time.time() - step_start) * 1000 + self._copy_support_files_resources() + self.stdout.write(f"[Sync] resources.yaml path: {resources_yaml_path}") + step_timings["1.1 复制 support-files/resources.yaml"] = (time.time() - step_start) * 1000 # 2. 计算当前哈希值(仅计算 resources.yaml) step_start = time.time() @@ -94,7 +85,11 @@ def handle(self, *args, **options): step_start = time.time() need_sync = force_sync or current_hash != last_hash if not need_sync: - self.stdout.write(self.style.SUCCESS("[Sync] API definition unchanged, skip sync to apigateway")) + self.stdout.write( + self.style.SUCCESS( + "[Sync] API definition unchanged, skip sync to apigateway" + ) + ) # 仍然获取公钥,确保公钥是最新的 self._fetch_public_key() step_timings["4. 对比决定是否同步"] = (time.time() - step_start) * 1000 @@ -106,7 +101,9 @@ def handle(self, *args, **options): if force_sync: self.stdout.write(self.style.WARNING("[Sync] Force sync enabled")) else: - self.stdout.write(self.style.WARNING("[Sync] API definition changed, start syncing...")) + self.stdout.write( + self.style.WARNING("[Sync] API definition changed, start syncing...") + ) # 5. 执行同步 step_start = time.time() @@ -128,7 +125,9 @@ def handle(self, *args, **options): # 7. 更新哈希值 step_start = time.time() self._save_sync_hash(current_hash, success=True) - self.stdout.write(self.style.SUCCESS("[Sync] API gateway sync completed successfully")) + self.stdout.write( + self.style.SUCCESS("[Sync] API gateway sync completed successfully") + ) step_timings["7. 更新哈希值"] = (time.time() - step_start) * 1000 # 打印耗时统计 @@ -147,97 +146,38 @@ def _print_timing_stats(self, step_timings): self.stdout.write(f" 总耗时: {total_time:.2f} ms") self.stdout.write("=" * 50 + "\n") - def _merge_support_files_resources(self): + def _copy_support_files_resources(self): """ - 将 support-files/resources.yaml 中的资源配置合并到生成的 resources.yaml 中 - - 合并逻辑: - 1. 读取自动生成的 resources.yaml - 2. 读取 support-files/resources.yaml(手动维护的补充配置) - 3. 将 support-files 中的 paths 追加到生成的 paths 中 - 4. 将 support-files 中的 components/schemas 合并到生成的 components 中 - 5. 写回合并后的 resources.yaml + 将 support-files/resources.yaml 复制到项目根目录作为 resources.yaml + + 说明: + - 不再使用 generate_resources_yaml 命令自动扫描 URL 模块 + - plugin_api/ 和 openapi/ 等接口已在 support-files/resources.yaml 中 + 通过子路径匹配(matchSubpath: true)的方式统一定义 + - 这样可以避免扫描 bk_plugin.apis.urls 和 bk_plugin.openapi.urls 模块 """ - generated_filepath = os.path.join(settings.BASE_DIR, "resources.yaml") support_files_dir = os.path.join(os.path.dirname(__file__), "support-files") support_filepath = os.path.join(support_files_dir, "resources.yaml") - - # 检查生成的文件是否存在 - if not os.path.exists(generated_filepath): - self.stdout.write(self.style.WARNING(f"[Sync] Generated resources.yaml not found: {generated_filepath}")) - return + target_filepath = os.path.join(settings.BASE_DIR, "resources.yaml") # 检查 support-files/resources.yaml 是否存在 if not os.path.exists(support_filepath): - self.stdout.write( - self.style.WARNING(f"[Sync] support-files/resources.yaml not found: {support_filepath}, skip merging") + self.stderr.write( + self.style.ERROR(f"[Sync] support-files/resources.yaml not found: {support_filepath}") ) - return + raise SystemExit(1) try: - # 读取自动生成的 resources.yaml - with open(generated_filepath, encoding="utf-8") as f: - generated_data = yaml.safe_load(f) - - # 读取 support-files/resources.yaml - with open(support_filepath, encoding="utf-8") as f: - support_data = yaml.safe_load(f) - - if not generated_data: - self.stdout.write(self.style.WARNING("[Sync] Generated resources.yaml is empty")) - return - - if not support_data: - self.stdout.write(self.style.WARNING("[Sync] support-files/resources.yaml is empty, skip merging")) - return - - merged_paths_count = 0 - merged_schemas_count = 0 - - # 合并 paths - if "paths" in support_data: - if "paths" not in generated_data: - generated_data["paths"] = {} - - for path, path_config in support_data["paths"].items(): - if path in generated_data["paths"]: - self.stdout.write( - self.style.WARNING( - f"[Sync] Path '{path}' already exists, will be overwritten by support-files config" - ) - ) - generated_data["paths"][path] = path_config - merged_paths_count += 1 - self.stdout.write(f"[Sync] Merged path: {path}") - - # 合并 components/schemas - if "components" in support_data and "schemas" in support_data.get("components", {}): - if "components" not in generated_data: - generated_data["components"] = {} - if "schemas" not in generated_data["components"]: - generated_data["components"]["schemas"] = {} - - for schema_name, schema_config in support_data["components"]["schemas"].items(): - if schema_name in generated_data["components"]["schemas"]: - self.stdout.write( - self.style.WARNING(f"[Sync] Schema '{schema_name}' already exists, will be overwritten") - ) - generated_data["components"]["schemas"][schema_name] = schema_config - merged_schemas_count += 1 - - # 写回合并后的文件 - with open(generated_filepath, "w", encoding="utf-8") as f: - yaml.dump(generated_data, f, default_flow_style=False, allow_unicode=True, sort_keys=False) - + # 直接复制文件 + shutil.copy2(support_filepath, target_filepath) self.stdout.write( - self.style.SUCCESS( - f"[Sync] Merged support-files/resources.yaml: " - f"{merged_paths_count} paths, {merged_schemas_count} schemas" - ) + self.style.SUCCESS(f"[Sync] Copied support-files/resources.yaml to {target_filepath}") ) - except Exception as e: - self.stderr.write(self.style.ERROR(f"[Sync] Failed to merge support-files/resources.yaml: {e}")) + self.stderr.write( + self.style.ERROR(f"[Sync] Failed to copy support-files/resources.yaml: {e}") + ) + raise SystemExit(1) def _calculate_resources_hash(self): """ @@ -250,7 +190,7 @@ def _calculate_resources_hash(self): filepath = os.path.join(settings.BASE_DIR, "resources.yaml") if os.path.exists(filepath): try: - with open(filepath, encoding="utf-8") as f: + with open(filepath, "r", encoding="utf-8") as f: data = yaml.safe_load(f) if data: @@ -258,17 +198,18 @@ def _calculate_resources_hash(self): # 这样即使原始文件中 A,B,C 和 B,C,A 的顺序不同, # 规范化后的内容也会相同,从而产生相同的 hash normalized_content = yaml.dump( - data, default_flow_style=False, allow_unicode=True, sort_keys=True # 关键:排序所有 key + data, + default_flow_style=False, + allow_unicode=True, + sort_keys=True # 关键:排序所有 key ) return hashlib.sha256(normalized_content.encode()).hexdigest() except Exception as e: self.stdout.write( - self.style.WARNING( - f"[Sync] Failed to normalize resources.yaml for hash: {e}, fallback to raw content hash" - ) + self.style.WARNING(f"[Sync] Failed to normalize resources.yaml for hash: {e}, fallback to raw content hash") ) # 回退到原始方式 - with open(filepath, encoding="utf-8") as f: + with open(filepath, "r", encoding="utf-8") as f: content = f.read() return hashlib.sha256(content.encode()).hexdigest() return "" @@ -283,7 +224,9 @@ def _get_last_sync_hash(self): state = APIGatewaySyncState.objects.filter(sync_success=True).first() return state.api_hash if state else "" except Exception as e: - self.stdout.write(self.style.WARNING(f"[Sync] Failed to get last sync hash: {e}")) + self.stdout.write( + self.style.WARNING(f"[Sync] Failed to get last sync hash: {e}") + ) return "" def _save_sync_hash(self, hash_value, success=True): @@ -299,7 +242,9 @@ def _save_sync_hash(self, hash_value, success=True): ) self.stdout.write(f"[Sync] Sync state saved (success={success})") except Exception as e: - self.stdout.write(self.style.WARNING(f"[Sync] Failed to save sync hash: {e}")) + self.stdout.write( + self.style.WARNING(f"[Sync] Failed to save sync hash: {e}") + ) def _fetch_public_key(self): """获取 API 网关公钥""" @@ -308,4 +253,4 @@ def _fetch_public_key(self): call_command("fetch_apigw_public_key") except Exception as e: self.stderr.write(self.style.ERROR(f"run fetch_apigw_public_key fail: {e}")) - raise SystemExit(1) + raise SystemExit(1) \ No newline at end of file From f1eef0cc542e24494e9f951beacb84d95e299e4b Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Tue, 20 Jan 2026 17:18:52 +0800 Subject: [PATCH 19/21] minor: framework release V2.3.4rc6 --- bk-plugin-framework/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bk-plugin-framework/pyproject.toml b/bk-plugin-framework/pyproject.toml index a9cc2f9..1f42607 100644 --- a/bk-plugin-framework/pyproject.toml +++ b/bk-plugin-framework/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-framework" -version = "2.3.4rc5" +version = "2.3.4rc6" description = "bk plugin python framework" authors = ["Your Name "] license = "MIT" From 91e07ab0ea351aa6d97b0f5bdbfe0c4d181a568a Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Tue, 20 Jan 2026 17:43:26 +0800 Subject: [PATCH 20/21] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=20runtime=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=20pyproject.toml=E6=96=87=E4=BB=B6=20--story?= =?UTF-8?q?=3D130029514?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- runtime/bk-plugin-runtime/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/bk-plugin-runtime/pyproject.toml b/runtime/bk-plugin-runtime/pyproject.toml index 849ac45..2f14e0c 100644 --- a/runtime/bk-plugin-runtime/pyproject.toml +++ b/runtime/bk-plugin-runtime/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bk-plugin-runtime" -version = "2.1.3rc3" +version = "2.1.3rc4" description = "bk plugin python django runtime" authors = ["Your Name "] license = "MIT" From 10fc9deb387eaaa32fe07cdd1bbcd0275b82f499 Mon Sep 17 00:00:00 2001 From: Xinkai Yi Date: Tue, 20 Jan 2026 17:45:47 +0800 Subject: [PATCH 21/21] =?UTF-8?q?fix:=20pre-commit=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=A0=BC=E5=BC=8F=20--story=3D130029514?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commands/sync_apigateway_if_changed.py | 49 ++++++------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py index 2ba65b4..60da989 100644 --- a/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py +++ b/bk-plugin-framework/bk_plugin_framework/services/bpf_service/management/commands/sync_apigateway_if_changed.py @@ -85,11 +85,7 @@ def handle(self, *args, **options): step_start = time.time() need_sync = force_sync or current_hash != last_hash if not need_sync: - self.stdout.write( - self.style.SUCCESS( - "[Sync] API definition unchanged, skip sync to apigateway" - ) - ) + self.stdout.write(self.style.SUCCESS("[Sync] API definition unchanged, skip sync to apigateway")) # 仍然获取公钥,确保公钥是最新的 self._fetch_public_key() step_timings["4. 对比决定是否同步"] = (time.time() - step_start) * 1000 @@ -101,9 +97,7 @@ def handle(self, *args, **options): if force_sync: self.stdout.write(self.style.WARNING("[Sync] Force sync enabled")) else: - self.stdout.write( - self.style.WARNING("[Sync] API definition changed, start syncing...") - ) + self.stdout.write(self.style.WARNING("[Sync] API definition changed, start syncing...")) # 5. 执行同步 step_start = time.time() @@ -125,9 +119,7 @@ def handle(self, *args, **options): # 7. 更新哈希值 step_start = time.time() self._save_sync_hash(current_hash, success=True) - self.stdout.write( - self.style.SUCCESS("[Sync] API gateway sync completed successfully") - ) + self.stdout.write(self.style.SUCCESS("[Sync] API gateway sync completed successfully")) step_timings["7. 更新哈希值"] = (time.time() - step_start) * 1000 # 打印耗时统计 @@ -162,21 +154,15 @@ def _copy_support_files_resources(self): # 检查 support-files/resources.yaml 是否存在 if not os.path.exists(support_filepath): - self.stderr.write( - self.style.ERROR(f"[Sync] support-files/resources.yaml not found: {support_filepath}") - ) + self.stderr.write(self.style.ERROR(f"[Sync] support-files/resources.yaml not found: {support_filepath}")) raise SystemExit(1) try: # 直接复制文件 shutil.copy2(support_filepath, target_filepath) - self.stdout.write( - self.style.SUCCESS(f"[Sync] Copied support-files/resources.yaml to {target_filepath}") - ) + self.stdout.write(self.style.SUCCESS(f"[Sync] Copied support-files/resources.yaml to {target_filepath}")) except Exception as e: - self.stderr.write( - self.style.ERROR(f"[Sync] Failed to copy support-files/resources.yaml: {e}") - ) + self.stderr.write(self.style.ERROR(f"[Sync] Failed to copy support-files/resources.yaml: {e}")) raise SystemExit(1) def _calculate_resources_hash(self): @@ -190,7 +176,7 @@ def _calculate_resources_hash(self): filepath = os.path.join(settings.BASE_DIR, "resources.yaml") if os.path.exists(filepath): try: - with open(filepath, "r", encoding="utf-8") as f: + with open(filepath, encoding="utf-8") as f: data = yaml.safe_load(f) if data: @@ -198,18 +184,17 @@ def _calculate_resources_hash(self): # 这样即使原始文件中 A,B,C 和 B,C,A 的顺序不同, # 规范化后的内容也会相同,从而产生相同的 hash normalized_content = yaml.dump( - data, - default_flow_style=False, - allow_unicode=True, - sort_keys=True # 关键:排序所有 key + data, default_flow_style=False, allow_unicode=True, sort_keys=True # 关键:排序所有 key ) return hashlib.sha256(normalized_content.encode()).hexdigest() except Exception as e: self.stdout.write( - self.style.WARNING(f"[Sync] Failed to normalize resources.yaml for hash: {e}, fallback to raw content hash") + self.style.WARNING( + f"[Sync] Failed to normalize resources.yaml for hash: {e}, fallback to raw content hash" + ) ) # 回退到原始方式 - with open(filepath, "r", encoding="utf-8") as f: + with open(filepath, encoding="utf-8") as f: content = f.read() return hashlib.sha256(content.encode()).hexdigest() return "" @@ -224,9 +209,7 @@ def _get_last_sync_hash(self): state = APIGatewaySyncState.objects.filter(sync_success=True).first() return state.api_hash if state else "" except Exception as e: - self.stdout.write( - self.style.WARNING(f"[Sync] Failed to get last sync hash: {e}") - ) + self.stdout.write(self.style.WARNING(f"[Sync] Failed to get last sync hash: {e}")) return "" def _save_sync_hash(self, hash_value, success=True): @@ -242,9 +225,7 @@ def _save_sync_hash(self, hash_value, success=True): ) self.stdout.write(f"[Sync] Sync state saved (success={success})") except Exception as e: - self.stdout.write( - self.style.WARNING(f"[Sync] Failed to save sync hash: {e}") - ) + self.stdout.write(self.style.WARNING(f"[Sync] Failed to save sync hash: {e}")) def _fetch_public_key(self): """获取 API 网关公钥""" @@ -253,4 +234,4 @@ def _fetch_public_key(self): call_command("fetch_apigw_public_key") except Exception as e: self.stderr.write(self.style.ERROR(f"run fetch_apigw_public_key fail: {e}")) - raise SystemExit(1) \ No newline at end of file + raise SystemExit(1)