mirror of
https://github.com/neondatabase/neon.git
synced 2026-05-17 05:00:38 +00:00
Return Result<()> from pageserver start/stop.
To provide meaningful error messages when it is called by CLI.
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
use std::env;
|
||||
use std::error;
|
||||
use std::fs;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use home;
|
||||
@@ -34,9 +33,6 @@ pub struct LocalEnv {
|
||||
|
||||
// Path to pageserver binary.
|
||||
pub zenith_distrib_dir: PathBuf,
|
||||
|
||||
// PageServer-specific options.
|
||||
pub pageserver: PageServerConf,
|
||||
}
|
||||
|
||||
impl LocalEnv {
|
||||
@@ -58,11 +54,6 @@ impl LocalEnv {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct PageServerConf {
|
||||
pub listen_address: SocketAddr,
|
||||
}
|
||||
|
||||
//
|
||||
// Issues in rust-lang repo has several discussions about proper library to check
|
||||
// home directory in a cross-platform way. Seems that current consensus is around
|
||||
@@ -150,9 +141,6 @@ pub fn init() -> Result<()> {
|
||||
data_dir,
|
||||
pg_distrib_dir,
|
||||
zenith_distrib_dir,
|
||||
pageserver: PageServerConf {
|
||||
listen_address: "127.0.0.1:5430".parse().unwrap(),
|
||||
},
|
||||
};
|
||||
let toml = toml::to_string(&conf)?;
|
||||
fs::write(cfg_path, toml)?;
|
||||
@@ -191,9 +179,6 @@ pub fn test_env() -> LocalEnv {
|
||||
data_dir,
|
||||
pg_distrib_dir: Path::new(env!("CARGO_MANIFEST_DIR")).join("../tmp_install"),
|
||||
zenith_distrib_dir: cargo_bin_dir(),
|
||||
pageserver: PageServerConf {
|
||||
listen_address: "127.0.0.1:65200".parse().unwrap(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,15 @@ use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::net::SocketAddr;
|
||||
use std::error;
|
||||
|
||||
use postgres::{Client, NoTls};
|
||||
|
||||
use crate::local_env::{self, LocalEnv};
|
||||
use crate::compute::{PostgresNode};
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn error::Error>>;
|
||||
|
||||
//
|
||||
// Collection of several example deployments useful for tests.
|
||||
//
|
||||
@@ -33,9 +36,10 @@ impl TestStorageControlPlane {
|
||||
let pserver = Arc::new(PageServerNode {
|
||||
env: env.clone(),
|
||||
kill_on_exit: true,
|
||||
listen_address: None,
|
||||
});
|
||||
pserver.init();
|
||||
pserver.start();
|
||||
pserver.start().unwrap();
|
||||
|
||||
TestStorageControlPlane {
|
||||
wal_acceptors: Vec::new(),
|
||||
@@ -52,11 +56,12 @@ impl TestStorageControlPlane {
|
||||
pageserver: Arc::new(PageServerNode {
|
||||
env: env.clone(),
|
||||
kill_on_exit: true,
|
||||
listen_address: None,
|
||||
}),
|
||||
test_done: AtomicBool::new(false),
|
||||
};
|
||||
cplane.pageserver.init();
|
||||
cplane.pageserver.start();
|
||||
cplane.pageserver.start().unwrap();
|
||||
|
||||
const WAL_ACCEPTOR_PORT: usize = 54321;
|
||||
|
||||
@@ -105,77 +110,95 @@ impl Drop for TestStorageControlPlane {
|
||||
//
|
||||
pub struct PageServerNode {
|
||||
kill_on_exit: bool,
|
||||
env: LocalEnv,
|
||||
listen_address: Option<SocketAddr>,
|
||||
pub env: LocalEnv,
|
||||
}
|
||||
|
||||
impl PageServerNode {
|
||||
pub fn from_env(env: &LocalEnv) -> PageServerNode {
|
||||
PageServerNode {
|
||||
kill_on_exit: false,
|
||||
listen_address: None, // default
|
||||
env: env.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn address(&self) -> SocketAddr {
|
||||
match self.listen_address {
|
||||
Some(addr) => addr,
|
||||
None => "127.0.0.1:64000".parse().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&self) {
|
||||
fs::create_dir_all(self.env.pageserver_data_dir()).unwrap();
|
||||
}
|
||||
|
||||
pub fn start(&self) {
|
||||
println!(
|
||||
"Starting pageserver at '{}'",
|
||||
self.env.pageserver.listen_address
|
||||
);
|
||||
pub fn start(&self) -> Result<()> {
|
||||
println!("Starting pageserver at '{}'", self.address());
|
||||
|
||||
let status = Command::new(self.env.zenith_distrib_dir.join("pageserver")) // XXX -> method
|
||||
.args(&["-D", self.env.pageserver_data_dir().to_str().unwrap()])
|
||||
.args(&[
|
||||
"-l",
|
||||
self.env.pageserver.listen_address.to_string().as_str(),
|
||||
self.address().to_string().as_str(),
|
||||
])
|
||||
.arg("-d")
|
||||
.arg("--skip-recovery")
|
||||
.env_clear()
|
||||
.env("PATH", self.env.pg_bin_dir().to_str().unwrap()) // needs postres-wal-redo binary
|
||||
.env("LD_LIBRARY_PATH", self.env.pg_lib_dir().to_str().unwrap())
|
||||
.status()
|
||||
.expect("failed to start pageserver");
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
panic!("pageserver start failed");
|
||||
return Err(Box::<dyn error::Error>::from(
|
||||
format!("Pageserver failed to start. See '{}' for details.",
|
||||
self.env.pageserver_log().to_str().unwrap())
|
||||
));
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop(&self) {
|
||||
pub fn stop(&self) -> Result<()> {
|
||||
let pidfile = self.env.pageserver_pidfile();
|
||||
let pid = fs::read_to_string(pidfile).unwrap();
|
||||
|
||||
let status = Command::new("kill")
|
||||
.arg(pid)
|
||||
.arg(pid.clone())
|
||||
.env_clear()
|
||||
.status()
|
||||
.expect("failed to execute kill");
|
||||
|
||||
if !status.success() {
|
||||
panic!("kill start failed");
|
||||
return Err(Box::<dyn error::Error>::from(
|
||||
format!("Failed to kill pageserver with pid {}",
|
||||
pid
|
||||
)));
|
||||
}
|
||||
|
||||
// await for pageserver stop
|
||||
for _ in 0..5 {
|
||||
let stream = TcpStream::connect(self.env.pageserver.listen_address);
|
||||
let stream = TcpStream::connect(self.address());
|
||||
if let Err(_e) = stream {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
println!(
|
||||
"Stopping pageserver on {}",
|
||||
self.env.pageserver.listen_address
|
||||
);
|
||||
println!("Stopping pageserver on {}", self.address());
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
|
||||
// ok, we failed to stop pageserver, let's panic
|
||||
panic!("Failed to stop pageserver");
|
||||
}
|
||||
|
||||
pub fn address(&self) -> &std::net::SocketAddr {
|
||||
&self.env.pageserver.listen_address
|
||||
if !status.success() {
|
||||
return Err(Box::<dyn error::Error>::from(
|
||||
format!("Failed to stop pageserver with pid {}",
|
||||
pid
|
||||
)));
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn page_server_psql(&self, sql: &str) -> Vec<postgres::SimpleQueryMessage> {
|
||||
// let addr = &self.page_servers[0].env.pageserver.listen_address;
|
||||
|
||||
let connstring = format!(
|
||||
"host={} port={} dbname={} user={}",
|
||||
self.address().ip(),
|
||||
@@ -193,7 +216,7 @@ impl PageServerNode {
|
||||
impl Drop for PageServerNode {
|
||||
fn drop(&mut self) {
|
||||
if self.kill_on_exit {
|
||||
self.stop();
|
||||
let _ = self.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use clap::{App, SubCommand};
|
||||
use std::fs;
|
||||
use std::process::exit;
|
||||
use std::process::Command;
|
||||
|
||||
use control_plane::local_env;
|
||||
use control_plane::{local_env, storage};
|
||||
|
||||
fn main() {
|
||||
let matches = App::new("zenith")
|
||||
@@ -44,7 +42,7 @@ fn main() {
|
||||
}
|
||||
|
||||
// all other commands would need config
|
||||
let conf = match local_env::load_config() {
|
||||
let env = match local_env::load_config() {
|
||||
Ok(conf) => conf,
|
||||
Err(e) => {
|
||||
eprintln!("Error loading config from ~/.zenith: {}", e);
|
||||
@@ -58,45 +56,22 @@ fn main() {
|
||||
}
|
||||
|
||||
("start", Some(_sub_m)) => {
|
||||
println!(
|
||||
"Starting pageserver at '{}'",
|
||||
conf.pageserver.listen_address
|
||||
);
|
||||
let pageserver = storage::PageServerNode::from_env(&env);
|
||||
|
||||
let status = Command::new(conf.zenith_distrib_dir.join("pageserver"))
|
||||
.args(&["-D", conf.data_dir.to_str().unwrap()])
|
||||
.args(&["-l", conf.pageserver.listen_address.to_string().as_str()])
|
||||
.arg("-d")
|
||||
.arg("--skip-recovery")
|
||||
.env_clear()
|
||||
.env("PATH", conf.pg_bin_dir().to_str().unwrap()) // pageserver needs postres-wal-redo binary
|
||||
.env("LD_LIBRARY_PATH", conf.pg_lib_dir().to_str().unwrap())
|
||||
.status()
|
||||
.expect("failed to start pageserver");
|
||||
|
||||
if !status.success() {
|
||||
eprintln!(
|
||||
"Pageserver failed to start. See '{}' for details.",
|
||||
conf.pageserver_log().to_str().unwrap()
|
||||
);
|
||||
if let Err(e) = pageserver.start() {
|
||||
eprintln!("start: {}", e);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// TODO: check it's actually started, or run status
|
||||
|
||||
// TODO: check and await actual start
|
||||
println!("Done!");
|
||||
}
|
||||
|
||||
("stop", Some(_sub_m)) => {
|
||||
let pid = fs::read_to_string(conf.pageserver_pidfile()).unwrap();
|
||||
let status = Command::new("kill")
|
||||
.arg(pid)
|
||||
.env_clear()
|
||||
.status()
|
||||
.expect("failed to execute kill");
|
||||
let pageserver = storage::PageServerNode::from_env(&env);
|
||||
|
||||
if !status.success() {
|
||||
eprintln!("Failed to kill pageserver");
|
||||
if let Err(e) = pageserver.stop() {
|
||||
eprintln!("stop: {}", e);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user