product-os-command-control 0.0.29

Product OS : Command and Control provides a set of tools for running command and control across a distributed set of Product OS : Servers.
Documentation
//! Command and control configuration for distributed systems.

use core::default::Default;
use core::str::FromStr;
use std::prelude::v1::*;
use serde::{Deserialize, Serialize};

use product_os_configuration::{ConfigError, ProductOSConfig};
use product_os_request::Uri;

/// Command and control configuration for managing distributed services.
///
/// This struct holds all configuration options for the command and control
/// subsystem, including server addresses, failure thresholds, and cron schedules.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CommandControl {
    /// Enable command and control features
    pub enable: bool,
    /// URL address of this node (e.g. "https://localhost:8443")
    pub url_address: String,
    /// Maximum number of servers to manage (must be > 0)
    pub max_servers: u8,
    /// Maximum number of failures before taking action (must be > 0)
    pub max_failures: u8,
    /// Enable pulse check (heartbeat monitoring)
    pub pulse_check: bool,
    /// Cron expression for pulse check frequency
    pub pulse_check_cron: String,
    /// Enable monitoring
    pub monitor: bool,
    /// Cron expression for monitoring frequency
    pub monitor_cron: String,
    /// Automatically start services on initialization
    pub auto_start_services: bool,
}

impl Default for CommandControl {
    fn default() -> Self {
        Self {
            enable: false,
            url_address: "https://localhost:8443".to_string(),
            max_servers: 1,
            max_failures: 1,
            pulse_check: false,
            pulse_check_cron: "0 * * * * * *".to_string(),
            monitor: false,
            monitor_cron: "0 * * * * * *".to_string(),
            auto_start_services: false,
        }
    }
}

impl ProductOSConfig for CommandControl {
    const SECTION_KEY: &'static str = "commandControl";

    fn validate(&self) -> Result<(), ConfigError> {
        let mut errors = Vec::new();

        if Uri::from_str(self.url_address.as_str()).is_err() {
            errors.push("url_address must be a valid URI (e.g. https://localhost:8443)".to_string());
        }

        if self.max_servers == 0 {
            errors.push("max_servers must be greater than 0".to_string());
        }

        if self.max_failures == 0 {
            errors.push("max_failures must be greater than 0".to_string());
        }

        if cron::Schedule::from_str(self.pulse_check_cron.as_str()).is_err() {
            errors.push(format!("pulse_check_cron is not a valid cron expression: {}", self.pulse_check_cron));
        }

        if cron::Schedule::from_str(self.monitor_cron.as_str()).is_err() {
            errors.push(format!("monitor_cron is not a valid cron expression: {}", self.monitor_cron));
        }

        if errors.is_empty() { Ok(()) }
        else { Err(ConfigError::ValidationError(errors)) }
    }
}