hypha: implement the ability to override the command line to execute

This commit is contained in:
Alex Zenla 2024-01-22 05:30:02 -08:00
parent e15ac71405
commit 3085a3738f
No known key found for this signature in database
GPG Key ID: 067B238899B51269
6 changed files with 49 additions and 8 deletions

View File

@ -30,6 +30,8 @@ enum Commands {
mem: u64, mem: u64,
#[arg(long)] #[arg(long)]
config_bundle: Option<String>, config_bundle: Option<String>,
#[arg(allow_hyphen_values = true, trailing_var_arg = true)]
run: Vec<String>,
}, },
Destroy { Destroy {
#[arg(short, long)] #[arg(short, long)]
@ -67,6 +69,7 @@ fn main() -> Result<()> {
cpus, cpus,
mem, mem,
config_bundle, config_bundle,
run,
} => { } => {
let kernel = map_kernel_path(&store_path, kernel); let kernel = map_kernel_path(&store_path, kernel);
let initrd = map_initrd_path(&store_path, initrd); let initrd = map_initrd_path(&store_path, initrd);
@ -77,6 +80,7 @@ fn main() -> Result<()> {
&image, &image,
cpus, cpus,
mem, mem,
if run.is_empty() { None } else { Some(run) },
)?; )?;
println!("launched domain: {}", domid); println!("launched domain: {}", domid);
} }

View File

