Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add gateway app binding #330

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,8 @@ def get_user_auth_type(self, obj):
return self.context["gateway_auth_configs"][obj.id].user_auth_type

def get_maintainers(self, obj):
# 网关对外的维护者,便于用户咨询网关问题,默认使用开发者;maintainers 为有权限管理网关的管理者
# TODO: 是否应该使用开发者,如何让网关管理员知道开发者用于 API 文档中展示为网关的维护者
return obj.developers or obj.maintainers
# TODO: 网关对外的维护者(助手号),便于用户咨询网关问题,需要单独使用一个新字段去维护?
return obj.maintainers


class GatewayRetrieveV1OutputSLZ(GatewayListV1OutputSLZ):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from rest_framework.validators import UniqueTogetherValidator
from tencent_apigateway_common.i18n.field import SerializerTranslatedField

from apigateway.biz.constants import APP_CODE_PATTERN
from apigateway.biz.gateway import GatewayHandler
from apigateway.biz.gateway_type import GatewayTypeHandler
from apigateway.core.constants import (
Expand Down Expand Up @@ -83,6 +84,9 @@ class GatewayCreateInputSLZ(serializers.ModelSerializer):
developers = serializers.ListField(
child=serializers.CharField(), allow_empty=True, default=list, help_text="网关开发者"
)
bk_app_codes = serializers.ListField(
child=serializers.RegexField(APP_CODE_PATTERN), allow_empty=True, required=False, help_text="网关关联的应用"
)

class Meta:
model = Gateway
Expand All @@ -92,6 +96,7 @@ class Meta:
"maintainers",
"developers",
"is_public",
"bk_app_codes",
)
lookup_field = "id"

Expand Down Expand Up @@ -140,6 +145,7 @@ class GatewayRetrieveOutputSLZ(serializers.ModelSerializer):
docs_url = serializers.SerializerMethodField(help_text="文档地址")
public_key_fingerprint = serializers.SerializerMethodField(help_text="公钥(指纹)")
allow_update_gateway_auth = serializers.SerializerMethodField(help_text="是否允许更新网关认证配置")
bk_app_codes = serializers.SerializerMethodField(help_text="网关关联的应用")

class Meta:
model = Gateway
Expand All @@ -159,6 +165,7 @@ class Meta:
"api_domain",
"docs_url",
"public_key_fingerprint",
"bk_app_codes",
)
read_only_fields = fields
lookup_field = "id"
Expand Down Expand Up @@ -199,12 +206,18 @@ def get_allow_update_gateway_auth(self, obj):
def get_is_official(self, obj):
return GatewayTypeHandler.is_official(self.context["auth_config"].gateway_type)

def get_bk_app_codes(self, obj):
return self.context["bk_app_codes"]


class GatewayUpdateInputSLZ(serializers.ModelSerializer):
maintainers = serializers.ListField(child=serializers.CharField(), allow_empty=True, help_text="网关维护人员")
developers = serializers.ListField(
child=serializers.CharField(), allow_empty=True, default=list, help_text="网关开发者"
)
bk_app_codes = serializers.ListField(
child=serializers.RegexField(APP_CODE_PATTERN), allow_empty=True, required=False, help_text="网关关联的应用"
)

class Meta:
model = Gateway
Expand All @@ -213,6 +226,7 @@ class Meta:
"maintainers",
"developers",
"is_public",
"bk_app_codes",
)
lookup_field = "id"

Expand Down
10 changes: 10 additions & 0 deletions src/dashboard/apigateway/apigateway/apis/web/gateway/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from apigateway.apis.web.constants import UserAuthTypeEnum
from apigateway.apps.audit.constants import OpTypeEnum
from apigateway.biz.gateway import GatewayHandler
from apigateway.biz.gateway_app_binding import GatewayAppBindingHandler
from apigateway.common.contexts import GatewayAuthContext
from apigateway.common.error_codes import error_codes
from apigateway.common.release.publish import trigger_gateway_publish
Expand Down Expand Up @@ -104,6 +105,8 @@ def create(self, request, *args, **kwargs):
slz = GatewayCreateInputSLZ(data=request.data, context={"created_by": request.user.username})
slz.is_valid(raise_exception=True)

