add actual actions to the client

This commit is contained in:
Vincent Stuyck 2025-12-20 00:40:34 +01:00
parent ad428dfa97
commit 8e35b8466b
4 changed files with 344 additions and 96 deletions

255
Cargo.lock generated
View File

@ -63,19 +63,22 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "checkmk-api"
version = "0.1.0"
dependencies = [
"base64",
"bytes",
"chrono",
"log",
"reqwest",
"secrecy",
"serde",
"serde_json",
"simplelog",
"thiserror",
"tokio",
]
@ -110,15 +113,6 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "deranged"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
dependencies = [
"powerfmt",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
@ -243,8 +237,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
@ -254,9 +250,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"r-efi",
"wasip2",
"wasm-bindgen",
]
[[package]]
@ -359,6 +357,7 @@ dependencies = [
"tokio",
"tokio-rustls",
"tower-service",
"webpki-roots",
]
[[package]]
@ -604,6 +603,12 @@ version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "lru-slab"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]]
name = "memchr"
version = "2.7.6"
@ -644,12 +649,6 @@ dependencies = [
"tempfile",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.19"
@ -659,15 +658,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@ -775,10 +765,13 @@ dependencies = [
]
[[package]]
name = "powerfmt"
version = "0.2.0"
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
@ -789,6 +782,61 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "quinn"
version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
dependencies = [
"bytes",
"cfg_aliases",
"pin-project-lite",
"quinn-proto",
"quinn-udp",
"rustc-hash",
"rustls",
"socket2",
"thiserror",
"tokio",
"tracing",
"web-time",
]
[[package]]
name = "quinn-proto"
version = "0.11.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
dependencies = [
"bytes",
"getrandom 0.3.4",
"lru-slab",
"rand",
"ring",
"rustc-hash",
"rustls",
"rustls-pki-types",
"slab",
"thiserror",
"tinyvec",
"tracing",
"web-time",
]
[[package]]
name = "quinn-udp"
version = "0.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
dependencies = [
"cfg_aliases",
"libc",
"once_cell",
"socket2",
"tracing",
"windows-sys 0.52.0",
]
[[package]]
name = "quote"
version = "1.0.42"
@ -804,6 +852,35 @@ version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "rand"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom 0.3.4",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
@ -837,6 +914,8 @@ dependencies = [
"native-tls",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls",
"rustls-pki-types",
"serde",
"serde_json",
@ -844,6 +923,7 @@ dependencies = [
"sync_wrapper",
"tokio",
"tokio-native-tls",
"tokio-rustls",
"tower",
"tower-http",
"tower-service",
@ -851,6 +931,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"webpki-roots",
]
[[package]]
@ -867,6 +948,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rustc-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustix"
version = "1.1.2"
@ -887,6 +974,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
dependencies = [
"once_cell",
"ring",
"rustls-pki-types",
"rustls-webpki",
"subtle",
@ -899,6 +987,7 @@ version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
dependencies = [
"web-time",
"zeroize",
]
@ -1043,17 +1132,6 @@ dependencies = [
"libc",
]
[[package]]
name = "simplelog"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0"
dependencies = [
"log",
"termcolor",
"time",
]
[[package]]
name = "slab"
version = "0.4.11"
@ -1153,15 +1231,6 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "2.0.17"
@ -1182,39 +1251,6 @@ dependencies = [
"syn",
]
[[package]]
name = "time"
version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
[[package]]
name = "time-macros"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tinystr"
version = "0.8.2"
@ -1225,6 +1261,21 @@ dependencies = [
"zerovec",
]
[[package]]
name = "tinyvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.48.0"
@ -1485,12 +1536,22 @@ dependencies = [
]
[[package]]
name = "winapi-util"
version = "0.1.11"
name = "web-time"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
dependencies = [
"windows-sys 0.61.2",
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webpki-roots"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e"
dependencies = [
"rustls-pki-types",
]
[[package]]
@ -1754,6 +1815,26 @@ dependencies = [
"synstructure",
]
[[package]]
name = "zerocopy"
version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zerofrom"
version = "0.1.6"

View File

@ -7,14 +7,11 @@ authors = [
]
[dependencies]
base64 = "0.22.1"
bytes = "1.11.0"
chrono = { version = "0.4.42", features = ["serde"] }
log = "0.4.29"
reqwest = "0.12.26"
reqwest = { version = "0.12.26", features = ["json", "rustls-tls"] }
secrecy = { version = "0.10.3", features = ["serde"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.145"
simplelog = "0.12.2"
thiserror = "2.0.17"
tokio = { version = "1.48.0", features = ["full"] }

View File

@ -1,6 +1,6 @@
use std::fmt;
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
@ -25,3 +25,65 @@ impl fmt::Display for DomainType {
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum HttpMethod {
Get,
Put,
Post,
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)]
#[serde(rename_all = "camelCase")]
pub(crate) struct DomainObject<E> {
pub domain_type: DomainType,
pub instance_id: String,
#[serde(default)]
pub title: Option<String>,
pub extensions: E,
// not used in this library
// #[serde(default)]
// pub links: Vec<RelationLink>,
// deprecated in favour of links
// pub members: M
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct DomainCollection<E> {
pub domain_type: DomainType,
pub instance_id: String,
#[serde(default)]
pub title: Option<String>,
pub value: Vec<DomainObject<E>>,
// not used in this library
// #[serde(default)]
// pub links: Vec<RelationLink>,
// pub extensions: Option<E>,
}
pub(crate) trait DomainExtention: DeserializeOwned + Serialize {
const DOMAIN_TYPE: DomainType;
type CreationRequest: Serialize;
type CreationQuery: Serialize;
type ReadQuery: Serialize;
type UpdateRequest: Serialize;
type DeleteQuery: Serialize;
}

View File

@ -9,7 +9,7 @@ use reqwest::header::{HeaderName, HeaderValue};
use serde::de::DeserializeOwned;
use tokio::sync::Semaphore;
use crate::api::DomainType;
use crate::api::{DomainCollection, DomainExtention, DomainObject, DomainType};
use crate::{Error, Result};
@ -205,7 +205,6 @@ impl InnerClient {
Err(Error::CheckmkError(cmkerror))
}
}
pub(crate) async fn invoke_api(&self, request: Request) -> Result<()> {
let _response = self.handle_request(request).await?;
Ok(())
@ -215,9 +214,9 @@ impl InnerClient {
serde_json::from_str(&response).map_err(Error::DeserializeResponse)
}
pub async fn get_etag(&self, domain_type: DomainType, id: &str) -> Result<HeaderValue> {
pub(crate) async fn get_etag(&self, object_url: &str) -> Result<HeaderValue> {
let mut response = self.http
.head(self.object_url(domain_type, id))
.head(object_url)
.send()
.await
.map_err(Error::SendRequest)?;
@ -235,6 +234,115 @@ impl InnerClient {
Err(Error::CheckmkError(cmkerror))
}
}
pub(crate) async fn create_domain_object<E: DomainExtention>(
&self,
body: &E::CreationRequest,
query: &E::CreationQuery
) -> Result<()> {
let request = self.http
.post(self.collection_url(E::DOMAIN_TYPE))
.json(body)
.query(query)
.build()
.unwrap();
self.invoke_api(request).await
}
pub(crate) async fn read_domain_object<E: DomainExtention>(
&self,
id: impl Display,
query: &E::ReadQuery
) -> Result<DomainObject<E>> {
let request = self.http
.get(self.object_url(E::DOMAIN_TYPE, id))
.query(query)
.build()
.unwrap();
self.query_api(request).await
}
pub(crate) async fn update_domain_object<E: DomainExtention>(
&self,
id: impl Display,
request: &E::UpdateRequest,
) -> Result<()> {
let url = self.object_url(E::DOMAIN_TYPE, id);
let etag = self.get_etag(&url).await?;
let request = self.http
.put(url)
.json(&request)
.header(reqwest::header::IF_MATCH, etag)
.build()
.unwrap();
self.invoke_api(request).await
}
pub(crate) async fn delete_domain_object<E: DomainExtention>(
&self,
id: impl Display,
params: &E::DeleteQuery,
) -> Result<()> {
let request = self.http
.delete(self.object_url(E::DOMAIN_TYPE, id))
.query(&params)
.build()
.unwrap();
self.invoke_api(request).await
}
pub(crate) async fn bulk_create_domain_objects<E: DomainExtention>(
&self,
body: &[E::CreationRequest],
query: &E::CreationQuery
) -> Result<()> {
let request = self.http
.post(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Create))
.json(body)
.query(query)
.build()
.unwrap();
self.invoke_api(request).await
}
pub(crate) async fn bulk_read_domain_objects<E: DomainExtention>(
&self,
query: &E::ReadQuery,
) -> Result<Vec<DomainObject<E>>> {
let request = self.http
.get(self.collection_url(E::DOMAIN_TYPE))
.query(query)
.build()
.unwrap();
let response: DomainCollection<E> = self.query_api(request).await?;
Ok(response.value)
}
pub(crate) async fn bulk_update_domain_objects<E: DomainExtention>(
&self,
body: &[E::UpdateRequest],
) -> Result<()> {
let request = self.http
.put(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Update))
.json(body)
.build()
.unwrap();
self.invoke_api(request).await
}
pub(crate) async fn bulk_delete_domain_objects<E: DomainExtention>(
&self,
ids: &[String],
) -> Result<()> {
let request = self.http
.post(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Delete))
.json(&ids)
.build()
.unwrap();
self.invoke_api(request).await
}
}
pub(crate) enum BulkAction {