From f787529842e22d59721a829d96040a4d0a7ad7c4 Mon Sep 17 00:00:00 2001 From: Javier Viola <363911+pepoviola@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:28:10 -0300 Subject: [PATCH] feat: add support to build chain-spec with a custom command (#204) --- crates/configuration/Cargo.toml | 3 + crates/configuration/src/network.rs | 7 +- crates/configuration/src/parachain.rs | 38 ++++++++++ crates/configuration/src/relaychain.rs | 39 +++++++++- crates/configuration/src/shared.rs | 1 - crates/configuration/src/shared/helpers.rs | 3 +- crates/configuration/src/shared/resources.rs | 2 +- crates/configuration/src/shared/types.rs | 2 +- .../orchestrator/src/generators/chain_spec.rs | 63 +++++++++++----- crates/orchestrator/src/generators/command.rs | 3 +- .../orchestrator/src/generators/keystore.rs | 3 +- crates/orchestrator/src/generators/port.rs | 3 +- crates/orchestrator/src/network/parachain.rs | 3 +- crates/orchestrator/src/network_spec.rs | 5 +- crates/orchestrator/src/network_spec/node.rs | 2 +- .../src/network_spec/parachain.rs | 19 +++-- .../src/network_spec/relaychain.rs | 21 ++++-- crates/orchestrator/src/shared/constants.rs | 3 + crates/orchestrator/src/spawner.rs | 3 +- crates/provider/src/docker/namespace.rs | 3 +- crates/provider/src/docker/node.rs | 4 +- crates/provider/src/kubernetes/client.rs | 2 +- crates/provider/src/kubernetes/namespace.rs | 7 +- crates/provider/src/kubernetes/node.rs | 7 +- crates/provider/src/native/node.rs | 4 +- crates/provider/src/shared/helpers.rs | 71 +------------------ crates/support/Cargo.toml | 1 + .../src/shared => support/src}/constants.rs | 0 crates/support/src/lib.rs | 2 + crates/support/src/replacer.rs | 71 +++++++++++++++++++ 30 files changed, 261 insertions(+), 134 deletions(-) rename crates/{configuration/src/shared => support/src}/constants.rs (100%) create mode 100644 crates/support/src/replacer.rs diff --git a/crates/configuration/Cargo.toml b/crates/configuration/Cargo.toml index 6672b1c..3995f0f 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 b8918a1..31b2ff6 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 3952afd..e2533f0 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 760be05..e605103 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 36b71c4..bb1d7bf 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 ee0a65e..c111e66 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 79f53fb..cdd820f 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 c1ae162..23bf307 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 fd9ed40..5d44e47 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 75a3acd..1adb490 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 01edca2..16eae1c 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 e2175e9..409061e 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 16e38cd..e5a8e77 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 5ea3b01..15c637c 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 f44c531..3c315d6 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 a353f0f..da9f9b7 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 ee4a678..3e2f1e7 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 59e880b..70342f6 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 af355cd..0bf332d 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 29dbeba..06c0306 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 e85c70d..e78e6a9 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 8aac49a..9d14dfc 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 7d4f2dd..ac43623 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 f8f1f4f..402c317 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 4523e81..ea2cb94 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 6898306..58ca72b 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 1b5c097..563fb06 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 57ee38c..b0b8e81 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 0000000..c2f8918 --- /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); + } +} -- GitLab