diff --git a/apiserver/paasng/paasng/accessories/log/views/config.py b/apiserver/paasng/paasng/accessories/log/views/config.py index 1fc93696af..7854e43083 100644 --- a/apiserver/paasng/paasng/accessories/log/views/config.py +++ b/apiserver/paasng/paasng/accessories/log/views/config.py @@ -28,6 +28,8 @@ from rest_framework.response import Response from rest_framework.viewsets import ViewSet +from paas_wl.infras.cluster.constants import ClusterFeatureFlag +from paas_wl.infras.cluster.shim import get_application_cluster from paasng.accessories.log.models import CustomCollectorConfig from paasng.accessories.log.serializers import ( BkLogCustomCollectMetadataOutputSLZ, @@ -83,6 +85,11 @@ def get_serializer_context(self): def get_metadata(self, request, code, module_name): """查询在日志平台已创建的自定义上报配置以及日志平台的访问地址""" application = self.get_application() + cluster = get_application_cluster(application) + if not cluster.has_feature_flag(ClusterFeatureFlag.ENABLE_BK_LOG_COLLECTOR): + # 集群未开启日志平台特性, 则直接返回,不再调用监控日志平台相关 API + raise error_codes.CUSTOM_COLLECTOR_UNSUPPORTED + module = self.get_module_via_path() slz = BkLogCustomCollectMetadataQuerySLZ(data=request.query_params) slz.is_valid(raise_exception=True) diff --git a/apiserver/paasng/paasng/platform/applications/management/commands/create_3rd_party_apps.py b/apiserver/paasng/paasng/platform/applications/management/commands/create_3rd_party_apps.py index 41e8cf1103..318f1fb61d 100644 --- a/apiserver/paasng/paasng/platform/applications/management/commands/create_3rd_party_apps.py +++ b/apiserver/paasng/paasng/platform/applications/management/commands/create_3rd_party_apps.py @@ -102,8 +102,9 @@ def handle(self, source, third_app_init_codes, override, dry_run, *args, **optio continue logger.info("going to create App according to desc: %s", f"{desc.name} - {desc.code}") + already_in_paas2 = bool(legacy_app) with atomic(): - self.create_3rd_app(desc) + self.create_3rd_app(desc, already_in_paas2) def get_app_secret_key(self, code: str) -> str: session = console_db.get_scoped_session() @@ -134,7 +135,7 @@ def create_oauth_client_by_code(self, code: str, region: str): create_oauth2_client(code, region) logger.info("create oauth app(code:%s) with a new randomly generated key", code) - def create_3rd_app(self, app_desc: Simple3rdAppDesc): + def create_3rd_app(self, app_desc: Simple3rdAppDesc, already_in_paas2: bool): try: application, created = Application.objects.update_or_create( code=app_desc.code, @@ -158,6 +159,10 @@ def create_3rd_app(self, app_desc: Simple3rdAppDesc): logger.exception("app initialize members failed, skip create: %s", e.message) return + # 新建的应用需要同步在桌面上创建(PaaS2.0),已经存在则不需要再创建 + # 添加 already_in_paas2 判断说明: + # bk_job、bk_cc 这些提前在桌面上创建过的应用就不会因为 应用ID 冲突回滚,导致无法在开发者中心上创建 + if created and (not already_in_paas2): try: before_finishing_application_creation.send("FakeSender", application=application) except IntegrityError as e: diff --git a/apiserver/paasng/paasng/platform/declarative/application/fields.py b/apiserver/paasng/paasng/platform/declarative/application/fields.py index a451e10d3f..30e3583bef 100644 --- a/apiserver/paasng/paasng/platform/declarative/application/fields.py +++ b/apiserver/paasng/paasng/platform/declarative/application/fields.py @@ -19,7 +19,7 @@ import logging from paasng.platform.applications.models import Application -from paasng.platform.declarative.application.constants import APP_NAME_FIELD +from paasng.platform.applications.signals import prepare_change_application_name from paasng.platform.declarative.application.resources import ApplicationDesc from paasng.platform.declarative.exceptions import DescriptionValidationError @@ -38,16 +38,25 @@ def handle_desc(self, desc: ApplicationDesc): class AppNameField(AppField): def handle_desc(self, desc: ApplicationDesc): + update_field_dict = {} + app_code = self.application.code + if self.application.name != desc.name_zh_cn: - raise DescriptionValidationError({APP_NAME_FIELD: "该字段不允许被修改"}) + # 修改中文名 + logger.warning("应用<%s> 的中文名将从 '%s' 修改成 '%s'", app_code, self.application.name, desc.name_zh_cn) + update_field_dict["name"] = desc.name_zh_cn + self.application.name = desc.name_zh_cn + self.application.save(update_fields=["name", "updated"]) if self.application.name_en != desc.name_en: - # 允许修改英文名 - logger.warning( - "应用<%s> 的英文名将从 '%s' 修改成 '%s'", desc.name_zh_cn, self.application.name_en, desc.name_en - ) + # 修改英文名 + logger.warning("应用<%s> 的英文名将从 '%s' 修改成 '%s'", app_code, self.application.name_en, desc.name_en) + update_field_dict["name_en"] = desc.name_en self.application.name_en = desc.name_en self.application.save(update_fields=["name_en", "updated"]) + # 应用名称修改后需要同步给桌面 + prepare_change_application_name.send(sender=self.application, code=app_code, **update_field_dict) + class AppRegionField(AppField): def handle_desc(self, desc: ApplicationDesc): diff --git a/apiserver/paasng/paasng/utils/error_codes.py b/apiserver/paasng/paasng/utils/error_codes.py index 43d86130fb..8783537ef9 100644 --- a/apiserver/paasng/paasng/utils/error_codes.py +++ b/apiserver/paasng/paasng/utils/error_codes.py @@ -83,6 +83,7 @@ class ErrorCodes: QUERY_REQUEST_ERROR = ErrorCode(_("查询日志失败,请检查查询条件")) CUSTOM_COLLECTOR_NOT_EXISTED = ErrorCode(_("日志平台-「自定义上报」配置不存在")) CANNOT_DELETE_CUSTOM_COLLECTOR = ErrorCode(_("删除日志采集规则失败")) + CUSTOM_COLLECTOR_UNSUPPORTED = ErrorCode(_("暂不支持自定义日志采集")) # 权限管理 CANNOT_MODIFY_ITEM = ErrorCode(_("当前项不允许变更")) # 迁移 diff --git a/apiserver/paasng/tests/api/test_log.py b/apiserver/paasng/tests/api/test_log.py index 89a8e50e1d..a158cdfde8 100644 --- a/apiserver/paasng/tests/api/test_log.py +++ b/apiserver/paasng/tests/api/test_log.py @@ -238,20 +238,21 @@ def test_list_metadata( }, ], } - - resp = api_client.get(url, data={"all": True}) - assert "url" in resp.data - options = resp.data["options"] - assert len(options) == 3 - assert options[0]["is_builtin"] - assert options[1]["is_builtin"] - assert not options[2]["is_builtin"] - - resp = api_client.get(url, data={"all": False}) - assert "url" in resp.data - filtered_options = resp.data["options"] - assert len(filtered_options) == 1 - assert options[2] == filtered_options[0] + with mock.patch("paasng.accessories.log.views.config.get_application_cluster") as fake_cluster: + fake_cluster.has_feature_flag.return_value = True + resp = api_client.get(url, data={"all": True}) + assert "url" in resp.data + options = resp.data["options"] + assert len(options) == 3 + assert options[0]["is_builtin"] + assert options[1]["is_builtin"] + assert not options[2]["is_builtin"] + + resp = api_client.get(url, data={"all": False}) + assert "url" in resp.data + filtered_options = resp.data["options"] + assert len(filtered_options) == 1 + assert options[2] == filtered_options[0] def test_insert_success(self, api_client, bk_app, bk_module, apigw_client, bkmonitor_space): url = f"/api/bkapps/applications/{bk_app.code}/modules/{bk_module.name}/log/custom-collector/" diff --git a/apiserver/paasng/tests/paasng/platform/declarative/application/conftest.py b/apiserver/paasng/tests/paasng/platform/declarative/application/conftest.py new file mode 100644 index 0000000000..fc4c610ffb --- /dev/null +++ b/apiserver/paasng/tests/paasng/platform/declarative/application/conftest.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) 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. + +import pytest + +from paasng.accessories.publish.sync_market.handlers import ( + on_change_application_name, + prepare_change_application_name, +) + + +@pytest.fixture(autouse=True) +def _mock_change_app_name_action(): + # skip change app name to console + prepare_change_application_name.disconnect(on_change_application_name) + yield + prepare_change_application_name.connect(on_change_application_name) diff --git a/apiserver/paasng/tests/paasng/platform/declarative/application/v2/test_controller.py b/apiserver/paasng/tests/paasng/platform/declarative/application/v2/test_controller.py index cb563b5b1c..0c814374a9 100644 --- a/apiserver/paasng/tests/paasng/platform/declarative/application/v2/test_controller.py +++ b/apiserver/paasng/tests/paasng/platform/declarative/application/v2/test_controller.py @@ -197,16 +197,20 @@ def test_region_modified(self, bk_user, existed_app): def test_name_modified(self, bk_user, existed_app): # Use new name + new_name = existed_app.name + "2" + new_name_en = existed_app.name + "en" + app_json = builder.make_app_desc( existed_app.code, decorator.with_module("default", True), ) - app_json["bk_app_name"] = existed_app.name + "2" + app_json["bk_app_name"] = new_name + app_json["bk_app_name_en"] = new_name_en controller = AppDeclarativeController(bk_user) - with pytest.raises(DescriptionValidationError) as exc_info: - controller.perform_action(get_app_description(app_json)) - assert "bk_app_name" in exc_info.value.detail + application = controller.perform_action(get_app_description(app_json)) + assert application.name == new_name + assert application.name_en == new_name_en def test_normal(self, bk_user, existed_app): app_json = builder.make_app_desc( diff --git a/apiserver/paasng/tests/paasng/platform/declarative/application/v3/test_controller.py b/apiserver/paasng/tests/paasng/platform/declarative/application/v3/test_controller.py index adb0c0cc0f..3c4d87ac6a 100644 --- a/apiserver/paasng/tests/paasng/platform/declarative/application/v3/test_controller.py +++ b/apiserver/paasng/tests/paasng/platform/declarative/application/v3/test_controller.py @@ -198,16 +198,22 @@ def test_region_modified(self, bk_user, existed_app): def test_name_modified(self, bk_user, existed_app): # Use new name + new_name = existed_app.name + "2" + new_name_en = existed_app.name + "en" + app_json = builder.make_app_desc( existed_app.code, decorator.with_module("default", True), ) - app_json["bkAppName"] = existed_app.name + "2" + app_json["bkAppName"] = new_name + app_json["bkAppNameEn"] = new_name_en controller = AppDeclarativeController(bk_user) - with pytest.raises(DescriptionValidationError) as exc_info: - controller.perform_action(get_app_description(app_json)) - assert "bk_app_name" in exc_info.value.detail + controller.perform_action(get_app_description(app_json)) + application = controller.perform_action(get_app_description(app_json)) + application.refresh_from_db() + assert application.name == new_name + assert application.name_en == new_name_en def test_normal(self, bk_user, existed_app): app_json = builder.make_app_desc( diff --git a/apiserver/paasng/tests/paasng/platform/declarative/handlers/test_v1.py b/apiserver/paasng/tests/paasng/platform/declarative/handlers/test_v1.py index 4da7afcece..20cc696040 100644 --- a/apiserver/paasng/tests/paasng/platform/declarative/handlers/test_v1.py +++ b/apiserver/paasng/tests/paasng/platform/declarative/handlers/test_v1.py @@ -21,6 +21,10 @@ import pytest from paasng.accessories.publish.market.models import Product +from paasng.accessories.publish.sync_market.handlers import ( + on_change_application_name, + prepare_change_application_name, +) from paasng.platform.applications.constants import AppLanguage from paasng.platform.applications.models import Application from paasng.platform.declarative.application.resources import ServiceSpec @@ -59,6 +63,7 @@ def test_app_creation(self, random_name, bk_user, app_desc, one_px_png): assert logo_content[23] == 144 def test_app_update_existed(self, bk_app, bk_user, app_desc): + prepare_change_application_name.disconnect(on_change_application_name) app_desc.update( { "app_code": bk_app.code,