use super::{Host, HostRef, ManagementURL, ServiceCheck, ServiceCheckHostRef};
use crate::{prelude::*, util::*};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
pub struct HostTemplate {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_string_or_number_to_u64",
default
)]
pub has_icon: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hosts: Option<ConfigRefMap<HostRef>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub managementurls: Option<ConfigObjectMap<ManagementURL>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub servicechecks: Option<ConfigRefMap<ServiceCheckHostRef>>,
#[serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_string_or_number_to_u64",
default
)]
pub id: Option<u64>,
#[serde(
rename = "ref",
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_readonly",
default
)]
pub ref_: Option<String>,
#[serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_string_or_number_to_option_bool",
serialize_with = "serialize_option_bool_as_string",
default
)]
pub uncommitted: Option<bool>,
}
impl CreateFromJson for HostTemplate {}
impl ConfigObject for HostTemplate {
type Builder = HostTemplateBuilder;
fn builder() -> Self::Builder {
HostTemplateBuilder::new()
}
fn config_path() -> Option<String> {
Some("/config/hosttemplate".to_string())
}
fn minimal(name: &str) -> Result<Self, OpsviewConfigError> {
Ok(Self {
name: validate_and_trim_hosttemplate_name(name)?,
..Default::default()
})
}
fn unique_name(&self) -> String {
self.name.clone()
}
}
impl Persistent for HostTemplate {
fn id(&self) -> Option<u64> {
self.id
}
fn ref_(&self) -> Option<String> {
if self.ref_.as_ref().is_some_and(|x| !x.is_empty()) {
self.ref_.clone()
} else {
None
}
}
fn name(&self) -> Option<String> {
if self.name.is_empty() {
None
} else {
Some(self.name.clone())
}
}
fn name_regex(&self) -> Option<String> {
Some(HOSTTEMPLATE_NAME_REGEX_STR.to_string())
}
fn validated_name(&self, name: &str) -> Result<String, OpsviewConfigError> {
validate_and_trim_hosttemplate_name(name)
}
fn set_name(&mut self, new_name: &str) -> Result<String, OpsviewConfigError> {
self.name = self.validated_name(new_name)?;
Ok(self.name.clone())
}
fn clear_readonly(&mut self) {
self.id = None;
self.ref_ = None;
self.uncommitted = None;
}
}
impl PersistentMap for ConfigObjectMap<HostTemplate> {
fn config_path() -> Option<String> {
Some("/config/hosttemplate".to_string())
}
}
#[derive(Clone, Debug, Default)]
pub struct HostTemplateBuilder {
name: Option<String>,
description: Option<String>,
has_icon: Option<u64>,
hosts: Option<ConfigRefMap<HostRef>>,
managementurls: Option<ConfigObjectMap<ManagementURL>>,
servicechecks: Option<ConfigRefMap<ServiceCheckHostRef>>,
}
impl Builder for HostTemplateBuilder {
type ConfigObject = HostTemplate;
fn new() -> Self {
HostTemplateBuilder::default()
}
fn name(mut self, name: &str) -> Self {
self.name = Some(name.to_string());
self
}
fn build(self) -> Result<Self::ConfigObject, OpsviewConfigError> {
let name = require_field(&self.name, "name")?;
let validated_description =
validate_opt_string(self.description, validate_and_trim_description)?;
if self
.has_icon
.is_some_and(|ts| !is_valid_past_unix_timestamp(ts))
{
return Err(OpsviewConfigError::InvalidTimestamp(format!(
"has_icon timestamp is in the future: {}",
self.has_icon.unwrap()
)));
}
Ok(HostTemplate {
name: validate_and_trim_hosttemplate_name(&name)?,
description: validated_description,
has_icon: self.has_icon,
hosts: self.hosts,
managementurls: self.managementurls,
servicechecks: self.servicechecks,
id: None,
ref_: None,
uncommitted: None,
})
}
}
impl HostTemplateBuilder {
pub fn clear_description(mut self) -> Self {
self.description = None;
self
}
pub fn clear_has_icon(mut self) -> Self {
self.has_icon = None;
self
}
pub fn clear_hosts(mut self) -> Self {
self.hosts = None;
self
}
pub fn clear_managementurls(mut self) -> Self {
self.managementurls = None;
self
}
pub fn clear_name(mut self) -> Self {
self.name = None;
self
}
pub fn clear_servicechecks(mut self) -> Self {
self.servicechecks = None;
self
}
pub fn description(mut self, description: &str) -> Self {
self.description = Some(description.to_string());
self
}
pub fn has_icon(mut self, has_icon: u64) -> Self {
self.has_icon = Some(has_icon);
self
}
pub fn hosts(mut self, hosts: &ConfigObjectMap<Host>) -> Self {
self.hosts = Some(hosts.into());
self
}
pub fn managementurls(mut self, managementurls: ConfigObjectMap<ManagementURL>) -> Self {
self.managementurls = Some(managementurls);
self
}
pub fn servicechecks(mut self, servicechecks: &ConfigObjectMap<ServiceCheck>) -> Self {
self.servicechecks = Some(servicechecks.into());
self
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq)]
pub struct HostTemplateRef {
name: String,
#[serde(
rename = "ref",
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_readonly",
default
)]
ref_: Option<String>,
}
impl CreateFromJson for HostTemplateRef {}
impl ConfigRef for HostTemplateRef {
type FullObject = HostTemplate;
fn ref_(&self) -> Option<String> {
self.ref_.clone()
}
fn name(&self) -> String {
self.name.clone()
}
fn unique_name(&self) -> String {
self.name.clone()
}
}
impl From<HostTemplate> for HostTemplateRef {
fn from(host_template: HostTemplate) -> Self {
Self {
name: host_template.name.clone(),
ref_: host_template.ref_.clone(),
}
}
}
impl From<Arc<HostTemplate>> for HostTemplateRef {
fn from(item: Arc<HostTemplate>) -> Self {
let cmd: HostTemplate = Arc::try_unwrap(item).unwrap_or_else(|arc| (*arc).clone());
HostTemplateRef::from(cmd)
}
}
impl From<&ConfigObjectMap<HostTemplate>> for ConfigRefMap<HostTemplateRef> {
fn from(host_templates: &ConfigObjectMap<HostTemplate>) -> Self {
ref_map_from(host_templates)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
let template = HostTemplate::default();
assert!(template.name.is_empty());
}
#[test]
fn test_minimal() {
let template = HostTemplate::minimal("My Host Template");
assert_eq!(template.unwrap().name, "My Host Template".to_string());
}
#[test]
fn test_thin_from_full_host_template() {
let obj = HostTemplate {
name: "My Host Template".to_string(),
description: Some("My Host Template Description".to_string()),
has_icon: Some(0),
hosts: None,
managementurls: None,
servicechecks: None,
id: Some(1),
ref_: Some("my-host-template-ref".to_string()),
uncommitted: Some(false),
};
let obj_ref = HostTemplateRef::from(obj.clone());
assert_eq!(obj_ref.name, obj.name);
assert_eq!(obj_ref.ref_, obj.ref_);
}
}