From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id BF6C29F9AA for ; Tue, 7 Nov 2023 11:19:04 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id A82F130282 for ; Tue, 7 Nov 2023 11:19:04 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Tue, 7 Nov 2023 11:19:03 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 5E7834698C for ; Tue, 7 Nov 2023 11:19:03 +0100 (CET) From: Lukas Wagner To: pve-devel@lists.proxmox.com Date: Tue, 7 Nov 2023 11:18:05 +0100 Message-Id: <20231107101827.340100-6-l.wagner@proxmox.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231107101827.340100-1-l.wagner@proxmox.com> References: <20231107101827.340100-1-l.wagner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.017 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pve-devel] [PATCH proxmox 05/27] notify: matcher: introduce common trait for match directives X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 07 Nov 2023 10:19:04 -0000 This allows us to make the match-checking code a bit shorter. Signed-off-by: Lukas Wagner --- proxmox-notify/src/matcher.rs | 92 +++++++++++++++++------------------ 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/proxmox-notify/src/matcher.rs b/proxmox-notify/src/matcher.rs index b03d11d..e299fd0 100644 --- a/proxmox-notify/src/matcher.rs +++ b/proxmox-notify/src/matcher.rs @@ -142,6 +142,11 @@ pub struct MatcherConfig { pub comment: Option, } +trait MatchDirective { + fn matches(&self, notification: &Notification) -> Result; +} + +/// Check if the notification metadata fields match #[derive(Clone, Debug)] pub enum FieldMatcher { Exact { @@ -157,9 +162,9 @@ pub enum FieldMatcher { proxmox_serde::forward_deserialize_to_from_str!(FieldMatcher); proxmox_serde::forward_serialize_to_display!(FieldMatcher); -impl FieldMatcher { - fn matches(&self, notification: &Notification) -> bool { - match self { +impl MatchDirective for FieldMatcher { + fn matches(&self, notification: &Notification) -> Result { + Ok(match self { FieldMatcher::Exact { field, matched_value, @@ -186,7 +191,7 @@ impl FieldMatcher { false } } - } + }) } } @@ -260,9 +265,22 @@ impl MatcherConfig { let mode = self.mode.unwrap_or_default(); let mut is_match = mode.neutral_element(); - is_match = mode.apply(is_match, self.check_severity_match(notification)); - is_match = mode.apply(is_match, self.check_field_match(notification)?); - is_match = mode.apply(is_match, self.check_calendar_match(notification)?); + + if let Some(severity_matchers) = self.match_severity.as_deref() { + is_match = mode.apply( + is_match, + self.check_matches(notification, severity_matchers)?, + ); + } + if let Some(field_matchers) = self.match_field.as_deref() { + is_match = mode.apply(is_match, self.check_matches(notification, field_matchers)?); + } + if let Some(calendar_matchers) = self.match_calendar.as_deref() { + is_match = mode.apply( + is_match, + self.check_matches(notification, calendar_matchers)?, + ); + } let invert_match = self.invert_match.unwrap_or_default(); @@ -273,46 +291,24 @@ impl MatcherConfig { }) } - fn check_field_match(&self, notification: &Notification) -> Result { - let mode = self.mode.unwrap_or_default(); - let mut is_match = mode.neutral_element(); - - if let Some(match_field) = self.match_field.as_deref() { - for field_matcher in match_field { - // let field_matcher: FieldMatcher = match_stmt.parse()?; - is_match = mode.apply(is_match, field_matcher.matches(notification)); - } - } - - Ok(is_match) - } - - fn check_severity_match(&self, notification: &Notification) -> bool { + /// Check if given `MatchDirectives` match a notification. + fn check_matches( + &self, + notification: &Notification, + matchers: &[impl MatchDirective], + ) -> Result { let mode = self.mode.unwrap_or_default(); let mut is_match = mode.neutral_element(); - if let Some(matchers) = self.match_severity.as_ref() { - for severity_matcher in matchers { - is_match = mode.apply(is_match, severity_matcher.matches(notification)); - } - } - - is_match - } - - fn check_calendar_match(&self, notification: &Notification) -> Result { - let mode = self.mode.unwrap_or_default(); - let mut is_match = mode.neutral_element(); - - if let Some(matchers) = self.match_calendar.as_ref() { - for matcher in matchers { - is_match = mode.apply(is_match, matcher.matches(notification)?); - } + for field_matcher in matchers { + is_match = mode.apply(is_match, field_matcher.matches(notification)?); } Ok(is_match) } } + +/// Match severity of the notification. #[derive(Clone, Debug)] pub struct SeverityMatcher { severities: Vec, @@ -321,9 +317,11 @@ pub struct SeverityMatcher { proxmox_serde::forward_deserialize_to_from_str!(SeverityMatcher); proxmox_serde::forward_serialize_to_display!(SeverityMatcher); -impl SeverityMatcher { - fn matches(&self, notification: &Notification) -> bool { - self.severities.contains(¬ification.metadata.severity) +/// Common trait implemented by all matching directives +impl MatchDirective for SeverityMatcher { + /// Check if this directive matches a given notification + fn matches(&self, notification: &Notification) -> Result { + Ok(self.severities.contains(¬ification.metadata.severity)) } } @@ -360,7 +358,7 @@ pub struct CalendarMatcher { proxmox_serde::forward_deserialize_to_from_str!(CalendarMatcher); proxmox_serde::forward_serialize_to_display!(CalendarMatcher); -impl CalendarMatcher { +impl MatchDirective for CalendarMatcher { fn matches(&self, notification: &Notification) -> Result { self.schedule .time_match(notification.metadata.timestamp, false) @@ -433,13 +431,13 @@ mod tests { Notification::new_templated(Severity::Notice, "test", "test", Value::Null, fields); let matcher: FieldMatcher = "exact:foo=bar".parse().unwrap(); - assert!(matcher.matches(¬ification)); + assert!(matcher.matches(¬ification).unwrap()); let matcher: FieldMatcher = "regex:foo=b.*".parse().unwrap(); - assert!(matcher.matches(¬ification)); + assert!(matcher.matches(¬ification).unwrap()); let matcher: FieldMatcher = "regex:notthere=b.*".parse().unwrap(); - assert!(!matcher.matches(¬ification)); + assert!(!matcher.matches(¬ification).unwrap()); assert!("regex:'3=b.*".parse::().is_err()); assert!("invalid:'bar=b.*".parse::().is_err()); @@ -455,6 +453,6 @@ mod tests { ); let matcher: SeverityMatcher = "info,notice,warning,error".parse().unwrap(); - assert!(matcher.matches(¬ification)); + assert!(matcher.matches(¬ification).unwrap()); } } -- 2.39.2