Skip to content

Commit

Permalink
[faux-mgs] Make console less panic-happy
Browse files Browse the repository at this point in the history
All the `.unwrap()`s have been replaced. Most of them were fine and
became `.expect("reason we think it's fine")`. The one that was not is
in #122: if we fail a send to the SP, we previously panicked. We now
buffer failed sends and will retry them (indefinitely, logging on each
failure).
  • Loading branch information
jgallagher committed Sep 8, 2023
1 parent 65744c5 commit 17e8a95
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 47 deletions.
37 changes: 24 additions & 13 deletions faux-mgs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ use slog::warn;
use slog::Drain;
use slog::Level;
use slog::Logger;
use slog_async::AsyncGuard;
use std::collections::BTreeMap;
use std::fs;
use std::fs::File;
use std::io;
use std::mem;
use std::net::SocketAddrV6;
use std::path::Path;
use std::path::PathBuf;
Expand Down Expand Up @@ -437,25 +439,23 @@ fn ignition_command_from_str(s: &str) -> Result<IgnitionCommand> {
}
}

fn build_logger(level: Level, path: Option<&Path>) -> Result<Logger> {
fn build_logger(
level: Level,
path: Option<&Path>,
) -> Result<(Logger, AsyncGuard)> {
fn make_drain<D: slog_term::Decorator + Send + 'static>(
level: Level,
decorator: D,
) -> slog::Fuse<slog_async::Async> {
) -> (slog::Fuse<slog_async::Async>, AsyncGuard) {
let drain = slog_term::FullFormat::new(decorator)
.build()
.filter_level(level)
.fuse();
slog_async::Async::new(drain).build().fuse()
let (drain, guard) = slog_async::Async::new(drain).build_with_guard();
(drain.fuse(), guard)
}

let drain = if let Some(path) = path {
// Special case /dev/null - don't even bother with slog_async, just
// return a discarding logger.
if path == Path::new("/dev/null") {
return Ok(Logger::root(slog::Discard, o!()));
}

let (drain, guard) = if let Some(path) = path {
let file = File::create(path).with_context(|| {
format!("failed to create logfile {}", path.display())
})?;
Expand All @@ -464,7 +464,7 @@ fn build_logger(level: Level, path: Option<&Path>) -> Result<Logger> {
make_drain(level, slog_term::TermDecorator::new().build())
};

Ok(Logger::root(drain, o!("component" => "faux-mgs")))
Ok((Logger::root(drain, o!("component" => "faux-mgs")), guard))
}

fn build_requested_interfaces(patterns: Vec<String>) -> Result<Vec<String>> {
Expand Down Expand Up @@ -507,7 +507,8 @@ fn build_requested_interfaces(patterns: Vec<String>) -> Result<Vec<String>> {
async fn main() -> Result<()> {
let args = Args::parse();

let log = build_logger(args.log_level, args.logfile.as_deref())?;
let (log, log_guard) =
build_logger(args.log_level, args.logfile.as_deref())?;

let per_attempt_timeout =
Duration::from_millis(args.per_attempt_timeout_millis);
Expand Down Expand Up @@ -589,7 +590,17 @@ async fn main() -> Result<()> {
.await?;

// If usart::run() returns, the user detached; exit.
return Ok(());
//
// We don't just `return Ok(())` here because we'll bump into
// https://github.com/tokio-rs/tokio/issues/2466: `usart::run()`
// reads from stdin, which means we end up with a task blocked in a
// system call, preventing tokio from shutting down the runtime
// created via `tokio::main`. We could create an explicit `Runtime`
// and call `shutdown_background`; instead, we explicitly exit to
// bypass tokio's shutdown. We first drop our `log_guard` to ensure
// any messages have been flushed.
mem::drop(log_guard);
std::process::exit(0);
}
Command::ServeHostPhase2 { directory } => {
populate_phase2_images(&host_phase2_provider, &directory, &log)
Expand Down
Loading

0 comments on commit 17e8a95

Please sign in to comment.