mirror of
https://github.com/neondatabase/neon.git
synced 2026-03-15 14:20:38 +00:00
Compare commits
34 Commits
split-prox
...
problame/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1e21c7705 | ||
|
|
004af53035 | ||
|
|
d8702dd819 | ||
|
|
5f04224817 | ||
|
|
9c547da6a6 | ||
|
|
6d343feef0 | ||
|
|
f73c8c6bd6 | ||
|
|
51224c84c2 | ||
|
|
6bccd64514 | ||
|
|
28c95e4207 | ||
|
|
aacf8110a0 | ||
|
|
70977afd07 | ||
|
|
7363b44b50 | ||
|
|
cc64e1b17f | ||
|
|
25dfafc2df | ||
|
|
d72fe6f5ee | ||
|
|
0bca1a5de3 | ||
|
|
511f593360 | ||
|
|
b96e0b2458 | ||
|
|
b4ed3b15b9 | ||
|
|
ad185dd594 | ||
|
|
58055c7a96 | ||
|
|
ec04f0f4d4 | ||
|
|
a52b563b59 | ||
|
|
89afba066c | ||
|
|
6bcb0959ad | ||
|
|
8f3051b416 | ||
|
|
998dc6255e | ||
|
|
700aa96770 | ||
|
|
4a72fe0908 | ||
|
|
923cdff13d | ||
|
|
498edfc0ff | ||
|
|
d2e2a88737 | ||
|
|
6f720eb38f |
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1348,6 +1348,7 @@ dependencies = [
|
|||||||
"tokio-postgres",
|
"tokio-postgres",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"toml",
|
"toml",
|
||||||
|
"toml_edit",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
"utils",
|
"utils",
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ serde_with.workspace = true
|
|||||||
tar.workspace = true
|
tar.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
toml.workspace = true
|
toml.workspace = true
|
||||||
|
toml_edit.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
tokio-postgres.workspace = true
|
tokio-postgres.workspace = true
|
||||||
tokio-util.workspace = true
|
tokio-util.workspace = true
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ fn main() -> Result<()> {
|
|||||||
let subcommand_result = match sub_name {
|
let subcommand_result = match sub_name {
|
||||||
"tenant" => rt.block_on(handle_tenant(sub_args, &mut env)),
|
"tenant" => rt.block_on(handle_tenant(sub_args, &mut env)),
|
||||||
"timeline" => rt.block_on(handle_timeline(sub_args, &mut env)),
|
"timeline" => rt.block_on(handle_timeline(sub_args, &mut env)),
|
||||||
"start" => rt.block_on(handle_start_all(sub_args, &env)),
|
"start" => rt.block_on(handle_start_all(&env)),
|
||||||
"stop" => rt.block_on(handle_stop_all(sub_args, &env)),
|
"stop" => rt.block_on(handle_stop_all(sub_args, &env)),
|
||||||
"pageserver" => rt.block_on(handle_pageserver(sub_args, &env)),
|
"pageserver" => rt.block_on(handle_pageserver(sub_args, &env)),
|
||||||
"storage_controller" => rt.block_on(handle_storage_controller(sub_args, &env)),
|
"storage_controller" => rt.block_on(handle_storage_controller(sub_args, &env)),
|
||||||
@@ -358,6 +358,13 @@ fn handle_init(init_match: &ArgMatches) -> anyhow::Result<LocalEnv> {
|
|||||||
default_conf(*num_pageservers)
|
default_conf(*num_pageservers)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pageserver_config: toml_edit::Document =
|
||||||
|
if let Some(path) = init_match.get_one::<PathBuf>("pageserver-config") {
|
||||||
|
std::fs::read_to_string(path)?.parse()?
|
||||||
|
} else {
|
||||||
|
toml_edit::Document::new()
|
||||||
|
};
|
||||||
|
|
||||||
let pg_version = init_match
|
let pg_version = init_match
|
||||||
.get_one::<u32>("pg-version")
|
.get_one::<u32>("pg-version")
|
||||||
.copied()
|
.copied()
|
||||||
@@ -375,7 +382,7 @@ fn handle_init(init_match: &ArgMatches) -> anyhow::Result<LocalEnv> {
|
|||||||
// Initialize pageserver, create initial tenant and timeline.
|
// Initialize pageserver, create initial tenant and timeline.
|
||||||
for ps_conf in &env.pageservers {
|
for ps_conf in &env.pageservers {
|
||||||
PageServerNode::from_env(&env, ps_conf)
|
PageServerNode::from_env(&env, ps_conf)
|
||||||
.initialize(&pageserver_config_overrides(init_match))
|
.initialize(&pageserver_config)
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
eprintln!("pageserver init failed: {e:?}");
|
eprintln!("pageserver init failed: {e:?}");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -397,15 +404,6 @@ fn get_default_pageserver(env: &local_env::LocalEnv) -> PageServerNode {
|
|||||||
PageServerNode::from_env(env, ps_conf)
|
PageServerNode::from_env(env, ps_conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pageserver_config_overrides(init_match: &ArgMatches) -> Vec<&str> {
|
|
||||||
init_match
|
|
||||||
.get_many::<String>("pageserver-config-override")
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.map(String::as_str)
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_tenant(
|
async fn handle_tenant(
|
||||||
tenant_match: &ArgMatches,
|
tenant_match: &ArgMatches,
|
||||||
env: &mut local_env::LocalEnv,
|
env: &mut local_env::LocalEnv,
|
||||||
@@ -1068,10 +1066,7 @@ fn get_pageserver(env: &local_env::LocalEnv, args: &ArgMatches) -> Result<PageSe
|
|||||||
async fn handle_pageserver(sub_match: &ArgMatches, env: &local_env::LocalEnv) -> Result<()> {
|
async fn handle_pageserver(sub_match: &ArgMatches, env: &local_env::LocalEnv) -> Result<()> {
|
||||||
match sub_match.subcommand() {
|
match sub_match.subcommand() {
|
||||||
Some(("start", subcommand_args)) => {
|
Some(("start", subcommand_args)) => {
|
||||||
if let Err(e) = get_pageserver(env, subcommand_args)?
|
if let Err(e) = get_pageserver(env, subcommand_args)?.start().await {
|
||||||
.start(&pageserver_config_overrides(subcommand_args))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
eprintln!("pageserver start failed: {e}");
|
eprintln!("pageserver start failed: {e}");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -1097,10 +1092,7 @@ async fn handle_pageserver(sub_match: &ArgMatches, env: &local_env::LocalEnv) ->
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = pageserver
|
if let Err(e) = pageserver.start().await {
|
||||||
.start(&pageserver_config_overrides(subcommand_args))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
eprintln!("pageserver start failed: {e}");
|
eprintln!("pageserver start failed: {e}");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -1227,7 +1219,7 @@ async fn handle_safekeeper(sub_match: &ArgMatches, env: &local_env::LocalEnv) ->
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_start_all(sub_match: &ArgMatches, env: &local_env::LocalEnv) -> anyhow::Result<()> {
|
async fn handle_start_all(env: &local_env::LocalEnv) -> anyhow::Result<()> {
|
||||||
// Endpoints are not started automatically
|
// Endpoints are not started automatically
|
||||||
|
|
||||||
broker::start_broker_process(env).await?;
|
broker::start_broker_process(env).await?;
|
||||||
@@ -1244,10 +1236,7 @@ async fn handle_start_all(sub_match: &ArgMatches, env: &local_env::LocalEnv) ->
|
|||||||
|
|
||||||
for ps_conf in &env.pageservers {
|
for ps_conf in &env.pageservers {
|
||||||
let pageserver = PageServerNode::from_env(env, ps_conf);
|
let pageserver = PageServerNode::from_env(env, ps_conf);
|
||||||
if let Err(e) = pageserver
|
if let Err(e) = pageserver.start().await {
|
||||||
.start(&pageserver_config_overrides(sub_match))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
eprintln!("pageserver {} start failed: {:#}", ps_conf.id, e);
|
eprintln!("pageserver {} start failed: {:#}", ps_conf.id, e);
|
||||||
try_stop_all(env, true).await;
|
try_stop_all(env, true).await;
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -1388,13 +1377,6 @@ fn cli() -> Command {
|
|||||||
.required(false)
|
.required(false)
|
||||||
.value_name("stop-mode");
|
.value_name("stop-mode");
|
||||||
|
|
||||||
let pageserver_config_args = Arg::new("pageserver-config-override")
|
|
||||||
.long("pageserver-config-override")
|
|
||||||
.num_args(1)
|
|
||||||
.action(ArgAction::Append)
|
|
||||||
.help("Additional pageserver's configuration options or overrides, refer to pageserver's 'config-override' CLI parameter docs for more")
|
|
||||||
.required(false);
|
|
||||||
|
|
||||||
let remote_ext_config_args = Arg::new("remote-ext-config")
|
let remote_ext_config_args = Arg::new("remote-ext-config")
|
||||||
.long("remote-ext-config")
|
.long("remote-ext-config")
|
||||||
.num_args(1)
|
.num_args(1)
|
||||||
@@ -1450,14 +1432,21 @@ fn cli() -> Command {
|
|||||||
.subcommand(
|
.subcommand(
|
||||||
Command::new("init")
|
Command::new("init")
|
||||||
.about("Initialize a new Neon repository, preparing configs for services to start with")
|
.about("Initialize a new Neon repository, preparing configs for services to start with")
|
||||||
.arg(pageserver_config_args.clone())
|
|
||||||
.arg(num_pageservers_arg.clone())
|
.arg(num_pageservers_arg.clone())
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("config")
|
Arg::new("config")
|
||||||
.long("config")
|
.long("config")
|
||||||
.required(false)
|
.required(false)
|
||||||
.value_parser(value_parser!(PathBuf))
|
.value_parser(value_parser!(PathBuf))
|
||||||
.value_name("config"),
|
.value_name("config")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("pageserver-config")
|
||||||
|
.long("pageserver-config")
|
||||||
|
.required(false)
|
||||||
|
.value_parser(value_parser!(PathBuf))
|
||||||
|
.value_name("pageserver-config")
|
||||||
|
.help("Merge the provided pageserver config into the one generated by neon_local."),
|
||||||
)
|
)
|
||||||
.arg(pg_version_arg.clone())
|
.arg(pg_version_arg.clone())
|
||||||
.arg(force_arg)
|
.arg(force_arg)
|
||||||
@@ -1539,7 +1528,6 @@ fn cli() -> Command {
|
|||||||
.subcommand(Command::new("status"))
|
.subcommand(Command::new("status"))
|
||||||
.subcommand(Command::new("start")
|
.subcommand(Command::new("start")
|
||||||
.about("Start local pageserver")
|
.about("Start local pageserver")
|
||||||
.arg(pageserver_config_args.clone())
|
|
||||||
)
|
)
|
||||||
.subcommand(Command::new("stop")
|
.subcommand(Command::new("stop")
|
||||||
.about("Stop local pageserver")
|
.about("Stop local pageserver")
|
||||||
@@ -1547,7 +1535,6 @@ fn cli() -> Command {
|
|||||||
)
|
)
|
||||||
.subcommand(Command::new("restart")
|
.subcommand(Command::new("restart")
|
||||||
.about("Restart local pageserver")
|
.about("Restart local pageserver")
|
||||||
.arg(pageserver_config_args.clone())
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@@ -1660,7 +1647,6 @@ fn cli() -> Command {
|
|||||||
.subcommand(
|
.subcommand(
|
||||||
Command::new("start")
|
Command::new("start")
|
||||||
.about("Start page server and safekeepers")
|
.about("Start page server and safekeepers")
|
||||||
.arg(pageserver_config_args)
|
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
Command::new("stop")
|
Command::new("stop")
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
//!
|
//!
|
||||||
//! .neon/
|
//! .neon/
|
||||||
//!
|
//!
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -77,7 +76,7 @@ impl PageServerNode {
|
|||||||
/// Merge overrides provided by the user on the command line with our default overides derived from neon_local configuration.
|
/// Merge overrides provided by the user on the command line with our default overides derived from neon_local configuration.
|
||||||
///
|
///
|
||||||
/// These all end up on the command line of the `pageserver` binary.
|
/// These all end up on the command line of the `pageserver` binary.
|
||||||
fn neon_local_overrides(&self, cli_overrides: &[&str]) -> Vec<String> {
|
fn neon_local_overrides(&self, cli_overrides: &toml_edit::Document) -> Vec<String> {
|
||||||
// FIXME: the paths should be shell-escaped to handle paths with spaces, quotas etc.
|
// FIXME: the paths should be shell-escaped to handle paths with spaces, quotas etc.
|
||||||
let pg_distrib_dir_param = format!(
|
let pg_distrib_dir_param = format!(
|
||||||
"pg_distrib_dir='{}'",
|
"pg_distrib_dir='{}'",
|
||||||
@@ -157,10 +156,7 @@ impl PageServerNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cli_overrides
|
if !cli_overrides.contains_key("remote_storage") {
|
||||||
.iter()
|
|
||||||
.any(|c| c.starts_with("remote_storage"))
|
|
||||||
{
|
|
||||||
overrides.push(format!(
|
overrides.push(format!(
|
||||||
"remote_storage={{local_path='../{PAGESERVER_REMOTE_STORAGE_DIR}'}}"
|
"remote_storage={{local_path='../{PAGESERVER_REMOTE_STORAGE_DIR}'}}"
|
||||||
));
|
));
|
||||||
@@ -173,13 +169,13 @@ impl PageServerNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply the user-provided overrides
|
// Apply the user-provided overrides
|
||||||
overrides.extend(cli_overrides.iter().map(|&c| c.to_owned()));
|
overrides.push(cli_overrides.to_string());
|
||||||
|
|
||||||
overrides
|
overrides
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes a pageserver node by creating its config with the overrides provided.
|
/// Initializes a pageserver node by creating its config with the overrides provided.
|
||||||
pub fn initialize(&self, config_overrides: &[&str]) -> anyhow::Result<()> {
|
pub fn initialize(&self, config_overrides: &toml_edit::Document) -> anyhow::Result<()> {
|
||||||
// First, run `pageserver --init` and wait for it to write a config into FS and exit.
|
// First, run `pageserver --init` and wait for it to write a config into FS and exit.
|
||||||
self.pageserver_init(config_overrides)
|
self.pageserver_init(config_overrides)
|
||||||
.with_context(|| format!("Failed to run init for pageserver node {}", self.conf.id))
|
.with_context(|| format!("Failed to run init for pageserver node {}", self.conf.id))
|
||||||
@@ -197,11 +193,11 @@ impl PageServerNode {
|
|||||||
.expect("non-Unicode path")
|
.expect("non-Unicode path")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(&self, config_overrides: &[&str]) -> anyhow::Result<()> {
|
pub async fn start(&self) -> anyhow::Result<()> {
|
||||||
self.start_node(config_overrides, false).await
|
self.start_node().await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pageserver_init(&self, config_overrides: &[&str]) -> anyhow::Result<()> {
|
fn pageserver_init(&self, config_overrides: &toml_edit::Document) -> anyhow::Result<()> {
|
||||||
let datadir = self.repo_path();
|
let datadir = self.repo_path();
|
||||||
let node_id = self.conf.id;
|
let node_id = self.conf.id;
|
||||||
println!(
|
println!(
|
||||||
@@ -219,11 +215,18 @@ impl PageServerNode {
|
|||||||
let datadir_path_str = datadir.to_str().with_context(|| {
|
let datadir_path_str = datadir.to_str().with_context(|| {
|
||||||
format!("Cannot start pageserver node {node_id} in path that has no string representation: {datadir:?}")
|
format!("Cannot start pageserver node {node_id} in path that has no string representation: {datadir:?}")
|
||||||
})?;
|
})?;
|
||||||
let mut args = self.pageserver_basic_args(config_overrides, datadir_path_str);
|
|
||||||
args.push(Cow::Borrowed("--init"));
|
|
||||||
|
|
||||||
|
// `pageserver --init` merges the `--config-override`s into a built-in default config,
|
||||||
|
// then writes out the merged product to `pageserver.toml`.
|
||||||
|
// TODO: just write the full `pageserver.toml` and get rid of `--config-override`.
|
||||||
|
let mut args = vec!["--init", "--workdir", datadir_path_str];
|
||||||
|
let overrides = self.neon_local_overrides(config_overrides);
|
||||||
|
for piece in &overrides {
|
||||||
|
args.push("--config-override");
|
||||||
|
args.push(piece);
|
||||||
|
}
|
||||||
let init_output = Command::new(self.env.pageserver_bin())
|
let init_output = Command::new(self.env.pageserver_bin())
|
||||||
.args(args.iter().map(Cow::as_ref))
|
.args(args)
|
||||||
.envs(self.pageserver_env_variables()?)
|
.envs(self.pageserver_env_variables()?)
|
||||||
.output()
|
.output()
|
||||||
.with_context(|| format!("Failed to run pageserver init for node {node_id}"))?;
|
.with_context(|| format!("Failed to run pageserver init for node {node_id}"))?;
|
||||||
@@ -262,11 +265,7 @@ impl PageServerNode {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_node(
|
async fn start_node(&self) -> anyhow::Result<()> {
|
||||||
&self,
|
|
||||||
config_overrides: &[&str],
|
|
||||||
update_config: bool,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
// TODO: using a thread here because start_process() is not async but we need to call check_status()
|
// TODO: using a thread here because start_process() is not async but we need to call check_status()
|
||||||
let datadir = self.repo_path();
|
let datadir = self.repo_path();
|
||||||
print!(
|
print!(
|
||||||
@@ -283,15 +282,12 @@ impl PageServerNode {
|
|||||||
self.conf.id, datadir,
|
self.conf.id, datadir,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let mut args = self.pageserver_basic_args(config_overrides, datadir_path_str);
|
let args = vec!["-D", datadir_path_str];
|
||||||
if update_config {
|
|
||||||
args.push(Cow::Borrowed("--update-config"));
|
|
||||||
}
|
|
||||||
background_process::start_process(
|
background_process::start_process(
|
||||||
"pageserver",
|
"pageserver",
|
||||||
&datadir,
|
&datadir,
|
||||||
&self.env.pageserver_bin(),
|
&self.env.pageserver_bin(),
|
||||||
args.iter().map(Cow::as_ref),
|
args,
|
||||||
self.pageserver_env_variables()?,
|
self.pageserver_env_variables()?,
|
||||||
background_process::InitialPidFile::Expect(self.pid_file()),
|
background_process::InitialPidFile::Expect(self.pid_file()),
|
||||||
|| async {
|
|| async {
|
||||||
@@ -308,22 +304,6 @@ impl PageServerNode {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pageserver_basic_args<'a>(
|
|
||||||
&self,
|
|
||||||
config_overrides: &'a [&'a str],
|
|
||||||
datadir_path_str: &'a str,
|
|
||||||
) -> Vec<Cow<'a, str>> {
|
|
||||||
let mut args = vec![Cow::Borrowed("-D"), Cow::Borrowed(datadir_path_str)];
|
|
||||||
|
|
||||||
let overrides = self.neon_local_overrides(config_overrides);
|
|
||||||
for config_override in overrides {
|
|
||||||
args.push(Cow::Borrowed("-c"));
|
|
||||||
args.push(Cow::Owned(config_override));
|
|
||||||
}
|
|
||||||
|
|
||||||
args
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pageserver_env_variables(&self) -> anyhow::Result<Vec<(String, String)>> {
|
fn pageserver_env_variables(&self) -> anyhow::Result<Vec<(String, String)>> {
|
||||||
// FIXME: why is this tied to pageserver's auth type? Whether or not the safekeeper
|
// FIXME: why is this tied to pageserver's auth type? Whether or not the safekeeper
|
||||||
// needs a token, and how to generate that token, seems independent to whether
|
// needs a token, and how to generate that token, seems independent to whether
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
//! Main entry point for the Page Server executable.
|
//! Main entry point for the Page Server executable.
|
||||||
|
|
||||||
use std::env::{var, VarError};
|
use std::env::{var, VarError};
|
||||||
|
use std::io::Read;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{env, ops::ControlFlow, str::FromStr};
|
use std::{env, ops::ControlFlow, str::FromStr};
|
||||||
@@ -151,37 +152,34 @@ fn initialize_config(
|
|||||||
workdir: &Utf8Path,
|
workdir: &Utf8Path,
|
||||||
) -> anyhow::Result<ControlFlow<(), &'static PageServerConf>> {
|
) -> anyhow::Result<ControlFlow<(), &'static PageServerConf>> {
|
||||||
let init = arg_matches.get_flag("init");
|
let init = arg_matches.get_flag("init");
|
||||||
let update_config = init || arg_matches.get_flag("update-config");
|
|
||||||
|
|
||||||
let (mut toml, config_file_exists) = if cfg_file_path.is_file() {
|
let file_contents: Option<toml_edit::Document> = match std::fs::File::open(cfg_file_path) {
|
||||||
if init {
|
Ok(mut f) => {
|
||||||
anyhow::bail!(
|
if init {
|
||||||
"Config file '{cfg_file_path}' already exists, cannot init it, use --update-config to update it",
|
anyhow::bail!("config file already exists: {cfg_file_path}");
|
||||||
);
|
}
|
||||||
|
let md = f.metadata().context("stat config file")?;
|
||||||
|
if md.is_file() {
|
||||||
|
let mut s = String::new();
|
||||||
|
f.read_to_string(&mut s).context("read config file")?;
|
||||||
|
Some(s.parse().context("parse config file toml")?)
|
||||||
|
} else {
|
||||||
|
anyhow::bail!("directory entry exists but is not a file: {cfg_file_path}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => None,
|
||||||
|
Err(e) => {
|
||||||
|
anyhow::bail!("open pageserver config: {e}: {cfg_file_path}");
|
||||||
}
|
}
|
||||||
// Supplement the CLI arguments with the config file
|
|
||||||
let cfg_file_contents = std::fs::read_to_string(cfg_file_path)
|
|
||||||
.with_context(|| format!("Failed to read pageserver config at '{cfg_file_path}'"))?;
|
|
||||||
(
|
|
||||||
cfg_file_contents
|
|
||||||
.parse::<toml_edit::Document>()
|
|
||||||
.with_context(|| {
|
|
||||||
format!("Failed to parse '{cfg_file_path}' as pageserver config")
|
|
||||||
})?,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
} else if cfg_file_path.exists() {
|
|
||||||
anyhow::bail!("Config file '{cfg_file_path}' exists but is not a regular file");
|
|
||||||
} else {
|
|
||||||
// We're initializing the tenant, so there's no config file yet
|
|
||||||
(
|
|
||||||
DEFAULT_CONFIG_FILE
|
|
||||||
.parse::<toml_edit::Document>()
|
|
||||||
.context("could not parse built-in config file")?,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut effective_config = file_contents.unwrap_or_else(|| {
|
||||||
|
DEFAULT_CONFIG_FILE
|
||||||
|
.parse()
|
||||||
|
.expect("unit tests ensure this works")
|
||||||
|
});
|
||||||
|
|
||||||
|
// Patch with overrides from the command line
|
||||||
if let Some(values) = arg_matches.get_many::<String>("config-override") {
|
if let Some(values) = arg_matches.get_many::<String>("config-override") {
|
||||||
for option_line in values {
|
for option_line in values {
|
||||||
let doc = toml_edit::Document::from_str(option_line).with_context(|| {
|
let doc = toml_edit::Document::from_str(option_line).with_context(|| {
|
||||||
@@ -189,22 +187,21 @@ fn initialize_config(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
for (key, item) in doc.iter() {
|
for (key, item) in doc.iter() {
|
||||||
if config_file_exists && update_config && key == "id" && toml.contains_key(key) {
|
effective_config.insert(key, item.clone());
|
||||||
anyhow::bail!("Pageserver config file exists at '{cfg_file_path}' and has node id already, it cannot be overridden");
|
|
||||||
}
|
|
||||||
toml.insert(key, item.clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Resulting toml: {toml}");
|
debug!("Resulting toml: {effective_config}");
|
||||||
let conf = PageServerConf::parse_and_validate(&toml, workdir)
|
|
||||||
|
// Construct the runtime representation
|
||||||
|
let conf = PageServerConf::parse_and_validate(&effective_config, workdir)
|
||||||
.context("Failed to parse pageserver configuration")?;
|
.context("Failed to parse pageserver configuration")?;
|
||||||
|
|
||||||
if update_config {
|
if init {
|
||||||
info!("Writing pageserver config to '{cfg_file_path}'");
|
info!("Writing pageserver config to '{cfg_file_path}'");
|
||||||
|
|
||||||
std::fs::write(cfg_file_path, toml.to_string())
|
std::fs::write(cfg_file_path, effective_config.to_string())
|
||||||
.with_context(|| format!("Failed to write pageserver config to '{cfg_file_path}'"))?;
|
.with_context(|| format!("Failed to write pageserver config to '{cfg_file_path}'"))?;
|
||||||
info!("Config successfully written to '{cfg_file_path}'")
|
info!("Config successfully written to '{cfg_file_path}'")
|
||||||
}
|
}
|
||||||
@@ -758,18 +755,13 @@ fn cli() -> Command {
|
|||||||
// See `settings.md` for more details on the extra configuration patameters pageserver can process
|
// See `settings.md` for more details on the extra configuration patameters pageserver can process
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("config-override")
|
Arg::new("config-override")
|
||||||
|
.long("config-override")
|
||||||
.short('c')
|
.short('c')
|
||||||
.num_args(1)
|
.num_args(1)
|
||||||
.action(ArgAction::Append)
|
.action(ArgAction::Append)
|
||||||
.help("Additional configuration overrides of the ones from the toml config file (or new ones to add there). \
|
.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}\"`"),
|
Any option has to be a valid toml document, example: `-c=\"foo='hey'\"` `-c=\"foo={value=1}\"`"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::new("update-config")
|
|
||||||
.long("update-config")
|
|
||||||
.action(ArgAction::SetTrue)
|
|
||||||
.help("Update the config file when started"),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("enabled-features")
|
Arg::new("enabled-features")
|
||||||
.long("enabled-features")
|
.long("enabled-features")
|
||||||
|
|||||||
@@ -76,13 +76,10 @@ you can use `--pg-version` argument.
|
|||||||
`TEST_OUTPUT`: Set the directory where test state and test output files
|
`TEST_OUTPUT`: Set the directory where test state and test output files
|
||||||
should go.
|
should go.
|
||||||
`TEST_SHARED_FIXTURES`: Try to re-use a single pageserver for all the tests.
|
`TEST_SHARED_FIXTURES`: Try to re-use a single pageserver for all the tests.
|
||||||
`NEON_PAGESERVER_OVERRIDES`: add a `;`-separated set of configs that will be passed as
|
|
||||||
`RUST_LOG`: logging configuration to pass into Neon CLI
|
`RUST_LOG`: logging configuration to pass into Neon CLI
|
||||||
|
|
||||||
Useful parameters and commands:
|
Useful parameters and commands:
|
||||||
|
|
||||||
`--pageserver-config-override=${value}` `-c` values to pass into pageserver through neon_local cli
|
|
||||||
|
|
||||||
`--preserve-database-files` to preserve pageserver (layer) and safekeer (segment) timeline files on disk
|
`--preserve-database-files` to preserve pageserver (layer) and safekeer (segment) timeline files on disk
|
||||||
after running a test suite. Such files might be large, so removed by default; but might be useful for debugging or creation of svg images with layer file contents.
|
after running a test suite. Such files might be large, so removed by default; but might be useful for debugging or creation of svg images with layer file contents.
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import textwrap
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
from contextlib import closing, contextmanager
|
from contextlib import ExitStack, closing, contextmanager
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
@@ -450,6 +450,7 @@ class NeonEnvBuilder:
|
|||||||
test_output_dir: Path,
|
test_output_dir: Path,
|
||||||
test_overlay_dir: Optional[Path] = None,
|
test_overlay_dir: Optional[Path] = None,
|
||||||
pageserver_remote_storage: Optional[RemoteStorage] = None,
|
pageserver_remote_storage: Optional[RemoteStorage] = None,
|
||||||
|
# toml that will be decomposed into `--config-override` flags during `pageserver --init`
|
||||||
pageserver_config_override: Optional[str] = None,
|
pageserver_config_override: Optional[str] = None,
|
||||||
num_safekeepers: int = 1,
|
num_safekeepers: int = 1,
|
||||||
num_pageservers: int = 1,
|
num_pageservers: int = 1,
|
||||||
@@ -1021,7 +1022,6 @@ class NeonEnv:
|
|||||||
self.neon_local_binpath = config.neon_binpath
|
self.neon_local_binpath = config.neon_binpath
|
||||||
self.pg_distrib_dir = config.pg_distrib_dir
|
self.pg_distrib_dir = config.pg_distrib_dir
|
||||||
self.endpoint_counter = 0
|
self.endpoint_counter = 0
|
||||||
self.pageserver_config_override = config.pageserver_config_override
|
|
||||||
self.storage_controller_config = config.storage_controller_config
|
self.storage_controller_config = config.storage_controller_config
|
||||||
|
|
||||||
# generate initial tenant ID here instead of letting 'neon init' generate it,
|
# generate initial tenant ID here instead of letting 'neon init' generate it,
|
||||||
@@ -1131,7 +1131,11 @@ class NeonEnv:
|
|||||||
cfg["safekeepers"].append(sk_cfg)
|
cfg["safekeepers"].append(sk_cfg)
|
||||||
|
|
||||||
log.info(f"Config: {cfg}")
|
log.info(f"Config: {cfg}")
|
||||||
self.neon_cli.init(cfg, force=config.config_init_force)
|
self.neon_cli.init(
|
||||||
|
cfg,
|
||||||
|
force=config.config_init_force,
|
||||||
|
pageserver_config_override=config.pageserver_config_override,
|
||||||
|
)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
# Storage controller starts first, so that pageserver /re-attach calls don't
|
# Storage controller starts first, so that pageserver /re-attach calls don't
|
||||||
@@ -1703,30 +1707,47 @@ class NeonCli(AbstractNeonCli):
|
|||||||
self,
|
self,
|
||||||
config: Dict[str, Any],
|
config: Dict[str, Any],
|
||||||
force: Optional[str] = None,
|
force: Optional[str] = None,
|
||||||
|
pageserver_config_override: Optional[str] = None,
|
||||||
) -> "subprocess.CompletedProcess[str]":
|
) -> "subprocess.CompletedProcess[str]":
|
||||||
with tempfile.NamedTemporaryFile(mode="w+") as tmp:
|
remote_storage = self.env.pageserver_remote_storage
|
||||||
tmp.write(toml.dumps(config))
|
|
||||||
tmp.flush()
|
|
||||||
|
|
||||||
cmd = ["init", f"--config={tmp.name}", "--pg-version", self.env.pg_version]
|
ps_config = {}
|
||||||
|
if remote_storage is not None:
|
||||||
|
remote_storage_toml_table = remote_storage_to_toml_inline_table(remote_storage)
|
||||||
|
ps_config["remote_storage"] = remote_storage_toml_table
|
||||||
|
|
||||||
|
if pageserver_config_override is not None:
|
||||||
|
for o in pageserver_config_override.split(";"):
|
||||||
|
override = toml.loads(o)
|
||||||
|
for key, value in override.items():
|
||||||
|
ps_config[key] = value
|
||||||
|
|
||||||
|
with ExitStack() as stack:
|
||||||
|
ps_config_file = stack.enter_context(tempfile.NamedTemporaryFile(mode="w+"))
|
||||||
|
ps_config_file.write(toml.dumps(ps_config))
|
||||||
|
ps_config_file.flush()
|
||||||
|
|
||||||
|
neon_local_config = stack.enter_context(tempfile.NamedTemporaryFile(mode="w+"))
|
||||||
|
neon_local_config.write(toml.dumps(config))
|
||||||
|
neon_local_config.flush()
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
"init",
|
||||||
|
f"--config={neon_local_config.name}",
|
||||||
|
"--pg-version",
|
||||||
|
self.env.pg_version,
|
||||||
|
f"--pageserver-config={ps_config_file.name}",
|
||||||
|
]
|
||||||
|
|
||||||
if force is not None:
|
if force is not None:
|
||||||
cmd.extend(["--force", force])
|
cmd.extend(["--force", force])
|
||||||
|
|
||||||
storage = self.env.pageserver_remote_storage
|
|
||||||
|
|
||||||
append_pageserver_param_overrides(
|
|
||||||
params_to_update=cmd,
|
|
||||||
remote_storage=storage,
|
|
||||||
pageserver_config_override=self.env.pageserver_config_override,
|
|
||||||
)
|
|
||||||
|
|
||||||
s3_env_vars = None
|
s3_env_vars = None
|
||||||
if isinstance(storage, S3Storage):
|
if isinstance(remote_storage, S3Storage):
|
||||||
s3_env_vars = storage.access_env_vars()
|
s3_env_vars = remote_storage.access_env_vars()
|
||||||
res = self.raw_cli(cmd, extra_env_vars=s3_env_vars)
|
res = self.raw_cli(cmd, extra_env_vars=s3_env_vars)
|
||||||
res.check_returncode()
|
res.check_returncode()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def storage_controller_start(self):
|
def storage_controller_start(self):
|
||||||
cmd = ["storage_controller", "start"]
|
cmd = ["storage_controller", "start"]
|
||||||
@@ -1741,16 +1762,10 @@ class NeonCli(AbstractNeonCli):
|
|||||||
def pageserver_start(
|
def pageserver_start(
|
||||||
self,
|
self,
|
||||||
id: int,
|
id: int,
|
||||||
overrides: Tuple[str, ...] = (),
|
|
||||||
extra_env_vars: Optional[Dict[str, str]] = None,
|
extra_env_vars: Optional[Dict[str, str]] = None,
|
||||||
) -> "subprocess.CompletedProcess[str]":
|
) -> "subprocess.CompletedProcess[str]":
|
||||||
start_args = ["pageserver", "start", f"--id={id}", *overrides]
|
start_args = ["pageserver", "start", f"--id={id}"]
|
||||||
storage = self.env.pageserver_remote_storage
|
storage = self.env.pageserver_remote_storage
|
||||||
append_pageserver_param_overrides(
|
|
||||||
params_to_update=start_args,
|
|
||||||
remote_storage=storage,
|
|
||||||
pageserver_config_override=self.env.pageserver_config_override,
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(storage, S3Storage):
|
if isinstance(storage, S3Storage):
|
||||||
s3_env_vars = storage.access_env_vars()
|
s3_env_vars = storage.access_env_vars()
|
||||||
@@ -2408,9 +2423,47 @@ class NeonPageserver(PgProtocol, LogUtils):
|
|||||||
return self.workdir / "tenants"
|
return self.workdir / "tenants"
|
||||||
return self.workdir / "tenants" / str(tenant_shard_id)
|
return self.workdir / "tenants" / str(tenant_shard_id)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def config_toml_path(self) -> Path:
|
||||||
|
return self.workdir / "pageserver.toml"
|
||||||
|
|
||||||
|
def edit_config_toml(self, edit_fn: Callable[[Dict[str, Any]], bool]):
|
||||||
|
"""
|
||||||
|
Edit the pageserver's config toml file in place.
|
||||||
|
|
||||||
|
The `edit_fn` is to manipulate the dict, and if it returns True, the file will be written.
|
||||||
|
If it returns False, no changes are made to the file system.
|
||||||
|
"""
|
||||||
|
path = self.config_toml_path
|
||||||
|
with open(path, "r") as f:
|
||||||
|
config = toml.load(f)
|
||||||
|
save = edit_fn(config)
|
||||||
|
if save:
|
||||||
|
with open(path, "w") as f:
|
||||||
|
toml.dump(config, f)
|
||||||
|
|
||||||
|
def patch_config_toml_nonrecursive(self, patch: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Non-recursively merge the given `patch` dict into the existing config toml, using `dict.update()`.
|
||||||
|
Returns the replaced values.
|
||||||
|
If there was no previous value, the key is mapped to None.
|
||||||
|
This allows to restore the original value by calling this method with the returned dict.
|
||||||
|
"""
|
||||||
|
replacements = {}
|
||||||
|
|
||||||
|
def doit(config: Dict[str, Any]) -> bool:
|
||||||
|
while len(patch) > 0:
|
||||||
|
key, new = patch.popitem()
|
||||||
|
old = config.get(key, None)
|
||||||
|
config[key] = new
|
||||||
|
replacements[key] = old
|
||||||
|
return True
|
||||||
|
|
||||||
|
self.edit_config_toml(doit)
|
||||||
|
return replacements
|
||||||
|
|
||||||
def start(
|
def start(
|
||||||
self,
|
self,
|
||||||
overrides: Tuple[str, ...] = (),
|
|
||||||
extra_env_vars: Optional[Dict[str, str]] = None,
|
extra_env_vars: Optional[Dict[str, str]] = None,
|
||||||
) -> "NeonPageserver":
|
) -> "NeonPageserver":
|
||||||
"""
|
"""
|
||||||
@@ -2420,9 +2473,7 @@ class NeonPageserver(PgProtocol, LogUtils):
|
|||||||
"""
|
"""
|
||||||
assert self.running is False
|
assert self.running is False
|
||||||
|
|
||||||
self.env.neon_cli.pageserver_start(
|
self.env.neon_cli.pageserver_start(self.id, extra_env_vars=extra_env_vars)
|
||||||
self.id, overrides=overrides, extra_env_vars=extra_env_vars
|
|
||||||
)
|
|
||||||
self.running = True
|
self.running = True
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -2585,33 +2636,6 @@ class NeonPageserver(PgProtocol, LogUtils):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def append_pageserver_param_overrides(
|
|
||||||
params_to_update: List[str],
|
|
||||||
remote_storage: Optional[RemoteStorage],
|
|
||||||
pageserver_config_override: Optional[str] = None,
|
|
||||||
):
|
|
||||||
if remote_storage is not None:
|
|
||||||
remote_storage_toml_table = remote_storage_to_toml_inline_table(remote_storage)
|
|
||||||
|
|
||||||
params_to_update.append(
|
|
||||||
f"--pageserver-config-override=remote_storage={remote_storage_toml_table}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
params_to_update.append('--pageserver-config-override=remote_storage=""')
|
|
||||||
|
|
||||||
env_overrides = os.getenv("NEON_PAGESERVER_OVERRIDES")
|
|
||||||
if env_overrides is not None:
|
|
||||||
params_to_update += [
|
|
||||||
f"--pageserver-config-override={o.strip()}" for o in env_overrides.split(";")
|
|
||||||
]
|
|
||||||
|
|
||||||
if pageserver_config_override is not None:
|
|
||||||
params_to_update += [
|
|
||||||
f"--pageserver-config-override={o.strip()}"
|
|
||||||
for o in pageserver_config_override.split(";")
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class PgBin:
|
class PgBin:
|
||||||
"""A helper class for executing postgres binaries"""
|
"""A helper class for executing postgres binaries"""
|
||||||
|
|
||||||
|
|||||||
@@ -140,10 +140,13 @@ def test_branch_creation_many(neon_compare: NeonCompare, n_branches: int, shape:
|
|||||||
|
|
||||||
# start without gc so we can time compaction with less noise; use shorter
|
# start without gc so we can time compaction with less noise; use shorter
|
||||||
# period for compaction so it starts earlier
|
# period for compaction so it starts earlier
|
||||||
|
def patch_default_tenant_config(config):
|
||||||
|
config["compaction_period"] = "3s"
|
||||||
|
config["gc_period"] = "0s"
|
||||||
|
return True
|
||||||
|
|
||||||
|
env.pageserver.edit_config_toml(patch_default_tenant_config)
|
||||||
env.pageserver.start(
|
env.pageserver.start(
|
||||||
overrides=(
|
|
||||||
"--pageserver-config-override=tenant_config={ compaction_period = '3s', gc_period = '0s' }",
|
|
||||||
),
|
|
||||||
# this does print more than we want, but the number should be comparable between runs
|
# this does print more than we want, but the number should be comparable between runs
|
||||||
extra_env_vars={
|
extra_env_vars={
|
||||||
"RUST_LOG": f"[compaction_loop{{tenant_id={env.initial_tenant}}}]=debug,info"
|
"RUST_LOG": f"[compaction_loop{{tenant_id={env.initial_tenant}}}]=debug,info"
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from dataclasses import dataclass
|
|||||||
from typing import Any, Dict, Iterable, Tuple
|
from typing import Any, Dict, Iterable, Tuple
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import toml
|
|
||||||
from fixtures.log_helper import log
|
from fixtures.log_helper import log
|
||||||
from fixtures.neon_fixtures import (
|
from fixtures.neon_fixtures import (
|
||||||
NeonEnv,
|
NeonEnv,
|
||||||
@@ -45,17 +44,15 @@ def test_min_resident_size_override_handling(
|
|||||||
ps_http.set_tenant_config(tenant_id, {})
|
ps_http.set_tenant_config(tenant_id, {})
|
||||||
assert_config(tenant_id, None, default_tenant_conf_value)
|
assert_config(tenant_id, None, default_tenant_conf_value)
|
||||||
|
|
||||||
env.pageserver.stop()
|
|
||||||
if config_level_override is not None:
|
if config_level_override is not None:
|
||||||
env.pageserver.start(
|
|
||||||
overrides=(
|
def set_min_resident_size(config):
|
||||||
"--pageserver-config-override=tenant_config={ min_resident_size_override = "
|
config["tenant_config"] = {"min_resident_size": config_level_override}
|
||||||
+ str(config_level_override)
|
return True
|
||||||
+ " }",
|
|
||||||
)
|
env.pageserver.edit_config_toml(set_min_resident_size)
|
||||||
)
|
env.pageserver.stop()
|
||||||
else:
|
env.pageserver.start()
|
||||||
env.pageserver.start()
|
|
||||||
|
|
||||||
tenant_id, _ = env.neon_cli.create_tenant()
|
tenant_id, _ = env.neon_cli.create_tenant()
|
||||||
assert_overrides(tenant_id, config_level_override)
|
assert_overrides(tenant_id, config_level_override)
|
||||||
@@ -164,34 +161,32 @@ class EvictionEnv:
|
|||||||
usage eviction task is unknown; it might need to run one more iteration
|
usage eviction task is unknown; it might need to run one more iteration
|
||||||
before assertions can be made.
|
before assertions can be made.
|
||||||
"""
|
"""
|
||||||
disk_usage_config = {
|
|
||||||
"period": period,
|
|
||||||
"max_usage_pct": max_usage_pct,
|
|
||||||
"min_avail_bytes": min_avail_bytes,
|
|
||||||
"mock_statvfs": mock_behavior,
|
|
||||||
"eviction_order": eviction_order.config(),
|
|
||||||
}
|
|
||||||
|
|
||||||
enc = toml.TomlEncoder()
|
|
||||||
|
|
||||||
# these can sometimes happen during startup before any tenants have been
|
# these can sometimes happen during startup before any tenants have been
|
||||||
# loaded, so nothing can be evicted, we just wait for next iteration which
|
# loaded, so nothing can be evicted, we just wait for next iteration which
|
||||||
# is able to evict.
|
# is able to evict.
|
||||||
pageserver.allowed_errors.append(".*WARN.* disk usage still high.*")
|
pageserver.allowed_errors.append(".*WARN.* disk usage still high.*")
|
||||||
|
|
||||||
pageserver.start(
|
pageserver.patch_config_toml_nonrecursive(
|
||||||
overrides=(
|
{
|
||||||
"--pageserver-config-override=disk_usage_based_eviction="
|
"disk_usage_based_eviction": {
|
||||||
+ enc.dump_inline_table(disk_usage_config).replace("\n", " "),
|
"period": period,
|
||||||
|
"max_usage_pct": max_usage_pct,
|
||||||
|
"min_avail_bytes": min_avail_bytes,
|
||||||
|
"mock_statvfs": mock_behavior,
|
||||||
|
"eviction_order": eviction_order.config(),
|
||||||
|
},
|
||||||
# Disk usage based eviction runs as a background task.
|
# Disk usage based eviction runs as a background task.
|
||||||
# But pageserver startup delays launch of background tasks for some time, to prioritize initial logical size calculations during startup.
|
# But pageserver startup delays launch of background tasks for some time, to prioritize initial logical size calculations during startup.
|
||||||
# But, initial logical size calculation may not be triggered if safekeepers don't publish new broker messages.
|
# But, initial logical size calculation may not be triggered if safekeepers don't publish new broker messages.
|
||||||
# But, we only have a 10-second-timeout in this test.
|
# But, we only have a 10-second-timeout in this test.
|
||||||
# So, disable the delay for this test.
|
# So, disable the delay for this test.
|
||||||
"--pageserver-config-override=background_task_maximum_delay='0s'",
|
"background_task_maximum_delay": "0s",
|
||||||
),
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
pageserver.start()
|
||||||
|
|
||||||
# we now do initial logical size calculation on startup, which on debug builds can fight with disk usage based eviction
|
# we now do initial logical size calculation on startup, which on debug builds can fight with disk usage based eviction
|
||||||
for tenant_id, timeline_id in self.timelines:
|
for tenant_id, timeline_id in self.timelines:
|
||||||
tenant_ps = self.neon_env.get_tenant_pageserver(tenant_id)
|
tenant_ps = self.neon_env.get_tenant_pageserver(tenant_id)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ from fixtures.types import Lsn, TenantId, TimelineId
|
|||||||
from fixtures.utils import wait_until
|
from fixtures.utils import wait_until
|
||||||
|
|
||||||
|
|
||||||
# test that we cannot override node id after init
|
|
||||||
def test_pageserver_init_node_id(
|
def test_pageserver_init_node_id(
|
||||||
neon_simple_env: NeonEnv, neon_binpath: Path, pg_distrib_dir: Path
|
neon_simple_env: NeonEnv, neon_binpath: Path, pg_distrib_dir: Path
|
||||||
):
|
):
|
||||||
@@ -49,11 +48,7 @@ def test_pageserver_init_node_id(
|
|||||||
|
|
||||||
bad_reinit = run_pageserver(good_init_cmd)
|
bad_reinit = run_pageserver(good_init_cmd)
|
||||||
assert bad_reinit.returncode == 1, "pageserver refuses to init if already exists"
|
assert bad_reinit.returncode == 1, "pageserver refuses to init if already exists"
|
||||||
assert "already exists, cannot init it" in bad_reinit.stderr
|
assert "config file already exists" in bad_reinit.stderr
|
||||||
|
|
||||||
bad_update = run_pageserver(["--update-config", "-c", "id = 3"])
|
|
||||||
assert bad_update.returncode == 1, "pageserver should not allow updating node id"
|
|
||||||
assert "has node id already, it cannot be overridden" in bad_update.stderr
|
|
||||||
|
|
||||||
|
|
||||||
def check_client(env: NeonEnv, client: PageserverHttpClient):
|
def check_client(env: NeonEnv, client: PageserverHttpClient):
|
||||||
|
|||||||
@@ -220,7 +220,12 @@ def test_generations_upgrade(neon_env_builder: NeonEnvBuilder):
|
|||||||
# We will start a pageserver with no control_plane_api set, so it won't be able to self-register
|
# We will start a pageserver with no control_plane_api set, so it won't be able to self-register
|
||||||
env.storage_controller.node_register(env.pageserver)
|
env.storage_controller.node_register(env.pageserver)
|
||||||
|
|
||||||
env.pageserver.start(overrides=('--pageserver-config-override=control_plane_api=""',))
|
replaced_config = env.pageserver.patch_config_toml_nonrecursive(
|
||||||
|
{
|
||||||
|
"control_plane_api": "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
env.pageserver.start()
|
||||||
env.storage_controller.node_configure(env.pageserver.id, {"availability": "Active"})
|
env.storage_controller.node_configure(env.pageserver.id, {"availability": "Active"})
|
||||||
|
|
||||||
env.neon_cli.create_tenant(
|
env.neon_cli.create_tenant(
|
||||||
@@ -251,8 +256,8 @@ def test_generations_upgrade(neon_env_builder: NeonEnvBuilder):
|
|||||||
assert parse_generation_suffix(key) is None
|
assert parse_generation_suffix(key) is None
|
||||||
|
|
||||||
env.pageserver.stop()
|
env.pageserver.stop()
|
||||||
|
|
||||||
# Starting without the override that disabled control_plane_api
|
# Starting without the override that disabled control_plane_api
|
||||||
|
env.pageserver.patch_config_toml_nonrecursive(replaced_config)
|
||||||
env.pageserver.start()
|
env.pageserver.start()
|
||||||
|
|
||||||
generate_uploads_and_deletions(env, pageserver=env.pageserver, init=False)
|
generate_uploads_and_deletions(env, pageserver=env.pageserver, init=False)
|
||||||
@@ -525,9 +530,12 @@ def test_emergency_mode(neon_env_builder: NeonEnvBuilder, pg_bin: PgBin):
|
|||||||
# incident, but it might be unavoidable: if so, we want to be able to start up
|
# incident, but it might be unavoidable: if so, we want to be able to start up
|
||||||
# and serve clients.
|
# and serve clients.
|
||||||
env.pageserver.stop() # Non-immediate: implicitly checking that shutdown doesn't hang waiting for CP
|
env.pageserver.stop() # Non-immediate: implicitly checking that shutdown doesn't hang waiting for CP
|
||||||
env.pageserver.start(
|
replaced = env.pageserver.patch_config_toml_nonrecursive(
|
||||||
overrides=("--pageserver-config-override=control_plane_emergency_mode=true",),
|
{
|
||||||
|
"control_plane_emergency_mode": True,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
env.pageserver.start()
|
||||||
|
|
||||||
# The pageserver should provide service to clients
|
# The pageserver should provide service to clients
|
||||||
generate_uploads_and_deletions(env, init=False, pageserver=env.pageserver)
|
generate_uploads_and_deletions(env, init=False, pageserver=env.pageserver)
|
||||||
@@ -549,6 +557,7 @@ def test_emergency_mode(neon_env_builder: NeonEnvBuilder, pg_bin: PgBin):
|
|||||||
|
|
||||||
# The pageserver should work fine when subsequently restarted in non-emergency mode
|
# The pageserver should work fine when subsequently restarted in non-emergency mode
|
||||||
env.pageserver.stop() # Non-immediate: implicitly checking that shutdown doesn't hang waiting for CP
|
env.pageserver.stop() # Non-immediate: implicitly checking that shutdown doesn't hang waiting for CP
|
||||||
|
env.pageserver.patch_config_toml_nonrecursive(replaced)
|
||||||
env.pageserver.start()
|
env.pageserver.start()
|
||||||
|
|
||||||
generate_uploads_and_deletions(env, init=False, pageserver=env.pageserver)
|
generate_uploads_and_deletions(env, init=False, pageserver=env.pageserver)
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
# It's possible to run any regular test with the local fs remote storage via
|
|
||||||
# env NEON_PAGESERVER_OVERRIDES="remote_storage={local_path='/tmp/neon_zzz/'}" poetry ......
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import queue
|
import queue
|
||||||
import shutil
|
import shutil
|
||||||
|
|||||||
@@ -290,9 +290,12 @@ def test_storage_controller_onboarding(neon_env_builder: NeonEnvBuilder, warm_up
|
|||||||
# This is the pageserver where we'll initially create the tenant. Run it in emergency
|
# This is the pageserver where we'll initially create the tenant. Run it in emergency
|
||||||
# mode so that it doesn't talk to storage controller, and do not register it.
|
# mode so that it doesn't talk to storage controller, and do not register it.
|
||||||
env.pageservers[0].allowed_errors.append(".*Emergency mode!.*")
|
env.pageservers[0].allowed_errors.append(".*Emergency mode!.*")
|
||||||
env.pageservers[0].start(
|
env.pageservers[0].patch_config_toml_nonrecursive(
|
||||||
overrides=("--pageserver-config-override=control_plane_emergency_mode=true",),
|
{
|
||||||
|
"control_plane_emergency_mode": True,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
env.pageservers[0].start()
|
||||||
origin_ps = env.pageservers[0]
|
origin_ps = env.pageservers[0]
|
||||||
|
|
||||||
# These are the pageservers managed by the sharding service, where the tenant
|
# These are the pageservers managed by the sharding service, where the tenant
|
||||||
|
|||||||
Reference in New Issue
Block a user