main: Simplify error and return handling in start_vmm

Use a Result<> type with an error to simplify the code in start_vmm().
This will also make it easier to add cleanup funtionality.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-10-26 16:16:56 +00:00
parent dfd21cbfc5
commit c22b788b47
3 changed files with 51 additions and 55 deletions

2
Cargo.lock generated
View File

@ -212,6 +212,7 @@ dependencies = [
name = "cloud-hypervisor"
version = "0.10.0"
dependencies = [
"anyhow",
"api_client",
"clap",
"credibility",
@ -227,6 +228,7 @@ dependencies = [
"ssh2",
"tempdir",
"tempfile",
"thiserror",
"vhost_user_block",
"vhost_user_net",
"vmm",

View File

@ -13,6 +13,7 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
lto = true
[dependencies]
anyhow = "1.0"
api_client = { path = "api_client" }
clap = { version = "2.33.3", features = ["wrap_help"] }
hypervisor = { path = "hypervisor" }
@ -21,6 +22,7 @@ log = { version = "0.4.11", features = ["std"] }
option_parser = { path = "option_parser" }
seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v0.22.0" }
serde_json = "1.0.59"
thiserror = "1.0"
vhost_user_block = { path = "vhost_user_block"}
vhost_user_net = { path = "vhost_user_net"}
vmm = { path = "vmm" }

View File

@ -3,6 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
extern crate anyhow;
extern crate vmm;
extern crate vmm_sys_util;
@ -13,14 +14,39 @@ use clap::{App, Arg, ArgGroup, ArgMatches};
use libc::EFD_NONBLOCK;
use log::LevelFilter;
use seccomp::SeccompAction;
use std::env;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::{env, process};
use thiserror::Error;
use vhost_user_block::start_block_backend;
use vhost_user_net::start_net_backend;
use vmm::config;
use vmm_sys_util::eventfd::EventFd;
#[derive(Error, Debug)]
enum Error {
#[error("Failed to create API EventFd: {0}")]
CreateAPIEventFd(#[source] std::io::Error),
#[error("Failed to open hypervisor interface (is /dev/kvm available?): {0}")]
CreateHypervisor(#[source] hypervisor::HypervisorError),
#[error("Failed to start the VMM thread: {0}")]
StartVMMThread(#[source] vmm::Error),
#[error("Error parsing config: {0}")]
ParsingConfig(vmm::config::Error),
#[error("Error creating VM: {0:?}")]
VmCreate(vmm::api::ApiError),
#[error("Error booting VM: {0:?}")]
VmBoot(vmm::api::ApiError),
#[error("Error restoring VM: {0:?}")]
VmRestore(vmm::api::ApiError),
#[error("Error parsing restore: {0}")]
ParsingRestore(vmm::config::Error),
#[error("Failed to join on VMM thread: {0:?}")]
ThreadJoin(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
#[error("VMM thread exited with error: {0}")]
VmmThread(#[source] vmm::Error),
}
struct Logger {
output: Mutex<Box<dyn std::io::Write + Send>>,
start: std::time::Instant,
@ -320,13 +346,13 @@ fn create_app<'a, 'b>(
app
}
fn start_vmm(cmd_arguments: ArgMatches) {
fn start_vmm(cmd_arguments: ArgMatches) -> Result<(), Error> {
let api_socket_path = cmd_arguments
.value_of("api-socket")
.expect("Missing argument: api-socket");
let (api_request_sender, api_request_receiver) = channel();
let api_evt = EventFd::new(EFD_NONBLOCK).expect("Cannot create API EventFd");
let api_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateAPIEventFd)?;
let http_sender = api_request_sender.clone();
let seccomp_action = if let Some(seccomp_value) = cmd_arguments.value_of("seccomp") {
@ -335,24 +361,15 @@ fn start_vmm(cmd_arguments: ArgMatches) {
"false" => SeccompAction::Allow,
"log" => SeccompAction::Log,
_ => {
eprintln!("Invalid parameter {} for \"--seccomp\" flag", seccomp_value);
process::exit(1);
// The user providing an invalid value will be rejected by clap
panic!("Invalid parameter {} for \"--seccomp\" flag", seccomp_value);
}
}
} else {
SeccompAction::Trap
};
let hypervisor = match hypervisor::new() {
Ok(h) => h,
Err(e) => {
eprintln!(
"Failed to open hypervisor interface (is /dev/kvm available?): {:?}",
e
);
process::exit(1);
}
};
let vmm_thread = match vmm::start_vmm_thread(
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_evt.try_clone().unwrap(),
@ -360,25 +377,14 @@ fn start_vmm(cmd_arguments: ArgMatches) {
api_request_receiver,
&seccomp_action,
hypervisor,
) {
Ok(t) => t,
Err(e) => {
eprintln!("Failed spawning the VMM thread {:?}", e);
process::exit(1);
}
};
)
.map_err(Error::StartVMMThread)?;
// Can't test for "vm-config" group as some have default values. The kernel
// is the only required option for booting the VM.
if cmd_arguments.is_present("kernel") {
let vm_params = config::VmParams::from_arg_matches(&cmd_arguments);
let vm_config = match config::VmConfig::parse(vm_params) {
Ok(config) => config,
Err(e) => {
eprintln!("{}", e);
process::exit(1);
}
};
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
println!(
"Cloud Hypervisor Guest\n\tAPI server: {}\n\tvCPUs: {}\n\tMemory: {} MB\n\tKernel: \
@ -399,36 +405,21 @@ fn start_vmm(cmd_arguments: ArgMatches) {
api_request_sender,
Arc::new(Mutex::new(vm_config)),
)
.expect("Could not create the VM");
vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).expect("Could not boot the VM");
.map_err(Error::VmCreate)?;
vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?;
} else if let Some(restore_params) = cmd_arguments.value_of("restore") {
vmm::api::vm_restore(
api_evt.try_clone().unwrap(),
api_request_sender,
Arc::new(match config::RestoreConfig::parse(restore_params) {
Ok(config) => config,
Err(e) => {
println!("{}", e);
process::exit(1);
}
}),
Arc::new(config::RestoreConfig::parse(restore_params).map_err(Error::ParsingRestore)?),
)
.expect("Could not restore the VM");
.map_err(Error::VmRestore)?;
}
match vmm_thread.join() {
Ok(res) => match res {
Ok(_) => (),
Err(e) => {
eprintln!("VMM thread failed {:?}", e);
process::exit(1);
}
},
Err(e) => {
eprintln!("Could not join VMM thread {:?}", e);
process::exit(1);
}
}
vmm_thread
.join()
.map_err(Error::ThreadJoin)?
.map_err(Error::VmmThread)
}
fn main() {
@ -488,8 +479,9 @@ fn main() {
start_net_backend(backend_command);
} else if let Some(backend_command) = cmd_arguments.value_of("block-backend") {
start_block_backend(backend_command);
} else {
start_vmm(cmd_arguments);
} else if let Err(e) = start_vmm(cmd_arguments) {
eprintln!("{}", e);
std::process::exit(1);
}
}