Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: supports reading config values from CLI #605

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
9 changes: 9 additions & 0 deletions crates/notary/server/src/domain/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,13 @@ pub struct CliFields {
/// Configuration file location
#[structopt(long, default_value = "./config/config.yaml")]
pub config_file: String,

#[structopt(long)]
pub port: Option<u16>,

#[structopt(long)]
pub tls_enabled: Option<bool>,

#[structopt(long)]
pub log_level: Option<String>,
}
2 changes: 2 additions & 0 deletions crates/notary/server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod middleware;
mod server;
mod server_tracing;
mod service;
mod settings;
mod signing;
mod util;

Expand All @@ -19,4 +20,5 @@ pub use domain::{
pub use error::NotaryServerError;
pub use server::{read_pem_file, run_server};
pub use server_tracing::init_tracing;
pub use settings::Settings;
pub use util::parse_config_file;
20 changes: 12 additions & 8 deletions crates/notary/server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,27 @@ use structopt::StructOpt;
use tracing::debug;

use notary_server::{
init_tracing, parse_config_file, run_server, CliFields, NotaryServerError,
NotaryServerProperties,
init_tracing, run_server, CliFields, NotaryServerError,
Settings,
};

#[tokio::main]
async fn main() -> Result<(), NotaryServerError> {
// Load command line arguments which contains the config file location
// Load command line arguments
let cli_fields: CliFields = CliFields::from_args();
let config: NotaryServerProperties = parse_config_file(&cli_fields.config_file)?;

// Load and merge configurations
let settings = Settings::new(&cli_fields)
.map_err(|err| eyre!("Failed to load settings: {}", err))?;

// Set up tracing for logging
init_tracing(&config).map_err(|err| eyre!("Failed to set up tracing: {err}"))?;
init_tracing(&settings.config)
.map_err(|err| eyre!("Failed to set up tracing: {err}"))?;

debug!(?config, "Server config loaded");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets keep one debug log instead

debug!(?settings, "Server settings loaded");

// Run the server
run_server(&config).await?;
run_server(&settings.config).await?;

Ok(())
}
}
77 changes: 77 additions & 0 deletions crates/notary/server/src/settings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use config::{Config, ConfigError, Environment, File};
anthonykimani marked this conversation as resolved.
Show resolved Hide resolved
use std::path::Path;
use tracing::{info, warn};
use crate::{CliFields, NotaryServerProperties};
use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub struct Settings {
#[serde(flatten)]
pub config: NotaryServerProperties,
}

impl Settings {
pub fn new(cli_fields: &CliFields) -> Result<Self, ConfigError> {
let mut builder = Config::builder();

// Add default values
builder = builder
anthonykimani marked this conversation as resolved.
Show resolved Hide resolved
.set_default("server.name", "notary-server")?
.set_default("server.host", "0.0.0.0")?
.set_default("server.port", 7047)?
.set_default("server.html-info", "<h1>Notary Server</h1>")?
.set_default("notarization.max-sent-data", 4096)?
.set_default("notarization.max-recv-data", 16384)?
.set_default("tls.enabled", true)?
.set_default("tls.private-key-pem-path", "../fixture/tls/notary.key")?
.set_default("tls.certificate-pem-path", "../fixture/tls/notary.crt")?
.set_default("notary-key.private-key-pem-path", "../fixture/notary/notary.key")?
.set_default("notary-key.public-key-pem-path", "../fixture/notary/notary.pub")?
.set_default("logging.level", "DEBUG")?
.set_default("logging.filter", Option::<String>::None)?
.set_default("authorization.enabled", false)?
.set_default("authorization.whitelist-csv-path", "../fixture/auth/whitelist.csv")?;

// Add the config file if it exists
let config_path = Path::new(&cli_fields.config_file);
if config_path.exists() {
info!("Loading configuration from: {}", cli_fields.config_file);
builder = builder.add_source(File::from(config_path));
} else {
warn!("Config file not found: {}. Using defaults and overrides.", cli_fields.config_file);
anthonykimani marked this conversation as resolved.
Show resolved Hide resolved
}

// Add environment variables
builder = builder.add_source(Environment::with_prefix("NOTARY_SERVER").separator("__"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: so env var will override config file; and CLI will override both of them; is that right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anthonykimani can u help to address this question?


// Add CLI overrides
if let Some(port) = cli_fields.port {
builder = builder.set_override("server.port", port)?;
}
if let Some(tls_enabled) = cli_fields.tls_enabled {
builder = builder.set_override("tls.enabled", tls_enabled)?;
}
if let Some(log_level) = &cli_fields.log_level {
builder = builder.set_override("logging.level", log_level.clone())?;
}

let config = builder.build()?;
let settings: Settings = config.try_deserialize()?;

// Validate file existence
Self::validate_file_exists(&settings.config.tls.private_key_pem_path, "TLS private key")?;
anthonykimani marked this conversation as resolved.
Show resolved Hide resolved
Self::validate_file_exists(&settings.config.tls.certificate_pem_path, "TLS certificate")?;
Self::validate_file_exists(&settings.config.notary_key.private_key_pem_path, "Notary private key")?;
Self::validate_file_exists(&settings.config.notary_key.public_key_pem_path, "Notary public key")?;

Ok(settings)
}

fn validate_file_exists(path: &str, file_type: &str) -> Result<(), ConfigError> {
if !Path::new(path).exists() {
Err(ConfigError::NotFound(format!("{} file not found: {}", file_type, path)))
} else {
Ok(())
}
}
}
Loading