Skip to content

Commit

Permalink
expose network configuration as envs to containers
Browse files Browse the repository at this point in the history
  • Loading branch information
elliptic committed Feb 13, 2024
1 parent 4b7999f commit fbbe26a
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 34 deletions.
18 changes: 17 additions & 1 deletion xc/src/container/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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>,
Expand All @@ -108,6 +121,8 @@ pub struct CreateContainer {
pub children_max: u32,

pub main_ip_selector: Option<MainAddressSelector>,

pub envs: HashMap<String, String>,
}

impl CreateContainer {
Expand Down Expand Up @@ -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
})
}
}
Expand Down
44 changes: 41 additions & 3 deletions xc/src/container/runner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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);
Expand Down
60 changes: 30 additions & 30 deletions xc/src/container/running.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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),
}
}
}
54 changes: 54 additions & 0 deletions xc/src/models/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions xcd/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
1 change: 1 addition & 0 deletions xcd/src/site.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit fbbe26a

Please sign in to comment.