mirror of
https://github.com/logos-blockchain/logos-blockchain-testing.git
synced 2026-01-02 13:23:13 +00:00
Restructure compose runner modules
This commit is contained in:
parent
e7c4bccaa6
commit
daa8f6a129
@ -5,8 +5,11 @@ use testing_framework_core::{
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
block_feed::spawn_block_feed_with_retry, environment::StackEnvironment,
|
||||
errors::ComposeRunnerError, ports::HostPortMapping, readiness::build_node_clients_with_ports,
|
||||
errors::ComposeRunnerError,
|
||||
infrastructure::{environment::StackEnvironment, ports::HostPortMapping},
|
||||
lifecycle::{
|
||||
block_feed::spawn_block_feed_with_retry, readiness::build_node_clients_with_ports,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct ClientBuilder;
|
||||
|
||||
@ -9,7 +9,7 @@ use testing_framework_core::scenario::{
|
||||
BlockFeedTask, CleanupGuard, Deployer, RequiresNodeControl, Runner, Scenario,
|
||||
};
|
||||
|
||||
use crate::{cleanup::RunnerCleanup, errors::ComposeRunnerError};
|
||||
use crate::{errors::ComposeRunnerError, lifecycle::cleanup::RunnerCleanup};
|
||||
|
||||
/// Docker Compose-based deployer for Nomos test scenarios.
|
||||
#[derive(Clone, Copy)]
|
||||
|
||||
@ -14,8 +14,10 @@ use super::{
|
||||
setup::{DeploymentContext, DeploymentSetup},
|
||||
};
|
||||
use crate::{
|
||||
control::ComposeNodeControl, errors::ComposeRunnerError, ports::compose_runner_host,
|
||||
readiness::metrics_handle_from_port,
|
||||
docker::control::ComposeNodeControl,
|
||||
errors::ComposeRunnerError,
|
||||
infrastructure::{environment::StackEnvironment, ports::compose_runner_host},
|
||||
lifecycle::readiness::metrics_handle_from_port,
|
||||
};
|
||||
|
||||
pub struct DeploymentOrchestrator {
|
||||
@ -48,7 +50,7 @@ impl DeploymentOrchestrator {
|
||||
ReadinessChecker::wait_all(&descriptors, &host_ports, &mut environment).await?;
|
||||
} else {
|
||||
info!("readiness checks disabled; giving the stack a short grace period");
|
||||
crate::readiness::maybe_sleep_for_disabled_readiness(false).await;
|
||||
crate::lifecycle::readiness::maybe_sleep_for_disabled_readiness(false).await;
|
||||
}
|
||||
|
||||
let host = compose_runner_host();
|
||||
@ -79,7 +81,7 @@ impl DeploymentOrchestrator {
|
||||
|
||||
fn maybe_node_control<Caps>(
|
||||
&self,
|
||||
environment: &crate::environment::StackEnvironment,
|
||||
environment: &StackEnvironment,
|
||||
) -> Option<Arc<dyn NodeControlHandle>>
|
||||
where
|
||||
Caps: RequiresNodeControl + Send + Sync,
|
||||
|
||||
@ -2,9 +2,11 @@ use testing_framework_core::topology::generation::GeneratedTopology;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::{
|
||||
environment::StackEnvironment,
|
||||
errors::ComposeRunnerError,
|
||||
ports::{HostPortMapping, discover_host_ports},
|
||||
infrastructure::{
|
||||
environment::StackEnvironment,
|
||||
ports::{HostPortMapping, discover_host_ports},
|
||||
},
|
||||
};
|
||||
|
||||
pub struct PortManager;
|
||||
|
||||
@ -2,10 +2,12 @@ use testing_framework_core::topology::generation::GeneratedTopology;
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
environment::StackEnvironment,
|
||||
errors::ComposeRunnerError,
|
||||
ports::{HostPortMapping, ensure_remote_readiness_with_ports},
|
||||
readiness::{ensure_executors_ready_with_ports, ensure_validators_ready_with_ports},
|
||||
infrastructure::{
|
||||
environment::StackEnvironment,
|
||||
ports::{HostPortMapping, ensure_remote_readiness_with_ports},
|
||||
},
|
||||
lifecycle::readiness::{ensure_executors_ready_with_ports, ensure_validators_ready_with_ports},
|
||||
};
|
||||
|
||||
pub struct ReadinessChecker;
|
||||
|
||||
@ -8,10 +8,10 @@ use tracing::info;
|
||||
|
||||
use crate::{
|
||||
docker::ensure_docker_available,
|
||||
environment::{
|
||||
errors::ComposeRunnerError,
|
||||
infrastructure::environment::{
|
||||
PortReservation, StackEnvironment, ensure_supported_topology, prepare_environment,
|
||||
},
|
||||
errors::ComposeRunnerError,
|
||||
};
|
||||
|
||||
pub const PROMETHEUS_PORT_ENV: &str = "TEST_FRAMEWORK_PROMETHEUS_PORT";
|
||||
|
||||
@ -4,7 +4,7 @@ use testing_framework_core::{
|
||||
topology::generation::{GeneratedNodeConfig, GeneratedTopology},
|
||||
};
|
||||
|
||||
use crate::platform::{host_gateway_entry, resolve_image};
|
||||
use crate::docker::platform::{host_gateway_entry, resolve_image};
|
||||
|
||||
mod node;
|
||||
|
||||
|
||||
@ -23,6 +23,22 @@ pub enum ComposeCommandError {
|
||||
Timeout { command: String, timeout: Duration },
|
||||
}
|
||||
|
||||
/// Run an arbitrary docker command with a timeout.
|
||||
pub async fn run_docker_command(
|
||||
mut command: Command,
|
||||
timeout_duration: Duration,
|
||||
description: &str,
|
||||
) -> Result<(), ComposeCommandError> {
|
||||
let result = timeout(timeout_duration, command.status()).await;
|
||||
match result {
|
||||
Ok(status) => handle_compose_status(status, description),
|
||||
Err(_) => Err(ComposeCommandError::Timeout {
|
||||
command: description.to_owned(),
|
||||
timeout: timeout_duration,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs `docker compose up -d` for the generated stack.
|
||||
pub async fn compose_up(
|
||||
compose_path: &Path,
|
||||
@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
|
||||
use testing_framework_core::scenario::{DynError, NodeControlHandle};
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::{docker::run_docker_command, errors::ComposeRunnerError};
|
||||
use crate::{docker::commands::run_docker_command, errors::ComposeRunnerError};
|
||||
|
||||
pub async fn restart_compose_service(
|
||||
compose_file: &Path,
|
||||
@ -23,10 +23,11 @@ pub async fn restart_compose_service(
|
||||
let description = "docker compose restart";
|
||||
run_docker_command(
|
||||
command,
|
||||
description,
|
||||
testing_framework_core::adjust_timeout(std::time::Duration::from_secs(120)),
|
||||
description,
|
||||
)
|
||||
.await
|
||||
.map_err(ComposeRunnerError::Compose)
|
||||
}
|
||||
|
||||
/// Compose-specific node control handle for restarting nodes.
|
||||
@ -1,13 +1,16 @@
|
||||
use std::{
|
||||
env,
|
||||
process::{Command as StdCommand, Stdio},
|
||||
time::Duration,
|
||||
};
|
||||
pub mod commands;
|
||||
pub mod control;
|
||||
pub mod platform;
|
||||
pub mod workspace;
|
||||
|
||||
use std::{env, process::Stdio, time::Duration};
|
||||
|
||||
use tokio::{process::Command, time::timeout};
|
||||
use tracing::warn;
|
||||
|
||||
use crate::{commands::ComposeCommandError, errors::ComposeRunnerError, template::repository_root};
|
||||
use crate::{
|
||||
docker::commands::ComposeCommandError, errors::ComposeRunnerError,
|
||||
infrastructure::template::repository_root,
|
||||
};
|
||||
|
||||
const IMAGE_BUILD_TIMEOUT: Duration = Duration::from_secs(600);
|
||||
const DOCKER_INFO_TIMEOUT: Duration = Duration::from_secs(15);
|
||||
@ -40,7 +43,7 @@ pub async fn ensure_docker_available() -> Result<(), ComposeRunnerError> {
|
||||
|
||||
/// Ensure the configured compose image exists, building a local one if needed.
|
||||
pub async fn ensure_compose_image() -> Result<(), ComposeRunnerError> {
|
||||
let (image, platform) = crate::platform::resolve_image();
|
||||
let (image, platform) = crate::docker::platform::resolve_image();
|
||||
ensure_image_present(&image, platform.as_deref()).await
|
||||
}
|
||||
|
||||
@ -123,73 +126,60 @@ pub async fn build_local_image(
|
||||
.arg(format!("CIRCUITS_OVERRIDE={value}"));
|
||||
}
|
||||
|
||||
let node_rev = std::env::var("NOMOS_NODE_REV")
|
||||
.unwrap_or_else(|_| String::from("d2dd5a5084e1daef4032562c77d41de5e4d495f8"));
|
||||
cmd.arg("--build-arg")
|
||||
.arg(format!("NOMOS_NODE_REV={node_rev}"));
|
||||
|
||||
if let Some(value) = env::var("NOMOS_CIRCUITS_VERSION")
|
||||
.ok()
|
||||
.filter(|val| !val.is_empty())
|
||||
{
|
||||
cmd.arg("--build-arg")
|
||||
.arg(format!("NOMOS_CIRCUITS_VERSION={value}"));
|
||||
}
|
||||
|
||||
if env::var("NOMOS_CIRCUITS_REBUILD_RAPIDSNARK").is_ok() {
|
||||
cmd.arg("--build-arg").arg("RAPIDSNARK_REBUILD=1");
|
||||
}
|
||||
|
||||
cmd.arg("-t")
|
||||
.arg(image)
|
||||
.arg("-f")
|
||||
.arg(&dockerfile)
|
||||
.arg(dockerfile)
|
||||
.arg(&repo_root);
|
||||
|
||||
run_docker_command(cmd, "docker build compose image", IMAGE_BUILD_TIMEOUT).await
|
||||
}
|
||||
cmd.current_dir(&repo_root);
|
||||
|
||||
/// Run a docker command with a timeout, mapping errors into runner errors.
|
||||
pub async fn run_docker_command(
|
||||
mut command: Command,
|
||||
description: &str,
|
||||
timeout_duration: Duration,
|
||||
) -> Result<(), ComposeRunnerError> {
|
||||
match timeout(timeout_duration, command.status()).await {
|
||||
Ok(Ok(status)) if status.success() => Ok(()),
|
||||
Ok(Ok(status)) => Err(ComposeRunnerError::Compose(ComposeCommandError::Failed {
|
||||
command: description.to_owned(),
|
||||
status,
|
||||
})),
|
||||
Ok(Err(source)) => Err(ComposeRunnerError::Compose(ComposeCommandError::Spawn {
|
||||
command: description.to_owned(),
|
||||
source,
|
||||
})),
|
||||
Err(_) => Err(ComposeRunnerError::Compose(ComposeCommandError::Timeout {
|
||||
command: description.to_owned(),
|
||||
timeout: timeout_duration,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_docker_platform() -> Result<Option<String>, ComposeRunnerError> {
|
||||
let output = StdCommand::new("docker")
|
||||
.arg("info")
|
||||
.arg("-f")
|
||||
.arg("{{.Architecture}}")
|
||||
.output()
|
||||
.map_err(|source| ComposeRunnerError::ImageBuild {
|
||||
source: source.into(),
|
||||
})?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let arch = String::from_utf8_lossy(&output.stdout).trim().to_owned();
|
||||
if arch.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(format!("linux/{arch}")))
|
||||
}
|
||||
|
||||
/// Choose the build platform from user override or docker host architecture.
|
||||
pub fn select_build_platform(
|
||||
requested: Option<&str>,
|
||||
) -> Result<Option<String>, ComposeRunnerError> {
|
||||
if let Some(value) = requested {
|
||||
return Ok(Some(value.to_owned()));
|
||||
}
|
||||
|
||||
detect_docker_platform()?.map_or_else(
|
||||
|| {
|
||||
warn!("docker host architecture unavailable; letting docker choose default platform");
|
||||
Ok(None)
|
||||
},
|
||||
|host_platform| Ok(Some(host_platform)),
|
||||
let status = timeout(
|
||||
testing_framework_core::adjust_timeout(IMAGE_BUILD_TIMEOUT),
|
||||
cmd.status(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| {
|
||||
ComposeRunnerError::Compose(ComposeCommandError::Timeout {
|
||||
command: String::from("docker build"),
|
||||
timeout: testing_framework_core::adjust_timeout(IMAGE_BUILD_TIMEOUT),
|
||||
})
|
||||
})?;
|
||||
|
||||
match status {
|
||||
Ok(code) if code.success() => Ok(()),
|
||||
Ok(code) => Err(ComposeRunnerError::Compose(ComposeCommandError::Failed {
|
||||
command: String::from("docker build"),
|
||||
status: code,
|
||||
})),
|
||||
Err(err) => Err(ComposeRunnerError::ImageBuild { source: err.into() }),
|
||||
}
|
||||
}
|
||||
|
||||
fn select_build_platform(platform: Option<&str>) -> Result<Option<String>, ComposeRunnerError> {
|
||||
Ok(platform.map(String::from).or_else(|| {
|
||||
let host_arch = std::env::consts::ARCH;
|
||||
match host_arch {
|
||||
"aarch64" | "arm64" => Some(String::from("linux/arm64")),
|
||||
"x86_64" => Some(String::from("linux/amd64")),
|
||||
_ => None,
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -10,7 +10,8 @@ use testing_framework_core::{
|
||||
use url::ParseError;
|
||||
|
||||
use crate::{
|
||||
commands::ComposeCommandError, descriptor::DescriptorBuildError, template::TemplateError,
|
||||
descriptor::DescriptorBuildError, docker::commands::ComposeCommandError,
|
||||
infrastructure::template::TemplateError,
|
||||
};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
|
||||
@ -13,16 +13,20 @@ use tracing::{debug, info, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
cfgsync::{CfgsyncServerHandle, update_cfgsync_config},
|
||||
cleanup::RunnerCleanup,
|
||||
commands::{compose_up, dump_compose_logs},
|
||||
deployer::setup::DEFAULT_PROMETHEUS_PORT,
|
||||
descriptor::ComposeDescriptor,
|
||||
docker::{ensure_compose_image, run_docker_command},
|
||||
docker::{
|
||||
commands::{compose_up, dump_compose_logs, run_docker_command},
|
||||
ensure_compose_image,
|
||||
platform::resolve_image,
|
||||
workspace::ComposeWorkspace,
|
||||
},
|
||||
errors::{ComposeRunnerError, ConfigError, WorkspaceError},
|
||||
platform::resolve_image,
|
||||
template::write_compose_file,
|
||||
workspace::ComposeWorkspace,
|
||||
infrastructure::{
|
||||
cfgsync::{CfgsyncServerHandle, update_cfgsync_config},
|
||||
template::write_compose_file,
|
||||
},
|
||||
lifecycle::cleanup::RunnerCleanup,
|
||||
};
|
||||
|
||||
const CFGSYNC_START_TIMEOUT: Duration = Duration::from_secs(180);
|
||||
@ -274,8 +278,8 @@ pub async fn launch_cfgsync(
|
||||
|
||||
run_docker_command(
|
||||
command,
|
||||
"docker run cfgsync server",
|
||||
adjust_timeout(CFGSYNC_START_TIMEOUT),
|
||||
"docker run cfgsync server",
|
||||
)
|
||||
.await
|
||||
.map_err(|source| ConfigError::CfgsyncStart {
|
||||
@ -0,0 +1,4 @@
|
||||
pub mod cfgsync;
|
||||
pub mod environment;
|
||||
pub mod ports;
|
||||
pub mod template;
|
||||
@ -11,8 +11,8 @@ use tokio::{process::Command, time::timeout};
|
||||
use url::ParseError;
|
||||
|
||||
use crate::{
|
||||
environment::StackEnvironment,
|
||||
errors::{ComposeRunnerError, StackReadinessError},
|
||||
infrastructure::environment::StackEnvironment,
|
||||
};
|
||||
|
||||
/// Host ports mapped for a single node.
|
||||
@ -1,24 +1,18 @@
|
||||
pub mod block_feed;
|
||||
pub mod cfgsync;
|
||||
pub mod cleanup;
|
||||
pub mod commands;
|
||||
pub mod control;
|
||||
pub mod deployer;
|
||||
pub mod descriptor;
|
||||
pub mod docker;
|
||||
pub mod environment;
|
||||
pub mod errors;
|
||||
pub mod platform;
|
||||
pub mod ports;
|
||||
pub mod readiness;
|
||||
pub mod template;
|
||||
pub mod wait;
|
||||
pub mod workspace;
|
||||
pub mod infrastructure;
|
||||
pub mod lifecycle;
|
||||
|
||||
pub use commands::{ComposeCommandError, compose_down, compose_up, dump_compose_logs};
|
||||
pub use deployer::ComposeDeployer;
|
||||
pub use descriptor::{ComposeDescriptor, ComposeDescriptorBuilder, EnvEntry, NodeDescriptor};
|
||||
pub use docker::{
|
||||
commands::{ComposeCommandError, compose_down, compose_up, dump_compose_logs},
|
||||
platform::{host_gateway_entry, resolve_image},
|
||||
};
|
||||
pub use errors::ComposeRunnerError;
|
||||
pub use platform::{host_gateway_entry, resolve_image};
|
||||
pub use ports::{HostPortMapping, NodeHostPorts};
|
||||
pub use template::{TemplateError, repository_root, write_compose_file};
|
||||
pub use infrastructure::{
|
||||
ports::{HostPortMapping, NodeHostPorts},
|
||||
template::{TemplateError, repository_root, write_compose_file},
|
||||
};
|
||||
|
||||
@ -3,9 +3,11 @@ use std::{env, path::PathBuf, thread};
|
||||
use testing_framework_core::scenario::CleanupGuard;
|
||||
|
||||
use crate::{
|
||||
cfgsync::CfgsyncServerHandle,
|
||||
commands::{ComposeCommandError, compose_down},
|
||||
workspace::ComposeWorkspace,
|
||||
docker::{
|
||||
commands::{ComposeCommandError, compose_down},
|
||||
workspace::ComposeWorkspace,
|
||||
},
|
||||
infrastructure::cfgsync::CfgsyncServerHandle,
|
||||
};
|
||||
|
||||
/// Cleans up a compose deployment and associated cfgsync container.
|
||||
4
testing-framework/runners/compose/src/lifecycle/mod.rs
Normal file
4
testing-framework/runners/compose/src/lifecycle/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod block_feed;
|
||||
pub mod cleanup;
|
||||
pub mod readiness;
|
||||
pub mod wait;
|
||||
@ -10,8 +10,8 @@ use tokio::time::sleep;
|
||||
|
||||
use crate::{
|
||||
errors::{NodeClientError, StackReadinessError},
|
||||
ports::{HostPortMapping, NodeHostPorts},
|
||||
wait::{wait_for_executors, wait_for_validators},
|
||||
infrastructure::ports::{HostPortMapping, NodeHostPorts},
|
||||
lifecycle::wait::{wait_for_executors, wait_for_validators},
|
||||
};
|
||||
|
||||
const DISABLED_READINESS_SLEEP: Duration = Duration::from_secs(5);
|
||||
Loading…
x
Reference in New Issue
Block a user