mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: introduce nice error messages on exit (CHV and ch-remote)
With the foundations of each error type implementing std::error::Error,
we can now nicely walk the `.source()` chain and print an error trace.
This commit introduces improved user-facing error printing when:
- Cloud Hypervisor fails with an error
- ch-remote fails (client error)
- ch-remote fails (remote error)
The additional context is a clear improvement in UX for both users and
developers. In the following example, the new behaviour is shown for
a direct invocation of Cloud Hypervisor leading to a failure. This
looks similar for ch-remote.
```
Old Style
`target/release/cloud-hypervisor --api-socket /tmp/chv2.sock --kernel /etc/bootitems/linux/kernel_minimal/stable.bzImage --cmdline console=ttyS0 --serial tty --console off --disk path=img.raw --initramfs /etc/bootitems/linux/initrd_minimal/default`
Error booting VM: VmBoot(LockingError(BlockError(LockDiskImage(AlreadyLocked)))
```
```
`target/release/cloud-hypervisor --api-socket /tmp/chv2.sock --kernel /etc/bootitems/linux/kernel_minimal/stable.bzImage --cmdline console=ttyS0 --serial tty --console off --disk path=img.raw --initramfs
/etc/bootitems/linux/initrd_minimal/default`
Error: Cloud Hypervisor exited with the following chain of errors:
0: Error booting VM
1: The VM could not boot
2: Error locking disk images: Another instance likely holds a lock
3: Cannot lock images of all block devices
4: Failed to get Write lock for disk image: ./img.raw
5: The file is already locked
Debug Info: VmBoot(VmBoot(LockingError(DiskLockError(LockDiskImage { error: AlreadyLocked, lock_type: Write, path: "./raw_disk.bin" })))
```
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
This commit is contained in:
committed by
Rob Bradford
parent
1433763d40
commit
060c9de07f
@@ -1131,8 +1131,8 @@ fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = target_api.do_command(&matches) {
|
||||
eprintln!("Error running command: {e}");
|
||||
if let Err(top_error) = target_api.do_command(&matches) {
|
||||
cloud_hypervisor::cli_print_error_chain(&top_error, "ch-remote");
|
||||
process::exit(1)
|
||||
};
|
||||
}
|
||||
|
||||
27
src/lib.rs
Normal file
27
src/lib.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright © 2025 Cyberus Technology GmbH
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/// Prints a chain of errors to the user in a consistent manner.
|
||||
/// The user will see a clear chain of errors, followed by debug output
|
||||
/// for opening issues.
|
||||
pub fn cli_print_error_chain(top_error: &dyn std::error::Error, component: &str) {
|
||||
eprint!("Error: {component} exited with the following ");
|
||||
if top_error.source().is_none() {
|
||||
eprintln!("error:");
|
||||
eprintln!(" {top_error}");
|
||||
} else {
|
||||
eprintln!("chain of errors:");
|
||||
std::iter::successors(Some(top_error), |sub_error| {
|
||||
sub_error.source()
|
||||
})
|
||||
.enumerate()
|
||||
.for_each(|(level, error)| {
|
||||
eprintln!(" {level}: {error}",);
|
||||
});
|
||||
}
|
||||
|
||||
eprintln!();
|
||||
eprintln!("Debug Info: {top_error:?}");
|
||||
}
|
||||
@@ -883,8 +883,8 @@ fn main() {
|
||||
path.map(|s| std::fs::remove_file(s).ok());
|
||||
0
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{e}");
|
||||
Err(top_error) => {
|
||||
cloud_hypervisor::cli_print_error_chain(&top_error, "Cloud Hypervisor");
|
||||
1
|
||||
}
|
||||
};
|
||||
|
||||
@@ -69,9 +69,20 @@ pub enum HttpError {
|
||||
|
||||
const HTTP_ROOT: &str = "/api/v1";
|
||||
|
||||
/// Creates the error response's body meant to be sent back to an API client.
|
||||
/// The error message contained in the response is supposed to be user-facing,
|
||||
/// thus insightful and helpful while balancing technical accuracy and
|
||||
/// simplicity.
|
||||
pub fn error_response(error: HttpError, status: StatusCode) -> Response {
|
||||
let mut response = Response::new(Version::Http11, status);
|
||||
response.set_body(Body::new(format!("{error}")));
|
||||
// We must use debug output here without `#`, as it is currently the only
|
||||
// feasible option to get all relevant error details to the receiver,
|
||||
// i.e., ch-remote, in a balanced form. The Display impl is not guaranteed
|
||||
// to hold all relevant or helpful data.
|
||||
//
|
||||
// TODO: We might print a nice error chain here as well and send it to the
|
||||
// remote, similar to the normal error reporting?
|
||||
response.set_body(Body::new(format!("{error:?}")));
|
||||
|
||||
response
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user