Skip to content

Commit

Permalink
Merge pull request #686 from TencentBlueKing/master
Browse files Browse the repository at this point in the history
  • Loading branch information
wklken authored Jun 11, 2024
2 parents b7f1f9d + da7a338 commit 406610c
Show file tree
Hide file tree
Showing 104 changed files with 4,255 additions and 88 deletions.
4 changes: 2 additions & 2 deletions src/dashboard-front/src/http/backends.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import fetch from './fetch';
// import { json2Query } from '@/common/util';
import { json2Query } from '@/common/util';

const { BK_DASHBOARD_URL } = window;

// 获取后端服务列表
export const getBackendsListData = (apigwId: number) => fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/backends/`);
export const getBackendsListData = (apigwId: number, data = {}) => fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/backends/?${json2Query(data)}`);

// 获取后端服务详情
export const getBackendsDetailData = (apigwId: number, backendId: number) => fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/backends/${backendId}/`);
2 changes: 1 addition & 1 deletion src/dashboard-front/src/views/basic-info/common/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface BasicInfoParams {
created_time: string
public_key: string
is_official: boolean
publish_validate_msg: string
publish_validate_msg?: string
}

export interface DialogParams {
Expand Down
5 changes: 4 additions & 1 deletion src/dashboard-front/src/views/basic-info/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,10 @@ const handleOperate = async (type: string) => {

if (['edit'].includes(type)) {
basicInfoDetailData.value = _.cloneDeep(basicInfoData.value);
dialogEditData.value.isShow = true;
console.log('basicInfoDetailData.value', basicInfoDetailData.value);
setTimeout(() => {
dialogEditData.value.isShow = true;
}, 500);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,22 @@
<bk-select
:input-search="false"
class="service"
:popoverOptions="{ extCls: 'service-select-popover' }"
v-model="backConfigData.id" @change="handleServiceChange">
<bk-option v-for="item in servicesData" :key="item.id" :value="item.id" :label="item.name" />
<!-- <bk-option v-for="item in servicesData" :key="item.id" :value="item.id" :label="item.name" /> -->
<bk-option
v-for="(item, index) in servicesData"
:value="item.id"
:key="index"
:label="item.name"
>
<div class="service-select-item">
<span>{{item.name}}</span>
<template v-if="item.description">
<span class="desc" :title="item.description">({{item.description}})</span>
</template>
</div>
</bk-option>
</bk-select>
<bk-button theme="primary" class="ml10" v-if="isEditService" @click="editService">
编辑服务
Expand Down Expand Up @@ -458,7 +472,7 @@ const handleMouseLeave = (e: Event, row: Record<string, number | string | boolea
};

const init = async () => {
const res = await getBackendsListData(common.apigwId);
const res = await getBackendsListData(common.apigwId, { offset: 0, limit: 1000 });
servicesData.value = res.results;
};

Expand Down Expand Up @@ -566,19 +580,34 @@ defineExpose({
top: -2px;
font-size: 24px;
cursor: pointer;
color: #3A84FF;
color: #3a84ff;
}
}
}

.service-select-popover {
.service-select-item {
display: flex;
}
.desc {
color: #979ba5;
margin-left: 6px;
width: 560px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: inline-block;
}
}

:deep(.back-config-timeout) {
display: inline-block;

.edit-action,
.refresh-icon {
margin-left: 8px;
font-size: 16px;
color: #3A84FF;
color: #3a84ff;
vertical-align: middle;
cursor: pointer;
}
Expand Down
172 changes: 122 additions & 50 deletions src/dashboard/apigateway/apigateway/apis/open/stage/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@ class StageProxyHTTPConfigSLZ(serializers.Serializer):
transform_headers = TransformHeadersSLZ(required=False, default=dict)


class BackendConfigSLZ(UpstreamsSLZ):
timeout = serializers.IntegerField(max_value=MAX_BACKEND_TIMEOUT_IN_SECOND, min_value=1)

class Meta:
ref_name = "apis.open.stage.BackendConfigSLZ"


class BackendSLZ(serializers.Serializer):
name = serializers.CharField(help_text="后端服务名称", required=True)
config = BackendConfigSLZ(allow_empty=False)

class Meta:
ref_name = "apis.open.stage.BackendSLZ"


class PluginConfigSLZ(serializers.Serializer):
type = serializers.CharField(help_text="插件类型名称")
yaml = serializers.CharField(help_text="插件yaml配置")
Expand All @@ -158,7 +173,9 @@ class StageSLZ(ExtensibleFieldMixin, serializers.ModelSerializer):
child=serializers.CharField(allow_blank=True, required=True),
default=dict,
)
proxy_http = StageProxyHTTPConfigSLZ()
proxy_http = StageProxyHTTPConfigSLZ(required=False)

backends = serializers.ListSerializer(help_text="后端配置", child=BackendSLZ(), allow_null=True, required=False)

plugin_configs = serializers.ListSerializer(
help_text="插件配置", child=PluginConfigSLZ(), allow_null=True, required=False
Expand All @@ -181,6 +198,7 @@ class Meta:
"vars",
"status",
"proxy_http",
"backends",
"plugin_configs",
"micro_gateway_id",
)
Expand All @@ -190,7 +208,7 @@ class Meta:
}
}
read_only_fields = ("id", "status")
non_model_fields = ["proxy_http", "plugin_configs", "rate_limit"]
non_model_fields = ["proxy_http", "backends", "plugin_configs", "rate_limit"]
lookup_field = "id"

validators = [
Expand All @@ -210,32 +228,63 @@ class Meta:
def validate(self, data):
self._validate_micro_gateway_stage_unique(data.get("micro_gateway_id"))
self._validate_plugin_configs(data.get("plugin_configs"))
# validate stage backend
if data.get("proxy_http") is None and data.get("backends") is None:
raise serializers.ValidationError(_("proxy_http or backends 必须要选择一种方式配置后端服务"))
return data

def create(self, validated_data):
# 1. save stage
instance = super().create(validated_data)

proxy_http_config = validated_data["proxy_http"]

# 2. create default backend
backend, _ = Backend.objects.get_or_create(
gateway=instance.gateway,
name=DEFAULT_BACKEND_NAME,
)

config = self._get_stage_backend_config(proxy_http_config)
backend_config = BackendConfig(
gateway=instance.gateway,
backend=backend,
stage=instance,
config=config,
)
backend_config.save()
proxy_http_config = validated_data.get("proxy_http")
# 兼容老的配置
if proxy_http_config is not None and len(proxy_http_config) != 0:
config = self._get_stage_backend_config(proxy_http_config)
backend_config = BackendConfig(
gateway=instance.gateway,
backend=backend,
stage=instance,
config=config,
)
backend_config.save()

# create or update header rewrite plugin config
stage_transform_headers = proxy_http_config.get("transform_headers") or {}
stage_config = HeaderRewriteConvertor.transform_headers_to_plugin_config(stage_transform_headers)
HeaderRewriteConvertor.sync_plugins(
instance.gateway_id,
PluginBindingScopeEnum.STAGE.value,
{instance.id: stage_config},
self.context["request"].user.username,
)

# 3. create other backend config with empty host
backends = Backend.objects.filter(gateway=instance.gateway).exclude(name=DEFAULT_BACKEND_NAME)
# 3.create config backend
backend_configs = []
names = [DEFAULT_BACKEND_NAME]
for backend_info in validated_data.get("backends", []):
names.append(backend_info["name"])
backend, _ = Backend.objects.get_or_create(
gateway=instance.gateway,
name=backend_info["name"],
)
config = self._get_stage_backend_config_v2(backend_info)
backend_config = BackendConfig(
gateway=instance.gateway,
backend=backend,
stage=instance,
config=config,
)
backend_configs.append(backend_config)

# 4. create other backend config with empty host
backends = Backend.objects.filter(gateway=instance.gateway).exclude(name__in=names)
config = {
"type": "node",
"timeout": 30,
Expand All @@ -255,16 +304,6 @@ def create(self, validated_data):
if backend_configs:
BackendConfig.objects.bulk_create(backend_configs)

# 4. create or update header rewrite plugin config
stage_transform_headers = proxy_http_config.get("transform_headers") or {}
stage_config = HeaderRewriteConvertor.transform_headers_to_plugin_config(stage_transform_headers)
HeaderRewriteConvertor.sync_plugins(
instance.gateway_id,
PluginBindingScopeEnum.STAGE.value,
{instance.id: stage_config},
self.context["request"].user.username,
)

# 5. sync stage plugin
self._sync_plugins(instance.gateway_id, instance.id, validated_data.get("plugin_configs", None))

Expand All @@ -283,6 +322,19 @@ def _get_stage_backend_config(self, proxy_http_config):
"hosts": hosts,
}

def _get_stage_backend_config_v2(self, backend: dict):
hosts = []
for host in backend["config"]["hosts"]:
scheme, _host = host["host"].rstrip("/").split("://")
hosts.append({"scheme": scheme, "host": _host, "weight": host["weight"]})

return {
"type": "node",
"timeout": backend["config"]["timeout"],
"loadbalance": backend["config"]["loadbalance"],
"hosts": hosts,
}

def update(self, instance, validated_data):
validated_data.pop("name", None)
# 仅能通过发布更新 status,不允许直接更新 status
Expand All @@ -292,38 +344,58 @@ def update(self, instance, validated_data):
# 1. 更新数据
instance = super().update(instance, validated_data)

proxy_http_config = validated_data["proxy_http"]

# 2. create default backend
backend, _ = Backend.objects.get_or_create(
gateway=instance.gateway,
name=DEFAULT_BACKEND_NAME,
)

backend_config = BackendConfig.objects.filter(
gateway=instance.gateway,
backend=backend,
stage=instance,
).first()
if not backend_config:
backend_config = BackendConfig(
proxy_http_config = validated_data.get("proxy_http")
if proxy_http_config is not None and len(proxy_http_config) != 0:
backend, _ = Backend.objects.get_or_create(
gateway=instance.gateway,
name=DEFAULT_BACKEND_NAME,
)
backend_config = BackendConfig.objects.filter(
gateway=instance.gateway,
backend=backend,
stage=instance,
).first()
if not backend_config:
backend_config = BackendConfig(
gateway=instance.gateway,
backend=backend,
stage=instance,
)

backend_config.config = self._get_stage_backend_config(proxy_http_config)
backend_config.save()

# create or update header rewrite plugin config
stage_transform_headers = proxy_http_config.get("transform_headers") or {}
stage_config = HeaderRewriteConvertor.transform_headers_to_plugin_config(stage_transform_headers)
HeaderRewriteConvertor.sync_plugins(
instance.gateway_id,
PluginBindingScopeEnum.STAGE.value,
{instance.id: stage_config},
self.context["request"].user.username,
)

backend_config.config = self._get_stage_backend_config(proxy_http_config)
backend_config.save()

# 3. create or update header rewrite plugin config
stage_transform_headers = proxy_http_config.get("transform_headers") or {}
stage_config = HeaderRewriteConvertor.transform_headers_to_plugin_config(stage_transform_headers)
HeaderRewriteConvertor.sync_plugins(
instance.gateway_id,
PluginBindingScopeEnum.STAGE.value,
{instance.id: stage_config},
self.context["request"].user.username,
)
# 3. update backend
for backend_info in validated_data.get("backends", []):
backend, _ = Backend.objects.get_or_create(
gateway=instance.gateway,
name=backend_info["name"],
)
backend_config = BackendConfig.objects.filter(
gateway=instance.gateway,
backend=backend,
stage=instance,
).first()

if not backend_config:
backend_config = BackendConfig(
gateway=instance.gateway,
backend=backend,
stage=instance,
)
backend_config.config = self._get_stage_backend_config_v2(backend_info)
backend_config.save()

# 4. sync stage plugin
self._sync_plugins(instance.gateway_id, instance.id, validated_data.get("plugin_configs", None))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ class Meta:
validators = [
MaxCountPerGatewayValidator(
Resource,
max_count_callback=lambda gateway: GatewayHandler.get_max_resource_count(gateway),
max_count_callback=lambda gateway: GatewayHandler.get_max_resource_count(gateway.name),
message=gettext_lazy("每个网关最多创建 {max_count} 个资源。"),
),
UniqueTogetherValidator(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def send_mail_for_perm_apply(record_id):
"expire_days_display": PermissionApplyExpireDaysEnum.get_choice_label(record.expire_days),
"grant_dimension_display": GrantDimensionEnum.get_choice_label(record.grant_dimension),
"resource_names": sorted(manager.get_resource_names_display(record.gateway.id, record.resource_ids)),
"perm_apply_link": f"{apigw_domain}/{record.gateway_id}/permission/applys",
"perm_apply_link": f"{apigw_domain}/{record.gateway_id}/permission/apply",
},
)

Expand Down
4 changes: 2 additions & 2 deletions src/dashboard/apigateway/apigateway/biz/resource/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,10 @@ def filter_by_resource_filter_condition(gateway_id: int, condition: Dict[str, An
queryset = Resource.objects.filter(gateway_id=gateway_id)

if condition.get("name"):
queryset = queryset.filter(name=condition["name"])
queryset = queryset.filter(name__icontains=condition["name"])

if condition.get("path"):
queryset = queryset.filter(path=condition["path"])
queryset = queryset.filter(path__icontains=condition["path"])

if condition.get("method"):
queryset = queryset.filter(method__in=condition["method"].split(","))
Expand Down
2 changes: 1 addition & 1 deletion src/dashboard/apigateway/apigateway/conf/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@
REDIS_SENTINEL_ADDR_LIST = [tuple(addr.split(":")) for addr in REDIS_SENTINEL_ADDR_STR.split(",") if addr]
# redis lock 配置
REDIS_PUBLISH_LOCK_TIMEOUT = env.int("BK_APIGW_PUBLISH_LOCK_TIMEOUT", 5)
REDIS_PUBLISH_LOCK_RETRY_GET_TIMES = env.int("BK_APIGW_PUBLISH_LOCK_RETRY_GET_TIMES", 1)
REDIS_PUBLISH_LOCK_RETRY_GET_TIMES = env.int("BK_APIGW_PUBLISH_LOCK_RETRY_GET_TIMES", 3)

DEFAULT_REDIS_CONFIG = CHANNEL_REDIS_CONFIG = {
"host": REDIS_HOST,
Expand Down
Loading

0 comments on commit 406610c

Please sign in to comment.