Skip to content

Commit

Permalink
fix: Give build_microvm_from_requests a proper error type
Browse files Browse the repository at this point in the history
Using FcExitCode as an error type is undesirable, as it allows us to
construct Err(FcExitCode::Ok), e.g. an object that says "error:
everything's okay!". This is confusing and has caused problems in
different contexts before, so replace FcExitCode with a proper error
type here.

Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
  • Loading branch information
roypat committed Nov 23, 2023
1 parent 259c8b8 commit 82901eb
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 21 deletions.
9 changes: 6 additions & 3 deletions src/firecracker/src/api_server_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ use utils::eventfd::EventFd;
use vmm::logger::{error, warn, ProcessTimeReporter};
use vmm::resources::VmResources;
use vmm::rpc_interface::{
ApiRequest, ApiResponse, PrebootApiController, RuntimeApiController, VmmAction,
ApiRequest, ApiResponse, BuildMicrovmFromRequestsError, PrebootApiController,
RuntimeApiController, VmmAction,
};
use vmm::vmm_config::instance_info::InstanceInfo;
use vmm::{EventManager, FcExitCode, Vmm};

#[derive(Debug, thiserror::Error, displaydoc::Display)]
pub enum ApiServerError {
/// MicroVMStopped with an error: {0:?}
/// Failed to build MicroVM: {0:?}.
BuildMicroVmError(BuildMicrovmFromRequestsError),
/// MicroVM stopped with an error: {0:?}
MicroVMStoppedWithError(FcExitCode),
/// Failed to open the API socket at: {0}. Check that it is not already used.
FailedToBindSocket(String),
Expand Down Expand Up @@ -222,7 +225,7 @@ pub(crate) fn run_with_api(
mmds_size_limit,
metadata_json,
)
.map_err(ApiServerError::MicroVMStoppedWithError),
.map_err(ApiServerError::BuildMicroVmError),

Check warning on line 228 in src/firecracker/src/api_server_adapter.rs

View check run for this annotation

Codecov / codecov/patch

src/firecracker/src/api_server_adapter.rs#L228

Added line #L228 was not covered by tests
};

