diff --git a/client/ayon_core/hooks/pre_filter_farm_environments.py b/client/ayon_core/hooks/pre_filter_farm_environments.py new file mode 100644 index 0000000000..d231acf5e9 --- /dev/null +++ b/client/ayon_core/hooks/pre_filter_farm_environments.py @@ -0,0 +1,72 @@ +import re + +from ayon_applications import PreLaunchHook, LaunchTypes +from ayon_core.lib import filter_profiles + + +class FilterFarmEnvironments(PreLaunchHook): + """Filter or modify calculated environment variables for farm rendering. + + This hook must run last, only after all other hooks are finished to get + correct environment for launch context. + + Implemented modifications to self.launch_context.env: + - skipping (list) of environment variable keys + - removing value in environment variable: + - supports regular expression in pattern + """ + order = 1000 + + launch_types = {LaunchTypes.farm_publish} + + def execute(self): + data = self.launch_context.data + project_settings = data["project_settings"] + filter_env_profiles = ( + project_settings["core"]["filter_env_profiles"]) + + if not filter_env_profiles: + self.log.debug("No profiles found for env var filtering") + return + + task_entity = data["task_entity"] + + filter_data = { + "host_names": self.host_name, + "task_types": task_entity["taskType"], + "task_names": task_entity["name"], + "folder_paths": data["folder_path"] + } + matching_profile = filter_profiles( + filter_env_profiles, filter_data, logger=self.log + ) + if not matching_profile: + self.log.debug("No matching profile found for env var filtering " + f"for {filter_data}") + return + + self._skip_environment_variables( + self.launch_context.env, matching_profile) + + self._modify_environment_variables( + self.launch_context.env, matching_profile) + + def _modify_environment_variables(self, calculated_env, matching_profile): + """Modify environment variable values.""" + for env_item in matching_profile["replace_in_environment"]: + key = env_item["environment_key"] + value = calculated_env.get(key) + if not value: + continue + + value = re.sub(value, env_item["pattern"], env_item["replacement"]) + if value: + calculated_env[key] = value + else: + calculated_env.pop(key) + + def _skip_environment_variables(self, calculated_env, matching_profile): + """Skips list of environment variable names""" + for skip_env in matching_profile["skip_env_keys"]: + self.log.info(f"Skipping {skip_env}") + calculated_env.pop(skip_env) diff --git a/server/settings/main.py b/server/settings/main.py index 40e16e7e91..0972ccdfb9 100644 --- a/server/settings/main.py +++ b/server/settings/main.py @@ -169,6 +169,46 @@ class VersionStartCategoryModel(BaseSettingsModel): ) +class EnvironmentReplacementModel(BaseSettingsModel): + environment_key: str = SettingsField("", title="Enviroment variable") + pattern: str = SettingsField("", title="Pattern") + replacement: str = SettingsField("", title="Replacement") + + +class FilterEnvsProfileModel(BaseSettingsModel): + _layout = "expanded" + + host_names: list[str] = SettingsField( + default_factory=list, + title="Host names" + ) + + task_types: list[str] = SettingsField( + default_factory=list, + title="Task types", + enum_resolver=task_types_enum + ) + + task_names: list[str] = SettingsField( + default_factory=list, + title="Task names" + ) + + folder_paths: list[str] = SettingsField( + default_factory=list, + title="Folder paths" + ) + + skip_env_keys: list[str] = SettingsField( + default_factory=list, + title="Skip environment variables" + ) + replace_in_environment: list[EnvironmentReplacementModel] = SettingsField( + default_factory=list, + title="Replace values in environment" + ) + + class CoreSettings(BaseSettingsModel): studio_name: str = SettingsField("", title="Studio name", scope=["studio"]) studio_code: str = SettingsField("", title="Studio code", scope=["studio"]) @@ -219,6 +259,9 @@ class CoreSettings(BaseSettingsModel): title="Project environments", section="---" ) + filter_env_profiles: list[FilterEnvsProfileModel] = SettingsField( + default_factory=list, + ) @validator( "environments", @@ -313,5 +356,6 @@ DEFAULT_VALUES = { "project_environments": json.dumps( {}, indent=4 - ) + ), + "filter_env_profiles": [], }