diff --git a/src/bin/proxmox-backup-api.rs b/src/bin/proxmox-backup-api.rs index e9953d77..eec71fe2 100644 --- a/src/bin/proxmox-backup-api.rs +++ b/src/bin/proxmox-backup-api.rs @@ -4,6 +4,7 @@ extern crate proxmox_backup; use proxmox_backup::api_schema::router::*; use proxmox_backup::api_schema::config::*; use proxmox_backup::server::rest::*; +use proxmox_backup::tools::daemon::ReexecStore; use proxmox_backup::auth_helpers::*; use proxmox_backup::config; @@ -11,9 +12,12 @@ use failure::*; use lazy_static::lazy_static; use futures::future::Future; +use tokio::prelude::*; use hyper; +static mut QUIT_MAIN: bool = false; + fn main() { if let Err(err) = run() { @@ -23,6 +27,8 @@ fn main() { } fn run() -> Result<(), Error> { + // This manages data for reloads: + let mut reexecer = ReexecStore::new(); if let Err(err) = syslog::init( syslog::Facility::LOG_DAEMON, @@ -43,8 +49,6 @@ fn run() -> Result<(), Error> { } let _ = csrf_secret(); // load with lazy_static - let addr = ([127,0,0,1], 82).into(); - lazy_static!{ static ref ROUTER: Router = proxmox_backup::api2::router(); } @@ -54,12 +58,76 @@ fn run() -> Result<(), Error> { let rest_server = RestServer::new(config); - let server = hyper::Server::bind(&addr) + // http server future: + + let listener: tokio::net::TcpListener = reexecer.restore( + "PROXMOX_BACKUP_LISTEN_FD", + || { + let addr = ([127,0,0,1], 82).into(); + Ok(tokio::net::TcpListener::bind(&addr)?) + }, + )?; + + let mut http_server = hyper::Server::builder(listener.incoming()) .serve(rest_server) .map_err(|e| eprintln!("server error: {}", e)); - // Run this server for... forever! - hyper::rt::run(server); + // signalfd future: + + let signal_handler = + proxmox_backup::tools::daemon::default_signalfd_stream( + reexecer, + || { + unsafe { QUIT_MAIN = true; } + Ok(()) + }, + )? + .map(|si| { + // debugging... + eprintln!("received signal: {}", si.ssi_signo); + }) + .map_err(|e| { + eprintln!("error from signalfd: {}, shutting down...", e); + unsafe { + QUIT_MAIN = true; + } + }); + + + // Combined future for signalfd & http server, we want to quit as soon as either of them ends. + // Neither of them is supposed to end unless some weird error happens, so just bail out if is + // the case... + let mut signal_handler = signal_handler.into_future(); + let main = futures::future::poll_fn(move || { + // Helper for some diagnostic error messages: + fn poll_helper(stream: &mut S, name: &'static str) -> bool { + match stream.poll() { + Ok(Async::Ready(_)) => { + eprintln!("{} ended, shutting down", name); + true + } + Err(_) => { + eprintln!("{} error, shutting down", name); + true + }, + _ => false, + } + } + if poll_helper(&mut http_server, "http server") || + poll_helper(&mut signal_handler, "signalfd handler") + { + return Ok(Async::Ready(())); + } + + if unsafe { QUIT_MAIN } { + eprintln!("shutdown requested"); + Ok(Async::Ready(())) + } else { + Ok(Async::NotReady) + } + }); + + hyper::rt::run(main); Ok(()) }