bk_app_codes = slz.validated_data.pop("bk_app_codes", None)

# 1. save gateway
slz.save(
status=GatewayStatusEnum.ACTIVE.value,
Expand All @@ -116,6 +119,7 @@ def create(self, request, *args, **kwargs):
gateway=slz.instance,
user_auth_type=UserAuthTypeEnum(settings.DEFAULT_USER_AUTH_TYPE).value,
username=request.user.username,
app_codes_to_binding=bk_app_codes,
)

# 3. record audit log
Expand Down Expand Up @@ -175,6 +179,7 @@ def retrieve(self, request, *args, **kwargs):
instance,
context={
"auth_config": GatewayAuthContext().get_auth_config(instance.pk),
"bk_app_codes": GatewayAppBindingHandler.get_bound_app_codes(instance),
},
)
return OKJsonResponse(data=slz.data)
Expand All @@ -186,8 +191,13 @@ def update(self, request, *args, **kwargs):
slz = GatewayUpdateInputSLZ(instance=instance, data=request.data, partial=partial)
slz.is_valid(raise_exception=True)

bk_app_codes = slz.validated_data.pop("bk_app_codes", None)

slz.save(updated_by=request.user.username)

if bk_app_codes is not None:
GatewayAppBindingHandler.update_gateway_app_bindings(instance, bk_app_codes)

GatewayHandler.record_audit_log_success(
username=request.user.username,
gateway_id=instance.id,
Expand Down
17 changes: 17 additions & 0 deletions src/dashboard/apigateway/apigateway/apps/gateway/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# TencentBlueKing is pleased to support the open source community by making
# 蓝鲸智云 - API 网关(BlueKing - APIGateway) 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.
#
# We undertake not to change the open source license (MIT license) applicable
# to the current version of the project delivered to anyone in the future.
#
29 changes: 29 additions & 0 deletions src/dashboard/apigateway/apigateway/apps/gateway/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#
# TencentBlueKing is pleased to support the open source community by making
# 蓝鲸智云 - API 网关(BlueKing - APIGateway) 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.
#
# We undertake not to change the open source license (MIT license) applicable
# to the current version of the project delivered to anyone in the future.
#
from django.contrib import admin

from .models import GatewayAppBinding


class GatewayAppBindingAdmin(admin.ModelAdmin):
list_display = ["id", "gateway", "bk_app_code", "updated_time"]
search_fields = ["gateway__id", "bk_app_code"]
list_filter = ["gateway"]


admin.site.register(GatewayAppBinding, GatewayAppBindingAdmin)
22 changes: 22 additions & 0 deletions src/dashboard/apigateway/apigateway/apps/gateway/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# TencentBlueKing is pleased to support the open source community by making
# 蓝鲸智云 - API 网关(BlueKing - APIGateway) 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.
#
# We undertake not to change the open source license (MIT license) applicable
# to the current version of the project delivered to anyone in the future.
#
from django.apps import AppConfig


class GatewayConfig(AppConfig):
name = "apigateway.apps.gateway"
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#
# TencentBlueKing is pleased to support the open source community by making
# 蓝鲸智云 - API 网关(BlueKing - APIGateway) 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.
#
# We undertake not to change the open source license (MIT license) applicable
# to the current version of the project delivered to anyone in the future.
#
# Generated by Django 3.2.18 on 2023-11-08 04:35

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
('core', '0032_gateway__developers'),
]

