use crate::platform::PlatformServices;
use anyhow::Error;
use fidl_fuchsia_virtualization::LinuxManagerProxy;
use std::fmt;
use {guest_cli_args as arguments, zx_status};
#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum WipeResult {
WipeCompleted,
IncorrectGuestState,
WipeFailure(i32),
UnsupportedGuest(arguments::GuestType),
}
impl fmt::Display for WipeResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
WipeResult::WipeCompleted => write!(f, "Successfully wiped guest"),
WipeResult::WipeFailure(status) => {
write!(f, "Failed to wipe data: {}", zx_status::Status::from_raw(*status))
}
WipeResult::IncorrectGuestState => {
write!(
f,
concat!(
"The VM has already started. Please stop the guest ",
"(by restarting the host or issuing a guest stop command) and retry."
)
)
}
WipeResult::UnsupportedGuest(guest) => {
write!(f, "Wipe is not supported for '{}'. Only 'termina' is supported", guest)
}
}
}
}
pub async fn handle_wipe<P: PlatformServices>(
services: &P,
args: &arguments::wipe_args::WipeArgs,
) -> Result<WipeResult, Error> {
if args.guest_type != arguments::GuestType::Termina {
return Ok(WipeResult::UnsupportedGuest(args.guest_type));
}
let linux_manager = services.connect_to_linux_manager().await?;
do_wipe(linux_manager).await
}
async fn do_wipe(proxy: LinuxManagerProxy) -> Result<WipeResult, Error> {
let result = match proxy.wipe_data().await?.map_err(zx_status::Status::from_raw) {
Err(zx_status::Status::BAD_STATE) => WipeResult::IncorrectGuestState,
Err(status) => WipeResult::WipeFailure(status.into_raw()),
Ok(()) => WipeResult::WipeCompleted,
};
Ok(result)
}
#[cfg(test)]
mod test {
use super::*;
use crate::platform::FuchsiaPlatformServices;
use fidl::endpoints::create_proxy_and_stream;
use fidl_fuchsia_virtualization::LinuxManagerMarker;
use fuchsia_async as fasync;
use futures::StreamExt;
fn serve_mock_manager(response: zx_status::Status) -> LinuxManagerProxy {
let (proxy, mut stream) = create_proxy_and_stream::<LinuxManagerMarker>();
fasync::Task::local(async move {
let responder = stream
.next()
.await
.expect("mock manager expected a request")
.unwrap()
.into_wipe_data()
.expect("unexpected call to mock manager");
if response == zx_status::Status::OK {
responder.send(Ok(())).expect("failed to send mock response");
} else {
responder.send(Err(response.into_raw())).expect("failed to send mock response");
}
})
.detach();
proxy
}
#[fasync::run_until_stalled(test)]
async fn unsupported_guest_type() {
let services = FuchsiaPlatformServices::new();
let result = handle_wipe(
&services,
&arguments::wipe_args::WipeArgs { guest_type: arguments::GuestType::Debian },
)
.await
.unwrap();
assert_eq!(result, WipeResult::UnsupportedGuest(arguments::GuestType::Debian));
}
#[fasync::run_until_stalled(test)]
async fn incorrect_guest_state() {
let proxy = serve_mock_manager(zx_status::Status::BAD_STATE);
let result = do_wipe(proxy).await.unwrap();
assert_eq!(result, WipeResult::IncorrectGuestState);
}
#[fasync::run_until_stalled(test)]
async fn guest_wipe_failure() {
let proxy = serve_mock_manager(zx_status::Status::NOT_FOUND);
let result = do_wipe(proxy).await.unwrap();
assert_eq!(result, WipeResult::WipeFailure(zx_status::Status::NOT_FOUND.into_raw()));
}
#[fasync::run_until_stalled(test)]
async fn guest_successfully_wiped() {
let proxy = serve_mock_manager(zx_status::Status::OK);
let result = do_wipe(proxy).await.unwrap();
assert_eq!(result, WipeResult::WipeCompleted);
}
}