apt-ostree/src/bin/monitoring-service.rs
robojerk 0ba99d6195 OCI Integration & Container Image Generation Complete! 🎉
FEAT: Complete OCI integration with container image generation capabilities

- Add comprehensive OCI module (src/oci.rs) with full specification compliance
- Implement OciImageBuilder for OSTree commit to container image conversion
- Add OciRegistry for push/pull operations with authentication support
- Create OciUtils for image validation, inspection, and format conversion
- Support both OCI and Docker image formats with proper content addressing
- Add SHA256 digest calculation for all image components
- Implement gzip compression for filesystem layers

CLI: Add complete OCI command suite
- apt-ostree oci build - Build OCI images from OSTree commits
- apt-ostree oci push - Push images to container registries
- apt-ostree oci pull - Pull images from registries
- apt-ostree oci inspect - Inspect image information
- apt-ostree oci validate - Validate image integrity
- apt-ostree oci convert - Convert between image formats

COMPOSE: Enhance compose workflow with OCI integration
- apt-ostree compose build-image - Convert deployments to OCI images
- apt-ostree compose container-encapsulate - Generate container images from commits
- apt-ostree compose image - Generate container images from treefiles

ARCH: Add OCI layer to project architecture
- Integrate OCI manager into lib.rs and main.rs
- Add proper error handling and recovery mechanisms
- Include comprehensive testing and validation
- Create test script for OCI functionality validation

DEPS: Add sha256 crate for content addressing
- Update Cargo.toml with sha256 dependency
- Ensure proper async/await handling with tokio::process::Command
- Fix borrow checker issues and lifetime management

DOCS: Update project documentation
- Add OCI integration summary documentation
- Update todo.md with milestone 9 completion
- Include usage examples and workflow documentation
2025-07-19 23:05:39 +00:00

341 lines
No EOL
12 KiB
Rust

