Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Test optimizations #1830

Open
wants to merge 8 commits into
base: bookworm
Choose a base branch
from
Prev Previous commit
Next Next commit
Add domains_add bulk operation
  • Loading branch information
selfhoster1312 committed May 10, 2024
commit 7a52066f5697b92037e8bb7ba5f41eb91334fc58
12 changes: 8 additions & 4 deletions src/certificate.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def certificate_install(domain_list, force=False, no_checks=False, self_signed=F
_certificate_install_letsencrypt(domain_list, force, no_checks)


def _certificate_install_selfsigned(domain_list, force=False):
def _certificate_install_selfsigned(domain_list, force=False, do_regen_conf=True):
failed_cert_install = []
for domain in domain_list:
operation_logger = OperationLogger(
Expand Down Expand Up @@ -201,7 +201,7 @@ def _certificate_install_selfsigned(domain_list, force=False):
_set_permissions(conf_file, "root", "root", 0o600)

# Actually enable the certificate we created
_enable_certificate(domain, new_cert_folder)
_enable_certificate(domain, new_cert_folder, do_regen_conf=do_regen_conf)

# Check new status indicate a recently created self-signed certificate
status = _get_status(domain)
Expand Down Expand Up @@ -627,7 +627,7 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder):
with open(csr_file, "wb") as f:
f.write(crypto.dump_certificate_request(crypto.FILETYPE_PEM, csr))

def _cert_exists(domain): bool
def _cert_exists(domain) -> bool:
cert_file = os.path.join(CERT_FOLDER, domain, "crt.pem")
return os.path.isfile(cert_file)

Expand Down Expand Up @@ -726,7 +726,7 @@ def _set_permissions(path, user, group, permissions):
chmod(path, permissions)


def _enable_certificate(domain, new_cert_folder):
def _enable_certificate(domain, new_cert_folder, do_regen_conf=True):
logger.debug("Enabling the certificate for domain %s ...", domain)

live_link = os.path.join(CERT_FOLDER, domain)
Expand All @@ -744,6 +744,10 @@ def _enable_certificate(domain, new_cert_folder):

os.symlink(new_cert_folder, live_link)

# We are in a higher operation such as domains_add for bulk manipulation
# that will take care of service / hooks later
if not do_regen_conf: return

logger.debug("Restarting services...")

for service in ("dovecot", "metronome"):
Expand Down
64 changes: 57 additions & 7 deletions src/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,58 @@ def _get_parent_domain_of(domain, return_self=False, topest=False):

return domain if return_self else None

def domains_regen(domains: List[str]):
for domain in domains:
_force_clear_hashes([f"/etc/nginx/conf.d/{domain}.conf"])

from yunohost.app import app_ssowatconf
from yunohost.service import _run_service_command
logger.debug("Restarting services...")
for service in ("dovecot", "metronome"):
# Ugly trick to not restart metronome if it's not installed or no domain configured for XMPP
if service == "metronome" and (
os.system("dpkg --list | grep -q 'ii *metronome'") != 0
or not glob("/etc/metronome/conf.d/*.cfg.lua")
):
continue
_run_service_command("restart", service)

if os.path.isfile("/etc/yunohost/installed"):
# regen nginx conf to be sure it integrates OCSP Stapling
# (We don't do this yet if postinstall is not finished yet)
# We also regenconf for postfix to propagate the SNI hash map thingy
regen_conf(
names=[
"nginx",
"metronome",
"dnsmasq",
"postfix",
"rspamd",
"mdns",
"dovecot",
]
)
app_ssowatconf()
_run_service_command("reload", "nginx")

# Used in tests to create many domains at once.
# The permissions/configuration are synchronized at the end of the entire operation.
@is_unit_operation()
def domains_add(operation_logger, domains: List[str]):
for domain in domains:
domain_add(domain, do_regen_conf=False)

domains_regen(domains)

from yunohost.hook import hook_callback
for domain in domains:
hook_callback("post_cert_update", args=[domain])
hook_callback("post_domain_add", args=[domain])
logger.success(m18n.n("domain_created"))

@is_unit_operation(exclude=["dyndns_recovery_password"])
def domain_add(
operation_logger, domain, dyndns_recovery_password=None, ignore_dyndns=False
operation_logger, domain, dyndns_recovery_password=None, ignore_dyndns=False, do_regen_conf=True
):
"""
Create a custom domain
Expand All @@ -258,7 +306,7 @@ def domain_add(
from yunohost.app import app_ssowatconf
from yunohost.utils.ldap import _get_ldap_interface
from yunohost.utils.password import assert_password_is_strong_enough
from yunohost.certificate import _certificate_install_selfsigned
from yunohost.certificate import _certificate_install_selfsigned, _cert_exists
from yunohost.utils.dns import is_yunohost_dyndns_domain

if dyndns_recovery_password:
Expand Down Expand Up @@ -306,7 +354,8 @@ def domain_add(
domain=domain, recovery_password=dyndns_recovery_password
)

_certificate_install_selfsigned([domain], True)
if not _cert_exists(domain):
_certificate_install_selfsigned([domain], True, do_regen_conf=False)

try:
attr_dict = {
Expand All @@ -323,7 +372,8 @@ def domain_add(
domain_list_cache = []

# Don't regen these conf if we're still in postinstall
if os.path.exists("/etc/yunohost/installed"):
# or if we're in a higher operation that will take care of it, such as domains_add
if os.path.exists("/etc/yunohost/installed") and do_regen_conf:
# Sometime we have weird issues with the regenconf where some files
# appears as manually modified even though they weren't touched ...
# There are a few ideas why this happens (like backup/restore nginx
Expand Down Expand Up @@ -356,9 +406,9 @@ def domain_add(
pass
raise e

hook_callback("post_domain_add", args=[domain])

logger.success(m18n.n("domain_created"))
if do_regen_conf:
hook_callback("post_domain_add", args=[domain])
logger.success(m18n.n("domain_created"))


@is_unit_operation(exclude=["dyndns_recovery_password"])
Expand Down
5 changes: 2 additions & 3 deletions src/tests/test_sso_and_portalapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from .conftest import message, raiseYunohostError, get_test_apps_dir

from yunohost.domain import _get_maindomain, domain_add, domain_remove, domain_list
from yunohost.domain import _get_maindomain, domain_add, domain_remove, domain_list, domains_add
from yunohost.user import user_create, user_list, user_delete, User, users_add
from yunohost.authenticators.ldap_ynhuser import Authenticator, SESSION_FOLDER, short_hash
from yunohost.app import app_install, app_remove, app_setting, app_ssowatconf, app_change_url
Expand Down Expand Up @@ -52,8 +52,7 @@ def setup_module(module):

domainlist = domain_list()["domains"]
domains = [ domain for domain in [ subdomain, secondarydomain ] if domain not in domainlist ]
for domain in domains:
domain_add(domain)
domains_add(domains)

app_install(
os.path.join(get_test_apps_dir(), "hellopy_ynh"),
Expand Down