Skip to content

Commit

Permalink
refactor: improve sandbox runtime and CLI args handling
Browse files Browse the repository at this point in the history
- Change args handling in mcrun to use trailing args after `--` instead of comma-separated --args
- Update sandbox runtime to support OCI image references and overlayfs
- Remove sandboxes.io registry support and use docker.io as default
- Rename ROOTS_SUBDIR to ROOTFS_SUBDIR for consistency
- Move EXTRACTED_LAYER_SUFFIX to utils/path.rs
- Add SCRIPTS_SUBDIR for better script organization
- Improve script handling with clear_and_add_scripts_to_dir
- Pass RUST_LOG env var to child processes
- Update README.md progress indicators
  • Loading branch information
appcypher committed Feb 25, 2025
1 parent da11a2d commit 345504b
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 110 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@
| | • Sandbox Groups | ⬜️ | Shared network, volume and env management |
| **🛠️ CLI Tools** |
| | **monocore CLI** | 🟨 | Project and sandbox management interface |
| |`init` || Project initialization |
| |`init` | | Project initialization |
| |`add` | ⬜️ | Add sandboxes, builds, or groups to project |
| |`remove` | ⬜️ | Remove project components |
| |`list` | ⬜️ | List sandboxes, builds, or groups |
| |`log` | ⬜️ | View component logs with filtering |
| |`tree` | ⬜️ | Display component layer hierarchy |
| |`run` | 🟨 | Execute defined component scripts |
| |`run` | | Execute defined component scripts |
| |`start` | ⬜️ | Execute component start scripts |
| |`shell` | ⬜️ | Interactive sandbox shell access |
| |`tmp` | ⬜️ | Temporary sandbox creation from images |
Expand Down Expand Up @@ -101,8 +101,6 @@
| | Docker Registry || Integration with Docker registry |
| | ghcr Registry | ⬜️ | Integration with GitHub Container Registry |
| | Quay Registry | ⬜️ | Integration with Red Hat Quay registry |
| **📊 Web UI** |
| | Desktop | ⬜️ | App dashboard |
| **🔌 SDK** |
| | Python SDK | ⬜️ | Sandbox orchestration with Python |
| | TypeScript SDK | ⬜️ | Sandbox orchestration with TypeScript |
Expand Down
37 changes: 21 additions & 16 deletions monocore/bin/mcrun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@
//! --ram-mib=1024 \
//! --workdir-path=/app \
//! --exec-path=/usr/bin/python3 \
//! --arg="-m" \
//! --arg="http.server" \
//! --arg="8080" \
//! --mapped-dirs=/host/path:/guest/path \
//! --port-map=8080:80 \
//! --env=KEY=VALUE
//! --env=KEY=VALUE \
//! -- -m http.server 8080
//! ```
//!
//! ### Supervisor Mode
Expand All @@ -41,13 +39,11 @@
//! --ram-mib=1024 \
//! --workdir-path=/app \
//! --exec-path=/usr/bin/python3 \
//! --arg="-m" \
//! --arg="http.server" \
//! --arg="8080" \
//! --mapped-dirs=/host/path:/guest/path \
//! --port-map=8080:80 \
//! --env=KEY=VALUE \
//! --forward-output
//! --forward-output \
//! -- -m http.server 8080
//! ```
use std::env;
Expand Down Expand Up @@ -80,10 +76,10 @@ async fn main() -> Result<()> {
ram_mib,
workdir_path,
exec_path,
args,
env,
mapped_dirs,
port_map,
args,
} => {
tracing_subscriber::fmt::init();

Expand Down Expand Up @@ -140,10 +136,10 @@ async fn main() -> Result<()> {
ram_mib,
workdir_path,
exec_path,
args,
env,
mapped_dirs,
port_map,
args,
} => {
tracing_subscriber::fmt::init();
tracing::info!("setting up supervisor");
Expand Down Expand Up @@ -175,11 +171,6 @@ async fn main() -> Result<()> {
format!("--exec-path={}", exec_path),
];

// Set args if provided
if !args.is_empty() {
child_args.push(format!("--args={}", args.join(",")));
}

// Set env if provided
if !env.is_empty() {
child_args.push(format!("--env={}", env.join(",")));
Expand All @@ -200,8 +191,22 @@ async fn main() -> Result<()> {
child_args.push(format!("--log-level={}", log_level));
}

// Set args if provided
if !args.is_empty() {
child_args.push("--".to_string());
for arg in args {
child_args.push(arg);
}
}

// Compose child environment variables
let child_envs = vec![("RUST_LOG", "mcrun=info,monocore=info")];
let mut child_envs = Vec::<(String, String)>::new();

// Only pass RUST_LOG if it's set in the environment
if let Ok(rust_log) = std::env::var("RUST_LOG") {
tracing::debug!("using existing RUST_LOG: {:?}", rust_log);
child_envs.push(("RUST_LOG".to_string(), rust_log));
}

// Create and start supervisor
let mut supervisor = Supervisor::new(
Expand Down
16 changes: 8 additions & 8 deletions monocore/lib/cli/args/mcrun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ pub enum McrunSubcommand {
#[arg(long)]
exec_path: String,

/// Arguments for the executable
#[arg(long, use_value_delimiter = true, value_delimiter = ',')]
args: Vec<String>,

/// Environment variables (KEY=VALUE format)
#[arg(long, use_value_delimiter = true, value_delimiter = ',')]
env: Vec<String>,
Expand All @@ -61,6 +57,10 @@ pub enum McrunSubcommand {
/// Port mappings (host:guest format)
#[arg(long, use_value_delimiter = true, value_delimiter = ',')]
port_map: Vec<String>,

/// Additional arguments after `--`
#[arg(last = true)]
args: Vec<String>,
},
/// Run as supervisor
Supervisor {
Expand Down Expand Up @@ -105,10 +105,6 @@ pub enum McrunSubcommand {
#[arg(long)]
exec_path: String,

/// Arguments for the executable
#[arg(long, use_value_delimiter = true, value_delimiter = ',')]
args: Vec<String>,

/// Environment variables (KEY=VALUE format)
#[arg(long, use_value_delimiter = true, value_delimiter = ',')]
env: Vec<String>,
Expand All @@ -120,5 +116,9 @@ pub enum McrunSubcommand {
/// Port mappings (host:guest format)
#[arg(long, use_value_delimiter = true, value_delimiter = ',')]
port_map: Vec<String>,

/// Additional arguments after `--`
#[arg(last = true)]
args: Vec<String>,
},
}
2 changes: 1 addition & 1 deletion monocore/lib/cli/args/monocore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ pub enum MonocoreSubcommand {
#[arg(default_value = DEFAULT_SCRIPT)]
script: String,

/// Additional arguments
/// Additional arguments after `--`
#[arg(last = true)]
args: Vec<String>,

Expand Down
2 changes: 1 addition & 1 deletion monocore/lib/config/defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub static DEFAULT_MONOCORE_HOME: LazyLock<PathBuf> =
LazyLock::new(|| dirs::home_dir().unwrap().join(MONOCORE_HOME_DIR));

/// The default OCI registry domain.
pub const DEFAULT_OCI_REGISTRY: &str = "sandboxes.io";
pub const DEFAULT_OCI_REGISTRY: &str = "docker.io";

/// The default OCI reference tag.
pub const DEFAULT_OCI_REFERENCE_TAG: &str = "latest";
Expand Down
36 changes: 4 additions & 32 deletions monocore/lib/management/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
oci::{DockerRegistry, OciRegistryPull, Reference},
utils::{
env::get_monocore_home_path,
path::{LAYERS_SUBDIR, OCI_DB_FILENAME},
path::{LAYERS_SUBDIR, OCI_DB_FILENAME}, EXTRACTED_LAYER_SUFFIX,
},
MonocoreError, MonocoreResult,
};
Expand All @@ -23,14 +23,9 @@ use tokio::{fs, process::Command};
// Constants
//--------------------------------------------------------------------------------------------------

/// The domain name for the Sandboxes.io registry.
const SANDBOXES_REGISTRY: &str = "sandboxes.io";

/// The domain name for the Docker registry.
const DOCKER_REGISTRY: &str = "docker.io";

/// The suffix added to extracted layer directories
const EXTRACTED_LAYER_SUFFIX: &str = "extracted";

//--------------------------------------------------------------------------------------------------
// Functions
Expand Down Expand Up @@ -92,39 +87,16 @@ pub async fn pull_image(
}

if image_group {
// Only sandboxes registry supports image group pulls.
let registry = name.to_string().split('/').next().unwrap_or("").to_string();

if registry != SANDBOXES_REGISTRY {
return Err(MonocoreError::InvalidArgument(format!(
"image group pull is only supported for sandboxes registry, got: {}",
registry
)));
}

// In image group mode, no fallback is applied
return pull_sandboxes_registry_image_group(&name).await;
return Err(MonocoreError::InvalidArgument(
"image group pull is currently not supported".to_string(),
));
}

// Single image pull mode (default if both flags are false, or if image is true)
let registry = name.to_string().split('/').next().unwrap_or("").to_string();
let temp_download_dir = tempdir()?.into_path();
if registry == DOCKER_REGISTRY {
pull_docker_registry_image(&name, &temp_download_dir, layer_path).await
} else if registry == SANDBOXES_REGISTRY {
match pull_sandboxes_registry_image(&name).await {
Ok(_) => Ok(()),
Err(e) => {
tracing::warn!(
"sandboxes registry image pull failed: {}. falling back to DockerRegistry pull.",
e
);
// Create a new reference with docker.io registry for fallback
let mut docker_ref = name.clone();
docker_ref.set_registry(DOCKER_REGISTRY.to_string());
pull_docker_registry_image(&docker_ref, &temp_download_dir, layer_path).await
}
}
} else {
Err(MonocoreError::InvalidArgument(format!(
"Unsupported registry: {}",
Expand Down
4 changes: 2 additions & 2 deletions monocore/lib/management/menv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! necessary components for running sandboxes, including configuration files,
//! databases, and log directories.
use crate::{config::DEFAULT_CONFIG, utils::ROOTS_SUBDIR, MonocoreResult};
use crate::{config::DEFAULT_CONFIG, utils::ROOTFS_SUBDIR, MonocoreResult};
use std::path::{Path, PathBuf};
use tokio::{fs, io::AsyncWriteExt};

Expand Down Expand Up @@ -70,7 +70,7 @@ async fn create_menv_dirs(menv_path: &Path) -> MonocoreResult<()> {
fs::create_dir_all(menv_path.join(LOG_SUBDIR)).await?;

// We'll create rootfs directory later when monofs is ready
fs::create_dir_all(menv_path.join(ROOTS_SUBDIR)).await?;
fs::create_dir_all(menv_path.join(ROOTFS_SUBDIR)).await?;

Ok(())
}
Expand Down
29 changes: 21 additions & 8 deletions monocore/lib/management/rootfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::{
};
use tokio::{fs::File as TokioFile, io::BufReader};

use crate::{utils::SANDBOX_SCRIPT_DIR, MonocoreResult};
use crate::MonocoreResult;

//--------------------------------------------------------------------------------------------------
// Constants
Expand Down Expand Up @@ -385,21 +385,34 @@ where
/// ## Returns
///
/// Returns `MonocoreResult<()>` indicating success or failure
pub fn patch_native_rootfs_with_scripts(
root_path: impl AsRef<Path>,
pub fn clear_and_add_scripts_to_dir(
scripts_dir: &Path,
scripts: Cow<HashMap<String, String>>,
shell_path: impl AsRef<Path>,
) -> MonocoreResult<()> {
// Create scripts directory
let script_dir = root_path.as_ref().join(SANDBOX_SCRIPT_DIR);
fs::create_dir_all(&script_dir)?;
// Clear or create the scripts directory
if scripts_dir.exists() {
// Remove all contents of the directory
for entry in fs::read_dir(&scripts_dir)? {
let entry = entry?;
let path = entry.path();
if path.is_file() {
fs::remove_file(path)?;
} else if path.is_dir() {
fs::remove_dir_all(path)?;
}
}
} else {
// Create the directory if it doesn't exist
fs::create_dir_all(&scripts_dir)?;
}

// Get shell path as string for shebang
let shell_path = shell_path.as_ref().to_string_lossy();

for (script_name, script_content) in scripts.iter() {
// Create script file path
let script_path = script_dir.join(script_name);
let script_path = scripts_dir.join(script_name);

// Write shebang and content
let full_content = format!("#!{}\n{}", shell_path, script_content);
Expand All @@ -410,7 +423,7 @@ pub fn patch_native_rootfs_with_scripts(
}

// Create shell script containing just the shell path
let shell_script_path = script_dir.join("shell");
let shell_script_path = scripts_dir.join("shell");
fs::write(&shell_script_path, shell_path.to_string())?;
fs::set_permissions(&shell_script_path, fs::Permissions::from_mode(0o750))?;

Expand Down
Loading

0 comments on commit 345504b

Please sign in to comment.