diff --git a/apiserver/paasng/paas_wl/bk_app/applications/managers/__init__.py b/apiserver/paasng/paas_wl/bk_app/applications/managers/__init__.py index 602efe90fd..00a4b19daf 100644 --- a/apiserver/paasng/paas_wl/bk_app/applications/managers/__init__.py +++ b/apiserver/paasng/paas_wl/bk_app/applications/managers/__init__.py @@ -16,7 +16,6 @@ # to the current version of the project delivered to anyone in the future. from .app_build import mark_as_latest_artifact -from .app_configvar import AppConfigVarManager from .app_metadata import WlAppMetadata, get_metadata, update_metadata -__all__ = ["AppConfigVarManager", "WlAppMetadata", "get_metadata", "update_metadata", "mark_as_latest_artifact"] +__all__ = ["WlAppMetadata", "get_metadata", "update_metadata", "mark_as_latest_artifact"] diff --git a/apiserver/paasng/paas_wl/bk_app/applications/managers/app_configvar.py b/apiserver/paasng/paas_wl/bk_app/applications/managers/app_configvar.py deleted file mode 100644 index da8112fe91..0000000000 --- a/apiserver/paasng/paas_wl/bk_app/applications/managers/app_configvar.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- 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 logging -from dataclasses import dataclass -from typing import TYPE_CHECKING, Dict - -from django.conf import settings - -from paas_wl.bk_app.applications.managers.app_metadata import get_metadata - -if TYPE_CHECKING: - from paas_wl.bk_app.applications.models import WlApp - -logger = logging.getLogger(__name__) - - -def get_default_subpath(app: "WlApp") -> str: - """Get the default sub path for given application, this value will be used for: - - - sub path based ingress resource, used as request accessing location - - injected builtin env variable: BKPAAS_SUB_PATH - """ - return f"/{app.region}-{app.name}/" - - -@dataclass -class AppConfigVarManager: - """应用相关的环境变量生成器 - - 职责: 管理与 `应用`和 `应用进程` 相关的环境变量, 例如日志路径, 应用ID, 模块名称 等等, 不涉及与具体运行版本相关的配置 - """ - - app: "WlApp" - - def __post_init__(self): - self.metadata = get_metadata(self.app) - - @staticmethod - def add_prefix(key: str) -> str: - return settings.SYSTEM_CONFIG_VARS_KEY_PREFIX + key - - def get_process_envs(self, process_type: str) -> Dict: - config_vars = self.get_envs() - config_vars.update( - { - self.add_prefix("LOG_NAME_PREFIX"): ( - f"{self.app.region}-bkapp-" - f"{self.metadata.get_paas_app_code()}-" - f"{self.metadata.environment}-{process_type}" - ), - self.add_prefix("PROCESS_TYPE"): process_type, - } - ) - return config_vars - - def get_envs(self) -> Dict: - config_vars = { - self.add_prefix("APP_LOG_PATH"): settings.MUL_MODULE_VOLUME_MOUNT_APP_LOGGING_DIR, - # May be overwrite by paasng module - self.add_prefix("SUB_PATH"): get_default_subpath(self.app), - } - # TODO: 使用更好的方式把端口暴露给用户 - config_vars.update({"PORT": str(settings.CONTAINER_PORT)}) - return config_vars diff --git a/apiserver/paasng/paas_wl/bk_app/processes/kres_entities.py b/apiserver/paasng/paas_wl/bk_app/processes/kres_entities.py index 89e47fc628..dddc92266d 100644 --- a/apiserver/paasng/paas_wl/bk_app/processes/kres_entities.py +++ b/apiserver/paasng/paas_wl/bk_app/processes/kres_entities.py @@ -21,7 +21,6 @@ from kubernetes.dynamic import ResourceField from paas_wl.bk_app.applications.constants import WlAppType -from paas_wl.bk_app.applications.managers import AppConfigVarManager from paas_wl.bk_app.applications.models import Release from paas_wl.bk_app.processes.entities import Probe, Resources, Runtime, Status from paas_wl.bk_app.processes.kres_slzs import InstanceDeserializer, ProcessDeserializer, ProcessSerializer @@ -31,6 +30,7 @@ from paas_wl.infras.resources.generation.version import AppResVerManager from paas_wl.infras.resources.kube_res.base import AppEntity, Schedule from paas_wl.infras.resources.utils.basic import get_full_node_selector, get_full_tolerations +from paas_wl.utils.env_vars import VarsRenderContext, render_vars_dict from paas_wl.workloads.images.utils import make_image_pull_secret_name @@ -116,9 +116,9 @@ def from_release(cls, type_: str, release: "Release", extra_envs: Optional[dict] build = release.build config = release.config procfile = release.get_procfile() - envs = AppConfigVarManager(app=release.app).get_process_envs(type_) - envs.update(release.get_envs()) + envs = release.get_envs() envs.update(extra_envs or {}) + envs = render_vars_dict(envs, VarsRenderContext(process_type=type_)) mapper_version = AppResVerManager(release.app).curr_version process = Process( diff --git a/apiserver/paasng/paas_wl/utils/env_vars.py b/apiserver/paasng/paas_wl/utils/env_vars.py new file mode 100644 index 0000000000..2692f00feb --- /dev/null +++ b/apiserver/paasng/paas_wl/utils/env_vars.py @@ -0,0 +1,48 @@ +# 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. +from dataclasses import dataclass +from typing import Dict + + +@dataclass +class VarsRenderContext: + """The context for rendering environment variables. + + :param process_type: The type of the process, e.g. "web", "worker". + """ + + process_type: str + + +def render_vars_dict(d: Dict[str, str], context: VarsRenderContext) -> Dict[str, str]: + """Render an environment variable dict, replace all supported variables with + values in the given context. + + :param d: The environment variable dict to be rendered. + :param context: The context for rendering. + :return: The rendered environment variable dict. The original dict is not modified. + """ + # Use a whitelist to avoid unexpected variable replacement + _supported_key_suffixes = {"_LOG_NAME_PREFIX", "_PROCESS_TYPE"} + result = d.copy() + for k, v in d.items(): + if not any(k.endswith(suffix) for suffix in _supported_key_suffixes): + continue + + # TODO: Use regular expression or other methods to replace variables when + # there are more variables to be supported. + result[k] = v.replace("{{bk_var_process_type}}", context.process_type) + return result diff --git a/apiserver/paasng/paas_wl/workloads/release_controller/hooks/kres_entities.py b/apiserver/paasng/paas_wl/workloads/release_controller/hooks/kres_entities.py index 2dfb213666..f77da701ad 100644 --- a/apiserver/paasng/paas_wl/workloads/release_controller/hooks/kres_entities.py +++ b/apiserver/paasng/paas_wl/workloads/release_controller/hooks/kres_entities.py @@ -26,7 +26,6 @@ from kubernetes.dynamic import ResourceField, ResourceInstance from typing_extensions import Literal -from paas_wl.bk_app.applications.managers import AppConfigVarManager from paas_wl.bk_app.applications.models import WlApp from paas_wl.infras.cluster.utils import get_cluster_by_app from paas_wl.infras.resource_templates.logging import get_app_logging_volume, get_app_logging_volume_mounts @@ -41,6 +40,7 @@ ) from paas_wl.infras.resources.kube_res.envs import decode_envs, encode_envs from paas_wl.infras.resources.utils.basic import get_full_node_selector, get_full_tolerations +from paas_wl.utils.env_vars import VarsRenderContext, render_vars_dict from paas_wl.utils.kubestatus import ( check_pod_health_status, get_container_fail_message, @@ -226,8 +226,8 @@ class Meta: @classmethod def from_db_obj(cls, command: "CommandModel", extra_envs: Optional[Dict] = None) -> "Command": envs = command.get_envs() - envs.update(AppConfigVarManager(command.app).get_envs()) envs.update(extra_envs or {}) + envs = render_vars_dict(envs, context=VarsRenderContext(process_type="sys-cmd")) return cls( app=command.app, diff --git a/apiserver/paasng/paasng/platform/engine/configurations/config_var.py b/apiserver/paasng/paasng/platform/engine/configurations/config_var.py index 2f385ce930..7fc0e59cd1 100644 --- a/apiserver/paasng/paasng/platform/engine/configurations/config_var.py +++ b/apiserver/paasng/paasng/platform/engine/configurations/config_var.py @@ -15,6 +15,7 @@ # to the current version of the project delivered to anyone in the future. """Config variables related functions""" + from typing import TYPE_CHECKING, Dict, Iterator, List from django.conf import settings @@ -78,6 +79,10 @@ def get_env_variables( # Part: system-wide env vars result.update(get_builtin_env_variables(engine_app, settings.CONFIGVAR_SYSTEM_PREFIX)) + # Port: workloads related env vars + vars_wl = _flatten_envs(generate_wl_builtin_env_vars(settings.CONFIGVAR_SYSTEM_PREFIX, env)) + result.update(vars_wl) + # Part: insert blobstore env vars if env.application.type != ApplicationType.CLOUD_NATIVE: result.update(generate_blobstore_env_vars(engine_app)) @@ -331,6 +336,54 @@ def get_builtin_env_variables(engine_app: "EngineApp", config_vars_prefix: str) } +# '{bk_var_*}' is a special placeholder and will be replaced by the actual value +# when the workloads resources are created. +_bk_var_tmpl_process_type = "{{bk_var_process_type}}" + + +def generate_wl_builtin_env_vars(config_vars_prefix: str, env=None) -> List[BuiltInEnvVarDetail]: + """Generate env vars related with workloads. + + :param config_vars_prefix: The prefix of the env vars. + :param env: Optional, the env object, if given, will include the env vars related + to the environment, such as subpath, process type, etc. + """ + items = [ + BuiltInEnvVarDetail( + key="APP_LOG_PATH", + value=settings.MUL_MODULE_VOLUME_MOUNT_APP_LOGGING_DIR, + description=_("应用日志文件存放路径"), + prefix=config_vars_prefix, + ), + BuiltInEnvVarDetail(key="PORT", value=str(settings.CONTAINER_PORT), description=_("目标端口号,值为 5000")), + ] + # Extend the env vars related to the env when given + if env: + wl_app = env.wl_app + app = env.module.application + items += [ + BuiltInEnvVarDetail( + key="LOG_NAME_PREFIX", + value=f"{app.region}-bkapp-{app.code}-{env.environment}-{_bk_var_tmpl_process_type}", + description=_("日志文件推荐使用的前缀"), + prefix=config_vars_prefix, + ), + BuiltInEnvVarDetail( + key="PROCESS_TYPE", + value=_bk_var_tmpl_process_type, + description=_("[不推荐使用] 当前进程类型"), + prefix=config_vars_prefix, + ), + BuiltInEnvVarDetail( + key="SUB_PATH", + value=f"/{wl_app.region}-{wl_app.name}/", + description=_("[不推荐使用] 基于规则拼接的应用访问子路径,仅适合向前兼容时使用"), + prefix=config_vars_prefix, + ), + ] + return items + + def get_preset_env_variables(env: ModuleEnvironment) -> Dict[str, str]: """Get PresetEnvVariable as env variables dict""" qs: Iterator[PresetEnvVariable] = PresetEnvVariable.objects.filter(module=env.module) diff --git a/apiserver/paasng/paasng/platform/engine/constants.py b/apiserver/paasng/paasng/platform/engine/constants.py index 4450c9f8fc..1b3f89d904 100644 --- a/apiserver/paasng/paasng/platform/engine/constants.py +++ b/apiserver/paasng/paasng/platform/engine/constants.py @@ -171,9 +171,3 @@ class AppRunTimeBuiltinEnv(str, StructuredEnum): "DEFAULT_PREALLOCATED_URLS", label=_('应用模块各环境的访问地址,如 {"stag": "http://stag.com", "prod": "http://prod.com"}'), ) - - -class NoPrefixAppRunTimeBuiltinEnv(str, StructuredEnum): - """Built-in envs without prefix in the app runtime""" - - PORT = EnumField("PORT", label=_("目标端口号,值为 5000")) diff --git a/apiserver/paasng/paasng/platform/engine/deploy/bg_build/utils.py b/apiserver/paasng/paasng/platform/engine/deploy/bg_build/utils.py index 85cf4ec385..427f6006b0 100644 --- a/apiserver/paasng/paasng/platform/engine/deploy/bg_build/utils.py +++ b/apiserver/paasng/paasng/platform/engine/deploy/bg_build/utils.py @@ -24,11 +24,10 @@ from blue_krill.storages.blobstore.base import SignatureType from django.conf import settings -from paas_wl.bk_app.applications.managers import AppConfigVarManager - # NOTE: Import kube resource related modules from paas_wl from paas_wl.bk_app.applications.models.build import BuildProcess from paas_wl.bk_app.deploy.app_res.utils import get_schedule_config +from paas_wl.utils.env_vars import VarsRenderContext, render_vars_dict from paas_wl.utils.text import b64encode from paas_wl.workloads.images.kres_entities import ImageCredentials from paas_wl.workloads.images.utils import make_image_pull_secret_name @@ -117,8 +116,6 @@ def generate_builder_env_vars(bp: BuildProcess, metadata: Dict) -> Dict[str, str PILOT_BUILDER_TIMEOUT=f"{settings.BUILD_PROCESS_TIMEOUT // 60}m", ) - env_vars.update(AppConfigVarManager(app=app).get_envs()) - # Inject extra env vars in settings for development purpose if settings.BUILD_EXTRA_ENV_VARS: env_vars.update(settings.BUILD_EXTRA_ENV_VARS) @@ -128,6 +125,7 @@ def generate_builder_env_vars(bp: BuildProcess, metadata: Dict) -> Dict[str, str if metadata: update_env_vars_with_metadata(env_vars, metadata) + return env_vars @@ -154,6 +152,7 @@ def update_env_vars_with_metadata(env_vars: Dict, metadata: Dict): :param metadata: metadata dict :return: """ + # All system built-in vars were injected by this step if "extra_envs" in metadata: env_vars.update(metadata["extra_envs"]) @@ -177,6 +176,8 @@ def prepare_slugbuilder_template( image = builder_image or settings.DEFAULT_SLUGBUILDER_IMAGE logger.info(f"build wl_app<{app.name}> with slugbuilder<{image}>") + env_vars = render_vars_dict(env_vars, VarsRenderContext(process_type="sys-builder")) + return SlugBuilderTemplate( name=generate_builder_name(app), namespace=app.namespace, diff --git a/apiserver/paasng/paasng/platform/engine/views/configvar.py b/apiserver/paasng/paasng/platform/engine/views/configvar.py index f7368e24e1..37a0189559 100644 --- a/apiserver/paasng/paasng/platform/engine/views/configvar.py +++ b/apiserver/paasng/paasng/platform/engine/views/configvar.py @@ -33,12 +33,12 @@ from paasng.platform.engine.configurations.config_var import ( generate_env_vars_by_region_and_env, generate_env_vars_for_bk_platform, + generate_wl_builtin_env_vars, ) from paasng.platform.engine.constants import ( AppInfoBuiltinEnv, AppRunTimeBuiltinEnv, ConfigVarEnvName, - NoPrefixAppRunTimeBuiltinEnv, ) from paasng.platform.engine.models import ConfigVar from paasng.platform.engine.models.config_var import add_prefix_to_key @@ -164,8 +164,13 @@ def get_runtime_envs(self, request, code): env_dict = self._get_enum_choices_dict(AppRunTimeBuiltinEnv) envs = add_prefix_to_key(env_dict, settings.CONFIGVAR_SYSTEM_PREFIX) - no_prefix_envs = self._get_enum_choices_dict(NoPrefixAppRunTimeBuiltinEnv) - return Response({**envs, **no_prefix_envs}) + wl_vars = generate_wl_builtin_env_vars(settings.CONFIGVAR_SYSTEM_PREFIX) + for env in wl_vars: + # Transform the dict structure to remove the value field in order to + # keep consistent and be compatible with the frontend. + # TODO: Show the value in the future. + envs.update({k: v["description"] for k, v in env.to_dict().items()}) + return Response({**envs}) class ConfigVarImportExportViewSet(viewsets.ViewSet, ApplicationCodeInPathMixin): diff --git a/apiserver/paasng/tests/paas_wl/bk_app/applications/models/test_app_managers.py b/apiserver/paasng/tests/paas_wl/bk_app/applications/models/test_app_managers.py index 70a8111837..09ee0c214c 100644 --- a/apiserver/paasng/tests/paas_wl/bk_app/applications/models/test_app_managers.py +++ b/apiserver/paasng/tests/paas_wl/bk_app/applications/models/test_app_managers.py @@ -16,31 +16,12 @@ # to the current version of the project delivered to anyone in the future. import pytest -from django.conf import settings -from paas_wl.bk_app.applications.managers import AppConfigVarManager, WlAppMetadata -from tests.paas_wl.utils.wl_app import create_wl_app +from paas_wl.bk_app.applications.managers import WlAppMetadata pytestmark = pytest.mark.django_db(databases=["workloads"]) -class TestAppConfigVarManager: - def test_app_configvar_generate(self): - wl_app = create_wl_app( - force_app_info={"name": "bkapp-test_me-stag", "region": settings.DEFAULT_REGION_NAME}, - paas_app_code="test_me", - environment="stag", - ) - - action = AppConfigVarManager(app=wl_app) - result = action.get_envs() - assert result["BKPAAS_SUB_PATH"] == "/default-bkapp-test_me-stag/" - - result_with_process = action.get_process_envs(process_type="fake") - assert result_with_process["BKPAAS_LOG_NAME_PREFIX"] == "default-bkapp-test_me-stag-fake" - assert result_with_process["PORT"] == str(settings.CONTAINER_PORT) - - class TestWlAppMetadata: def test_empty_data(self): obj = WlAppMetadata() diff --git a/apiserver/paasng/tests/paas_wl/test_utils/test_env_vars.py b/apiserver/paasng/tests/paas_wl/test_utils/test_env_vars.py new file mode 100644 index 0000000000..c6f88d5888 --- /dev/null +++ b/apiserver/paasng/tests/paas_wl/test_utils/test_env_vars.py @@ -0,0 +1,37 @@ +# 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. +from paas_wl.utils.env_vars import VarsRenderContext, render_vars_dict + + +def test_render_vars_dict(): + d = { + "BKPAAS_PROCESS_TYPE": "{{bk_var_process_type}}", + "OTHER_PRE_LOG_NAME_PREFIX": "foo-{{bk_var_process_type}}", + # with valid name but variable does not match + "OTHER_PRE_PROCESS_TYPE": "{{another_var}}", + "FOO": "some random value", + # the variable matches but the name is not in whitelist + "BAR": "{{bk_var_process_type}}", + "FOO_BAR": "{{some_var}}", + } + assert render_vars_dict(d, VarsRenderContext(process_type="web")) == { + "BKPAAS_PROCESS_TYPE": "web", + "OTHER_PRE_LOG_NAME_PREFIX": "foo-web", + "OTHER_PRE_PROCESS_TYPE": "{{another_var}}", + "FOO": "some random value", + "BAR": "{{bk_var_process_type}}", + "FOO_BAR": "{{some_var}}", + } diff --git a/apiserver/paasng/tests/paasng/platform/bkapp_model/test_manifest.py b/apiserver/paasng/tests/paasng/platform/bkapp_model/test_manifest.py index 06eeffdd4f..41bdcfd82e 100644 --- a/apiserver/paasng/tests/paasng/platform/bkapp_model/test_manifest.py +++ b/apiserver/paasng/tests/paasng/platform/bkapp_model/test_manifest.py @@ -460,6 +460,7 @@ def test_apply_env_annots_with_deploy_id(blank_resource, bk_stag_env): assert blank_resource.metadata.annotations["bkapp.paas.bk.tencent.com/bkpaas-deploy-id"] == "foo-id" +@pytest.mark.usefixtures("_with_wl_apps") def test_apply_builtin_env_vars(blank_resource, bk_stag_env, bk_deployment): G( DeploymentDescription, @@ -495,6 +496,7 @@ def test_apply_builtin_env_vars(blank_resource, bk_stag_env, bk_deployment): assert "BKPAAS_SERVICE_ADDRESSES_BKSAAS" not in var_names +@pytest.mark.usefixtures("_with_wl_apps") def test_builtin_env_has_high_priority(blank_resource, bk_stag_env): custom_login_url = generate_random_string() diff --git a/apiserver/paasng/tests/paasng/platform/engine/configurations/test_config_var.py b/apiserver/paasng/tests/paasng/platform/engine/configurations/test_config_var.py index 2bf3b1c166..01f421045e 100644 --- a/apiserver/paasng/tests/paasng/platform/engine/configurations/test_config_var.py +++ b/apiserver/paasng/tests/paasng/platform/engine/configurations/test_config_var.py @@ -24,7 +24,12 @@ from paasng.platform.declarative.exceptions import DescriptionValidationError from paasng.platform.declarative.handlers import AppDescriptionHandler -from paasng.platform.engine.configurations.config_var import get_builtin_env_variables, get_env_variables +from paasng.platform.engine.configurations.config_var import ( + _flatten_envs, + generate_wl_builtin_env_vars, + get_builtin_env_variables, + get_env_variables, +) from paasng.platform.engine.constants import AppRunTimeBuiltinEnv from paasng.platform.engine.models.config_var import ConfigVar from tests.utils.helpers import override_region_configs @@ -32,6 +37,7 @@ pytestmark = pytest.mark.django_db(databases=["default", "workloads"]) +@pytest.mark.usefixtures("_with_wl_apps") class TestGetEnvVariables: @pytest.mark.parametrize( ("include_config_vars", "ctx"), [(True, does_not_raise("bar")), (False, pytest.raises(KeyError))] @@ -44,9 +50,16 @@ def test_param_include_config_vars(self, bk_module, bk_stag_env, include_config_ def test_builtin_id_and_secret(self, bk_app, bk_stag_env): env_vars = get_env_variables(bk_stag_env) + assert env_vars["BKPAAS_APP_ID"] == bk_app.code assert env_vars["BKPAAS_APP_SECRET"] != "" + def test_wl_vars_exists(self, bk_stag_env): + env_vars = get_env_variables(bk_stag_env) + + assert env_vars["PORT"] != "" + assert env_vars["BKPAAS_PROCESS_TYPE"] != "" + @pytest.mark.parametrize( ("yaml_content", "ctx"), [ @@ -144,9 +157,7 @@ def update_region_hook(config): if provide_env_vars_platform: assert set(settings.BK_PAAS2_PLATFORM_ENVS.keys()).issubset(set(config_vars.keys())) == contain_bk_envs - def test_builtin_env_keys(self, bk_app): - bk_module = bk_app.get_default_module() - bk_stag_env = bk_module.envs.get(environment="stag") + def test_builtin_env_keys(self, bk_stag_env): config_vars = get_builtin_env_variables(bk_stag_env.engine_app, settings.CONFIGVAR_SYSTEM_PREFIX) assert {"BKPAAS_LOGIN_URL", "BKPAAS_APP_CODE", "BKPAAS_APP_ID", "BKPAAS_APP_SECRET"}.issubset( @@ -160,3 +171,14 @@ def test_builtin_env_keys(self, bk_app): if key != AppRunTimeBuiltinEnv.DEFAULT_PREALLOCATED_URLS.value ] assert set(runtime_env_keys).issubset(config_vars.keys()) + + +@pytest.mark.usefixtures("_with_wl_apps") +def test_generate_wl_builtin_env_vars(bk_stag_env): + env_vars = _flatten_envs(generate_wl_builtin_env_vars(settings.CONFIGVAR_SYSTEM_PREFIX, bk_stag_env)) + + assert "PORT" in env_vars + assert "BKPAAS_APP_LOG_PATH" in env_vars + assert "BKPAAS_SUB_PATH" in env_vars + assert env_vars["BKPAAS_PROCESS_TYPE"] == "{{bk_var_process_type}}" + assert env_vars["BKPAAS_LOG_NAME_PREFIX"].endswith("-{{bk_var_process_type}}") diff --git a/apiserver/paasng/tests/paasng/platform/engine/configurations/test_ingress.py b/apiserver/paasng/tests/paasng/platform/engine/configurations/test_ingress.py index a3109895ac..aaa92519c3 100644 --- a/apiserver/paasng/tests/paasng/platform/engine/configurations/test_ingress.py +++ b/apiserver/paasng/tests/paasng/platform/engine/configurations/test_ingress.py @@ -103,6 +103,7 @@ def test_as_env( default_subpath_key: f"http://example.com{normal_style_sub_path}", } + @pytest.mark.usefixtures("_with_wl_apps") @pytest.mark.parametrize( ("app", "force_legacy_style", "expected"), [ diff --git a/apiserver/paasng/tests/paasng/platform/engine/deploy/bg_build/test_utils.py b/apiserver/paasng/tests/paasng/platform/engine/deploy/bg_build/test_utils.py index 3f3f93f073..7aeb03e109 100644 --- a/apiserver/paasng/tests/paasng/platform/engine/deploy/bg_build/test_utils.py +++ b/apiserver/paasng/tests/paasng/platform/engine/deploy/bg_build/test_utils.py @@ -23,7 +23,6 @@ import urllib3 from django.conf import settings -from paas_wl.bk_app.applications.managers import AppConfigVarManager from paasng.platform.engine.deploy.bg_build.utils import ( generate_builder_env_vars, generate_slug_path, @@ -50,9 +49,6 @@ def test_generate_env_vars_without_metadata(self, build_proc, wl_app): if settings.PYTHON_BUILDPACK_PIP_INDEX_URL: for k, v in get_envs_from_pypi_url(settings.PYTHON_BUILDPACK_PIP_INDEX_URL).items(): assert env_vars.pop(k) == v, f"{k} 与预期不符" - app_config_var = AppConfigVarManager(app=wl_app).get_envs() - for key in app_config_var.keys() & env_vars.keys(): - assert env_vars[key] == app_config_var[key], f"{key} 与预期不符" def test_update_env_vars_with_metadata(self, build_proc): env: Dict[str, str] = {} diff --git a/apiserver/paasng/tests/paasng/platform/engine/deploy/test_release.py b/apiserver/paasng/tests/paasng/platform/engine/deploy/test_release.py index 139a3824c1..9e63c3bad7 100644 --- a/apiserver/paasng/tests/paasng/platform/engine/deploy/test_release.py +++ b/apiserver/paasng/tests/paasng/platform/engine/deploy/test_release.py @@ -39,6 +39,7 @@ def _auto_binding_phases(bk_prod_env, bk_deployment): manager.attach(DeployPhaseTypes(p.type), bk_deployment) +@pytest.mark.usefixtures("_with_wl_apps") @pytest.mark.usefixtures("_auto_binding_phases") class TestApplicationReleaseMgr: """Tests for ApplicationReleaseMgr""" diff --git a/operator/pkg/controllers/bkapp/common/env_vars.go b/operator/pkg/controllers/bkapp/common/env_vars.go index 5ce040c80e..5f37bf4070 100644 --- a/operator/pkg/controllers/bkapp/common/env_vars.go +++ b/operator/pkg/controllers/bkapp/common/env_vars.go @@ -20,7 +20,9 @@ package common import ( "sort" + "strings" + "github.com/samber/lo" corev1 "k8s.io/api/core/v1" paasv1alpha2 "bk.tencent.com/paas-app-operator/api/v1alpha2" @@ -37,3 +39,33 @@ func GetAppEnvs(bkapp *paasv1alpha2.BkApp) []corev1.EnvVar { sort.Slice(envs, func(i, j int) bool { return envs[i].Name < envs[j].Name }) return envs } + +// VarsRenderContext is the context object for rendering variables list +type VarsRenderContext struct { + // ProcessType is the type of the process, e.g. "web", "worker" + ProcessType string +} + +// RenderAppVars render a list of env variables, it replaces var template with their +// actual values. Only a limited set of vars are supported, including: +// +// - {{bk_var_process_type}} -> real process type +func RenderAppVars(vars []corev1.EnvVar, context VarsRenderContext) []corev1.EnvVar { + supportedKeySuffixes := []string{"_LOG_NAME_PREFIX", "_PROCESS_TYPE"} + + results := make([]corev1.EnvVar, len(vars)) + for i, v := range vars { + newValue := v.Value + // Only do the rendering if the key ends with any supported suffix to prevent + // unnecessary rendering. + if lo.SomeBy(supportedKeySuffixes, func(suffix string) bool { + return strings.HasSuffix(v.Name, suffix) + }) { + // TODO: Use other method to replace the variables when more variables are supported + newValue = strings.ReplaceAll(newValue, "{{bk_var_process_type}}", context.ProcessType) + } + + results[i] = corev1.EnvVar{Name: v.Name, Value: newValue} + } + return results +} diff --git a/operator/pkg/controllers/bkapp/common/env_vars_test.go b/operator/pkg/controllers/bkapp/common/env_vars_test.go index 8f7e58247a..0b2fe88184 100644 --- a/operator/pkg/controllers/bkapp/common/env_vars_test.go +++ b/operator/pkg/controllers/bkapp/common/env_vars_test.go @@ -21,6 +21,7 @@ package common import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" paasv1alpha2 "bk.tencent.com/paas-app-operator/api/v1alpha2" @@ -66,3 +67,38 @@ var _ = Describe("Get App Envs", func() { Expect(len(envs)).To(Equal(0)) }) }) + +var _ = Describe("Get App Envs", func() { + It("No \"bk-var-*\" vars in the value", func() { + envs := []corev1.EnvVar{ + {Name: "FOO", Value: "some random value foo"}, + {Name: "BAR", Value: "some random value bar"}, + } + renderedVars := RenderAppVars(envs, VarsRenderContext{ProcessType: "web"}) + + By("The rendered vars should be the same as the input vars") + Expect(renderedVars).To(Equal(envs)) + }) + + It("Contains supported vars", func() { + envs := []corev1.EnvVar{ + {Name: "BKPAAS_PROCESS_TYPE", Value: "{{bk_var_process_type}}"}, + {Name: "OTHER_PRE_LOG_NAME_PREFIX", Value: "foo-{{bk_var_process_type}}"}, + // with valid name but variable does not match + {Name: "OTHER_PRE_PROCESS_TYPE", Value: "{{another_var}}"}, + {Name: "FOO", Value: "some random value foo"}, + // the variable matches but the name is not in whitelist + {Name: "BAR", Value: "{{bk_var_process_type}}"}, + } + renderedVars := RenderAppVars(envs, VarsRenderContext{ProcessType: "web"}) + + By("The `process_type` should be rendered properly.") + Expect(renderedVars).To(Equal([]corev1.EnvVar{ + {Name: "BKPAAS_PROCESS_TYPE", Value: "web"}, + {Name: "OTHER_PRE_LOG_NAME_PREFIX", Value: "foo-web"}, + {Name: "OTHER_PRE_PROCESS_TYPE", Value: "{{another_var}}"}, + {Name: "FOO", Value: "some random value foo"}, + {Name: "BAR", Value: "{{bk_var_process_type}}"}, + })) + }) +}) diff --git a/operator/pkg/controllers/bkapp/hooks/resources/hooks.go b/operator/pkg/controllers/bkapp/hooks/resources/hooks.go index 72776c2630..ab46119e0e 100644 --- a/operator/pkg/controllers/bkapp/hooks/resources/hooks.go +++ b/operator/pkg/controllers/bkapp/hooks/resources/hooks.go @@ -122,6 +122,11 @@ func BuildPreReleaseHook(bkapp *paasv1alpha2.BkApp, status *paasv1alpha2.HookSta command = append([]string{"launcher"}, command...) } + // Generate the environment variables and render the "{{bk_var_*}}" var placeholder which + // might be used in the values. + envVars := common.GetAppEnvs(bkapp) + envVars = common.RenderAppVars(envVars, common.VarsRenderContext{ProcessType: "sys-pre-rel"}) + return &HookInstance{ Pod: &corev1.Pod{ TypeMeta: metav1.TypeMeta{ @@ -146,7 +151,7 @@ func BuildPreReleaseHook(bkapp *paasv1alpha2.BkApp, status *paasv1alpha2.HookSta Image: bkapp.Spec.Build.Image, Command: kubeutil.ReplaceCommandEnvVariables(command), Args: kubeutil.ReplaceCommandEnvVariables(args), - Env: common.GetAppEnvs(bkapp), + Env: envVars, Name: "hook", ImagePullPolicy: bkapp.Spec.Build.ImagePullPolicy, // pre-hook 使用默认资源配置 diff --git a/operator/pkg/controllers/bkapp/processes/resources/deployment.go b/operator/pkg/controllers/bkapp/processes/resources/deployment.go index d4f0f0efb6..d211672ca6 100644 --- a/operator/pkg/controllers/bkapp/processes/resources/deployment.go +++ b/operator/pkg/controllers/bkapp/processes/resources/deployment.go @@ -62,8 +62,11 @@ func BuildProcDeployment(app *paasv1alpha2.BkApp, procName string) (*appsv1.Depl deployID = DefaultDeployID } - // Prepare data + // Generate the environment variables and render the "{{bk_var_*}}" var placeholder which + // might be used in the values. envVars := common.GetAppEnvs(app) + envVars = common.RenderAppVars(envVars, common.VarsRenderContext{ProcessType: procName}) + mounterMap, err := volumes.GetAllVolumeMounterMap(app) if err != nil { return nil, err