mirror of
https://github.com/moghtech/komodo.git
synced 2025-12-05 19:17:36 -06:00
docker service create
This commit is contained in:
@@ -225,7 +225,7 @@ impl Resolve<ExecuteArgs> for Deploy {
|
||||
|
||||
match periphery_client(&server)
|
||||
.await?
|
||||
.request(api::container::Deploy {
|
||||
.request(api::container::RunContainer {
|
||||
deployment,
|
||||
stop_signal: self.stop_signal,
|
||||
stop_time: self.stop_time,
|
||||
|
||||
@@ -20,7 +20,7 @@ use komodo_client::{
|
||||
user::User,
|
||||
},
|
||||
};
|
||||
use periphery_client::api::compose::*;
|
||||
use periphery_client::api::{DeployStackResponse, compose::*};
|
||||
use resolver_api::Resolve;
|
||||
use uuid::Uuid;
|
||||
|
||||
@@ -165,14 +165,14 @@ impl Resolve<ExecuteArgs> for DeployStack {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let ComposeUpResponse {
|
||||
let DeployStackResponse {
|
||||
logs,
|
||||
deployed,
|
||||
services,
|
||||
file_contents,
|
||||
missing_files,
|
||||
remote_errors,
|
||||
compose_config,
|
||||
merged_config,
|
||||
commit_hash,
|
||||
commit_message,
|
||||
} = periphery_client(&server)
|
||||
@@ -219,7 +219,7 @@ impl Resolve<ExecuteArgs> for DeployStack {
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
compose_config,
|
||||
merged_config,
|
||||
commit_hash.clone(),
|
||||
commit_message.clone(),
|
||||
)
|
||||
|
||||
@@ -35,10 +35,10 @@ use crate::{
|
||||
mod helpers;
|
||||
use helpers::*;
|
||||
|
||||
impl Resolve<super::Args> for GetDockerfileContentsOnHost {
|
||||
impl Resolve<crate::api::Args> for GetDockerfileContentsOnHost {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<GetDockerfileContentsOnHostResponse> {
|
||||
let GetDockerfileContentsOnHost {
|
||||
name,
|
||||
@@ -75,7 +75,7 @@ impl Resolve<super::Args> for GetDockerfileContentsOnHost {
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for WriteDockerfileContentsToHost {
|
||||
impl Resolve<crate::api::Args> for WriteDockerfileContentsToHost {
|
||||
#[instrument(
|
||||
"WriteDockerfileContentsToHost",
|
||||
skip_all,
|
||||
@@ -87,7 +87,10 @@ impl Resolve<super::Args> for WriteDockerfileContentsToHost {
|
||||
dockerfile_path = &self.dockerfile_path,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let WriteDockerfileContentsToHost {
|
||||
name,
|
||||
build_path,
|
||||
@@ -123,7 +126,7 @@ impl Resolve<super::Args> for WriteDockerfileContentsToHost {
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for build::Build {
|
||||
impl Resolve<crate::api::Args> for build::Build {
|
||||
#[instrument(
|
||||
"Build",
|
||||
skip_all,
|
||||
@@ -136,7 +139,7 @@ impl Resolve<super::Args> for build::Build {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<Log>> {
|
||||
let build::Build {
|
||||
mut build,
|
||||
@@ -339,7 +342,7 @@ impl Resolve<super::Args> for build::Build {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PruneBuilders {
|
||||
impl Resolve<crate::api::Args> for PruneBuilders {
|
||||
#[instrument(
|
||||
"PruneBuilders",
|
||||
skip_all,
|
||||
@@ -348,7 +351,10 @@ impl Resolve<super::Args> for PruneBuilders {
|
||||
core = args.core,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker builder prune -a -f");
|
||||
Ok(
|
||||
run_komodo_standard_command("Prune Builders", None, command)
|
||||
@@ -359,7 +365,7 @@ impl Resolve<super::Args> for PruneBuilders {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PruneBuildx {
|
||||
impl Resolve<crate::api::Args> for PruneBuildx {
|
||||
#[instrument(
|
||||
"PruneBuildx",
|
||||
skip_all,
|
||||
@@ -368,7 +374,10 @@ impl Resolve<super::Args> for PruneBuildx {
|
||||
core = args.core,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker buildx prune -a -f");
|
||||
Ok(
|
||||
run_komodo_standard_command("Prune Buildx", None, command)
|
||||
|
||||
@@ -14,7 +14,7 @@ use komodo_client::entities::{
|
||||
update::Log,
|
||||
};
|
||||
use periphery_client::api::{
|
||||
compose::ComposeUpResponse, git::PullOrCloneRepo,
|
||||
DeployStackResponse, git::PullOrCloneRepo,
|
||||
};
|
||||
use resolver_api::Resolve;
|
||||
use tokio::fs;
|
||||
@@ -89,7 +89,7 @@ pub fn env_file_args(
|
||||
pub async fn compose_down(
|
||||
project: &str,
|
||||
services: &[String],
|
||||
res: &mut ComposeUpResponse,
|
||||
res: &mut DeployStackResponse,
|
||||
) -> anyhow::Result<()> {
|
||||
let docker_compose = docker_compose();
|
||||
let service_args = if services.is_empty() {
|
||||
@@ -191,7 +191,7 @@ pub async fn pull_or_clone_stack(
|
||||
pub async fn validate_files(
|
||||
stack: &Stack,
|
||||
run_directory: &Path,
|
||||
res: &mut ComposeUpResponse,
|
||||
res: &mut DeployStackResponse,
|
||||
) {
|
||||
let file_paths = stack
|
||||
.all_file_dependencies()
|
||||
|
||||
@@ -20,7 +20,7 @@ use komodo_client::{
|
||||
},
|
||||
parsers::parse_multiline_command,
|
||||
};
|
||||
use periphery_client::api::compose::*;
|
||||
use periphery_client::api::{DeployStackResponse, compose::*};
|
||||
use resolver_api::Resolve;
|
||||
use shell_escape::unix::escape;
|
||||
use tracing::Instrument;
|
||||
@@ -36,8 +36,11 @@ mod write;
|
||||
|
||||
use helpers::*;
|
||||
|
||||
impl Resolve<super::Args> for GetComposeLog {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
impl Resolve<crate::api::Args> for GetComposeLog {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let GetComposeLog {
|
||||
project,
|
||||
services,
|
||||
@@ -61,8 +64,11 @@ impl Resolve<super::Args> for GetComposeLog {
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for GetComposeLogSearch {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
impl Resolve<crate::api::Args> for GetComposeLogSearch {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let GetComposeLogSearch {
|
||||
project,
|
||||
services,
|
||||
@@ -91,10 +97,10 @@ impl Resolve<super::Args> for GetComposeLogSearch {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for GetComposeContentsOnHost {
|
||||
impl Resolve<crate::api::Args> for GetComposeContentsOnHost {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<GetComposeContentsOnHostResponse> {
|
||||
let GetComposeContentsOnHost {
|
||||
name,
|
||||
@@ -146,7 +152,7 @@ impl Resolve<super::Args> for GetComposeContentsOnHost {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for WriteComposeContentsToHost {
|
||||
impl Resolve<crate::api::Args> for WriteComposeContentsToHost {
|
||||
#[instrument(
|
||||
"WriteComposeContentsToHost",
|
||||
skip_all,
|
||||
@@ -158,7 +164,10 @@ impl Resolve<super::Args> for WriteComposeContentsToHost {
|
||||
file_path = self.file_path,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let WriteComposeContentsToHost {
|
||||
name,
|
||||
run_directory,
|
||||
@@ -188,7 +197,7 @@ impl Resolve<super::Args> for WriteComposeContentsToHost {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for WriteCommitComposeContents {
|
||||
impl Resolve<crate::api::Args> for WriteCommitComposeContents {
|
||||
#[instrument(
|
||||
"WriteCommitComposeContents",
|
||||
skip_all,
|
||||
@@ -202,7 +211,7 @@ impl Resolve<super::Args> for WriteCommitComposeContents {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<RepoExecutionResponse> {
|
||||
let WriteCommitComposeContents {
|
||||
stack,
|
||||
@@ -243,7 +252,7 @@ impl Resolve<super::Args> for WriteCommitComposeContents {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for ComposePull {
|
||||
impl Resolve<crate::api::Args> for ComposePull {
|
||||
#[instrument(
|
||||
"ComposePull",
|
||||
skip_all,
|
||||
@@ -256,7 +265,7 @@ impl Resolve<super::Args> for ComposePull {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<ComposePullResponse> {
|
||||
let ComposePull {
|
||||
mut stack,
|
||||
@@ -362,7 +371,7 @@ impl Resolve<super::Args> for ComposePull {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for ComposeUp {
|
||||
impl Resolve<crate::api::Args> for ComposeUp {
|
||||
#[instrument(
|
||||
"ComposeUp",
|
||||
skip_all,
|
||||
@@ -376,8 +385,8 @@ impl Resolve<super::Args> for ComposeUp {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
) -> anyhow::Result<ComposeUpResponse> {
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<DeployStackResponse> {
|
||||
let ComposeUp {
|
||||
mut stack,
|
||||
repo,
|
||||
@@ -387,7 +396,13 @@ impl Resolve<super::Args> for ComposeUp {
|
||||
mut replacers,
|
||||
} = self;
|
||||
|
||||
let mut res = ComposeUpResponse::default();
|
||||
if !stack.config.swarm_id.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"This method should only be called for Compose Stacks. This is an internal error and should not happen."
|
||||
));
|
||||
}
|
||||
|
||||
let mut res = DeployStackResponse::default();
|
||||
|
||||
let mut interpolator =
|
||||
Interpolator::new(None, &periphery_config().secrets);
|
||||
@@ -502,8 +517,8 @@ impl Resolve<super::Args> for ComposeUp {
|
||||
let compose =
|
||||
serde_yaml_ng::from_str::<ComposeFile>(&config_log.stdout)
|
||||
.context("Failed to parse compose contents")?;
|
||||
// Record sanitized compose config output
|
||||
res.compose_config = Some(config_log.stdout);
|
||||
// Store sanitized compose config output
|
||||
res.merged_config = Some(config_log.stdout);
|
||||
for (
|
||||
service_name,
|
||||
ComposeService {
|
||||
@@ -660,7 +675,7 @@ impl Resolve<super::Args> for ComposeUp {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for ComposeExecution {
|
||||
impl Resolve<crate::api::Args> for ComposeExecution {
|
||||
#[instrument(
|
||||
"ComposeExecution",
|
||||
skip_all,
|
||||
@@ -671,7 +686,10 @@ impl Resolve<super::Args> for ComposeExecution {
|
||||
command = self.command,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let ComposeExecution { project, command } = self;
|
||||
let docker_compose = docker_compose();
|
||||
let log = run_komodo_standard_command(
|
||||
@@ -686,7 +704,7 @@ impl Resolve<super::Args> for ComposeExecution {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for ComposeRun {
|
||||
impl Resolve<crate::api::Args> for ComposeRun {
|
||||
#[instrument(
|
||||
"ComposeRun",
|
||||
skip_all,
|
||||
@@ -698,7 +716,10 @@ impl Resolve<super::Args> for ComposeRun {
|
||||
service = &self.service
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let ComposeRun {
|
||||
mut stack,
|
||||
repo,
|
||||
|
||||
@@ -7,9 +7,8 @@ use komodo_client::entities::{
|
||||
stack::Stack, to_path_compatible_name, update::Log,
|
||||
};
|
||||
use periphery_client::api::{
|
||||
compose::{
|
||||
ComposePullResponse, ComposeRunResponse, ComposeUpResponse,
|
||||
},
|
||||
DeployStackResponse,
|
||||
compose::{ComposePullResponse, ComposeRunResponse},
|
||||
git::{CloneRepo, PullOrCloneRepo},
|
||||
};
|
||||
use resolver_api::Resolve;
|
||||
@@ -24,7 +23,7 @@ pub trait WriteStackRes {
|
||||
fn set_commit_message(&mut self, _message: Option<String>) {}
|
||||
}
|
||||
|
||||
impl WriteStackRes for &mut ComposeUpResponse {
|
||||
impl WriteStackRes for &mut DeployStackResponse {
|
||||
fn logs(&mut self) -> &mut Vec<Log> {
|
||||
&mut self.logs
|
||||
}
|
||||
|
||||
@@ -19,16 +19,18 @@ use crate::{
|
||||
state::docker_client,
|
||||
};
|
||||
|
||||
mod run;
|
||||
|
||||
// ======
|
||||
// READ
|
||||
// ======
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for InspectContainer {
|
||||
impl Resolve<crate::api::Args> for InspectContainer {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Container> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
@@ -41,8 +43,11 @@ impl Resolve<super::Args> for InspectContainer {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for GetContainerLog {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
impl Resolve<crate::api::Args> for GetContainerLog {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let GetContainerLog {
|
||||
name,
|
||||
tail,
|
||||
@@ -64,8 +69,11 @@ impl Resolve<super::Args> for GetContainerLog {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for GetContainerLogSearch {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
impl Resolve<crate::api::Args> for GetContainerLogSearch {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let GetContainerLogSearch {
|
||||
name,
|
||||
terms,
|
||||
@@ -95,10 +103,10 @@ impl Resolve<super::Args> for GetContainerLogSearch {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for GetContainerStats {
|
||||
impl Resolve<crate::api::Args> for GetContainerStats {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<ContainerStats> {
|
||||
let mut stats = get_container_stats(Some(self.name)).await?;
|
||||
let stats =
|
||||
@@ -109,10 +117,10 @@ impl Resolve<super::Args> for GetContainerStats {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for GetFullContainerStats {
|
||||
impl Resolve<crate::api::Args> for GetFullContainerStats {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<FullContainerStats> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
@@ -125,10 +133,10 @@ impl Resolve<super::Args> for GetFullContainerStats {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for GetContainerStatsList {
|
||||
impl Resolve<crate::api::Args> for GetContainerStatsList {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<ContainerStats>> {
|
||||
get_container_stats(None).await
|
||||
}
|
||||
@@ -138,7 +146,7 @@ impl Resolve<super::Args> for GetContainerStatsList {
|
||||
// ACTIONS
|
||||
// =========
|
||||
|
||||
impl Resolve<super::Args> for StartContainer {
|
||||
impl Resolve<crate::api::Args> for StartContainer {
|
||||
#[instrument(
|
||||
"StartContainer",
|
||||
skip_all,
|
||||
@@ -148,7 +156,10 @@ impl Resolve<super::Args> for StartContainer {
|
||||
container = self.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Docker Start",
|
||||
@@ -162,7 +173,7 @@ impl Resolve<super::Args> for StartContainer {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for RestartContainer {
|
||||
impl Resolve<crate::api::Args> for RestartContainer {
|
||||
#[instrument(
|
||||
"RestartContainer",
|
||||
skip_all,
|
||||
@@ -172,7 +183,10 @@ impl Resolve<super::Args> for RestartContainer {
|
||||
container = self.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Docker Restart",
|
||||
@@ -186,7 +200,7 @@ impl Resolve<super::Args> for RestartContainer {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PauseContainer {
|
||||
impl Resolve<crate::api::Args> for PauseContainer {
|
||||
#[instrument(
|
||||
"PauseContainer",
|
||||
skip_all,
|
||||
@@ -196,7 +210,10 @@ impl Resolve<super::Args> for PauseContainer {
|
||||
container = self.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Docker Pause",
|
||||
@@ -208,7 +225,7 @@ impl Resolve<super::Args> for PauseContainer {
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for UnpauseContainer {
|
||||
impl Resolve<crate::api::Args> for UnpauseContainer {
|
||||
#[instrument(
|
||||
"UnpauseContainer",
|
||||
skip_all,
|
||||
@@ -218,7 +235,10 @@ impl Resolve<super::Args> for UnpauseContainer {
|
||||
container = self.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Docker Unpause",
|
||||
@@ -232,7 +252,7 @@ impl Resolve<super::Args> for UnpauseContainer {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for StopContainer {
|
||||
impl Resolve<crate::api::Args> for StopContainer {
|
||||
#[instrument(
|
||||
"StopContainer",
|
||||
skip_all,
|
||||
@@ -242,7 +262,10 @@ impl Resolve<super::Args> for StopContainer {
|
||||
container = self.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let StopContainer { name, signal, time } = self;
|
||||
let command = stop_container_command(&name, signal, time);
|
||||
let log =
|
||||
@@ -269,7 +292,7 @@ impl Resolve<super::Args> for StopContainer {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for RemoveContainer {
|
||||
impl Resolve<crate::api::Args> for RemoveContainer {
|
||||
#[instrument(
|
||||
"RemoveContainer",
|
||||
skip_all,
|
||||
@@ -279,7 +302,10 @@ impl Resolve<super::Args> for RemoveContainer {
|
||||
container = self.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let RemoveContainer { name, signal, time } = self;
|
||||
let stop_command = stop_container_command(&name, signal, time);
|
||||
let command =
|
||||
@@ -317,7 +343,7 @@ impl Resolve<super::Args> for RemoveContainer {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for RenameContainer {
|
||||
impl Resolve<crate::api::Args> for RenameContainer {
|
||||
#[instrument(
|
||||
"RenameContainer",
|
||||
skip_all,
|
||||
@@ -328,7 +354,10 @@ impl Resolve<super::Args> for RenameContainer {
|
||||
new = self.new_name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let RenameContainer {
|
||||
curr_name,
|
||||
new_name,
|
||||
@@ -343,7 +372,7 @@ impl Resolve<super::Args> for RenameContainer {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PruneContainers {
|
||||
impl Resolve<crate::api::Args> for PruneContainers {
|
||||
#[instrument(
|
||||
"PruneContainers",
|
||||
skip_all,
|
||||
@@ -352,7 +381,10 @@ impl Resolve<super::Args> for PruneContainers {
|
||||
core = args.core
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker container prune -f");
|
||||
Ok(
|
||||
run_komodo_standard_command("Prune Containers", None, command)
|
||||
@@ -363,7 +395,7 @@ impl Resolve<super::Args> for PruneContainers {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for StartAllContainers {
|
||||
impl Resolve<crate::api::Args> for StartAllContainers {
|
||||
#[instrument(
|
||||
"StartAllContainers",
|
||||
skip_all,
|
||||
@@ -374,7 +406,7 @@ impl Resolve<super::Args> for StartAllContainers {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<Log>> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
@@ -405,7 +437,7 @@ impl Resolve<super::Args> for StartAllContainers {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for RestartAllContainers {
|
||||
impl Resolve<crate::api::Args> for RestartAllContainers {
|
||||
#[instrument(
|
||||
"RestartAllContainers",
|
||||
skip_all,
|
||||
@@ -416,7 +448,7 @@ impl Resolve<super::Args> for RestartAllContainers {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<Log>> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
@@ -447,7 +479,7 @@ impl Resolve<super::Args> for RestartAllContainers {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PauseAllContainers {
|
||||
impl Resolve<crate::api::Args> for PauseAllContainers {
|
||||
#[instrument(
|
||||
"PauseAllContainers",
|
||||
skip_all,
|
||||
@@ -458,7 +490,7 @@ impl Resolve<super::Args> for PauseAllContainers {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<Log>> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
@@ -489,7 +521,7 @@ impl Resolve<super::Args> for PauseAllContainers {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for UnpauseAllContainers {
|
||||
impl Resolve<crate::api::Args> for UnpauseAllContainers {
|
||||
#[instrument(
|
||||
"UnpauseAllContainers",
|
||||
skip_all,
|
||||
@@ -500,7 +532,7 @@ impl Resolve<super::Args> for UnpauseAllContainers {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<Log>> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
@@ -531,7 +563,7 @@ impl Resolve<super::Args> for UnpauseAllContainers {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for StopAllContainers {
|
||||
impl Resolve<crate::api::Args> for StopAllContainers {
|
||||
#[instrument(
|
||||
"StopAllContainers",
|
||||
skip_all,
|
||||
@@ -542,7 +574,7 @@ impl Resolve<super::Args> for StopAllContainers {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<Log>> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
@@ -1,34 +1,36 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use anyhow::Context;
|
||||
use command::{
|
||||
KomodoCommandMode, run_komodo_command_with_sanitization,
|
||||
};
|
||||
use formatting::format_serror;
|
||||
use interpolate::Interpolator;
|
||||
use komodo_client::{
|
||||
entities::{
|
||||
EnvironmentVar,
|
||||
deployment::{
|
||||
Conversion, Deployment, DeploymentConfig, DeploymentImage,
|
||||
RestartMode, conversions_from_str, extract_registry_domain,
|
||||
},
|
||||
environment_vars_from_str,
|
||||
update::Log,
|
||||
use komodo_client::entities::{
|
||||
deployment::{
|
||||
Deployment, DeploymentConfig, DeploymentImage, RestartMode,
|
||||
conversions_from_str, extract_registry_domain,
|
||||
},
|
||||
parsers::QUOTE_PATTERN,
|
||||
environment_vars_from_str,
|
||||
update::Log,
|
||||
};
|
||||
use periphery_client::api::container::{
|
||||
RemoveContainer, RunContainer,
|
||||
};
|
||||
use periphery_client::api::container::{Deploy, RemoveContainer};
|
||||
use resolver_api::Resolve;
|
||||
use tracing::Instrument;
|
||||
|
||||
use crate::{
|
||||
config::periphery_config,
|
||||
docker::{docker_login, pull_image},
|
||||
helpers::{format_extra_args, format_labels},
|
||||
helpers::{
|
||||
push_conversions, push_environment, push_extra_args, push_labels,
|
||||
},
|
||||
};
|
||||
|
||||
impl Resolve<super::Args> for Deploy {
|
||||
impl Resolve<crate::api::Args> for RunContainer {
|
||||
#[instrument(
|
||||
"Deploy",
|
||||
"DeployContainer",
|
||||
skip_all,
|
||||
fields(
|
||||
id = args.id.to_string(),
|
||||
@@ -38,8 +40,11 @@ impl Resolve<super::Args> for Deploy {
|
||||
stop_time = self.stop_time,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
let Deploy {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let RunContainer {
|
||||
mut deployment,
|
||||
stop_signal,
|
||||
stop_time,
|
||||
@@ -57,15 +62,15 @@ impl Resolve<super::Args> for Deploy {
|
||||
{
|
||||
if image.is_empty() {
|
||||
return Ok(Log::error(
|
||||
"get image",
|
||||
String::from("deployment does not have image attached"),
|
||||
"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"),
|
||||
"Get Image",
|
||||
String::from("Deployment does not have image attached"),
|
||||
));
|
||||
};
|
||||
|
||||
@@ -77,9 +82,9 @@ impl Resolve<super::Args> for Deploy {
|
||||
.await
|
||||
{
|
||||
return Ok(Log::error(
|
||||
"docker login",
|
||||
"Docker Login",
|
||||
format_serror(
|
||||
&e.context("failed to login to docker registry").into(),
|
||||
&e.context("Failed to login to docker registry").into(),
|
||||
),
|
||||
));
|
||||
}
|
||||
@@ -99,7 +104,7 @@ impl Resolve<super::Args> for Deploy {
|
||||
let command = docker_run_command(&deployment, image)
|
||||
.context("Unable to generate valid docker run command")?;
|
||||
|
||||
let span = info_span!("RunDockerRun");
|
||||
let span = info_span!("ExecuteDockerRun");
|
||||
let Some(log) = run_komodo_command_with_sanitization(
|
||||
"Docker Run",
|
||||
None,
|
||||
@@ -138,75 +143,53 @@ fn docker_run_command(
|
||||
}: &Deployment,
|
||||
image: &str,
|
||||
) -> anyhow::Result<String> {
|
||||
let ports = parse_conversions(
|
||||
let mut res =
|
||||
format!("docker run -d --name {name} --network {network}");
|
||||
|
||||
push_conversions(
|
||||
&mut res,
|
||||
&conversions_from_str(ports).context("Invalid ports")?,
|
||||
"-p",
|
||||
);
|
||||
let volumes = parse_conversions(
|
||||
)?;
|
||||
|
||||
push_conversions(
|
||||
&mut res,
|
||||
&conversions_from_str(volumes).context("Invalid volumes")?,
|
||||
"-v",
|
||||
);
|
||||
let network = parse_network(network);
|
||||
let restart = parse_restart(restart);
|
||||
let environment = parse_environment(
|
||||
)?;
|
||||
|
||||
push_environment(
|
||||
&mut res,
|
||||
&environment_vars_from_str(environment)
|
||||
.context("Invalid environment")?,
|
||||
);
|
||||
let labels = format_labels(
|
||||
)?;
|
||||
|
||||
push_restart(&mut res, restart)?;
|
||||
|
||||
push_labels(
|
||||
&mut res,
|
||||
&environment_vars_from_str(labels).context("Invalid labels")?,
|
||||
);
|
||||
let command = parse_command(command);
|
||||
let extra_args = format_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("")
|
||||
}
|
||||
push_extra_args(&mut res, extra_args)?;
|
||||
|
||||
fn parse_environment(environment: &[EnvironmentVar]) -> String {
|
||||
environment
|
||||
.iter()
|
||||
.map(|p| {
|
||||
if p.value.starts_with(QUOTE_PATTERN)
|
||||
&& p.value.ends_with(QUOTE_PATTERN)
|
||||
{
|
||||
// If the value already wrapped in quotes, don't wrap it again
|
||||
format!(" --env {}={}", p.variable, p.value)
|
||||
} else {
|
||||
format!(" --env {}=\"{}\"", p.variable, p.value)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("")
|
||||
}
|
||||
write!(&mut res, " {image}")?;
|
||||
|
||||
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}")
|
||||
if !command.is_empty() {
|
||||
write!(&mut res, " {command}")?;
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn push_restart(
|
||||
command: &mut String,
|
||||
restart: &RestartMode,
|
||||
) -> anyhow::Result<()> {
|
||||
let restart = match restart {
|
||||
RestartMode::OnFailure => "on-failure:10",
|
||||
_ => restart.as_ref(),
|
||||
};
|
||||
write!(command, " --restart {restart}")
|
||||
.context("Failed to write restart mode")
|
||||
}
|
||||
@@ -22,8 +22,11 @@ use crate::{docker::docker_login, state::docker_client};
|
||||
// IMAGE
|
||||
// =====
|
||||
|
||||
impl Resolve<super::Args> for InspectImage {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Image> {
|
||||
impl Resolve<crate::api::Args> for InspectImage {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Image> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
@@ -35,10 +38,10 @@ impl Resolve<super::Args> for InspectImage {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for ImageHistory {
|
||||
impl Resolve<crate::api::Args> for ImageHistory {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<ImageHistoryResponseItem>> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
@@ -60,7 +63,7 @@ fn pull_cache() -> &'static TimeoutCache<String, Log> {
|
||||
PULL_CACHE.get_or_init(Default::default)
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for PullImage {
|
||||
impl Resolve<crate::api::Args> for PullImage {
|
||||
#[instrument(
|
||||
"PullImage",
|
||||
skip_all,
|
||||
@@ -71,7 +74,10 @@ impl Resolve<super::Args> for PullImage {
|
||||
account = self.account,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let PullImage {
|
||||
name,
|
||||
account,
|
||||
@@ -118,7 +124,7 @@ impl Resolve<super::Args> for PullImage {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for DeleteImage {
|
||||
impl Resolve<crate::api::Args> for DeleteImage {
|
||||
#[instrument(
|
||||
"DeleteImage",
|
||||
skip_all,
|
||||
@@ -128,7 +134,10 @@ impl Resolve<super::Args> for DeleteImage {
|
||||
image = self.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = format!("docker image rm {}", self.name);
|
||||
Ok(
|
||||
run_komodo_standard_command("Delete Image", None, command)
|
||||
@@ -139,7 +148,7 @@ impl Resolve<super::Args> for DeleteImage {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PruneImages {
|
||||
impl Resolve<crate::api::Args> for PruneImages {
|
||||
#[instrument(
|
||||
"PruneImages",
|
||||
skip_all,
|
||||
@@ -148,7 +157,10 @@ impl Resolve<super::Args> for PruneImages {
|
||||
core = args.core,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker image prune -a -f");
|
||||
Ok(
|
||||
run_komodo_standard_command("Prune Images", None, command)
|
||||
@@ -161,8 +173,11 @@ impl Resolve<super::Args> for PruneImages {
|
||||
// NETWORK
|
||||
// =======
|
||||
|
||||
impl Resolve<super::Args> for InspectNetwork {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Network> {
|
||||
impl Resolve<crate::api::Args> for InspectNetwork {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Network> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
@@ -174,7 +189,7 @@ impl Resolve<super::Args> for InspectNetwork {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for CreateNetwork {
|
||||
impl Resolve<crate::api::Args> for CreateNetwork {
|
||||
#[instrument(
|
||||
"CreateNetwork",
|
||||
skip_all,
|
||||
@@ -185,7 +200,10 @@ impl Resolve<super::Args> for CreateNetwork {
|
||||
driver = self.driver,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let CreateNetwork { name, driver } = self;
|
||||
let driver = match driver {
|
||||
Some(driver) => format!(" -d {driver}"),
|
||||
@@ -201,7 +219,7 @@ impl Resolve<super::Args> for CreateNetwork {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for DeleteNetwork {
|
||||
impl Resolve<crate::api::Args> for DeleteNetwork {
|
||||
#[instrument(
|
||||
"DeleteNetwork",
|
||||
skip_all,
|
||||
@@ -211,7 +229,10 @@ impl Resolve<super::Args> for DeleteNetwork {
|
||||
network = self.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = format!("docker network rm {}", self.name);
|
||||
Ok(
|
||||
run_komodo_standard_command("Delete Network", None, command)
|
||||
@@ -222,7 +243,7 @@ impl Resolve<super::Args> for DeleteNetwork {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PruneNetworks {
|
||||
impl Resolve<crate::api::Args> for PruneNetworks {
|
||||
#[instrument(
|
||||
"PruneNetworks",
|
||||
skip_all,
|
||||
@@ -231,7 +252,10 @@ impl Resolve<super::Args> for PruneNetworks {
|
||||
core = args.core,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker network prune -f");
|
||||
Ok(
|
||||
run_komodo_standard_command("Prune Networks", None, command)
|
||||
@@ -244,8 +268,11 @@ impl Resolve<super::Args> for PruneNetworks {
|
||||
// VOLUME
|
||||
// ======
|
||||
|
||||
impl Resolve<super::Args> for InspectVolume {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Volume> {
|
||||
impl Resolve<crate::api::Args> for InspectVolume {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Volume> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
@@ -257,7 +284,7 @@ impl Resolve<super::Args> for InspectVolume {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for DeleteVolume {
|
||||
impl Resolve<crate::api::Args> for DeleteVolume {
|
||||
#[instrument(
|
||||
"DeleteVolume",
|
||||
skip_all,
|
||||
@@ -267,7 +294,10 @@ impl Resolve<super::Args> for DeleteVolume {
|
||||
volume = self.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = format!("docker volume rm {}", self.name);
|
||||
Ok(
|
||||
run_komodo_standard_command("Delete Volume", None, command)
|
||||
@@ -278,7 +308,7 @@ impl Resolve<super::Args> for DeleteVolume {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PruneVolumes {
|
||||
impl Resolve<crate::api::Args> for PruneVolumes {
|
||||
#[instrument(
|
||||
"PruneVolumes",
|
||||
skip_all,
|
||||
@@ -287,7 +317,10 @@ impl Resolve<super::Args> for PruneVolumes {
|
||||
core = args.core,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let command = String::from("docker volume prune -a -f");
|
||||
Ok(
|
||||
run_komodo_standard_command("Prune Volumes", None, command)
|
||||
|
||||
@@ -16,10 +16,10 @@ use crate::{
|
||||
config::periphery_config, helpers::handle_post_repo_execution,
|
||||
};
|
||||
|
||||
impl Resolve<super::Args> for GetLatestCommit {
|
||||
impl Resolve<crate::api::Args> for GetLatestCommit {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Option<LatestCommit>> {
|
||||
let repo_path = match self.path {
|
||||
Some(p) => PathBuf::from(p),
|
||||
@@ -33,7 +33,7 @@ impl Resolve<super::Args> for GetLatestCommit {
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for CloneRepo {
|
||||
impl Resolve<crate::api::Args> for CloneRepo {
|
||||
#[instrument(
|
||||
"CloneRepo",
|
||||
skip_all,
|
||||
@@ -46,7 +46,7 @@ impl Resolve<super::Args> for CloneRepo {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<PeripheryRepoExecutionResponse> {
|
||||
let CloneRepo {
|
||||
args,
|
||||
@@ -79,7 +79,7 @@ impl Resolve<super::Args> for CloneRepo {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PullRepo {
|
||||
impl Resolve<crate::api::Args> for PullRepo {
|
||||
#[instrument(
|
||||
"PullRepo",
|
||||
skip_all,
|
||||
@@ -92,7 +92,7 @@ impl Resolve<super::Args> for PullRepo {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<PeripheryRepoExecutionResponse> {
|
||||
let PullRepo {
|
||||
args,
|
||||
@@ -124,7 +124,7 @@ impl Resolve<super::Args> for PullRepo {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for PullOrCloneRepo {
|
||||
impl Resolve<crate::api::Args> for PullOrCloneRepo {
|
||||
#[instrument(
|
||||
"PullOrCloneRepo",
|
||||
skip_all,
|
||||
@@ -137,7 +137,7 @@ impl Resolve<super::Args> for PullOrCloneRepo {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<PeripheryRepoExecutionResponse> {
|
||||
let PullOrCloneRepo {
|
||||
args,
|
||||
@@ -171,7 +171,7 @@ impl Resolve<super::Args> for PullOrCloneRepo {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for RenameRepo {
|
||||
impl Resolve<crate::api::Args> for RenameRepo {
|
||||
#[instrument(
|
||||
"RenameRepo",
|
||||
skip_all,
|
||||
@@ -182,7 +182,10 @@ impl Resolve<super::Args> for RenameRepo {
|
||||
new_name = self.new_name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let RenameRepo {
|
||||
curr_name,
|
||||
new_name,
|
||||
@@ -201,7 +204,7 @@ impl Resolve<super::Args> for RenameRepo {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for DeleteRepo {
|
||||
impl Resolve<crate::api::Args> for DeleteRepo {
|
||||
#[instrument(
|
||||
"DeleteRepo",
|
||||
skip_all,
|
||||
@@ -212,7 +215,10 @@ impl Resolve<super::Args> for DeleteRepo {
|
||||
is_build = self.is_build,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Log> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let DeleteRepo { name, is_build } = self;
|
||||
// If using custom clone path, it will be passed by core instead of name.
|
||||
// So the join will resolve to just the absolute path.
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for RotatePrivateKey {
|
||||
impl Resolve<crate::api::Args> for RotatePrivateKey {
|
||||
#[instrument(
|
||||
"RotatePrivateKey",
|
||||
skip_all,
|
||||
@@ -23,7 +23,7 @@ impl Resolve<super::Args> for RotatePrivateKey {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<RotatePrivateKeyResponse> {
|
||||
let public_key = periphery_keys().rotate().await?.into_inner();
|
||||
info!("New Public Key: {public_key}");
|
||||
@@ -33,7 +33,7 @@ impl Resolve<super::Args> for RotatePrivateKey {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for RotateCorePublicKey {
|
||||
impl Resolve<crate::api::Args> for RotateCorePublicKey {
|
||||
#[instrument(
|
||||
"RotateCorePublicKey",
|
||||
skip_all,
|
||||
@@ -45,7 +45,7 @@ impl Resolve<super::Args> for RotateCorePublicKey {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<NoData> {
|
||||
let config = periphery_config();
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ pub mod terminal;
|
||||
mod build;
|
||||
mod compose;
|
||||
mod container;
|
||||
mod deploy;
|
||||
mod docker;
|
||||
mod git;
|
||||
mod keys;
|
||||
@@ -94,7 +93,7 @@ pub enum PeripheryRequest {
|
||||
GetFullContainerStats(GetFullContainerStats),
|
||||
|
||||
// Container (Write)
|
||||
Deploy(Deploy),
|
||||
RunContainer(RunContainer),
|
||||
StartContainer(StartContainer),
|
||||
RestartContainer(RestartContainer),
|
||||
PauseContainer(PauseContainer),
|
||||
@@ -136,21 +135,25 @@ pub enum PeripheryRequest {
|
||||
// All in one (Write)
|
||||
PruneSystem(PruneSystem),
|
||||
|
||||
// Swarm
|
||||
// Swarm (Read)
|
||||
PollSwarmStatus(PollSwarmStatus),
|
||||
InspectSwarmNode(InspectSwarmNode),
|
||||
UpdateSwarmNode(UpdateSwarmNode),
|
||||
RemoveSwarmNodes(RemoveSwarmNodes),
|
||||
InspectSwarmStack(InspectSwarmStack),
|
||||
RemoveSwarmStacks(RemoveSwarmStacks),
|
||||
InspectSwarmService(InspectSwarmService),
|
||||
GetSwarmServiceLog(GetSwarmServiceLog),
|
||||
GetSwarmServiceLogSearch(GetSwarmServiceLogSearch),
|
||||
RemoveSwarmServices(RemoveSwarmServices),
|
||||
InspectSwarmTask(InspectSwarmTask),
|
||||
InspectSwarmConfig(InspectSwarmConfig),
|
||||
RemoveSwarmConfigs(RemoveSwarmConfigs),
|
||||
InspectSwarmSecret(InspectSwarmSecret),
|
||||
|
||||
// Swarm (Write)
|
||||
UpdateSwarmNode(UpdateSwarmNode),
|
||||
RemoveSwarmNodes(RemoveSwarmNodes),
|
||||
DeploySwarmStack(DeploySwarmStack),
|
||||
RemoveSwarmStacks(RemoveSwarmStacks),
|
||||
CreateSwarmService(CreateSwarmService),
|
||||
RemoveSwarmServices(RemoveSwarmServices),
|
||||
RemoveSwarmConfigs(RemoveSwarmConfigs),
|
||||
RemoveSwarmSecrets(RemoveSwarmSecrets),
|
||||
|
||||
// Terminal
|
||||
|
||||
@@ -13,10 +13,10 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
impl Resolve<super::Args> for PollStatus {
|
||||
impl Resolve<crate::api::Args> for PollStatus {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<PollStatusResponse> {
|
||||
let stats_client = stats_client().read().await;
|
||||
|
||||
|
||||
@@ -1,384 +0,0 @@
|
||||
use anyhow::Context as _;
|
||||
use command::{
|
||||
run_komodo_shell_command, run_komodo_standard_command,
|
||||
};
|
||||
use komodo_client::entities::{
|
||||
docker::{
|
||||
SwarmLists, config::SwarmConfig, node::SwarmNode,
|
||||
secret::SwarmSecret, service::SwarmService, stack::SwarmStack,
|
||||
task::SwarmTask,
|
||||
},
|
||||
update::Log,
|
||||
};
|
||||
use periphery_client::api::swarm::*;
|
||||
use resolver_api::Resolve;
|
||||
|
||||
use crate::{
|
||||
docker::{
|
||||
config::{inspect_swarm_config, list_swarm_configs},
|
||||
stack::{inspect_swarm_stack, list_swarm_stacks},
|
||||
},
|
||||
helpers::format_log_grep,
|
||||
state::docker_client,
|
||||
};
|
||||
|
||||
impl Resolve<super::Args> for PollSwarmStatus {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
) -> anyhow::Result<PollSwarmStatusResponse> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
let (inspect, nodes, services, tasks, secrets, configs, stacks) = tokio::join!(
|
||||
client.inspect_swarm(),
|
||||
client.list_swarm_nodes(),
|
||||
client.list_swarm_services(),
|
||||
client.list_swarm_tasks(),
|
||||
client.list_swarm_secrets(),
|
||||
list_swarm_configs(),
|
||||
list_swarm_stacks(),
|
||||
);
|
||||
Ok(PollSwarmStatusResponse {
|
||||
inspect: inspect.ok(),
|
||||
lists: SwarmLists {
|
||||
nodes: nodes.unwrap_or_default(),
|
||||
services: services.unwrap_or_default(),
|
||||
tasks: tasks.unwrap_or_default(),
|
||||
secrets: secrets.unwrap_or_default(),
|
||||
configs: configs.unwrap_or_default(),
|
||||
stacks: stacks.unwrap_or_default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ======
|
||||
// Node
|
||||
// ======
|
||||
|
||||
impl Resolve<super::Args> for InspectSwarmNode {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
) -> anyhow::Result<SwarmNode> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
client.inspect_swarm_node(&self.node).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for UpdateSwarmNode {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker node update");
|
||||
|
||||
if let Some(role) = self.role {
|
||||
command += " --role=";
|
||||
command += role.as_ref();
|
||||
}
|
||||
|
||||
if let Some(availability) = self.availability {
|
||||
command += " --availability=";
|
||||
command += availability.as_ref();
|
||||
}
|
||||
|
||||
if let Some(label_add) = self.label_add {
|
||||
for (key, value) in label_add {
|
||||
command += " --label-add ";
|
||||
command += &key;
|
||||
if let Some(value) = value {
|
||||
command += "=";
|
||||
command += &value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(label_rm) = self.label_rm {
|
||||
for key in label_rm {
|
||||
command += " --label-rm ";
|
||||
command += &key;
|
||||
}
|
||||
}
|
||||
|
||||
command += " ";
|
||||
command += &self.node;
|
||||
|
||||
Ok(
|
||||
run_komodo_standard_command("Update Swarm Node", None, command)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for RemoveSwarmNodes {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker node rm");
|
||||
if self.force {
|
||||
command += " --force"
|
||||
}
|
||||
for node in self.nodes {
|
||||
command += " ";
|
||||
command += &node;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Nodes",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// =======
|
||||
// Stack
|
||||
// =======
|
||||
|
||||
impl Resolve<super::Args> for InspectSwarmStack {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
) -> anyhow::Result<SwarmStack> {
|
||||
inspect_swarm_stack(self.stack).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for RemoveSwarmStacks {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker stack rm");
|
||||
// This defaults to true, only need when false
|
||||
if !self.detach {
|
||||
command += " --detach=false"
|
||||
}
|
||||
for stack in self.stacks {
|
||||
command += " ";
|
||||
command += &stack;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Stacks",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// =========
|
||||
// Service
|
||||
// =========
|
||||
|
||||
impl Resolve<super::Args> for InspectSwarmService {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
) -> anyhow::Result<SwarmService> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
client.inspect_swarm_service(&self.service).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for GetSwarmServiceLog {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
let GetSwarmServiceLog {
|
||||
service,
|
||||
tail,
|
||||
timestamps,
|
||||
no_task_ids,
|
||||
no_resolve,
|
||||
details,
|
||||
} = self;
|
||||
let timestamps = if timestamps {
|
||||
" --timestamps"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let no_task_ids = if no_task_ids {
|
||||
" --no-task-ids"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let no_resolve = if no_resolve {
|
||||
" --no-resolve"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let details = if details {
|
||||
" --details"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let command = format!(
|
||||
"docker service logs --tail {tail}{timestamps}{no_task_ids}{no_resolve}{details} {service}",
|
||||
);
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Get Swarm Service Log",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for GetSwarmServiceLogSearch {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
let GetSwarmServiceLogSearch {
|
||||
service,
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
no_task_ids,
|
||||
no_resolve,
|
||||
details,
|
||||
} = self;
|
||||
let timestamps = if timestamps {
|
||||
" --timestamps"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let no_task_ids = if no_task_ids {
|
||||
" --no-task-ids"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let no_resolve = if no_resolve {
|
||||
" --no-resolve"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let details = if details {
|
||||
" --details"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let grep = format_log_grep(&terms, combinator, invert);
|
||||
let command = format!(
|
||||
"docker service logs --tail 5000{timestamps}{no_task_ids}{no_resolve}{details} {service} 2>&1 | {grep}",
|
||||
);
|
||||
Ok(
|
||||
run_komodo_shell_command(
|
||||
"Search Swarm Service Log",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for RemoveSwarmServices {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker service rm");
|
||||
for service in self.services {
|
||||
command += " ";
|
||||
command += &service;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Services",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ======
|
||||
// Task
|
||||
// ======
|
||||
|
||||
impl Resolve<super::Args> for InspectSwarmTask {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
) -> anyhow::Result<SwarmTask> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
client.inspect_swarm_task(&self.task).await
|
||||
}
|
||||
}
|
||||
|
||||
// ========
|
||||
// Config
|
||||
// ========
|
||||
|
||||
impl Resolve<super::Args> for InspectSwarmConfig {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
) -> anyhow::Result<Vec<SwarmConfig>> {
|
||||
inspect_swarm_config(&self.config).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for RemoveSwarmConfigs {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker config rm");
|
||||
for config in self.configs {
|
||||
command += " ";
|
||||
command += &config;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Configs",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ========
|
||||
// Secret
|
||||
// ========
|
||||
|
||||
impl Resolve<super::Args> for InspectSwarmSecret {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
) -> anyhow::Result<SwarmSecret> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
client.inspect_swarm_secret(&self.secret).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<super::Args> for RemoveSwarmSecrets {
|
||||
async fn resolve(self, _: &super::Args) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker secret rm");
|
||||
for secret in self.secrets {
|
||||
command += " ";
|
||||
command += &secret;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Secrets",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
271
bin/periphery/src/api/swarm/mod.rs
Normal file
271
bin/periphery/src/api/swarm/mod.rs
Normal file
@@ -0,0 +1,271 @@
|
||||
use anyhow::Context as _;
|
||||
use command::run_komodo_standard_command;
|
||||
use komodo_client::entities::{
|
||||
docker::{
|
||||
SwarmLists, config::SwarmConfig, node::SwarmNode,
|
||||
secret::SwarmSecret, task::SwarmTask,
|
||||
},
|
||||
update::Log,
|
||||
};
|
||||
use periphery_client::api::swarm::*;
|
||||
use resolver_api::Resolve;
|
||||
|
||||
use crate::{
|
||||
docker::{
|
||||
config::{inspect_swarm_config, list_swarm_configs},
|
||||
stack::list_swarm_stacks,
|
||||
},
|
||||
state::docker_client,
|
||||
};
|
||||
|
||||
mod service;
|
||||
mod stack;
|
||||
|
||||
impl Resolve<crate::api::Args> for PollSwarmStatus {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<PollSwarmStatusResponse> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
let (inspect, nodes, services, tasks, secrets, configs, stacks) = tokio::join!(
|
||||
client.inspect_swarm(),
|
||||
client.list_swarm_nodes(),
|
||||
client.list_swarm_services(),
|
||||
client.list_swarm_tasks(),
|
||||
client.list_swarm_secrets(),
|
||||
list_swarm_configs(),
|
||||
list_swarm_stacks(),
|
||||
);
|
||||
Ok(PollSwarmStatusResponse {
|
||||
inspect: inspect.ok(),
|
||||
lists: SwarmLists {
|
||||
nodes: nodes.unwrap_or_default(),
|
||||
services: services.unwrap_or_default(),
|
||||
tasks: tasks.unwrap_or_default(),
|
||||
secrets: secrets.unwrap_or_default(),
|
||||
configs: configs.unwrap_or_default(),
|
||||
stacks: stacks.unwrap_or_default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ======
|
||||
// Node
|
||||
// ======
|
||||
|
||||
impl Resolve<crate::api::Args> for InspectSwarmNode {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<SwarmNode> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
client.inspect_swarm_node(&self.node).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for UpdateSwarmNode {
|
||||
#[instrument(
|
||||
"UpdateSwarmNode",
|
||||
skip_all,
|
||||
fields(
|
||||
id = args.id.to_string(),
|
||||
core = args.core,
|
||||
node = self.node,
|
||||
update = serde_json::to_string(&self).unwrap_or_else(|e| e.to_string())
|
||||
)
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker node update");
|
||||
|
||||
if let Some(role) = self.role {
|
||||
command += " --role=";
|
||||
command += role.as_ref();
|
||||
}
|
||||
|
||||
if let Some(availability) = self.availability {
|
||||
command += " --availability=";
|
||||
command += availability.as_ref();
|
||||
}
|
||||
|
||||
if let Some(label_add) = self.label_add {
|
||||
for (key, value) in label_add {
|
||||
command += " --label-add ";
|
||||
command += &key;
|
||||
if let Some(value) = value {
|
||||
command += "=";
|
||||
command += &value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(label_rm) = self.label_rm {
|
||||
for key in label_rm {
|
||||
command += " --label-rm ";
|
||||
command += &key;
|
||||
}
|
||||
}
|
||||
|
||||
command += " ";
|
||||
command += &self.node;
|
||||
|
||||
Ok(
|
||||
run_komodo_standard_command("Update Swarm Node", None, command)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for RemoveSwarmNodes {
|
||||
#[instrument(
|
||||
"RemoveSwarmNodes",
|
||||
skip_all,
|
||||
fields(
|
||||
id = args.id.to_string(),
|
||||
core = args.core,
|
||||
nodes = serde_json::to_string(&self.nodes).unwrap_or_else(|e| e.to_string()),
|
||||
force = self.force,
|
||||
)
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker node rm");
|
||||
if self.force {
|
||||
command += " --force"
|
||||
}
|
||||
for node in self.nodes {
|
||||
command += " ";
|
||||
command += &node;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Nodes",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ======
|
||||
// Task
|
||||
// ======
|
||||
|
||||
impl Resolve<crate::api::Args> for InspectSwarmTask {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<SwarmTask> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
client.inspect_swarm_task(&self.task).await
|
||||
}
|
||||
}
|
||||
|
||||
// ========
|
||||
// Config
|
||||
// ========
|
||||
|
||||
impl Resolve<crate::api::Args> for InspectSwarmConfig {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<SwarmConfig>> {
|
||||
inspect_swarm_config(&self.config).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for RemoveSwarmConfigs {
|
||||
#[instrument(
|
||||
"RemoveSwarmConfigs",
|
||||
skip_all,
|
||||
fields(
|
||||
id = args.id.to_string(),
|
||||
core = args.core,
|
||||
configs = serde_json::to_string(&self.configs).unwrap_or_else(|e| e.to_string()),
|
||||
)
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker config rm");
|
||||
for config in self.configs {
|
||||
command += " ";
|
||||
command += &config;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Configs",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ========
|
||||
// Secret
|
||||
// ========
|
||||
|
||||
impl Resolve<crate::api::Args> for InspectSwarmSecret {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<SwarmSecret> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
client.inspect_swarm_secret(&self.secret).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for RemoveSwarmSecrets {
|
||||
#[instrument(
|
||||
"RemoveSwarmSecrets",
|
||||
skip_all,
|
||||
fields(
|
||||
id = args.id.to_string(),
|
||||
core = args.core,
|
||||
secrets = serde_json::to_string(&self.secrets).unwrap_or_else(|e| e.to_string()),
|
||||
)
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker secret rm");
|
||||
for secret in self.secrets {
|
||||
command += " ";
|
||||
command += &secret;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Secrets",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
327
bin/periphery/src/api/swarm/service.rs
Normal file
327
bin/periphery/src/api/swarm/service.rs
Normal file
@@ -0,0 +1,327 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use anyhow::Context as _;
|
||||
use command::{
|
||||
KomodoCommandMode, run_komodo_command_with_sanitization,
|
||||
run_komodo_shell_command, run_komodo_standard_command,
|
||||
};
|
||||
use formatting::format_serror;
|
||||
use interpolate::Interpolator;
|
||||
use komodo_client::entities::{
|
||||
deployment::{
|
||||
Deployment, DeploymentConfig, DeploymentImage,
|
||||
conversions_from_str, extract_registry_domain,
|
||||
},
|
||||
docker::service::SwarmService,
|
||||
environment_vars_from_str,
|
||||
update::Log,
|
||||
};
|
||||
use periphery_client::api::swarm::{
|
||||
CreateSwarmService, GetSwarmServiceLog, GetSwarmServiceLogSearch,
|
||||
InspectSwarmService, RemoveSwarmServices,
|
||||
};
|
||||
use resolver_api::Resolve;
|
||||
use tracing::Instrument;
|
||||
|
||||
use crate::{
|
||||
config::periphery_config,
|
||||
docker::docker_login,
|
||||
helpers::{
|
||||
format_log_grep, push_conversions, push_environment,
|
||||
push_extra_args, push_labels,
|
||||
},
|
||||
state::docker_client,
|
||||
};
|
||||
|
||||
impl Resolve<crate::api::Args> for InspectSwarmService {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<SwarmService> {
|
||||
let client = docker_client().load();
|
||||
let client = client
|
||||
.iter()
|
||||
.next()
|
||||
.context("Could not connect to docker client")?;
|
||||
client.inspect_swarm_service(&self.service).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for GetSwarmServiceLog {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let GetSwarmServiceLog {
|
||||
service,
|
||||
tail,
|
||||
timestamps,
|
||||
no_task_ids,
|
||||
no_resolve,
|
||||
details,
|
||||
} = self;
|
||||
let timestamps = if timestamps {
|
||||
" --timestamps"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let no_task_ids = if no_task_ids {
|
||||
" --no-task-ids"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let no_resolve = if no_resolve {
|
||||
" --no-resolve"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let details = if details {
|
||||
" --details"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let command = format!(
|
||||
"docker service logs --tail {tail}{timestamps}{no_task_ids}{no_resolve}{details} {service}",
|
||||
);
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Get Swarm Service Log",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for GetSwarmServiceLogSearch {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let GetSwarmServiceLogSearch {
|
||||
service,
|
||||
terms,
|
||||
combinator,
|
||||
invert,
|
||||
timestamps,
|
||||
no_task_ids,
|
||||
no_resolve,
|
||||
details,
|
||||
} = self;
|
||||
let timestamps = if timestamps {
|
||||
" --timestamps"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let no_task_ids = if no_task_ids {
|
||||
" --no-task-ids"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let no_resolve = if no_resolve {
|
||||
" --no-resolve"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let details = if details {
|
||||
" --details"
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let grep = format_log_grep(&terms, combinator, invert);
|
||||
let command = format!(
|
||||
"docker service logs --tail 5000{timestamps}{no_task_ids}{no_resolve}{details} {service} 2>&1 | {grep}",
|
||||
);
|
||||
Ok(
|
||||
run_komodo_shell_command(
|
||||
"Search Swarm Service Log",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for RemoveSwarmServices {
|
||||
#[instrument(
|
||||
"RemoveSwarmServices",
|
||||
skip_all,
|
||||
fields(
|
||||
id = args.id.to_string(),
|
||||
core = args.core,
|
||||
services = serde_json::to_string(&self.services).unwrap_or_else(|e| e.to_string()),
|
||||
)
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker service rm");
|
||||
for service in self.services {
|
||||
command += " ";
|
||||
command += &service;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Services",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for CreateSwarmService {
|
||||
#[instrument(
|
||||
"CreateSwarmService",
|
||||
skip_all,
|
||||
fields(
|
||||
id = args.id.to_string(),
|
||||
core = args.core,
|
||||
deployment = &self.deployment.name,
|
||||
)
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
let CreateSwarmService {
|
||||
mut deployment,
|
||||
registry_token,
|
||||
mut replacers,
|
||||
} = self;
|
||||
|
||||
let mut interpolator =
|
||||
Interpolator::new(None, &periphery_config().secrets);
|
||||
interpolator.interpolate_deployment(&mut deployment)?;
|
||||
replacers.extend(interpolator.secret_replacers);
|
||||
|
||||
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 build replaced by Core",
|
||||
),
|
||||
));
|
||||
};
|
||||
|
||||
let use_with_registry_auth = match docker_login(
|
||||
&extract_registry_domain(image)?,
|
||||
&deployment.config.image_registry_account,
|
||||
registry_token.as_deref(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
return Ok(Log::error(
|
||||
"Docker Login",
|
||||
format_serror(
|
||||
&e.context("Failed to login to docker registry").into(),
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let command = docker_service_create_command(
|
||||
&deployment,
|
||||
image,
|
||||
use_with_registry_auth,
|
||||
)
|
||||
.context(
|
||||
"Unable to generate valid docker service create command",
|
||||
)?;
|
||||
|
||||
let span = info_span!("ExecuteDockerServiceCreate");
|
||||
let Some(log) = run_komodo_command_with_sanitization(
|
||||
"Docker Service Create",
|
||||
None,
|
||||
command,
|
||||
KomodoCommandMode::Shell,
|
||||
&replacers,
|
||||
)
|
||||
.instrument(span)
|
||||
.await
|
||||
else {
|
||||
// The none case is only for empty command,
|
||||
// this won't be the case given it is populated above.
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
Ok(log)
|
||||
}
|
||||
}
|
||||
|
||||
fn docker_service_create_command(
|
||||
Deployment {
|
||||
name,
|
||||
config:
|
||||
DeploymentConfig {
|
||||
volumes,
|
||||
ports,
|
||||
network,
|
||||
command,
|
||||
environment,
|
||||
labels,
|
||||
extra_args,
|
||||
..
|
||||
},
|
||||
..
|
||||
}: &Deployment,
|
||||
image: &str,
|
||||
use_with_registry_auth: bool,
|
||||
) -> anyhow::Result<String> {
|
||||
let mut res = format!(
|
||||
"docker service create --name {name} --network {network}"
|
||||
);
|
||||
|
||||
push_conversions(
|
||||
&mut res,
|
||||
&conversions_from_str(ports).context("Invalid ports")?,
|
||||
"-p",
|
||||
)?;
|
||||
|
||||
push_conversions(
|
||||
&mut res,
|
||||
&conversions_from_str(volumes).context("Invalid volumes")?,
|
||||
"--mount",
|
||||
)?;
|
||||
|
||||
push_environment(
|
||||
&mut res,
|
||||
&environment_vars_from_str(environment)
|
||||
.context("Invalid environment")?,
|
||||
)?;
|
||||
|
||||
push_labels(
|
||||
&mut res,
|
||||
&environment_vars_from_str(labels).context("Invalid labels")?,
|
||||
)?;
|
||||
|
||||
if use_with_registry_auth {
|
||||
res += " --with-registry-auth";
|
||||
}
|
||||
|
||||
push_extra_args(&mut res, extra_args)?;
|
||||
|
||||
write!(&mut res, " {image}")?;
|
||||
|
||||
if !command.is_empty() {
|
||||
write!(&mut res, " {command}")?;
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
72
bin/periphery/src/api/swarm/stack.rs
Normal file
72
bin/periphery/src/api/swarm/stack.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use command::run_komodo_standard_command;
|
||||
use komodo_client::entities::{
|
||||
docker::stack::SwarmStack, update::Log,
|
||||
};
|
||||
use periphery_client::api::swarm::{
|
||||
DeploySwarmStack, InspectSwarmStack, RemoveSwarmStacks,
|
||||
};
|
||||
use resolver_api::Resolve;
|
||||
|
||||
use crate::docker::stack::inspect_swarm_stack;
|
||||
|
||||
impl Resolve<crate::api::Args> for InspectSwarmStack {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<SwarmStack> {
|
||||
inspect_swarm_stack(self.stack).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for RemoveSwarmStacks {
|
||||
#[instrument(
|
||||
"RemoveSwarmStacks",
|
||||
skip_all,
|
||||
fields(
|
||||
id = args.id.to_string(),
|
||||
core = args.core,
|
||||
stacks = serde_json::to_string(&self.stacks).unwrap_or_else(|e| e.to_string()),
|
||||
)
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Log> {
|
||||
let mut command = String::from("docker stack rm");
|
||||
// This defaults to true, only need when false
|
||||
if !self.detach {
|
||||
command += " --detach=false"
|
||||
}
|
||||
for stack in self.stacks {
|
||||
command += " ";
|
||||
command += &stack;
|
||||
}
|
||||
Ok(
|
||||
run_komodo_standard_command(
|
||||
"Remove Swarm Stacks",
|
||||
None,
|
||||
command,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve<crate::api::Args> for DeploySwarmStack {
|
||||
#[instrument(
|
||||
"DeploySwarmStack",
|
||||
skip_all,
|
||||
fields(
|
||||
id = args.id.to_string(),
|
||||
core = args.core,
|
||||
stack = self.stack.name,
|
||||
repo = self.repo.as_ref().map(|repo| &repo.name),
|
||||
)
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,10 @@ use crate::{
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for ListTerminals {
|
||||
impl Resolve<crate::api::Args> for ListTerminals {
|
||||
async fn resolve(
|
||||
self,
|
||||
_: &super::Args,
|
||||
_: &crate::api::Args,
|
||||
) -> anyhow::Result<Vec<Terminal>> {
|
||||
clean_up_terminals().await;
|
||||
Ok(list_terminals(self.target.as_ref()).await)
|
||||
@@ -37,7 +37,7 @@ impl Resolve<super::Args> for ListTerminals {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for CreateServerTerminal {
|
||||
impl Resolve<crate::api::Args> for CreateServerTerminal {
|
||||
#[instrument(
|
||||
"CreateServerTerminal",
|
||||
skip_all,
|
||||
@@ -51,7 +51,7 @@ impl Resolve<super::Args> for CreateServerTerminal {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<NoData> {
|
||||
if periphery_config().disable_terminals {
|
||||
return Err(anyhow!(
|
||||
@@ -71,7 +71,7 @@ impl Resolve<super::Args> for CreateServerTerminal {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for CreateContainerExecTerminal {
|
||||
impl Resolve<crate::api::Args> for CreateContainerExecTerminal {
|
||||
#[instrument(
|
||||
"CreateContainerExecTerminal",
|
||||
skip_all,
|
||||
@@ -86,7 +86,7 @@ impl Resolve<super::Args> for CreateContainerExecTerminal {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<NoData> {
|
||||
if periphery_config().disable_container_terminals {
|
||||
return Err(anyhow!(
|
||||
@@ -119,7 +119,7 @@ impl Resolve<super::Args> for CreateContainerExecTerminal {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for CreateContainerAttachTerminal {
|
||||
impl Resolve<crate::api::Args> for CreateContainerAttachTerminal {
|
||||
#[instrument(
|
||||
"CreateContainerAttachTerminal",
|
||||
skip_all,
|
||||
@@ -133,7 +133,7 @@ impl Resolve<super::Args> for CreateContainerAttachTerminal {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<NoData> {
|
||||
if periphery_config().disable_container_terminals {
|
||||
return Err(anyhow!(
|
||||
@@ -164,7 +164,7 @@ impl Resolve<super::Args> for CreateContainerAttachTerminal {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for DeleteTerminal {
|
||||
impl Resolve<crate::api::Args> for DeleteTerminal {
|
||||
#[instrument(
|
||||
"DeleteTerminal",
|
||||
skip_all,
|
||||
@@ -176,7 +176,7 @@ impl Resolve<super::Args> for DeleteTerminal {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<NoData> {
|
||||
delete_terminal(&self.target, &self.terminal).await;
|
||||
Ok(NoData {})
|
||||
@@ -185,7 +185,7 @@ impl Resolve<super::Args> for DeleteTerminal {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for DeleteAllTerminals {
|
||||
impl Resolve<crate::api::Args> for DeleteAllTerminals {
|
||||
#[instrument(
|
||||
"DeleteAllTerminals",
|
||||
skip_all,
|
||||
@@ -196,7 +196,7 @@ impl Resolve<super::Args> for DeleteAllTerminals {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<NoData> {
|
||||
delete_all_terminals().await;
|
||||
Ok(NoData {})
|
||||
@@ -205,7 +205,7 @@ impl Resolve<super::Args> for DeleteAllTerminals {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for ConnectTerminal {
|
||||
impl Resolve<crate::api::Args> for ConnectTerminal {
|
||||
#[instrument(
|
||||
"ConnectTerminal",
|
||||
skip_all,
|
||||
@@ -215,7 +215,10 @@ impl Resolve<super::Args> for ConnectTerminal {
|
||||
terminal = self.terminal,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Uuid> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Uuid> {
|
||||
let connection =
|
||||
core_connections().get(&args.core).await.with_context(
|
||||
|| format!("Failed to find channel for {}", args.core),
|
||||
@@ -234,7 +237,7 @@ impl Resolve<super::Args> for ConnectTerminal {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for DisconnectTerminal {
|
||||
impl Resolve<crate::api::Args> for DisconnectTerminal {
|
||||
#[instrument(
|
||||
"DisconnectTerminal",
|
||||
skip_all,
|
||||
@@ -246,7 +249,7 @@ impl Resolve<super::Args> for DisconnectTerminal {
|
||||
)]
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &super::Args,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<NoData> {
|
||||
terminal_channels().remove(&self.channel).await;
|
||||
Ok(NoData {})
|
||||
@@ -255,7 +258,7 @@ impl Resolve<super::Args> for DisconnectTerminal {
|
||||
|
||||
//
|
||||
|
||||
impl Resolve<super::Args> for ExecuteTerminal {
|
||||
impl Resolve<crate::api::Args> for ExecuteTerminal {
|
||||
#[instrument(
|
||||
"ExecuteTerminal",
|
||||
skip_all,
|
||||
@@ -266,7 +269,10 @@ impl Resolve<super::Args> for ExecuteTerminal {
|
||||
command = self.command,
|
||||
)
|
||||
)]
|
||||
async fn resolve(self, args: &super::Args) -> anyhow::Result<Uuid> {
|
||||
async fn resolve(
|
||||
self,
|
||||
args: &crate::api::Args,
|
||||
) -> anyhow::Result<Uuid> {
|
||||
let channel =
|
||||
core_connections().get(&args.core).await.with_context(
|
||||
|| format!("Failed to find channel for {}", args.core),
|
||||
|
||||
@@ -34,7 +34,7 @@ impl DockerClient {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether build result should be pushed after build
|
||||
/// Returns whether login was actually performed.
|
||||
#[instrument("DockerLogin", skip(registry_token))]
|
||||
pub async fn docker_login(
|
||||
domain: &str,
|
||||
@@ -45,30 +45,33 @@ pub async fn docker_login(
|
||||
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 = run_shell_command(&format!(
|
||||
"echo {registry_token} | docker login {domain} --username '{account}' --password-stdin",
|
||||
), None)
|
||||
.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")))
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
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("PullImage")]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
net::IpAddr, path::PathBuf, str::FromStr as _, sync::OnceLock,
|
||||
time::Duration,
|
||||
fmt::Write, net::IpAddr, path::PathBuf, str::FromStr as _,
|
||||
sync::OnceLock, time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
@@ -14,6 +14,7 @@ use komodo_client::{
|
||||
entities::{
|
||||
EnvironmentVar, RepoExecutionArgs, RepoExecutionResponse,
|
||||
SearchCombinator, SystemCommand, all_logs_success,
|
||||
deployment::Conversion,
|
||||
},
|
||||
parsers::QUOTE_PATTERN,
|
||||
};
|
||||
@@ -34,6 +35,17 @@ pub fn format_extra_args(extra_args: &[String]) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_extra_args(
|
||||
command: &mut String,
|
||||
extra_args: &[String],
|
||||
) -> anyhow::Result<()> {
|
||||
for arg in extra_args {
|
||||
write!(command, " {arg}")
|
||||
.context("Failed to write extra args to command")?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn format_labels(labels: &[EnvironmentVar]) -> String {
|
||||
labels
|
||||
.iter()
|
||||
@@ -51,6 +63,56 @@ pub fn format_labels(labels: &[EnvironmentVar]) -> String {
|
||||
.join("")
|
||||
}
|
||||
|
||||
pub fn push_labels(
|
||||
command: &mut String,
|
||||
labels: &[EnvironmentVar],
|
||||
) -> anyhow::Result<()> {
|
||||
for label in labels {
|
||||
if label.value.starts_with(QUOTE_PATTERN)
|
||||
&& label.value.ends_with(QUOTE_PATTERN)
|
||||
{
|
||||
write!(command, " --label {}={}", label.variable, label.value)
|
||||
} else {
|
||||
write!(
|
||||
command,
|
||||
" --label {}=\"{}\"",
|
||||
label.variable, label.value
|
||||
)
|
||||
}
|
||||
.context("Failed to write labels to command")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_conversions(
|
||||
command: &mut String,
|
||||
conversions: &[Conversion],
|
||||
flag: &str,
|
||||
) -> anyhow::Result<()> {
|
||||
for Conversion { local, container } in conversions {
|
||||
write!(command, " {flag} {local}:{container}")
|
||||
.context("Failed to format conversions")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_environment(
|
||||
command: &mut String,
|
||||
environment: &[EnvironmentVar],
|
||||
) -> anyhow::Result<()> {
|
||||
for EnvironmentVar { variable, value } in environment {
|
||||
if value.starts_with(QUOTE_PATTERN)
|
||||
&& value.ends_with(QUOTE_PATTERN)
|
||||
{
|
||||
write!(command, " --env {variable}={value}")
|
||||
} else {
|
||||
write!(command, " --env {variable}=\"{value}\"")
|
||||
}
|
||||
.context("Failed to format environment")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn format_log_grep(
|
||||
terms: &[String],
|
||||
combinator: SearchCombinator,
|
||||
|
||||
@@ -5,7 +5,7 @@ use derive_default_builder::DefaultBuilder;
|
||||
use derive_variants::EnumVariants;
|
||||
use partial_derive2::Partial;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{Display, EnumString};
|
||||
use strum::{AsRefStr, Display, EnumString};
|
||||
use typeshare::typeshare;
|
||||
|
||||
use crate::{
|
||||
@@ -58,7 +58,19 @@ pub type _PartialDeploymentConfig = PartialDeploymentConfig;
|
||||
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
#[partial(skip_serializing_none, from, diff)]
|
||||
pub struct DeploymentConfig {
|
||||
/// The id of server the deployment is deployed on.
|
||||
/// The Swarm to deploy the Deployment on (as a Swarm Service), setting the Deployment into Swarm mode.
|
||||
///
|
||||
/// Note. If both swarm_id and server_id are set,
|
||||
/// swarm_id overrides server_id and the Deployment will be in Swarm mode.
|
||||
#[serde(default, alias = "swarm")]
|
||||
#[partial_attr(serde(alias = "swarm"))]
|
||||
#[builder(default)]
|
||||
pub swarm_id: String,
|
||||
|
||||
/// The Server to deploy the Deployment on, setting the Deployment into Container mode.
|
||||
///
|
||||
/// Note. If both swarm_id and server_id are set,
|
||||
/// swarm_id overrides server_id and the Deployment will be in Swarm mode.
|
||||
#[serde(default, alias = "server")]
|
||||
#[partial_attr(serde(alias = "server"))]
|
||||
#[builder(default)]
|
||||
@@ -134,6 +146,14 @@ pub struct DeploymentConfig {
|
||||
#[builder(default)]
|
||||
pub command: String,
|
||||
|
||||
/// The number of replicas for the Service.
|
||||
///
|
||||
/// Note. Only used in Swarm mode.
|
||||
#[serde(default = "default_replicas")]
|
||||
#[builder(default = "default_replicas()")]
|
||||
#[partial_default(default_replicas())]
|
||||
pub replicas: i32,
|
||||
|
||||
/// The default termination signal to use to stop the deployment. Defaults to SigTerm (default docker signal).
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
@@ -145,7 +165,8 @@ pub struct DeploymentConfig {
|
||||
#[partial_default(default_termination_timeout())]
|
||||
pub termination_timeout: i32,
|
||||
|
||||
/// Extra args which are interpolated into the `docker run` command,
|
||||
/// Extra args which are interpolated into the
|
||||
/// `docker run` / `docker service create` command,
|
||||
/// and affect the container configuration.
|
||||
#[serde(default, deserialize_with = "string_list_deserializer")]
|
||||
#[partial_attr(serde(
|
||||
@@ -156,7 +177,8 @@ pub struct DeploymentConfig {
|
||||
pub extra_args: Vec<String>,
|
||||
|
||||
/// Labels attached to various termination signal options.
|
||||
/// Used to specify different shutdown functionality depending on the termination signal.
|
||||
/// Used to specify different shutdown functionality depending
|
||||
/// on the termination signal.
|
||||
#[serde(default, deserialize_with = "term_labels_deserializer")]
|
||||
#[partial_attr(serde(
|
||||
default,
|
||||
@@ -186,7 +208,7 @@ pub struct DeploymentConfig {
|
||||
#[builder(default)]
|
||||
pub volumes: String,
|
||||
|
||||
/// The environment variables passed to the container.
|
||||
/// The environment variables passed to the container / service.
|
||||
#[serde(default, deserialize_with = "env_vars_deserializer")]
|
||||
#[partial_attr(serde(
|
||||
default,
|
||||
@@ -216,6 +238,10 @@ impl DeploymentConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn default_replicas() -> i32 {
|
||||
1
|
||||
}
|
||||
|
||||
fn default_send_alerts() -> bool {
|
||||
true
|
||||
}
|
||||
@@ -231,26 +257,28 @@ fn default_network() -> String {
|
||||
impl Default for DeploymentConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
swarm_id: Default::default(),
|
||||
server_id: Default::default(),
|
||||
send_alerts: default_send_alerts(),
|
||||
links: Default::default(),
|
||||
image: Default::default(),
|
||||
image_registry_account: Default::default(),
|
||||
skip_secret_interp: Default::default(),
|
||||
redeploy_on_build: Default::default(),
|
||||
poll_for_updates: Default::default(),
|
||||
auto_update: Default::default(),
|
||||
term_signal_labels: Default::default(),
|
||||
send_alerts: default_send_alerts(),
|
||||
links: Default::default(),
|
||||
network: default_network(),
|
||||
restart: Default::default(),
|
||||
command: Default::default(),
|
||||
replicas: default_replicas(),
|
||||
termination_signal: Default::default(),
|
||||
termination_timeout: default_termination_timeout(),
|
||||
extra_args: Default::default(),
|
||||
term_signal_labels: Default::default(),
|
||||
ports: Default::default(),
|
||||
volumes: Default::default(),
|
||||
environment: Default::default(),
|
||||
labels: Default::default(),
|
||||
network: default_network(),
|
||||
restart: Default::default(),
|
||||
command: Default::default(),
|
||||
extra_args: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,6 +427,7 @@ impl From<ContainerStateStatusEnum> for DeploymentState {
|
||||
Default,
|
||||
Display,
|
||||
EnumString,
|
||||
AsRefStr,
|
||||
)]
|
||||
pub enum RestartMode {
|
||||
#[default]
|
||||
|
||||
@@ -278,7 +278,19 @@ pub type _PartialStackConfig = PartialStackConfig;
|
||||
#[partial_derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
#[partial(skip_serializing_none, from, diff)]
|
||||
pub struct StackConfig {
|
||||
/// The server to deploy the stack on.
|
||||
/// The Swarm to deploy the Stack on, setting the Stack into Swarm mode.
|
||||
///
|
||||
/// Note. If both swarm_id and server_id are set,
|
||||
/// swarm_id overrides server_id and the Stack will be in Swarm mode.
|
||||
#[serde(default, alias = "swarm")]
|
||||
#[partial_attr(serde(alias = "swarm"))]
|
||||
#[builder(default)]
|
||||
pub swarm_id: String,
|
||||
|
||||
/// The Server to deploy the Stack on, setting the Stack into Compose mode.
|
||||
///
|
||||
/// Note. If both swarm_id and server_id are set,
|
||||
/// swarm_id overrides server_id and the Stack will be in Swarm mode.
|
||||
#[serde(default, alias = "server")]
|
||||
#[partial_attr(serde(alias = "server"))]
|
||||
#[builder(default)]
|
||||
@@ -295,9 +307,9 @@ pub struct StackConfig {
|
||||
|
||||
/// Optionally specify a custom project name for the stack.
|
||||
/// If this is empty string, it will default to the stack name.
|
||||
/// Used with `docker compose -p {project_name}`.
|
||||
/// Used with `docker compose -p {project_name}` / `docker stack deploy {project_name}`.
|
||||
///
|
||||
/// Note. Can be used to import pre-existing stacks.
|
||||
/// Note. Can be used to import pre-existing stacks with names that do not match Stack name.
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
pub project_name: String,
|
||||
@@ -305,6 +317,8 @@ pub struct StackConfig {
|
||||
/// Whether to automatically `compose pull` before redeploying stack.
|
||||
/// Ensured latest images are deployed.
|
||||
/// Will fail if the compose file specifies a locally build image.
|
||||
///
|
||||
/// Note. Not used in Swarm mode.
|
||||
#[serde(default = "default_auto_pull")]
|
||||
#[builder(default = "default_auto_pull()")]
|
||||
#[partial_default(default_auto_pull())]
|
||||
@@ -312,6 +326,8 @@ pub struct StackConfig {
|
||||
|
||||
/// Whether to `docker compose build` before `compose down` / `compose up`.
|
||||
/// Combine with build_extra_args for custom behaviors.
|
||||
///
|
||||
/// Note. Not used in Swarm mode.
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
pub run_build: bool,
|
||||
@@ -447,6 +463,8 @@ pub struct StackConfig {
|
||||
/// The name of the written environment file before `docker compose up`.
|
||||
/// Relative to the run directory root.
|
||||
/// Default: .env
|
||||
///
|
||||
/// Note. Not used in Swarm mode.
|
||||
#[serde(default = "default_env_file_path")]
|
||||
#[builder(default = "default_env_file_path()")]
|
||||
#[partial_default(default_env_file_path())]
|
||||
@@ -500,7 +518,11 @@ pub struct StackConfig {
|
||||
#[builder(default)]
|
||||
pub post_deploy: SystemCommand,
|
||||
|
||||
/// The extra arguments to pass after `docker compose up -d`.
|
||||
/// The extra arguments to pass to the deploy command.
|
||||
///
|
||||
/// - For Compose stack, uses `docker compose up -d [EXTRA_ARGS]`.
|
||||
/// - For Swarm mode. `docker stack deploy [OPTIONS] STACK`
|
||||
///
|
||||
/// If empty, no extra arguments will be passed.
|
||||
#[serde(default, deserialize_with = "string_list_deserializer")]
|
||||
#[partial_attr(serde(
|
||||
@@ -513,6 +535,8 @@ pub struct StackConfig {
|
||||
/// The extra arguments to pass after `docker compose build`.
|
||||
/// If empty, no extra build arguments will be passed.
|
||||
/// Only used if `run_build: true`
|
||||
///
|
||||
/// Note. Not used in Swarm mode.
|
||||
#[serde(default, deserialize_with = "string_list_deserializer")]
|
||||
#[partial_attr(serde(
|
||||
default,
|
||||
@@ -560,6 +584,8 @@ pub struct StackConfig {
|
||||
/// which is given relative to the run directory.
|
||||
///
|
||||
/// If it is empty, no file will be written.
|
||||
///
|
||||
/// Note. Not used in Swarm mode.
|
||||
#[serde(default, deserialize_with = "env_vars_deserializer")]
|
||||
#[partial_attr(serde(
|
||||
default,
|
||||
@@ -611,6 +637,7 @@ fn default_send_alerts() -> bool {
|
||||
impl Default for StackConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
swarm_id: Default::default(),
|
||||
server_id: Default::default(),
|
||||
project_name: Default::default(),
|
||||
run_directory: Default::default(),
|
||||
@@ -688,6 +715,9 @@ pub struct StackServiceNames {
|
||||
///
|
||||
/// This stores only 1. and 2., ie stacko-mongo.
|
||||
/// Containers will be matched via regex like `^container_name-?[0-9]*$``
|
||||
///
|
||||
/// Note. Setting container_name is not supported by Swarm,
|
||||
/// so will always be 1. and 2. in Swarm mode.
|
||||
pub container_name: String,
|
||||
/// The services image.
|
||||
#[serde(default)]
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
use komodo_client::entities::{
|
||||
FileContents, RepoExecutionResponse, SearchCombinator,
|
||||
repo::Repo,
|
||||
stack::{
|
||||
Stack, StackFileDependency, StackRemoteFileContents,
|
||||
StackServiceNames,
|
||||
},
|
||||
stack::{Stack, StackFileDependency, StackRemoteFileContents},
|
||||
update::Log,
|
||||
};
|
||||
use resolver_api::Resolve;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::api::DeployStackResponse;
|
||||
|
||||
//
|
||||
|
||||
/// Get the compose contents on the host, for stacks using
|
||||
@@ -165,7 +164,7 @@ pub struct ComposePullResponse {
|
||||
|
||||
/// docker compose up.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Resolve)]
|
||||
#[response(ComposeUpResponse)]
|
||||
#[response(DeployStackResponse)]
|
||||
#[error(anyhow::Error)]
|
||||
pub struct ComposeUp {
|
||||
/// The stack to deploy
|
||||
@@ -185,31 +184,6 @@ pub struct ComposeUp {
|
||||
pub replacers: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct ComposeUpResponse {
|
||||
/// If any of the required files are missing, they will be here.
|
||||
pub missing_files: Vec<String>,
|
||||
/// The logs produced by the deploy
|
||||
pub logs: Vec<Log>,
|
||||
/// Whether stack was successfully deployed
|
||||
pub deployed: bool,
|
||||
/// The stack services.
|
||||
///
|
||||
/// Note. The "image" is after interpolation.
|
||||
#[serde(default)]
|
||||
pub services: Vec<StackServiceNames>,
|
||||
/// The deploy compose file contents if they could be acquired, or empty vec.
|
||||
pub file_contents: Vec<StackRemoteFileContents>,
|
||||
/// The error in getting remote file contents at the path, or null
|
||||
pub remote_errors: Vec<FileContents>,
|
||||
/// The output of `docker compose config` at deploy time
|
||||
pub compose_config: Option<String>,
|
||||
/// If its a repo based stack, will include the latest commit hash
|
||||
pub commit_hash: Option<String>,
|
||||
/// If its a repo based stack, will include the latest commit message
|
||||
pub commit_message: Option<String>,
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
|
||||
@@ -87,10 +87,12 @@ pub struct GetFullContainerStats {
|
||||
// ACTIONS
|
||||
// =======
|
||||
|
||||
/// Executes `docker run` to create a container
|
||||
/// using info given by the Deployment
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Resolve)]
|
||||
#[response(Log)]
|
||||
#[error(anyhow::Error)]
|
||||
pub struct Deploy {
|
||||
pub struct RunContainer {
|
||||
pub deployment: Deployment,
|
||||
pub stop_signal: Option<TerminationSignal>,
|
||||
pub stop_time: Option<i32>,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use komodo_client::entities::{
|
||||
FileContents,
|
||||
config::{DockerRegistry, GitProvider},
|
||||
stack::{StackRemoteFileContents, StackServiceNames},
|
||||
update::Log,
|
||||
};
|
||||
use resolver_api::Resolve;
|
||||
@@ -83,3 +85,27 @@ pub struct ListSecrets {}
|
||||
#[response(Log)]
|
||||
#[error(anyhow::Error)]
|
||||
pub struct PruneSystem {}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct DeployStackResponse {
|
||||
/// If any of the required files are missing, they will be here.
|
||||
pub missing_files: Vec<String>,
|
||||
/// The logs produced by the deploy
|
||||
pub logs: Vec<Log>,
|
||||
/// Whether stack was successfully deployed
|
||||
pub deployed: bool,
|
||||
/// The stack services.
|
||||
///
|
||||
/// Note. The "image" is after interpolation.
|
||||
pub services: Vec<StackServiceNames>,
|
||||
/// The deploy compose file contents if they could be acquired, or empty vec.
|
||||
pub file_contents: Vec<StackRemoteFileContents>,
|
||||
/// The error in getting remote file contents at the path, or null
|
||||
pub remote_errors: Vec<FileContents>,
|
||||
/// The output of `docker compose config` / `docker stack config` at deploy time
|
||||
pub merged_config: Option<String>,
|
||||
/// If its a repo based stack, will include the latest commit hash
|
||||
pub commit_hash: Option<String>,
|
||||
/// If its a repo based stack, will include the latest commit message
|
||||
pub commit_message: Option<String>,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||
|
||||
use komodo_client::entities::{
|
||||
SearchCombinator,
|
||||
deployment::Deployment,
|
||||
docker::{
|
||||
SwarmLists,
|
||||
config::SwarmConfig,
|
||||
@@ -12,11 +13,15 @@ use komodo_client::entities::{
|
||||
swarm::SwarmInspectInfo,
|
||||
task::SwarmTask,
|
||||
},
|
||||
repo::Repo,
|
||||
stack::Stack,
|
||||
update::Log,
|
||||
};
|
||||
use resolver_api::Resolve;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::api::DeployStackResponse;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Resolve)]
|
||||
#[response(PollSwarmStatusResponse)]
|
||||
#[error(anyhow::Error)]
|
||||
@@ -81,6 +86,26 @@ pub struct InspectSwarmStack {
|
||||
pub stack: String,
|
||||
}
|
||||
|
||||
/// `docker stack deploy [OPTIONS] STACK`
|
||||
///
|
||||
/// https://docs.docker.com/reference/cli/docker/stack/deploy/
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Resolve)]
|
||||
#[response(DeployStackResponse)]
|
||||
#[error(anyhow::Error)]
|
||||
pub struct DeploySwarmStack {
|
||||
/// The stack to deploy
|
||||
pub stack: Stack,
|
||||
/// The linked repo, if it exists.
|
||||
pub repo: Option<Repo>,
|
||||
/// If provided, use it to login in. Otherwise check periphery local registries.
|
||||
pub git_token: Option<String>,
|
||||
/// If provided, use it to login in. Otherwise check periphery local git providers.
|
||||
pub registry_token: Option<String>,
|
||||
/// Propogate any secret replacers from core interpolation.
|
||||
#[serde(default)]
|
||||
pub replacers: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
/// `docker stack rm [OPTIONS] STACK [STACK...]`
|
||||
///
|
||||
/// https://docs.docker.com/reference/cli/docker/stack/rm/
|
||||
@@ -170,6 +195,21 @@ pub struct GetSwarmServiceLogSearch {
|
||||
pub details: bool,
|
||||
}
|
||||
|
||||
/// `docker service create [OPTIONS] IMAGE [COMMAND] [ARG...]`
|
||||
///
|
||||
/// https://docs.docker.com/reference/cli/docker/service/create/
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Resolve)]
|
||||
#[response(Log)]
|
||||
#[error(anyhow::Error)]
|
||||
pub struct CreateSwarmService {
|
||||
pub deployment: Deployment,
|
||||
/// Override registry token with one sent from core.
|
||||
pub registry_token: Option<String>,
|
||||
/// Propogate any secret replacers from core interpolation.
|
||||
#[serde(default)]
|
||||
pub replacers: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
/// `docker service rm SERVICE [SERVICE...]`
|
||||
///
|
||||
/// https://docs.docker.com/reference/cli/docker/service/rm/
|
||||
|
||||
Reference in New Issue
Block a user