Skip to content
Open
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
10 changes: 4 additions & 6 deletions sdks/c/src/options.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::os::raw::{c_char, c_int};

use boxlite::runtime::options::{
BoxOptions, NetworkSpec, PortProtocol, PortSpec, RootfsSpec, Secret, VolumeSpec,
BoxOptions, NetworkPolicy, NetworkSpec, PortProtocol, PortSpec, RootfsSpec, Secret, VolumeSpec,
};

use crate::error::{BoxliteErrorCode, FFIError, null_pointer_error, write_error};
Expand Down Expand Up @@ -403,17 +403,15 @@ pub unsafe fn options_add_port(
pub unsafe fn options_set_network_enabled(handle: *mut OptionsHandle) {
unsafe {
if !handle.is_null() {
(*handle).options.network = NetworkSpec::Enabled {
allow_net: Vec::new(),
};
(*handle).options.network = NetworkPolicy::outbound_enabled(Vec::new());
}
}
}

pub unsafe fn options_set_network_disabled(handle: *mut OptionsHandle) {
unsafe {
if !handle.is_null() {
(*handle).options.network = NetworkSpec::Disabled;
(*handle).options.network = NetworkPolicy::outbound_disabled();
}
}
}
Expand All @@ -424,7 +422,7 @@ pub unsafe fn options_add_network_allow(handle: *mut OptionsHandle, host: *const
return;
}
if let Ok(h) = c_str_to_string(host)
&& let NetworkSpec::Enabled { allow_net } = &mut (*handle).options.network
&& let NetworkSpec::Enabled { allow_net } = &mut (*handle).options.network.outbound
{
allow_net.push(h);
}
Expand Down
30 changes: 19 additions & 11 deletions sdks/node/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use std::time::Duration;
use boxlite::runtime::advanced_options::{AdvancedBoxOptions, HealthCheckOptions, SecurityOptions};
use boxlite::runtime::constants::images;
use boxlite::runtime::options::{
BoxOptions, BoxliteOptions, ImageRegistry, ImageRegistryAuth, NetworkConfig, NetworkMode,
NetworkSpec, PortProtocol, PortSpec, RegistryTransport, RootfsSpec, Secret, VolumeSpec,
BoxOptions, BoxliteOptions, ImageRegistry, ImageRegistryAuth, InboundNetworkConfig,
NetworkConfig, NetworkMode, NetworkPolicy, OutboundNetworkConfig, PortProtocol, PortSpec,
RegistryTransport, RootfsSpec, Secret, VolumeSpec,
};
use napi::bindgen_prelude::Error;
use napi_derive::napi;
Expand Down Expand Up @@ -387,14 +388,17 @@ impl From<PortSpec> for JsPortSpec {
}
}

