Skip to content

Commit

Permalink
feat: added JsonSchema support for custom data source plugin configur…
Browse files Browse the repository at this point in the history
…ation (#1902)
  • Loading branch information
rolin999 authored Aug 26, 2024
1 parent 910d0f6 commit 01d0911
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 5 deletions.
24 changes: 24 additions & 0 deletions src/bk-user/bkuser/apis/web/data_source/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
"""
TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available.
Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""

import json
from typing import Any, Dict

import jsonref

from bkuser.plugins.base import get_plugin_cfg_cls


def get_data_source_plugin_cfg_json_schema(plugin_id: str) -> Dict[str, Any]:
"""获取数据源插件配置类的 JsonSchema, without any jsonRef"""
json_schema = get_plugin_cfg_cls(plugin_id).model_json_schema()
# replace json refs
return jsonref.loads((json.dumps(json_schema)))
5 changes: 5 additions & 0 deletions src/bk-user/bkuser/apis/web/data_source/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,3 +363,8 @@ class DataSourceSyncRecordRetrieveOutputSLZ(serializers.Serializer):

class DataSourceDestroyInputSLZ(serializers.Serializer):
is_delete_idp = serializers.BooleanField(help_text="重置数据源时是否同时删除 Idp 相关配置", default=False)


class DataSourcePluginConfigMetaRetrieveOutputSLZ(serializers.Serializer):
id = serializers.CharField(help_text="数据源插件唯一标识")
json_schema = serializers.JSONField(help_text="配置的 JSON Schema")
7 changes: 7 additions & 0 deletions src/bk-user/bkuser/apis/web/data_source/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
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.urls import path

from bkuser.apis.web.data_source import views
Expand Down Expand Up @@ -91,4 +92,10 @@
views.DataSourceSyncApi.as_view(),
name="data_source.sync",
),
# 数据源插件配置元数据
path(
"plugins/<str:id>/config-meta/",
views.DataSourcePluginConfigMetaRetrieveApi.as_view(),
name="data_source_plugin.config_meta.retrieve",
),
]
27 changes: 27 additions & 0 deletions src/bk-user/bkuser/apis/web/data_source/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
DataSourceImportOrSyncOutputSLZ,
DataSourceListInputSLZ,
DataSourceListOutputSLZ,
DataSourcePluginConfigMetaRetrieveOutputSLZ,
DataSourcePluginDefaultConfigOutputSLZ,
DataSourcePluginOutputSLZ,
DataSourceRandomPasswordInputSLZ,
Expand Down Expand Up @@ -72,6 +73,8 @@
from bkuser.plugins.base import get_default_plugin_cfg, get_plugin_cfg_schema_map, get_plugin_cls
from bkuser.plugins.constants import DataSourcePluginEnum

from .schema import get_data_source_plugin_cfg_json_schema

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -588,3 +591,27 @@ def get_queryset(self):
)
def get(self, request, *args, **kwargs):
return Response(DataSourceSyncRecordRetrieveOutputSLZ(instance=self.get_object()).data)


class DataSourcePluginConfigMetaRetrieveApi(generics.RetrieveAPIView):
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

queryset = DataSourcePlugin.objects.all()
lookup_url_kwarg = "id"

@swagger_auto_schema(
tags=["data_source"],
operation_description="数据源插件配置元数据",
responses={status.HTTP_200_OK: DataSourcePluginConfigMetaRetrieveOutputSLZ()},
)
def get(self, request, *args, **kwargs):
plugin = self.get_object()

try:
json_schema = get_data_source_plugin_cfg_json_schema(plugin.id)
except NotImplementedError:
raise error_codes.DATA_SOURCE_PLUGIN_NOT_LOAD

return Response(
DataSourcePluginConfigMetaRetrieveOutputSLZ(instance={"id": plugin.id, "json_schema": json_schema}).data
)
3 changes: 2 additions & 1 deletion src/bk-user/bkuser/apis/web/idp/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
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 re
from typing import Any, Dict

Expand Down Expand Up @@ -39,7 +40,7 @@ class IdpPluginOutputSLZ(serializers.Serializer):

class IdpPluginConfigMetaRetrieveOutputSLZ(serializers.Serializer):
id = serializers.CharField(help_text="认证源插件唯一标识")
json_schema = serializers.JSONField(help_text="配置的JSON Schema")
json_schema = serializers.JSONField(help_text="配置的 JSON Schema")


class IdpListOutputSLZ(serializers.Serializer):
Expand Down
3 changes: 2 additions & 1 deletion src/bk-user/bkuser/apis/web/idp/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
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.urls import path

from . import views
Expand All @@ -19,7 +20,7 @@
path(
"plugins/<str:id>/config-meta/",
views.IdpPluginConfigMetaRetrieveApi.as_view(),
name="idp_plugin_config_meta.retrieve",
name="idp_plugin.config_meta.retrieve",
),
# 本地账密登录,比较特殊单独 API
path("local/", views.LocalIdpCreateApi.as_view(), name="idp.local.create"),
Expand Down
7 changes: 4 additions & 3 deletions src/bk-user/bkuser/apis/web/idp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
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 transaction
from django.utils.translation import gettext_lazy as _
from drf_yasg.utils import swagger_auto_schema
Expand Down Expand Up @@ -75,15 +76,15 @@ class IdpPluginConfigMetaRetrieveApi(generics.RetrieveAPIView):
responses={status.HTTP_200_OK: IdpPluginConfigMetaRetrieveOutputSLZ()},
)
def get(self, request, *args, **kwargs):
instance = self.get_object()
plugin = self.get_object()

try:
json_schema = get_idp_plugin_cfg_json_schema(instance.id)
json_schema = get_idp_plugin_cfg_json_schema(plugin.id)
except NotImplementedError:
raise error_codes.IDP_PLUGIN_NOT_LOAD

return Response(
IdpPluginConfigMetaRetrieveOutputSLZ(instance={"id": instance.id, "json_schema": json_schema}).data
IdpPluginConfigMetaRetrieveOutputSLZ(instance={"id": plugin.id, "json_schema": json_schema}).data
)


Expand Down
1 change: 1 addition & 0 deletions src/bk-user/bkuser/common/error_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class ErrorCodes:

# 数据源插件
DATA_SOURCE_PLUGIN_NOT_DEFAULT_CONFIG = ErrorCode(_("当前数据源插件未提供默认配置"))
DATA_SOURCE_PLUGIN_NOT_LOAD = ErrorCode(_("数据源插件未加载"))

# 数据源
DATA_SOURCE_OPERATION_UNSUPPORTED = ErrorCode(_("当前数据源不支持该操作"))
Expand Down
20 changes: 20 additions & 0 deletions src/bk-user/tests/apis/web/data_source/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,23 @@ def test_retrieve(self, api_client):
def test_retrieve_not_exists(self, api_client):
resp = api_client.get(reverse("data_source_plugin.default_config", args=["not_exists"]))
assert resp.status_code == status.HTTP_404_NOT_FOUND


class TestDataSourcePluginConfigMetaRetrieveApi:
def test_retrieve_with_local_data_source_plugin(self, api_client):
resp = api_client.get(
reverse("data_source_plugin.config_meta.retrieve", args=[DataSourcePluginEnum.LOCAL.value])
)
assert resp.status_code == status.HTTP_200_OK
assert resp.data["json_schema"] != ""

def test_retrieve_with_general_data_source_plugin(self, api_client):
resp = api_client.get(
reverse("data_source_plugin.config_meta.retrieve", args=[DataSourcePluginEnum.GENERAL.value])
)
assert resp.status_code == status.HTTP_200_OK
assert resp.data["json_schema"] != ""

def test_retrieve_with_not_exists_data_source_plugin(self, api_client):
resp = api_client.get(reverse("data_source_plugin.config_meta.retrieve", args=["not_exists"]))
assert resp.status_code == status.HTTP_404_NOT_FOUND

0 comments on commit 01d0911

Please sign in to comment.