diff --git a/hypha/bin/controller.rs b/hypha/bin/controller.rs index e345046..b646d8c 100644 --- a/hypha/bin/controller.rs +++ b/hypha/bin/controller.rs @@ -30,6 +30,8 @@ enum Commands { mem: u64, #[arg(long)] config_bundle: Option, + #[arg(allow_hyphen_values = true, trailing_var_arg = true)] + run: Vec, }, Destroy { #[arg(short, long)] @@ -67,6 +69,7 @@ fn main() -> Result<()> { cpus, mem, config_bundle, + run, } => { let kernel = map_kernel_path(&store_path, kernel); let initrd = map_initrd_path(&store_path, initrd); @@ -77,6 +80,7 @@ fn main() -> Result<()> { &image, cpus, mem, + if run.is_empty() { None } else { Some(run) }, )?; println!("launched domain: {}", domid); } diff --git a/hypha/src/container/init.rs b/hypha/src/container/init.rs index ea70b55..743cfd7 100644 --- a/hypha/src/container/init.rs +++ b/hypha/src/container/init.rs @@ -1,5 +1,6 @@ use crate::error::Result; use crate::hypha_err; +use crate::shared::LaunchInfo; use log::trace; use nix::libc::dup2; use nix::unistd::execve; @@ -27,6 +28,7 @@ const OVERLAY_UPPER_PATH: &str = "/overlay/upper"; const NEW_ROOT_PATH: &str = "/newroot"; const IMAGE_CONFIG_JSON_PATH: &str = "/config/image/config.json"; +const LAUNCH_CONFIG_JSON_PATH: &str = "/config/launch.json"; pub struct ContainerInit {} @@ -49,12 +51,13 @@ impl ContainerInit { self.mount_squashfs_images()?; let config = self.parse_image_config()?; + let launch = self.parse_launch_config()?; self.mount_new_root()?; self.nuke_initrd()?; self.bind_new_root()?; self.map_console(console)?; if let Some(cfg) = config.config() { - self.run(cfg)?; + self.run(cfg, &launch)?; } else { return hypha_err!("unable to determine what to execute, image config doesn't tell us"); } @@ -131,6 +134,12 @@ impl ContainerInit { Ok(config) } + fn parse_launch_config(&mut self) -> Result { + trace!("parsing launch config"); + let launch_config = Path::new(LAUNCH_CONFIG_JSON_PATH); + Ok(serde_json::from_str(&fs::read_to_string(launch_config)?)?) + } + fn nuke_initrd(&mut self) -> Result<()> { trace!("nuking initrd"); let initrd_dev = fs::metadata("/")?.st_dev(); @@ -189,14 +198,20 @@ impl ContainerInit { Ok(()) } - fn run(&mut self, config: &Config) -> Result<()> { + fn run(&mut self, config: &Config, launch: &LaunchInfo) -> Result<()> { let mut cmd = match config.cmd() { None => vec![], Some(value) => value.clone(), }; + + if launch.run.is_some() { + cmd = launch.run.as_ref().unwrap().clone(); + } + if cmd.is_empty() { cmd.push("/bin/sh".to_string()); } + trace!("running container command: {}", cmd.join(" ")); let path = cmd.remove(0); let mut env = match config.env() { @@ -205,10 +220,8 @@ impl ContainerInit { }; env.push("HYPHA_CONTAINER=1".to_string()); let path_cstr = CString::new(path)?; - let mut cmd_cstr = ContainerInit::strings_as_cstrings(cmd)?; - cmd_cstr.push(CString::new("")?); - let mut env_cstr = ContainerInit::strings_as_cstrings(env)?; - env_cstr.push(CString::new("")?); + let cmd_cstr = ContainerInit::strings_as_cstrings(cmd)?; + let env_cstr = ContainerInit::strings_as_cstrings(env)?; let mut working_dir = config .working_dir() .as_ref() diff --git a/hypha/src/ctl/cfgblk.rs b/hypha/src/ctl/cfgblk.rs index 65228f9..b08f713 100644 --- a/hypha/src/ctl/cfgblk.rs +++ b/hypha/src/ctl/cfgblk.rs @@ -1,5 +1,6 @@ use crate::error::Result; use crate::image::ImageInfo; +use crate::shared::LaunchInfo; use backhand::{FilesystemWriter, NodeHeader}; use std::fs; use std::fs::File; @@ -32,12 +33,13 @@ impl ConfigBlock<'_> { }) } - pub fn build(&self) -> Result<()> { + pub fn build(&self, launch_config: &LaunchInfo) -> Result<()> { let config_bundle_content = match self.config_bundle { None => None, Some(path) => Some(fs::read(path)?), }; let manifest = self.image_info.config.to_string()?; + let launch = serde_json::to_string(launch_config)?; let mut writer = FilesystemWriter::default(); writer.push_dir( "/image", @@ -58,6 +60,16 @@ impl ConfigBlock<'_> { mtime: 0, }, )?; + writer.push_file( + launch.as_bytes(), + "/launch.json", + NodeHeader { + permissions: 384, + uid: 0, + gid: 0, + mtime: 0, + }, + )?; if let Some(config_bundle_content) = config_bundle_content.as_ref() { writer.push_file( config_bundle_content.as_slice(), diff --git a/hypha/src/ctl/mod.rs b/hypha/src/ctl/mod.rs index e311209..9565268 100644 --- a/hypha/src/ctl/mod.rs +++ b/hypha/src/ctl/mod.rs @@ -6,6 +6,7 @@ use crate::error::{HyphaError, Result}; use crate::image::cache::ImageCache; use crate::image::name::ImageName; use crate::image::{ImageCompiler, ImageInfo}; +use crate::shared::LaunchInfo; use loopdev::LoopControl; use std::io::{Read, Write}; use std::path::PathBuf; @@ -59,6 +60,7 @@ impl Controller { compiler.compile(&image) } + #[allow(clippy::too_many_arguments)] pub fn launch( &mut self, kernel_path: &str, @@ -67,12 +69,15 @@ impl Controller { image: &str, vcpus: u32, mem: u64, + run: Option>, ) -> Result { let uuid = Uuid::new_v4(); let name = format!("hypha-{uuid}"); let image_info = self.compile(image)?; + let launch_config = LaunchInfo { run }; + let cfgblk = ConfigBlock::new(&uuid, &image_info, config_bundle_path)?; - cfgblk.build()?; + cfgblk.build(&launch_config)?; let image_squashfs_path = image_info .image_squashfs diff --git a/hypha/src/lib.rs b/hypha/src/lib.rs index 6211ecd..b295648 100644 --- a/hypha/src/lib.rs +++ b/hypha/src/lib.rs @@ -3,3 +3,4 @@ pub mod container; pub mod ctl; pub mod error; pub mod image; +mod shared; diff --git a/hypha/src/shared/mod.rs b/hypha/src/shared/mod.rs new file mode 100644 index 0000000..ef779bf --- /dev/null +++ b/hypha/src/shared/mod.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct LaunchInfo { + pub run: Option>, +}