main: Enable the api-socket to be passed as an fd

To avoid race issues where the api-socket may not be created by the
time a cloud-hypervisor caller is ready to look for it, enable the
caller to pass the api-socket fd directly.

Avoid breaking current callers by allowing the --api-socket path to be
passed as it is now in addition to through the path argument.

Signed-off-by: William Douglas <william.r.douglas@gmail.com>
This commit is contained in:
William Douglas
2021-04-09 23:46:55 +00:00
parent 375382cb08
commit 767b4f0e59
4 changed files with 75 additions and 22 deletions

View File

@@ -25,7 +25,7 @@ use signal_hook::{
};
use std::env;
use std::fs::File;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::{FromRawFd, RawFd};
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread;
@@ -62,6 +62,8 @@ enum Error {
ThreadJoin(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
#[error("VMM thread exited with error: {0}")]
VmmThread(#[source] vmm::Error),
#[error("Error parsing --api-socket: {0}")]
ParsingApiSocket(std::num::ParseIntError),
#[error("Error parsing --event-monitor: {0}")]
ParsingEventMonitor(option_parser::OptionParserError),
#[error("Error parsing --event-monitor: path or fd required")]
@@ -324,7 +326,7 @@ fn create_app<'a, 'b>(
.arg(
Arg::with_name("api-socket")
.long("api-socket")
.help("HTTP API socket path (UNIX domain socket).")
.help("HTTP API socket (UNIX domain socket): path=</path/to/a/file> or fd=<fd>.")
.takes_value(true)
.min_values(1)
.group("vmm-config"),
@@ -379,7 +381,7 @@ fn create_app<'a, 'b>(
app
}
fn start_vmm(cmd_arguments: ArgMatches, api_socket_path: &Option<String>) -> Result<(), Error> {
fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
let log_level = match cmd_arguments.occurrences_of("v") {
0 => LevelFilter::Warn,
1 => LevelFilter::Info,
@@ -402,6 +404,29 @@ fn start_vmm(cmd_arguments: ArgMatches, api_socket_path: &Option<String>) -> Res
.map(|()| log::set_max_level(log_level))
.map_err(Error::LoggerSetup)?;
let (api_socket_path, api_socket_fd) =
if let Some(socket_config) = cmd_arguments.value_of("api-socket") {
let mut parser = OptionParser::new();
parser.add("path").add("fd");
parser.parse(socket_config).unwrap_or_default();
if let Some(fd) = parser.get("fd") {
(
None,
Some(fd.parse::<RawFd>().map_err(Error::ParsingApiSocket)?),
)
} else if let Some(path) = parser.get("path") {
(Some(path), None)
} else {
(
cmd_arguments.value_of("api-socket").map(|s| s.to_string()),
None,
)
}
} else {
(None, None)
};
if let Some(monitor_config) = cmd_arguments.value_of("event-monitor") {
let mut parser = OptionParser::new();
parser.add("path").add("fd");
@@ -474,7 +499,8 @@ fn start_vmm(cmd_arguments: ArgMatches, api_socket_path: &Option<String>) -> Res
let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?;
let vmm_thread = vmm::start_vmm_thread(
env!("CARGO_PKG_VERSION").to_string(),
api_socket_path,
&api_socket_path,
api_socket_fd,
api_evt.try_clone().unwrap(),
http_sender,
api_request_receiver,
@@ -510,7 +536,9 @@ fn start_vmm(cmd_arguments: ArgMatches, api_socket_path: &Option<String>) -> Res
vmm_thread
.join()
.map_err(Error::ThreadJoin)?
.map_err(Error::VmmThread)
.map_err(Error::VmmThread)?;
Ok(api_socket_path)
}
fn main() {
@@ -519,16 +547,17 @@ fn main() {
let (default_vcpus, default_memory, default_rng) = prepare_default_values();
let cmd_arguments = create_app(&default_vcpus, &default_memory, &default_rng).get_matches();
let api_socket_path = cmd_arguments.value_of("api-socket").map(|s| s.to_string());
let exit_code = if let Err(e) = start_vmm(cmd_arguments, &api_socket_path) {
eprintln!("{}", e);
1
} else {
0
let exit_code = match start_vmm(cmd_arguments) {
Ok(path) => {
path.map(|s| std::fs::remove_file(s).ok());
0
}
Err(e) => {
eprintln!("{}", e);
1
}
};
api_socket_path.map(|s| std::fs::remove_file(s).ok());
std::process::exit(exit_code);
}