operations = [
migrations.CreateModel(
name='GatewayAppBinding',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_time', models.DateTimeField(auto_now_add=True, null=True)),
('updated_time', models.DateTimeField(auto_now=True, null=True)),
('created_by', models.CharField(blank=True, max_length=32, null=True)),
('updated_by', models.CharField(blank=True, max_length=32, null=True)),
('bk_app_code', models.CharField(db_index=True, max_length=32)),
('gateway', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.gateway')),
],
options={
'db_table': 'gateway_app_binding',
'unique_together': {('gateway', 'bk_app_code')},
},
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# TencentBlueKing is pleased to support the open source community by making
# 蓝鲸智云 - API 网关(BlueKing - APIGateway) 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.
#
# We undertake not to change the open source license (MIT license) applicable
# to the current version of the project delivered to anyone in the future.
#
39 changes: 39 additions & 0 deletions src/dashboard/apigateway/apigateway/apps/gateway/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
#
# TencentBlueKing is pleased to support the open source community by making
# 蓝鲸智云 - API 网关(BlueKing - APIGateway) 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.
#
# We undertake not to change the open source license (MIT license) applicable
# to the current version of the project delivered to anyone in the future.
#
from django.db import models

from apigateway.common.mixins.models import OperatorModelMixin, TimestampedModelMixin
from apigateway.core.models import Gateway


class GatewayAppBinding(TimestampedModelMixin, OperatorModelMixin):
"""
网关绑定的蓝鲸应用
- 仅影响 HomePage 中运维开发分数的计算
"""

gateway = models.ForeignKey(Gateway, on_delete=models.CASCADE)
bk_app_code = models.CharField(max_length=32, db_index=True)

def __str__(self):
return f"<GatewayAppBinding: {self.bk_app_code}/{self.gateway_id}>"

class Meta:
db_table = "gateway_app_binding"
unique_together = ("gateway", "bk_app_code")
8 changes: 7 additions & 1 deletion src/dashboard/apigateway/apigateway/biz/gateway/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from apigateway.apps.monitor.models import AlarmStrategy
from apigateway.apps.plugin.models import PluginBinding
from apigateway.apps.support.models import ReleasedResourceDoc
from apigateway.biz.gateway_app_binding import GatewayAppBindingHandler
from apigateway.biz.gateway_jwt import GatewayJWTHandler
from apigateway.biz.gateway_related_app import GatewayRelatedAppHandler
from apigateway.biz.iam import IAMHandler
Expand Down Expand Up @@ -149,6 +150,7 @@ def save_related_data(
user_config: Optional[dict] = None,
unfiltered_sensitive_keys: Optional[List[str]] = None,
api_type: Optional[GatewayTypeEnum] = None,
app_codes_to_binding: Optional[List[str]] = None,
):
# 1. save gateway auth_config
GatewayHandler.save_auth_config(
Expand All @@ -175,7 +177,11 @@ def save_related_data(
if related_app_code:
GatewayRelatedAppHandler.add_related_app(gateway.id, related_app_code)

# 6. 在权限中心注册分级管理员,创建用户组
# 6. update gateway app binding
if app_codes_to_binding is not None:
GatewayAppBindingHandler.update_gateway_app_bindings(gateway, app_codes_to_binding)

# 7. 在权限中心注册分级管理员,创建用户组
if settings.USE_BK_IAM_PERMISSION:
IAMHandler.register_grade_manager_and_builtin_user_groups(gateway)

Expand Down
48 changes: 48 additions & 0 deletions src/dashboard/apigateway/apigateway/biz/gateway_app_binding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
#
# TencentBlueKing is pleased to support the open source community by making
# 蓝鲸智云 - API 网关(BlueKing - APIGateway) 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.
#
# We undertake not to change the open source license (MIT license) applicable
# to the current version of the project delivered to anyone in the future.
#
from typing import List

from apigateway.apps.gateway.models import GatewayAppBinding
from apigateway.core.models import Gateway


class GatewayAppBindingHandler:
@classmethod
def update_gateway_app_bindings(cls, gateway: Gateway, bk_app_codes: List[str]):
"""
更新网关应用的绑定
- 1. 如果 bk_app_codes 中应用未绑定,则新增绑定
- 2. 如果已绑定的应用未在 bk_app_codes 中,则删除
"""
bound_app_codes = cls.get_bound_app_codes(gateway)
app_codes_to_add = set(bk_app_codes) - set(bound_app_codes)
app_codes_to_delete = set(bound_app_codes) - set(bk_app_codes)

if app_codes_to_add:
GatewayAppBinding.objects.bulk_create(
[GatewayAppBinding(gateway=gateway, bk_app_code=code) for code in app_codes_to_add]
)

if app_codes_to_delete:
GatewayAppBinding.objects.filter(gateway=gateway, bk_app_code__in=app_codes_to_delete).delete()

@staticmethod
def get_bound_app_codes(gateway: Gateway) -> List[str]:
"""获取已绑定的应用"""
return list(GatewayAppBinding.objects.filter(gateway=gateway).values_list("bk_app_code", flat=True))
Loading