#![allow(unused)]
use crate::RtckResult;
use serde::{Deserialize, Serialize};
pub trait FirecrackerRequest {
fn encode(&self) -> String;
}
pub trait FirecrackerResponse {
type Succ<'de>: Serialize + Deserialize<'de>;
type Fail<'de>: Serialize + Deserialize<'de>;
fn is_succ(&self) -> bool;
fn is_err(&self) -> bool;
fn succ<'de>(&self) -> &Self::Succ<'de>;
fn err<'de>(&self) -> &Self::Fail<'de>;
fn create_succ<'de>(content: Self::Succ<'de>) -> Self
where
Self: Sized;
fn create_fail<'de>(content: Self::Fail<'de>) -> Self
where
Self: Sized;
fn decode<'de>(payload: &'de Vec<u8>) -> crate::RtckResult<Self>
where
Self: Sized,
Self::Succ<'de>: 'static,
{
match serde_json::from_slice::<Self::Succ<'de>>(&payload) {
Ok(content) => Ok(Self::create_succ(content)),
Err(_) => match serde_json::from_slice::<Self::Fail<'de>>(&payload) {
Ok(content) => Ok(Self::create_fail(content)),
Err(e) => Err(crate::RtckError::Decode(e.to_string())),
},
}
}
}
pub trait FirecrackerEvent {
type Req: FirecrackerRequest;
type Res: FirecrackerResponse;
fn req(&self) -> String;
fn res(payload: &Vec<u8>) -> RtckResult<Self::Res>;
}
macro_rules! impl_all_firecracker_traits {
($struct_name:ty, $method:expr, $endpoint:expr, $payload:ty, $res_succ:ty, $res_fail:ty) => {
use super::{FirecrackerEvent, FirecrackerRequest, FirecrackerResponse};
use crate::{
agent::{serialize_request, HttpRequest},
models::{$payload, $res_fail, $res_succ},
};
use either::Either;
impl paste::paste! {[<$struct_name Request>]} {
pub fn new(payload: $payload) -> Self {
Self(payload)
}
}
impl $struct_name {
pub fn new(payload: $payload) -> Self {
Self(<paste::paste! {[<$struct_name Request>]}>::new(payload))
}
}
impl_firecracker_request!(
paste::paste! {[<$struct_name Request>]},
$method,
$endpoint,
$payload
);
impl_firecracker_response!(
paste::paste! {[<$struct_name Response>]},
$res_succ,
$res_fail
);
impl_firecracker_event!(
$struct_name,
paste::paste! {[<$struct_name Request>]},
paste::paste! {[<$struct_name Response>]}
);
};
($struct_name:ty, $method:expr, $endpoint:expr, $res_succ:ty, $res_fail:ty) => {
use super::{FirecrackerEvent, FirecrackerRequest, FirecrackerResponse};
use crate::{
agent::{serialize_request, HttpRequest},
models::{$res_fail, $res_succ},
};
use either::Either;
impl paste::paste! {[<$struct_name Request>]} {
pub fn new() -> Self {
Self
}
}
impl $struct_name {
pub fn new() -> Self {
Self(paste::paste! {[<$struct_name Request>]})
}
}
impl_firecracker_request!(paste::paste! {[<$struct_name Request>]}, $method, $endpoint);
impl_firecracker_response!(
paste::paste! {[<$struct_name Response>]},
$res_succ,
$res_fail
);
impl_firecracker_event!(
$struct_name,
paste::paste! {[<$struct_name Request>]},
paste::paste! {[<$struct_name Response>]}
);
};
($struct_name:ty, $method:expr, $endpoint:expr, $payload:ty, $id:ident, $res_succ:ty, $res_fail:ty) => {
use super::{FirecrackerEvent, FirecrackerRequest, FirecrackerResponse};
use crate::{
agent::{serialize_request, HttpRequest},
models::{$payload, $res_fail, $res_succ},
};
use either::Either;
impl paste::paste! {[<$struct_name Request>]} {
pub fn new(payload: $payload) -> Self {
Self(payload)
}
}
impl $struct_name {
pub fn new(payload: $payload) -> Self {
Self(<paste::paste! {[<$struct_name Request>]}>::new(payload))
}
}
impl_firecracker_request!(
paste::paste! {[<$struct_name Request>]},
$method,
$endpoint,
$payload,
$id
);
impl_firecracker_response!(
paste::paste! {[<$struct_name Response>]},
$res_succ,
$res_fail
);
impl_firecracker_event!(
$struct_name,
paste::paste! {[<$struct_name Request>]},
paste::paste! {[<$struct_name Response>]}
);
};
}
macro_rules! impl_firecracker_request {
($struct_name:ty, $method:expr, $endpoint:expr, $payload:ty) => {
impl FirecrackerRequest for $struct_name {
fn encode(&self) -> String {
let body = serde_json::to_string(&self.0).expect("Fatal error");
let request = HttpRequest::new($method, $endpoint, Some(body.len()), Some(body));
serialize_request(&request)
}
}
};
($struct_name:ty, $method:expr, $endpoint:expr) => {
impl FirecrackerRequest for $struct_name {
fn encode(&self) -> String {
let request = HttpRequest::new($method, $endpoint, None, None);
serialize_request(&request)
}
}
};
($struct_name:ty, $method:expr, $endpoint:expr, $payload:ty, $id:ident) => {
impl FirecrackerRequest for $struct_name {
fn encode(&self) -> String {
let path = format!("{}/{}", $endpoint, &self.0.$id);
let body = serde_json::to_string(&self.0).expect("Fatal error");
let request =
HttpRequest::new($method, path.as_str(), Some(body.len()), Some(body));
serialize_request(&request)
}
}
};
}
macro_rules! impl_firecracker_event {
($type:ty, $req:ty, $res:ty) => {
impl FirecrackerEvent for $type {
type Req = $req;
type Res = $res;
fn req(&self) -> String {
self.0.encode()
}
fn res(payload: &Vec<u8>) -> crate::RtckResult<Self::Res> {
Self::Res::decode(payload)
}
}
};
}
macro_rules! impl_firecracker_response {
($type:ty, $succ:ty, $fail:ty) => {
impl FirecrackerResponse for $type {
type Succ<'de> = $succ;
type Fail<'de> = $fail;
#[inline]
fn is_succ(&self) -> bool {
self.0.is_left()
}
#[inline]
fn is_err(&self) -> bool {
self.0.is_right()
}
#[inline]
fn succ<'de>(&self) -> &Self::Succ<'de> {
self.0
.as_ref()
.left()
.expect("Use is_succ to check your response")
}
#[inline]
fn err<'de>(&self) -> &Self::Fail<'de> {
self.0
.as_ref()
.right()
.expect("Use is_err to check your response")
}
#[inline]
fn create_succ<'de>(content: Self::Succ<'de>) -> Self
where
Self: Sized,
{
Self(either::Left(content))
}
#[inline]
fn create_fail<'de>(content: Self::Fail<'de>) -> Self
where
Self: Sized,
{
Self(either::Right(content))
}
}
};
}
pub mod create_snapshot;
pub use create_snapshot::CreateSnapshot;
pub mod create_sync_action;
pub use create_sync_action::CreateSyncAction;
pub mod describe_balloon_config;
pub use describe_balloon_config::DescribeBalloonConfig;
pub mod describe_balloon_stats;
pub use describe_balloon_stats::DescribeBalloonStats;
pub mod describe_instance;
pub use describe_instance::DescribeInstance;
pub mod get_export_vm_config;
pub use get_export_vm_config::GetExportVmConfig;
pub mod get_firecracker_version;
pub use get_firecracker_version::GetFirecrackerVersion;
pub mod get_machine_configuration;
pub use get_machine_configuration::GetMachineConfiguration;
pub mod get_mmds;
pub use get_mmds::GetMmds;
pub mod patch_balloon_stats_interval;
pub use patch_balloon_stats_interval::PatchBalloonStatsInterval;
pub mod patch_balloon;
pub use patch_balloon::PatchBalloon;
pub mod patch_guest_drive_by_id;
pub use patch_guest_drive_by_id::PatchGuestDriveByID;
pub mod patch_guest_network_interface_by_id;
pub use patch_guest_network_interface_by_id::PatchGuestNetworkInterfaceByID;
pub mod patch_machine_configuration;
pub use patch_machine_configuration::PatchMachineConfiguration;
pub mod patch_mmds;
pub use patch_mmds::PatchMmds;
pub mod patch_vm;
pub use patch_vm::PatchVm;
pub mod load_snapshot;
pub use load_snapshot::LoadSnapshot;
pub mod put_balloon;
pub use put_balloon::PutBalloon;
pub mod put_cpu_configuration;
pub use put_cpu_configuration::PutCpuConfiguration;
pub mod put_entropy;
pub use put_entropy::PutEntropy;
pub mod put_guest_boot_source;
pub use put_guest_boot_source::PutGuestBootSource;
pub mod put_guest_drive_by_id;
pub use put_guest_drive_by_id::PutGuestDriveByID;
pub mod put_guest_network_interface_by_id;
pub use put_guest_network_interface_by_id::PutGuestNetworkInterfaceByID;
pub mod put_guest_vsock;
pub use put_guest_vsock::PutGuestVsock;
pub mod put_logger;
pub use put_logger::PutLogger;
pub mod put_machine_configuration;
pub use put_machine_configuration::PutMachineConfiguration;
pub mod put_metrics;
pub use put_metrics::PutMetrics;
pub mod put_mmds_config;
pub use put_mmds_config::PutMmdsConfig;
pub mod put_mmds;
pub use put_mmds::PutMmds;