Return Result<()> from pageserver start/stop.

To provide meaningful error messages when it is called by CLI.
This commit is contained in:
Stas Kelvich
2021-04-10 19:03:40 +03:00
parent 6264dc6aa3
commit 39ebec51d1
3 changed files with 61 additions and 78 deletions

View File

@@ -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(),
},
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}