mirror of
https://github.com/moghtech/komodo.git
synced 2026-09-11 16:01:27 +00:00
* stack destroy before deploy option * add timestamps. Fix log polling even when poll not selected * Add build [[$VERSION]] support. VERSION build arg default * fix clippy lint * initialize `first_builder` * run_komodo_command uses parse_multiline_command * comment UI for $VERSION and new command feature * bump some deps * support multiline commands in pre_deploy / pre_build
202 lines
4.9 KiB
Rust
202 lines
4.9 KiB
Rust
use anyhow::Context;
|
|
use command::run_komodo_command;
|
|
use formatting::format_serror;
|
|
use komodo_client::entities::{
|
|
deployment::{
|
|
conversions_from_str, extract_registry_domain, Conversion,
|
|
Deployment, DeploymentConfig, DeploymentImage, RestartMode,
|
|
},
|
|
environment_vars_from_str, to_komodo_name,
|
|
update::Log,
|
|
EnvironmentVar,
|
|
};
|
|
use periphery_client::api::container::{Deploy, RemoveContainer};
|
|
use resolver_api::Resolve;
|
|
|
|
use crate::{
|
|
config::periphery_config,
|
|
docker::{docker_login, pull_image},
|
|
helpers::{parse_extra_args, parse_labels},
|
|
State,
|
|
};
|
|
|
|
impl Resolve<Deploy> for State {
|
|
#[instrument(
|
|
name = "Deploy",
|
|
skip(self, core_replacers, registry_token)
|
|
)]
|
|
async fn resolve(
|
|
&self,
|
|
Deploy {
|
|
deployment,
|
|
stop_signal,
|
|
stop_time,
|
|
registry_token,
|
|
replacers: core_replacers,
|
|
}: Deploy,
|
|
_: (),
|
|
) -> anyhow::Result<Log> {
|
|
let image = if let DeploymentImage::Image { image } =
|
|
&deployment.config.image
|
|
{
|
|
if image.is_empty() {
|
|
return Ok(Log::error(
|
|
"get image",
|
|
String::from("deployment does not have image attached"),
|
|
));
|
|
}
|
|
image
|
|
} else {
|
|
return Ok(Log::error(
|
|
"get image",
|
|
String::from("deployment does not have image attached"),
|
|
));
|
|
};
|
|
|
|
if let Err(e) = docker_login(
|
|
&extract_registry_domain(image)?,
|
|
&deployment.config.image_registry_account,
|
|
registry_token.as_deref(),
|
|
)
|
|
.await
|
|
{
|
|
return Ok(Log::error(
|
|
"docker login",
|
|
format_serror(
|
|
&e.context("failed to login to docker registry").into(),
|
|
),
|
|
));
|
|
}
|
|
|
|
let _ = pull_image(image).await;
|
|
debug!("image pulled");
|
|
let _ = State
|
|
.resolve(
|
|
RemoveContainer {
|
|
name: deployment.name.clone(),
|
|
signal: stop_signal,
|
|
time: stop_time,
|
|
},
|
|
(),
|
|
)
|
|
.await;
|
|
debug!("container stopped and removed");
|
|
|
|
let command = docker_run_command(&deployment, image)
|
|
.context("Unable to generate valid docker run command")?;
|
|
debug!("docker run command: {command}");
|
|
|
|
if deployment.config.skip_secret_interp {
|
|
Ok(run_komodo_command("docker run", None, command).await)
|
|
} else {
|
|
let command = svi::interpolate_variables(
|
|
&command,
|
|
&periphery_config().secrets,
|
|
svi::Interpolator::DoubleBrackets,
|
|
true,
|
|
)
|
|
.context(
|
|
"failed to interpolate secrets into docker run command",
|
|
);
|
|
|
|
let (command, mut replacers) = match command {
|
|
Ok(res) => res,
|
|
Err(e) => {
|
|
return Ok(Log::error("docker run", format!("{e:?}")));
|
|
}
|
|
};
|
|
|
|
replacers.extend(core_replacers);
|
|
let mut log =
|
|
run_komodo_command("docker run", None, command).await;
|
|
log.command = svi::replace_in_string(&log.command, &replacers);
|
|
log.stdout = svi::replace_in_string(&log.stdout, &replacers);
|
|
log.stderr = svi::replace_in_string(&log.stderr, &replacers);
|
|
|
|
Ok(log)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn docker_run_command(
|
|
Deployment {
|
|
name,
|
|
config:
|
|
DeploymentConfig {
|
|
volumes,
|
|
ports,
|
|
network,
|
|
command,
|
|
restart,
|
|
environment,
|
|
labels,
|
|
extra_args,
|
|
..
|
|
},
|
|
..
|
|
}: &Deployment,
|
|
image: &str,
|
|
) -> anyhow::Result<String> {
|
|
let name = to_komodo_name(name);
|
|
let ports = parse_conversions(
|
|
&conversions_from_str(ports).context("Invalid ports")?,
|
|
"-p",
|
|
);
|
|
let volumes = parse_conversions(
|
|
&conversions_from_str(volumes).context("Invalid volumes")?,
|
|
"-v",
|
|
);
|
|
let network = parse_network(network);
|
|
let restart = parse_restart(restart);
|
|
let environment = parse_environment(
|
|
&environment_vars_from_str(environment)
|
|
.context("Invalid environment")?,
|
|
);
|
|
let labels = parse_labels(
|
|
&environment_vars_from_str(labels).context("Invalid labels")?,
|
|
);
|
|
let command = parse_command(command);
|
|
let extra_args = parse_extra_args(extra_args);
|
|
let command = format!("docker run -d --name {name}{ports}{volumes}{network}{restart}{environment}{labels}{extra_args} {image}{command}");
|
|
Ok(command)
|
|
}
|
|
|
|
fn parse_conversions(
|
|
conversions: &[Conversion],
|
|
flag: &str,
|
|
) -> String {
|
|
conversions
|
|
.iter()
|
|
.map(|p| format!(" {flag} {}:{}", p.local, p.container))
|
|
.collect::<Vec<_>>()
|
|
.join("")
|
|
}
|
|
|
|
fn parse_environment(environment: &[EnvironmentVar]) -> String {
|
|
environment
|
|
.iter()
|
|
.map(|p| format!(" --env {}=\"{}\"", p.variable, p.value))
|
|
.collect::<Vec<_>>()
|
|
.join("")
|
|
}
|
|
|
|
fn parse_network(network: &str) -> String {
|
|
format!(" --network {network}")
|
|
}
|
|
|
|
fn parse_restart(restart: &RestartMode) -> String {
|
|
let restart = match restart {
|
|
RestartMode::OnFailure => "on-failure:10".to_string(),
|
|
_ => restart.to_string(),
|
|
};
|
|
format!(" --restart {restart}")
|
|
}
|
|
|
|
fn parse_command(command: &str) -> String {
|
|
if command.is_empty() {
|
|
String::new()
|
|
} else {
|
|
format!(" {command}")
|
|
}
|
|
}
|