diff --git a/src/api/rules.rs b/src/api/rules.rs index 860987d..e873772 100644 --- a/src/api/rules.rs +++ b/src/api/rules.rs @@ -148,6 +148,64 @@ pub struct Rule { pub conditions: RuleCondition } +impl Rule { + pub fn new(ruleset: String, folder: String) -> Self { + Self { + ruleset, + folder, + ..Default::default() + } + } + + pub fn set_ruleset(&mut self, ruleset: String) { + self.ruleset = ruleset; + } + pub fn with_ruleset(mut self, ruleset: String) -> Self { + self.set_ruleset(ruleset); + self + } + + pub fn set_folder(&mut self, folder: String) { + self.folder = folder; + } + pub fn with_folder(mut self, folder: String) -> Self { + self.set_folder(folder); + self + } + + pub fn set_folder_index(&mut self, index: usize) { + self.folder_index = index; + } + pub fn with_folder_index(mut self, index: usize) -> Self { + self.set_folder_index(index); + self + } + + pub fn set_properties(&mut self, properties: RuleProperties) { + self.properties = properties; + } + pub fn with_properties(mut self, properties: RuleProperties) -> Self { + self.set_properties(properties); + self + } + + pub fn set_value_raw(&mut self, value_raw: String) { + self.value_raw = value_raw; + } + pub fn with_value_raw(mut self, value_raw: String) -> Self { + self.set_value_raw(value_raw); + self + } + + pub fn set_conditions(&mut self, conditions: RuleCondition) { + self.conditions = conditions; + } + pub fn with_conditions(mut self, conditions: RuleCondition) -> Self { + self.set_conditions(conditions); + self + } +} + #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[cfg_attr(feature = "schemars", derive(JsonSchema))] pub struct RuleProperties { @@ -157,6 +215,47 @@ pub struct RuleProperties { pub disabled: bool } +impl RuleProperties { + pub fn new(description: String) -> Self { + Self { + description, + ..Default::default() + } + } + + pub fn set_description(&mut self, description: String) { + self.description = description; + } + pub fn with_description(mut self, description: String) -> Self { + self.set_description(description); + self + } + + pub fn set_comment(&mut self, comment: String) { + self.comment = comment; + } + pub fn with_comment(mut self, comment: String) -> Self { + self.set_comment(comment); + self + } + + pub fn set_documentation_url(&mut self, url: String) { + self.documentation_url = url; + } + pub fn with_documentation_url(mut self, url: String) -> Self { + self.set_documentation_url(url); + self + } + + pub fn set_disabled(&mut self, disabled: bool) { + self.disabled = disabled; + } + pub fn with_disabled(mut self, disabled: bool) -> Self { + self.set_disabled(disabled); + self + } +} + // TODO: implement pub trait RuleMatch { fn matches(&self, other: Self) -> bool; @@ -165,11 +264,149 @@ pub trait RuleMatch { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[cfg_attr(feature = "schemars", derive(JsonSchema))] pub struct RuleCondition { - pub host_name: MatchCondition, + pub host_name: Option, pub host_tags: Vec, pub host_label_groups: Vec, pub service_label_groups: Vec, - pub service_description: MatchCondition + pub service_description: Option, +} + +impl RuleCondition { + /// Match hosts whose name is one of the given values. + pub fn match_hosts(&mut self, hosts: Vec) { + self.host_name = Some(MatchCondition { match_on: hosts, operator: MatchOperator::OneOf }); + } + pub fn matching_hosts(mut self, hosts: Vec) -> Self { + self.match_hosts(hosts); + self + } + + /// Exclude hosts whose name is one of the given values. + pub fn exclude_hosts(&mut self, hosts: Vec) { + self.host_name = Some(MatchCondition { match_on: hosts, operator: MatchOperator::NoneOf }); + } + pub fn excluding_hosts(mut self, hosts: Vec) -> Self { + self.exclude_hosts(hosts); + self + } + + /// Clear any host name condition. + pub fn clear_hosts(&mut self) { + self.host_name = None; + } + + /// Match services whose description is one of the given values. + pub fn match_services(&mut self, services: Vec) { + self.service_description = Some(MatchCondition { match_on: services, operator: MatchOperator::OneOf }); + } + pub fn matching_services(mut self, services: Vec) -> Self { + self.match_services(services); + self + } + + /// Exclude services whose description is one of the given values. + pub fn exclude_services(&mut self, services: Vec) { + self.service_description = Some(MatchCondition { match_on: services, operator: MatchOperator::NoneOf }); + } + pub fn excluding_services(mut self, services: Vec) -> Self { + self.exclude_services(services); + self + } + + /// Clear any service description condition. + pub fn clear_services(&mut self) { + self.service_description = None; + } + + /// Require the host tag `key` to equal `value`. + pub fn require_host_tag(&mut self, key: String, value: String) { + self.host_tags.push(HostTagCondition { key, match_on: TagMatchOperator::Is(value) }); + } + pub fn with_host_tag(mut self, key: String, value: String) -> Self { + self.require_host_tag(key, value); + self + } + + /// Require the host tag `key` to not equal `value`. + pub fn exclude_host_tag(&mut self, key: String, value: String) { + self.host_tags.push(HostTagCondition { key, match_on: TagMatchOperator::IsNot(value) }); + } + pub fn without_host_tag(mut self, key: String, value: String) -> Self { + self.exclude_host_tag(key, value); + self + } + + /// Require the host tag `key` to be one of `values`. + pub fn require_any_host_tag(&mut self, key: String, values: Vec) { + self.host_tags.push(HostTagCondition { key, match_on: TagMatchOperator::OneOff(values) }); + } + pub fn with_any_host_tag(mut self, key: String, values: Vec) -> Self { + self.require_any_host_tag(key, values); + self + } + + /// Require the host tag `key` to be none of `values`. + pub fn exclude_any_host_tag(&mut self, key: String, values: Vec) { + self.host_tags.push(HostTagCondition { key, match_on: TagMatchOperator::NoneOff(values) }); + } + pub fn without_any_host_tag(mut self, key: String, values: Vec) -> Self { + self.exclude_any_host_tag(key, values); + self + } + + /// Add a host label group that must ALL match (AND). + pub fn require_host_labels(&mut self, labels: Vec) { + self.host_label_groups.push(LabelGroupCondition { operator: LabelOperator::And, label_group: labels }); + } + pub fn with_host_labels(mut self, labels: Vec) -> Self { + self.require_host_labels(labels); + self + } + + /// Add a host label group where ANY must match (OR). + pub fn require_any_host_label(&mut self, labels: Vec) { + self.host_label_groups.push(LabelGroupCondition { operator: LabelOperator::Or, label_group: labels }); + } + pub fn with_any_host_label(mut self, labels: Vec) -> Self { + self.require_any_host_label(labels); + self + } + + /// Add a host label group that must NOT match (NOT). + pub fn exclude_host_labels(&mut self, labels: Vec) { + self.host_label_groups.push(LabelGroupCondition { operator: LabelOperator::Not, label_group: labels }); + } + pub fn excluding_host_labels(mut self, labels: Vec) -> Self { + self.exclude_host_labels(labels); + self + } + + /// Add a service label group that must ALL match (AND). + pub fn require_service_labels(&mut self, labels: Vec) { + self.service_label_groups.push(LabelGroupCondition { operator: LabelOperator::And, label_group: labels }); + } + pub fn with_service_labels(mut self, labels: Vec) -> Self { + self.require_service_labels(labels); + self + } + + /// Add a service label group where ANY must match (OR). + pub fn require_any_service_label(&mut self, labels: Vec) { + self.service_label_groups.push(LabelGroupCondition { operator: LabelOperator::Or, label_group: labels }); + } + pub fn with_any_service_label(mut self, labels: Vec) -> Self { + self.require_any_service_label(labels); + self + } + + /// Add a service label group that must NOT match (NOT). + pub fn exclude_service_labels(&mut self, labels: Vec) { + self.service_label_groups.push(LabelGroupCondition { operator: LabelOperator::Not, label_group: labels }); + } + pub fn excluding_service_labels(mut self, labels: Vec) -> Self { + self.exclude_service_labels(labels); + self + } } #[derive(Debug, Clone, Default, Serialize, Deserialize)] @@ -316,6 +553,7 @@ mod serde_tags { let mut tvalue: Option = None; while let Some(key) = map.next_key()? { + #[allow(unused_must_use)] match key { Field::Key => {tkey.insert(map.next_value()?);}, Field::Operator => {toperator.insert(map.next_value()?);},