perf: improve perf for a bunch of operations by lazy import + lazy define of config-panel related stuff

This commit is contained in:
Alexandre Aubin 2023-11-27 18:03:23 +01:00 committed by axolotle
parent 650c0136f2
commit 3dda3bc4d5
2 changed files with 259 additions and 233 deletions

View file

@ -17,11 +17,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import time
import glob import glob
import os import os
import shutil import shutil
import yaml import yaml
import time
import re import re
import subprocess import subprocess
import tempfile import tempfile
@ -45,13 +45,6 @@ from moulinette.utils.filesystem import (
chmod, chmod,
) )
from yunohost.utils.configpanel import ConfigPanel
from yunohost.utils.form import (
DomainOption,
WebPathOption,
ask_questions_and_parse_answers,
parse_raw_options,
)
from yunohost.utils.i18n import _value_for_locale from yunohost.utils.i18n import _value_for_locale
from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.utils.system import ( from yunohost.utils.system import (
@ -414,6 +407,7 @@ def app_change_url(operation_logger, app, domain, path):
path -- New path at which the application will be move path -- New path at which the application will be move
""" """
from yunohost.utils.form import DomainOption, WebPathOption
from yunohost.hook import hook_exec_with_script_debug_if_failure, hook_callback from yunohost.hook import hook_exec_with_script_debug_if_failure, hook_callback
from yunohost.service import service_reload_or_restart from yunohost.service import service_reload_or_restart
@ -964,6 +958,8 @@ def app_upgrade(
def app_manifest(app, with_screenshot=False): def app_manifest(app, with_screenshot=False):
from yunohost.utils.form import parse_raw_options
manifest, extracted_app_folder = _extract_app(app) manifest, extracted_app_folder = _extract_app(app)
manifest["install"] = parse_raw_options(manifest.get("install", {}), serialize=True) manifest["install"] = parse_raw_options(manifest.get("install", {}), serialize=True)
@ -1060,6 +1056,7 @@ def app_install(
) )
from yunohost.regenconf import manually_modified_files from yunohost.regenconf import manually_modified_files
from yunohost.utils.legacy import _patch_legacy_php_versions, _patch_legacy_helpers from yunohost.utils.legacy import _patch_legacy_php_versions, _patch_legacy_helpers
from yunohost.utils.form import ask_questions_and_parse_answers
# Check if disk space available # Check if disk space available
if free_space_in_directory("/") <= 512 * 1000 * 1000: if free_space_in_directory("/") <= 512 * 1000 * 1000:
@ -1393,7 +1390,7 @@ def app_remove(operation_logger, app, purge=False, force_workdir=None):
permission_delete, permission_delete,
permission_sync_to_user, permission_sync_to_user,
) )
from yunohost.domain import domain_list, domain_config_get, domain_config_set from yunohost.domain import domain_list, domain_config_set, _get_raw_domain_settings
if not _is_installed(app): if not _is_installed(app):
raise YunohostValidationError( raise YunohostValidationError(
@ -1471,7 +1468,7 @@ def app_remove(operation_logger, app, purge=False, force_workdir=None):
hook_remove(app) hook_remove(app)
for domain in domain_list()["domains"]: for domain in domain_list()["domains"]:
if domain_config_get(domain, "feature.app.default_app") == app: if _get_raw_domain_settings(domain).get("default_app") == app:
domain_config_set(domain, "feature.app.default_app", "_none") domain_config_set(domain, "feature.app.default_app", "_none")
if ret == 0: if ret == 0:
@ -1572,6 +1569,7 @@ def app_register_url(app, domain, path):
domain -- The domain on which the app should be registered (e.g. your.domain.tld) domain -- The domain on which the app should be registered (e.g. your.domain.tld)
path -- The path to be registered (e.g. /coffee) path -- The path to be registered (e.g. /coffee)
""" """
from yunohost.utils.form import DomainOption, WebPathOption
from yunohost.permission import ( from yunohost.permission import (
permission_url, permission_url,
user_permission_update, user_permission_update,
@ -1614,7 +1612,7 @@ def app_ssowatconf():
""" """
from yunohost.domain import ( from yunohost.domain import (
domain_list, domain_list,
domain_config_get, _get_raw_domain_settings,
_get_domain_portal_dict, _get_domain_portal_dict,
) )
from yunohost.permission import user_permission_list from yunohost.permission import user_permission_list
@ -1654,8 +1652,8 @@ def app_ssowatconf():
# FIXME : this could be handled by nginx's regen conf to further simplify ssowat's code ... # FIXME : this could be handled by nginx's regen conf to further simplify ssowat's code ...
redirected_urls = {} redirected_urls = {}
for domain in domains: for domain in domains:
default_app = domain_config_get(domain, "feature.app.default_app") default_app = _get_raw_domain_settings(domain).get("default_app")
if default_app != "_none" and _is_installed(default_app): if default_app not in ["_none", None] and _is_installed(default_app):
app_settings = _get_app_settings(default_app) app_settings = _get_app_settings(default_app)
app_domain = app_settings["domain"] app_domain = app_settings["domain"]
app_path = app_settings["path"] app_path = app_settings["path"]
@ -1753,11 +1751,13 @@ def app_change_label(app, new_label):
def app_action_list(app): def app_action_list(app):
AppConfigPanel = _get_AppConfigPanel()
return AppConfigPanel(app).list_actions() return AppConfigPanel(app).list_actions()
@is_unit_operation() @is_unit_operation()
def app_action_run(operation_logger, app, action, args=None, args_file=None): def app_action_run(operation_logger, app, action, args=None, args_file=None):
AppConfigPanel = _get_AppConfigPanel()
return AppConfigPanel(app).run_action( return AppConfigPanel(app).run_action(
action, args=args, args_file=args_file, operation_logger=operation_logger action, args=args, args_file=args_file, operation_logger=operation_logger
) )
@ -1779,6 +1779,7 @@ def app_config_get(app, key="", full=False, export=False):
else: else:
mode = "classic" mode = "classic"
AppConfigPanel = _get_AppConfigPanel()
try: try:
config_ = AppConfigPanel(app) config_ = AppConfigPanel(app)
return config_.get(key, mode) return config_.get(key, mode)
@ -1798,12 +1799,16 @@ def app_config_set(
Apply a new app configuration Apply a new app configuration
""" """
AppConfigPanel = _get_AppConfigPanel()
config_ = AppConfigPanel(app) config_ = AppConfigPanel(app)
return config_.set(key, value, args, args_file, operation_logger=operation_logger) return config_.set(key, value, args, args_file, operation_logger=operation_logger)
class AppConfigPanel(ConfigPanel): def _get_AppConfigPanel():
from yunohost.utils.configpanel import ConfigPanel
class AppConfigPanel(ConfigPanel):
entity_type = "app" entity_type = "app"
save_path_tpl = os.path.join(APPS_SETTING_PATH, "{entity}/settings.yml") save_path_tpl = os.path.join(APPS_SETTING_PATH, "{entity}/settings.yml")
config_path_tpl = os.path.join(APPS_SETTING_PATH, "{entity}/config_panel.toml") config_path_tpl = os.path.join(APPS_SETTING_PATH, "{entity}/config_panel.toml")
@ -1852,10 +1857,10 @@ class AppConfigPanel(ConfigPanel):
if not os.path.exists(config_script): if not os.path.exists(config_script):
logger.debug("Adding a default config script") logger.debug("Adding a default config script")
default_script = """#!/bin/bash default_script = """#!/bin/bash
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
ynh_abort_if_errors ynh_abort_if_errors
ynh_app_config_run $1 ynh_app_config_run $1
""" """
write_to_file(config_script, default_script) write_to_file(config_script, default_script)
# Call config script to extract current values # Call config script to extract current values
@ -1884,6 +1889,8 @@ ynh_app_config_run $1
raise YunohostError("app_action_failed", action=action, app=app) raise YunohostError("app_action_failed", action=action, app=app)
return values return values
return AppConfigPanel
def _get_app_settings(app): def _get_app_settings(app):
""" """
@ -2782,6 +2789,7 @@ def _get_conflicting_apps(domain, path, ignore_app=None):
""" """
from yunohost.domain import _assert_domain_exists from yunohost.domain import _assert_domain_exists
from yunohost.utils.form import DomainOption, WebPathOption
domain = DomainOption.normalize(domain) domain = DomainOption.normalize(domain)
path = WebPathOption.normalize(path) path = WebPathOption.normalize(path)

View file

@ -34,17 +34,8 @@ from moulinette.utils.filesystem import (
write_to_yaml, write_to_yaml,
) )
from yunohost.app import (
app_ssowatconf,
_installed_apps,
_get_app_settings,
_get_conflicting_apps,
)
from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf
from yunohost.utils.configpanel import ConfigPanel
from yunohost.utils.form import BaseOption
from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.utils.dns import is_yunohost_dyndns_domain
from yunohost.log import is_unit_operation from yunohost.log import is_unit_operation
if TYPE_CHECKING: if TYPE_CHECKING:
@ -191,7 +182,7 @@ def domain_info(domain):
domain -- Domain to be checked domain -- Domain to be checked
""" """
from yunohost.app import app_info from yunohost.app import app_info, _installed_apps, _get_app_settings
from yunohost.dns import _get_registar_settings from yunohost.dns import _get_registar_settings
from yunohost.certificate import certificate_status from yunohost.certificate import certificate_status
@ -268,6 +259,7 @@ def domain_add(
from yunohost.utils.ldap import _get_ldap_interface from yunohost.utils.ldap import _get_ldap_interface
from yunohost.utils.password import assert_password_is_strong_enough from yunohost.utils.password import assert_password_is_strong_enough
from yunohost.certificate import _certificate_install_selfsigned from yunohost.certificate import _certificate_install_selfsigned
from yunohost.utils.dns import is_yunohost_dyndns_domain
if dyndns_recovery_password: if dyndns_recovery_password:
operation_logger.data_to_redact.append(dyndns_recovery_password) operation_logger.data_to_redact.append(dyndns_recovery_password)
@ -383,8 +375,15 @@ def domain_remove(
""" """
import glob import glob
from yunohost.hook import hook_callback from yunohost.hook import hook_callback
from yunohost.app import app_ssowatconf, app_info, app_remove from yunohost.app import (
app_ssowatconf,
app_info,
app_remove,
_get_app_settings,
_installed_apps,
)
from yunohost.utils.ldap import _get_ldap_interface from yunohost.utils.ldap import _get_ldap_interface
from yunohost.utils.dns import is_yunohost_dyndns_domain
if dyndns_recovery_password: if dyndns_recovery_password:
operation_logger.data_to_redact.append(dyndns_recovery_password) operation_logger.data_to_redact.append(dyndns_recovery_password)
@ -566,6 +565,7 @@ def domain_main_domain(operation_logger, new_main_domain=None):
""" """
from yunohost.tools import _set_hostname from yunohost.tools import _set_hostname
from yunohost.app import app_ssowatconf
# If no new domain specified, we return the current main domain # If no new domain specified, we return the current main domain
if not new_main_domain: if not new_main_domain:
@ -614,6 +614,8 @@ def domain_url_available(domain, path):
path -- The path to check (e.g. /coffee) path -- The path to check (e.g. /coffee)
""" """
from yunohost.app import _get_conflicting_apps
return len(_get_conflicting_apps(domain, path)) == 0 return len(_get_conflicting_apps(domain, path)) == 0
@ -623,7 +625,8 @@ def _get_raw_domain_settings(domain):
so the file may be completely empty so the file may be completely empty
""" """
_assert_domain_exists(domain) _assert_domain_exists(domain)
path = DomainConfigPanel.save_path_tpl.format(entity=domain) # NB: this corresponds to save_path_tpl in DomainConfigPanel
path = f"{DOMAIN_SETTINGS_DIR}/{domain}.yml"
if os.path.exists(path): if os.path.exists(path):
return read_yaml(path) return read_yaml(path)
@ -647,6 +650,7 @@ def domain_config_get(domain, key="", full=False, export=False):
else: else:
mode = "classic" mode = "classic"
DomainConfigPanel = _get_DomainConfigPanel()
config = DomainConfigPanel(domain) config = DomainConfigPanel(domain)
return config.get(key, mode) return config.get(key, mode)
@ -658,12 +662,18 @@ def domain_config_set(
""" """
Apply a new domain configuration Apply a new domain configuration
""" """
from yunohost.utils.form import BaseOption
DomainConfigPanel = _get_DomainConfigPanel()
BaseOption.operation_logger = operation_logger BaseOption.operation_logger = operation_logger
config = DomainConfigPanel(domain) config = DomainConfigPanel(domain)
return config.set(key, value, args, args_file, operation_logger=operation_logger) return config.set(key, value, args, args_file, operation_logger=operation_logger)
class DomainConfigPanel(ConfigPanel): def _get_DomainConfigPanel():
from yunohost.utils.configpanel import ConfigPanel
class DomainConfigPanel(ConfigPanel):
entity_type = "domain" entity_type = "domain"
save_path_tpl = f"{DOMAIN_SETTINGS_DIR}/{{entity}}.yml" save_path_tpl = f"{DOMAIN_SETTINGS_DIR}/{{entity}}.yml"
save_mode = "diff" save_mode = "diff"
@ -693,7 +703,9 @@ class DomainConfigPanel(ConfigPanel):
if not any_filter or panel_id == "dns": if not any_filter or panel_id == "dns":
from yunohost.dns import _get_registrar_config_section from yunohost.dns import _get_registrar_config_section
raw_config["dns"]["registrar"] = _get_registrar_config_section(self.entity) raw_config["dns"]["registrar"] = _get_registrar_config_section(
self.entity
)
# Cert stuff # Cert stuff
if not any_filter or panel_id == "cert": if not any_filter or panel_id == "cert":
@ -721,7 +733,9 @@ class DomainConfigPanel(ConfigPanel):
# FIXME not sure why "summary" was injected in settings values # FIXME not sure why "summary" was injected in settings values
# ("summary", "summary") # ("summary", "summary")
]: ]:
raw_config["cert"]["cert"][option_id]["default"] = status[status_key] raw_config["cert"]["cert"][option_id]["default"] = status[
status_key
]
# Other specific strings used in config panels # Other specific strings used in config panels
# i18n: domain_config_cert_renew_help # i18n: domain_config_cert_renew_help
@ -739,7 +753,7 @@ class DomainConfigPanel(ConfigPanel):
} }
if "default_app" in next_settings: if "default_app" in next_settings:
from yunohost.app import app_ssowatconf, app_map from yunohost.app import app_map
if "/" in app_map(raw=True).get(self.entity, {}): if "/" in app_map(raw=True).get(self.entity, {}):
raise YunohostValidationError( raise YunohostValidationError(
@ -816,6 +830,8 @@ class DomainConfigPanel(ConfigPanel):
# Reload ssowat if default app changed # Reload ssowat if default app changed
if "default_app" in next_settings: if "default_app" in next_settings:
from yunohost.app import app_ssowatconf
app_ssowatconf() app_ssowatconf()
stuff_to_regen_conf = set() stuff_to_regen_conf = set()
@ -828,6 +844,8 @@ class DomainConfigPanel(ConfigPanel):
if stuff_to_regen_conf: if stuff_to_regen_conf:
regen_conf(names=list(stuff_to_regen_conf)) regen_conf(names=list(stuff_to_regen_conf))
return DomainConfigPanel
def domain_action_run(domain, action, args=None): def domain_action_run(domain, action, args=None):
import urllib.parse import urllib.parse