Coverage for frappe_manager / site_manager / modules / bench_ssl.py: 37%
43 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-07-02 18:13 +0530
« prev ^ index » next coverage.py v7.13.5, created at 2026-07-02 18:13 +0530
1"""BenchSSL - SSL Certificate Management Module
3This module handles all SSL certificate operations for a bench including:
4- Creating certificates
5- Checking certificate existence
6- Removing certificates
7- Updating certificates
8- Renewing certificates
9"""
11from frappe_manager.site_manager.bench_config import SSLCertificate
12from frappe_manager.site_manager.exceptions import (
13 BenchServiceNotRunning,
14 BenchSSLCertificateAlreadyIssued,
15 BenchSSLCertificateNotIssued,
16)
17from frappe_manager.ssl_manager.certificate import SUPPORTED_SSL_TYPES
18from frappe_manager.ssl_manager.ssl_certificate_manager import SSLCertificateManager
21class BenchSSL:
22 """Manages SSL certificates for a bench."""
24 def __init__(
25 self,
26 certificate_manager: SSLCertificateManager,
27 bench_name: str,
28 is_service_running_fn,
29 ):
30 """
31 Initialize BenchSSL module.
33 Args:
34 certificate_manager: SSL certificate manager instance
35 bench_name: Name of the bench
36 is_service_running_fn: Function to check if a service is running
37 """
38 self.certificate_manager = certificate_manager
39 self.bench_name = bench_name
40 self._is_service_running = is_service_running_fn
42 def create_individual_certificates(self) -> None:
43 """
44 Create individual SSL certificates for all domains.
46 This generates separate certificates for the primary domain and each
47 alias domain, rather than a single SAN certificate covering all domains.
48 """
49 self.certificate_manager.generate_all_certificates()
51 def has_certificate(self) -> bool:
52 """
53 Check if bench has an SSL certificate.
55 Returns:
56 True if certificate exists, False otherwise
57 """
58 return self.certificate_manager.has_certificate()
60 def remove_certificate(self, domain: str | None = None) -> None:
61 """
62 Remove SSL certificate from the bench.
64 Args:
65 domain: Domain to remove certificate for. If None, removes primary certificate.
66 """
67 self.certificate_manager.remove_certificate(domain)
69 def remove_all_certificates(self) -> None:
70 """
71 Remove ALL SSL certificates from the bench.
73 This removes all certificates for the primary domain and all alias domains,
74 including their symlinks, vhost configs, and acme.sh configurations.
75 This is useful for complete cleanup when deleting a bench.
76 """
77 self.certificate_manager.remove_all_certificates()
79 def update_certificate(self, certificate: SSLCertificate, raise_error: bool = True) -> bool:
80 """
81 Update SSL certificate configuration.
83 Args:
84 certificate: New certificate configuration
85 raise_error: Whether to raise error on failures
87 Returns:
88 True if update was successful
90 Raises:
91 BenchSSLCertificateAlreadyIssued: If certificate already exists (when raise_error=True)
92 BenchSSLCertificateNotIssued: If trying to remove non-existent cert (when raise_error=True)
93 """
94 if certificate.ssl_type == SUPPORTED_SSL_TYPES.le:
95 if self.has_certificate():
96 if raise_error:
97 raise BenchSSLCertificateAlreadyIssued(self.bench_name)
98 return False
99 self.create_individual_certificates()
101 elif certificate.ssl_type == SUPPORTED_SSL_TYPES.none:
102 if self.has_certificate():
103 self.remove_certificate()
104 else:
105 if not raise_error:
106 return False
107 raise BenchSSLCertificateNotIssued(self.bench_name)
109 return True
111 def renew_certificate(self, domain: str | None = None, dry_run: bool = False, force: bool = False) -> None:
112 """
113 Renew existing SSL certificate.
115 Args:
116 domain: Domain to renew certificate for. If None, renews primary certificate.
117 dry_run: If True, uses Let's Encrypt staging server and skips system modifications
118 force: If True, forces renewal even if certificate is not due for renewal
120 Raises:
121 BenchSSLCertificateNotIssued: If no certificate exists
122 BenchServiceNotRunning: If nginx service is not running
123 """
124 if not self.has_certificate():
125 raise BenchSSLCertificateNotIssued(self.bench_name)
127 if not self._is_service_running("nginx"):
128 raise BenchServiceNotRunning(self.bench_name, "nginx")
130 self.certificate_manager.renew_certificate(domain, dry_run=dry_run, force=force)
132 def renew_all_certificates(self, dry_run: bool = False, force: bool = False) -> None:
133 """
134 Renew all SSL certificates for the bench.
136 This renews all certificates that are due for renewal.
137 Certificates not due for renewal are skipped.
139 Args:
140 dry_run: If True, uses Let's Encrypt staging server and skips system modifications
141 force: If True, forces renewal for all certificates regardless of expiry
143 Raises:
144 BenchSSLCertificateNotIssued: If no certificates exist
145 BenchServiceNotRunning: If nginx service is not running
146 """
147 if not self.has_certificate():
148 raise BenchSSLCertificateNotIssued(self.bench_name)
150 if not self._is_service_running("nginx"):
151 raise BenchServiceNotRunning(self.bench_name, "nginx")
153 self.certificate_manager.renew_all_certificates(dry_run=dry_run, force=force)