added docker metrics
All checks were successful
Rust Cross-Platform Build / Detect Rust Project (push) Successful in 4s
Rust Cross-Platform Build / Run Tests (push) Successful in 1m3s
Rust Cross-Platform Build / Build (x86_64-unknown-linux-gnu) (push) Successful in 2m56s
Rust Cross-Platform Build / Build (x86_64-pc-windows-gnu) (push) Successful in 3m37s
Rust Cross-Platform Build / Set Tag Name (push) Successful in 5s
Rust Cross-Platform Build / Build and Push Docker Image (push) Successful in 2m12s
Rust Cross-Platform Build / Workflow Summary (push) Successful in 2s
Rust Cross-Platform Build / Create Tag (push) Successful in 5s
All checks were successful
Rust Cross-Platform Build / Detect Rust Project (push) Successful in 4s
Rust Cross-Platform Build / Run Tests (push) Successful in 1m3s
Rust Cross-Platform Build / Build (x86_64-unknown-linux-gnu) (push) Successful in 2m56s
Rust Cross-Platform Build / Build (x86_64-pc-windows-gnu) (push) Successful in 3m37s
Rust Cross-Platform Build / Set Tag Name (push) Successful in 5s
Rust Cross-Platform Build / Build and Push Docker Image (push) Successful in 2m12s
Rust Cross-Platform Build / Workflow Summary (push) Successful in 2s
Rust Cross-Platform Build / Create Tag (push) Successful in 5s
This commit is contained in:
@@ -15,7 +15,7 @@ use std::time::Duration;
|
|||||||
use crate::docker::serverclientcomm::handle_server_message;
|
use crate::docker::serverclientcomm::handle_server_message;
|
||||||
use crate::hardware::HardwareInfo;
|
use crate::hardware::HardwareInfo;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
Acknowledgment, HeartbeatDto, IdResponse, MetricDto, RegistrationDto, ServerMessage,
|
Acknowledgment, HeartbeatDto, IdResponse, MetricDto, RegistrationDto, ServerMessage, DockerMetricDto
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@@ -39,7 +39,7 @@ use bollard::Docker;
|
|||||||
/// Returns an error if unable to register after repeated attempts.
|
/// Returns an error if unable to register after repeated attempts.
|
||||||
pub async fn register_with_server(
|
pub async fn register_with_server(
|
||||||
base_url: &str,
|
base_url: &str,
|
||||||
) -> Result<(i32, String), Box<dyn Error + Send + Sync>> {
|
) -> Result<(u16, String), Box<dyn Error + Send + Sync>> {
|
||||||
// First get local IP
|
// First get local IP
|
||||||
let ip = local_ip_address::local_ip()?.to_string();
|
let ip = local_ip_address::local_ip()?.to_string();
|
||||||
println!("Local IP address detected: {}", ip);
|
println!("Local IP address detected: {}", ip);
|
||||||
@@ -103,7 +103,7 @@ pub async fn register_with_server(
|
|||||||
async fn get_server_id_by_ip(
|
async fn get_server_id_by_ip(
|
||||||
base_url: &str,
|
base_url: &str,
|
||||||
ip: &str,
|
ip: &str,
|
||||||
) -> Result<(i32, String), Box<dyn Error + Send + Sync>> {
|
) -> Result<(u16, String), Box<dyn Error + Send + Sync>> {
|
||||||
let client = Client::builder()
|
let client = Client::builder()
|
||||||
.danger_accept_invalid_certs(true)
|
.danger_accept_invalid_certs(true)
|
||||||
.build()?;
|
.build()?;
|
||||||
@@ -342,19 +342,19 @@ pub async fn send_acknowledgment(
|
|||||||
|
|
||||||
pub async fn send_docker_metrics(
|
pub async fn send_docker_metrics(
|
||||||
base_url: &str,
|
base_url: &str,
|
||||||
docker_metrics: &MetricDto,
|
docker_metrics: &DockerMetricDto,
|
||||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
let url = format!("{}/monitoring/docker-metric", base_url);
|
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 {
|
match client.post(&url).json(&docker_metrics).send().await {
|
||||||
Ok(res) => println!(
|
Ok(res) => println!(
|
||||||
"✅ Sent metrics for server {} | Status: {}",
|
"✅ Sent docker metrics for server {} | Status: {}",
|
||||||
docker_metrics.server_id,
|
docker_metrics.server_id,
|
||||||
res.status()
|
res.status()
|
||||||
),
|
),
|
||||||
Err(err) => eprintln!("❌ Failed to send metrics: {}", err),
|
Err(err) => eprintln!("❌ Failed to send docker metrics: {}", err),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@@ -11,7 +11,7 @@ pub mod container;
|
|||||||
pub mod serverclientcomm;
|
pub mod serverclientcomm;
|
||||||
pub mod stats;
|
pub mod stats;
|
||||||
|
|
||||||
use crate::models::{DockerRegistrationDto, DockerMetricDto, DockerContainer};
|
use crate::models::{DockerRegistrationDto, DockerMetricDto, DockerContainer, DockerContainerInfo};
|
||||||
use bollard::{query_parameters::InspectContainerOptions, Docker};
|
use bollard::{query_parameters::InspectContainerOptions, Docker};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ impl DockerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets all available containers as DTOs for registration
|
/// Gets all available containers as DTOs for registration
|
||||||
pub async fn get_containers_for_registration(
|
pub async fn get_containers(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Vec<DockerContainer>, Box<dyn Error + Send + Sync>> {
|
) -> Result<Vec<DockerContainer>, Box<dyn Error + Send + Sync>> {
|
||||||
let containers = container::get_available_containers(&self.docker).await;
|
let containers = container::get_available_containers(&self.docker).await;
|
||||||
@@ -103,8 +103,6 @@ impl DockerManager {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Gets the number of running containers
|
/// Gets the number of running containers
|
||||||
pub async fn get_container_count(&self) -> Result<usize, Box<dyn Error + Send + Sync>> {
|
pub async fn get_container_count(&self) -> Result<usize, Box<dyn Error + Send + Sync>> {
|
||||||
let containers = container::get_available_containers(&self.docker).await;
|
let containers = container::get_available_containers(&self.docker).await;
|
||||||
@@ -118,6 +116,47 @@ impl DockerManager {
|
|||||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
container::restart_container(&self.docker, container_id).await
|
container::restart_container(&self.docker, container_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collects Docker metrics for all containers
|
||||||
|
pub async fn collect_metrics(
|
||||||
|
&self,
|
||||||
|
) -> Result<DockerMetricDto, Box<dyn Error + Send + Sync>> {
|
||||||
|
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
|
// Keep these as utility functions if needed, but they should use DockerManager internally
|
||||||
|
@@ -34,6 +34,7 @@ pub mod models;
|
|||||||
use bollard::Docker;
|
use bollard::Docker;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::sync::Arc;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
/// Awaits a spawned asynchronous task and flattens its nested `Result` type.
|
/// Awaits a spawned asynchronous task and flattens its nested `Result` type.
|
||||||
@@ -113,7 +114,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|||||||
|
|
||||||
// Start background tasks
|
// Start background tasks
|
||||||
// Start server listening for commands (only if Docker is available)
|
// 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({
|
tokio::spawn({
|
||||||
let docker = docker_manager.docker.clone();
|
let docker = docker_manager.docker.clone();
|
||||||
let server_url = server_url.to_string();
|
let server_url = server_url.to_string();
|
||||||
@@ -136,8 +137,9 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|||||||
let metrics_handle = tokio::spawn({
|
let metrics_handle = tokio::spawn({
|
||||||
let ip = ip.clone();
|
let ip = ip.clone();
|
||||||
let server_url = server_url.to_string();
|
let server_url = server_url.to_string();
|
||||||
|
let docker_manager = docker_manager.as_ref().cloned().unwrap();
|
||||||
async move {
|
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
|
collector.run(&server_url).await
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -10,13 +10,15 @@
|
|||||||
/// ## Usage
|
/// ## Usage
|
||||||
/// The [`Collector`] struct is instantiated in the main loop and runs as a background task, continuously collecting and reporting metrics.
|
/// 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::error::Error;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::api;
|
use crate::{api, docker};
|
||||||
|
use crate::docker::DockerManager;
|
||||||
//use crate::docker::DockerInfo;
|
//use crate::docker::DockerInfo;
|
||||||
use crate::hardware::network::NetworkMonitor;
|
use crate::hardware::network::NetworkMonitor;
|
||||||
use crate::hardware::HardwareInfo;
|
use crate::hardware::HardwareInfo;
|
||||||
use crate::models::MetricDto;
|
use crate::models::{DockerMetricDto, MetricDto};
|
||||||
|
|
||||||
/// Main orchestrator for hardware and network metric collection and reporting.
|
/// 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.
|
/// - `server_id`: Unique server ID assigned by the backend.
|
||||||
/// - `ip_address`: IP address of the agent.
|
/// - `ip_address`: IP address of the agent.
|
||||||
pub struct Collector {
|
pub struct Collector {
|
||||||
|
docker_manager: DockerManager,
|
||||||
network_monitor: NetworkMonitor,
|
network_monitor: NetworkMonitor,
|
||||||
server_id: i32,
|
server_id: u16,
|
||||||
ip_address: String,
|
ip_address: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,8 +44,9 @@ impl Collector {
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// A new `Collector` ready to collect and report metrics.
|
/// 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 {
|
Self {
|
||||||
|
docker_manager,
|
||||||
network_monitor: NetworkMonitor::new(),
|
network_monitor: NetworkMonitor::new(),
|
||||||
server_id,
|
server_id,
|
||||||
ip_address,
|
ip_address,
|
||||||
@@ -72,7 +76,16 @@ impl Collector {
|
|||||||
continue;
|
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_metrics(base_url, &metrics).await?;
|
||||||
|
api::send_docker_metrics(base_url, &docker_metrics).await?;
|
||||||
tokio::time::sleep(Duration::from_secs(20)).await;
|
tokio::time::sleep(Duration::from_secs(20)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,58 +126,16 @@ impl Collector {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets container metrics for all containers
|
/// NOTE: This is a compilation-safe stub. Implement the Docker collection using your
|
||||||
pub async fn docker_collect(
|
/// DockerManager API and container helpers when available.
|
||||||
&self,
|
pub async fn docker_collect(&self) -> Result<DockerMetricDto, Box<dyn Error + Send + Sync>> {
|
||||||
) -> Result<Vec<DockerContainer>, Box<dyn Error + Send + Sync>> {
|
let metrics = self
|
||||||
let containers = container::get_available_containers(&self.docker).await;
|
.docker_manager
|
||||||
let mut metrics = Vec::new();
|
.collect_metrics()
|
||||||
|
.await?;
|
||||||
for container in containers {
|
Ok(DockerMetricDto {
|
||||||
// Get network stats (you'll need to implement this in container.rs)
|
server_id: self.server_id,
|
||||||
let network_stats = container::get_network_stats(&self.docker, &container.id).await?;
|
containers: metrics.containers,
|
||||||
// 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::<InspectContainerOptions>)
|
|
||||||
.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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
pub struct RegistrationDto {
|
pub struct RegistrationDto {
|
||||||
#[serde(rename = "id")]
|
#[serde(rename = "id")]
|
||||||
pub server_id: i32,
|
pub server_id: u16,
|
||||||
#[serde(rename = "ipAddress")]
|
#[serde(rename = "ipAddress")]
|
||||||
pub ip_address: String,
|
pub ip_address: String,
|
||||||
#[serde(rename = "cpuType")]
|
#[serde(rename = "cpuType")]
|
||||||
@@ -59,7 +59,7 @@ pub struct RegistrationDto {
|
|||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
pub struct MetricDto {
|
pub struct MetricDto {
|
||||||
#[serde(rename = "serverId")]
|
#[serde(rename = "serverId")]
|
||||||
pub server_id: i32,
|
pub server_id: u16,
|
||||||
#[serde(rename = "ipAddress")]
|
#[serde(rename = "ipAddress")]
|
||||||
pub ip_address: String,
|
pub ip_address: String,
|
||||||
#[serde(rename = "cpu_Load")]
|
#[serde(rename = "cpu_Load")]
|
||||||
@@ -116,7 +116,7 @@ pub struct DiskInfoDetailed {
|
|||||||
/// - `ip_address`: IPv4 or IPv6 address (string)
|
/// - `ip_address`: IPv4 or IPv6 address (string)
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct IdResponse {
|
pub struct IdResponse {
|
||||||
pub id: i32,
|
pub id: u16,
|
||||||
#[serde(rename = "ipAddress")]
|
#[serde(rename = "ipAddress")]
|
||||||
pub ip_address: String,
|
pub ip_address: String,
|
||||||
}
|
}
|
||||||
@@ -188,7 +188,7 @@ pub struct Acknowledgment {
|
|||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
pub struct DockerRegistrationDto {
|
pub struct DockerRegistrationDto {
|
||||||
/// Unique server identifier (integer)
|
/// Unique server identifier (integer)
|
||||||
pub server_id: u32,
|
pub server_id: u16,
|
||||||
/// json stringified array of DockerContainer
|
/// json stringified array of DockerContainer
|
||||||
///
|
///
|
||||||
/// ## Json Example
|
/// ## Json Example
|
||||||
@@ -198,12 +198,12 @@ pub struct DockerRegistrationDto {
|
|||||||
/// id: unique container ID (first 12 hex digits)
|
/// id: unique container ID (first 12 hex digits)
|
||||||
/// image: docker image name
|
/// image: docker image name
|
||||||
/// name: container name
|
/// name: container name
|
||||||
pub containers: String,
|
pub containers: String // Vec<DockerContainer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
pub struct DockerMetricDto {
|
pub struct DockerMetricDto {
|
||||||
pub server_id: String,
|
pub server_id: u16,
|
||||||
/// json stringified array of DockerContainer
|
/// json stringified array of DockerContainer
|
||||||
///
|
///
|
||||||
/// ## Json Example
|
/// ## Json Example
|
||||||
@@ -217,7 +217,7 @@ pub struct DockerMetricDto {
|
|||||||
/// network: network stats
|
/// network: network stats
|
||||||
/// cpu: cpu stats
|
/// cpu: cpu stats
|
||||||
/// ram: ram stats
|
/// ram: ram stats
|
||||||
pub containers: String,
|
pub containers: String // Vec<DockerContainerInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
|
Reference in New Issue
Block a user