diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs index 8848c1e3..ea3c3776 100644 --- a/src/api2/config/datastore.rs +++ b/src/api2/config/datastore.rs @@ -5,6 +5,7 @@ use serde_json::Value; use ::serde::{Deserialize, Serialize}; use proxmox::api::{api, Router, RpcEnvironment, Permission}; +use proxmox::api::schema::parse_property_string; use proxmox::tools::fs::open_file_locked; use crate::api2::types::*; @@ -74,7 +75,7 @@ pub fn list_datastores( }, "notify": { optional: true, - type: Notify, + schema: DATASTORE_NOTIFY_STRING_SCHEMA, }, "gc-schedule": { optional: true, @@ -218,7 +219,7 @@ pub enum DeletableProperty { }, "notify": { optional: true, - type: Notify, + schema: DATASTORE_NOTIFY_STRING_SCHEMA, }, "gc-schedule": { optional: true, @@ -282,7 +283,7 @@ pub fn update_datastore( keep_weekly: Option, keep_monthly: Option, keep_yearly: Option, - notify: Option, + notify: Option, notify_user: Option, delete: Option>, digest: Option, @@ -346,7 +347,15 @@ pub fn update_datastore( if keep_monthly.is_some() { data.keep_monthly = keep_monthly; } if keep_yearly.is_some() { data.keep_yearly = keep_yearly; } - if notify.is_some() { data.notify = notify; } + if let Some(notify_str) = notify { + let value = parse_property_string(¬ify_str, &DatastoreNotify::API_SCHEMA)?; + let notify: DatastoreNotify = serde_json::from_value(value)?; + if let DatastoreNotify { gc: None, verify: None, sync: None } = notify { + data.notify = None; + } else { + data.notify = Some(notify_str); + } + } if notify_user.is_some() { data.notify_user = notify_user; } config.set_data(&name, "datastore", &data)?; diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs index 7ee89f57..2380e36a 100644 --- a/src/api2/types/mod.rs +++ b/src/api2/types/mod.rs @@ -1167,3 +1167,35 @@ pub enum Notify { /// Send notifications for failed jobs only Error, } + +#[api( + properties: { + gc: { + type: Notify, + optional: true, + }, + verify: { + type: Notify, + optional: true, + }, + sync: { + type: Notify, + optional: true, + }, + }, +)] +#[derive(Debug, Serialize, Deserialize)] +/// Datastore notify settings +pub struct DatastoreNotify { + /// Garbage collection settings + pub gc: Option, + /// Verify job setting + pub verify: Option, + /// Sync job setting + pub sync: Option, +} + +pub const DATASTORE_NOTIFY_STRING_SCHEMA: Schema = StringSchema::new( + "Datastore notification setting") + .format(&ApiStringFormat::PropertyString(&DatastoreNotify::API_SCHEMA)) + .schema(); diff --git a/src/config/datastore.rs b/src/config/datastore.rs index 7e38a783..4c3031fc 100644 --- a/src/config/datastore.rs +++ b/src/config/datastore.rs @@ -38,7 +38,7 @@ pub const DIR_NAME_SCHEMA: Schema = StringSchema::new("Directory name").schema() }, "notify": { optional: true, - type: Notify, + schema: DATASTORE_NOTIFY_STRING_SCHEMA, }, comment: { optional: true, @@ -114,7 +114,7 @@ pub struct DataStoreConfig { pub notify_user: Option, /// Send notification only for job errors #[serde(skip_serializing_if="Option::is_none")] - pub notify: Option, + pub notify: Option, } fn init() -> SectionConfig { diff --git a/src/server/email_notifications.rs b/src/server/email_notifications.rs index a3bca801..a4383361 100644 --- a/src/server/email_notifications.rs +++ b/src/server/email_notifications.rs @@ -4,6 +4,7 @@ use serde_json::json; use handlebars::{Handlebars, Helper, Context, RenderError, RenderContext, Output, HelperResult}; use proxmox::tools::email::sendmail; +use proxmox::api::schema::parse_property_string; use crate::{ config::datastore::DataStoreConfig, @@ -14,6 +15,7 @@ use crate::{ GarbageCollectionStatus, Userid, Notify, + DatastoreNotify, }, tools::format::HumanByte, }; @@ -190,14 +192,19 @@ fn send_job_status_mail( pub fn send_gc_status( email: &str, - notify: Notify, + notify: DatastoreNotify, datastore: &str, status: &GarbageCollectionStatus, result: &Result<(), Error>, ) -> Result<(), Error> { - if notify == Notify::Never || (result.is_ok() && notify == Notify::Error) { - return Ok(()); + match notify.gc { + None => { /* send notifications by default */ }, + Some(notify) => { + if notify == Notify::Never || (result.is_ok() && notify == Notify::Error) { + return Ok(()); + } + } } let (fqdn, port) = get_server_url(); @@ -244,15 +251,11 @@ pub fn send_gc_status( pub fn send_verify_status( email: &str, - notify: Notify, + notify: DatastoreNotify, job: VerificationJobConfig, result: &Result, Error>, ) -> Result<(), Error> { - if notify == Notify::Never || (result.is_ok() && notify == Notify::Error) { - return Ok(()); - } - let (fqdn, port) = get_server_url(); let mut data = json!({ "job": job, @@ -260,8 +263,11 @@ pub fn send_verify_status( "port": port, }); + let mut result_is_ok = false; + let text = match result { Ok(errors) if errors.is_empty() => { + result_is_ok = true; HANDLEBARS.render("verify_ok_template", &data)? } Ok(errors) => { @@ -274,6 +280,15 @@ pub fn send_verify_status( } }; + match notify.verify { + None => { /* send notifications by default */ }, + Some(notify) => { + if notify == Notify::Never || (result_is_ok && notify == Notify::Error) { + return Ok(()); + } + } + } + let subject = match result { Ok(errors) if errors.is_empty() => format!( "Verify Datastore '{}' successful", @@ -292,13 +307,18 @@ pub fn send_verify_status( pub fn send_sync_status( email: &str, - notify: Notify, + notify: DatastoreNotify, job: &SyncJobConfig, result: &Result<(), Error>, ) -> Result<(), Error> { - if notify == Notify::Never || (result.is_ok() && notify == Notify::Error) { - return Ok(()); + match notify.sync { + None => { /* send notifications by default */ }, + Some(notify) => { + if notify == Notify::Never || (result.is_ok() && notify == Notify::Error) { + return Ok(()); + } + } } let (fqdn, port) = get_server_url(); @@ -399,11 +419,12 @@ fn lookup_user_email(userid: &Userid) -> Option { /// Lookup Datastore notify settings pub fn lookup_datastore_notify_settings( store: &str, -) -> (Option, Notify) { +) -> (Option, DatastoreNotify) { - let mut notify = Notify::Always; let mut email = None; + let notify = DatastoreNotify { gc: None, verify: None, sync: None }; + let (config, _digest) = match crate::config::datastore::config() { Ok(result) => result, Err(_) => return (email, notify), @@ -419,8 +440,12 @@ pub fn lookup_datastore_notify_settings( None => lookup_user_email(Userid::backup_userid()), }; - if let Some(value) = config.notify { - notify = value; + let notify_str = config.notify.unwrap_or(String::new()); + + if let Ok(value) = parse_property_string(¬ify_str, &DatastoreNotify::API_SCHEMA) { + if let Ok(notify) = serde_json::from_value(value) { + return (email, notify); + } } (email, notify)