blob: 86134c554c117440a0f804c5cdb3d9206d3d1129 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
mod chromeos;
use std::error::Error;
use std::fmt;
pub use self::chromeos::ChromeOS;
struct UnimplementedError {
name: &'static str,
function: &'static str,
}
impl fmt::Display for UnimplementedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"backend `{}` does not implement `{}`",
self.name, self.function
)
}
}
impl fmt::Debug for UnimplementedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as fmt::Display>::fmt(self, f)
}
}
impl Error for UnimplementedError {}
// The input for this macro is an ordinary trait declaration, with some restrictions. Each method
// must take `&mut self` and return a `Result` where the `Ok` variant implements `Default` and the
// `Err` variant is `Box<Error>`. All other arguments types must implement `Default` and no provided
// implementations for the methods are allowed.
//
// The output of this macro is the input trait with provided methods that return
// `UnimplementedError`. The macro will also produce an implementation of the trait that uses only
// provided methods (i.e. returns an error) and an implementation that only returns
// `Ok(Default::default())`. Each dummy implementation also gets a suite of tests.
macro_rules! impl_backend {
($(#[$trait_attr:meta])* pub trait $trait_nm:ident {
$( $(#[$fn_attr:meta])* fn $fn_nm:ident (&mut self $(, $arg_nm:ident: $arg_ty:ty)* $(,)*) -> Result<$fn_ret:ty, Box<Error>>;)+
}) => {
$(#[$trait_attr])*
pub trait $trait_nm {
/// Returns the name of this implementation.
fn name(&self) -> &'static str;
$(
$(#[$fn_attr])*
fn $fn_nm(&mut self $(, $arg_nm: $arg_ty)*) -> Result<$fn_ret, Box<Error>> {
$(let _ = $arg_nm;)*
Err(UnimplementedError {
name: self.name(),
function: stringify!($fn_nm)
}.into())
}
)+
}
/// A backend that has no side effects and returns an error for every method call.
#[derive(Default)]
pub struct DummyUnimplementedBackend;
impl DummyUnimplementedBackend {
/// Creates a dummy backend with no implementations.
pub fn new() -> DummyUnimplementedBackend {
DummyUnimplementedBackend
}
}
impl $trait_nm for DummyUnimplementedBackend {
fn name(&self) -> &'static str {
"Dummy Unimplemented"
}
}
#[cfg(test)]
mod dummy_unimplemented_backend_tests {
use super::{$trait_nm, DummyUnimplementedBackend};
$(
#[test]
#[should_panic]
fn $fn_nm() {
let mut backend = DummyUnimplementedBackend::new();
backend.$fn_nm( $( <$arg_ty as Default>::default(), )* ).unwrap();
}
)+
}
/// A backend that always returns an `Ok` result with a default value and has no side
/// effects.
#[derive(Default)]
pub struct DummyDefaultBackend;
impl DummyDefaultBackend {
pub fn new() -> DummyDefaultBackend {
DummyDefaultBackend
}
}
impl $trait_nm for DummyDefaultBackend {
fn name(&self) -> &'static str {
"Dummy Default"
}
$(
fn $fn_nm(&mut self $(, $arg_nm: $arg_ty)*) -> Result<$fn_ret, Box<Error>> {
$(let _ = $arg_nm;)*
Ok(Default::default())
}
)+
}
#[cfg(test)]
mod dummy_default_backend_tests {
use super::{$trait_nm, DummyDefaultBackend};
$(
#[test]
fn $fn_nm() {
let mut backend = DummyDefaultBackend::new();
backend.$fn_nm( $( <$arg_ty as Default>::default(), )* ).unwrap();
}
)+
}
}
}
impl_backend! {
/// Defines the method and provides a default implementation that returns an
/// `UnimplementedError`.
pub trait Backend {
// Metrics
/// Sends a `Platform.CrOSEvent` enum histogram sample.
fn metrics_send_sample(&mut self, name: &str) -> Result<(), Box<Error>>;
// Sessions
/// Gets a list of active sessions as a list of tuples: `(email, user_id_hash)`.
fn sessions_list(&mut self) -> Result<Vec<(String, String)>, Box<Error>>;
// Vm
/// Starts a VM called `name` with the given `user_id_hash`.
fn vm_start(
&mut self,
name: &str,
user_id_hash: &str,
enable_gpu: bool,
) -> Result<(), Box<Error>>;
/// Stop `name` VM with given `user_id_hash`.
fn vm_stop(&mut self, name: &str, user_id_hash: &str) -> Result<(), Box<Error>>;
/// Exports the stateful disk image of `name` VM owned by `user_id_hash` to `file_name`,
/// optionally to external drive `removable_media`.
fn vm_export(
&mut self,
name: &str,
user_id_hash: &str,
file_name: &str,
removable_media: Option<&str>,
) -> Result<(), Box<Error>>;
/// Share a `path` with VM `name` owned by `user_id_hash` and return the path inside the VM
/// that it was mounted.
fn vm_share_path(
&mut self,
name: &str,
user_id_hash: &str,
path: &str,
) -> Result<String, Box<Error>>;
// Vsh
/// Starts `vsh` to open a shell into `vm_name` owned by `user_id_hash`.
fn vsh_exec(&mut self, vm_name: &str, user_id_hash: &str) -> Result<(), Box<Error>>;
/// Opens virtual shell in `container_name`, inside the `vm_name`, owned by `user_id_hash`.
fn vsh_exec_container(
&mut self,
vm_name: &str,
user_id_hash: &str,
container_name: &str,
) -> Result<(), Box<Error>>;
// Disk
/// Destroys the disk of `vm_name` for the given `user_id_hash`.
fn disk_destroy(&mut self, vm_name: &str, user_id_hash: &str) -> Result<(), Box<Error>>;
/// Gets a list of all VM disks for `user_id_hash` and their total size.
fn disk_list(&mut self, user_id_hash: &str) -> Result<(Vec<String>, u64), Box<Error>>;
// Container
/// Creates `container_name` ,inside the `vm_name`, owned by `user_id_hash`, derived from
/// `image_alias` from the `image_server`.
fn container_create(
&mut self,
vm_name: &str,
user_id_hash: &str,
container_name: &str,
image_server: &str,
image_alias: &str,
) -> Result<(), Box<Error>>;
/// Starts `container_name`, inside the `vm_name`, owned by `user_id_hash`.
fn container_start(
&mut self,
vm_name: &str,
user_id_hash: &str,
container_name: &str,
) -> Result<(), Box<Error>>;
/// Sets up the `username` in `container_name`, inside the `vm_name`, owned by
/// `user_id_hash`.
fn container_setup_user(
&mut self,
vm_name: &str,
user_id_hash: &str,
container_name: &str,
username: &str,
) -> Result<(), Box<Error>>;
// USB
fn usb_attach(
&mut self,
vm_name: &str,
user_id_hash: &str,
bus: u8,
device: u8,
) -> Result<u8, Box<Error>>;
fn usb_detach(
&mut self,
vm_name: &str,
user_id_hash: &str,
port: u8,
) -> Result<(), Box<Error>>;
fn usb_list(
&mut self,
vm_name: &str,
user_id_hash: &str,
) -> Result<Vec<(u8, u16, u16, String)>, Box<Error>>;
}
}