Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement VM pause and resume #15

Merged
merged 2 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions firepilot/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
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
Expand All @@ -35,7 +36,7 @@
/// Execute a command onto the binary behind the executor
///
/// It is only used to spawn the executor process, not to send commands to it
fn spawn_binary_child(&self, args: &Vec<String>) -> Result<Child, ExecuteError>;

Check warning on line 39 in firepilot/src/executor.rs

View workflow job for this annotation

GitHub Actions / Quality

writing `&Vec` instead of `&[_]` involves a new object where a slice will do
}

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -103,7 +104,7 @@

impl Executor {
/// Create a new Executor with no implementation, and with id "default"
pub fn new() -> Executor {

Check warning on line 107 in firepilot/src/executor.rs

View workflow job for this annotation

GitHub Actions / Quality

you should consider adding a `Default` implementation for `Executor`
Executor {
firecracker: None,
socket_process: None,
Expand Down Expand Up @@ -134,7 +135,7 @@
/// Return the configured executor, or panic if none is configured
fn executor(&self) -> &dyn Execute {
match &self.firecracker {
Some(firecracker) => return firecracker,

Check warning on line 138 in firepilot/src/executor.rs

View workflow job for this annotation

GitHub Actions / Quality

unneeded `return` statement
None => panic!("No executor found"),
}
}
Expand All @@ -158,11 +159,16 @@
}

#[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")
Expand Down Expand Up @@ -204,7 +210,18 @@
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(())
}

/// 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(())
}

Expand Down Expand Up @@ -261,7 +278,7 @@

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(())
}

Expand All @@ -276,7 +293,7 @@

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(())
}
Expand All @@ -296,7 +313,7 @@

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(())
}
Expand Down
14 changes: 14 additions & 0 deletions firepilot/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(())
}
}
Loading