@ -1,5 +1,6 @@
use crate::error::Result; use crate::error::Result;
use crate::hypha_err; use crate::hypha_err;
use crate::shared::LaunchInfo;
use log::trace; use log::trace;
use nix::libc::dup2; use nix::libc::dup2;
use nix::unistd::execve; use nix::unistd::execve;
@ -27,6 +28,7 @@ const OVERLAY_UPPER_PATH: &str = "/overlay/upper";
const NEW_ROOT_PATH: &str = "/newroot"; const NEW_ROOT_PATH: &str = "/newroot";
const IMAGE_CONFIG_JSON_PATH: &str = "/config/image/config.json"; const IMAGE_CONFIG_JSON_PATH: &str = "/config/image/config.json";
const LAUNCH_CONFIG_JSON_PATH: &str = "/config/launch.json";
pub struct ContainerInit {} pub struct ContainerInit {}
@ -49,12 +51,13 @@ impl ContainerInit {
self.mount_squashfs_images()?; self.mount_squashfs_images()?;
let config = self.parse_image_config()?; let config = self.parse_image_config()?;
let launch = self.parse_launch_config()?;
self.mount_new_root()?; self.mount_new_root()?;
self.nuke_initrd()?; self.nuke_initrd()?;
self.bind_new_root()?; self.bind_new_root()?;
self.map_console(console)?; self.map_console(console)?;
if let Some(cfg) = config.config() { if let Some(cfg) = config.config() {
self.run(cfg)?; self.run(cfg, &launch)?;
} else { } else {
return hypha_err!("unable to determine what to execute, image config doesn't tell us"); return hypha_err!("unable to determine what to execute, image config doesn't tell us");
} }
@ -131,6 +134,12 @@ impl ContainerInit {
Ok(config) Ok(config)
} }
fn parse_launch_config(&mut self) -> Result<LaunchInfo> {
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<()> { fn nuke_initrd(&mut self) -> Result<()> {
trace!("nuking initrd"); trace!("nuking initrd");
let initrd_dev = fs::metadata("/")?.st_dev(); let initrd_dev = fs::metadata("/")?.st_dev();
@ -189,14 +198,20 @@ impl ContainerInit {
Ok(()) Ok(())
} }
fn run(&mut self, config: &Config) -> Result<()> { fn run(&mut self, config: &Config, launch: &LaunchInfo) -> Result<()> {
let mut cmd = match config.cmd() { let mut cmd = match config.cmd() {
None => vec![], None => vec![],
Some(value) => value.clone(), Some(value) => value.clone(),
}; };
if launch.run.is_some() {
cmd = launch.run.as_ref().unwrap().clone();
}
if cmd.is_empty() { if cmd.is_empty() {
cmd.push("/bin/sh".to_string()); cmd.push("/bin/sh".to_string());
} }
trace!("running container command: {}", cmd.join(" ")); trace!("running container command: {}", cmd.join(" "));
let path = cmd.remove(0); let path = cmd.remove(0);
let mut env = match config.env() { let mut env = match config.env() {
@ -205,10 +220,8 @@ impl ContainerInit {
}; };
env.push("HYPHA_CONTAINER=1".to_string()); env.push("HYPHA_CONTAINER=1".to_string());
let path_cstr = CString::new(path)?; let path_cstr = CString::new(path)?;
let mut cmd_cstr = ContainerInit::strings_as_cstrings(cmd)?; let cmd_cstr = ContainerInit::strings_as_cstrings(cmd)?;
cmd_cstr.push(CString::new("")?); let env_cstr = ContainerInit::strings_as_cstrings(env)?;
let mut env_cstr = ContainerInit::strings_as_cstrings(env)?;
env_cstr.push(CString::new("")?);
let mut working_dir = config let mut working_dir = config
.working_dir() .working_dir()
.as_ref() .as_ref()

View File

@ -1,5 +1,6 @@
use crate::error::Result; use crate::error::Result;
use crate::image::ImageInfo; use crate::image::ImageInfo;
use crate::shared::LaunchInfo;
use backhand::{FilesystemWriter, NodeHeader}; use backhand::{FilesystemWriter, NodeHeader};
use std::fs; use std::fs;
use std::fs::File; 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 { let config_bundle_content = match self.config_bundle {
None => None, None => None,
Some(path) => Some(fs::read(path)?), Some(path) => Some(fs::read(path)?),
}; };
let manifest = self.image_info.config.to_string()?; let manifest = self.image_info.config.to_string()?;
let launch = serde_json::to_string(launch_config)?;
let mut writer = FilesystemWriter::default(); let mut writer = FilesystemWriter::default();
writer.push_dir( writer.push_dir(
"/image", "/image",
@ -58,6 +60,16 @@ impl ConfigBlock<'_> {
mtime: 0, 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() { if let Some(config_bundle_content) = config_bundle_content.as_ref() {
writer.push_file( writer.push_file(
config_bundle_content.as_slice(), config_bundle_content.as_slice(),

View File

@ -6,6 +6,7 @@ use crate::error::{HyphaError, Result};
use crate::image::cache::ImageCache; use crate::image::cache::ImageCache;
use crate::image::name::ImageName; use crate::image::name::ImageName;
use crate::image::{ImageCompiler, ImageInfo}; use crate::image::{ImageCompiler, ImageInfo};
use crate::shared::LaunchInfo;
use loopdev::LoopControl; use loopdev::LoopControl;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::PathBuf; use std::path::PathBuf;
@ -59,6 +60,7 @@ impl Controller {
compiler.compile(&image) compiler.compile(&image)
} }
#[allow(clippy::too_many_arguments)]
pub fn launch( pub fn launch(
&mut self, &mut self,
kernel_path: &str, kernel_path: &str,
@ -67,12 +69,15 @@ impl Controller {
image: &str, image: &str,
vcpus: u32, vcpus: u32,
mem: u64, mem: u64,
run: Option<Vec<String>>,
) -> Result<u32> { ) -> Result<u32> {
let uuid = Uuid::new_v4(); let uuid = Uuid::new_v4();
let name = format!("hypha-{uuid}"); let name = format!("hypha-{uuid}");
let image_info = self.compile(image)?; let image_info = self.compile(image)?;
let launch_config = LaunchInfo { run };
let cfgblk = ConfigBlock::new(&uuid, &image_info, config_bundle_path)?; let cfgblk = ConfigBlock::new(&uuid, &image_info, config_bundle_path)?;
cfgblk.build()?; cfgblk.build(&launch_config)?;
let image_squashfs_path = image_info let image_squashfs_path = image_info
.image_squashfs .image_squashfs

View File

@ -3,3 +3,4 @@ pub mod container;
pub mod ctl; pub mod ctl;
pub mod error; pub mod error;
pub mod image; pub mod image;
mod shared;

6
hypha/src/shared/mod.rs Normal file
View File

@ -0,0 +1,6 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct LaunchInfo {
pub run: Option<Vec<String>>,
}