use super::{BSMComponent, BSMComponentRef, MonitoringCluster, MonitoringClusterRef};
use crate::{prelude::*, util::*};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
pub struct BSMService {
pub name: String,
#[serde(alias = "business_components")]
pub components: Option<ConfigRefMap<BSMComponentRef>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub monitoring_cluster: Option<MonitoringClusterRef>,
#[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 BSMService {}
impl ConfigObject for BSMService {
type Builder = BSMServiceBuilder;
fn builder() -> Self::Builder {
BSMServiceBuilder::new()
}
fn config_path() -> Option<String> {
Some("/config/bsmservice".to_string())
}
fn minimal(name: &str) -> Result<Self, OpsviewConfigError> {
Ok(Self {
name: validate_and_trim_bsmservice_name(name)?,
..Default::default()
})
}
fn unique_name(&self) -> String {
let name = self.name.clone();
match (self.id.as_ref(), self.ref_.as_ref()) {
(Some(id), _) => format!("{}-{}", name, id),
(_, Some(ref_)) => ref_.clone(),
_ => name,
}
}
}
impl Persistent for BSMService {
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(INLINE_FREE_TEXT_REGEX_STR.to_string())
}
fn validated_name(&self, name: &str) -> Result<String, OpsviewConfigError> {
validate_and_trim_bsmservice_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<BSMService> {
fn config_path() -> Option<String> {
Some("/config/bsmservice".to_string())
}
}
#[derive(Clone, Debug, Default)]
pub struct BSMServiceBuilder {
name: Option<String>,
components: Option<ConfigRefMap<BSMComponentRef>>,
monitoring_cluster: Option<MonitoringClusterRef>,
}
impl Builder for BSMServiceBuilder {
type ConfigObject = BSMService;
fn new() -> Self {
BSMServiceBuilder::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 components = require_field(&self.components, "components")?;
Ok(BSMService {
name: validate_and_trim_bsmservice_name(&name)?,
components: Some(components),
monitoring_cluster: self.monitoring_cluster,
id: None,
ref_: None,
uncommitted: None,
})
}
}
impl BSMServiceBuilder {
pub fn clear_components(mut self) -> Self {
self.components = None;
self
}
pub fn clear_monitoring_cluster(mut self) -> Self {
self.monitoring_cluster = None;
self
}
pub fn clear_name(mut self) -> Self {
self.name = None;
self
}
pub fn components(mut self, components: &ConfigObjectMap<BSMComponent>) -> Self {
self.components = Some(components.into());
self
}
pub fn monitoring_cluster(mut self, monitoring_cluster: MonitoringCluster) -> Self {
self.monitoring_cluster = Some(MonitoringClusterRef::from(monitoring_cluster));
self
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq)]
pub struct BSMServiceRef {
name: String,
#[serde(
rename = "ref",
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_readonly",
default
)]
ref_: Option<String>,
}
impl CreateFromJson for BSMServiceRef {}
impl ConfigRef for BSMServiceRef {
type FullObject = BSMService;
fn ref_(&self) -> Option<String> {
self.ref_.clone()
}
fn name(&self) -> String {
self.name.clone()
}
fn unique_name(&self) -> String {
let name = self.name.clone();
match self.ref_.as_ref() {
Some(ref_) => ref_.clone(),
_ => name,
}
}
}
impl From<BSMService> for BSMServiceRef {
fn from(full_object: BSMService) -> Self {
Self {
name: full_object.name.clone(),
ref_: full_object.ref_.clone(),
}
}
}
impl From<Arc<BSMService>> for BSMServiceRef {
fn from(item: Arc<BSMService>) -> Self {
let service: BSMService = Arc::try_unwrap(item).unwrap_or_else(|arc| (*arc).clone());
BSMServiceRef::from(service)
}
}
impl From<&ConfigObjectMap<BSMService>> for ConfigRefMap<BSMServiceRef> {
fn from(services: &ConfigObjectMap<BSMService>) -> Self {
ref_map_from(services)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
let service = BSMService::default();
assert!(service.name.is_empty());
}
#[test]
fn test_minimal() {
let service = BSMService::minimal("My BSM Service");
assert_eq!(service.unwrap().name, "My BSM Service".to_string());
}
#[test]
fn test_is_valid_bsmservice_name() {
assert!(validate_and_trim_bsmservice_name("Valid Service Name").is_ok());
assert!(validate_and_trim_bsmservice_name("Another-Valid_Service.Name123").is_ok());
assert!(validate_and_trim_bsmservice_name(&"A".repeat(255)).is_ok());
assert!(validate_and_trim_bsmservice_name("").is_err()); assert!(validate_and_trim_bsmservice_name(&"A".repeat(256)).is_err());
}
}