diff --git a/src/api/mod.rs b/src/api/mod.rs index 2d3a6aa..7420dab 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -25,7 +25,7 @@ pub enum DomainType { ActivationRun, Ruleset, Rule, - Dict + Dict, } impl fmt::Display for DomainType { diff --git a/src/api/rules.rs b/src/api/rules.rs index eedbd51..d78d981 100644 --- a/src/api/rules.rs +++ b/src/api/rules.rs @@ -1,14 +1,16 @@ use std::fmt::Display; -use serde::{Deserialize, Serialize}; #[cfg(feature = "schemars")] use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::api::{DomainExtension, DomainObject, domain_bulk_read, domain_client, domain_create, domain_delete, domain_update}; +use crate::api::{ + DomainExtension, DomainObject, domain_bulk_read, domain_client, domain_create, domain_delete, + domain_update, +}; use crate::{ApiClient, Client, Error, Result}; - #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "schemars", derive(JsonSchema))] pub struct Ruleset { @@ -26,7 +28,7 @@ pub struct Ruleset { // item_enum: Option<()>, // this value is not set when searching for a specific ruleset (dont ask me why) pub match_type: Option, - pub number_of_rules: usize + pub number_of_rules: usize, } impl DomainExtension for Ruleset { @@ -41,7 +43,7 @@ pub enum MatchType { First, Dict, List, - Varies + Varies, } domain_client!(Ruleset, ruleset_api); @@ -98,15 +100,13 @@ impl RulesetQuery { } } - - impl ApiClient { pub async fn read(&self, id: impl Display) -> Result { #[derive(Deserialize, Serialize)] struct RulesetCompact { name: String, folder: Option, - number_of_rules: usize + number_of_rules: usize, } impl DomainExtension for RulesetCompact { @@ -124,7 +124,6 @@ impl ApiClient { item_type: None, item_name: None, match_type: None, - } } } @@ -141,16 +140,16 @@ domain_bulk_read!(Ruleset, RulesetQuery); #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[cfg_attr(feature = "schemars", derive(JsonSchema))] pub struct Rule { - #[serde(default, skip_serializing_if="Option::is_none")] + #[serde(default, skip_serializing_if = "Option::is_none")] pub folder_index: Option, - #[serde(default, skip_serializing_if="Option::is_none")] + #[serde(default, skip_serializing_if = "Option::is_none")] pub id: Option, pub ruleset: String, pub folder: String, pub properties: RuleProperties, pub value_raw: String, - pub conditions: RuleCondition + pub conditions: RuleCondition, } impl DomainExtension for Rule { @@ -213,7 +212,7 @@ pub struct RuleProperties { pub description: String, pub comment: String, pub documentation_url: String, - pub disabled: bool + pub disabled: bool, } impl RuleProperties { @@ -275,7 +274,10 @@ pub struct RuleCondition { 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 }); + self.host_name = Some(MatchCondition { + match_on: hosts, + operator: MatchOperator::OneOf, + }); } pub fn matching_hosts(mut self, hosts: Vec) -> Self { self.match_hosts(hosts); @@ -284,7 +286,10 @@ impl RuleCondition { /// 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 }); + self.host_name = Some(MatchCondition { + match_on: hosts, + operator: MatchOperator::NoneOf, + }); } pub fn excluding_hosts(mut self, hosts: Vec) -> Self { self.exclude_hosts(hosts); @@ -298,7 +303,10 @@ impl RuleCondition { /// 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 }); + self.service_description = Some(MatchCondition { + match_on: services, + operator: MatchOperator::OneOf, + }); } pub fn matching_services(mut self, services: Vec) -> Self { self.match_services(services); @@ -307,7 +315,10 @@ impl RuleCondition { /// 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 }); + self.service_description = Some(MatchCondition { + match_on: services, + operator: MatchOperator::NoneOf, + }); } pub fn excluding_services(mut self, services: Vec) -> Self { self.exclude_services(services); @@ -321,7 +332,10 @@ impl RuleCondition { /// 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) }); + 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); @@ -330,7 +344,10 @@ impl RuleCondition { /// 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) }); + 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); @@ -339,7 +356,10 @@ impl RuleCondition { /// 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) }); + 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); @@ -348,7 +368,10 @@ impl RuleCondition { /// 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) }); + 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); @@ -357,7 +380,10 @@ impl RuleCondition { /// 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 }); + 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); @@ -366,7 +392,10 @@ impl RuleCondition { /// 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 }); + 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); @@ -375,7 +404,10 @@ impl RuleCondition { /// 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 }); + 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); @@ -384,7 +416,10 @@ impl RuleCondition { /// 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 }); + 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); @@ -393,7 +428,10 @@ impl RuleCondition { /// 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 }); + 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); @@ -402,7 +440,10 @@ impl RuleCondition { /// 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 }); + 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); @@ -414,7 +455,7 @@ impl RuleCondition { #[cfg_attr(feature = "schemars", derive(JsonSchema))] pub struct MatchCondition { match_on: Vec, - operator: MatchOperator + operator: MatchOperator, } #[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] @@ -423,14 +464,14 @@ pub struct MatchCondition { pub enum MatchOperator { #[default] OneOf, - NoneOf + NoneOf, } #[derive(Debug, Clone)] #[cfg_attr(feature = "schemars", derive(JsonSchema))] pub struct HostTagCondition { key: String, - match_on: TagMatchOperator + match_on: TagMatchOperator, } #[derive(Debug, Clone)] @@ -446,20 +487,23 @@ pub enum TagMatchOperator { #[cfg_attr(feature = "schemars", derive(JsonSchema))] pub struct LabelGroupCondition { operator: LabelOperator, - label_group: Vec + label_group: Vec, } #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[cfg_attr(feature = "schemars", derive(JsonSchema))] pub struct LabelCondition { operator: LabelOperator, - label: String + label: String, } #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[cfg_attr(feature = "schemars", derive(JsonSchema))] pub enum LabelOperator { - #[default] And, Or, Not + #[default] + And, + Or, + Not, } domain_client!(Rule, rule_api); @@ -469,17 +513,14 @@ domain_delete!(Rule); impl ApiClient { pub async fn read(&self, id: Uuid) -> Result { - let mut object = self.inner - .read_domain_object::(id, &()) - .await?; + let mut object = self.inner.read_domain_object::(id, &()).await?; object.extensions.id = Some(Uuid::parse_str(&object.id)?); Ok(object.extensions) } pub async fn bulk_read(&self) -> Result> { - let objects = self.inner - .bulk_read_domain_objects::(&()) - .await?; - let objects = objects.value + let objects = self.inner.bulk_read_domain_objects::(&()).await?; + let objects = objects + .value .into_iter() .map(|mut object| { object.extensions.id = Some(Uuid::parse_str(&object.id)?); @@ -491,14 +532,19 @@ impl ApiClient { } mod serde_tags { - use serde::{Deserialize, Serialize, de::{self, Visitor, Unexpected, Error}, ser::SerializeStruct}; + use serde::{ + Deserialize, Serialize, + de::{self, Error, Unexpected, Visitor}, + ser::SerializeStruct, + }; use crate::api::rules::{HostTagCondition, TagMatchOperator}; impl Serialize for HostTagCondition { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer { + S: serde::Serializer, + { let mut map = serializer.serialize_struct("HostTagCondition", 3)?; map.serialize_field("key", &self.key)?; @@ -507,19 +553,19 @@ mod serde_tags { TagMatchOperator::Is(value) => { map.serialize_field("operator", "is")?; map.serialize_field("value", &value)?; - }, + } TagMatchOperator::IsNot(value) => { map.serialize_field("operator", "is_not")?; map.serialize_field("value", &value)?; - }, + } TagMatchOperator::OneOff(items) => { map.serialize_field("operator", "one_of")?; map.serialize_field("value", items)?; - }, + } TagMatchOperator::NoneOff(items) => { map.serialize_field("operator", "none_of")?; map.serialize_field("value", items)?; - }, + } }; map.end() @@ -528,7 +574,7 @@ mod serde_tags { struct HostTagConditionVisitor; - impl <'de> Visitor<'de> for HostTagConditionVisitor { + impl<'de> Visitor<'de> for HostTagConditionVisitor { type Value = HostTagCondition; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -536,29 +582,31 @@ mod serde_tags { } fn visit_map(self, mut map: A) -> Result - where - A: serde::de::MapAccess<'de>, { - + where + A: serde::de::MapAccess<'de>, + { #[derive(Debug, Deserialize)] #[serde(rename_all = "lowercase")] enum Field { Key, Operator, - Value + Value, } - #[derive(Debug, Deserialize)] #[serde(rename_all = "snake_case")] enum Operator { - Is, IsNot, OneOff, NoneOff + Is, + IsNot, + OneOff, + NoneOff, } #[derive(Debug, Deserialize)] #[serde(untagged)] enum ValueKind { Single(String), - Multiple(Vec) + Multiple(Vec), } impl ValueKind { @@ -572,7 +620,7 @@ mod serde_tags { fn into_multiple(self) -> Result, String> { match self { Self::Multiple(ss) => Ok(ss), - Self::Single(s) => Err(s) + Self::Single(s) => Err(s), } } } @@ -584,43 +632,51 @@ mod serde_tags { 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()?);}, - Field::Value => {tvalue.insert(map.next_value()?);} + Field::Key => { + tkey.insert(map.next_value()?); + } + Field::Operator => { + toperator.insert(map.next_value()?); + } + Field::Value => { + tvalue.insert(map.next_value()?); + } }; - }; + } let key = tkey.ok_or(A::Error::missing_field("key"))?; let match_on = match toperator.ok_or(de::Error::missing_field("operator"))? { Operator::Is => TagMatchOperator::Is( - tvalue.and_then(|v| v.into_single()) - .ok_or(A::Error::invalid_value( - Unexpected::Seq, - &"single string" - ))? + tvalue + .and_then(|v| v.into_single()) + .ok_or(A::Error::invalid_value(Unexpected::Seq, &"single string"))?, ), Operator::IsNot => TagMatchOperator::IsNot( - tvalue.and_then(|v| v.into_single()) - .ok_or(A::Error::invalid_value( - Unexpected::Seq, - &"single string" - ))? + tvalue + .and_then(|v| v.into_single()) + .ok_or(A::Error::invalid_value(Unexpected::Seq, &"single string"))?, ), Operator::OneOff => TagMatchOperator::OneOff( - tvalue.ok_or(A::Error::missing_field("value"))? + tvalue + .ok_or(A::Error::missing_field("value"))? .into_multiple() - .map_err(|s| A::Error::invalid_value( - Unexpected::Str(s.as_str()), - &"sequence of stirngs" - ))? + .map_err(|s| { + A::Error::invalid_value( + Unexpected::Str(s.as_str()), + &"sequence of stirngs", + ) + })?, ), Operator::NoneOff => TagMatchOperator::NoneOff( - tvalue.ok_or(A::Error::missing_field("value"))? + tvalue + .ok_or(A::Error::missing_field("value"))? .into_multiple() - .map_err(|s| A::Error::invalid_value( - Unexpected::Str(s.as_str()), - &"sequence of stirngs" - ))? + .map_err(|s| { + A::Error::invalid_value( + Unexpected::Str(s.as_str()), + &"sequence of stirngs", + ) + })?, ), }; @@ -628,11 +684,11 @@ mod serde_tags { } } - impl <'de> Deserialize<'de> for HostTagCondition { - + impl<'de> Deserialize<'de> for HostTagCondition { fn deserialize(deserializer: D) -> Result where - D: serde::Deserializer<'de> { + D: serde::Deserializer<'de>, + { deserializer.deserialize_map(HostTagConditionVisitor) } } diff --git a/src/error.rs b/src/error.rs index 9a59eeb..6b029e9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -33,7 +33,7 @@ pub enum Error { #[error("Failed to parse ETag header: {0}")] ParseEtag(#[source] std::string::FromUtf8Error), #[error("failed to parse domain object id: {0}")] - ParseId(#[from] uuid::Error) + ParseId(#[from] uuid::Error), } #[derive(Debug, Deserialize)]