wasmtime: add CLI options for pre-opened TCP listen sockets (#3729)
This patch implements CLI options to insert pre-opened sockets.
`--listenfd` : Inherit environment variables and file descriptors following
the systemd listen fd specification (UNIX only).
`--tcplisten <SOCKET ADDRESS>`: Grant access to the given TCP listen socket.
Signed-off-by: Harald Hoyer <harald@profian.com>
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -1585,6 +1585,17 @@ version = "0.0.37"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95f5690fef754d905294c56f7ac815836f2513af966aa47f2e07ac79be07827f"
|
checksum = "95f5690fef754d905294c56f7ac815836f2513af966aa47f2e07ac79be07827f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "listenfd"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "809e514e2cb8a9624701346ea3e694c1766d76778e343e537d873c1c366e79a7"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"uuid",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
@@ -3472,6 +3483,7 @@ dependencies = [
|
|||||||
"humantime 2.1.0",
|
"humantime 2.1.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
|
"listenfd",
|
||||||
"memchr",
|
"memchr",
|
||||||
"more-asserts",
|
"more-asserts",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ rayon = "1.5.0"
|
|||||||
humantime = "2.0.0"
|
humantime = "2.0.0"
|
||||||
wasmparser = "0.82.0"
|
wasmparser = "0.82.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
listenfd = "0.3.5"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
rustix = "0.33.0"
|
rustix = "0.33.0"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
use structopt::{clap::AppSettings, StructOpt};
|
use structopt::{clap::AppSettings, StructOpt};
|
||||||
use wasmtime::{Engine, Func, Linker, Module, Store, Trap, Val, ValType};
|
use wasmtime::{Engine, Func, Linker, Module, Store, Trap, Val, ValType};
|
||||||
use wasmtime_wasi::sync::{ambient_authority, Dir, WasiCtxBuilder};
|
use wasmtime_wasi::sync::{ambient_authority, Dir, TcpListener, WasiCtxBuilder};
|
||||||
|
|
||||||
#[cfg(feature = "wasi-nn")]
|
#[cfg(feature = "wasi-nn")]
|
||||||
use wasmtime_wasi_nn::WasiNnCtx;
|
use wasmtime_wasi_nn::WasiNnCtx;
|
||||||
@@ -91,6 +91,19 @@ pub struct RunCommand {
|
|||||||
#[structopt(long = "allow-precompiled")]
|
#[structopt(long = "allow-precompiled")]
|
||||||
allow_precompiled: bool,
|
allow_precompiled: bool,
|
||||||
|
|
||||||
|
/// Inherit environment variables and file descriptors following the
|
||||||
|
/// systemd listen fd specification (UNIX only)
|
||||||
|
#[structopt(long = "listenfd")]
|
||||||
|
listenfd: bool,
|
||||||
|
|
||||||
|
/// Grant access to the given TCP listen socket
|
||||||
|
#[structopt(
|
||||||
|
long = "tcplisten",
|
||||||
|
number_of_values = 1,
|
||||||
|
value_name = "SOCKET ADDRESS"
|
||||||
|
)]
|
||||||
|
tcplisten: Vec<String>,
|
||||||
|
|
||||||
/// Grant access to the given host directory
|
/// Grant access to the given host directory
|
||||||
#[structopt(long = "dir", number_of_values = 1, value_name = "DIRECTORY")]
|
#[structopt(long = "dir", number_of_values = 1, value_name = "DIRECTORY")]
|
||||||
dirs: Vec<String>,
|
dirs: Vec<String>,
|
||||||
@@ -151,6 +164,8 @@ impl RunCommand {
|
|||||||
let engine = Engine::new(&config)?;
|
let engine = Engine::new(&config)?;
|
||||||
let mut store = Store::new(&engine, Host::default());
|
let mut store = Store::new(&engine, Host::default());
|
||||||
|
|
||||||
|
let preopen_sockets = self.compute_preopen_sockets()?;
|
||||||
|
|
||||||
// Make wasi available by default.
|
// Make wasi available by default.
|
||||||
let preopen_dirs = self.compute_preopen_dirs()?;
|
let preopen_dirs = self.compute_preopen_dirs()?;
|
||||||
let argv = self.compute_argv();
|
let argv = self.compute_argv();
|
||||||
@@ -165,6 +180,8 @@ impl RunCommand {
|
|||||||
&argv,
|
&argv,
|
||||||
&self.vars,
|
&self.vars,
|
||||||
&self.common.wasi_modules.unwrap_or(WasiModules::default()),
|
&self.common.wasi_modules.unwrap_or(WasiModules::default()),
|
||||||
|
self.listenfd,
|
||||||
|
preopen_sockets,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Load the preload wasm modules.
|
// Load the preload wasm modules.
|
||||||
@@ -243,6 +260,20 @@ impl RunCommand {
|
|||||||
Ok(preopen_dirs)
|
Ok(preopen_dirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compute_preopen_sockets(&self) -> Result<Vec<TcpListener>> {
|
||||||
|
let mut listeners = vec![];
|
||||||
|
|
||||||
|
for address in &self.tcplisten {
|
||||||
|
let stdlistener = std::net::TcpListener::bind(address)
|
||||||
|
.with_context(|| format!("failed to bind to address '{}'", address))?;
|
||||||
|
|
||||||
|
let _ = stdlistener.set_nonblocking(true)?;
|
||||||
|
|
||||||
|
listeners.push(TcpListener::from_std(stdlistener))
|
||||||
|
}
|
||||||
|
Ok(listeners)
|
||||||
|
}
|
||||||
|
|
||||||
fn compute_argv(&self) -> Vec<String> {
|
fn compute_argv(&self) -> Vec<String> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
|
||||||
@@ -415,6 +446,8 @@ fn populate_with_wasi(
|
|||||||
argv: &[String],
|
argv: &[String],
|
||||||
vars: &[(String, String)],
|
vars: &[(String, String)],
|
||||||
wasi_modules: &WasiModules,
|
wasi_modules: &WasiModules,
|
||||||
|
listenfd: bool,
|
||||||
|
mut tcplisten: Vec<TcpListener>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if wasi_modules.wasi_common {
|
if wasi_modules.wasi_common {
|
||||||
wasmtime_wasi::add_to_linker(linker, |host| host.wasi.as_mut().unwrap())?;
|
wasmtime_wasi::add_to_linker(linker, |host| host.wasi.as_mut().unwrap())?;
|
||||||
@@ -422,9 +455,23 @@ fn populate_with_wasi(
|
|||||||
let mut builder = WasiCtxBuilder::new();
|
let mut builder = WasiCtxBuilder::new();
|
||||||
builder = builder.inherit_stdio().args(argv)?.envs(vars)?;
|
builder = builder.inherit_stdio().args(argv)?.envs(vars)?;
|
||||||
|
|
||||||
|
let mut num_fd: usize = 3;
|
||||||
|
|
||||||
|
if listenfd {
|
||||||
|
let (n, b) = ctx_set_listenfd(num_fd, builder)?;
|
||||||
|
num_fd = n;
|
||||||
|
builder = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
for listener in tcplisten.drain(..) {
|
||||||
|
builder = builder.preopened_socket(num_fd as _, listener)?;
|
||||||
|
num_fd += 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (name, dir) in preopen_dirs.into_iter() {
|
for (name, dir) in preopen_dirs.into_iter() {
|
||||||
builder = builder.preopened_dir(dir, name)?;
|
builder = builder.preopened_dir(dir, name)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
store.data_mut().wasi = Some(builder.build());
|
store.data_mut().wasi = Some(builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,3 +501,35 @@ fn populate_with_wasi(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
fn ctx_set_listenfd(num_fd: usize, builder: WasiCtxBuilder) -> Result<(usize, WasiCtxBuilder)> {
|
||||||
|
Ok((num_fd, builder))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn ctx_set_listenfd(num_fd: usize, builder: WasiCtxBuilder) -> Result<(usize, WasiCtxBuilder)> {
|
||||||
|
use listenfd::ListenFd;
|
||||||
|
|
||||||
|
let mut builder = builder;
|
||||||
|
let mut num_fd = num_fd;
|
||||||
|
|
||||||
|
for env in ["LISTEN_FDS", "LISTEN_FDNAMES"] {
|
||||||
|
if let Ok(val) = std::env::var(env) {
|
||||||
|
builder = builder.env(env, &val)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut listenfd = ListenFd::from_env();
|
||||||
|
|
||||||
|
for i in 0..listenfd.len() {
|
||||||
|
if let Some(stdlistener) = listenfd.take_tcp_listener(i)? {
|
||||||
|
let _ = stdlistener.set_nonblocking(true)?;
|
||||||
|
let listener = TcpListener::from_std(stdlistener);
|
||||||
|
builder = builder.preopened_socket((3 + i) as _, listener)?;
|
||||||
|
num_fd = 3 + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((num_fd, builder))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user