(&self, domain: &str, force: bool)
| 96 | /// Try to renew certificate for a specific domain if needed |
| 97 | #[tracing::instrument(skip(self))] |
| 98 | pub async fn try_renew(&self, domain: &str, force: bool) -> Result<bool> { |
| 99 | // Check if config exists |
| 100 | let config = self |
| 101 | .kv_store |
| 102 | .get_zt_domain_config(domain) |
| 103 | .context("ZT-Domain config not found")?; |
| 104 | |
| 105 | // Check if renewal is needed |
| 106 | let cert_data = self.kv_store.get_cert_data(domain); |
| 107 | let needs_renew = if force { |
| 108 | true |
| 109 | } else if let Some(ref data) = cert_data { |
| 110 | let now = now_secs(); |
| 111 | let expires_in = data.not_after.saturating_sub(now); |
| 112 | expires_in < self.config().renew_before_expiration.as_secs() |
| 113 | } else { |
| 114 | true |
| 115 | }; |
| 116 | |
| 117 | if !needs_renew { |
| 118 | info!("does not need renewal"); |
| 119 | return Ok(false); |
| 120 | } |
| 121 | |
| 122 | // Try to acquire lock |
| 123 | if !self |
| 124 | .kv_store |
| 125 | .try_acquire_cert_lock(domain, RENEW_LOCK_TIMEOUT_SECS) |
| 126 | { |
| 127 | info!("another node is renewing, skipping"); |
| 128 | return Ok(false); |
| 129 | } |
| 130 | |
| 131 | info!("acquired renew lock, starting renewal"); |
| 132 | |
| 133 | // Perform renewal or initial issuance |
| 134 | let result = if cert_data.is_some() { |
| 135 | self.do_renew(domain, &config).await |
| 136 | } else { |
| 137 | // No existing certificate, request new one |
| 138 | info!("no existing certificate, requesting new one"); |
| 139 | self.do_request_new(domain, &config).await.map(|_| true) |
| 140 | }; |
| 141 | |
| 142 | // Release lock regardless of result |
| 143 | if let Err(err) = self.kv_store.release_cert_lock(domain) { |
| 144 | error!("failed to release lock: {err:?}"); |
| 145 | } |
| 146 | |
| 147 | result |
| 148 | } |
| 149 | |
| 150 | /// Request new certificate for a domain |
| 151 | #[tracing::instrument(skip(self))] |
no test coverage detected