From: Lukas Wagner <l.wagner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v2 proxmox 11/42] notify: api: add API for sendmail endpoints
Date: Wed, 24 May 2023 15:56:18 +0200 [thread overview]
Message-ID: <20230524135649.934881-12-l.wagner@proxmox.com> (raw)
In-Reply-To: <20230524135649.934881-1-l.wagner@proxmox.com>
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
proxmox-notify/src/api/mod.rs | 7 +
proxmox-notify/src/api/sendmail.rs | 254 +++++++++++++++++++++++++++++
2 files changed, 261 insertions(+)
create mode 100644 proxmox-notify/src/api/sendmail.rs
diff --git a/proxmox-notify/src/api/mod.rs b/proxmox-notify/src/api/mod.rs
index 9e5f15b8..76c98d09 100644
--- a/proxmox-notify/src/api/mod.rs
+++ b/proxmox-notify/src/api/mod.rs
@@ -6,6 +6,8 @@ use serde::Serialize;
pub mod channel;
pub mod common;
+#[cfg(feature = "sendmail")]
+pub mod sendmail;
#[derive(Debug, Serialize)]
pub struct ApiError {
@@ -84,6 +86,11 @@ fn verify_digest(config: &Config, digest: Option<&[u8]>) -> Result<(), ApiError>
fn endpoint_exists(config: &Config, name: &str) -> bool {
let mut exists = false;
+ #[cfg(feature = "sendmail")]
+ {
+ exists = exists || sendmail::get_endpoint(config, name).is_ok();
+ }
+
exists
}
diff --git a/proxmox-notify/src/api/sendmail.rs b/proxmox-notify/src/api/sendmail.rs
new file mode 100644
index 00000000..458893ae
--- /dev/null
+++ b/proxmox-notify/src/api/sendmail.rs
@@ -0,0 +1,254 @@
+use crate::api::ApiError;
+use crate::endpoints::sendmail::{
+ DeleteableSendmailProperty, SendmailConfig, SendmailConfigUpdater, SENDMAIL_TYPENAME,
+};
+use crate::Config;
+
+/// Get a list of all sendmail endpoints.
+///
+/// The caller is responsible for any needed permission checks.
+/// Returns a list of all sendmail endpoints or an `ApiError` if the config is erroneous.
+pub fn get_endpoints(config: &Config) -> Result<Vec<SendmailConfig>, ApiError> {
+ config
+ .config
+ .convert_to_typed_array(SENDMAIL_TYPENAME)
+ .map_err(|e| ApiError::internal_server_error("Could not fetch endpoints", Some(e.into())))
+}
+
+/// Get sendmail endpoint with given `name`.
+///
+/// The caller is responsible for any needed permission checks.
+/// Returns the endpoint or an `ApiError` if the endpoint was not found.
+pub fn get_endpoint(config: &Config, name: &str) -> Result<SendmailConfig, ApiError> {
+ config
+ .config
+ .lookup(SENDMAIL_TYPENAME, name)
+ .map_err(|_| ApiError::not_found(format!("endpoint '{name}' not found"), None))
+}
+
+/// Add a new sendmail endpoint.
+///
+/// The caller is responsible for any needed permission checks.
+/// The caller also responsible for locking the configuration files.
+/// Returns an `ApiError` if an endpoint with the same name already exists,
+/// or if the endpoint could not be saved.
+pub fn add_endpoint(config: &mut Config, endpoint: &SendmailConfig) -> Result<(), ApiError> {
+ if super::endpoint_exists(config, &endpoint.name) {
+ return Err(ApiError::bad_request(
+ format!("endpoint with name '{}' already exists!", &endpoint.name),
+ None,
+ ));
+ }
+
+ config
+ .config
+ .set_data(&endpoint.name, SENDMAIL_TYPENAME, endpoint)
+ .map_err(|e| {
+ ApiError::internal_server_error(
+ format!("could not save endpoint '{}'", endpoint.name),
+ Some(e.into()),
+ )
+ })?;
+
+ Ok(())
+}
+
+/// Update existing sendmail endpoint
+///
+/// The caller is responsible for any needed permission checks.
+/// The caller also responsible for locking the configuration files.
+/// Returns an `ApiError` if the config could not be saved.
+pub fn update_endpoint(
+ config: &mut Config,
+ name: &str,
+ updater: &SendmailConfigUpdater,
+ delete: Option<&[DeleteableSendmailProperty]>,
+ digest: Option<&[u8]>,
+) -> Result<(), ApiError> {
+ super::verify_digest(config, digest)?;
+
+ let mut endpoint = get_endpoint(config, name)?;
+
+ if let Some(delete) = delete {
+ for deleteable_property in delete {
+ match deleteable_property {
+ DeleteableSendmailProperty::FromAddress => endpoint.from_address = None,
+ DeleteableSendmailProperty::Author => endpoint.author = None,
+ DeleteableSendmailProperty::Comment => endpoint.comment = None,
+ }
+ }
+ }
+
+ if let Some(recipient) = &updater.recipient {
+ endpoint.recipient = recipient.iter().map(String::from).collect();
+ }
+
+ if let Some(from_address) = &updater.from_address {
+ endpoint.from_address = Some(from_address.into());
+ }
+
+ if let Some(author) = &updater.author {
+ endpoint.author = Some(author.into());
+ }
+
+ if let Some(comment) = &updater.comment {
+ endpoint.comment = Some(comment.into());
+ }
+
+ config
+ .config
+ .set_data(name, SENDMAIL_TYPENAME, &endpoint)
+ .map_err(|e| {
+ ApiError::internal_server_error(
+ format!("could not save endpoint '{name}'"),
+ Some(e.into()),
+ )
+ })?;
+
+ Ok(())
+}
+
+/// Delete existing sendmail endpoint
+///
+/// The caller is responsible for any needed permission checks.
+/// The caller also responsible for locking the configuration files.
+/// Returns an `ApiError` if the endpoint does not exist.
+pub fn delete_endpoint(config: &mut Config, name: &str) -> Result<(), ApiError> {
+ // Check if the endpoint exists
+ let _ = get_endpoint(config, name)?;
+
+ config.config.sections.remove(name);
+
+ Ok(())
+}
+
+#[cfg(test)]
+pub mod tests {
+ use super::*;
+ use crate::api::test_helpers::*;
+
+ pub fn add_sendmail_endpoint_for_test(config: &mut Config, name: &str) -> Result<(), ApiError> {
+ add_endpoint(
+ config,
+ &SendmailConfig {
+ name: name.into(),
+ recipient: vec!["user1@example.com".into()],
+ from_address: Some("from@example.com".into()),
+ author: Some("root".into()),
+ comment: Some("Comment".into()),
+ },
+ )?;
+
+ assert!(get_endpoint(config, name).is_ok());
+ Ok(())
+ }
+
+ #[test]
+ fn test_sendmail_create() -> Result<(), ApiError> {
+ let mut config = empty_config();
+
+ assert_eq!(get_endpoints(&config)?.len(), 0);
+ add_sendmail_endpoint_for_test(&mut config, "sendmail-endpoint")?;
+
+ // Endpoints must have a unique name
+ assert!(add_sendmail_endpoint_for_test(&mut config, "sendmail-endpoint").is_err());
+ assert_eq!(get_endpoints(&config)?.len(), 1);
+ Ok(())
+ }
+
+ #[test]
+ fn test_update_not_existing_returns_error() -> Result<(), ApiError> {
+ let mut config = empty_config();
+
+ assert!(update_endpoint(&mut config, "test", &Default::default(), None, None,).is_err());
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_update_invalid_digest_returns_error() -> Result<(), ApiError> {
+ let mut config = empty_config();
+ add_sendmail_endpoint_for_test(&mut config, "sendmail-endpoint")?;
+
+ assert!(update_endpoint(
+ &mut config,
+ "sendmail-endpoint",
+ &SendmailConfigUpdater {
+ recipient: Some(vec!["user2@example.com".into(), "user3@example.com".into()]),
+ from_address: Some("root@example.com".into()),
+ author: Some("newauthor".into()),
+ comment: Some("new comment".into()),
+ },
+ None,
+ Some(&[0; 32]),
+ )
+ .is_err());
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_sendmail_update() -> Result<(), ApiError> {
+ let mut config = empty_config();
+ add_sendmail_endpoint_for_test(&mut config, "sendmail-endpoint")?;
+
+ let digest = config.digest;
+
+ update_endpoint(
+ &mut config,
+ "sendmail-endpoint",
+ &SendmailConfigUpdater {
+ recipient: Some(vec!["user2@example.com".into(), "user3@example.com".into()]),
+ from_address: Some("root@example.com".into()),
+ author: Some("newauthor".into()),
+ comment: Some("new comment".into()),
+ },
+ None,
+ Some(&digest),
+ )?;
+
+ let endpoint = get_endpoint(&config, "sendmail-endpoint")?;
+
+ assert_eq!(
+ endpoint.recipient,
+ vec![
+ "user2@example.com".to_string(),
+ "user3@example.com".to_string()
+ ]
+ );
+ assert_eq!(endpoint.from_address, Some("root@example.com".to_string()));
+ assert_eq!(endpoint.author, Some("newauthor".to_string()));
+ assert_eq!(endpoint.comment, Some("new comment".to_string()));
+
+ // Test property deletion
+ update_endpoint(
+ &mut config,
+ "sendmail-endpoint",
+ &Default::default(),
+ Some(&[
+ DeleteableSendmailProperty::FromAddress,
+ DeleteableSendmailProperty::Author,
+ ]),
+ None,
+ )?;
+
+ let endpoint = get_endpoint(&config, "sendmail-endpoint")?;
+
+ assert_eq!(endpoint.from_address, None);
+ assert_eq!(endpoint.author, None);
+
+ Ok(())
+ }
+
+ #[test]
+ fn test_sendmail_delete() -> Result<(), ApiError> {
+ let mut config = empty_config();
+ add_sendmail_endpoint_for_test(&mut config, "sendmail-endpoint")?;
+
+ delete_endpoint(&mut config, "sendmail-endpoint")?;
+ assert!(delete_endpoint(&mut config, "sendmail-endpoint").is_err());
+ assert_eq!(get_endpoints(&config)?.len(), 0);
+
+ Ok(())
+ }
+}
--
2.30.2
next prev parent reply other threads:[~2023-05-24 13:58 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-24 13:56 [pve-devel] [PATCH v2 cluster/guest-common/manager/ha-manager/proxmox{, -perl-rs} 00/42] fix #4156: introduce new notification module Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 01/42] add `proxmox-human-byte` crate Lukas Wagner
2023-06-26 11:58 ` Wolfgang Bumiller
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 02/42] human-byte: move tests to their own sub-module Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 03/42] add proxmox-notify crate Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 04/42] notify: add debian packaging Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 05/42] notify: preparation for the first endpoint plugin Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 06/42] notify: preparation for the API Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 07/42] notify: api: add API for sending notifications/testing endpoints Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 08/42] notify: add notification channels Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 09/42] notify: api: add API for channels Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 10/42] notify: add sendmail plugin Lukas Wagner
2023-05-24 13:56 ` Lukas Wagner [this message]
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 12/42] notify: add gotify endpoint Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 13/42] notify: api: add API for gotify endpoints Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 14/42] notify: add notification filter mechanism Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 15/42] notify: api: add API for filters Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 16/42] notify: add template rendering Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox 17/42] notify: add example for " Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox-perl-rs 18/42] log: set default log level to 'info', add product specific logging env var Lukas Wagner
2023-06-05 7:27 ` Wolfgang Bumiller
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox-perl-rs 19/42] add PVE::RS::Notify module Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox-perl-rs 20/42] notify: add api for sending notifications/testing endpoints Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox-perl-rs 21/42] notify: add api for notification channels Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox-perl-rs 22/42] notify: add api for sendmail endpoints Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox-perl-rs 23/42] notify: add api for gotify endpoints Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 proxmox-perl-rs 24/42] notify: add api for notification filters Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-cluster 25/42] cluster files: add notifications.cfg Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-guest-common 26/42] vzdump: add config options for new notification backend Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 27/42] test: fix names of .PHONY targets Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 28/42] add PVE::Notify module Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 29/42] vzdump: send notifications via new notification module Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 30/42] test: rename mail_test.pl to vzdump_notification_test.pl Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 31/42] api: apt: send notification via new notification module Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 32/42] api: replication: send notifications " Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 33/42] ui: backup: allow to select notification channel for notifications Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 34/42] ui: backup: adapt backup job details to new notification params Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 35/42] ui: backup: allow to set notification-{channel, mode} for one-off backups Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 36/42] api: prepare api handler module for notification config Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 37/42] api: add api routes for notification channels Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 38/42] api: add api routes for sendmail endpoints Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 39/42] api: add api routes for gotify endpoints Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 40/42] api: add api routes for notification filters Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-manager 41/42] ui: backup: disable notification mode selector for now Lukas Wagner
2023-05-24 13:56 ` [pve-devel] [PATCH v2 pve-ha-manager 42/42] manager: send notifications via new notification module Lukas Wagner
2023-05-26 8:31 ` [pve-devel] [PATCH v2 cluster/guest-common/manager/ha-manager/proxmox{, -perl-rs} 00/42] fix #4156: introduce " 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=20230524135649.934881-12-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.