mirror of
https://github.com/michael-yuji/xc.git
synced 2026-03-23 17:25:13 +01:00
expose network configuration as envs to containers
This commit is contained in:
@@ -67,17 +67,29 @@ pub struct CreateContainer {
|
||||
pub root: String,
|
||||
/// The devfs ruleset id assigned to this container
|
||||
pub devfs_ruleset_id: u16,
|
||||
|
||||
pub ip_alloc: Vec<IpAssign>,
|
||||
|
||||
pub mount_req: Vec<Mount>,
|
||||
|
||||
pub vnet: bool,
|
||||
|
||||
pub init: Vec<Jexec>,
|
||||
|
||||
pub deinit: Vec<Jexec>,
|
||||
|
||||
pub main: Option<Jexec>,
|
||||
|
||||
pub linux: bool,
|
||||
|
||||
pub main_norun: bool,
|
||||
|
||||
pub init_norun: bool,
|
||||
|
||||
pub deinit_norun: bool,
|
||||
|
||||
pub persist: bool,
|
||||
|
||||
pub no_clean: bool,
|
||||
/// Do not create /proc automatically and abort mounting procfs if the directory is missing.
|
||||
pub linux_no_create_proc_dir: bool,
|
||||
@@ -87,6 +99,7 @@ pub struct CreateContainer {
|
||||
pub linux_no_mount_sys: bool,
|
||||
/// Do not mount linux procfs
|
||||
pub linux_no_mount_proc: bool,
|
||||
|
||||
pub zfs_origin: Option<String>,
|
||||
|
||||
pub origin_image: Option<JailImage>,
|
||||
@@ -108,6 +121,8 @@ pub struct CreateContainer {
|
||||
pub children_max: u32,
|
||||
|
||||
pub main_ip_selector: Option<MainAddressSelector>,
|
||||
|
||||
pub envs: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl CreateContainer {
|
||||
@@ -413,7 +428,8 @@ impl CreateContainer {
|
||||
started: None,
|
||||
finished_at: None,
|
||||
jailed_datasets: self.jailed_datasets,
|
||||
main_ip_selector: None,
|
||||
main_ip_selector: self.main_ip_selector,
|
||||
envs: self.envs
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,9 +194,10 @@ impl ProcessRunner {
|
||||
info!("spawn: {exec:#?}");
|
||||
container_runner::spawn_process!(|| (self.container.jid, id, exec));
|
||||
|
||||
let mut envs = self.container.envs.clone();
|
||||
|
||||
let jail = freebsd::jail::RunningJail::from_jid_unchecked(self.container.jid);
|
||||
let paths = exec
|
||||
.envs
|
||||
let paths = envs
|
||||
.get("PATH")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| "/bin:/usr/bin:/sbin:/usr/sbin".to_string());
|
||||
@@ -247,11 +248,48 @@ impl ProcessRunner {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
for (key, value) in exec.envs.iter() {
|
||||
envs.insert(key.to_string(), value.to_string());
|
||||
}
|
||||
|
||||
if let Some(address) = self.container.main_address() {
|
||||
// allow faking the environ to make debugging easier
|
||||
if !envs.contains_key("XC_MAIN_IP") {
|
||||
envs.insert("XC_MAIN_IP".to_string(), address.address.to_string());
|
||||
}
|
||||
if !envs.contains_key("XC_MAIN_IFACE") {
|
||||
envs.insert("XC_MAIN_IFACE".to_string(), address.interface);
|
||||
}
|
||||
}
|
||||
|
||||
let mut networks_count = 0;
|
||||
for network in self.container.networks() {
|
||||
networks_count += 1;
|
||||
let network_name = network.network.as_ref().unwrap();
|
||||
envs.insert(
|
||||
format!("XC_NETWORK_{network_name}_ADDR_COUNT"),
|
||||
network.addresses.len().to_string()
|
||||
);
|
||||
envs.insert(
|
||||
format!("XC_NETWORK_{network_name}_IFACE"),
|
||||
network.interface.to_string(),
|
||||
);
|
||||
for (i, addr) in network.addresses.iter().enumerate() {
|
||||
envs.insert(format!("XC_NETWORK_{network_name}_ADDR_{i}"), addr.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
envs.insert("XC_NETWORKS_COUNT".to_string(), networks_count.to_string());
|
||||
|
||||
envs.insert("XC_ID".to_string(), self.container.id.to_string());
|
||||
|
||||
|
||||
let mut cmd = std::process::Command::new(&exec.arg0);
|
||||
|
||||
cmd.env_clear()
|
||||
.args(&exec.args)
|
||||
.envs(&exec.envs)
|
||||
.envs(envs)
|
||||
.jail(&jail)
|
||||
.juid(uid)
|
||||
.jgid(gid);
|
||||
|
||||
@@ -27,7 +27,7 @@ use crate::container::request::Mount;
|
||||
use crate::container::ContainerManifest;
|
||||
use crate::models::exec::Jexec;
|
||||
use crate::models::jail_image::JailImage;
|
||||
use crate::models::network::{DnsSetting, IpAssign, MainAddressSelector};
|
||||
use crate::models::network::{DnsSetting, IpAssign, MainAddressSelector, AssignedAddress};
|
||||
use crate::util::realpath;
|
||||
|
||||
use anyhow::Context;
|
||||
@@ -93,6 +93,28 @@ pub struct RunningContainer {
|
||||
pub jailed_datasets: Vec<PathBuf>,
|
||||
|
||||
pub main_ip_selector: Option<MainAddressSelector>,
|
||||
|
||||
pub envs: HashMap<String, String>,
|
||||
}
|
||||
|
||||
pub struct ContainerNetworkIter<'a>(std::slice::Iter<'a, IpAssign>);
|
||||
|
||||
impl<'a> Iterator for ContainerNetworkIter<'a> {
|
||||
type Item = &'a IpAssign;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
match self.0.next() {
|
||||
None => return None,
|
||||
x@Some(assign) => {
|
||||
if assign.network.is_none() {
|
||||
continue
|
||||
} else {
|
||||
return x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RunningContainer {
|
||||
@@ -158,34 +180,12 @@ impl RunningContainer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn main_address(&self) -> Option<IpAddr> {
|
||||
match &self.main_ip_selector {
|
||||
Some(MainAddressSelector::Ip(address)) => Some(*address),
|
||||
Some(MainAddressSelector::Network(network)) => {
|
||||
for alloc in self.ip_alloc.iter() {
|
||||
match alloc.network.as_ref() {
|
||||
Some(_network) if network == _network => {
|
||||
match alloc.addresses.first() {
|
||||
None => continue,
|
||||
Some(addr) => return Some(addr.addr())
|
||||
}
|
||||
},
|
||||
_ => continue
|
||||
}
|
||||
}
|
||||
None
|
||||
},
|
||||
None => {
|
||||
for alloc in self.ip_alloc.iter() {
|
||||
if alloc.network.is_some() {
|
||||
if let Some(address) = alloc.addresses.first() {
|
||||
return Some(address.addr())
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
},
|
||||
}
|
||||
pub fn main_address(&self) -> Option<AssignedAddress> {
|
||||
MainAddressSelector::select(&self.main_ip_selector, self.ip_alloc.iter())
|
||||
}
|
||||
|
||||
pub fn networks(&self) -> ContainerNetworkIter<'_> {
|
||||
ContainerNetworkIter(self.ip_alloc.iter())
|
||||
}
|
||||
|
||||
pub fn serialized(&self) -> ContainerManifest {
|
||||
@@ -224,7 +224,7 @@ impl RunningContainer {
|
||||
started: self.started,
|
||||
finished_at: self.finished_at,
|
||||
created: self.created,
|
||||
main_address: self.main_address(),
|
||||
main_address: self.main_address().map(|a| a.address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,6 +163,60 @@ pub enum MainAddressSelector {
|
||||
Ip(IpAddr)
|
||||
}
|
||||
|
||||
pub struct AssignedAddress {
|
||||
pub interface: String,
|
||||
pub address: IpAddr,
|
||||
}
|
||||
|
||||
impl AssignedAddress {
|
||||
pub fn new(interface: String, address: IpAddr) -> AssignedAddress {
|
||||
AssignedAddress {
|
||||
interface,
|
||||
address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MainAddressSelector {
|
||||
pub fn select<'a, I: Iterator<Item = &'a IpAssign>>(selector: &Option<Self>, pool: I) -> Option<AssignedAddress> {
|
||||
match selector {
|
||||
None => {
|
||||
for alloc in pool {
|
||||
if alloc.network.is_some() {
|
||||
if let Some(address) = alloc.addresses.first() {
|
||||
return Some(AssignedAddress::new(alloc.interface.to_string(), address.addr()))
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
},
|
||||
Some(MainAddressSelector::Ip(address)) => /*Some(*address)*/ {
|
||||
for alloc in pool {
|
||||
if alloc.addresses.iter().any(|addr| addr.addr() == *address) {
|
||||
return Some(AssignedAddress::new(alloc.interface.to_string(), *address))
|
||||
}
|
||||
}
|
||||
None
|
||||
},
|
||||
Some(MainAddressSelector::Network(network)) => {
|
||||
for alloc in pool {
|
||||
match alloc.network.as_ref() {
|
||||
Some(_network) if network == _network => {
|
||||
match alloc.addresses.first() {
|
||||
None => continue,
|
||||
Some(addr) =>
|
||||
return Some(AssignedAddress::new(alloc.interface.to_string(), addr.addr()))
|
||||
}
|
||||
},
|
||||
_ => continue
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MainAddressSelector {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
||||
@@ -460,6 +460,8 @@ impl InstantiateBlueprint {
|
||||
|
||||
let devfs_ruleset_id = devfs_store.get_ruleset_id(&devfs_rules);
|
||||
|
||||
envs.insert("XC_DEVFS_RULESET".to_string(), devfs_ruleset_id.to_string());
|
||||
|
||||
let main = match &request.request.entry_point {
|
||||
Some(spec) => {
|
||||
let args = {
|
||||
|
||||
@@ -448,6 +448,7 @@ impl Site {
|
||||
jailed_datasets: blueprint.jailed_datasets,
|
||||
children_max: blueprint.children_max,
|
||||
main_ip_selector: blueprint.main_ip_selector,
|
||||
envs: blueprint.envs,
|
||||
};
|
||||
|
||||
for iface in blueprint.created_interfaces.iter() {
|
||||
|
||||
Reference in New Issue
Block a user