Skip to main content

max / makenotwork

3.8 KB · 97 lines History Blame Raw
1 //! Background TLS certificate check task.
2
3 use tokio::task::JoinHandle;
4 use tracing::info;
5
6 use pom::alerts::Alerter;
7 use pom::checks::tls;
8 use pom::config::Config;
9 use pom::db;
10
11 use super::{CheckInterval, configured_targets};
12
13 pub(crate) fn spawn_tls_tasks(
14 config: &Config,
15 pool: &sqlx::SqlitePool,
16 cancel: &tokio_util::sync::CancellationToken,
17 alerter: Option<&Alerter>,
18 ) -> Vec<JoinHandle<()>> {
19 let tls_interval_secs = config.serve.tls_check_interval_secs;
20 let mut handles = Vec::new();
21
22 for (name, target_config) in configured_targets(config) {
23 if let Some(tls_config) = target_config.tls {
24 let pool = pool.clone();
25 let name = name.clone();
26 let label = target_config.label.clone();
27 let alerter = alerter.cloned();
28 let warn_days = tls_config.warn_days;
29 let cancel = cancel.clone();
30
31 info!(
32 "{name}: TLS check every {tls_interval_secs}s (host={})",
33 tls_config.host
34 );
35
36 handles.push(tokio::spawn(async move {
37 let mut ticks = CheckInterval::new(tls_interval_secs, cancel);
38 while ticks.next().await {
39 let previous = db::get_latest_tls_check(&pool, &name).await.ok().flatten();
40 let status = tls::check_tls(&name, &tls_config).await;
41 info!(
42 "{}: TLS {}, {}d remaining",
43 name,
44 if status.valid { "valid" } else { "invalid" },
45 status.days_remaining
46 );
47 if let Err(e) = db::insert_tls_check(&pool, &status).await {
48 tracing::error!("{name}: failed to store TLS check: {e}");
49 }
50
51 // Fire alerts on TLS state transitions
52 if let Some(ref alerter) = alerter {
53 let was_ok = previous
54 .as_ref()
55 .is_none_or(|p| p.valid && p.error.is_none());
56 let now_warn = status.valid && status.days_remaining <= warn_days as i64;
57 let now_error = !status.valid || status.error.is_some();
58
59 if was_ok && now_error {
60 alerter
61 .send_tls_error_alert(
62 &name,
63 &tls_config.host,
64 status.error.as_deref().unwrap_or("certificate invalid"),
65 )
66 .await;
67 } else if was_ok && now_warn {
68 alerter
69 .send_tls_expiry_alert(
70 &name,
71 &tls_config.host,
72 status.days_remaining,
73 &status.not_after,
74 )
75 .await;
76 } else if let Some(ref prev) = previous {
77 let was_bad = !prev.valid
78 || prev.error.is_some()
79 || prev.days_remaining <= warn_days as i64;
80 let now_ok = status.valid
81 && status.error.is_none()
82 && status.days_remaining > warn_days as i64;
83 if was_bad && now_ok {
84 alerter
85 .send_tls_recovery(&name, &label, status.days_remaining)
86 .await;
87 }
88 }
89 }
90 }
91 }));
92 }
93 }
94
95 handles
96 }
97