Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 35 additions & 13 deletions bin/core/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,10 @@ async fn set_default_gateway(
));
}

// Remove existing default routes
let remove_default = Command::new("sh")
.args(["-c", "ip route del default 2>/dev/null || true"])
// Remove existing default routes. Failure is ignored because the route may
// not exist yet.
let remove_default = Command::new("ip")
.args(["route", "del", "default"])
.output()
.await;

Expand All @@ -272,13 +273,21 @@ async fn set_default_gateway(
}

// Add new default route
let add_default_cmd = format!(
"ip route add default via {gateway} dev {interface_name}"
trace!(
"Adding default route: ip route add default via {} dev {}",
gateway, interface_name
);
trace!("Adding default route: {}", add_default_cmd);

let add_default = Command::new("sh")
.args(["-c", &add_default_cmd])
let add_default = Command::new("ip")
.args([
"route",
"add",
"default",
"via",
gateway,
"dev",
interface_name,
])
.output()
.await
.context("Failed to add default route")?;
Expand All @@ -302,10 +311,23 @@ async fn set_default_gateway(
/// Check if we have sufficient network privileges
async fn check_network_privileges() -> bool {
// Try to test NET_ADMIN capability with a harmless route operation
let capability_test = Command::new("sh")
.args(["-c", "ip route add 198.51.100.1/32 dev lo 2>/dev/null && ip route del 198.51.100.1/32 dev lo 2>/dev/null"])
.output()
.await;
let add_test = Command::new("ip")
.args(["route", "add", "198.51.100.1/32", "dev", "lo"])
.output()
.await;

let Ok(output) = add_test else {
return false;
};

if !output.status.success() {
return false;
}

let del_test = Command::new("ip")
.args(["route", "del", "198.51.100.1/32", "dev", "lo"])
.output()
.await;

matches!(capability_test, Ok(output) if output.status.success())
matches!(del_test, Ok(output) if output.status.success())
}
2 changes: 1 addition & 1 deletion bin/periphery/src/api/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ impl Resolve<crate::api::Args> for build::Build {
"Docker Build",
build_path.as_ref(),
command,
KomodoCommandMode::Shell,
KomodoCommandMode::Standard,
&replacers,
)
.instrument(span)
Expand Down
58 changes: 42 additions & 16 deletions bin/periphery/src/api/compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{borrow::Cow, fmt::Write, path::PathBuf};
use anyhow::{Context, anyhow};
use command::{
KomodoCommandMode, run_komodo_command_with_sanitization,
run_komodo_shell_command, run_komodo_standard_command,
run_komodo_standard_command,
};
use formatting::format_serror;
use git::write_commit_file;
Expand All @@ -29,7 +29,7 @@ use tracing::Instrument;
use crate::{
config::periphery_config,
docker::compose::docker_compose,
helpers::{format_extra_args, format_log_grep},
helpers::{format_extra_args, run_log_search},
stack::{
maybe_login_registry, pull_or_clone_stack, validate_files,
write::write_stack,
Expand Down Expand Up @@ -78,19 +78,35 @@ impl Resolve<crate::api::Args> for GetComposeLogSearch {
timestamps,
} = self;
let docker_compose = docker_compose();
let grep = format_log_grep(&terms, combinator, invert);
let timestamps = if timestamps {
" --timestamps"
let mut args = vec![
"-p".to_string(),
project,
"logs".to_string(),
"--tail".to_string(),
"5000".to_string(),
];
if timestamps {
args.push("--timestamps".to_string());
}
args.extend(services);
let (program, args) = if docker_compose == "docker compose" {
let mut prefixed = vec!["compose".to_string()];
prefixed.extend(args);
("docker", prefixed)
} else {
Default::default()
(docker_compose, args)
};
let command = format!(
"{docker_compose} -p {project} logs --tail 5000{timestamps} {} 2>&1 | {grep}",
services.join(" ")
);
Ok(
run_komodo_shell_command("Search Stack Log", None, command)
.await,
run_log_search(
"Search Stack Log",
None,
program,
args,
&terms,
combinator,
invert,
)
.await,
)
}
}
Expand Down Expand Up @@ -722,7 +738,7 @@ impl Resolve<crate::api::Args> for ComposeUp {
let command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} up -d{extra_args}{service_args}",
);
let (command, _) = match maybe_wrap_command(
let (command, wrapped) = match maybe_wrap_command(
command,
&compose_cmd_wrapper,
wrapper_include,
Expand All @@ -735,12 +751,17 @@ impl Resolve<crate::api::Args> for ComposeUp {
}
};

let mode = if wrapped {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let span = info_span!("ExecuteComposeUp");
let Some(log) = run_komodo_command_with_sanitization(
"Compose Up",
run_directory.as_path(),
command,
KomodoCommandMode::Shell,
mode,
&replacers,
)
.instrument(span)
Expand Down Expand Up @@ -981,7 +1002,7 @@ impl Resolve<crate::api::Args> for ComposeRun {
let run_command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} run{run_flags} {service}{command_args}",
);
let (run_command, _) = match maybe_wrap_command(
let (run_command, wrapped) = match maybe_wrap_command(
run_command,
&compose_cmd_wrapper,
wrapper_include,
Expand All @@ -991,12 +1012,17 @@ impl Resolve<crate::api::Args> for ComposeRun {
Err(log) => return Ok(log),
};

let mode = if wrapped {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let span = info_span!("RunComposeRun", run_command);
let Some(log) = run_komodo_command_with_sanitization(
"Compose Run",
run_directory.as_path(),
run_command,
KomodoCommandMode::Shell,
mode,
&replacers,
)
.instrument(span)
Expand Down
112 changes: 81 additions & 31 deletions bin/periphery/src/api/container/mod.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
use anyhow::Context;
use command::{
run_komodo_shell_command, run_komodo_standard_command,
command_string, run_command_args, run_komodo_standard_command,
};
use futures_util::future::join_all;
use komodo_client::entities::{
docker::{
container::{Container, ContainerListItem, ContainerStats},
stats::FullContainerStats,
},
komodo_timestamp,
update::Log,
};
use mogh_resolver::Resolve;
use periphery_client::api::container::*;

use crate::{
docker::{stats::get_container_stats, stop_container_command},
helpers::format_log_grep,
helpers::run_log_search,
state::docker_client,
};

Expand Down Expand Up @@ -81,20 +82,24 @@ impl Resolve<crate::api::Args> for GetContainerLogSearch {
invert,
timestamps,
} = self;
let grep = format_log_grep(&terms, combinator, invert);
let timestamps = if timestamps {
" --timestamps"
} else {
Default::default()
};
let command = format!(
"docker logs {name} --tail 5000{timestamps} 2>&1 | {grep}"
);
let mut args = vec![
"logs".to_string(),
name,
"--tail".to_string(),
"5000".to_string(),
];
if timestamps {
args.push("--timestamps".to_string());
}
Ok(
run_komodo_shell_command(
run_log_search(
"Get container log grep",
None,
command,
"docker",
args,
&terms,
combinator,
invert,
)
.await,
)
Expand Down Expand Up @@ -307,25 +312,10 @@ impl Resolve<crate::api::Args> for RemoveContainer {
args: &crate::api::Args,
) -> anyhow::Result<Log> {
let RemoveContainer { name, signal, time } = self;
let stop_command = stop_container_command(&name, signal, time);
let command =
format!("{stop_command} && docker container rm {name}");
let log = run_komodo_shell_command(
"Docker Stop and Remove",
None,
command,
)
.await;
let log = stop_and_remove_container(&name, signal, time).await;
if log.stderr.contains("unknown flag: --signal") {
let stop_command = stop_container_command(&name, None, time);
let command =
format!("{stop_command} && docker container rm {name}");
let mut log = run_komodo_shell_command(
"Docker Stop and Remove",
None,
command,
)
.await;
let mut log =
stop_and_remove_container(&name, None, time).await;
log.stderr = format!(
"Old docker version: unable to use --signal flag{}",
if !log.stderr.is_empty() {
Expand All @@ -341,6 +331,66 @@ impl Resolve<crate::api::Args> for RemoveContainer {
}
}

async fn stop_and_remove_container(
name: &str,
signal: Option<komodo_client::entities::TerminationSignal>,
time: Option<i32>,
) -> Log {
let stop_args = stop_container_args(name, signal, time);
let rm_args =
vec!["container".to_string(), "rm".to_string(), name.to_string()];
let command = format!(
"{} && {}",
command_string("docker", &stop_args),
command_string("docker", &rm_args)
);
let start_ts = komodo_timestamp();

let stop_output =
run_command_args("docker", &stop_args, None, None).await;
if !stop_output.success() {
return Log {
stage: "Docker Stop and Remove".to_string(),
stdout: stop_output.stdout,
stderr: stop_output.stderr,
command,
success: false,
start_ts,
end_ts: komodo_timestamp(),
};
}

let rm_output =
run_command_args("docker", &rm_args, None, None).await;
Log {
stage: "Docker Stop and Remove".to_string(),
stdout: format!("{}{}", stop_output.stdout, rm_output.stdout),
stderr: format!("{}{}", stop_output.stderr, rm_output.stderr),
command,
success: rm_output.success(),
start_ts,
end_ts: komodo_timestamp(),
}
}

fn stop_container_args(
name: &str,
signal: Option<komodo_client::entities::TerminationSignal>,
time: Option<i32>,
) -> Vec<String> {
let mut args = vec!["stop".to_string()];
if let Some(signal) = signal {
args.push("--signal".to_string());
args.push(signal.to_string());
}
if let Some(time) = time {
args.push("--time".to_string());
args.push(time.to_string());
}
args.push(name.to_string());
args
}

//

impl Resolve<crate::api::Args> for RenameContainer {
Expand Down
2 changes: 1 addition & 1 deletion bin/periphery/src/api/container/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl Resolve<crate::api::Args> for RunContainer {
"Docker Run",
None,
command,
KomodoCommandMode::Shell,
KomodoCommandMode::Standard,
&replacers,
)
.instrument(span)
Expand Down
Loading