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
3 changes: 2 additions & 1 deletion packages/cli/src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ impl Cli {
.map_err(|source| tg::error!(!source, "failed to store the command"))?;
let reference = tg::Reference::with_object(command.into());
let mut options = args.build;
options.spawn.sandbox.arg.network = crate::sandbox::Network::new(true);
options.spawn.sandbox.arg.network =
crate::sandbox::NetworkOptions::with_network(tg::sandbox::Network::default());
let args = crate::process::build::Args {
options,
reference: Some(reference),
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/process/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl Cli {
}

let cacheable = args.options.spawn.sandbox.arg.mounts.is_empty()
&& !args.options.spawn.sandbox.arg.network.get()
&& !args.options.spawn.sandbox.arg.network.is_enabled()
&& matches!(args.options.spawn.stdin, Some(tg::process::Stdio::Null))
&& matches!(args.options.spawn.stdout, Some(tg::process::Stdio::Log))
&& matches!(args.options.spawn.stderr, Some(tg::process::Stdio::Log))
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/process/spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,7 @@ impl Cli {
_ => Some(tg::Either::Left(tg::sandbox::create::Arg {
cpu: options.sandbox.arg.cpu,
hostname: options.sandbox.arg.hostname.clone(),
isolation: options.sandbox.arg.isolation,
location: None,
memory: options.sandbox.arg.memory,
mounts,
Expand Down
55 changes: 29 additions & 26 deletions packages/cli/src/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,67 +50,70 @@ pub struct Options {
#[arg(long)]
pub hostname: Option<String>,

#[arg(long)]
pub isolation: Option<tg::sandbox::Isolation>,

#[arg(long)]
pub memory: Option<u64>,

#[arg(action = clap::ArgAction::Append, long = "mount", num_args = 1, short)]
pub mounts: Vec<tg::sandbox::Mount>,

#[clap(flatten)]
pub network: Network,
pub network: NetworkOptions,

#[arg(long)]
pub user: Option<String>,
}

#[derive(Clone, Debug, Default, clap::Args)]
pub struct Network {
/// Whether to enable the network.
pub struct NetworkOptions {
/// Enable networking. Accepts `host`, `bridge`, or `bridge=NAME[@IP]`.
#[arg(
default_missing_value = "true",
long,
num_args = 0..=1,
overrides_with = "no_network",
require_equals = true,
)]
network: Option<bool>,
network: Option<tg::Either<bool, tg::sandbox::Network>>,

#[arg(
default_missing_value = "true",
long,
num_args = 0..=1,
overrides_with = "network",
require_equals = true,
)]
no_network: Option<bool>,
#[arg(long, overrides_with = "network")]
no_network: bool,
}

impl Network {
pub fn get(&self) -> bool {
self.network
.or(self.no_network.map(|v| !v))
.unwrap_or(false)
impl NetworkOptions {
pub fn get(&self) -> tg::Either<bool, tg::sandbox::Network> {
if self.no_network {
tg::Either::Left(false)
} else {
self.network.clone().unwrap_or(tg::Either::Left(false))
}
}

pub fn new(network: bool) -> Self {
Self {
network: Some(network),
no_network: None,
}
pub fn is_enabled(&self) -> bool {
!matches!(self.get(), tg::Either::Left(false))
}

pub fn try_get(&self) -> Option<bool> {
self.network.or(self.no_network.map(|v| !v))
pub fn is_unset(&self) -> bool {
self.network.is_none() && !self.no_network
}

pub fn with_network(network: tg::sandbox::Network) -> Self {
Self {
network: Some(tg::Either::Right(network)),
no_network: false,
}
}
}

impl Options {
pub fn is_empty(&self) -> bool {
self.cpu.is_none()
&& self.hostname.is_none()
&& self.isolation.is_none()
&& self.memory.is_none()
&& self.mounts.is_empty()
&& self.network.try_get().is_none()
&& self.network.is_unset()
&& self.user.is_none()
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/sandbox/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl Cli {
let arg = tg::sandbox::create::Arg {
cpu: args.arg.cpu,
hostname: args.arg.hostname,
isolation: args.arg.isolation,
location: args.location.get(),
memory: args.arg.memory,
mounts: args.arg.mounts,
Expand Down
18 changes: 15 additions & 3 deletions packages/cli/test.nu
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const server_exit_directory_name = 'server_jobs'

def main [
--accept (-a) # Accept all new and updated snapshots.
--bridge # Use bridge networking as the default for the test harness.
--clean # Clean up leftover test resources from cockroach, postgres, scylla, and nats.
--cloud # Enable cloud database backends (cockroach, postgres, scylla, nats) for spawn --cloud.
--jobs (-j): int # The number of concurrent tests to run.
Expand Down Expand Up @@ -115,7 +116,7 @@ def main [
let kernel_path_str = $kernel_path | default "" | into string
if $no_capture {
for test in $tests {
let result = run_test $test $cloud $quickjs $no_capture $preserve_temps $timeout $vm $kernel_path_str
let result = run_test $test $bridge $cloud $quickjs $no_capture $preserve_temps $timeout $vm $kernel_path_str
print_test_result $result $print_passing_test_output
$results = $results | append $result
}
Expand All @@ -129,7 +130,7 @@ def main [

def spawn [test: record] {
job spawn {
let result = run_test $test $cloud $quickjs $no_capture $preserve_temps $timeout $vm $kernel_path_str
let result = run_test $test $bridge $cloud $quickjs $no_capture $preserve_temps $timeout $vm $kernel_path_str
$result | job send 0
}
}
Expand Down Expand Up @@ -353,7 +354,7 @@ def main [
}
}

def run_test [test: record, cloud: bool, quickjs: bool, no_capture: bool, preserve_temps: bool, timeout: duration, vm: bool, kernel_path: string] {
def run_test [test: record, bridge: bool, cloud: bool, quickjs: bool, no_capture: bool, preserve_temps: bool, timeout: duration, vm: bool, kernel_path: string] {
# Create a temp directory for this test.
let temp_path = mktemp -d -t tangram_test_XXXXXX | path expand

Expand Down Expand Up @@ -405,6 +406,7 @@ def run_test [test: record, cloud: bool, quickjs: bool, no_capture: bool, preser
TANGRAM_CONFIG: ($temp_path | path join "config.json"),
TANGRAM_MODE: client,
TANGRAM_QUIET: true,
TANGRAM_TEST_BRIDGE: (if $bridge { "1" } else { "" }),
TANGRAM_TEST_CLOUD: (if $cloud { "1" } else { "" }),
TANGRAM_TEST_QUICKJS: (if $quickjs { "1" } else { "" }),
TANGRAM_TEST_VM: (if $vm { "1" } else { "" }),
Expand Down Expand Up @@ -834,6 +836,7 @@ export def --env spawn [
}
}


let use_vm = (($env.TANGRAM_TEST_VM? | default "") | str length) > 0
if $use_vm {
let kernel_path = $env.TANGRAM_TEST_KERNEL_PATH? | default ""
Expand All @@ -850,6 +853,15 @@ export def --env spawn [
}
}

let use_bridge = (($env.TANGRAM_TEST_BRIDGE? | default "") | str length) > 0
if $use_bridge {
$default_config = $default_config | merge deep {
sandbox: {
bridge: {},
},
}
}

mut id: any = null
let use_cloud = $cloud and (($env.TANGRAM_TEST_CLOUD? | default "") | str length) > 0
if $use_cloud {
Expand Down
4 changes: 3 additions & 1 deletion packages/clients/js/src/handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ export namespace Handle {
export type SandboxArg = {
cpu?: number | undefined;
hostname?: string | undefined;
isolation?: tg.Sandbox.Isolation.Data | undefined;
location?: tg.Location.Arg | undefined;
memory?: number | undefined;
mounts?: Array<tg.Sandbox.Mount.Data> | undefined;
network: boolean;
network: boolean | tg.Sandbox.Network.Data;
ttl?: number | undefined;
user?: string | undefined;
};
Expand Down
35 changes: 32 additions & 3 deletions packages/clients/js/src/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1348,7 +1348,7 @@ export namespace Process {

/** The process's name. */
name?: string | undefined;
network?: boolean | undefined;
network?: boolean | tg.Sandbox.Network | undefined;

/** Configure or select the sandbox for this process. */
sandbox?: boolean | tg.Sandbox.Arg | tg.Sandbox.Id | undefined;
Expand Down Expand Up @@ -2479,6 +2479,17 @@ let isSandboxArg = (value: unknown): value is tg.Sandbox.Arg => {
return typeof value === "object" && value !== null && !Array.isArray(value);
};

let isNetworkEnabled = (value: boolean | tg.Sandbox.Network | undefined) => {
if (value) {
if (typeof value === "boolean") {
return value;
}
return true;
} else {
return false;
}
};

let normalizeSandbox = (
arg: Pick<
tg.Process.ArgObject,
Expand Down Expand Up @@ -2519,13 +2530,19 @@ let normalizeSandbox = (
if (sandbox.hostname !== undefined) {
output.hostname = sandbox.hostname;
}
if (sandbox.isolation !== undefined) {
output.isolation = tg.Sandbox.Isolation.toData(sandbox.isolation);
}
if (sandbox.location !== undefined) {
output.location = sandbox.location;
}
if (sandbox.memory !== undefined) {
output.memory = sandbox.memory;
}
if (sandbox.mounts !== undefined) {
output.mounts = sandbox.mounts.map(tg.Sandbox.Mount.toDataString);
}
output.network = sandbox.network ?? false;
output.network = normalizeNetwork(sandbox.network);
if ("ttl" in sandbox) {
output.ttl = sandbox.ttl;
} else if (defaultTtl) {
Expand All @@ -2548,11 +2565,23 @@ let normalizeSandbox = (
];
}
if (hasNetwork) {
output.network = network;
output.network = normalizeNetwork(network);
}
return output;
};

let normalizeNetwork = (
value: boolean | tg.Sandbox.Network | undefined,
): boolean | tg.Sandbox.Network.Data => {
if (value === undefined) {
return false;
}
if (typeof value === "boolean") {
return value;
}
return tg.Sandbox.Network.toData(value);
};

let normalizeDebug = (
debug: boolean | tg.Process.Debug | undefined,
): tg.Process.Debug | undefined => {
Expand Down
32 changes: 31 additions & 1 deletion packages/clients/js/src/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,43 @@ export namespace Sandbox {
export type Arg = {
cpu?: number | undefined;
hostname?: string | undefined;
isolation?: tg.Sandbox.Isolation | undefined;
location?: tg.Location.Arg | undefined;
memory?: number | undefined;
mounts?: Array<tg.Sandbox.Mount> | undefined;
network?: boolean | undefined;
network?: boolean | tg.Sandbox.Network | undefined;
ttl?: number | undefined;
user?: string | undefined;
};

export type Isolation = "container" | "seatbelt" | "vm";

export namespace Isolation {
export type Data = { kind: tg.Sandbox.Isolation };

export let toData = (value: tg.Sandbox.Isolation): tg.Sandbox.Isolation.Data => {
return { kind: value };
};

export let fromData = (data: tg.Sandbox.Isolation.Data): tg.Sandbox.Isolation => {
return data.kind;
};
}

export type Network = "host" | "bridge";

export namespace Network {
export type Data = { kind: tg.Sandbox.Network };

export let toData = (value: tg.Sandbox.Network): tg.Sandbox.Network.Data => {
return { kind: value };
};

export let fromData = (data: tg.Sandbox.Network.Data): tg.Sandbox.Network => {
return data.kind;
};
}

export type Status = "created" | "started" | "finished";

export type Mount = {
Expand Down
11 changes: 8 additions & 3 deletions packages/clients/rust/src/process.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::time::Duration;

use {
crate::prelude::*,
std::{
marker::PhantomData,
ops::Deref,
path::PathBuf,
sync::{Arc, Mutex, RwLock},
time::Duration,
},
tangram_util::arc::Ext as _,
};
Expand Down Expand Up @@ -429,10 +430,14 @@ pub(crate) fn normalize_sandbox_arg(
}
Ok(Some(tg::Either::Left(tg::sandbox::create::Arg {
cpu,
hostname: None,
isolation: None,
location: None,
memory,
network: false,
network: tg::Either::Left(false),
mounts: Vec::new(),
ttl: Some(Duration::ZERO),
..Default::default()
user: None,
})))
},
}
Expand Down
16 changes: 12 additions & 4 deletions packages/clients/rust/src/process/build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::time::Duration;

use crate::prelude::*;

pub async fn build(arg: tg::process::Arg) -> tg::Result<tg::Value> {
Expand Down Expand Up @@ -31,14 +33,20 @@ impl<O> tg::Process<O> {
let sandbox = super::normalize_sandbox_arg(arg.sandbox.clone(), arg.cpu, arg.memory)?
.unwrap_or_else(|| {
tg::Either::Left(tg::sandbox::create::Arg {
network: false,
ttl: Some(std::time::Duration::ZERO),
..Default::default()
cpu: None,
hostname: None,
isolation: None,
location: None,
memory: None,
network: tg::Either::Left(false),
mounts: Vec::new(),
ttl: Some(Duration::ZERO),
user: None,
})
});
let cacheable = matches!(
&sandbox,
tg::Either::Left(arg) if arg.mounts.is_empty() && !arg.network
tg::Either::Left(arg) if arg.mounts.is_empty() && matches!(&arg.network, tg::Either::Left(false))
) && arg.stdin.is_null()
&& arg.stdout.is_log()
&& arg.stderr.is_log();
Expand Down
Loading