diff --git a/WatcherAgent/src/api.rs b/WatcherAgent/src/api.rs index 9130e82..368119b 100644 --- a/WatcherAgent/src/api.rs +++ b/WatcherAgent/src/api.rs @@ -424,6 +424,29 @@ pub async fn send_acknowledgment( Ok(()) } +/// Sends Docker container metrics to the backend monitoring endpoint. +/// +/// This function asynchronously transmits Docker container statistics including +/// CPU usage, memory consumption, network I/O, and container status to the +/// backend server for monitoring and analysis. +/// +/// # Arguments +/// +/// * `base_url` - The base URL of the backend server (e.g., "http://localhost:8080") +/// * `docker_metrics` - Reference to a [`DockerMetricDto`] containing container metrics data +/// +/// # Returns +/// +/// * `Ok(())` - If the HTTP request was successfully sent (regardless of HTTP status code) +/// * `Err(Box)` - If JSON serialization fails or other errors occur +/// +/// # Behavior +/// +/// - Constructs the full endpoint URL: `{base_url}/monitoring/docker-metric` +/// - Serializes the metrics data to pretty JSON for debugging output +/// - Sends a POST request with JSON content-type +/// - Logs success/failure messages to stdout/stderr +/// - Always returns `Ok(())` after request attempt (does not validate HTTP response status) pub async fn send_docker_metrics( base_url: &str, docker_metrics: &DockerMetricDto, @@ -431,7 +454,7 @@ pub async fn send_docker_metrics( let client = Client::new(); let url = format!("{}/monitoring/docker-metric", base_url); - println!("Docker Metrics: {}", serde_json::to_string_pretty(&docker_metrics)?); + println!("📤 JSON being posted:\n{}", serde_json::to_string_pretty(&docker_metrics)?); match client.post(&url).json(&docker_metrics).send().await { Ok(res) => println!( diff --git a/WatcherAgent/src/docker/container.rs b/WatcherAgent/src/docker/container.rs index 87daa6a..810f160 100644 --- a/WatcherAgent/src/docker/container.rs +++ b/WatcherAgent/src/docker/container.rs @@ -154,19 +154,6 @@ pub async fn restart_container( Ok(()) } -/* -/// Extracts a Docker container ID from a string line. -/// -/// # Arguments -/// * `line` - The input string containing a container ID or related info. -/// -/// # Returns -/// * `Option` - The extracted container ID if found. -pub fn extract_client_container_id(line: &str) -> Option { - // ...existing code... -} -*/ - /// Gets network statistics for a specific container pub async fn get_network_stats( docker: &Docker, diff --git a/WatcherAgent/src/docker/mod.rs b/WatcherAgent/src/docker/mod.rs index be0c2c6..494a64b 100644 --- a/WatcherAgent/src/docker/mod.rs +++ b/WatcherAgent/src/docker/mod.rs @@ -35,7 +35,15 @@ impl Default for DockerManager { } impl DockerManager { - /// Creates a new DockerManager instance + /// Creates a new DockerManager instance with Docker connection + /// + /// Establishes a connection to the local Docker daemon using default connection settings. + /// This is the primary constructor for the Docker manager. + /// + /// # Returns + /// + /// * `Ok(Self)` - Successfully connected Docker manager instance + /// * `Err(Box)` - If Docker daemon is not running or connection fails pub fn new() -> Result> { let docker = Docker::connect_with_local_defaults() .map_err(|e| format!("Failed to connect to Docker: {}", e))?; @@ -44,13 +52,31 @@ impl DockerManager { } /// Creates a DockerManager instance with optional Docker connection + /// + /// Attempts to connect to Docker but returns None instead of an error if connection fails. + /// Useful for scenarios where Docker availability is optional. + /// + /// # Returns + /// + /// * `Some(Self)` - If Docker connection is successful + /// * `None` - If Docker connection fails or Docker daemon is not available pub fn new_optional() -> Option { Docker::connect_with_local_defaults() .map(|docker| Self { docker }) .ok() } - /// Finds the Docker container running the agent by image name + + /// Finds the Docker container running the WatcherAgent by image name + /// + /// Searches through all available containers to find the one running the agent. + /// Matches containers whose image name contains "watcher-agent". + /// + /// # Returns + /// + /// * `Ok(Some(DockerContainer))` - Agent container found with full container details + /// * `Ok(None)` - No agent container found (agent may not be running in Docker) + /// * `Err(Box)` - If container enumeration fails pub async fn get_client_container( &self, ) -> Result, Box> { @@ -67,7 +93,14 @@ impl DockerManager { })) } - /// Gets the current client version (image name) if running in Docker + /// Gets the current client version from Docker image name + /// + /// Extracts the image name (without tag) from the agent's container. + /// Returns "unknown" if the agent is not running in Docker or if version cannot be determined. + /// + /// # Returns + /// + /// * `String` - Image name portion before ':' tag, or "unknown" if not determinable pub async fn get_client_version(&self) -> String { match self.get_client_container().await { Ok(Some(container)) => container @@ -90,6 +123,13 @@ impl DockerManager { } /// Checks if Docker is available and the agent is running in a container + /// + /// Determines whether the agent is operating within a Docker container environment. + /// This is used to enable/disable Docker-specific functionality. + /// + /// # Returns + /// + /// * `bool` - True if agent is running in Docker container, false otherwise pub async fn is_dockerized(&self) -> bool { self.get_client_container() .await @@ -97,7 +137,15 @@ impl DockerManager { .unwrap_or(false) } - /// Gets all available containers as DTOs for registration + /// Gets all available Docker containers as DTOs + /// + /// Retrieves a list of all containers (running and stopped) and converts them + /// to simplified DTOs suitable for registration with the backend server. + /// + /// # Returns + /// + /// * `Ok(Vec)` - List of all containers with id, image, and name + /// * `Err(Box)` - If container enumeration fails pub async fn get_containers( &self, ) -> Result, Box> { @@ -114,12 +162,32 @@ impl DockerManager { } /// Gets the number of running containers + /// + /// Counts all containers that are currently available (both running and stopped). + /// This provides a quick overview of container density on the host. + /// + /// # Returns + /// + /// * `Ok(usize)` - Total number of containers + /// * `Err(Box)` - If container counting fails pub async fn get_container_count(&self) -> Result> { let containers = container::get_available_containers(&self.docker).await; Ok(containers.len()) } /// Restarts a specific container by ID + /// + /// Initiates a restart of the specified container. This is typically used + /// in response to backend commands for container management. + /// + /// # Arguments + /// + /// * `container_id` - The full or partial container ID to restart + /// + /// # Returns + /// + /// * `Ok(())` - Container restart successfully initiated + /// * `Err(Box)` - If container not found or restart fails pub async fn restart_container( &self, container_id: &str, @@ -127,7 +195,16 @@ impl DockerManager { container::restart_container(&self.docker, container_id).await } - /// Collects Docker metrics for all containers + /// Collects comprehensive Docker metrics for all containers + /// + /// Gathers CPU usage, memory consumption, network I/O, and status information + /// for all containers. Matches statistics to containers using container ID prefixes. + /// Returns partial data even if some statistics collection fails. + /// + /// # Returns + /// + /// * `Ok(DockerMetricDto)` - Complete metrics data for all containers + /// * `Err(Box)` - If critical failures occur pub async fn collect_metrics(&self) -> Result> { let containers = self.get_containers().await?; @@ -238,7 +315,7 @@ impl DockerManager { let container_infos: Vec = container_infos_total .into_iter() .filter_map(|info| { - let _container = match info.container { + let container = match info.container { Some(c) => c, None => { eprintln!("Warning: Container info missing container data, skipping"); @@ -286,7 +363,7 @@ impl DockerManager { }; Some(DockerCollectMetricDto { - server_id: 0, + id: container.id, status: status_dto, cpu: cpu_dto, ram: ram_dto, @@ -303,6 +380,15 @@ impl DockerManager { Ok(dto) } + /// Creates registration DTO with container information + /// + /// Prepares container data for initial registration with the backend server. + /// This includes basic container information without detailed metrics. + /// + /// # Returns + /// + /// * `Ok(DockerServiceDto)` - Container information ready for registration + /// * `Err(Box)` - If container enumeration fails pub async fn create_registration_dto( &self, ) -> Result> { @@ -322,16 +408,33 @@ impl DockerManager { // Keep these as utility functions if needed, but they should use DockerManager internally impl DockerContainer { /// Returns the container ID + /// + /// # Returns + /// + /// * `&str` - Full container ID string pub fn id(&self) -> &str { &self.id } - /// Returns the image name + /// Returns the container image name + /// + /// Returns "unknown" if the image name is not available. + /// + /// # Returns + /// + /// * `&str` - Image name or "unknown" if not available pub fn image(&self) -> &str { &self.image.as_deref().unwrap_or("unknown") } /// Returns the container name + /// + /// Returns "unknown" if the container name is not available. + /// Container names typically start with '/' in Docker. + /// + /// # Returns + /// + /// * `&str` - Container name or "unknown" if not available pub fn name(&self) -> &str { &self.name.as_deref().unwrap_or("unknown") } diff --git a/WatcherAgent/src/docker/stats/status.rs b/WatcherAgent/src/docker/stats/status.rs index 846ddd0..17221d1 100644 --- a/WatcherAgent/src/docker/stats/status.rs +++ b/WatcherAgent/src/docker/stats/status.rs @@ -5,6 +5,22 @@ use bollard::query_parameters::{ListContainersOptions, InspectContainerOptions}; use bollard::models::{ContainerSummaryStateEnum, ContainerStateStatusEnum}; /// Get status information for all containers +/// +/// # Arguments +/// +/// * `docker` - Reference to Docker client +/// +/// # Returns +/// +/// * `Ok(Vec)` - Vector of container status information +/// * `Err(Box)` - If Docker API call fails +/// +/// # Behavior +/// +/// - Lists all containers (including stopped ones) +/// - Converts container state enum to string representation +/// - Converts timestamp from i64 to string +/// - Returns basic status info (finished_at is not available in list view) pub async fn get_all_containers_status( docker: &Docker, ) -> Result, Box> { @@ -52,7 +68,26 @@ pub async fn get_all_containers_status( Ok(status_infos) } + /// Get status information for a specific container +/// +/// # Arguments +/// +/// * `docker` - Reference to Docker client +/// * `container_id` - ID of the container to inspect +/// +/// # Returns +/// +/// * `Ok(Some(ContainerStatusInfo))` - Status info if container found +/// * `Ok(None)` - If container not found +/// * `Err(Box)` - If Docker API call fails +/// +/// # Behavior +/// +/// - First tries to find container in list (faster) +/// - Falls back to container inspect for detailed info +/// - Provides more detailed information including finished_at timestamp +/// - Handles container not found case gracefully pub async fn get_single_container_status( docker: &Docker, container_id: &str, diff --git a/WatcherAgent/src/models.rs b/WatcherAgent/src/models.rs index b178f8a..0c91811 100644 --- a/WatcherAgent/src/models.rs +++ b/WatcherAgent/src/models.rs @@ -225,7 +225,7 @@ pub struct DockerMetricDto { #[derive(Debug, Serialize, Clone)] pub struct DockerCollectMetricDto { - pub server_id: u16, + pub id: String, pub status: DockerContainerStatusDto, pub cpu: DockerContainerCpuDto, pub ram: DockerContainerRamDto,