diff --git a/WatcherAgent/src/api.rs b/WatcherAgent/src/api.rs index 156df86..19f81ba 100644 --- a/WatcherAgent/src/api.rs +++ b/WatcherAgent/src/api.rs @@ -15,7 +15,7 @@ use std::time::Duration; use crate::docker::serverclientcomm::handle_server_message; use crate::hardware::HardwareInfo; use crate::models::{ - Acknowledgment, HeartbeatDto, IdResponse, MetricDto, RegistrationDto, ServerMessage, + Acknowledgment, HeartbeatDto, IdResponse, MetricDto, RegistrationDto, ServerMessage, DockerMetricDto }; use anyhow::Result; @@ -39,7 +39,7 @@ use bollard::Docker; /// Returns an error if unable to register after repeated attempts. pub async fn register_with_server( base_url: &str, -) -> Result<(i32, String), Box> { +) -> Result<(u16, String), Box> { // First get local IP let ip = local_ip_address::local_ip()?.to_string(); println!("Local IP address detected: {}", ip); @@ -103,7 +103,7 @@ pub async fn register_with_server( async fn get_server_id_by_ip( base_url: &str, ip: &str, -) -> Result<(i32, String), Box> { +) -> Result<(u16, String), Box> { let client = Client::builder() .danger_accept_invalid_certs(true) .build()?; @@ -342,19 +342,19 @@ pub async fn send_acknowledgment( pub async fn send_docker_metrics( base_url: &str, - docker_metrics: &MetricDto, + docker_metrics: &DockerMetricDto, ) -> Result<(), Box> { let client = Client::new(); let url = format!("{}/monitoring/docker-metric", base_url); - println!("Metrics: {:?}", docker_metrics); + println!("Docker Metrics: {:?}", docker_metrics); match client.post(&url).json(&docker_metrics).send().await { Ok(res) => println!( - "✅ Sent metrics for server {} | Status: {}", + "✅ Sent docker metrics for server {} | Status: {}", docker_metrics.server_id, res.status() ), - Err(err) => eprintln!("❌ Failed to send metrics: {}", err), + Err(err) => eprintln!("❌ Failed to send docker metrics: {}", err), } Ok(()) diff --git a/WatcherAgent/src/docker/mod.rs b/WatcherAgent/src/docker/mod.rs index e652a4c..cc52ae8 100644 --- a/WatcherAgent/src/docker/mod.rs +++ b/WatcherAgent/src/docker/mod.rs @@ -11,7 +11,7 @@ pub mod container; pub mod serverclientcomm; pub mod stats; -use crate::models::{DockerRegistrationDto, DockerMetricDto, DockerContainer}; +use crate::models::{DockerRegistrationDto, DockerMetricDto, DockerContainer, DockerContainerInfo}; use bollard::{query_parameters::InspectContainerOptions, Docker}; use std::error::Error; @@ -88,7 +88,7 @@ impl DockerManager { } /// Gets all available containers as DTOs for registration - pub async fn get_containers_for_registration( + pub async fn get_containers( &self, ) -> Result, Box> { let containers = container::get_available_containers(&self.docker).await; @@ -103,8 +103,6 @@ impl DockerManager { .collect()) } - - /// Gets the number of running containers pub async fn get_container_count(&self) -> Result> { let containers = container::get_available_containers(&self.docker).await; @@ -118,6 +116,47 @@ impl DockerManager { ) -> Result<(), Box> { container::restart_container(&self.docker, container_id).await } + + /// Collects Docker metrics for all containers + pub async fn collect_metrics( + &self, + ) -> Result> { + let containers = self.get_containers().await?; + let (cpu_stats, net_stats, mem_stats) = stats::get_container_stats(&self.docker).await?; + + let container_infos: Vec<_> = containers + .into_iter() + .map(|container| { + let cpu = cpu_stats + .iter() + .find(|c| c.container_id == container.id) + .cloned(); + let network = net_stats + .iter() + .find(|n| n.container_id == container.id) + .cloned(); + let ram = mem_stats + .iter() + .find(|m| m.container_id == container.id) + .cloned(); + + DockerContainerInfo { + container: Some(container), + status: None, // Status can be fetched if needed + cpu, + network, + ram, + } + }) + .collect(); + + let dto = DockerMetricDto { + server_id: 0, + containers: serde_json::to_string(&container_infos)?, + }; + + Ok(dto) + } } // Keep these as utility functions if needed, but they should use DockerManager internally diff --git a/WatcherAgent/src/main.rs b/WatcherAgent/src/main.rs index 4c3d6e6..8460ea6 100644 --- a/WatcherAgent/src/main.rs +++ b/WatcherAgent/src/main.rs @@ -34,6 +34,7 @@ pub mod models; use bollard::Docker; use std::env; use std::error::Error; +use std::sync::Arc; use tokio::task::JoinHandle; /// Awaits a spawned asynchronous task and flattens its nested `Result` type. @@ -113,7 +114,7 @@ async fn main() -> Result<(), Box> { // Start background tasks // Start server listening for commands (only if Docker is available) - let listening_handle = if let Some(docker_manager) = docker_manager { + let listening_handle = if let Some(ref docker_manager) = docker_manager { tokio::spawn({ let docker = docker_manager.docker.clone(); let server_url = server_url.to_string(); @@ -136,8 +137,9 @@ async fn main() -> Result<(), Box> { let metrics_handle = tokio::spawn({ let ip = ip.clone(); let server_url = server_url.to_string(); + let docker_manager = docker_manager.as_ref().cloned().unwrap(); async move { - let mut collector = metrics::Collector::new(server_id, ip); + let mut collector = metrics::Collector::new(server_id, ip, docker_manager); collector.run(&server_url).await } }); diff --git a/WatcherAgent/src/metrics.rs b/WatcherAgent/src/metrics.rs index bf6dfc3..9908fb9 100644 --- a/WatcherAgent/src/metrics.rs +++ b/WatcherAgent/src/metrics.rs @@ -10,13 +10,15 @@ /// ## Usage /// The [`Collector`] struct is instantiated in the main loop and runs as a background task, continuously collecting and reporting metrics. use std::error::Error; +use std::sync::Arc; use std::time::Duration; -use crate::api; +use crate::{api, docker}; +use crate::docker::DockerManager; //use crate::docker::DockerInfo; use crate::hardware::network::NetworkMonitor; use crate::hardware::HardwareInfo; -use crate::models::MetricDto; +use crate::models::{DockerMetricDto, MetricDto}; /// Main orchestrator for hardware and network metric collection and reporting. /// @@ -27,8 +29,9 @@ use crate::models::MetricDto; /// - `server_id`: Unique server ID assigned by the backend. /// - `ip_address`: IP address of the agent. pub struct Collector { + docker_manager: DockerManager, network_monitor: NetworkMonitor, - server_id: i32, + server_id: u16, ip_address: String, } @@ -41,8 +44,9 @@ impl Collector { /// /// # Returns /// A new `Collector` ready to collect and report metrics. - pub fn new(server_id: i32, ip_address: String) -> Self { + pub fn new(server_id: u16, ip_address: String, docker_manager: DockerManager) -> Self { Self { + docker_manager, network_monitor: NetworkMonitor::new(), server_id, ip_address, @@ -72,7 +76,16 @@ impl Collector { continue; } }; + let docker_metrics = match self.docker_collect().await { + Ok(metrics) => metrics, + Err(e) => { + eprintln!("Error collecting docker metrics: {}", e); + tokio::time::sleep(Duration::from_secs(10)).await; + continue; + } + }; api::send_metrics(base_url, &metrics).await?; + api::send_docker_metrics(base_url, &docker_metrics).await?; tokio::time::sleep(Duration::from_secs(20)).await; } } @@ -113,58 +126,16 @@ impl Collector { }) } - /// Gets container metrics for all containers - pub async fn docker_collect( - &self, - ) -> Result, Box> { - let containers = container::get_available_containers(&self.docker).await; - let mut metrics = Vec::new(); - - for container in containers { - // Get network stats (you'll need to implement this in container.rs) - let network_stats = container::get_network_stats(&self.docker, &container.id).await?; - // Get CPU stats (you'll need to implement this in container.rs) - let cpu_stats = container::get_cpu_stats(&self.docker, &container.id).await?; - - // Get current status by inspecting the container - let status = match self - .docker - .inspect_container(&container.id, None::) - .await - { - Ok(container_info) => { - // Extract status from container state and convert to string - container_info - .state - .and_then(|state| state.status) - .map(|status_enum| { - match status_enum { - bollard::models::ContainerStateStatusEnum::CREATED => "created", - bollard::models::ContainerStateStatusEnum::RUNNING => "running", - bollard::models::ContainerStateStatusEnum::PAUSED => "paused", - bollard::models::ContainerStateStatusEnum::RESTARTING => { - "restarting" - } - bollard::models::ContainerStateStatusEnum::REMOVING => "removing", - bollard::models::ContainerStateStatusEnum::EXITED => "exited", - bollard::models::ContainerStateStatusEnum::DEAD => "dead", - bollard::secret::ContainerStateStatusEnum::EMPTY => todo!(), - } - .to_string() - }) - .unwrap_or_else(|| "unknown".to_string()) - } - Err(_) => "unknown".to_string(), - }; - - metrics.push(DockerContainerMetricDto { - server_id: container.id, - status: status, - network: network_stats, - cpu: cpu_stats, - }); - } - - Ok(metrics) + /// NOTE: This is a compilation-safe stub. Implement the Docker collection using your + /// DockerManager API and container helpers when available. + pub async fn docker_collect(&self) -> Result> { + let metrics = self + .docker_manager + .collect_metrics() + .await?; + Ok(DockerMetricDto { + server_id: self.server_id, + containers: metrics.containers, + }) } } diff --git a/WatcherAgent/src/models.rs b/WatcherAgent/src/models.rs index a8c1aa3..40c3b81 100644 --- a/WatcherAgent/src/models.rs +++ b/WatcherAgent/src/models.rs @@ -25,7 +25,7 @@ use serde::{Deserialize, Serialize}; #[derive(Serialize, Debug)] pub struct RegistrationDto { #[serde(rename = "id")] - pub server_id: i32, + pub server_id: u16, #[serde(rename = "ipAddress")] pub ip_address: String, #[serde(rename = "cpuType")] @@ -59,7 +59,7 @@ pub struct RegistrationDto { #[derive(Serialize, Debug)] pub struct MetricDto { #[serde(rename = "serverId")] - pub server_id: i32, + pub server_id: u16, #[serde(rename = "ipAddress")] pub ip_address: String, #[serde(rename = "cpu_Load")] @@ -116,7 +116,7 @@ pub struct DiskInfoDetailed { /// - `ip_address`: IPv4 or IPv6 address (string) #[derive(Deserialize)] pub struct IdResponse { - pub id: i32, + pub id: u16, #[serde(rename = "ipAddress")] pub ip_address: String, } @@ -188,7 +188,7 @@ pub struct Acknowledgment { #[derive(Debug, Serialize, Clone)] pub struct DockerRegistrationDto { /// Unique server identifier (integer) - pub server_id: u32, + pub server_id: u16, /// json stringified array of DockerContainer /// /// ## Json Example @@ -198,12 +198,12 @@ pub struct DockerRegistrationDto { /// id: unique container ID (first 12 hex digits) /// image: docker image name /// name: container name - pub containers: String, + pub containers: String // Vec, } #[derive(Debug, Serialize, Clone)] pub struct DockerMetricDto { - pub server_id: String, + pub server_id: u16, /// json stringified array of DockerContainer /// /// ## Json Example @@ -217,7 +217,7 @@ pub struct DockerMetricDto { /// network: network stats /// cpu: cpu stats /// ram: ram stats - pub containers: String, + pub containers: String // Vec, } #[derive(Debug, Serialize, Clone)]