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

* 资源导入时,支持旧版本 yaml 中的 upstreams/transform_headers #281

Merged
merged 12 commits into from
Oct 13, 2023
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# -*- 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.
#
# 1.13 版本:兼容旧版 (api_version=0.1) 资源 yaml 通过 openapi 导入
import re

from django.utils.translation import gettext as _
from rest_framework import serializers

from apigateway.core.constants import DEFAULT_LB_HOST_WEIGHT, STAGE_VAR_REFERENCE_PATTERN, LoadBalanceTypeEnum

# 通过 openapi 导入时,只允许导入使用环境变量的后端地址
RESOURCE_DOMAIN_PATTERN = re.compile(r"^http(s)?:\/\/\{%s\}$" % (STAGE_VAR_REFERENCE_PATTERN.pattern))

HEADER_KEY_PATTERN = re.compile(r"^[a-zA-Z0-9-]{1,100}$")


class LegacyResourceHostSLZ(serializers.Serializer):
host = serializers.RegexField(RESOURCE_DOMAIN_PATTERN)
weight = serializers.IntegerField(min_value=1, default=DEFAULT_LB_HOST_WEIGHT)


class LegacyUpstreamsSLZ(serializers.Serializer):
loadbalance = serializers.ChoiceField(choices=LoadBalanceTypeEnum.get_choices(), required=False)
hosts = serializers.ListField(child=LegacyResourceHostSLZ(), allow_empty=False, required=False)

def validate(self, data):
if "hosts" in data and not data.get("loadbalance"):
raise serializers.ValidationError(_("hosts 存在时,需要指定 loadbalance 类型。"))

return data


class LegacyTransformHeadersSLZ(serializers.Serializer):
set = serializers.DictField(label="设置", child=serializers.CharField(), required=False, allow_empty=True)
delete = serializers.ListField(label="删除", child=serializers.CharField(), required=False, allow_empty=True)

def _validate_headers_key(self, value):
for key in value:
if not HEADER_KEY_PATTERN.match(key):
raise serializers.ValidationError(_("Header 键由字母、数字、连接符(-)组成,长度小于100个字符。"))
return value

def validate_set(self, value):
return self._validate_headers_key(value)

def validate_delete(self, value):
return self._validate_headers_key(value)
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from apigateway.core.utils import get_path_display

from .constants import MAX_LABEL_COUNT_PER_RESOURCE, PATH_PATTERN, RESOURCE_NAME_PATTERN
from .legacy_serializers import LegacyTransformHeadersSLZ, LegacyUpstreamsSLZ


class ResourceQueryInputSLZ(serializers.Serializer):
Expand Down Expand Up @@ -119,6 +120,9 @@ class HttpBackendConfigSLZ(serializers.Serializer):
path = serializers.RegexField(PATH_PATTERN)
match_subpath = serializers.BooleanField(required=False)
timeout = serializers.IntegerField(max_value=MAX_BACKEND_TIMEOUT_IN_SECOND, min_value=0, required=False)
# 1.13 版本: 兼容旧版 (api_version=0.1) 资源 yaml 通过 openapi 导入
legacy_upstreams = LegacyUpstreamsSLZ(allow_null=True, required=False)
legacy_transform_headers = LegacyTransformHeadersSLZ(allow_null=True, required=False)


class ResourceInputSLZ(serializers.ModelSerializer):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
from apigateway.core.constants import DEFAULT_BACKEND_NAME, HTTP_METHOD_ANY
from apigateway.core.models import Backend, Gateway, Resource

from .legacy_synchronizers import LegacyTransformHeadersToPluginSynchronizer, LegacyUpstreamToBackendSynchronizer

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -329,9 +331,15 @@ def import_resources(self):
# 3. 补全标签 ID 数据
self._complete_label_ids()

# 4. 创建或更新资源
# 4. [legacy upstreams] 创建或更新 backend,并替换资源对应的 backend
self._sync_legacy_upstreams_to_backend_and_replace_resource_backend()

# 5. 创建或更新资源
self._create_or_update_resources()

# 6. [legacy transform-headers] 将 transform-headers 转换为 bk-header-rewrite 插件,并绑定到资源
self._sync_legacy_transform_headers_to_plugins()

def get_selected_resource_data_list(self) -> List[ResourceData]:
return self.resource_data_list

Expand Down Expand Up @@ -387,3 +395,13 @@ def _create_or_update_resources(self) -> List[Resource]:
username=self.username,
)
return saver.save()

def _sync_legacy_upstreams_to_backend_and_replace_resource_backend(self):
"""根据 backend_config 中的 legacy_upstreams 创建 backend,并替换 resource_data_list 中资源关联的 backend"""
synchronizer = LegacyUpstreamToBackendSynchronizer(self.gateway, self.resource_data_list, self.username)
synchronizer.sync_backends_and_replace_resource_backend()

def _sync_legacy_transform_headers_to_plugins(self):
"""根据 backend_config 中的 legacy_transform_headers 创建 bk-header-rewrite 插件,并绑定到资源"""
synchronizer = LegacyTransformHeadersToPluginSynchronizer(self.gateway, self.resource_data_list, self.username)
synchronizer.sync_plugins()
Loading