add default implementations for domain extention queries
This commit is contained in:
parent
8e35b8466b
commit
52cff0c9fa
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -11,6 +11,17 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
@ -73,6 +84,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
name = "checkmk-api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"log",
|
||||
"reqwest",
|
||||
@ -834,7 +846,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@ -7,6 +7,7 @@ authors = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.89"
|
||||
chrono = { version = "0.4.42", features = ["serde"] }
|
||||
log = "0.4.29"
|
||||
reqwest = { version = "0.12.26", features = ["json", "rustls-tls"] }
|
||||
|
||||
54
src/api/folders.rs
Normal file
54
src/api/folders.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::api::DomainExtention;
|
||||
use crate::api::rules::contactgroups::HostContactGroups;
|
||||
use crate::api::rules::snmp::SnmpCommunity;
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct FolderConfig {
|
||||
pub path: String,
|
||||
pub attributes: FolderAttributes,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct FolderAttributes {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub site: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub contactgroups: Option<HostContactGroups>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub parents: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub snmp_community: Option<SnmpCommunity>,
|
||||
#[serde(default)]
|
||||
pub labels: HashMap<String, String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
/// this attribute is not optional when queried from the api.
|
||||
/// It cannot be filled in when creating a new folder.
|
||||
pub meta_data: Option<MetaData>,
|
||||
#[serde(flatten, skip_serializing_if = "HashMap::is_empty")]
|
||||
/// 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_"
|
||||
pub tags: HashMap<String, String>,
|
||||
|
||||
// TODO: to be implemented
|
||||
// #[serde(flatten, default)]
|
||||
// pub networkscan: NetworkScan,
|
||||
// #[serde(flatten, default)]
|
||||
// pub management: ManagementProtocol,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MetaData {
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
// can be null when builtin by checkmk, like the root diretory
|
||||
pub created_by: Option<String>,
|
||||
}
|
||||
|
||||
// impl DomainExtention for FolderConfig {
|
||||
|
||||
// }
|
||||
@ -1,3 +1,6 @@
|
||||
pub mod folders;
|
||||
pub(crate) mod rules;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
@ -36,18 +39,18 @@ pub enum HttpMethod {
|
||||
Delete,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub(crate) struct RelationLink {
|
||||
#[serde(rename = "domainType")]
|
||||
pub domain_type: DomainType,
|
||||
pub rel: String,
|
||||
pub href: String,
|
||||
pub method: HttpMethod,
|
||||
pub r#type: String,
|
||||
#[serde(default)]
|
||||
pub title: Option<String>,
|
||||
// body_params: HashMap<String, String> // i will deal with this later
|
||||
}
|
||||
// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
// pub(crate) struct RelationLink {
|
||||
// #[serde(rename = "domainType")]
|
||||
// pub domain_type: DomainType,
|
||||
// pub rel: String,
|
||||
// pub href: String,
|
||||
// pub method: HttpMethod,
|
||||
// pub r#type: String,
|
||||
// #[serde(default)]
|
||||
// pub title: Option<String>,
|
||||
// // body_params: HashMap<String, String> // i will deal with this later
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -87,3 +90,12 @@ pub(crate) trait DomainExtention: DeserializeOwned + Serialize {
|
||||
type UpdateRequest: Serialize;
|
||||
type DeleteQuery: Serialize;
|
||||
}
|
||||
|
||||
// these are essentials tags for domain extentions to signal that bulk operations are possible
|
||||
// not every extention supports bulk operations. and not all extentions that do support all of them
|
||||
pub(crate) trait BulkCreateDomainExtention: DomainExtention {}
|
||||
pub(crate) trait BulkReadDomainExtention: DomainExtention {}
|
||||
pub(crate) trait BulkUpdateDomainExtention: DomainExtention {
|
||||
type BulkUpdateRequest: Serialize;
|
||||
}
|
||||
pub(crate) trait BulkDeleteDomainExtention: DomainExtention {}
|
||||
|
||||
10
src/api/rules/contactgroups.rs
Normal file
10
src/api/rules/contactgroups.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct HostContactGroups {
|
||||
groups: Vec<String>,
|
||||
r#use: bool,
|
||||
use_for_services: bool,
|
||||
recuse_use: bool,
|
||||
recuse_perms: bool
|
||||
}
|
||||
2
src/api/rules/mod.rs
Normal file
2
src/api/rules/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod contactgroups;
|
||||
pub mod snmp;
|
||||
69
src/api/rules/snmp.rs
Normal file
69
src/api/rules/snmp.rs
Normal file
@ -0,0 +1,69 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum SnmpV3AuthProtocol {
|
||||
#[serde(rename = "MD5-96")]
|
||||
Md5,
|
||||
#[serde(rename = "SHA-1-96")]
|
||||
Sha96,
|
||||
#[serde(rename = "SHA-2-224")]
|
||||
Sha224,
|
||||
#[serde(rename = "SHA-2-256")]
|
||||
Sha256,
|
||||
#[serde(rename = "SHA-2-384")]
|
||||
Sha384,
|
||||
#[serde(rename = "SHA-2-512")]
|
||||
Sha512,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SnmpV3Auth {
|
||||
pub auth_protocol: SnmpV3AuthProtocol,
|
||||
pub security_name: String,
|
||||
pub auth_password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum SnmpV3PrivProtocol {
|
||||
#[serde(rename = "CBC-DES")]
|
||||
Des,
|
||||
#[serde(rename = "3DES-EDE")]
|
||||
Des3,
|
||||
#[serde(rename = "AES-128")]
|
||||
Aes128,
|
||||
#[serde(rename = "AES-192")]
|
||||
Aes192,
|
||||
#[serde(rename = "AES-256")]
|
||||
Aes256,
|
||||
#[serde(rename = "AES-192-Blumenthal")]
|
||||
Aes192Blumenthal,
|
||||
#[serde(rename = "AES-256-Blumenthal")]
|
||||
Aes256Blumenthal,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SnmpV3Priv {
|
||||
pub privacy_protocol: SnmpV3PrivProtocol,
|
||||
pub privacy_password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum SnmpCommunity {
|
||||
V1V2Community {
|
||||
community: String,
|
||||
},
|
||||
NoAuthNoPriv {
|
||||
security_name: String,
|
||||
},
|
||||
AuthNoPriv {
|
||||
#[serde(flatten)]
|
||||
auth: SnmpV3Auth,
|
||||
},
|
||||
AuthPriv {
|
||||
#[serde(flatten)]
|
||||
authentication: SnmpV3Auth,
|
||||
#[serde(flatten)]
|
||||
privacy: SnmpV3Priv,
|
||||
},
|
||||
}
|
||||
112
src/client.rs
112
src/client.rs
@ -9,7 +9,7 @@ use reqwest::header::{HeaderName, HeaderValue};
|
||||
use serde::de::DeserializeOwned;
|
||||
use tokio::sync::Semaphore;
|
||||
|
||||
use crate::api::{DomainCollection, DomainExtention, DomainObject, DomainType};
|
||||
use crate::api::{BulkCreateDomainExtention, BulkDeleteDomainExtention, BulkReadDomainExtention, BulkUpdateDomainExtention, DomainCollection, DomainExtention, DomainObject, DomainType};
|
||||
use crate::{Error, Result};
|
||||
|
||||
|
||||
@ -281,32 +281,32 @@ impl InnerClient {
|
||||
pub(crate) async fn delete_domain_object<E: DomainExtention>(
|
||||
&self,
|
||||
id: impl Display,
|
||||
params: &E::DeleteQuery,
|
||||
query: &E::DeleteQuery,
|
||||
) -> Result<()> {
|
||||
let request = self.http
|
||||
.delete(self.object_url(E::DOMAIN_TYPE, id))
|
||||
.query(¶ms)
|
||||
.query(&query)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
self.invoke_api(request).await
|
||||
}
|
||||
|
||||
pub(crate) async fn bulk_create_domain_objects<E: DomainExtention>(
|
||||
pub(crate) async fn bulk_create_domain_objects<E: BulkCreateDomainExtention>(
|
||||
&self,
|
||||
body: &[E::CreationRequest],
|
||||
request: &[E::CreationRequest],
|
||||
query: &E::CreationQuery
|
||||
) -> Result<()> {
|
||||
let request = self.http
|
||||
.post(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Create))
|
||||
.json(body)
|
||||
.json(request)
|
||||
.query(query)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
self.invoke_api(request).await
|
||||
}
|
||||
pub(crate) async fn bulk_read_domain_objects<E: DomainExtention>(
|
||||
pub(crate) async fn bulk_read_domain_objects<E: BulkReadDomainExtention>(
|
||||
&self,
|
||||
query: &E::ReadQuery,
|
||||
) -> Result<Vec<DomainObject<E>>> {
|
||||
@ -319,9 +319,9 @@ impl InnerClient {
|
||||
let response: DomainCollection<E> = self.query_api(request).await?;
|
||||
Ok(response.value)
|
||||
}
|
||||
pub(crate) async fn bulk_update_domain_objects<E: DomainExtention>(
|
||||
pub(crate) async fn bulk_update_domain_objects<E: BulkUpdateDomainExtention>(
|
||||
&self,
|
||||
body: &[E::UpdateRequest],
|
||||
body: &[E::BulkUpdateRequest],
|
||||
) -> Result<()> {
|
||||
let request = self.http
|
||||
.put(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Update))
|
||||
@ -331,7 +331,7 @@ impl InnerClient {
|
||||
|
||||
self.invoke_api(request).await
|
||||
}
|
||||
pub(crate) async fn bulk_delete_domain_objects<E: DomainExtention>(
|
||||
pub(crate) async fn bulk_delete_domain_objects<E: BulkDeleteDomainExtention>(
|
||||
&self,
|
||||
ids: &[String],
|
||||
) -> Result<()> {
|
||||
@ -362,3 +362,95 @@ impl Display for BulkAction {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ApiClient<D: DomainExtention> {
|
||||
inner: Arc<InnerClient>,
|
||||
_marker: PhantomData<D>
|
||||
}
|
||||
|
||||
impl <D: DomainExtention> ApiClient<D> {
|
||||
pub async fn create(
|
||||
&self,
|
||||
request: &D::CreationRequest,
|
||||
query: &D::CreationQuery
|
||||
) -> Result<()> {
|
||||
self.inner.create_domain_object::<D>(request, query).await
|
||||
}
|
||||
pub async fn read(
|
||||
&self,
|
||||
id: impl Display,
|
||||
query: &D::ReadQuery
|
||||
) -> Result<D> {
|
||||
self.inner
|
||||
.read_domain_object(id, query)
|
||||
.await
|
||||
.map(|obj| obj.extensions)
|
||||
}
|
||||
pub async fn update(
|
||||
&self,
|
||||
id: impl Display,
|
||||
request: &D::UpdateRequest
|
||||
) -> Result<()> {
|
||||
self.inner
|
||||
.update_domain_object::<D>(id, request)
|
||||
.await
|
||||
}
|
||||
pub async fn delete(
|
||||
&self,
|
||||
id: impl Display,
|
||||
query: &D::DeleteQuery
|
||||
) -> Result<()> {
|
||||
self.inner
|
||||
.delete_domain_object::<D>(id, query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl <D: BulkCreateDomainExtention> ApiClient<D> {
|
||||
pub async fn bulk_create(
|
||||
&self,
|
||||
request: &[D::CreationRequest],
|
||||
query: &D::CreationQuery,
|
||||
) -> Result<()> {
|
||||
self.inner
|
||||
.bulk_create_domain_objects::<D>(request, query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl <D: BulkReadDomainExtention> ApiClient<D> {
|
||||
pub async fn bulk_read(
|
||||
&self,
|
||||
query: &D::ReadQuery,
|
||||
) -> 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)
|
||||
}
|
||||
}
|
||||
|
||||
impl <D: BulkUpdateDomainExtention> ApiClient<D> {
|
||||
pub async fn bulk_update(
|
||||
&self,
|
||||
request: &[D::BulkUpdateRequest],
|
||||
) -> Result<()> {
|
||||
self.inner
|
||||
.bulk_update_domain_objects::<D>(request)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl <D: BulkDeleteDomainExtention> ApiClient<D> {
|
||||
pub async fn bulk_delete(
|
||||
&self,
|
||||
ids: &[String],
|
||||
) -> Result<()> {
|
||||
self.inner
|
||||
.bulk_delete_domain_objects::<D>(ids)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user