let result = build_result.and_then(|(vm_resources, vmm)| {

Check warning on line 231 in src/firecracker/src/api_server_adapter.rs

View check run for this annotation

Codecov / codecov/patch

src/firecracker/src/api_server_adapter.rs#L231

Added line #L231 was not covered by tests
Expand Down
40 changes: 22 additions & 18 deletions src/vmm/src/rpc_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use super::{
};
use crate::builder::StartMicrovmError;
use crate::cpu_config::templates::{CustomCpuTemplate, GuestConfigError};
use crate::logger::{error, info, warn, LoggerConfig, *};
use crate::logger::{info, warn, LoggerConfig, *};
use crate::mmds::data_store::{self, Mmds};
use crate::persist::{CreateSnapshotError, RestoreFromSnapshotError, VmInfo};
use crate::resources::VmmConfig;
Expand All @@ -42,7 +42,7 @@ use crate::vmm_config::net::{
use crate::vmm_config::snapshot::{CreateSnapshotParams, LoadSnapshotParams, SnapshotType};
use crate::vmm_config::vsock::{VsockConfigError, VsockDeviceConfig};
use crate::vmm_config::{self, RateLimiterUpdate};
use crate::{EventManager, FcExitCode};
use crate::EventManager;

/// This enum represents the public interface of the VMM. Each action contains various
/// bits of information (ids, paths, etc.).
Expand Down Expand Up @@ -247,7 +247,7 @@ pub struct PrebootApiController<'a> {
boot_path: bool,
// Some PrebootApiRequest errors are irrecoverable and Firecracker
// should cleanly teardown if they occur.
fatal_error: Option<FcExitCode>,
fatal_error: Option<BuildMicrovmFromRequestsError>,
}

// TODO Remove when `EventManager` implements `std::fmt::Debug`.
Expand Down Expand Up @@ -287,6 +287,17 @@ pub type ApiRequest = Box<VmmAction>;
/// Shorthand type for a response containing a boxed Result.
pub type ApiResponse = Box<std::result::Result<VmmData, VmmActionError>>;

/// Error type for `PrebootApiController::build_microvm_from_requests`.
#[derive(Debug, thiserror::Error, displaydoc::Display, derive_more::From)]

Check warning on line 291 in src/vmm/src/rpc_interface.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/rpc_interface.rs#L291

Added line #L291 was not covered by tests
pub enum BuildMicrovmFromRequestsError {
/// Populating MMDS from file failed: {0:?}.
Mmds(data_store::Error),
/// Loading snapshot failed.
Restore,
/// Resuming MicroVM after loading snapshot failed.
Resume,
}

impl<'a> PrebootApiController<'a> {
/// Constructor for the PrebootApiController.
pub fn new(
Expand Down Expand Up @@ -320,7 +331,7 @@ impl<'a> PrebootApiController<'a> {
boot_timer_enabled: bool,
mmds_size_limit: usize,
metadata_json: Option<&str>,
) -> Result<(VmResources, Arc<Mutex<Vmm>>), FcExitCode> {
) -> Result<(VmResources, Arc<Mutex<Vmm>>), BuildMicrovmFromRequestsError> {

Check warning on line 334 in src/vmm/src/rpc_interface.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/rpc_interface.rs#L334

Added line #L334 was not covered by tests
let mut vm_resources = VmResources::default();
// Silence false clippy warning. Clippy suggests using
// VmResources { boot_timer: boot_timer_enabled, ..Default::default() }; but this will
Expand All @@ -333,16 +344,9 @@ impl<'a> PrebootApiController<'a> {

// Init the data store from file, if present.
if let Some(data) = metadata_json {
vm_resources
.locked_mmds_or_default()
.put_data(
serde_json::from_str(data)
.expect("MMDS error: metadata provided not valid json"),
)
.map_err(|err| {
error!("Populating MMDS from file failed: {:?}", err);
crate::FcExitCode::GenericError
})?;
vm_resources.locked_mmds_or_default().put_data(
serde_json::from_str(data).expect("MMDS error: metadata provided not valid json"),
)?;

Check warning on line 349 in src/vmm/src/rpc_interface.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/rpc_interface.rs#L347-L349

Added lines #L347 - L349 were not covered by tests

info!("Successfully added metadata to mmds from file");
}
Expand Down Expand Up @@ -376,8 +380,8 @@ impl<'a> PrebootApiController<'a> {
to_api.send(Box::new(res)).expect("one-shot channel closed");

// If any fatal errors were encountered, break the loop.
if let Some(exit_code) = preboot_controller.fatal_error {
return Err(exit_code);
if let Some(preboot_error) = preboot_controller.fatal_error {
return Err(preboot_error);

Check warning on line 384 in src/vmm/src/rpc_interface.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/rpc_interface.rs#L383-L384

Added lines #L383 - L384 were not covered by tests
}
}

Expand Down Expand Up @@ -577,7 +581,7 @@ impl<'a> PrebootApiController<'a> {
)
.map_err(|err| {
// If restore fails, we consider the process is too dirty to recover.
self.fatal_error = Some(FcExitCode::BadConfiguration);
self.fatal_error = Some(BuildMicrovmFromRequestsError::Restore);

Check warning on line 584 in src/vmm/src/rpc_interface.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/rpc_interface.rs#L584

Added line #L584 was not covered by tests
err
})?;
// Resume VM
Expand All @@ -587,7 +591,7 @@ impl<'a> PrebootApiController<'a> {
.resume_vm()
.map_err(|err| {
// If resume fails, we consider the process is too dirty to recover.
self.fatal_error = Some(FcExitCode::BadConfiguration);
self.fatal_error = Some(BuildMicrovmFromRequestsError::Resume);

Check warning on line 594 in src/vmm/src/rpc_interface.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/rpc_interface.rs#L594

Added line #L594 was not covered by tests
err
})?;
}
Expand Down

0 comments on commit 82901eb

Please sign in to comment.