added docker management
All checks were successful
Rust Cross-Platform Build / Detect Rust Project (push) Successful in 4s
Rust Cross-Platform Build / Set Tag Name (push) Successful in 4s
Rust Cross-Platform Build / Run Tests (push) Successful in 1m2s
Rust Cross-Platform Build / Build (x86_64-unknown-linux-gnu) (push) Successful in 2m18s
Rust Cross-Platform Build / Build (x86_64-pc-windows-gnu) (push) Successful in 3m25s
Rust Cross-Platform Build / Build and Push Docker Image (push) Successful in 2m0s
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 / Set Tag Name (push) Successful in 4s
Rust Cross-Platform Build / Run Tests (push) Successful in 1m2s
Rust Cross-Platform Build / Build (x86_64-unknown-linux-gnu) (push) Successful in 2m18s
Rust Cross-Platform Build / Build (x86_64-pc-windows-gnu) (push) Successful in 3m25s
Rust Cross-Platform Build / Build and Push Docker Image (push) Successful in 2m0s
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:
@@ -1,15 +1,17 @@
|
||||
|
||||
//! Docker container utilities for WatcherAgent
|
||||
//!
|
||||
//! Provides functions to list and process Docker containers using the Bollard library.
|
||||
//!
|
||||
use crate::models::DockerContainer;
|
||||
use crate::docker::stats;
|
||||
use crate::docker::stats::{ContainerCpuInfo, ContainerNetworkInfo};
|
||||
use crate::models::{DockerContainerDto, DockerContainerRegistrationDto};
|
||||
|
||||
use bollard::query_parameters::{ListContainersOptions};
|
||||
use bollard::query_parameters::{
|
||||
CreateImageOptions, ListContainersOptions, RestartContainerOptions,
|
||||
};
|
||||
use bollard::Docker;
|
||||
|
||||
|
||||
|
||||
use futures_util::StreamExt;
|
||||
use std::error::Error;
|
||||
|
||||
/// Returns a list of available Docker containers.
|
||||
///
|
||||
@@ -18,54 +20,60 @@ use bollard::Docker;
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Vec<DockerContainer>` - Vector of Docker container info.
|
||||
pub async fn get_available_container(docker: &Docker) -> Vec<DockerContainer> {
|
||||
pub async fn get_available_containers(docker: &Docker) -> Vec<DockerContainerDto> {
|
||||
println!("=== DOCKER CONTAINER LIST ===");
|
||||
|
||||
|
||||
let options = Some(ListContainersOptions {
|
||||
all: true,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
|
||||
let containers_list = match docker.list_containers(options).await {
|
||||
Ok(containers) => {
|
||||
println!("Available containers ({}):", containers.len());
|
||||
containers.into_iter()
|
||||
containers
|
||||
.into_iter()
|
||||
.filter_map(|container| {
|
||||
container.id.as_ref()?; // Skip if no ID
|
||||
|
||||
|
||||
let id = container.id?;
|
||||
let short_id = if id.len() > 12 { &id[..12] } else { &id };
|
||||
//let short_id: u32 = short_string_id.trim().parse().unwrap();
|
||||
|
||||
let name = container.names
|
||||
let name = container
|
||||
.names
|
||||
.and_then(|names| names.into_iter().next())
|
||||
.map(|name| name.trim_start_matches('/').to_string())
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
|
||||
let image = container.image
|
||||
|
||||
let image = container
|
||||
.image
|
||||
.as_ref()
|
||||
.map(|img| img.to_string())
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
|
||||
let status = container.status
|
||||
.as_ref()
|
||||
.map(|s| match s.to_lowercase().as_str() {
|
||||
s if s.contains("up") || s.contains("running") => "running".to_string(),
|
||||
s if s.contains("exited") || s.contains("stopped") => "stopped".to_string(),
|
||||
_ => s.to_string(),
|
||||
})
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
|
||||
println!(" - ID: {}, Image: {}, Name: {}", short_id, container.image.unwrap(), name);
|
||||
|
||||
Some(DockerContainer {
|
||||
ID: short_id.to_string(),
|
||||
|
||||
/*let status = container
|
||||
.status
|
||||
.as_ref()
|
||||
.map(|s| match s.to_lowercase().as_str() {
|
||||
s if s.contains("up") || s.contains("running") => "running".to_string(),
|
||||
s if s.contains("exited") || s.contains("stopped") => {
|
||||
"stopped".to_string()
|
||||
}
|
||||
_ => s.to_string(),
|
||||
})
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
|
||||
println!(
|
||||
" - ID: {}, Image: {}, Name: {}",
|
||||
short_id,
|
||||
container.image.unwrap(),
|
||||
name
|
||||
);*/
|
||||
|
||||
Some(DockerContainerDto {
|
||||
id: short_id.to_string(),
|
||||
image,
|
||||
Name: name,
|
||||
Status: status,
|
||||
_net_in: 0.0,
|
||||
_net_out: 0.0,
|
||||
_cpu_load: 0.0,
|
||||
name: name,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@@ -75,10 +83,96 @@ pub async fn get_available_container(docker: &Docker) -> Vec<DockerContainer> {
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
containers_list
|
||||
}
|
||||
|
||||
/// Pulls a new Docker image and restarts the current container.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `docker` - Reference to a Bollard Docker client.
|
||||
/// * `image` - The name of the Docker image to pull.
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Result<(), Box<dyn Error + Send + Sync>>` - Ok if updated successfully, error otherwise.
|
||||
pub async fn update_docker_image(
|
||||
docker: &Docker,
|
||||
image: &str,
|
||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
println!("Updating to {}", image);
|
||||
|
||||
// 1. Pull new image
|
||||
let mut stream = docker.create_image(
|
||||
Some(CreateImageOptions {
|
||||
from_image: Some(image.to_string()),
|
||||
..Default::default()
|
||||
}),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
// Use the stream with proper trait bounds
|
||||
while let Some(result) = StreamExt::next(&mut stream).await {
|
||||
match result {
|
||||
Ok(progress) => {
|
||||
if let Some(status) = progress.status {
|
||||
println!("Pull status: {}", status);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error pulling image: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Restart the current container
|
||||
let options = Some(ListContainersOptions {
|
||||
all: true,
|
||||
..Default::default()
|
||||
});
|
||||
let container_id = docker
|
||||
.list_containers(options)
|
||||
.await?
|
||||
.into_iter()
|
||||
.find_map(|c| {
|
||||
c.image
|
||||
.as_ref()
|
||||
.and_then(|img| if img == image { c.id } else { None })
|
||||
});
|
||||
let _ = restart_container(docker, &container_id.unwrap()).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Restarts the agent's own Docker container.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `docker` - Reference to a Bollard Docker client.
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Result<(), Box<dyn Error + Send + Sync>>` - Ok if restarted successfully, error otherwise.
|
||||
pub async fn restart_container(
|
||||
docker: &Docker,
|
||||
container_id: &str,
|
||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
println!("Restarting container {}", container_id);
|
||||
if let Err(e) = docker
|
||||
.restart_container(
|
||||
&container_id.to_string(),
|
||||
Some(RestartContainerOptions {
|
||||
signal: None,
|
||||
t: Some(0),
|
||||
}),
|
||||
)
|
||||
.await
|
||||
{
|
||||
eprintln!("Failed to restart container: {}", e);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
/// Extracts a Docker container ID from a string line.
|
||||
///
|
||||
@@ -90,4 +184,48 @@ pub async fn get_available_container(docker: &Docker) -> Vec<DockerContainer> {
|
||||
pub fn extract_client_container_id(line: &str) -> Option<String> {
|
||||
// ...existing code...
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
/// Gets network statistics for a specific container
|
||||
pub async fn get_network_stats(
|
||||
docker: &Docker,
|
||||
container_id: &str,
|
||||
) -> Result<ContainerNetworkInfo, Box<dyn Error + Send + Sync>> {
|
||||
let (_, net_info) = stats::get_single_container_stats(docker, container_id).await?;
|
||||
|
||||
if let Some(net_info) = net_info {
|
||||
Ok(net_info)
|
||||
} else {
|
||||
// Return default network info if not found
|
||||
Ok(ContainerNetworkInfo {
|
||||
container_id: container_id.to_string(),
|
||||
rx_bytes: 0,
|
||||
tx_bytes: 0,
|
||||
rx_packets: 0,
|
||||
tx_packets: 0,
|
||||
rx_errors: 0,
|
||||
tx_errors: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets CPU statistics for a specific container
|
||||
pub async fn get_cpu_stats(
|
||||
docker: &Docker,
|
||||
container_id: &str,
|
||||
) -> Result<ContainerCpuInfo, Box<dyn Error + Send + Sync>> {
|
||||
let (cpu_info, _) = stats::get_single_container_stats(docker, container_id).await?;
|
||||
|
||||
if let Some(cpu_info) = cpu_info {
|
||||
Ok(cpu_info)
|
||||
} else {
|
||||
// Return default CPU info if not found
|
||||
Ok(ContainerCpuInfo {
|
||||
container_id: container_id.to_string(),
|
||||
cpu_usage_percent: 0.0,
|
||||
system_cpu_usage: 0,
|
||||
container_cpu_usage: 0,
|
||||
online_cpus: 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user