From 9ac0f2c06535edf0e8d2095a6cb92cf44a732254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20L=C3=B3pez?= <00xc@protonmail.com> Date: Wed, 4 Oct 2023 10:12:28 +0200 Subject: [PATCH 1/2] refactor(executor): take HTTP method in Executor::send_request() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow callers to set the HTTP method instead of hardcoding it to PUT. Signed-off-by: Carlos López <00xc@protonmail.com> --- firepilot/src/executor.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/firepilot/src/executor.rs b/firepilot/src/executor.rs index 5b9631a..7f0be20 100644 --- a/firepilot/src/executor.rs +++ b/firepilot/src/executor.rs @@ -158,11 +158,16 @@ impl Executor { } #[instrument(skip_all, fields(id = %self.id))] - async fn send_request(&self, url: hyper::Uri, body: String) -> Result<(), ExecuteError> { + async fn send_request( + &self, + url: hyper::Uri, + method: Method, + body: String, + ) -> Result<(), ExecuteError> { debug!("Send request to socket: {}", url); trace!("Sent body to socket [{}]: {}", url, body); let request = Request::builder() - .method(Method::PUT) + .method(method) .uri(url.clone()) .header("Content-Type", "application/json") .header("Accept", "application/json") @@ -204,7 +209,7 @@ impl Executor { let json = serde_json::to_string(&action).map_err(ExecuteError::Serialize)?; let url: hyper::Uri = Uri::new(self.chroot().join("firecracker.socket"), "/actions").into(); - self.send_request(url, json).await?; + self.send_request(url, Method::PUT, json).await?; Ok(()) } @@ -261,7 +266,7 @@ impl Executor { let url: hyper::Uri = Uri::new(self.chroot().join("firecracker.socket"), "/boot-source").into(); - self.send_request(url, json).await?; + self.send_request(url, Method::PUT, json).await?; Ok(()) } @@ -276,7 +281,7 @@ impl Executor { let path = format!("/drives/{}", drive.drive_id); let url: hyper::Uri = Uri::new(self.chroot().join("firecracker.socket"), &path).into(); - self.send_request(url, json).await?; + self.send_request(url, Method::PUT, json).await?; } Ok(()) } @@ -296,7 +301,7 @@ impl Executor { let path = format!("/network-interfaces/{}", network_interface.iface_id); let url: hyper::Uri = Uri::new(self.chroot().join("firecracker.socket"), &path).into(); - self.send_request(url, json).await?; + self.send_request(url, Method::PUT, json).await?; } Ok(()) } From 8f8c77079448e5eeac106ee6931b914d30838a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20L=C3=B3pez?= <00xc@protonmail.com> Date: Wed, 4 Oct 2023 10:34:54 +0200 Subject: [PATCH 2/2] feat: implement VM pause and resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Carlos López <00xc@protonmail.com> --- firepilot/src/executor.rs | 12 ++++++++++++ firepilot/src/machine.rs | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/firepilot/src/executor.rs b/firepilot/src/executor.rs index 7f0be20..72d3c38 100644 --- a/firepilot/src/executor.rs +++ b/firepilot/src/executor.rs @@ -26,6 +26,7 @@ use hyperlocal::{UnixClientExt, UnixConnector, Uri}; use tracing::{debug, error, info, instrument, trace}; use crate::machine::FirepilotError; +use firepilot_models::models::vm::Vm; use firepilot_models::models::{BootSource, Drive, NetworkInterface}; /// Interface to determine how to execute commands on the socket and where to do it @@ -213,6 +214,17 @@ impl Executor { Ok(()) } + /// Sets the microVM the to the specified state + #[instrument(skip_all, fields(id = %self.id))] + pub async fn set_vm_state(&self, state: Vm) -> Result<(), ExecuteError> { + debug!("Change VM state: {:#?}", state); + let json = serde_json::to_string(&state).map_err(ExecuteError::Serialize)?; + + let url: hyper::Uri = Uri::new(self.chroot().join("firecracker.socket"), "/vm").into(); + self.send_request(url, Method::PATCH, json).await?; + Ok(()) + } + /// Full path to the chroot of the machine which contains the socket, drives, kernel, etc... pub fn chroot(&self) -> PathBuf { self.executor().chroot().join(&self.id) diff --git a/firepilot/src/machine.rs b/firepilot/src/machine.rs index 4e20f97..379ba6e 100644 --- a/firepilot/src/machine.rs +++ b/firepilot/src/machine.rs @@ -35,6 +35,8 @@ use crate::{ executor::{Action, Executor}, }; +use firepilot_models::models::vm::{State, Vm}; + #[derive(Debug)] pub enum FirepilotError { /// Mostly problems related to directories error or unavailable files @@ -151,4 +153,16 @@ impl Machine { self.executor.send_action(Action::SendCtrlAltDel).await?; Ok(()) } + + /// Pause a running VM + pub async fn pause(&self) -> Result<(), FirepilotError> { + self.executor.set_vm_state(Vm::new(State::Paused)).await?; + Ok(()) + } + + /// Resume a paused VM + pub async fn resume(&self) -> Result<(), FirepilotError> { + self.executor.set_vm_state(Vm::new(State::Resumed)).await?; + Ok(()) + } }