137 lines
4.0 KiB
Rust
137 lines
4.0 KiB
Rust
use crate::http::error::Result;
|
|
use bollard::{
|
|
container::{
|
|
InspectContainerOptions, KillContainerOptions, RemoveContainerOptions,
|
|
RestartContainerOptions, StartContainerOptions, StopContainerOptions,
|
|
},
|
|
service::{ContainerInspectResponse, ContainerSummary, MountPoint},
|
|
Docker,
|
|
};
|
|
use serde::Serialize;
|
|
use std::{collections::HashMap, path::Path};
|
|
use time::OffsetDateTime;
|
|
|
|
#[derive(Serialize)]
|
|
pub struct ContainerInfo {
|
|
pub id: String,
|
|
pub name: String,
|
|
pub state: String,
|
|
pub image: String,
|
|
pub image_id: String,
|
|
pub created_at: String,
|
|
pub volumes: Option<Vec<MountPoint>>,
|
|
pub env: Option<Vec<String>>,
|
|
pub labels: Option<HashMap<String, String>>,
|
|
}
|
|
|
|
impl ContainerInfo {
|
|
pub fn stack(&self) -> Option<String> {
|
|
self.labels
|
|
.clone()
|
|
.and_then(|lab| lab.get("com.docker.compose.project").cloned())
|
|
}
|
|
|
|
pub fn stack_folder(&self) -> Option<String> {
|
|
self.labels
|
|
.clone()
|
|
.and_then(|lab| lab.get("com.docker.compose.project.working_dir").cloned())
|
|
.and_then(|workdir| {
|
|
Path::new(&workdir)
|
|
.components()
|
|
.last()
|
|
.and_then(|part| part.as_os_str().to_str())
|
|
.map(|s| s.to_string())
|
|
})
|
|
}
|
|
|
|
pub fn running(&self) -> bool {
|
|
self.state == "running"
|
|
}
|
|
}
|
|
|
|
impl From<ContainerSummary> for ContainerInfo {
|
|
fn from(value: ContainerSummary) -> Self {
|
|
let created = OffsetDateTime::from_unix_timestamp(value.created.unwrap())
|
|
.unwrap_or(OffsetDateTime::UNIX_EPOCH);
|
|
ContainerInfo {
|
|
id: value.id.unwrap_or_default(),
|
|
name: value.names.unwrap_or_default()[0]
|
|
.trim_start_matches('/')
|
|
.to_string(),
|
|
state: value.state.unwrap_or_default(),
|
|
image: value.image.unwrap_or_default(),
|
|
image_id: value.image_id.unwrap_or_default(),
|
|
created_at: created.time().to_string(),
|
|
volumes: value.mounts,
|
|
labels: value.labels,
|
|
env: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<ContainerInspectResponse> for ContainerInfo {
|
|
fn from(value: ContainerInspectResponse) -> Self {
|
|
let config = value.config.unwrap_or_default();
|
|
ContainerInfo {
|
|
id: value.id.unwrap_or_default(),
|
|
name: value.name.unwrap_or_default(),
|
|
state: value
|
|
.state
|
|
.and_then(|s| s.status)
|
|
.unwrap_or(bollard::service::ContainerStateStatusEnum::EMPTY)
|
|
.to_string(),
|
|
image: config.image.unwrap_or_default(),
|
|
image_id: value.image.unwrap_or_default(),
|
|
created_at: value.created.unwrap_or_default(),
|
|
volumes: value.mounts,
|
|
labels: config.labels,
|
|
env: config.env,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn get_info(docker: &Docker, name: &str) -> Result<ContainerInfo> {
|
|
let info = docker
|
|
.inspect_container(name, Some(InspectContainerOptions { size: true }))
|
|
.await?;
|
|
|
|
Ok(info.into())
|
|
}
|
|
|
|
pub async fn start(docker: &Docker, name: &str) -> Result<()> {
|
|
Ok(docker
|
|
.start_container(name, None::<StartContainerOptions<String>>)
|
|
.await?)
|
|
}
|
|
|
|
pub async fn restart(docker: &Docker, name: &str) -> Result<()> {
|
|
Ok(docker
|
|
.restart_container(name, Some(RestartContainerOptions { t: 30 }))
|
|
.await?)
|
|
}
|
|
|
|
pub async fn stop(docker: &Docker, name: &str) -> Result<()> {
|
|
Ok(docker
|
|
.stop_container(name, Some(StopContainerOptions { t: 30 }))
|
|
.await?)
|
|
}
|
|
|
|
pub async fn kill(docker: &Docker, name: &str) -> Result<()> {
|
|
Ok(docker
|
|
.kill_container(name, None::<KillContainerOptions<String>>)
|
|
.await?)
|
|
}
|
|
|
|
pub async fn remove(docker: &Docker, name: &str) -> Result<()> {
|
|
Ok(docker
|
|
.remove_container(
|
|
name,
|
|
Some(RemoveContainerOptions {
|
|
v: false,
|
|
force: true,
|
|
link: false,
|
|
}),
|
|
)
|
|
.await?)
|
|
}
|