From 8ff1a14e84e8ccd66b2898d661d9d566e6c8d1b1 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Sat, 20 Apr 2024 18:59:14 -0400 Subject: [PATCH] letsencrypt: Re-obtain certificates during repair - Set check_id and domain for domain diagnostic check - If there is an error, store it in thread local storage. - Drop checking for case when no domain is configured. This is better done after initial setup via notification rather than in diagnostics. Proposed change also will not show the warning if a .local domain is configured (almost always). Keep checking for Check id to deal with older stored diagnostic results. - Call obtain when certificate is not available. Call re-obtain otherwise. This is important for properly calling the post-obtain operations. Signed-off-by: James Valleroy [sunil: Drop check for case when no domain is configured] [sunil: Call either obtain or re-obtain based on current state of certificate] Signed-off-by: Sunil Mohan Adapa Reviewed-by: Sunil Mohan Adapa --- plinth/modules/letsencrypt/__init__.py | 40 ++++++++++++++++++++------ 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/plinth/modules/letsencrypt/__init__.py b/plinth/modules/letsencrypt/__init__.py index 5464126f0..4f652b11d 100644 --- a/plinth/modules/letsencrypt/__init__.py +++ b/plinth/modules/letsencrypt/__init__.py @@ -17,6 +17,7 @@ from plinth.modules.apache.components import diagnose_url from plinth.modules.backups.components import BackupRestore from plinth.modules.names.components import DomainType from plinth.package import Packages +from plinth.setup import store_error_message from plinth.signals import domain_added, domain_removed, post_app_loading from plinth.utils import format_lazy @@ -96,17 +97,40 @@ class LetsEncryptApp(app_module.App): for domain in names.components.DomainName.list(): if domain.domain_type.can_have_certificate: - results.append(diagnose_url('https://' + domain.name)) - - if not results: - results.append( - DiagnosticCheck( - 'letsencrypt-cannot-test', - gettext_noop('Cannot test: No domains are configured.'), - Result.WARNING)) + result = diagnose_url('https://' + domain.name) + result.check_id = f'letsencrypt-domain-{domain.name}' + result.parameters['domain'] = domain.name + results.append(result) return results + def repair(self, failed_checks: list) -> bool: + """Try to repair failed diagnostics. + + Returns whether the app setup should be re-run. + """ + status = get_status() + + # Obtain/re-obtain certificates for failing domains + for failed_check in failed_checks: + if not failed_check.check_id.startswith('letsencrypt-domain'): + continue + + domain = failed_check.parameters['domain'] + try: + domain_status = status['domains'][domain] + if domain_status.get('certificate_available', False): + certificate_obtain(domain) + else: + certificate_reobtain(domain) + except Exception as error: + # This happens if a non-functional domain is configured. + logger.error('Could not re-obtain certificate: %s', error) + # Add the error message to thread local storage + store_error_message(str(error)) + + return False + def setup(self, old_version): """Install and configure the app.""" super().setup(old_version)