diff --git a/testing-framework/core/src/kzg.rs b/testing-framework/core/src/kzg.rs new file mode 100644 index 0000000..645b0f3 --- /dev/null +++ b/testing-framework/core/src/kzg.rs @@ -0,0 +1,86 @@ +use std::path::{Path, PathBuf}; + +use testing_framework_env as tf_env; + +use crate::constants::{DEFAULT_KZG_CONTAINER_PATH, DEFAULT_KZG_HOST_DIR}; + +/// Default in-image path for KZG params used by testnet images. +pub const DEFAULT_IN_IMAGE_KZG_PARAMS_PATH: &str = "/opt/nomos/kzg-params/kzgrs_test_params"; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum KzgMode { + HostPath, + InImage, +} + +impl KzgMode { + #[must_use] + pub fn from_env_or_default() -> Self { + match tf_env::nomos_kzg_mode().as_deref() { + Some("hostPath") => Self::HostPath, + Some("inImage") => Self::InImage, + None => Self::InImage, + Some(other) => { + tracing::warn!( + value = other, + "unknown NOMOS_KZG_MODE; defaulting to inImage" + ); + Self::InImage + } + } + } +} + +/// Canonical KZG parameters model used by runners and config distribution. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct KzgParamsSpec { + pub mode: KzgMode, + /// Value written into node configs (cfgsync `global_params_path`) and, + /// where applicable, exported as `NOMOS_KZGRS_PARAMS_PATH` for node + /// processes. + pub node_params_path: String, + /// Host directory that must exist when running in `HostPath` mode. + pub host_params_dir: Option, +} + +impl KzgParamsSpec { + #[must_use] + pub fn for_compose(use_kzg_mount: bool) -> Self { + let node_params_path = tf_env::nomos_kzgrs_params_path().unwrap_or_else(|| { + if use_kzg_mount { + DEFAULT_KZG_CONTAINER_PATH.to_string() + } else { + DEFAULT_IN_IMAGE_KZG_PARAMS_PATH.to_string() + } + }); + Self { + mode: if use_kzg_mount { + KzgMode::HostPath + } else { + KzgMode::InImage + }, + node_params_path, + host_params_dir: None, + } + } + + #[must_use] + pub fn for_k8s(root: &Path) -> Self { + let mode = KzgMode::from_env_or_default(); + match mode { + KzgMode::HostPath => Self { + mode, + node_params_path: DEFAULT_KZG_CONTAINER_PATH.to_string(), + host_params_dir: Some(root.join( + tf_env::nomos_kzg_dir_rel().unwrap_or_else(|| DEFAULT_KZG_HOST_DIR.to_string()), + )), + }, + KzgMode::InImage => Self { + mode, + node_params_path: tf_env::nomos_kzgrs_params_path() + .unwrap_or_else(|| DEFAULT_IN_IMAGE_KZG_PARAMS_PATH.to_string()), + host_params_dir: None, + }, + } + } +} diff --git a/testing-framework/core/src/lib.rs b/testing-framework/core/src/lib.rs index d82ea58..db604f4 100644 --- a/testing-framework/core/src/lib.rs +++ b/testing-framework/core/src/lib.rs @@ -1,4 +1,5 @@ pub mod constants; +pub mod kzg; pub mod nodes; pub mod scenario; pub mod topology; diff --git a/testing-framework/deployers/compose/src/descriptor/mod.rs b/testing-framework/deployers/compose/src/descriptor/mod.rs index 2535ebb..0fc1d40 100644 --- a/testing-framework/deployers/compose/src/descriptor/mod.rs +++ b/testing-framework/deployers/compose/src/descriptor/mod.rs @@ -5,7 +5,8 @@ use std::{ use serde::Serialize; use testing_framework_core::{ - constants::{DEFAULT_CFGSYNC_PORT, kzg_container_path}, + constants::DEFAULT_CFGSYNC_PORT, + kzg::KzgParamsSpec, topology::generation::{GeneratedNodeConfig, GeneratedTopology}, }; use testing_framework_env as tf_env; @@ -180,12 +181,12 @@ fn default_extra_hosts() -> Vec { host_gateway_entry().into_iter().collect() } -fn base_environment(cfgsync_port: u16) -> Vec { +fn base_environment(cfgsync_port: u16, use_kzg_mount: bool) -> Vec { let pol_mode = tf_env::pol_proof_dev_mode().unwrap_or_else(|| "true".to_string()); let rust_log = tf_env::rust_log().unwrap_or_else(|| "info".to_string()); let nomos_log_level = tf_env::nomos_log_level().unwrap_or_else(|| "info".to_string()); let time_backend = tf_env::nomos_time_backend().unwrap_or_else(|| "monotonic".into()); - let kzg_path = tf_env::nomos_kzgrs_params_path().unwrap_or_else(kzg_container_path); + let kzg_path = KzgParamsSpec::for_compose(use_kzg_mount).node_params_path; vec![ EnvEntry::new("POL_PROOF_DEV_MODE", pol_mode), EnvEntry::new("RUST_LOG", rust_log), diff --git a/testing-framework/deployers/compose/src/descriptor/node.rs b/testing-framework/deployers/compose/src/descriptor/node.rs index 810c7b2..930f6e5 100644 --- a/testing-framework/deployers/compose/src/descriptor/node.rs +++ b/testing-framework/deployers/compose/src/descriptor/node.rs @@ -53,7 +53,7 @@ impl NodeDescriptor { use_kzg_mount: bool, cfgsync_port: u16, ) -> Self { - let mut environment = base_environment(cfgsync_port); + let mut environment = base_environment(cfgsync_port, use_kzg_mount); let identifier = kind.instance_name(index); let api_port = node.general.api_config.address.port(); let testing_port = node.general.api_config.testing_http_address.port(); diff --git a/testing-framework/deployers/compose/src/infrastructure/cfgsync.rs b/testing-framework/deployers/compose/src/infrastructure/cfgsync.rs index 8786cea..590b80a 100644 --- a/testing-framework/deployers/compose/src/infrastructure/cfgsync.rs +++ b/testing-framework/deployers/compose/src/infrastructure/cfgsync.rs @@ -4,6 +4,7 @@ use nomos_tracing::metrics::otlp::OtlpMetricsConfig; use nomos_tracing_service::MetricsLayer; use reqwest::Url; use testing_framework_core::{ + kzg::KzgParamsSpec, scenario::cfgsync::{apply_topology_overrides, load_cfgsync_template, write_cfgsync_template}, topology::generation::GeneratedTopology, }; @@ -76,6 +77,7 @@ pub fn update_cfgsync_config( let mut cfg = load_cfgsync_template(path)?; cfg.port = port; apply_topology_overrides(&mut cfg, topology, use_kzg_mount); + cfg.global_params_path = KzgParamsSpec::for_compose(use_kzg_mount).node_params_path; if let Some(endpoint) = metrics_otlp_ingest_url.cloned() { cfg.tracing_settings.metrics = MetricsLayer::Otlp(OtlpMetricsConfig { endpoint, diff --git a/testing-framework/deployers/k8s/src/infrastructure/assets.rs b/testing-framework/deployers/k8s/src/infrastructure/assets.rs index 397f37c..90684fc 100644 --- a/testing-framework/deployers/k8s/src/infrastructure/assets.rs +++ b/testing-framework/deployers/k8s/src/infrastructure/assets.rs @@ -10,14 +10,16 @@ use nomos_tracing_service::MetricsLayer; use reqwest::Url; use serde::Serialize; use tempfile::TempDir; +pub use testing_framework_core::kzg::KzgMode; use testing_framework_core::{ constants::cfgsync_port, + kzg::KzgParamsSpec, scenario::cfgsync::{apply_topology_overrides, load_cfgsync_template, render_cfgsync_yaml}, topology::generation::GeneratedTopology, }; use testing_framework_env as tf_env; use thiserror::Error; -use tracing::{debug, info, warn}; +use tracing::{debug, info}; /// Paths and image metadata required to deploy the Helm chart. pub struct RunnerAssets { @@ -75,27 +77,6 @@ pub enum AssetsError { }, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum KzgMode { - HostPath, - InImage, -} - -fn kzg_mode() -> KzgMode { - match tf_env::nomos_kzg_mode().as_deref() { - Some("hostPath") => KzgMode::HostPath, - Some("inImage") => KzgMode::InImage, - None => KzgMode::InImage, - Some(other) => { - warn!( - value = other, - "unknown NOMOS_KZG_MODE; defaulting to inImage" - ); - KzgMode::InImage - } - } -} - /// Render cfgsync config, Helm values, and locate scripts/KZG assets for a /// topology. pub fn prepare_assets( @@ -109,8 +90,8 @@ pub fn prepare_assets( ); let root = workspace_root().map_err(|source| AssetsError::WorkspaceRoot { source })?; - let kzg_mode = kzg_mode(); - let cfgsync_yaml = render_cfgsync_config(&root, topology, kzg_mode, metrics_otlp_ingest_url)?; + let kzg_spec = KzgParamsSpec::for_k8s(&root); + let cfgsync_yaml = render_cfgsync_config(&root, topology, &kzg_spec, metrics_otlp_ingest_url)?; let tempdir = tempfile::Builder::new() .prefix("nomos-helm-") @@ -119,8 +100,8 @@ pub fn prepare_assets( let cfgsync_file = write_temp_file(tempdir.path(), "cfgsync.yaml", cfgsync_yaml)?; let scripts = validate_scripts(&root)?; - let kzg_path = match kzg_mode { - KzgMode::HostPath => Some(validate_kzg_params(&root)?), + let kzg_path = match kzg_spec.mode { + KzgMode::HostPath => Some(validate_kzg_params(&root, &kzg_spec)?), KzgMode::InImage => None, }; let chart_path = helm_chart_path()?; @@ -137,7 +118,7 @@ pub fn prepare_assets( cfgsync = %cfgsync_file.display(), values = %values_file.display(), image, - kzg_mode = ?kzg_mode, + kzg_mode = ?kzg_spec.mode, kzg = %kzg_display, chart = %chart_path.display(), "k8s runner assets prepared" @@ -145,7 +126,7 @@ pub fn prepare_assets( Ok(RunnerAssets { image, - kzg_mode, + kzg_mode: kzg_spec.mode, kzg_path, chart_path, cfgsync_file, @@ -159,12 +140,11 @@ pub fn prepare_assets( } const CFGSYNC_K8S_TIMEOUT_SECS: u64 = 300; -const DEFAULT_IN_IMAGE_KZG_PARAMS_PATH: &str = "/opt/nomos/kzg-params/kzgrs_test_params"; fn render_cfgsync_config( root: &Path, topology: &GeneratedTopology, - kzg_mode: KzgMode, + kzg_spec: &KzgParamsSpec, metrics_otlp_ingest_url: Option<&Url>, ) -> Result { let cfgsync_template_path = stack_assets_root(root).join("cfgsync.yaml"); @@ -173,12 +153,8 @@ fn render_cfgsync_config( let mut cfg = load_cfgsync_template(&cfgsync_template_path) .map_err(|source| AssetsError::Cfgsync { source })?; - apply_topology_overrides(&mut cfg, topology, kzg_mode == KzgMode::HostPath); - - if kzg_mode == KzgMode::InImage { - cfg.global_params_path = tf_env::nomos_kzgrs_params_path() - .unwrap_or_else(|| DEFAULT_IN_IMAGE_KZG_PARAMS_PATH.to_string()); - } + apply_topology_overrides(&mut cfg, topology, kzg_spec.mode == KzgMode::HostPath); + cfg.global_params_path = kzg_spec.node_params_path.clone(); if let Some(endpoint) = metrics_otlp_ingest_url.cloned() { cfg.tracing_settings.metrics = MetricsLayer::Otlp(OtlpMetricsConfig { @@ -228,10 +204,12 @@ fn validate_scripts(root: &Path) -> Result { }) } -fn validate_kzg_params(root: &Path) -> Result { - let rel = tf_env::nomos_kzg_dir_rel() - .unwrap_or_else(|| testing_framework_core::constants::DEFAULT_KZG_HOST_DIR.to_string()); - let path = root.join(rel); +fn validate_kzg_params(root: &Path, spec: &KzgParamsSpec) -> Result { + let Some(path) = spec.host_params_dir.clone() else { + return Err(AssetsError::MissingKzg { + path: root.join(testing_framework_core::constants::DEFAULT_KZG_HOST_DIR), + }); + }; if path.exists() { Ok(path) } else {