From 7a4818c60a15b9ff71e94b3974fa31aa6241df50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arma=C3=ABl=20Gu=C3=A9neau?= Date: Wed, 10 Apr 2024 19:39:50 +0200 Subject: [PATCH] feature: allow specifying short names for repos --- src/main.rs | 79 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/src/main.rs b/src/main.rs index e999fbf..578257f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,7 @@ fn default_alert_duration() -> u64 { #[derive(Serialize, Deserialize)] struct RepoConfig { + name: Option, email: String, // all durations below are measured in days inactivity: u64, @@ -72,6 +73,13 @@ impl fmt::Display for AlertStatus { } } +fn repo_name(repo: &str, name: &Option) -> String { + match name { + None => repo.to_owned(), + Some(short_name) => format!("{} ({})", short_name, repo), + } +} + fn is_alert_needed( cfg: &RepoConfig, inactive_for: Duration, @@ -86,15 +94,26 @@ fn is_alert_needed( } } -async fn send_email(email: &str, repo: &str, inactive: Duration) -> eyre::Result<()> { +async fn send_email( + name: &Option, + email: &str, + repo: &str, + inactive: Duration, +) -> eyre::Result<()> { use lettre::{AsyncSendmailTransport, AsyncTransport, Message}; let email = Message::builder() .from("infracoll ".parse().unwrap()) .to(email.parse()?) - .subject(format!("restic-alarm: inactive repository {}", repo)) + .subject(format!( + "restic-alarm: inactive repository {}", + match name { + None => repo, + Some(name) => name, + } + )) .body(format!( "Alert: Repository {} has been inactive for {} days.\n", - repo, + repo_name(repo, name), inactive.as_secs() / (3600 * 24) )) .unwrap(); @@ -217,33 +236,42 @@ async fn repo_last_snapshot(client: &s3::Client, repo: &str) -> eyre::Result, + alert_status: Option, +} + // this function can fail for reasons that depend on the user-provided 'repo' config // (e.g. if it fails to parse). // So the error must not be propagated to the toplevel, which would abort the // alert for remaining repositories; it should instead just be reported/logged. -async fn check_repo( - client: &s3::Client, - state: &mut State, - repo: &str, -) -> eyre::Result> { +async fn check_repo(client: &s3::Client, state: &mut State, repo: &str) -> eyre::Result { let config = read_repo_config(client, repo).await?; - if let Some(inactivity) = repo_last_snapshot(client, repo).await? { + let alert_status = if let Some(inactivity) = repo_last_snapshot(client, repo).await? { let last_alert = state.last_alert(repo); let alert = is_alert_needed(&config, inactivity, last_alert); if alert { - println!("Sending alert to {} about bucket {}", config.email, repo); - send_email(&config.email, repo, inactivity).await?; + println!( + "Sending alert to {} about repo {}", + config.email, + repo_name(repo, &config.name) + ); + send_email(&config.name, &config.email, repo, inactivity).await?; state.update_last_alert(repo); write_state(client, state).await?; } - Ok(Some(AlertStatus { + Some(AlertStatus { alert, inactivity, last_alert, - })) + }) } else { - Ok(None) - } + None + }; + Ok(RepoInfo { + name: config.name.clone(), + alert_status, + }) } #[::tokio::main] @@ -260,15 +288,18 @@ async fn main() -> eyre::Result<()> { for repo in repos { match check_repo(&client, &mut state, &repo).await { - Ok(None) => { - println!("{}: no snapshot, skipping", &repo) - } - Ok(Some(status)) => { - println!("{}: {}", &repo, status); - } - Err(err) => { - // is this the best way to log the error? - println!("Error ({}): {:?}", &repo, err) + Ok(RepoInfo { + name, + alert_status: None, + }) => println!("{}: no snapshot, skipping", repo_name(&repo, &name)), + Ok(RepoInfo { + name, + alert_status: Some(status), + }) => println!("{}: {}", repo_name(&repo, &name), status), + Err(err) => + // is this the best way to log the error? + { + println!("{}: ERROR: {:?}", &repo, err) } } }