all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Lukas Wagner <l.wagner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH proxmox 1/2] notify: api: allow resetting built-in targets when they are referenced
Date: Thu, 14 Dec 2023 13:42:07 +0100	[thread overview]
Message-ID: <20231214124208.219312-1-l.wagner@proxmox.com> (raw)

by a matcher.

In the 'delete'-handler targets, we check if a
target is still referenced by a matcher - if it is, we return an
error. For built-in targets, this is actually not necessary, since
'deleting' a built-in only resets it to its default settings - it will
continue to exist after that.
The user could easily trigger this if 'mail-to-root', which is
referenced by 'default-matcher' is modified and then reset to its
defaults: An error is shown, the built-in target is not reset.

This commit disables this check if it is a built-in target.

Renamed the helper 'ensure_unused' to 'ensure_safe_to_delete' in the
process.

Also fixed the tests in api::test - they were never executed due to a
faulty #[cfg] directive.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
 proxmox-notify/src/api/gotify.rs   |  2 +-
 proxmox-notify/src/api/mod.rs      | 74 ++++++++++++++++++++++--------
 proxmox-notify/src/api/sendmail.rs |  2 +-
 proxmox-notify/src/api/smtp.rs     |  2 +-
 4 files changed, 59 insertions(+), 21 deletions(-)

