notify: matcher: support lists of values for 'exact' match-field mode

For example, one can now use:
  match-field exact:type=vzdump,replication
to match on vzdump AND replication events.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
This commit is contained in:
Lukas Wagner 2023-12-13 17:37:42 +01:00 committed by Wolfgang Bumiller
parent 39c4d7d85e
commit ead4190e7b

View File

@ -160,7 +160,7 @@ trait MatchDirective {
pub enum FieldMatcher {
Exact {
field: String,
matched_value: String,
matched_values: Vec<String>,
},
Regex {
field: String,
@ -176,12 +176,12 @@ impl MatchDirective for FieldMatcher {
Ok(match self {
FieldMatcher::Exact {
field,
matched_value,
matched_values,
} => {
let value = notification.metadata.additional_fields.get(field);
if let Some(value) = value {
matched_value == value
matched_values.contains(value)
} else {
// Metadata field does not exist, so we do not match
false
@ -212,9 +212,10 @@ impl fmt::Display for FieldMatcher {
match self {
FieldMatcher::Exact {
field,
matched_value,
matched_values,
} => {
write!(f, "exact:{field}={matched_value}")
let values = matched_values.join(",");
write!(f, "exact:{field}={values}")
}
FieldMatcher::Regex {
field,
@ -256,10 +257,17 @@ impl FromStr for FieldMatcher {
None => Err(Error::FilterFailed(format!(
"invalid match-field statement: {s}"
))),
Some((field, expected_value)) => Ok(Self::Exact {
field: field.into(),
matched_value: expected_value.into(),
}),
Some((field, expected_values)) => {
let values: Vec<String> = expected_values
.split(',')
.map(str::trim)
.map(String::from)
.collect();
Ok(Self::Exact {
field: field.into(),
matched_values: values,
})
}
}
} else {
Err(Error::FilterFailed(format!(
@ -460,6 +468,23 @@ mod tests {
let matcher: FieldMatcher = "regex:notthere=b.*".parse().unwrap();
assert!(!matcher.matches(&notification).unwrap());
let matcher: FieldMatcher = "exact:foo=bar,test".parse().unwrap();
assert!(matcher.matches(&notification).unwrap());
let mut fields = HashMap::new();
fields.insert("foo".into(), "test".into());
let notification =
Notification::new_templated(Severity::Notice, "test", "test", Value::Null, fields);
assert!(matcher.matches(&notification).unwrap());
let mut fields = HashMap::new();
fields.insert("foo".into(), "notthere".into());
let notification =
Notification::new_templated(Severity::Notice, "test", "test", Value::Null, fields);
assert!(!matcher.matches(&notification).unwrap());
assert!("regex:'3=b.*".parse::<FieldMatcher>().is_err());
assert!("invalid:'bar=b.*".parse::<FieldMatcher>().is_err());
}