Skip to main content

product_os_command_control/
config.rs

1//! Command and control configuration for distributed systems.
2
3use core::default::Default;
4use core::str::FromStr;
5use std::prelude::v1::*;
6use serde::{Deserialize, Serialize};
7
8use product_os_configuration::{ConfigError, ProductOSConfig};
9use product_os_request::Uri;
10
11/// Command and control configuration for managing distributed services.
12///
13/// This struct holds all configuration options for the command and control
14/// subsystem, including server addresses, failure thresholds, and cron schedules.
15#[derive(Clone, Debug, Deserialize, Serialize)]
16#[serde(rename_all = "camelCase")]
17pub struct CommandControl {
18    /// Enable command and control features
19    pub enable: bool,
20    /// URL address of this node (e.g. "https://localhost:8443")
21    pub url_address: String,
22    /// Maximum number of servers to manage (must be > 0)
23    pub max_servers: u8,
24    /// Maximum number of failures before taking action (must be > 0)
25    pub max_failures: u8,
26    /// Enable pulse check (heartbeat monitoring)
27    pub pulse_check: bool,
28    /// Cron expression for pulse check frequency
29    pub pulse_check_cron: String,
30    /// Enable monitoring
31    pub monitor: bool,
32    /// Cron expression for monitoring frequency
33    pub monitor_cron: String,
34    /// Automatically start services on initialization
35    pub auto_start_services: bool,
36}
37
38impl Default for CommandControl {
39    fn default() -> Self {
40        Self {
41            enable: false,
42            url_address: "https://localhost:8443".to_string(),
43            max_servers: 1,
44            max_failures: 1,
45            pulse_check: false,
46            pulse_check_cron: "0 * * * * * *".to_string(),
47            monitor: false,
48            monitor_cron: "0 * * * * * *".to_string(),
49            auto_start_services: false,
50        }
51    }
52}
53
54impl ProductOSConfig for CommandControl {
55    const SECTION_KEY: &'static str = "commandControl";
56
57    fn validate(&self) -> Result<(), ConfigError> {
58        let mut errors = Vec::new();
59
60        if Uri::from_str(self.url_address.as_str()).is_err() {
61            errors.push("url_address must be a valid URI (e.g. https://localhost:8443)".to_string());
62        }
63
64        if self.max_servers == 0 {
65            errors.push("max_servers must be greater than 0".to_string());
66        }
67
68        if self.max_failures == 0 {
69            errors.push("max_failures must be greater than 0".to_string());
70        }
71
72        if cron::Schedule::from_str(self.pulse_check_cron.as_str()).is_err() {
73            errors.push(format!("pulse_check_cron is not a valid cron expression: {}", self.pulse_check_cron));
74        }
75
76        if cron::Schedule::from_str(self.monitor_cron.as_str()).is_err() {
77            errors.push(format!("monitor_cron is not a valid cron expression: {}", self.monitor_cron));
78        }
79
80        if errors.is_empty() { Ok(()) }
81        else { Err(ConfigError::ValidationError(errors)) }
82    }
83}