diff --git a/proxmox-notify/src/api/gotify.rs b/proxmox-notify/src/api/gotify.rs
index 98ff255..a93a024 100644
--- a/proxmox-notify/src/api/gotify.rs
+++ b/proxmox-notify/src/api/gotify.rs
@@ -136,7 +136,7 @@ pub fn update_endpoint(
 pub fn delete_gotify_endpoint(config: &mut Config, name: &str) -> Result<(), HttpError> {
     // Check if the endpoint exists
     let _ = get_endpoint(config, name)?;
-    super::ensure_unused(config, name)?;
+    super::ensure_safe_to_delete(config, name)?;
 
     remove_private_config_entry(config, name)?;
     config.config.sections.remove(name);
diff --git a/proxmox-notify/src/api/mod.rs b/proxmox-notify/src/api/mod.rs
index 762d448..919dcb9 100644
--- a/proxmox-notify/src/api/mod.rs
+++ b/proxmox-notify/src/api/mod.rs
@@ -3,7 +3,7 @@ use std::collections::HashSet;
 
 use proxmox_http_error::HttpError;
 
-use crate::Config;
+use crate::{Config, Origin};
 
 pub mod common;
 #[cfg(feature = "gotify")]
@@ -111,7 +111,26 @@ fn get_referrers(config: &Config, entity: &str) -> Result<HashSet<String>, HttpE
     Ok(referrers)
 }
 
-fn ensure_unused(config: &Config, entity: &str) -> Result<(), HttpError> {
+fn ensure_safe_to_delete(config: &Config, entity: &str) -> Result<(), HttpError> {
+    if let Some(entity_config) = config.config.sections.get(entity) {
+        let origin: Option<Origin> = entity_config
+            .1
+            .as_object()
+            .and_then(|obj| obj.get("origin"))
+            .cloned()
+            .and_then(|origin_value| serde_json::from_value(origin_value).ok());
+        if let Some(origin) = origin {
+            // Built-ins are never actually removed, only reset to their default
+            // It is thus safe to do the reset if another entity depends
+            // on it
+            if origin == Origin::Builtin || origin == Origin::ModifiedBuiltin {
+                return Ok(());
+            }
+        }
+    } else {
+        http_bail!(NOT_FOUND, "entity '{entity}' does not exist");
+    }
+
     let referrers = get_referrers(config, entity)?;
 
     if !referrers.is_empty() {
@@ -191,31 +210,31 @@ mod test_helpers {
     }
 }
 
-#[cfg(all(test, gotify, sendmail))]
+#[cfg(all(test, feature = "gotify", feature = "sendmail"))]
 mod tests {
     use super::*;
     use crate::endpoints::gotify::{GotifyConfig, GotifyPrivateConfig};
     use crate::endpoints::sendmail::SendmailConfig;
-    use crate::filter::FilterConfig;
-    use crate::group::GroupConfig;
+    use crate::matcher::MatcherConfig;
 
     fn prepare_config() -> Result<Config, HttpError> {
-        let mut config = super::test_helpers::empty_config();
+        let mut config = test_helpers::empty_config();
 
-        matcher::add_matcher(
+        sendmail::add_endpoint(
             &mut config,
-            &MatcherConfig {
-                name: "matcher".to_string(),
-                target: Some(vec!["sendmail".to_string(), "gotify".to_string()])
-                    ..Default::default(),
+            &SendmailConfig {
+                name: "sendmail".to_string(),
+                mailto: Some(vec!["foo@example.com".to_string()]),
+                ..Default::default()
             },
         )?;
 
         sendmail::add_endpoint(
             &mut config,
             &SendmailConfig {
-                name: "sendmail".to_string(),
+                name: "builtin".to_string(),
                 mailto: Some(vec!["foo@example.com".to_string()]),
+                origin: Some(Origin::Builtin),
                 ..Default::default()
             },
         )?;
@@ -233,6 +252,19 @@ mod tests {
             },
         )?;
 
+        matcher::add_matcher(
+            &mut config,
+            &MatcherConfig {
+                name: "matcher".to_string(),
+                target: Some(vec![
+                    "sendmail".to_string(),
+                    "gotify".to_string(),
+                    "builtin".to_string(),
+                ]),
+                ..Default::default()
+            },
+        )?;
+
         Ok(config)
     }
 
@@ -245,6 +277,7 @@ mod tests {
             HashSet::from([
                 "matcher".to_string(),
                 "sendmail".to_string(),
+                "builtin".to_string(),
                 "gotify".to_string()
             ])
         );
@@ -268,12 +301,17 @@ mod tests {
     }
 
     #[test]
-    fn test_ensure_unused() {
+    fn test_ensure_safe_to_delete() {
         let config = prepare_config().unwrap();
 
-        assert!(ensure_unused(&config, "gotify").is_err());
-        assert!(ensure_unused(&config, "sendmail").is_err());
-        assert!(ensure_unused(&config, "matcher").is_ok());
+        assert!(ensure_safe_to_delete(&config, "gotify").is_err());
+        assert!(ensure_safe_to_delete(&config, "sendmail").is_err());
+        assert!(ensure_safe_to_delete(&config, "matcher").is_ok());
+
+        // built-ins are always safe to delete, since there is no way to actually
+        // delete them... they will only be reset to their default settings and
+        // will thus continue to exist
+        assert!(ensure_safe_to_delete(&config, "builtin").is_ok());
     }
 
     #[test]
@@ -281,7 +319,7 @@ mod tests {
         let config = prepare_config().unwrap();
 
         assert!(ensure_unique(&config, "sendmail").is_err());
-        assert!(ensure_unique(&config, "group").is_err());
+        assert!(ensure_unique(&config, "matcher").is_err());
         assert!(ensure_unique(&config, "new").is_ok());
     }
 
@@ -289,6 +327,6 @@ mod tests {
     fn test_ensure_endpoints_exist() {
         let config = prepare_config().unwrap();
 
-        assert!(ensure_endpoints_exist(&config, &vec!["sendmail", "gotify"]).is_ok());
+        assert!(ensure_endpoints_exist(&config, &["sendmail", "gotify", "builtin"]).is_ok());
     }
 }
diff --git a/proxmox-notify/src/api/sendmail.rs b/proxmox-notify/src/api/sendmail.rs
index 0f40178..e911505 100644
--- a/proxmox-notify/src/api/sendmail.rs
+++ b/proxmox-notify/src/api/sendmail.rs
@@ -144,7 +144,7 @@ pub fn update_endpoint(
 pub fn delete_endpoint(config: &mut Config, name: &str) -> Result<(), HttpError> {
     // Check if the endpoint exists
     let _ = get_endpoint(config, name)?;
-    super::ensure_unused(config, name)?;
+    super::ensure_safe_to_delete(config, name)?;
 
     config.config.sections.remove(name);
 
diff --git a/proxmox-notify/src/api/smtp.rs b/proxmox-notify/src/api/smtp.rs
index 14b301c..6bd0c4b 100644
--- a/proxmox-notify/src/api/smtp.rs
+++ b/proxmox-notify/src/api/smtp.rs
@@ -192,7 +192,7 @@ pub fn update_endpoint(
 pub fn delete_endpoint(config: &mut Config, name: &str) -> Result<(), HttpError> {
     // Check if the endpoint exists
     let _ = get_endpoint(config, name)?;
-    super::ensure_unused(config, name)?;
+    super::ensure_safe_to_delete(config, name)?;
 
     super::remove_private_config_entry(config, name)?;
     config.config.sections.remove(name);
-- 
2.39.2





             reply	other threads:[~2023-12-14 12:42 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-14 12:42 Lukas Wagner [this message]
2023-12-14 12:42 ` [pve-devel] [PATCH proxmox 2/2] notify: add separate context for unit-tests Lukas Wagner
2024-01-08 10:44 ` [pve-devel] [PATCH proxmox 1/2] notify: api: allow resetting built-in targets when they are referenced Lukas Wagner
2024-01-09 13:18 ` Wolfgang Bumiller
2024-01-10  8:29   ` Lukas Wagner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231214124208.219312-1-l.wagner@proxmox.com \
    --to=l.wagner@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal