diff --git a/crates/configuration/Cargo.toml b/crates/configuration/Cargo.toml index 6672b1ca67f0087bff5bec2165f085316133db00..3995f0fb9f6b216a24efaebca89b1501b64be153 100644 --- a/crates/configuration/Cargo.toml +++ b/crates/configuration/Cargo.toml @@ -21,3 +21,6 @@ serde = { workspace = true, features = ["derive"] } toml = { workspace = true } serde_json = { workspace = true } +# zombienet deps +support = { workspace = true } + diff --git a/crates/configuration/src/network.rs b/crates/configuration/src/network.rs index b8918a11859278fc8d8a3d8c5612bff43dc42680..31b2ff6c01c3351959b9ad693b00e307689d2974 100644 --- a/crates/configuration/src/network.rs +++ b/crates/configuration/src/network.rs @@ -3,6 +3,9 @@ use std::{cell::RefCell, fs, marker::PhantomData, rc::Rc}; use anyhow::anyhow; use regex::Regex; use serde::{Deserialize, Serialize}; +use support::constants::{ + NO_ERR_DEF_BUILDER, RELAY_NOT_NONE, RW_FAILED, THIS_IS_A_BUG, VALIDATION_CHECK, VALID_REGEX, +}; use crate::{ global_settings::{GlobalSettings, GlobalSettingsBuilder}, @@ -10,10 +13,6 @@ use crate::{ parachain::{self, ParachainConfig, ParachainConfigBuilder}, relaychain::{self, RelaychainConfig, RelaychainConfigBuilder}, shared::{ - constants::{ - NO_ERR_DEF_BUILDER, RELAY_NOT_NONE, RW_FAILED, THIS_IS_A_BUG, VALIDATION_CHECK, - VALID_REGEX, - }, helpers::merge_errors_vecs, macros::states, node::NodeConfig, diff --git a/crates/configuration/src/parachain.rs b/crates/configuration/src/parachain.rs index 3952afda8b3c0120e0b491db5fa55677467f8fc6..e2533f0353d8e58a7d466c9d07ae088e5aa6edd3 100644 --- a/crates/configuration/src/parachain.rs +++ b/crates/configuration/src/parachain.rs @@ -127,6 +127,10 @@ pub struct ParachainConfig { genesis_state_path: Option<AssetLocation>, genesis_state_generator: Option<Command>, chain_spec_path: Option<AssetLocation>, + // Full _template_ command, will be rendered using [tera] + // and executed for generate the chain-spec. + // available tokens {{chainName}} / {{disableBootnodes}} + chain_spec_command: Option<String>, #[serde(rename = "cumulus_based", default = "default_as_true")] is_cumulus_based: bool, #[serde(skip_serializing_if = "std::vec::Vec::is_empty", default)] @@ -217,6 +221,11 @@ impl ParachainConfig { self.chain_spec_path.as_ref() } + /// The full _template_ command to genera the chain-spec + pub fn chain_spec_command(&self) -> Option<&str> { + self.chain_spec_command.as_deref() + } + /// Whether the parachain is based on cumulus. pub fn is_cumulus_based(&self) -> bool { self.is_cumulus_based @@ -282,6 +291,7 @@ impl<C: Context> Default for ParachainConfigBuilder<Initial, C> { genesis_state_generator: None, genesis_overrides: None, chain_spec_path: None, + chain_spec_command: None, is_cumulus_based: true, bootnodes_addresses: vec![], collators: vec![], @@ -652,6 +662,18 @@ impl<C: Context> ParachainConfigBuilder<WithId, C> { ) } + /// Set the chain-spec command _template_ for the relay chain. + pub fn with_chain_spec_command(self, cmd_template: impl Into<String>) -> Self { + Self::transition( + ParachainConfig { + chain_spec_command: Some(cmd_template.into()), + ..self.config + }, + self.validation_context, + self.errors, + ) + } + /// Set whether the parachain is based on cumulus (true in a majority of case, except adder or undying collators). pub fn cumulus_based(self, choice: bool) -> Self { Self::transition( @@ -1218,4 +1240,20 @@ mod tests { Some(&RegistrationStrategy::UsingExtrinsic) ); } + + #[test] + fn parachain_config_builder_should_works_with_chain_spec_command() { + const CMD_TPL: &str = "./bin/chain-spec-generator {% raw %} {{chainName}} {% endraw %}"; + let relaychain_config = ParachainConfigBuilder::new(Default::default()) + .with_id(2000) + .with_chain("some-chain") + .with_default_image("myrepo:myimage") + .with_default_command("default_command") + .with_chain_spec_command(CMD_TPL) + .with_collator(|collator| collator.with_name("collator")) + .build() + .unwrap(); + + assert_eq!(relaychain_config.chain_spec_command(), Some(CMD_TPL)); + } } diff --git a/crates/configuration/src/relaychain.rs b/crates/configuration/src/relaychain.rs index 760be05fea542d76dc462b5c3e4cffa8e7686d22..e6051038a15dbc6b3f4bb6ae8311da7f58a4d3d5 100644 --- a/crates/configuration/src/relaychain.rs +++ b/crates/configuration/src/relaychain.rs @@ -1,10 +1,10 @@ use std::{cell::RefCell, error::Error, fmt::Debug, marker::PhantomData, rc::Rc}; use serde::{Deserialize, Serialize}; +use support::constants::{DEFAULT_TYPESTATE, THIS_IS_A_BUG}; use crate::{ shared::{ - constants::{DEFAULT_TYPESTATE, THIS_IS_A_BUG}, errors::{ConfigError, FieldError}, helpers::{merge_errors, merge_errors_vecs}, macros::states, @@ -29,6 +29,10 @@ pub struct RelaychainConfig { #[serde(skip_serializing_if = "std::vec::Vec::is_empty", default)] default_args: Vec<Arg>, chain_spec_path: Option<AssetLocation>, + // Full _template_ command, will be rendered using [tera] + // and executed for generate the chain-spec. + // available tokens {{chainName}} / {{disableBootnodes}} + chain_spec_command: Option<String>, random_nominators_count: Option<u32>, max_nominations: Option<u8>, #[serde(skip_serializing_if = "std::vec::Vec::is_empty", default)] @@ -73,6 +77,11 @@ impl RelaychainConfig { self.chain_spec_path.as_ref() } + /// The full _template_ command to genera the chain-spec + pub fn chain_spec_command(&self) -> Option<&str> { + self.chain_spec_command.as_deref() + } + /// The non-default command used for nodes. pub fn command(&self) -> Option<&Command> { self.command.as_ref() @@ -130,6 +139,7 @@ impl Default for RelaychainConfigBuilder<Initial> { default_db_snapshot: None, default_args: vec![], chain_spec_path: None, + chain_spec_command: None, command: None, random_nominators_count: None, max_nominations: None, @@ -313,6 +323,18 @@ impl RelaychainConfigBuilder<WithChain> { ) } + /// Set the chain-spec command _template_ for the relay chain. + pub fn with_chain_spec_command(self, cmd_template: impl Into<String>) -> Self { + Self::transition( + RelaychainConfig { + chain_spec_command: Some(cmd_template.into()), + ..self.config + }, + self.validation_context, + self.errors, + ) + } + /// Set the number of `random nominators` to create for chains using staking, this is used in tandem with `max_nominations` to simulate the amount of nominators and nominations. pub fn with_random_nominators_count(self, random_nominators_count: u32) -> Self { Self::transition( @@ -657,4 +679,19 @@ mod tests { "relaychain.nodes['node'].image: 'invalid image' doesn't match regex '^([ip]|[hostname]/)?[tag_name]:[tag_version]?$'" ); } + + #[test] + fn relaychain_config_builder_should_works_with_chain_spec_command() { + const CMD_TPL: &str = "./bin/chain-spec-generator {% raw %} {{chainName}} {% endraw %}"; + let relaychain_config = RelaychainConfigBuilder::new(Default::default()) + .with_chain("polkadot") + .with_default_image("myrepo:myimage") + .with_default_command("default_command") + .with_chain_spec_command(CMD_TPL) + .with_node(|node| node.with_name("node1").bootnode(true)) + .build() + .unwrap(); + + assert_eq!(relaychain_config.chain_spec_command(), Some(CMD_TPL)); + } } diff --git a/crates/configuration/src/shared.rs b/crates/configuration/src/shared.rs index 36b71c43e223e632d1cb93f900efd225ec583384..bb1d7bf19f2f4ff2ba97c84a3eda393105f21e17 100644 --- a/crates/configuration/src/shared.rs +++ b/crates/configuration/src/shared.rs @@ -1,4 +1,3 @@ -pub mod constants; pub mod errors; pub mod helpers; pub mod macros; diff --git a/crates/configuration/src/shared/helpers.rs b/crates/configuration/src/shared/helpers.rs index ee0a65e2fb825a06f84432ee6a77e449eb721020..c111e66e04e5a0edd22f380c89f8bb5a250b069d 100644 --- a/crates/configuration/src/shared/helpers.rs +++ b/crates/configuration/src/shared/helpers.rs @@ -1,7 +1,8 @@ use std::{cell::RefCell, rc::Rc}; +use support::constants::{BORROWABLE, THIS_IS_A_BUG}; + use super::{ - constants::{BORROWABLE, THIS_IS_A_BUG}, errors::ValidationError, types::{Port, ValidationContext}, }; diff --git a/crates/configuration/src/shared/resources.rs b/crates/configuration/src/shared/resources.rs index 79f53fb58e458535b48c01febf2b3e5d719064d4..cdd820fd8d000462d630d82969997b9603a74889 100644 --- a/crates/configuration/src/shared/resources.rs +++ b/crates/configuration/src/shared/resources.rs @@ -7,12 +7,12 @@ use serde::{ ser::SerializeStruct, Deserialize, Serialize, }; +use support::constants::{SHOULD_COMPILE, THIS_IS_A_BUG}; use super::{ errors::{ConversionError, FieldError}, helpers::merge_errors, }; -use crate::shared::constants::{SHOULD_COMPILE, THIS_IS_A_BUG}; /// A resource quantity used to define limits (k8s/podman only). /// It can be constructed from a `&str` or u64, if it fails, it returns a [`ConversionError`]. diff --git a/crates/configuration/src/shared/types.rs b/crates/configuration/src/shared/types.rs index c1ae162acdfccc5c9cd54785491ac9618220571c..23bf307465cc56484f20a361e213ca91a7d2f7d0 100644 --- a/crates/configuration/src/shared/types.rs +++ b/crates/configuration/src/shared/types.rs @@ -8,10 +8,10 @@ use std::{ use lazy_static::lazy_static; use regex::Regex; use serde::{de, Deserialize, Deserializer, Serialize}; +use support::constants::{INFAILABLE, PREFIX_CANT_BE_NONE, SHOULD_COMPILE, THIS_IS_A_BUG}; use url::Url; use super::{errors::ConversionError, resources::Resources}; -use crate::shared::constants::{INFAILABLE, PREFIX_CANT_BE_NONE, SHOULD_COMPILE, THIS_IS_A_BUG}; /// An alias for a duration in seconds. pub type Duration = u32; diff --git a/crates/orchestrator/src/generators/chain_spec.rs b/crates/orchestrator/src/generators/chain_spec.rs index fd9ed40e7d9860ef7c6626d8ac0b1c0220779db2..5d44e47fe052ec32c52b5c6de925814819cee44f 100644 --- a/crates/orchestrator/src/generators/chain_spec.rs +++ b/crates/orchestrator/src/generators/chain_spec.rs @@ -4,14 +4,14 @@ use std::{ }; use anyhow::anyhow; -use configuration::{shared::constants::THIS_IS_A_BUG, types::AssetLocation, HrmpChannelConfig}; +use configuration::{types::AssetLocation, HrmpChannelConfig}; use provider::{ constants::NODE_CONFIG_DIR, types::{GenerateFileCommand, GenerateFilesOptions, TransferedFile}, DynNamespace, ProviderError, }; use serde_json::json; -use support::fs::FileSystem; +use support::{constants::THIS_IS_A_BUG, fs::FileSystem, replacer::apply_replacements}; use tracing::{debug, trace, warn}; use super::errors::GeneratorError; @@ -144,19 +144,38 @@ impl ChainSpec { } } else { // we should create the chain-spec using command. - // SAFETY: we ensure that command is some with the first check of the fn - let cmd = self.command.as_ref().unwrap(); - let mut args: Vec<String> = vec!["build-spec".into()]; + let mut replacement_value = String::default(); if let Some(chain_name) = self.chain_name.as_ref() { if !chain_name.is_empty() { - args.push("--chain".into()); - args.push(chain_name.clone()); + replacement_value = chain_name.clone(); } - } - args.push("--disable-default-bootnode".into()); + }; + + // SAFETY: we ensure that command is some with the first check of the fn + // default as empty + let sanitized_cmd = if replacement_value.is_empty() { + // we need to remove the `--chain` flag + self.command.as_ref().unwrap().replace("--chain", "") + } else { + self.command.as_ref().unwrap().clone() + }; + + let full_cmd = apply_replacements( + &sanitized_cmd, + &HashMap::from([("chainName", replacement_value.as_str())]), + ); + trace!("full_cmd: {:?}", full_cmd); + + let parts: Vec<&str> = full_cmd.split_whitespace().collect(); + let Some((cmd, args)) = parts.split_first() else { + return Err(GeneratorError::ChainSpecGeneration(format!( + "Invalid generator command: {full_cmd}" + ))); + }; + trace!("cmd: {:?} - args: {:?}", cmd, args); let generate_command = - GenerateFileCommand::new(cmd.as_str(), maybe_plain_spec_path.clone()).args(args); + GenerateFileCommand::new(cmd, maybe_plain_spec_path.clone()).args(args); let options = GenerateFilesOptions::new(vec![generate_command], self.image.clone()); ns.generate_files(options).await?; } @@ -226,13 +245,23 @@ impl ChainSpec { chain_spec_path_in_pod.clone() }; - let args: Vec<String> = vec![ - "build-spec".into(), - "--chain".into(), - chain_spec_path_in_args, - "--raw".into(), - "--disable-default-bootnode".into(), - ]; + let mut full_cmd = apply_replacements( + cmd, + &HashMap::from([("chainName", chain_spec_path_in_args.as_str())]), + ); + + if !full_cmd.contains("--raw") { + full_cmd = format!("{full_cmd} --raw"); + } + trace!("full_cmd: {:?}", full_cmd); + + let parts: Vec<&str> = full_cmd.split_whitespace().collect(); + let Some((cmd, args)) = parts.split_first() else { + return Err(GeneratorError::ChainSpecGeneration(format!( + "Invalid generator command: {full_cmd}" + ))); + }; + trace!("cmd: {:?} - args: {:?}", cmd, args); let generate_command = GenerateFileCommand::new(cmd, raw_spec_path.clone()).args(args); let options = GenerateFilesOptions::with_files( diff --git a/crates/orchestrator/src/generators/command.rs b/crates/orchestrator/src/generators/command.rs index 75a3acd2280caab9b268c9910ea993a66c35c693..1adb49031a74e205f9682df15a7482dc5db0aca1 100644 --- a/crates/orchestrator/src/generators/command.rs +++ b/crates/orchestrator/src/generators/command.rs @@ -1,4 +1,5 @@ -use configuration::{shared::constants::THIS_IS_A_BUG, types::Arg}; +use configuration::types::Arg; +use support::constants::THIS_IS_A_BUG; use crate::{network_spec::node::NodeSpec, shared::constants::*}; diff --git a/crates/orchestrator/src/generators/keystore.rs b/crates/orchestrator/src/generators/keystore.rs index 01edca2d2268ef126aa1a81d1c19a548c36881aa..16eae1ce81c2c69154bba961e0966e55ca4f8286 100644 --- a/crates/orchestrator/src/generators/keystore.rs +++ b/crates/orchestrator/src/generators/keystore.rs @@ -3,9 +3,8 @@ use std::{ vec, }; -use configuration::shared::constants::THIS_IS_A_BUG; use hex::encode; -use support::fs::FileSystem; +use support::{constants::THIS_IS_A_BUG, fs::FileSystem}; use super::errors::GeneratorError; use crate::{shared::types::NodeAccounts, ScopedFilesystem}; diff --git a/crates/orchestrator/src/generators/port.rs b/crates/orchestrator/src/generators/port.rs index e2175e91a1250d666e8c0e3a1e91bc329cd55827..409061e0118360f5dd49740cb9de9fc63bea48fe 100644 --- a/crates/orchestrator/src/generators/port.rs +++ b/crates/orchestrator/src/generators/port.rs @@ -1,6 +1,7 @@ use std::net::TcpListener; -use configuration::shared::{constants::THIS_IS_A_BUG, types::Port}; +use configuration::shared::types::Port; +use support::constants::THIS_IS_A_BUG; use super::errors::GeneratorError; use crate::shared::types::ParkedPort; diff --git a/crates/orchestrator/src/network/parachain.rs b/crates/orchestrator/src/network/parachain.rs index 16e38cddbec284d9a8e791c2ae62d4d97a6da986..e5a8e77aefa93a915c5c11fe02ea978209f230a4 100644 --- a/crates/orchestrator/src/network/parachain.rs +++ b/crates/orchestrator/src/network/parachain.rs @@ -3,11 +3,10 @@ use std::{ str::FromStr, }; -use configuration::shared::constants::THIS_IS_A_BUG; use provider::types::TransferedFile; use subxt::{dynamic::Value, tx::TxStatus, OnlineClient, SubstrateConfig}; use subxt_signer::{sr25519::Keypair, SecretUri}; -use support::fs::FileSystem; +use support::{constants::THIS_IS_A_BUG, fs::FileSystem}; use tracing::info; // use crate::generators::key::generate_pair; diff --git a/crates/orchestrator/src/network_spec.rs b/crates/orchestrator/src/network_spec.rs index 5ea3b0191666865d23fcaa6bcd30c665170ca6fd..15c637c06401b076ab4148bfd003f4aee0233f32 100644 --- a/crates/orchestrator/src/network_spec.rs +++ b/crates/orchestrator/src/network_spec.rs @@ -3,11 +3,10 @@ use std::{ sync::Arc, }; -use configuration::{ - shared::constants::THIS_IS_A_BUG, GlobalSettings, HrmpChannelConfig, NetworkConfig, -}; +use configuration::{GlobalSettings, HrmpChannelConfig, NetworkConfig}; use futures::future::try_join_all; use provider::{ProviderError, ProviderNamespace}; +use support::constants::THIS_IS_A_BUG; use tracing::debug; use crate::errors::OrchestratorError; diff --git a/crates/orchestrator/src/network_spec/node.rs b/crates/orchestrator/src/network_spec/node.rs index f44c531d5fe9e7d6cd3636d4ffb495f7f9d3000d..3c315d6d42a806805d6eda3136675e0ccd57f82f 100644 --- a/crates/orchestrator/src/network_spec/node.rs +++ b/crates/orchestrator/src/network_spec/node.rs @@ -1,11 +1,11 @@ use configuration::shared::{ - constants::THIS_IS_A_BUG, node::{EnvVar, NodeConfig}, resources::Resources, types::{Arg, AssetLocation, Command, Image}, }; use multiaddr::Multiaddr; use provider::types::Port; +use support::constants::THIS_IS_A_BUG; use crate::{ errors::OrchestratorError, diff --git a/crates/orchestrator/src/network_spec/parachain.rs b/crates/orchestrator/src/network_spec/parachain.rs index a353f0fb04ade78345bb1bdb7f686fc179ad478b..da9f9b7f05a5e85c0d116e2198a7435d3466678e 100644 --- a/crates/orchestrator/src/network_spec/parachain.rs +++ b/crates/orchestrator/src/network_spec/parachain.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf}; use configuration::{ shared::resources::Resources, @@ -6,7 +6,7 @@ use configuration::{ ParachainConfig, RegistrationStrategy, }; use provider::DynNamespace; -use support::fs::FileSystem; +use support::{fs::FileSystem, replacer::apply_replacements}; use tracing::debug; use super::node::NodeSpec; @@ -16,7 +16,7 @@ use crate::{ chain_spec::{ChainSpec, Context}, para_artifact::*, }, - shared::types::ChainDefaultContext, + shared::{constants::DEFAULT_CHAIN_SPEC_TPL_COMMAND, types::ChainDefaultContext}, ScopedFilesystem, }; @@ -113,9 +113,20 @@ impl ParachainSpec { } else { // TODO: Do we need to add the posibility to set the command to use? // Currently (v1) is possible but when is set is set to the default command. + + let replacements = HashMap::from([ + ("disableBootnodes", "--disable-default-bootnode"), + ("mainCommand", main_cmd.as_str()), + ]); + let tmpl = if let Some(tmpl) = config.chain_spec_command() { + apply_replacements(tmpl, &replacements) + } else { + apply_replacements(DEFAULT_CHAIN_SPEC_TPL_COMMAND, &replacements) + }; + Some( chain_spec_builder - .command(main_cmd.as_str()) + .command(tmpl.as_str()) .image(main_image.clone()), ) } diff --git a/crates/orchestrator/src/network_spec/relaychain.rs b/crates/orchestrator/src/network_spec/relaychain.rs index ee4a678ed6424102df42572a6476dc973bc01511..3e2f1e73e56f274f5cc545ce100cbae0f0b7cec2 100644 --- a/crates/orchestrator/src/network_spec/relaychain.rs +++ b/crates/orchestrator/src/network_spec/relaychain.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use configuration::{ shared::{ resources::Resources, @@ -5,12 +7,13 @@ use configuration::{ }, RelaychainConfig, }; +use support::replacer::apply_replacements; use super::node::NodeSpec; use crate::{ errors::OrchestratorError, generators::chain_spec::{ChainSpec, Context}, - shared::types::ChainDefaultContext, + shared::{constants::DEFAULT_CHAIN_SPEC_TPL_COMMAND, types::ChainDefaultContext}, }; /// A relaychain configuration spec @@ -75,11 +78,17 @@ impl RelaychainSpec { let chain_spec = if let Some(chain_spec_path) = config.chain_spec_path() { chain_spec.asset_location(chain_spec_path.clone()) } else { - // TODO: Do we need to add the posibility to set the command to use? - // Currently (v1) is possible but when is set is set to the default command. - chain_spec - .command(main_cmd.as_str()) - .image(main_image.clone()) + let replacements = HashMap::from([ + ("disableBootnodes", "--disable-default-bootnode"), + ("mainCommand", main_cmd.as_str()), + ]); + let tmpl = if let Some(tmpl) = config.chain_spec_command() { + apply_replacements(tmpl, &replacements) + } else { + apply_replacements(DEFAULT_CHAIN_SPEC_TPL_COMMAND, &replacements) + }; + + chain_spec.command(tmpl.as_str()).image(main_image.clone()) }; // build the `node_specs` diff --git a/crates/orchestrator/src/shared/constants.rs b/crates/orchestrator/src/shared/constants.rs index 59e880bffa680f0cc4549aa86f03960e8325332c..70342f609ecb8c97bfa8ed9d25291b3633005e3e 100644 --- a/crates/orchestrator/src/shared/constants.rs +++ b/crates/orchestrator/src/shared/constants.rs @@ -6,3 +6,6 @@ pub const RPC_PORT: u16 = 9944; pub const RPC_HTTP_PORT: u16 = 9933; // P2P default port pub const P2P_PORT: u16 = 30333; +// default command template to build chain-spec +pub const DEFAULT_CHAIN_SPEC_TPL_COMMAND: &str = + "{{mainCommand}} build-spec --chain {{chainName}} {{disableBootnodes}}"; diff --git a/crates/orchestrator/src/spawner.rs b/crates/orchestrator/src/spawner.rs index af355cd09ac395be3b451d670d921050f0690cfc..0bf332d3a1b8a83a67616f921f48064c88e598b1 100644 --- a/crates/orchestrator/src/spawner.rs +++ b/crates/orchestrator/src/spawner.rs @@ -1,14 +1,13 @@ use std::{collections::HashMap, path::PathBuf}; use anyhow::Context; -use configuration::shared::constants::THIS_IS_A_BUG; use provider::{ constants::{LOCALHOST, NODE_CONFIG_DIR, NODE_DATA_DIR, NODE_RELAY_DATA_DIR, P2P_PORT}, shared::helpers::running_in_ci, types::{SpawnNodeOptions, TransferedFile}, DynNamespace, }; -use support::fs::FileSystem; +use support::{constants::THIS_IS_A_BUG, fs::FileSystem}; use tracing::info; use crate::{ diff --git a/crates/provider/src/docker/namespace.rs b/crates/provider/src/docker/namespace.rs index 29dbeba4121a3897ecb7bf17b8bb61f0275718ed..06c030689dc85b973407be938a7f725a2a2c5c33 100644 --- a/crates/provider/src/docker/namespace.rs +++ b/crates/provider/src/docker/namespace.rs @@ -6,8 +6,7 @@ use std::{ use anyhow::anyhow; use async_trait::async_trait; -use configuration::shared::constants::THIS_IS_A_BUG; -use support::fs::FileSystem; +use support::{constants::THIS_IS_A_BUG, fs::FileSystem}; use tokio::sync::{Mutex, RwLock}; use tracing::{debug, trace}; use uuid::Uuid; diff --git a/crates/provider/src/docker/node.rs b/crates/provider/src/docker/node.rs index e85c70db26d128c4449e7971a7d378f85b489d2a..e78e6a965a9ee8482f4123fbb0201ca85c8ee479 100644 --- a/crates/provider/src/docker/node.rs +++ b/crates/provider/src/docker/node.rs @@ -8,9 +8,9 @@ use std::{ use anyhow::anyhow; use async_trait::async_trait; -use configuration::{shared::constants::THIS_IS_A_BUG, types::AssetLocation}; +use configuration::types::AssetLocation; use futures::future::try_join_all; -use support::fs::FileSystem; +use support::{constants::THIS_IS_A_BUG, fs::FileSystem}; use tokio::{time::sleep, try_join}; use tracing::debug; diff --git a/crates/provider/src/kubernetes/client.rs b/crates/provider/src/kubernetes/client.rs index 8aac49a18b2e107c2d5bd0ba5ce9be5bba0c2b0b..9d14dfc94aa7297da94188fa40fc11b9b548aa2c 100644 --- a/crates/provider/src/kubernetes/client.rs +++ b/crates/provider/src/kubernetes/client.rs @@ -4,7 +4,6 @@ use std::{ }; use anyhow::anyhow; -use configuration::shared::constants::THIS_IS_A_BUG; use futures::{StreamExt, TryStreamExt}; use k8s_openapi::api::core::v1::{ ConfigMap, Namespace, Pod, PodSpec, PodStatus, Service, ServiceSpec, @@ -17,6 +16,7 @@ use kube::{ Api, Resource, }; use serde::de::DeserializeOwned; +use support::constants::THIS_IS_A_BUG; use tokio::{io::AsyncRead, net::TcpListener, task::JoinHandle}; use tokio_util::compat::FuturesAsyncReadCompatExt; use tracing::{debug, trace}; diff --git a/crates/provider/src/kubernetes/namespace.rs b/crates/provider/src/kubernetes/namespace.rs index 7d4f2ddd274d16aaad217057aba2147d6199cf0e..ac43623888c40b24def288599fc5be35d156df26 100644 --- a/crates/provider/src/kubernetes/namespace.rs +++ b/crates/provider/src/kubernetes/namespace.rs @@ -7,14 +7,13 @@ use std::{ use anyhow::anyhow; use async_trait::async_trait; -use configuration::shared::constants::THIS_IS_A_BUG; use k8s_openapi::{ api::core::v1::{ Container, ContainerPort, HTTPGetAction, PodSpec, Probe, ServicePort, ServiceSpec, }, apimachinery::pkg::util::intstr::IntOrString, }; -use support::fs::FileSystem; +use support::{constants::THIS_IS_A_BUG, fs::FileSystem, replacer::apply_replacements}; use tokio::sync::{Mutex, RwLock}; use tracing::{debug, trace}; use uuid::Uuid; @@ -23,7 +22,7 @@ use super::{client::KubernetesClient, node::KubernetesNode}; use crate::{ constants::NAMESPACE_PREFIX, kubernetes::node::KubernetesNodeOptions, - shared::helpers::{self, running_in_ci}, + shared::helpers::running_in_ci, types::{ GenerateFileCommand, GenerateFilesOptions, ProviderCapabilities, RunCommandOptions, SpawnNodeOptions, @@ -153,7 +152,7 @@ where } async fn initialize_static_resources(&self) -> Result<(), ProviderError> { - let np_manifest = helpers::apply_replacements( + let np_manifest = apply_replacements( include_str!("./static-configs/namespace-network-policy.yaml"), &HashMap::from([("namespace", self.name())]), ); diff --git a/crates/provider/src/kubernetes/node.rs b/crates/provider/src/kubernetes/node.rs index f8f1f4fd17121fcd22550b91d456b46c7739b2fd..402c317300150bae3bc1617a7724f05d12c52add 100644 --- a/crates/provider/src/kubernetes/node.rs +++ b/crates/provider/src/kubernetes/node.rs @@ -9,14 +9,11 @@ use std::{ use anyhow::anyhow; use async_trait::async_trait; -use configuration::{ - shared::{constants::THIS_IS_A_BUG, resources::Resources}, - types::AssetLocation, -}; +use configuration::{shared::resources::Resources, types::AssetLocation}; use futures::future::try_join_all; use k8s_openapi::api::core::v1::{ServicePort, ServiceSpec}; use sha2::Digest; -use support::fs::FileSystem; +use support::{constants::THIS_IS_A_BUG, fs::FileSystem}; use tokio::{sync::RwLock, task::JoinHandle, time::sleep, try_join}; use tracing::trace; use url::Url; diff --git a/crates/provider/src/native/node.rs b/crates/provider/src/native/node.rs index 4523e818177a420731f6fb8c1ad8986a8932304a..ea2cb94d3a5972cee45e59365943063b7532539a 100644 --- a/crates/provider/src/native/node.rs +++ b/crates/provider/src/native/node.rs @@ -7,7 +7,7 @@ use std::{ use anyhow::anyhow; use async_trait::async_trait; -use configuration::{shared::constants::THIS_IS_A_BUG, types::AssetLocation}; +use configuration::types::AssetLocation; use flate2::read::GzDecoder; use futures::future::try_join_all; use nix::{ @@ -15,7 +15,7 @@ use nix::{ unistd::Pid, }; use sha2::Digest; -use support::fs::FileSystem; +use support::{constants::THIS_IS_A_BUG, fs::FileSystem}; use tar::Archive; use tokio::{ io::{AsyncRead, AsyncReadExt, BufReader}, diff --git a/crates/provider/src/shared/helpers.rs b/crates/provider/src/shared/helpers.rs index 68983061aeef6d67f49aa85c68f5ee7099281178..58ca72b0efe2a0edf31ae900d896ed0d33681761 100644 --- a/crates/provider/src/shared/helpers.rs +++ b/crates/provider/src/shared/helpers.rs @@ -1,27 +1,4 @@ -use std::{collections::HashMap, env}; - -use configuration::shared::constants::VALID_REGEX; -use regex::{Captures, Regex}; - -pub(crate) fn apply_replacements(text: &str, replacements: &HashMap<&str, &str>) -> String { - let re = Regex::new(r#"\{\{([a-zA-Z0-9_]*)\}\}"#).unwrap_or_else(|_| { - panic!( - "{} {}", - VALID_REGEX, - configuration::shared::constants::THIS_IS_A_BUG - ) - }); - - let augmented_text = re.replace_all(text, |caps: &Captures| { - if let Some(replacements_value) = replacements.get(&caps[1]) { - replacements_value.to_string() - } else { - caps[0].to_string() - } - }); - - augmented_text.to_string() -} +use std::env; /// Check if we are running in `CI` by checking the 'RUN_IN_CI' env var pub fn running_in_ci() -> bool { @@ -32,52 +9,6 @@ pub fn running_in_ci() -> bool { mod tests { use super::*; - #[test] - fn replace_should_works() { - let text = "some {{namespace}}"; - let mut replacements = HashMap::new(); - replacements.insert("namespace", "demo-123"); - let res = apply_replacements(text, &replacements); - assert_eq!("some demo-123".to_string(), res); - } - - #[test] - fn replace_multiple_should_works() { - let text = r#"some {{namespace}} - other is {{other}}"#; - let augmented_text = r#"some demo-123 - other is other-123"#; - - let mut replacements = HashMap::new(); - replacements.insert("namespace", "demo-123"); - replacements.insert("other", "other-123"); - let res = apply_replacements(text, &replacements); - assert_eq!(augmented_text, res); - } - - #[test] - fn replace_multiple_with_missing_should_works() { - let text = r#"some {{namespace}} - other is {{other}}"#; - let augmented_text = r#"some demo-123 - other is {{other}}"#; - - let mut replacements = HashMap::new(); - replacements.insert("namespace", "demo-123"); - - let res = apply_replacements(text, &replacements); - assert_eq!(augmented_text, res); - } - - #[test] - fn replace_without_replacement_should_leave_text_unchanged() { - let text = "some {{namespace}}"; - let mut replacements = HashMap::new(); - replacements.insert("other", "demo-123"); - let res = apply_replacements(text, &replacements); - assert_eq!(text.to_string(), res); - } - #[test] fn check_runing_in_ci_env_var() { assert!(!running_in_ci()); diff --git a/crates/support/Cargo.toml b/crates/support/Cargo.toml index 1b5c097973523150b3d32b29b15efe379b268060..563fb062204503981d3c036348eaf0ccecd20228 100644 --- a/crates/support/Cargo.toml +++ b/crates/support/Cargo.toml @@ -22,3 +22,4 @@ tokio = { workspace = true, features = ["full"] } uuid = { workspace = true, features = ["v4"] } nix = { workspace = true, features = ["signal"] } rand = { workspace = true } +regex = { workspace = true } diff --git a/crates/configuration/src/shared/constants.rs b/crates/support/src/constants.rs similarity index 100% rename from crates/configuration/src/shared/constants.rs rename to crates/support/src/constants.rs diff --git a/crates/support/src/lib.rs b/crates/support/src/lib.rs index 57ee38c4b3ebf08d43463c2c3aa29778bfaed2c0..b0b8e81b06cfe3faeffbbfa41182c7508b94066d 100644 --- a/crates/support/src/lib.rs +++ b/crates/support/src/lib.rs @@ -1,2 +1,4 @@ +pub mod constants; pub mod fs; pub mod net; +pub mod replacer; diff --git a/crates/support/src/replacer.rs b/crates/support/src/replacer.rs new file mode 100644 index 0000000000000000000000000000000000000000..c2f89185ee14b76913c0a7ebda541d3419a09324 --- /dev/null +++ b/crates/support/src/replacer.rs @@ -0,0 +1,71 @@ +use std::collections::HashMap; + +use regex::{Captures, Regex}; + +use crate::constants::{THIS_IS_A_BUG, VALID_REGEX}; + +pub fn apply_replacements(text: &str, replacements: &HashMap<&str, &str>) -> String { + let re = Regex::new(r#"\{\{([a-zA-Z0-9_]*)\}\}"#) + .unwrap_or_else(|_| panic!("{} {}", VALID_REGEX, THIS_IS_A_BUG)); + + let augmented_text = re.replace_all(text, |caps: &Captures| { + if let Some(replacements_value) = replacements.get(&caps[1]) { + replacements_value.to_string() + } else { + caps[0].to_string() + } + }); + + augmented_text.to_string() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn replace_should_works() { + let text = "some {{namespace}}"; + let mut replacements = HashMap::new(); + replacements.insert("namespace", "demo-123"); + let res = apply_replacements(text, &replacements); + assert_eq!("some demo-123".to_string(), res); + } + + #[test] + fn replace_multiple_should_works() { + let text = r#"some {{namespace}} + other is {{other}}"#; + let augmented_text = r#"some demo-123 + other is other-123"#; + + let mut replacements = HashMap::new(); + replacements.insert("namespace", "demo-123"); + replacements.insert("other", "other-123"); + let res = apply_replacements(text, &replacements); + assert_eq!(augmented_text, res); + } + + #[test] + fn replace_multiple_with_missing_should_works() { + let text = r#"some {{namespace}} + other is {{other}}"#; + let augmented_text = r#"some demo-123 + other is {{other}}"#; + + let mut replacements = HashMap::new(); + replacements.insert("namespace", "demo-123"); + + let res = apply_replacements(text, &replacements); + assert_eq!(augmented_text, res); + } + + #[test] + fn replace_without_replacement_should_leave_text_unchanged() { + let text = "some {{namespace}}"; + let mut replacements = HashMap::new(); + replacements.insert("other", "demo-123"); + let res = apply_replacements(text, &replacements); + assert_eq!(text.to_string(), res); + } +}