mirror of
https://github.com/moghtech/komodo.git
synced 2026-10-28 16:00:38 +00:00
123 lines
3.1 KiB
Rust
123 lines
3.1 KiB
Rust
use std::sync::{Arc, OnceLock};
|
|
|
|
use anyhow::{Context, anyhow};
|
|
use arc_swap::ArcSwap;
|
|
use bollard::Docker;
|
|
use command::run_komodo_command;
|
|
use komodo_client::entities::{TerminationSignal, update::Log};
|
|
use run_command::async_run_command;
|
|
|
|
pub mod stats;
|
|
|
|
mod containers;
|
|
mod images;
|
|
mod networks;
|
|
mod volumes;
|
|
|
|
pub fn docker_client() -> &'static SwappableDockerClient {
|
|
static DOCKER_CLIENT: OnceLock<SwappableDockerClient> =
|
|
OnceLock::new();
|
|
DOCKER_CLIENT.get_or_init(SwappableDockerClient::init)
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct SwappableDockerClient(ArcSwap<Option<DockerClient>>);
|
|
|
|
impl SwappableDockerClient {
|
|
pub fn init() -> Self {
|
|
let docker = Docker::connect_with_defaults()
|
|
.context("Failed to connect to docker api. Docker monitoring won't work and will return empty results.")
|
|
// Only logs on first init, although keeps trying to connect
|
|
.inspect_err(|e| warn!("{e:#}"))
|
|
.map(|docker| DockerClient { docker })
|
|
.ok();
|
|
Self(ArcSwap::new(Arc::new(docker)))
|
|
}
|
|
|
|
pub fn load(&self) -> arc_swap::Guard<Arc<Option<DockerClient>>> {
|
|
let res = self.0.load();
|
|
if res.is_some() {
|
|
return res;
|
|
}
|
|
self.reload();
|
|
self.0.load()
|
|
}
|
|
|
|
pub fn reload(&self) {
|
|
let docker = Docker::connect_with_defaults()
|
|
.map(|docker| DockerClient { docker })
|
|
.ok();
|
|
self.0.store(Arc::new(docker));
|
|
}
|
|
}
|
|
|
|
pub struct DockerClient {
|
|
docker: Docker,
|
|
}
|
|
|
|
impl Default for DockerClient {
|
|
fn default() -> DockerClient {
|
|
DockerClient {
|
|
docker: Docker::connect_with_defaults()
|
|
.expect("failed to connect to docker daemon"),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns whether build result should be pushed after build
|
|
#[instrument(skip(registry_token))]
|
|
pub async fn docker_login(
|
|
domain: &str,
|
|
account: &str,
|
|
// For local token override from core.
|
|
registry_token: Option<&str>,
|
|
) -> anyhow::Result<bool> {
|
|
if domain.is_empty() || account.is_empty() {
|
|
return Ok(false);
|
|
}
|
|
let registry_token = match registry_token {
|
|
Some(token) => token,
|
|
None => crate::helpers::registry_token(domain, account)?,
|
|
};
|
|
let log = async_run_command(&format!(
|
|
"echo {registry_token} | docker login {domain} --username '{account}' --password-stdin",
|
|
))
|
|
.await;
|
|
if log.success() {
|
|
Ok(true)
|
|
} else {
|
|
let mut e = anyhow!("End of trace");
|
|
for line in
|
|
log.stderr.split('\n').filter(|line| !line.is_empty()).rev()
|
|
{
|
|
e = e.context(line.to_string());
|
|
}
|
|
for line in
|
|
log.stdout.split('\n').filter(|line| !line.is_empty()).rev()
|
|
{
|
|
e = e.context(line.to_string());
|
|
}
|
|
Err(e.context(format!("Registry {domain} login error")))
|
|
}
|
|
}
|
|
|
|
#[instrument]
|
|
pub async fn pull_image(image: &str) -> Log {
|
|
let command = format!("docker pull {image}");
|
|
run_komodo_command("Docker Pull", None, command).await
|
|
}
|
|
|
|
pub fn stop_container_command(
|
|
container_name: &str,
|
|
signal: Option<TerminationSignal>,
|
|
time: Option<i32>,
|
|
) -> String {
|
|
let signal = signal
|
|
.map(|signal| format!(" --signal {signal}"))
|
|
.unwrap_or_default();
|
|
let time = time
|
|
.map(|time| format!(" --time {time}"))
|
|
.unwrap_or_default();
|
|
format!("docker stop{signal}{time} {container_name}")
|
|
}
|