cargo fmt

This commit is contained in:
Vincent Stuyck 2025-12-20 01:59:51 +01:00
parent 91be1f0acb
commit ebc349de64
5 changed files with 97 additions and 109 deletions

View File

@ -34,7 +34,6 @@ pub struct FolderAttributes {
/// Additional attributes that can be used to categorize hosts. every tag is part of a tag_group /// Additional attributes that can be used to categorize hosts. every tag is part of a tag_group
/// NOTE that checkmk always returns taggroups prefixed with "tag_" /// NOTE that checkmk always returns taggroups prefixed with "tag_"
pub tags: HashMap<String, String>, pub tags: HashMap<String, String>,
// TODO: to be implemented // TODO: to be implemented
// #[serde(flatten, default)] // #[serde(flatten, default)]
// pub networkscan: NetworkScan, // pub networkscan: NetworkScan,
@ -116,16 +115,11 @@ pub struct FolderCreationRequest {
pub name: String, pub name: String,
pub title: String, pub title: String,
pub parent: String, pub parent: String,
pub attributes: FolderAttributes pub attributes: FolderAttributes,
} }
impl FolderCreationRequest { impl FolderCreationRequest {
pub fn new( pub fn new(name: String, title: String, parent: String, attributes: FolderAttributes) -> Self {
name: String,
title: String,
parent: String,
attributes: FolderAttributes
) -> Self {
Self { Self {
name, name,
title, title,
@ -154,7 +148,7 @@ impl FolderUpdateRequest {
title, title,
attributes: Some(attributes), attributes: Some(attributes),
update_attributes: None, update_attributes: None,
remove_attributes: None remove_attributes: None,
} }
} }
pub fn update(title: String, attributes: FolderAttributes) -> Self { pub fn update(title: String, attributes: FolderAttributes) -> Self {
@ -162,7 +156,7 @@ impl FolderUpdateRequest {
title, title,
attributes: None, attributes: None,
update_attributes: Some(attributes), update_attributes: Some(attributes),
remove_attributes: None remove_attributes: None,
} }
} }
pub fn remove(title: String, attributes: FolderAttributes) -> Self { pub fn remove(title: String, attributes: FolderAttributes) -> Self {
@ -170,14 +164,14 @@ impl FolderUpdateRequest {
title, title,
attributes: None, attributes: None,
update_attributes: None, update_attributes: None,
remove_attributes: Some(attributes) remove_attributes: Some(attributes),
} }
} }
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct FolderDeleteQuery { pub struct FolderDeleteQuery {
pub delete_mode: FolderDeleteMode pub delete_mode: FolderDeleteMode,
} }
impl FolderDeleteQuery { impl FolderDeleteQuery {
@ -190,5 +184,5 @@ impl FolderDeleteQuery {
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum FolderDeleteMode { pub enum FolderDeleteMode {
Recursive, Recursive,
AbotyOnNonEmpty AbotyOnNonEmpty,
} }

View File

@ -29,7 +29,6 @@ impl fmt::Display for DomainType {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")] #[serde(rename_all = "UPPERCASE")]
pub enum HttpMethod { pub enum HttpMethod {

View File

@ -6,5 +6,5 @@ pub struct HostContactGroups {
r#use: bool, r#use: bool,
use_for_services: bool, use_for_services: bool,
recuse_use: bool, recuse_use: bool,
recuse_perms: bool recuse_perms: bool,
} }

View File

@ -4,20 +4,22 @@ use std::net::{IpAddr, SocketAddr};
use std::sync::Arc; use std::sync::Arc;
use log::trace; use log::trace;
use reqwest::{Certificate, Request};
use reqwest::header::{HeaderName, HeaderValue}; use reqwest::header::{HeaderName, HeaderValue};
use reqwest::{Certificate, Request};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use tokio::sync::Semaphore; use tokio::sync::Semaphore;
use crate::api::{BulkCreateDomainExtention, BulkDeleteDomainExtention, BulkReadDomainExtention, BulkUpdateDomainExtention, DomainCollection, DomainExtention, DomainObject, DomainType}; use crate::api::{
BulkCreateDomainExtention, BulkDeleteDomainExtention, BulkReadDomainExtention,
BulkUpdateDomainExtention, DomainCollection, DomainExtention, DomainObject, DomainType,
};
use crate::{Error, Result}; use crate::{Error, Result};
pub struct Client(Arc<InnerClient>); pub struct Client(Arc<InnerClient>);
struct InnerClient { struct InnerClient {
http: reqwest::Client, http: reqwest::Client,
url: String, url: String,
semaphore: Semaphore semaphore: Semaphore,
} }
#[derive(Default, PartialEq, Eq)] #[derive(Default, PartialEq, Eq)]
@ -25,7 +27,8 @@ enum SslStrategy {
NoSll, NoSll,
IngoreHostname, IngoreHostname,
IgnoreCertificate, IgnoreCertificate,
#[default] Strict #[default]
Strict,
} }
#[derive(Default)] #[derive(Default)]
@ -45,7 +48,7 @@ pub struct ClientBuilder<T> {
resolve: Option<SocketAddr>, resolve: Option<SocketAddr>,
port: u16, port: u16,
_marker: PhantomData<T> _marker: PhantomData<T>,
} }
impl<T> ClientBuilder<T> { impl<T> ClientBuilder<T> {
@ -55,20 +58,30 @@ impl <T> ClientBuilder<T> {
} }
impl ClientBuilder<RequiresLocation> { impl ClientBuilder<RequiresLocation> {
pub fn on_host_and_site(self, hostname: String, sitename: String) -> ClientBuilder<RequiresCredentials> { pub fn on_host_and_site(
self,
hostname: String,
sitename: String,
) -> ClientBuilder<RequiresCredentials> {
ClientBuilder::<RequiresCredentials> { ClientBuilder::<RequiresCredentials> {
hostname, sitename, hostname,
sitename,
..Default::default() ..Default::default()
} }
} }
} }
impl ClientBuilder<RequiresCredentials> { impl ClientBuilder<RequiresCredentials> {
pub fn with_credentials(self, username: String, password: String) -> ClientBuilder<RequiresNothing> { pub fn with_credentials(
self,
username: String,
password: String,
) -> ClientBuilder<RequiresNothing> {
ClientBuilder { ClientBuilder {
hostname: self.hostname, hostname: self.hostname,
sitename: self.sitename, sitename: self.sitename,
username, password, username,
password,
..Default::default() ..Default::default()
} }
} }
@ -80,8 +93,10 @@ type ClientBuildResult<T> = std::result::Result<T, ClientBuildError>;
pub enum ClientBuildError { pub enum ClientBuildError {
#[error("failed to build client: {0}")] #[error("failed to build client: {0}")]
BuildClient(#[from] reqwest::Error), BuildClient(#[from] reqwest::Error),
#[error("invalid credentials. thise can only consist of visibly ASCII characters (ie. (32-127))")] #[error(
InvalidCredentials(#[from] reqwest::header::InvalidHeaderValue) "invalid credentials. thise can only consist of visibly ASCII characters (ie. (32-127))"
)]
InvalidCredentials(#[from] reqwest::header::InvalidHeaderValue),
} }
impl ClientBuilder<RequiresNothing> { impl ClientBuilder<RequiresNothing> {
@ -148,7 +163,8 @@ impl ClientBuilder<RequiresNothing> {
builder = builder.add_root_certificate(certificate); builder = builder.add_root_certificate(certificate);
} }
builder.build() builder
.build()
.map_err(ClientBuildError::BuildClient) .map_err(ClientBuildError::BuildClient)
.map_err(Error::BuildClient)? .map_err(Error::BuildClient)?
}; };
@ -157,7 +173,11 @@ impl ClientBuilder<RequiresNothing> {
// not sure if this has been inproved since 2.2 // not sure if this has been inproved since 2.2
let semaphore = Semaphore::new(10); let semaphore = Semaphore::new(10);
Ok(Client(Arc::new(InnerClient { http, url, semaphore }))) Ok(Client(Arc::new(InnerClient {
http,
url,
semaphore,
})))
} }
} }
@ -166,7 +186,7 @@ impl Client {
Self(Arc::new(InnerClient { Self(Arc::new(InnerClient {
http: client, http: client,
semaphore: Semaphore::new(10), semaphore: Semaphore::new(10),
url url,
})) }))
} }
pub fn builder() -> ClientBuilder<RequiresLocation> { pub fn builder() -> ClientBuilder<RequiresLocation> {
@ -182,26 +202,27 @@ impl InnerClient {
format!("{}/domain-types/{}/collections/all", self.url, domain_type) format!("{}/domain-types/{}/collections/all", self.url, domain_type)
} }
pub(crate) fn bulk_action_url(&self, domain_type: DomainType, action: BulkAction) -> String { pub(crate) fn bulk_action_url(&self, domain_type: DomainType, action: BulkAction) -> String {
format!("{}/domain-types/{}/actions/bulk-{}/invoke",self.url, domain_type, action) format!(
"{}/domain-types/{}/actions/bulk-{}/invoke",
self.url, domain_type, action
)
} }
pub(crate) async fn handle_request(&self, request: Request) -> Result<String> { pub(crate) async fn handle_request(&self, request: Request) -> Result<String> {
trace!("sending {}-request to {}", request.method(), request.url()); trace!("sending {}-request to {}", request.method(), request.url());
let response = self.http let response = self
.http
.execute(request) .execute(request)
.await .await
.map_err(Error::SendRequest)?; .map_err(Error::SendRequest)?;
let status = response.status(); let status = response.status();
let body = response.text() let body = response.text().await.map_err(Error::ReceiveBody)?;
.await
.map_err(Error::ReceiveBody)?;
if status.is_success() { if status.is_success() {
Ok(body) Ok(body)
} else { } else {
let cmkerror = serde_json::from_str(&body) let cmkerror = serde_json::from_str(&body).map_err(Error::DeserializeResponse)?;
.map_err(Error::DeserializeResponse)?;
Err(Error::CheckmkError(cmkerror)) Err(Error::CheckmkError(cmkerror))
} }
} }
@ -215,22 +236,21 @@ impl InnerClient {
} }
pub(crate) async fn get_etag(&self, object_url: &str) -> Result<HeaderValue> { pub(crate) async fn get_etag(&self, object_url: &str) -> Result<HeaderValue> {
let mut response = self.http let mut response = self
.http
.head(object_url) .head(object_url)
.send() .send()
.await .await
.map_err(Error::SendRequest)?; .map_err(Error::SendRequest)?;
if response.status().is_success() { if response.status().is_success() {
response.headers_mut() response
.headers_mut()
.remove("ETag") .remove("ETag")
.ok_or(Error::MissingHeader("ETag")) .ok_or(Error::MissingHeader("ETag"))
} else { } else {
let body = response.text() let body = response.text().await.map_err(Error::ReceiveBody)?;
.await let cmkerror = serde_json::from_str(&body).map_err(Error::DeserializeResponse)?;
.map_err(Error::ReceiveBody)?;
let cmkerror = serde_json::from_str(&body)
.map_err(Error::DeserializeResponse)?;
Err(Error::CheckmkError(cmkerror)) Err(Error::CheckmkError(cmkerror))
} }
} }
@ -238,9 +258,10 @@ impl InnerClient {
pub(crate) async fn create_domain_object<E: DomainExtention>( pub(crate) async fn create_domain_object<E: DomainExtention>(
&self, &self,
body: &E::CreationRequest, body: &E::CreationRequest,
query: &E::CreationQuery query: &E::CreationQuery,
) -> Result<()> { ) -> Result<()> {
let request = self.http let request = self
.http
.post(self.collection_url(E::DOMAIN_TYPE)) .post(self.collection_url(E::DOMAIN_TYPE))
.json(body) .json(body)
.query(query) .query(query)
@ -252,9 +273,10 @@ impl InnerClient {
pub(crate) async fn read_domain_object<E: DomainExtention>( pub(crate) async fn read_domain_object<E: DomainExtention>(
&self, &self,
id: impl Display, id: impl Display,
query: &E::ReadQuery query: &E::ReadQuery,
) -> Result<DomainObject<E>> { ) -> Result<DomainObject<E>> {
let request = self.http let request = self
.http
.get(self.object_url(E::DOMAIN_TYPE, id)) .get(self.object_url(E::DOMAIN_TYPE, id))
.query(query) .query(query)
.build() .build()
@ -269,7 +291,8 @@ impl InnerClient {
) -> Result<()> { ) -> Result<()> {
let url = self.object_url(E::DOMAIN_TYPE, id); let url = self.object_url(E::DOMAIN_TYPE, id);
let etag = self.get_etag(&url).await?; let etag = self.get_etag(&url).await?;
let request = self.http let request = self
.http
.put(url) .put(url)
.json(&request) .json(&request)
.header(reqwest::header::IF_MATCH, etag) .header(reqwest::header::IF_MATCH, etag)
@ -283,7 +306,8 @@ impl InnerClient {
id: impl Display, id: impl Display,
query: &E::DeleteQuery, query: &E::DeleteQuery,
) -> Result<()> { ) -> Result<()> {
let request = self.http let request = self
.http
.delete(self.object_url(E::DOMAIN_TYPE, id)) .delete(self.object_url(E::DOMAIN_TYPE, id))
.query(&query) .query(&query)
.build() .build()
@ -295,9 +319,10 @@ impl InnerClient {
pub(crate) async fn bulk_create_domain_objects<E: BulkCreateDomainExtention>( pub(crate) async fn bulk_create_domain_objects<E: BulkCreateDomainExtention>(
&self, &self,
request: &[E::CreationRequest], request: &[E::CreationRequest],
query: &E::CreationQuery query: &E::CreationQuery,
) -> Result<()> { ) -> Result<()> {
let request = self.http let request = self
.http
.post(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Create)) .post(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Create))
.json(request) .json(request)
.query(query) .query(query)
@ -310,7 +335,8 @@ impl InnerClient {
&self, &self,
query: &E::ReadQuery, query: &E::ReadQuery,
) -> Result<Vec<DomainObject<E>>> { ) -> Result<Vec<DomainObject<E>>> {
let request = self.http let request = self
.http
.get(self.collection_url(E::DOMAIN_TYPE)) .get(self.collection_url(E::DOMAIN_TYPE))
.query(query) .query(query)
.build() .build()
@ -323,7 +349,8 @@ impl InnerClient {
&self, &self,
body: &[E::BulkUpdateRequest], body: &[E::BulkUpdateRequest],
) -> Result<()> { ) -> Result<()> {
let request = self.http let request = self
.http
.put(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Update)) .put(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Update))
.json(body) .json(body)
.build() .build()
@ -335,7 +362,8 @@ impl InnerClient {
&self, &self,
ids: &[String], ids: &[String],
) -> Result<()> { ) -> Result<()> {
let request = self.http let request = self
.http
.post(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Delete)) .post(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Delete))
.json(&ids) .json(&ids)
.build() .build()
@ -365,44 +393,28 @@ impl Display for BulkAction {
pub struct ApiClient<D: DomainExtention> { pub struct ApiClient<D: DomainExtention> {
inner: Arc<InnerClient>, inner: Arc<InnerClient>,
_marker: PhantomData<D> _marker: PhantomData<D>,
} }
impl<D: DomainExtention> ApiClient<D> { impl<D: DomainExtention> ApiClient<D> {
pub async fn create( pub async fn create(
&self, &self,
request: &D::CreationRequest, request: &D::CreationRequest,
query: &D::CreationQuery query: &D::CreationQuery,
) -> Result<()> { ) -> Result<()> {
self.inner.create_domain_object::<D>(request, query).await self.inner.create_domain_object::<D>(request, query).await
} }
pub async fn read( pub async fn read(&self, id: impl Display, query: &D::ReadQuery) -> Result<D> {
&self,
id: impl Display,
query: &D::ReadQuery
) -> Result<D> {
self.inner self.inner
.read_domain_object(id, query) .read_domain_object(id, query)
.await .await
.map(|obj| obj.extensions) .map(|obj| obj.extensions)
} }
pub async fn update( pub async fn update(&self, id: impl Display, request: &D::UpdateRequest) -> Result<()> {
&self, self.inner.update_domain_object::<D>(id, request).await
id: impl Display,
request: &D::UpdateRequest
) -> Result<()> {
self.inner
.update_domain_object::<D>(id, request)
.await
} }
pub async fn delete( pub async fn delete(&self, id: impl Display, query: &D::DeleteQuery) -> Result<()> {
&self, self.inner.delete_domain_object::<D>(id, query).await
id: impl Display,
query: &D::DeleteQuery
) -> Result<()> {
self.inner
.delete_domain_object::<D>(id, query)
.await
} }
} }
@ -419,38 +431,21 @@ impl <D: BulkCreateDomainExtention> ApiClient<D> {
} }
impl<D: BulkReadDomainExtention> ApiClient<D> { impl<D: BulkReadDomainExtention> ApiClient<D> {
pub async fn bulk_read( pub async fn bulk_read(&self, query: &D::ReadQuery) -> Result<Vec<D>> {
&self, let objs = self.inner.bulk_read_domain_objects::<D>(query).await?;
query: &D::ReadQuery, let exts = objs.into_iter().map(|obj| obj.extensions).collect();
) -> Result<Vec<D>> {
let objs = self.inner
.bulk_read_domain_objects::<D>(query)
.await?;
let exts = objs.into_iter()
.map(|obj| obj.extensions)
.collect();
Ok(exts) Ok(exts)
} }
} }
impl<D: BulkUpdateDomainExtention> ApiClient<D> { impl<D: BulkUpdateDomainExtention> ApiClient<D> {
pub async fn bulk_update( pub async fn bulk_update(&self, request: &[D::BulkUpdateRequest]) -> Result<()> {
&self, self.inner.bulk_update_domain_objects::<D>(request).await
request: &[D::BulkUpdateRequest],
) -> Result<()> {
self.inner
.bulk_update_domain_objects::<D>(request)
.await
} }
} }
impl<D: BulkDeleteDomainExtention> ApiClient<D> { impl<D: BulkDeleteDomainExtention> ApiClient<D> {
pub async fn bulk_delete( pub async fn bulk_delete(&self, ids: &[String]) -> Result<()> {
&self, self.inner.bulk_delete_domain_objects::<D>(ids).await
ids: &[String],
) -> Result<()> {
self.inner
.bulk_delete_domain_objects::<D>(ids)
.await
} }
} }

View File

@ -1,5 +1,5 @@
pub mod api;
mod client; mod client;
mod error; mod error;
pub mod api;
pub use error::{Error, Result}; pub use error::{Error, Result};