//! APT-OSTree Monitoring Service
//!
//! This service runs in the background to collect metrics, perform health checks,
//! and provide monitoring capabilities for the APT-OSTree system.
use std::sync::Arc;
use std::time::Duration;
use tokio::time::interval;
use tracing::{info, warn, error, debug};
use serde_json;
use apt_ostree::monitoring::{MonitoringManager, MonitoringConfig};
use apt_ostree::error::AptOstreeResult;
/// Monitoring service configuration
#[derive(Debug, Clone)]
struct MonitoringServiceConfig {
/// Metrics collection interval in seconds
pub metrics_interval: u64,
/// Health check interval in seconds
pub health_check_interval: u64,
/// Export metrics to file
pub export_metrics: bool,
/// Metrics export file path
pub metrics_file: String,
/// Enable system resource monitoring
pub enable_system_monitoring: bool,
/// Enable performance monitoring
pub enable_performance_monitoring: bool,
/// Enable transaction monitoring
pub enable_transaction_monitoring: bool,
}
impl Default for MonitoringServiceConfig {
fn default() -> Self {
Self {
metrics_interval: 60,
health_check_interval: 300,
export_metrics: true,
metrics_file: "/var/log/apt-ostree/metrics.json".to_string(),
enable_system_monitoring: true,
enable_performance_monitoring: true,
enable_transaction_monitoring: true,
}
}
}
/// Monitoring service
struct MonitoringService {
config: MonitoringServiceConfig,
monitoring_manager: Arc<MonitoringManager>,
running: bool,
}
impl MonitoringService {
/// Create a new monitoring service
fn new(config: MonitoringServiceConfig) -> AptOstreeResult<Self> {
info!("Creating monitoring service with config: {:?}", config);
let monitoring_config = MonitoringConfig {
log_level: "info".to_string(),
log_file: None,
structured_logging: true,
enable_metrics: true,
metrics_interval: config.metrics_interval,
enable_health_checks: true,
health_check_interval: config.health_check_interval,
enable_performance_monitoring: config.enable_performance_monitoring,
enable_transaction_monitoring: config.enable_transaction_monitoring,
enable_system_monitoring: config.enable_system_monitoring,
};
let monitoring_manager = Arc::new(MonitoringManager::new(monitoring_config)?);
monitoring_manager.init_logging()?;
Ok(Self {
config,
monitoring_manager,
running: false,
})
}
/// Start the monitoring service
async fn start(&mut self) -> AptOstreeResult<()> {
info!("Starting monitoring service");
self.running = true;
// Start metrics collection task
let metrics_manager = self.monitoring_manager.clone();
let metrics_interval = self.config.metrics_interval;
let export_metrics = self.config.export_metrics;
let metrics_file = self.config.metrics_file.clone();
tokio::spawn(async move {
let mut interval = interval(Duration::from_secs(metrics_interval));
while let Some(_) = interval.tick().await {
debug!("Collecting system metrics");
if let Err(e) = metrics_manager.record_system_metrics().await {
error!("Failed to record system metrics: {}", e);
}
if export_metrics {
if let Err(e) = Self::export_metrics_to_file(&metrics_manager, &metrics_file).await {
error!("Failed to export metrics to file: {}", e);
}
}
}
});
// Start health check task
let health_manager = self.monitoring_manager.clone();
let health_interval = self.config.health_check_interval;
tokio::spawn(async move {
let mut interval = interval(Duration::from_secs(health_interval));
while let Some(_) = interval.tick().await {
debug!("Running health checks");
match health_manager.run_health_checks().await {
Ok(results) => {
for result in results {
match result.status {
apt_ostree::monitoring::HealthStatus::Healthy => {
debug!("Health check passed: {}", result.check_name);
}
apt_ostree::monitoring::HealthStatus::Warning => {
warn!("Health check warning: {} - {}", result.check_name, result.message);
}
apt_ostree::monitoring::HealthStatus::Critical => {
error!("Health check critical: {} - {}", result.check_name, result.message);
}
apt_ostree::monitoring::HealthStatus::Unknown => {
warn!("Health check unknown: {} - {}", result.check_name, result.message);
}
}
}
}
Err(e) => {
error!("Failed to run health checks: {}", e);
}
}
}
});
info!("Monitoring service started successfully");
Ok(())
}
/// Stop the monitoring service
async fn stop(&mut self) -> AptOstreeResult<()> {
info!("Stopping monitoring service");
self.running = false;
// Export final metrics
if self.config.export_metrics {
if let Err(e) = Self::export_metrics_to_file(&self.monitoring_manager, &self.config.metrics_file).await {
error!("Failed to export final metrics: {}", e);
}
}
info!("Monitoring service stopped");
Ok(())
}
/// Export metrics to file
async fn export_metrics_to_file(
monitoring_manager: &Arc<MonitoringManager>,
file_path: &str,
) -> AptOstreeResult<()> {
let metrics_json = monitoring_manager.export_metrics().await?;
// Ensure directory exists
if let Some(parent) = std::path::Path::new(file_path).parent() {
std::fs::create_dir_all(parent)?;
}
// Write metrics to file
std::fs::write(file_path, metrics_json)?;
debug!("Metrics exported to: {}", file_path);
Ok(())
}
/// Get service statistics
async fn get_statistics(&self) -> AptOstreeResult<String> {
let stats = self.monitoring_manager.get_statistics().await?;
let output = format!(
"Monitoring Service Statistics:\n\
Uptime: {} seconds\n\
Metrics collected: {}\n\
Performance metrics: {}\n\
Active transactions: {}\n\
Health checks performed: {}\n\
Service running: {}\n",
stats.uptime_seconds,
stats.metrics_collected,
stats.performance_metrics_collected,
stats.active_transactions,
stats.health_checks_performed,
self.running
);
Ok(output)
}
/// Run a single health check cycle
async fn run_health_check_cycle(&self) -> AptOstreeResult<()> {
info!("Running health check cycle");
let results = self.monitoring_manager.run_health_checks().await?;
let mut healthy_count = 0;
let mut warning_count = 0;
let mut critical_count = 0;
let mut unknown_count = 0;
for result in results {
match result.status {
apt_ostree::monitoring::HealthStatus::Healthy => {
healthy_count += 1;
debug!("✅ {}: {}", result.check_name, result.message);
}
apt_ostree::monitoring::HealthStatus::Warning => {
warning_count += 1;
warn!("⚠️ {}: {}", result.check_name, result.message);
}
apt_ostree::monitoring::HealthStatus::Critical => {
critical_count += 1;
error!("❌ {}: {}", result.check_name, result.message);
}
apt_ostree::monitoring::HealthStatus::Unknown => {
unknown_count += 1;
warn!("❓ {}: {}", result.check_name, result.message);
}
}
}
info!(
"Health check cycle completed: {} healthy, {} warnings, {} critical, {} unknown",
healthy_count, warning_count, critical_count, unknown_count
);
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize logging
tracing_subscriber::fmt::init();
info!("Starting APT-OSTree monitoring service");
// Parse command line arguments
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 {
match args[1].as_str() {
"start" => {
let config = MonitoringServiceConfig::default();
let mut service = MonitoringService::new(config)?;
service.start().await?;
// Keep the service running
loop {
tokio::time::sleep(Duration::from_secs(1)).await;
}
}
"stop" => {
info!("Stop command received (not implemented in this version)");
}
"status" => {
let config = MonitoringServiceConfig::default();
let service = MonitoringService::new(config)?;
let stats = service.get_statistics().await?;
println!("{}", stats);
}
"health-check" => {
let config = MonitoringServiceConfig::default();
let service = MonitoringService::new(config)?;
service.run_health_check_cycle().await?;
}
"export-metrics" => {
let config = MonitoringServiceConfig::default();
let service = MonitoringService::new(config)?;
let metrics_json = service.monitoring_manager.export_metrics().await?;
println!("{}", metrics_json);
}
_ => {
eprintln!("Usage: {} [start|stop|status|health-check|export-metrics]", args[0]);
std::process::exit(1);
}
}
} else {
// Default: start the service
let config = MonitoringServiceConfig::default();
let mut service = MonitoringService::new(config)?;
service.start().await?;
// Keep the service running
loop {
tokio::time::sleep(Duration::from_secs(1)).await;
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_monitoring_service_creation() {
let config = MonitoringServiceConfig::default();
let service = MonitoringService::new(config).unwrap();
assert!(service.running == false);
}
#[tokio::test]
async fn test_health_check_cycle() {
let config = MonitoringServiceConfig::default();
let service = MonitoringService::new(config).unwrap();
assert!(service.run_health_check_cycle().await.is_ok());
}
#[tokio::test]
async fn test_get_statistics() {
let config = MonitoringServiceConfig::default();
let service = MonitoringService::new(config).unwrap();
let stats = service.get_statistics().await.unwrap();
assert!(!stats.is_empty());
assert!(stats.contains("Monitoring Service Statistics"));
}
}