impl TryFrom<JsNetworkSpec> for NetworkSpec {
impl TryFrom<JsNetworkSpec> for NetworkPolicy {
type Error = boxlite_shared::errors::BoxliteError;

fn try_from(js_spec: JsNetworkSpec) -> Result<Self, Self::Error> {
let mode = js_spec.mode.parse::<NetworkMode>()?;
NetworkSpec::try_from(NetworkConfig {
mode,
allow_net: js_spec.allow_net.unwrap_or_default(),
NetworkPolicy::try_from(NetworkConfig {
outbound: OutboundNetworkConfig {
mode,
allow_net: js_spec.allow_net.unwrap_or_default(),
},
inbound: InboundNetworkConfig::default(),
})
}
}
Expand All @@ -416,8 +420,8 @@ impl TryFrom<JsBoxOptions> for BoxOptions {

// Convert network spec
let network = match js_opts.network {
Some(spec) => NetworkSpec::try_from(spec)?,
None => NetworkSpec::default(),
Some(spec) => NetworkPolicy::try_from(spec)?,
None => NetworkPolicy::default(),
};

// Convert ports
Expand Down Expand Up @@ -613,6 +617,7 @@ impl From<&JsBoxliteRestOptions> for boxlite::BoxliteRestOptions {
#[cfg(test)]
mod tests {
use super::*;
use boxlite::runtime::options::NetworkSpec;

fn js_registry(host: &str) -> JsImageRegistry {
JsImageRegistry {
Expand Down Expand Up @@ -855,7 +860,7 @@ mod tests {
assert_eq!(opts.auto_delete, None);
assert!(opts.advanced.capabilities.add.is_empty());
assert!(opts.advanced.capabilities.drop.is_empty());
match opts.network {
match opts.network.outbound {
NetworkSpec::Enabled { allow_net } => {
assert_eq!(allow_net, vec!["example.com", "*.openai.com"]);
}
Expand Down Expand Up @@ -904,12 +909,15 @@ mod tests {

#[test]
fn disabled_network_rejects_allow_net() {
let err = NetworkSpec::try_from(JsNetworkSpec {
let err = NetworkPolicy::try_from(JsNetworkSpec {
mode: "disabled".into(),
allow_net: Some(vec!["example.com".into()]),
})
.unwrap_err();

assert!(err.to_string().contains("network.mode=\"disabled\""));
assert!(
err.to_string()
.contains("network.outbound.mode=\"disabled\"")
);
}
}
20 changes: 12 additions & 8 deletions sdks/python/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use boxlite::litebox::copy::CopyOptions;
use boxlite::runtime::advanced_options::{HealthCheckOptions, SecurityOptions};
use boxlite::runtime::constants::images;
use boxlite::runtime::options::{
BoxOptions, BoxliteOptions, ImageRegistry, ImageRegistryAuth, NetworkConfig, NetworkMode,
NetworkSpec, PortProtocol, PortSpec, RegistryTransport, RootfsSpec, VolumeSpec,
BoxOptions, BoxliteOptions, ImageRegistry, ImageRegistryAuth, InboundNetworkConfig,
NetworkConfig, NetworkMode, NetworkPolicy, OutboundNetworkConfig, PortProtocol, PortSpec,
RegistryTransport, RootfsSpec, VolumeSpec,
};
use pyo3::exceptions::PyRuntimeError;
use pyo3::prelude::*;
Expand Down Expand Up @@ -271,14 +272,17 @@ impl PyNetworkSpec {
}
}

impl TryFrom<PyNetworkSpec> for NetworkSpec {
impl TryFrom<PyNetworkSpec> for NetworkPolicy {
type Error = boxlite::BoxliteError;

fn try_from(py_spec: PyNetworkSpec) -> Result<Self, Self::Error> {
let mode = py_spec.mode.parse::<NetworkMode>()?;
NetworkSpec::try_from(NetworkConfig {
mode,
allow_net: py_spec.allow_net,
NetworkPolicy::try_from(NetworkConfig {
outbound: OutboundNetworkConfig {
mode,
allow_net: py_spec.allow_net,
},
inbound: InboundNetworkConfig::default(),
})
}
}
Expand Down Expand Up @@ -511,8 +515,8 @@ impl TryFrom<PyBoxOptions> for BoxOptions {
let volumes = py_opts.volumes.into_iter().map(VolumeSpec::from).collect();

let network = match py_opts.network {
Some(spec) => NetworkSpec::try_from(spec)?,
None => NetworkSpec::default(),
Some(spec) => NetworkPolicy::try_from(spec)?,
None => NetworkPolicy::default(),
};

let ports = py_opts.ports.into_iter().map(PortSpec::from).collect();
Expand Down
4 changes: 2 additions & 2 deletions src/boxlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ pub use runtime::advanced_options::{
};
pub use runtime::options::{
BoxArchive, BoxOptions, BoxliteOptions, CloneOptions, ExportOptions, ImageRegistry,
ImageRegistryAuth, NetworkMode, NetworkSpec, PortProtocol, RegistryTransport, RootfsSpec,
Secret, SnapshotOptions,
ImageRegistryAuth, InboundNetworkPolicy, NetworkMode, NetworkPolicy, NetworkSpec,
OutboundNetworkPolicy, PortProtocol, RegistryTransport, RootfsSpec, Secret, SnapshotOptions,
};
/// Boxlite library version (from CARGO_PKG_VERSION at compile time).
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
Expand Down
117 changes: 58 additions & 59 deletions src/boxlite/src/litebox/init/tasks/guest_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::net::constants::{GATEWAY_IP, GUEST_CIDR, GUEST_INTERFACE};
use crate::pipeline::PipelineTask;
use crate::portal::GuestSession;
use crate::portal::interfaces::{ContainerInitConfig, GuestInitConfig, NetworkInitConfig};
use crate::runtime::options::NetworkSpec;
use async_trait::async_trait;
use boxlite_shared::ContainerDevice;
use boxlite_shared::errors::{BoxliteError, BoxliteResult};
Expand Down Expand Up @@ -40,69 +41,67 @@ impl PipelineTask<InitCtx> for GuestInitTask {
let task_name = self.name();
let box_id = task_start(&ctx, task_name).await;

let (guest_session, volume_mgr, rootfs_init, container_mounts, bootstrap) = {
let mut ctx = ctx.lock().await;
let guest_session = ctx
.guest_session
.take()
.ok_or_else(|| BoxliteError::Internal("connect task must run first".into()))?;
let image = ctx
.container_image_config
.clone()
.ok_or_else(|| BoxliteError::Internal("rootfs task must run first".into()))?;
let volume_mgr = ctx
.volume_mgr
.take()
.ok_or_else(|| BoxliteError::Internal("vmm_spawn task must run first".into()))?;
let rootfs_init = ctx
.rootfs_init
.take()
.ok_or_else(|| BoxliteError::Internal("vmm_spawn task must run first".into()))?;
let container_mounts = ctx
.container_mounts
.take()
.ok_or_else(|| BoxliteError::Internal("vmm_spawn task must run first".into()))?;

let network = match &ctx.config.options.network {
crate::runtime::options::NetworkSpec::Enabled { .. } => Some(NetworkInitConfig {
interface: GUEST_INTERFACE.to_string(),
ip: Some(GUEST_CIDR.to_string()),
gateway: Some(GATEWAY_IP.to_string()),
}),
crate::runtime::options::NetworkSpec::Disabled => None,
};
let bootstrap = GuestBootstrapConfig {
guest: GuestInitConfig {
volumes: volume_mgr.build_guest_mounts(),
network,
},
container: ContainerInitConfig {
container_id: ctx.config.container.id.as_str().to_owned(),
image,
rootfs: rootfs_init.clone(),
mounts: container_mounts.clone(),
ca_certs: ctx.ca_cert_pem.iter().cloned().collect(),
tty: ctx.config.options.tty,
devices: if ctx.config.options.advanced.nested_virtualization {
vec![kvm_device()]
} else {
Vec::new()
let (guest_session, volume_mgr, rootfs_init, container_mounts, bootstrap) =
{
let mut ctx = ctx.lock().await;
let guest_session = ctx
.guest_session
.take()
.ok_or_else(|| BoxliteError::Internal("connect task must run first".into()))?;
let image = ctx
.container_image_config
.clone()
.ok_or_else(|| BoxliteError::Internal("rootfs task must run first".into()))?;
let volume_mgr = ctx.volume_mgr.take().ok_or_else(|| {
BoxliteError::Internal("vmm_spawn task must run first".into())
})?;
let rootfs_init = ctx.rootfs_init.take().ok_or_else(|| {
BoxliteError::Internal("vmm_spawn task must run first".into())
})?;
let container_mounts = ctx.container_mounts.take().ok_or_else(|| {
BoxliteError::Internal("vmm_spawn task must run first".into())
})?;

let network = match &ctx.config.options.network.outbound {
NetworkSpec::Enabled { .. } => Some(NetworkInitConfig {
interface: GUEST_INTERFACE.to_string(),
ip: Some(GUEST_CIDR.to_string()),
gateway: Some(GATEWAY_IP.to_string()),
}),
NetworkSpec::Disabled => None,
};
let bootstrap = GuestBootstrapConfig {
guest: GuestInitConfig {
volumes: volume_mgr.build_guest_mounts(),
network,
},
advanced: crate::portal::interfaces::container::ContainerAdvancedConfig {
capabilities: ctx.config.options.advanced.capabilities.clone(),
container: ContainerInitConfig {
container_id: ctx.config.container.id.as_str().to_owned(),
image,
rootfs: rootfs_init.clone(),
mounts: container_mounts.clone(),
ca_certs: ctx.ca_cert_pem.iter().cloned().collect(),
tty: ctx.config.options.tty,
devices: if ctx.config.options.advanced.nested_virtualization {
vec![kvm_device()]
} else {
Vec::new()
},
advanced: crate::portal::interfaces::container::ContainerAdvancedConfig {
capabilities: ctx.config.options.advanced.capabilities.clone(),
},
},
},
};

(
guest_session,
volume_mgr,
rootfs_init,
container_mounts,
bootstrap,
)
};

(
guest_session,
volume_mgr,
rootfs_init,
container_mounts,
bootstrap,
)
};

run_guest_init(guest_session.clone(), bootstrap)
.await
.inspect_err(|e| log_task_error(&box_id, task_name, e))?;
Expand Down
7 changes: 4 additions & 3 deletions src/boxlite/src/litebox/init/tasks/vmm_attach.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use super::{InitCtx, task_start};
use crate::litebox::CrashReport;
use crate::net::NetworkBackendConfig;
use crate::pipeline::PipelineTask;
use crate::runtime::options::NetworkSpec;
use crate::runtime::rt_impl::stash_exit_file;
use crate::util::{PidFileReader, ProcessIdentity};
use crate::vmm::ExitInfo;
Expand All @@ -35,11 +36,11 @@ impl PipelineTask<InitCtx> for VmmAttachTask {
let (runtime, config_id, network) = {
let ctx = ctx.lock().await;
// Reattach still owns a control backend for the box's live gvproxy.
let network = match &ctx.config.options.network {
crate::runtime::options::NetworkSpec::Enabled { allow_net } => {
let network = match &ctx.config.options.network.outbound {
NetworkSpec::Enabled { allow_net } => {
Some((allow_net.clone(), ctx.config.options.secrets.clone()))
}
crate::runtime::options::NetworkSpec::Disabled => None,
NetworkSpec::Disabled => None,
};
(ctx.runtime.clone(), ctx.config.id.clone(), network)
};
Expand Down
20 changes: 7 additions & 13 deletions src/boxlite/src/litebox/init/tasks/vmm_spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::rootfs::guest::{GuestRootfs, Strategy};
use crate::runtime::constants::{guest_paths, mount_tags};
use crate::runtime::id::BoxID;
use crate::runtime::layout::BoxFilesystemLayout;
use crate::runtime::options::BoxOptions;
use crate::runtime::options::{BoxOptions, NetworkSpec};
use crate::runtime::rt_impl::SharedRuntimeImpl;
use crate::runtime::types::ContainerID;
use crate::util::find_binary;
Expand Down Expand Up @@ -260,10 +260,7 @@ async fn build_config(
guest_rootfs,
network_backend_spec,
network_backend_endpoint: None,
disable_network: matches!(
options.network,
crate::runtime::options::NetworkSpec::Disabled
),
disable_network: matches!(options.network.outbound, NetworkSpec::Disabled),
home_dir: runtime.layout.home_dir().to_path_buf(),
// Diagnostic files in box_dir (preserved on crash)
console_output: Some(layout.console_output_path()),
Expand Down Expand Up @@ -359,9 +356,9 @@ fn build_network_backend(
runtime: &SharedRuntimeImpl,
) -> BoxliteResult<Option<Box<dyn NetworkBackend>>> {
// Disabled = no network at all.
let allow_net = match &options.network {
crate::runtime::options::NetworkSpec::Enabled { allow_net } => allow_net.clone(),
crate::runtime::options::NetworkSpec::Disabled => return Ok(None),
let allow_net = match &options.network.outbound {
NetworkSpec::Enabled { allow_net } => allow_net.clone(),
NetworkSpec::Disabled => return Ok(None),
};

let config = NetworkBackendConfig {
Expand All @@ -379,10 +376,7 @@ fn unpublished_exposed_tcp_ports(
image_config: &ContainerImageConfig,
options: &BoxOptions,
) -> Vec<u16> {
if matches!(
options.network,
crate::runtime::options::NetworkSpec::Disabled
) {
if matches!(options.network.outbound, NetworkSpec::Disabled) {
return Vec::new();
}

Expand Down Expand Up @@ -462,7 +456,7 @@ mod tests {
);

let disabled_options = BoxOptions {
network: crate::runtime::options::NetworkSpec::Disabled,
network: crate::runtime::options::NetworkPolicy::outbound_disabled(),
..Default::default()
};
assert!(
Expand Down
Loading
Loading