diff --git a/control_plane/src/storage.rs b/control_plane/src/storage.rs index d1f6e421d0..b201fd1f7a 100644 --- a/control_plane/src/storage.rs +++ b/control_plane/src/storage.rs @@ -96,7 +96,11 @@ impl PageServerNode { .unwrap() } - pub fn init(&self, create_tenant: Option<&str>) -> anyhow::Result<()> { + pub fn init( + &self, + create_tenant: Option<&str>, + config_overrides: &[&str], + ) -> anyhow::Result<()> { let mut cmd = Command::new(self.env.pageserver_bin()?); let var = "LLVM_PROFILE_FILE"; if let Some(val) = std::env::var_os(var) { @@ -104,32 +108,38 @@ impl PageServerNode { } // FIXME: the paths should be shell-escaped to handle paths with spaces, quotas etc. - let mut args = vec![ - "--init".to_string(), - "-D".to_string(), - self.env.base_data_dir.display().to_string(), - "-c".to_string(), - format!("pg_distrib_dir='{}'", self.env.pg_distrib_dir.display()), - "-c".to_string(), - format!("auth_type='{}'", self.env.pageserver.auth_type), - "-c".to_string(), - format!( - "listen_http_addr='{}'", - self.env.pageserver.listen_http_addr - ), - "-c".to_string(), - format!("listen_pg_addr='{}'", self.env.pageserver.listen_pg_addr), - ]; + let base_data_dir_param = self.env.base_data_dir.display().to_string(); + let pg_distrib_dir_param = + format!("pg_distrib_dir='{}'", self.env.pg_distrib_dir.display()); + let authg_type_param = format!("auth_type='{}'", self.env.pageserver.auth_type); + let listen_http_addr_param = format!( + "listen_http_addr='{}'", + self.env.pageserver.listen_http_addr + ); + let listen_pg_addr_param = + format!("listen_pg_addr='{}'", self.env.pageserver.listen_pg_addr); + let mut args = Vec::with_capacity(20); + + args.push("--init"); + args.extend(["-D", &base_data_dir_param]); + args.extend(["-c", &pg_distrib_dir_param]); + args.extend(["-c", &authg_type_param]); + args.extend(["-c", &listen_http_addr_param]); + args.extend(["-c", &listen_pg_addr_param]); + + for config_override in config_overrides { + args.extend(["-c", config_override]); + } if self.env.pageserver.auth_type != AuthType::Trust { args.extend([ - "-c".to_string(), - "auth_validation_public_key_path='auth_public_key.pem'".to_string(), + "-c", + "auth_validation_public_key_path='auth_public_key.pem'", ]); } if let Some(tenantid) = create_tenant { - args.extend(["--create-tenant".to_string(), tenantid.to_string()]) + args.extend(["--create-tenant", tenantid]) } let status = cmd @@ -154,7 +164,7 @@ impl PageServerNode { self.repo_path().join("pageserver.pid") } - pub fn start(&self) -> anyhow::Result<()> { + pub fn start(&self, config_overrides: &[&str]) -> anyhow::Result<()> { print!( "Starting pageserver at '{}' in '{}'", connection_address(&self.pg_connection_config), @@ -163,7 +173,15 @@ impl PageServerNode { io::stdout().flush().unwrap(); let mut cmd = Command::new(self.env.pageserver_bin()?); - cmd.args(&["-D", self.repo_path().to_str().unwrap()]) + + let repo_path = self.repo_path(); + let mut args = vec!["-D", repo_path.to_str().unwrap()]; + + for config_override in config_overrides { + args.extend(["-c", config_override]); + } + + cmd.args(&args) .arg("--daemonize") .env_clear() .env("RUST_BACKTRACE", "1"); diff --git a/pageserver/src/bin/pageserver.rs b/pageserver/src/bin/pageserver.rs index 8905724839..d3a78b0954 100644 --- a/pageserver/src/bin/pageserver.rs +++ b/pageserver/src/bin/pageserver.rs @@ -53,12 +53,12 @@ fn main() -> Result<()> { ) // See `settings.md` for more details on the extra configuration patameters pageserver can process .arg( - Arg::with_name("config-option") + Arg::with_name("config-override") .short("c") .takes_value(true) .number_of_values(1) .multiple(true) - .help("Additional configuration options or overrides of the ones from the toml config file. + .help("Additional configuration overrides of the ones from the toml config file (or new ones to add there). Any option has to be a valid toml document, example: `-c \"foo='hey'\"` `-c \"foo={value=1}\"`"), ) .get_matches(); @@ -105,7 +105,7 @@ fn main() -> Result<()> { }; // Process any extra options given with -c - if let Some(values) = arg_matches.values_of("config-option") { + if let Some(values) = arg_matches.values_of("config-override") { for option_line in values { let doc = toml_edit::Document::from_str(option_line).with_context(|| { format!( diff --git a/test_runner/README.md b/test_runner/README.md index b305b2cc25..81436dcd45 100644 --- a/test_runner/README.md +++ b/test_runner/README.md @@ -47,6 +47,9 @@ Useful environment variables: `TEST_OUTPUT`: Set the directory where test state and test output files should go. `TEST_SHARED_FIXTURES`: Try to re-use a single pageserver for all the tests. +`ZENITH_PAGESERVER_OVERRIDES`: add a `;`-separated set of configs that will be passed as +`--pageserver-config-override=${value}` parameter values when zenith cli is invoked +`RUST_LOG`: logging configuration to pass into Zenith CLI Let stdout, stderr and `INFO` log messages go to the terminal instead of capturing them: `pytest -s --log-cli-level=INFO ...` diff --git a/zenith/src/main.rs b/zenith/src/main.rs index d73ee8a297..505bd4905f 100644 --- a/zenith/src/main.rs +++ b/zenith/src/main.rs @@ -102,12 +102,21 @@ fn main() -> Result<()> { .required(false) .value_name("stop-mode"); + let pageserver_config_args = Arg::with_name("pageserver-config-override") + .long("pageserver-config-override") + .takes_value(true) + .number_of_values(1) + .multiple(true) + .help("Additional pageserver's configuration options or overrides, refer to pageserver's 'pageserver-config-override' CLI parameter docs for more") + .required(false); + let matches = App::new("Zenith CLI") .setting(AppSettings::ArgRequiredElseHelp) .version(GIT_VERSION) .subcommand( SubCommand::with_name("init") .about("Initialize a new Zenith repository") + .arg(pageserver_config_args.clone()) .arg( Arg::with_name("config") .long("config") @@ -133,10 +142,10 @@ fn main() -> Result<()> { .setting(AppSettings::ArgRequiredElseHelp) .about("Manage pageserver") .subcommand(SubCommand::with_name("status")) - .subcommand(SubCommand::with_name("start").about("Start local pageserver")) + .subcommand(SubCommand::with_name("start").about("Start local pageserver").arg(pageserver_config_args.clone())) .subcommand(SubCommand::with_name("stop").about("Stop local pageserver") .arg(stop_mode_arg.clone())) - .subcommand(SubCommand::with_name("restart").about("Restart local pageserver")) + .subcommand(SubCommand::with_name("restart").about("Restart local pageserver").arg(pageserver_config_args)) ) .subcommand( SubCommand::with_name("safekeeper") @@ -403,6 +412,7 @@ fn handle_init(init_match: &ArgMatches) -> Result<()> { if let Err(e) = pageserver.init( // default_tenantid was generated by the `env.init()` call above Some(&env.default_tenantid.unwrap().to_string()), + &pageserver_config_overrides(init_match), ) { eprintln!("pageserver init failed: {}", e); exit(1); @@ -411,6 +421,14 @@ fn handle_init(init_match: &ArgMatches) -> Result<()> { Ok(()) } +fn pageserver_config_overrides<'a>(init_match: &'a ArgMatches) -> Vec<&'a str> { + init_match + .values_of("pageserver-config-override") + .into_iter() + .flatten() + .collect() +} + fn handle_tenant(tenant_match: &ArgMatches, env: &local_env::LocalEnv) -> Result<()> { let pageserver = PageServerNode::from_env(env); match tenant_match.subcommand() { @@ -572,8 +590,8 @@ fn handle_pageserver(sub_match: &ArgMatches, env: &local_env::LocalEnv) -> Resul let pageserver = PageServerNode::from_env(env); match sub_match.subcommand() { - ("start", Some(_sub_m)) => { - if let Err(e) = pageserver.start() { + ("start", Some(start_match)) => { + if let Err(e) = pageserver.start(&pageserver_config_overrides(start_match)) { eprintln!("pageserver start failed: {}", e); exit(1); } @@ -588,22 +606,20 @@ fn handle_pageserver(sub_match: &ArgMatches, env: &local_env::LocalEnv) -> Resul } } - ("restart", Some(_sub_m)) => { + ("restart", Some(restart_match)) => { //TODO what shutdown strategy should we use here? if let Err(e) = pageserver.stop(false) { eprintln!("pageserver stop failed: {}", e); exit(1); } - if let Err(e) = pageserver.start() { + if let Err(e) = pageserver.start(&pageserver_config_overrides(restart_match)) { eprintln!("pageserver start failed: {}", e); exit(1); } } - (sub_name, _) => { - bail!("Unexpected pageserver subcommand '{}'", sub_name) - } + (sub_name, _) => bail!("Unexpected pageserver subcommand '{}'", sub_name), } Ok(()) } @@ -662,12 +678,12 @@ fn handle_safekeeper(sub_match: &ArgMatches, env: &local_env::LocalEnv) -> Resul Ok(()) } -fn handle_start_all(_sub_match: &ArgMatches, env: &local_env::LocalEnv) -> Result<()> { +fn handle_start_all(sub_match: &ArgMatches, env: &local_env::LocalEnv) -> Result<()> { let pageserver = PageServerNode::from_env(env); // Postgres nodes are not started automatically - if let Err(e) = pageserver.start() { + if let Err(e) = pageserver.start(&pageserver_config_overrides(sub_match)) { eprintln!("pageserver start failed: {}", e); exit(1); }