Node envconfig (#382)
* Move config to a new location * Log config override with env variables * Network config override with env variables * Http env vars * Consensus env vars
This commit is contained in:
parent
ea64b74aa6
commit
8e0937beb7
|
@ -7,6 +7,7 @@ consensus:
|
|||
fountain_settings: null
|
||||
overlay_settings:
|
||||
nodes: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]]
|
||||
leader_super_majority_threshold: 1
|
||||
leader:
|
||||
cur: 0
|
||||
network:
|
||||
|
@ -14,7 +15,7 @@ network:
|
|||
host: 0.0.0.0
|
||||
port: 3000
|
||||
log_level: "fatal"
|
||||
nodeKey: null
|
||||
node_key: "0000000000000000000000000000000000000000000000000000000000000001"
|
||||
discV5BootstrapNodes: []
|
||||
initial_peers: []
|
||||
relayTopics: []
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
use std::{
|
||||
net::{IpAddr, SocketAddr},
|
||||
path::PathBuf,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::Carnot;
|
||||
use clap::{Parser, ValueEnum};
|
||||
use color_eyre::eyre::{self, eyre, Result};
|
||||
use hex::FromHex;
|
||||
#[cfg(feature = "metrics")]
|
||||
use metrics::{backend::map::MapMetricsBackend, types::MetricsData, MetricsService};
|
||||
use nomos_http::{backends::axum::AxumBackend, http::HttpService};
|
||||
#[cfg(feature = "libp2p")]
|
||||
use nomos_libp2p::{secp256k1::SecretKey, Multiaddr};
|
||||
use nomos_log::{Logger, LoggerBackend, LoggerFormat};
|
||||
#[cfg(feature = "libp2p")]
|
||||
use nomos_network::backends::libp2p::Libp2p;
|
||||
#[cfg(feature = "waku")]
|
||||
use nomos_network::backends::waku::Waku;
|
||||
use nomos_network::NetworkService;
|
||||
use overwatch_rs::services::ServiceData;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::Level;
|
||||
#[cfg(feature = "waku")]
|
||||
use waku_bindings::{Multiaddr, SecretKey};
|
||||
|
||||
#[derive(ValueEnum, Clone, Debug, Default)]
|
||||
pub enum LoggerBackendType {
|
||||
Gelf,
|
||||
File,
|
||||
#[default]
|
||||
Stdout,
|
||||
Stderr,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct LogArgs {
|
||||
/// Address for the Gelf backend
|
||||
#[clap(long = "log-addr", env = "LOG_ADDR", required_if_eq("backend", "Gelf"))]
|
||||
log_addr: Option<SocketAddr>,
|
||||
|
||||
/// Directory for the File backend
|
||||
#[clap(long = "log-dir", env = "LOG_DIR", required_if_eq("backend", "File"))]
|
||||
directory: Option<PathBuf>,
|
||||
|
||||
/// Prefix for the File backend
|
||||
#[clap(long = "log-path", env = "LOG_PATH", required_if_eq("backend", "File"))]
|
||||
prefix: Option<PathBuf>,
|
||||
|
||||
/// Backend type
|
||||
#[clap(long = "log-backend", env = "LOG_BACKEND", value_enum)]
|
||||
backend: Option<LoggerBackendType>,
|
||||
|
||||
#[clap(long = "log-format", env = "LOG_FORMAT")]
|
||||
format: Option<String>,
|
||||
|
||||
#[clap(long = "log-level", env = "LOG_LEVEL")]
|
||||
level: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct NetworkArgs {
|
||||
#[clap(long = "net-host", env = "NET_HOST")]
|
||||
host: Option<IpAddr>,
|
||||
|
||||
#[clap(long = "net-port", env = "NET_PORT")]
|
||||
port: Option<usize>,
|
||||
|
||||
#[clap(long = "net-node-key", env = "NET_NODE_KEY")]
|
||||
node_key: Option<String>,
|
||||
|
||||
#[clap(long = "net-initial-peers", env = "NET_INITIAL_PEERS")]
|
||||
pub initial_peers: Option<Vec<Multiaddr>>,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct HttpArgs {
|
||||
#[clap(long = "http-host", env = "HTTP_HOST")]
|
||||
http_addr: Option<SocketAddr>,
|
||||
|
||||
#[clap(long = "http-cors-origin", env = "HTTP_CORS_ORIGIN")]
|
||||
pub cors_origins: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct ConsensusArgs {
|
||||
#[clap(long = "consensus-priv-key", env = "CONSENSUS_PRIV_KEY")]
|
||||
consensus_priv_key: Option<String>,
|
||||
|
||||
#[clap(long = "consensus-timeout-secs", env = "CONSENSUS_TIMEOUT_SECS")]
|
||||
consensus_timeout_secs: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Clone, Debug, Default)]
|
||||
pub enum OverlayType {
|
||||
#[default]
|
||||
Flat,
|
||||
Tree,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct OverlayArgs {
|
||||
// TODO: Act on type and support other overlays.
|
||||
#[clap(long = "overlay-type", env = "OVERLAY_TYPE")]
|
||||
pub overlay_type: Option<OverlayType>,
|
||||
|
||||
#[clap(long = "overlay-nodes", env = "OVERLAY_NODES")]
|
||||
pub overlay_nodes: Option<Vec<String>>,
|
||||
|
||||
#[clap(long = "overlay-leader", env = "OVERLAY_LEADER")]
|
||||
pub overlay_leader: Option<usize>,
|
||||
|
||||
#[clap(
|
||||
long = "overlay-leader-super-majority-threshold",
|
||||
env = "OVERLAY_LEADER_SUPER_MAJORITY_THRESHOLD"
|
||||
)]
|
||||
pub overlay_leader_super_majority_threshold: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Serialize)]
|
||||
pub struct Config {
|
||||
pub log: <Logger as ServiceData>::Settings,
|
||||
#[cfg(feature = "waku")]
|
||||
pub network: <NetworkService<Waku> as ServiceData>::Settings,
|
||||
#[cfg(feature = "libp2p")]
|
||||
pub network: <NetworkService<Libp2p> as ServiceData>::Settings,
|
||||
pub http: <HttpService<AxumBackend> as ServiceData>::Settings,
|
||||
pub consensus: <Carnot as ServiceData>::Settings,
|
||||
#[cfg(feature = "metrics")]
|
||||
pub metrics: <MetricsService<MapMetricsBackend<MetricsData>> as ServiceData>::Settings,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn update_log(mut self, log_args: LogArgs) -> Result<Self> {
|
||||
let LogArgs {
|
||||
backend,
|
||||
log_addr: addr,
|
||||
directory,
|
||||
prefix,
|
||||
format,
|
||||
level,
|
||||
} = log_args;
|
||||
|
||||
// Override the file config with the one from env variables.
|
||||
if let Some(backend) = backend {
|
||||
self.log.backend = match backend {
|
||||
LoggerBackendType::Gelf => LoggerBackend::Gelf {
|
||||
addr: addr.ok_or_else(|| eyre!("Gelf backend requires an address."))?,
|
||||
},
|
||||
LoggerBackendType::File => LoggerBackend::File {
|
||||
directory: directory
|
||||
.ok_or_else(|| eyre!("File backend requires a directory."))?,
|
||||
prefix,
|
||||
},
|
||||
LoggerBackendType::Stdout => LoggerBackend::Stdout,
|
||||
LoggerBackendType::Stderr => LoggerBackend::Stderr,
|
||||
}
|
||||
};
|
||||
|
||||
// Update parts of the config.
|
||||
if let Some(format_str) = format {
|
||||
self.log.format = match format_str.as_str() {
|
||||
"Json" => LoggerFormat::Json,
|
||||
"Plain" => LoggerFormat::Plain,
|
||||
_ => return Err(eyre!("Invalid log format provided.")),
|
||||
};
|
||||
}
|
||||
if let Some(level_str) = level {
|
||||
self.log.level = match level_str.as_str() {
|
||||
"DEBUG" => Level::DEBUG,
|
||||
_ => return Err(eyre!("Invalid log level provided.")),
|
||||
};
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[cfg(feature = "waku")]
|
||||
pub fn update_network(mut self, network_args: NetworkArgs) -> Result<Self> {
|
||||
let NetworkArgs {
|
||||
host,
|
||||
port,
|
||||
node_key,
|
||||
initial_peers,
|
||||
} = network_args;
|
||||
|
||||
if let Some(host) = host {
|
||||
self.network.backend.inner.host = Some(host);
|
||||
}
|
||||
|
||||
if let Some(port) = port {
|
||||
self.network.backend.inner.port = Some(port);
|
||||
}
|
||||
|
||||
if let Some(node_key) = node_key {
|
||||
use std::str::FromStr;
|
||||
self.network.backend.inner.node_key = Some(SecretKey::from_str(&node_key)?);
|
||||
}
|
||||
|
||||
if let Some(peers) = initial_peers {
|
||||
self.network.backend.initial_peers = peers;
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[cfg(feature = "libp2p")]
|
||||
pub fn update_network(mut self, network_args: NetworkArgs) -> Result<Self> {
|
||||
let NetworkArgs {
|
||||
host,
|
||||
port,
|
||||
node_key,
|
||||
initial_peers,
|
||||
} = network_args;
|
||||
|
||||
if let Some(IpAddr::V4(h)) = host {
|
||||
self.network.backend.host = h;
|
||||
} else if host.is_some() {
|
||||
return Err(eyre!("Unsupported ip version"));
|
||||
}
|
||||
|
||||
if let Some(port) = port {
|
||||
self.network.backend.port = port as u16;
|
||||
}
|
||||
|
||||
if let Some(node_key) = node_key {
|
||||
let mut key_bytes = hex::decode(node_key)?;
|
||||
self.network.backend.node_key = SecretKey::try_from_bytes(key_bytes.as_mut_slice())?;
|
||||
}
|
||||
|
||||
if let Some(peers) = initial_peers {
|
||||
self.network.backend.initial_peers = peers;
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn update_http(mut self, http_args: HttpArgs) -> Result<Self> {
|
||||
let HttpArgs {
|
||||
http_addr,
|
||||
cors_origins,
|
||||
} = http_args;
|
||||
|
||||
if let Some(addr) = http_addr {
|
||||
self.http.backend.address = addr;
|
||||
}
|
||||
|
||||
if let Some(cors) = cors_origins {
|
||||
self.http.backend.cors_origins = cors;
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn update_consensus(mut self, consensus_args: ConsensusArgs) -> Result<Self> {
|
||||
let ConsensusArgs {
|
||||
consensus_priv_key,
|
||||
consensus_timeout_secs,
|
||||
} = consensus_args;
|
||||
|
||||
if let Some(private_key) = consensus_priv_key {
|
||||
let bytes = <[u8; 32]>::from_hex(private_key)?;
|
||||
self.consensus.private_key = bytes;
|
||||
}
|
||||
|
||||
if let Some(timeout) = consensus_timeout_secs {
|
||||
let secs = timeout.parse::<u64>()?;
|
||||
self.consensus.timeout = Duration::from_secs(secs);
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn update_overlay(mut self, overlay_args: OverlayArgs) -> Result<Self> {
|
||||
let OverlayArgs {
|
||||
overlay_nodes,
|
||||
overlay_leader_super_majority_threshold,
|
||||
..
|
||||
} = overlay_args;
|
||||
|
||||
if let Some(nodes) = overlay_nodes {
|
||||
self.consensus.overlay_settings.nodes = nodes
|
||||
.iter()
|
||||
.map(|n| {
|
||||
<[u8; 32]>::from_hex(n)
|
||||
.map_err(|e| eyre::eyre!("Failed to decode hex: {}", e))
|
||||
.map(|b| b.into())
|
||||
})
|
||||
.collect::<Result<Vec<_>, eyre::Report>>()?;
|
||||
}
|
||||
|
||||
if let Some(threshold) = overlay_leader_super_majority_threshold {
|
||||
self.consensus
|
||||
.overlay_settings
|
||||
.leader_super_majority_threshold = Some(threshold.into());
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
mod blob;
|
||||
mod config;
|
||||
mod tx;
|
||||
|
||||
use color_eyre::eyre::Result;
|
||||
|
@ -14,8 +15,6 @@ use nomos_core::fountain::mock::MockFountain;
|
|||
use nomos_http::backends::axum::AxumBackend;
|
||||
use nomos_http::bridge::HttpBridgeService;
|
||||
use nomos_http::http::HttpService;
|
||||
#[cfg(feature = "libp2p")]
|
||||
use nomos_libp2p::secp256k1::SecretKey;
|
||||
use nomos_log::Logger;
|
||||
#[cfg(feature = "libp2p")]
|
||||
use nomos_mempool::network::adapters::libp2p::Libp2pAdapter as MempoolLibp2pAdapter;
|
||||
|
@ -28,49 +27,15 @@ use nomos_network::backends::libp2p::Libp2p;
|
|||
use nomos_network::backends::waku::Waku;
|
||||
use nomos_network::NetworkService;
|
||||
use overwatch_derive::*;
|
||||
use overwatch_rs::services::{handle::ServiceHandle, ServiceData};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "waku")]
|
||||
use waku_bindings::SecretKey;
|
||||
use overwatch_rs::services::handle::ServiceHandle;
|
||||
|
||||
use crate::blob::Blob;
|
||||
pub use config::{Config, ConsensusArgs, HttpArgs, LogArgs, NetworkArgs, OverlayArgs};
|
||||
pub use tx::Tx;
|
||||
|
||||
#[cfg(all(feature = "waku", feature = "libp2p"))]
|
||||
compile_error!("feature \"waku\" and feature \"libp2p\" cannot be enabled at the same time");
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Serialize)]
|
||||
pub struct Config {
|
||||
pub log: <Logger as ServiceData>::Settings,
|
||||
#[cfg(feature = "waku")]
|
||||
pub network: <NetworkService<Waku> as ServiceData>::Settings,
|
||||
#[cfg(feature = "libp2p")]
|
||||
pub network: <NetworkService<Libp2p> as ServiceData>::Settings,
|
||||
pub http: <HttpService<AxumBackend> as ServiceData>::Settings,
|
||||
pub consensus: <Carnot as ServiceData>::Settings,
|
||||
#[cfg(feature = "metrics")]
|
||||
pub metrics: <MetricsService<MapMetricsBackend<MetricsData>> as ServiceData>::Settings,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn set_node_key(&mut self, node_key: Option<String>) -> Result<()> {
|
||||
if let Some(node_key) = node_key {
|
||||
#[cfg(feature = "waku")]
|
||||
{
|
||||
use std::str::FromStr;
|
||||
self.network.backend.inner.node_key = Some(SecretKey::from_str(&node_key)?)
|
||||
}
|
||||
#[cfg(feature = "libp2p")]
|
||||
{
|
||||
let mut key_bytes = hex::decode(node_key)?;
|
||||
self.network.backend.node_key =
|
||||
SecretKey::try_from_bytes(key_bytes.as_mut_slice())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "waku")]
|
||||
pub type Carnot = CarnotConsensus<
|
||||
ConsensusWakuAdapter,
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use nomos_node::{Config, Nomos, NomosServiceSettings, Tx};
|
||||
use nomos_node::{
|
||||
Config, ConsensusArgs, HttpArgs, LogArgs, NetworkArgs, Nomos, NomosServiceSettings,
|
||||
OverlayArgs, Tx,
|
||||
};
|
||||
|
||||
mod bridges;
|
||||
|
||||
|
@ -22,15 +25,38 @@ use std::sync::Arc;
|
|||
struct Args {
|
||||
/// Path for a yaml-encoded network config file
|
||||
config: std::path::PathBuf,
|
||||
/// Overrides node key in config file
|
||||
#[clap(long = "node-key")]
|
||||
node_key: Option<String>,
|
||||
/// Overrides log config.
|
||||
#[clap(flatten)]
|
||||
log_args: LogArgs,
|
||||
/// Overrides network config.
|
||||
#[clap(flatten)]
|
||||
network_args: NetworkArgs,
|
||||
/// Overrides http config.
|
||||
#[clap(flatten)]
|
||||
http_args: HttpArgs,
|
||||
/// Overrides consensus config.
|
||||
#[clap(flatten)]
|
||||
consensus_args: ConsensusArgs,
|
||||
/// Overrides overlay config.
|
||||
#[clap(flatten)]
|
||||
overlay_args: OverlayArgs,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let Args { config, node_key } = Args::parse();
|
||||
let mut config = serde_yaml::from_reader::<_, Config>(std::fs::File::open(config)?)?;
|
||||
config.set_node_key(node_key)?;
|
||||
let Args {
|
||||
config,
|
||||
log_args,
|
||||
http_args,
|
||||
network_args,
|
||||
consensus_args,
|
||||
overlay_args,
|
||||
} = Args::parse();
|
||||
let config = serde_yaml::from_reader::<_, Config>(std::fs::File::open(config)?)?
|
||||
.update_log(log_args)?
|
||||
.update_http(http_args)?
|
||||
.update_consensus(consensus_args)?
|
||||
.update_overlay(overlay_args)?
|
||||
.update_network(network_args)?;
|
||||
|
||||
let bridges: Vec<HttpBridge> = vec![
|
||||
Arc::new(Box::new(bridges::carnot_info_bridge)),
|
||||
|
|
Loading…
Reference in New Issue