diff --git a/Cargo.lock b/Cargo.lock index 5c5f9602..91dd6f3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,11 +9,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "anyhow" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" + [[package]] name = "api" version = "0.1.0" dependencies = [ "clap", + "thiserror", "vmm", ] @@ -139,12 +146,41 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "proc-macro2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "syn" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -154,12 +190,38 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + [[package]] name = "utils" version = "0.1.0" @@ -230,6 +292,7 @@ dependencies = [ "kvm-ioctls", "libc", "linux-loader", + "thiserror", "utils", "vm-device", "vm-memory", @@ -242,6 +305,7 @@ dependencies = [ name = "vmm-reference" version = "0.1.0" dependencies = [ + "anyhow", "api", "vmm", ] diff --git a/Cargo.toml b/Cargo.toml index 412c58ec..1949e030 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" license = "Apache-2.0 OR BSD-3-Clause" [dependencies] +anyhow = "1.0" vmm = { path = "src/vmm" } api = { path = "src/api" } diff --git a/src/api/Cargo.toml b/src/api/Cargo.toml index 37c1594f..d3b39eef 100644 --- a/src/api/Cargo.toml +++ b/src/api/Cargo.toml @@ -6,5 +6,6 @@ edition = "2018" [dependencies] clap = "2.33.3" +thiserror = "1.0" vmm = { path = "../vmm" } diff --git a/src/api/src/lib.rs b/src/api/src/lib.rs index 79cee637..5af9f92a 100644 --- a/src/api/src/lib.rs +++ b/src/api/src/lib.rs @@ -9,8 +9,17 @@ use std::result; use clap::{App, Arg}; +use thiserror::Error; use vmm::VMMConfig; +#[derive(Error, Debug)] +/// Cli api errors. +pub enum CliError { + /// Failed to parse CLI. + #[error("Failed to parse cli {0}")] + Parse(String), +} + /// Command line parser. pub struct CLI; @@ -20,7 +29,7 @@ impl CLI { /// # Arguments /// /// * `cmdline_args` - command line arguments passed to the application. - pub fn launch(cmdline_args: Vec<&str>) -> result::Result { + pub fn launch(cmdline_args: Vec<&str>) -> result::Result { let mut app = App::new(cmdline_args[0].to_string()) .arg( Arg::with_name("memory") @@ -59,21 +68,19 @@ impl CLI { let mut help_msg_buf: Vec = vec![]; // If the write fails, we'll just have an empty help message. let _ = app.write_long_help(&mut help_msg_buf); - let help_msg = String::from_utf8_lossy(&help_msg_buf); - let matches = app.get_matches_from_safe(cmdline_args).map_err(|e| { - eprintln!("{}", help_msg); - format!("Invalid command line arguments: {}", e) - })?; + let matches = app + .get_matches_from_safe(cmdline_args) + .map_err(|e| CliError::Parse(format!("{}", e)))?; - Ok(VMMConfig::builder() + VMMConfig::builder() .memory_config(matches.value_of("memory")) .kernel_config(matches.value_of("kernel")) .vcpu_config(matches.value_of("vcpu")) .net_config(matches.value_of("net")) .block_config(matches.value_of("block")) .build() - .map_err(|e| format!("{:?}", e))?) + .map_err(|e| CliError::Parse(format!("{}", e))) } } diff --git a/src/main.rs b/src/main.rs index 573f75bf..d69e56c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,37 +1,44 @@ // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause -#[cfg(target_arch = "x86_64")] -use std::convert::TryFrom; -#[cfg(target_arch = "x86_64")] -use std::env; #[cfg(target_arch = "x86_64")] -use api::CLI; -#[cfg(target_arch = "x86_64")] -use vmm::VMM; +mod main { + use std::convert::TryFrom; + use std::env; + + use api::CLI; + use vmm::VMM; -fn main() { - #[cfg(target_arch = "x86_64")] - { - match CLI::launch( + use anyhow::Context; + + pub type Result = anyhow::Result; + + pub fn run() -> Result<()> { + let vmm_config = CLI::launch( env::args() .collect::>() .iter() .map(|s| s.as_str()) .collect(), - ) { - Ok(vmm_config) => { - let mut vmm = - VMM::try_from(vmm_config).expect("Failed to create VMM from configurations"); - // For now we are just unwrapping here, in the future we might use a nicer way of - // handling errors such as pretty printing them. - vmm.run().unwrap(); - } - Err(e) => { - eprintln!("Failed to parse command line options. {}", e); - } - } + ) + .context("Failed to parse CLI options")?; + + let mut vmm = + VMM::try_from(vmm_config).context("Failed to create VMM from configurations")?; + + vmm.run().context("failed to run VMM") + } +} + +#[cfg(target_arch = "aarch64")] +mod main { + pub type Result = std::result::Result; + pub fn run() -> Result<()> { + println!("Reference VMM under construction!"); + Ok(()) } - #[cfg(target_arch = "aarch64")] - println!("Reference VMM under construction!") +} + +fn main() -> main::Result<()> { + main::run() } diff --git a/src/vmm/Cargo.toml b/src/vmm/Cargo.toml index 2366c899..0a0d26b2 100644 --- a/src/vmm/Cargo.toml +++ b/src/vmm/Cargo.toml @@ -5,6 +5,7 @@ authors = ["rust-vmm AWS maintainers "] edition = "2018" [dependencies] +thiserror = "1.0" event-manager = "0.2.1" kvm-bindings = { version = "0.4.0", features = ["fam-wrappers"] } diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index 7b302c54..eaa04195 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -49,6 +49,8 @@ use serial::SerialWrapper; use vm_vcpu::vcpu::{cpuid::filter_cpuid, VcpuState}; use vm_vcpu::vm::{self, ExitHandler, KvmVm, VmState}; +use thiserror::Error; + mod boot; mod config; @@ -81,41 +83,58 @@ pub enum MemoryError { } /// VMM errors. -#[derive(Debug)] +#[derive(Error, Debug)] pub enum Error { /// Failed to create block device. + #[error("Failed to create block device.")] Block(block::Error), /// Failed to write boot parameters to guest memory. + #[error("Failed to write boot parameters to guest memory.")] BootConfigure(configurator::Error), /// Error configuring boot parameters. + #[error("Error configuring boot parameters.")] BootParam(boot::Error), /// Error configuring the kernel command line. + #[error("Error configuring the kernel command line.")] Cmdline(cmdline::Error), /// Error setting up devices. + #[error("Error setting up devices.")] Device(serial::Error), /// Event management error. + #[error("Event management error.")] EventManager(event_manager::Error), /// I/O error. + #[error("I/O error.")] IO(io::Error), /// Failed to load kernel. + #[error("Failed to load kernel.")] KernelLoad(loader::Error), /// Failed to create net device. + #[error("Failed to create net device.")] Net(net::Error), /// Address stored in the rip registry does not fit in guest memory. + #[error("Address stored in the rip registry does not fit in guest memory.")] RipOutOfGuestMemory, /// Invalid KVM API version. + #[error("Invalid KVM API version.")] KvmApiVersion(i32), /// Unsupported KVM capability. + #[error("Unsupported KVM capability.")] KvmCap(Cap), /// Error issuing an ioctl to KVM. + #[error("Error issuing an ioctl to KVM.")] KvmIoctl(kvm_ioctls::Error), /// Memory error. + #[error("Memory error.")] Memory(MemoryError), /// Invalid number of vCPUs specified. + #[error("Invalid number of vCPUs specified.")] VcpuNumber(u8), /// VM errors. + #[error("VM errors.")] Vm(vm::Error), /// Exit event errors. + #[error("Exit event errors.")] ExitEvent(io::Error), }