use std::{
env::{split_paths, var_os},
path::PathBuf,
};
use crate::{
builder::{Builder, BuilderError},
executor::{Executor, FirecrackerExecutor},
};
use super::assert_not_none;
#[derive(Debug)]
pub struct FirecrackerExecutorBuilder {
chroot: Option<String>,
exec_binary: Option<PathBuf>,
}
impl FirecrackerExecutorBuilder {
pub fn new() -> FirecrackerExecutorBuilder {
FirecrackerExecutorBuilder {
chroot: None,
exec_binary: None,
}
}
fn find_binary_from_path() -> Option<PathBuf> {
var_os("PATH").and_then(|paths| {
split_paths(&paths)
.filter_map(|d| {
let full_path = d.join("firecracker");
if full_path.is_file() {
Some(full_path)
} else {
None
}
})
.next()
})
}
fn find_binary_from_current_directory() -> Option<PathBuf> {
let full_path = PathBuf::from("./firecracker");
match full_path.is_file() {
true => Some(full_path),
false => None,
}
}
fn find_binary_from_env_location() -> Option<PathBuf> {
if let Some(path) = var_os("FIRECRACKER_LOCATION") {
if PathBuf::from(&path).is_file() {
return Some(PathBuf::from(path));
}
log::warn!(
"FIRECRACKER_LOCATION is set but the file does not exist: {:?}",
path
);
}
None
}
pub fn determine_binary_location() -> Result<PathBuf, BuilderError> {
Self::find_binary_from_env_location()
.or_else(Self::find_binary_from_path)
.or_else(Self::find_binary_from_current_directory)
.map(|p| Ok(p))
.unwrap_or(Err(BuilderError::BinaryNotFound("Check if FIRECRACKER_LOCATION environment variable is correctly set. For more information check https://docs.rs/firepilot/ ".to_string())))
}
pub fn auto() -> Result<FirecrackerExecutorBuilder, BuilderError> {
let binary_path = Self::determine_binary_location()?;
let chroot = "/srv".to_string();
let builder = Self::new()
.with_chroot(chroot)
.with_exec_binary(binary_path);
Ok(builder)
}
pub fn with_chroot(mut self, chroot: String) -> FirecrackerExecutorBuilder {
self.chroot = Some(chroot);
self
}
pub fn with_exec_binary(mut self, exec_binary: PathBuf) -> FirecrackerExecutorBuilder {
self.exec_binary = Some(exec_binary);
self
}
}
impl Builder<Executor> for FirecrackerExecutorBuilder {
fn try_build(self) -> Result<Executor, BuilderError> {
assert_not_none(stringify!(self.chroot), &self.chroot)?;
assert_not_none(stringify!(self.exec_binary), &self.exec_binary)?;
let executor = FirecrackerExecutor {
chroot: self.chroot.unwrap(),
exec_binary: self.exec_binary.unwrap(),
};
Ok(Executor::new_with_firecracker(executor))
}
}
#[cfg(test)]
mod tests {
use serial_test::serial;
use std::env::var_os;
use std::fs::File;
use tempfile::tempdir;
use crate::builder::executor::FirecrackerExecutorBuilder;
#[test]
fn test_firecracker_executor_builder() {
use super::FirecrackerExecutorBuilder;
use crate::builder::Builder;
use std::path::PathBuf;
FirecrackerExecutorBuilder::new()
.with_chroot("/".to_string())
.with_exec_binary(PathBuf::from("/usr/bin/firecracker"))
.try_build()
.unwrap();
}
#[test]
fn test_firecracker_executor_required_fields() {
use super::FirecrackerExecutorBuilder;
use crate::builder::Builder;
use std::path::PathBuf;
let result = FirecrackerExecutorBuilder::new()
.with_chroot("/".to_string())
.try_build();
assert!(result.is_err());
let result = FirecrackerExecutorBuilder::new()
.with_exec_binary(PathBuf::from("/usr/bin/firecracker"))
.try_build();
assert!(result.is_err());
}
#[test]
#[serial]
fn test_can_determine_binary_location_from_env() {
let dir = tempdir().expect("failed to create temporary directory");
let file_path = dir.path().join("firecracker");
let _file = File::create(file_path.clone()).expect("failed to create temporary file");
std::env::set_var("FIRECRACKER_LOCATION", file_path);
let result = FirecrackerExecutorBuilder::determine_binary_location();
assert!(result.is_ok());
std::env::remove_var("FIRECRACKER_LOCATION");
}
#[test]
#[serial]
fn test_cant_determine_binary_location_from_env() {
std::env::set_var("FIRECRACKER_LOCATION", "/tmp/invalid_path/firecracker");
let result = FirecrackerExecutorBuilder::find_binary_from_env_location();
assert!(result.is_none());
std::env::remove_var("FIRECRACKER_LOCATION");
}
#[test]
fn test_can_determine_binary_location_from_path() {
let dir = tempdir().expect("failed to create temporary directory");
let file_path = dir.path().join("firecracker");
let _file = File::create(file_path.clone()).expect("failed to create temporary file");
std::env::set_var("PATH", file_path.parent().unwrap());
println!("{:?}", var_os("PATH"));
let result = FirecrackerExecutorBuilder::determine_binary_location();
assert!(result.is_ok())
}
#[test]
fn test_cant_determine_binary_location_from_path() {
std::env::set_var("PATH", "/tmp/invalid_path");
let result = FirecrackerExecutorBuilder::determine_binary_location();
assert!(result.is_err())
}
}