Skip to content
Snippets Groups Projects
Verified Commit 4b37c0f4 authored by Loris Moulin's avatar Loris Moulin
Browse files

feat: added port validation in NodeConfigBuilder using ValidationContext

parent 4c3d46d9
Branches
No related merge requests found
use super::types::ParaId;
use super::types::{ParaId, Port};
/// An error at the configuration level.
#[derive(thiserror::Error, Debug)]
......@@ -66,6 +66,18 @@ pub enum FieldError {
#[error("limit_cpu: {0}")]
LimitCpu(anyhow::Error),
#[error("ws_port: {0}")]
WsPort(anyhow::Error),
#[error("rpc_port: {0}")]
RpcPort(anyhow::Error),
#[error("prometheus_port: {0}")]
PrometheusPort(anyhow::Error),
#[error("p2p_port: {0}")]
P2pPort(anyhow::Error),
}
/// A conversion error for shared types across fields.
......@@ -80,3 +92,10 @@ pub enum ConversionError {
#[error("can't be empty")]
CantBeEmpty,
}
/// A validation error for shared types across fields.
#[derive(thiserror::Error, Debug, Clone)]
pub enum ValidationError {
#[error("'{0}' is already used")]
PortAlreadyUsed(Port),
}
use std::{cell::RefCell, rc::Rc};
use super::{
errors::ValidationError,
types::{Port, ValidationContext},
};
pub fn merge_errors(errors: Vec<anyhow::Error>, new_error: anyhow::Error) -> Vec<anyhow::Error> {
let mut errors = errors;
errors.push(new_error);
......@@ -17,3 +24,19 @@ pub fn merge_errors_vecs(
errors
}
pub fn ensure_port_unique(
port: Port,
validation_context: Rc<RefCell<ValidationContext>>,
) -> Result<(), anyhow::Error> {
let mut context = validation_context
.try_borrow_mut()
.expect("must be borrowable as mutable, this is a bug please report it: https://github.com/paritytech/zombienet-sdk/issues");
if !context.used_ports.contains(&port) {
context.used_ports.push(port);
return Ok(());
}
Err(ValidationError::PortAlreadyUsed(port).into())
}
......@@ -4,7 +4,7 @@ use multiaddr::Multiaddr;
use super::{
errors::FieldError,
helpers::{merge_errors, merge_errors_vecs},
helpers::{ensure_port_unique, merge_errors, merge_errors_vecs},
macros::states,
resources::ResourcesBuilder,
types::{AssetLocation, ChainDefaultContext, Command, Image, ValidationContext},
......@@ -422,50 +422,78 @@ impl NodeConfigBuilder<Buildable> {
/// Set the websocket port that will be exposed. Uniqueness across config will be checked.
pub fn with_ws_port(self, ws_port: Port) -> Self {
Self::transition(
NodeConfig {
ws_port: Some(ws_port),
..self.config
},
self.validation_context,
self.errors,
)
match ensure_port_unique(ws_port, self.validation_context.clone()) {
Ok(_) => Self::transition(
NodeConfig {
ws_port: Some(ws_port),
..self.config
},
self.validation_context,
self.errors,
),
Err(error) => Self::transition(
self.config,
self.validation_context,
merge_errors(self.errors, FieldError::WsPort(error).into()),
),
}
}
/// Set the RPC port that will be exposed. Uniqueness across config will be checked.
pub fn with_rpc_port(self, rpc_port: Port) -> Self {
Self::transition(
NodeConfig {
rpc_port: Some(rpc_port),
..self.config
},
self.validation_context,
self.errors,
)
match ensure_port_unique(rpc_port, self.validation_context.clone()) {
Ok(_) => Self::transition(
NodeConfig {
rpc_port: Some(rpc_port),
..self.config
},
self.validation_context,
self.errors,
),
Err(error) => Self::transition(
self.config,
self.validation_context,
merge_errors(self.errors, FieldError::RpcPort(error).into()),
),
}
}
/// Set the prometheus port that will be exposed for metrics. Uniqueness across config will be checked.
pub fn with_prometheus_port(self, prometheus_port: Port) -> Self {
Self::transition(
NodeConfig {
prometheus_port: Some(prometheus_port),
..self.config
},
self.validation_context,
self.errors,
)
match ensure_port_unique(prometheus_port, self.validation_context.clone()) {
Ok(_) => Self::transition(
NodeConfig {
prometheus_port: Some(prometheus_port),
..self.config
},
self.validation_context,
self.errors,
),
Err(error) => Self::transition(
self.config,
self.validation_context,
merge_errors(self.errors, FieldError::PrometheusPort(error).into()),
),
}
}
/// Set the P2P port that will be exposed. Uniqueness across will be checked.
/// Set the P2P port that will be exposed. Uniqueness across config will be checked.
pub fn with_p2p_port(self, p2p_port: Port) -> Self {
Self::transition(
NodeConfig {
p2p_port: Some(p2p_port),
..self.config
},
self.validation_context,
self.errors,
)
match ensure_port_unique(p2p_port, self.validation_context.clone()) {
Ok(_) => Self::transition(
NodeConfig {
p2p_port: Some(p2p_port),
..self.config
},
self.validation_context,
self.errors,
),
Err(error) => Self::transition(
self.config,
self.validation_context,
merge_errors(self.errors, FieldError::P2pPort(error).into()),
),
}
}
/// Set the P2P cert hash that will be used as part of the multiaddress
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment