Bound and configure the per-Domain runsc dcache
This commit is contained in:
parent
503f090121
commit
db9a561d0c
13 changed files with 157 additions and 11 deletions
|
|
@ -10,8 +10,8 @@ use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
use crate::identity::{ConfigurationFingerprint, DeviceId, DomainId, HostPath, InodeId, MountId};
|
use crate::identity::{ConfigurationFingerprint, DeviceId, DomainId, HostPath, InodeId, MountId};
|
||||||
use crate::records::{
|
use crate::records::{
|
||||||
ConfigurationFingerprintRecordV1, MailboxRequest, ResolvedAutoApprovalRule, ResolvedVolume,
|
ConfigurationFingerprintRecordV1, MAX_RUNSC_DCACHE, MailboxRequest, ResolvedAutoApprovalRule,
|
||||||
TRUSTED_HOST_CONFIGURATION_SCHEMA_ID, TrustedHostConfigurationV1, VolumeKind,
|
ResolvedVolume, TRUSTED_HOST_CONFIGURATION_SCHEMA_ID, TrustedHostConfigurationV1, VolumeKind,
|
||||||
};
|
};
|
||||||
use confined_io::{io_error, open_absolute_directory, validate_executable};
|
use confined_io::{io_error, open_absolute_directory, validate_executable};
|
||||||
use validation::validate_sandbox_path;
|
use validation::validate_sandbox_path;
|
||||||
|
|
@ -27,6 +27,7 @@ pub enum ConfigurationErrorKind {
|
||||||
InvalidProfile,
|
InvalidProfile,
|
||||||
InvalidPath,
|
InvalidPath,
|
||||||
PathConflict,
|
PathConflict,
|
||||||
|
InvalidRuntime,
|
||||||
InvalidNetwork,
|
InvalidNetwork,
|
||||||
MissingEnvironment,
|
MissingEnvironment,
|
||||||
InvalidVolume,
|
InvalidVolume,
|
||||||
|
|
@ -72,6 +73,7 @@ const fn error_label(kind: ConfigurationErrorKind) -> &'static str {
|
||||||
ConfigurationErrorKind::InvalidProfile => "invalid profile",
|
ConfigurationErrorKind::InvalidProfile => "invalid profile",
|
||||||
ConfigurationErrorKind::InvalidPath => "invalid path",
|
ConfigurationErrorKind::InvalidPath => "invalid path",
|
||||||
ConfigurationErrorKind::PathConflict => "path conflict",
|
ConfigurationErrorKind::PathConflict => "path conflict",
|
||||||
|
ConfigurationErrorKind::InvalidRuntime => "invalid runtime configuration",
|
||||||
ConfigurationErrorKind::InvalidNetwork => "invalid network policy",
|
ConfigurationErrorKind::InvalidNetwork => "invalid network policy",
|
||||||
ConfigurationErrorKind::MissingEnvironment => "invalid environment reference",
|
ConfigurationErrorKind::MissingEnvironment => "invalid environment reference",
|
||||||
ConfigurationErrorKind::InvalidVolume => "invalid volume",
|
ConfigurationErrorKind::InvalidVolume => "invalid volume",
|
||||||
|
|
@ -679,6 +681,11 @@ impl ResolvedDomainConfiguration {
|
||||||
&self.fingerprint_record
|
&self.fingerprint_record
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn runsc_dcache(&self) -> u32 {
|
||||||
|
self.fingerprint_record.runsc_dcache
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn effective_allow_prefixes(&self) -> &[Ipv4Prefix] {
|
pub fn effective_allow_prefixes(&self) -> &[Ipv4Prefix] {
|
||||||
&self.effective_allow_prefixes
|
&self.effective_allow_prefixes
|
||||||
|
|
|
||||||
|
|
@ -343,6 +343,7 @@ pub fn load_trusted_configuration(
|
||||||
selected_profile: request.selected_profile.clone(),
|
selected_profile: request.selected_profile.clone(),
|
||||||
storage_root: host_path(&storage_canonical),
|
storage_root: host_path(&storage_canonical),
|
||||||
runtime_root: host_path(&runtime_canonical),
|
runtime_root: host_path(&runtime_canonical),
|
||||||
|
runsc_dcache: configuration.runtime().runsc_dcache,
|
||||||
image: selected.image.clone(),
|
image: selected.image.clone(),
|
||||||
isolate_gitignored: selected.isolate_gitignored,
|
isolate_gitignored: selected.isolate_gitignored,
|
||||||
persistent_dirs,
|
persistent_dirs,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use super::confined_io::{
|
||||||
};
|
};
|
||||||
use super::{
|
use super::{
|
||||||
ConfigurationError, ConfigurationErrorKind, ConfigurationFingerprint,
|
ConfigurationError, ConfigurationErrorKind, ConfigurationFingerprint,
|
||||||
ConfigurationFingerprintRecordV1, Digest, DomainId, Sha256,
|
ConfigurationFingerprintRecordV1, Digest, DomainId, MAX_RUNSC_DCACHE, Sha256,
|
||||||
TRUSTED_HOST_CONFIGURATION_SCHEMA_ID, TrustedHostConfigurationV1,
|
TRUSTED_HOST_CONFIGURATION_SCHEMA_ID, TrustedHostConfigurationV1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -33,6 +33,7 @@ pub fn derive_configuration_fingerprint(
|
||||||
push_bytes(&mut preimage, record.selected_profile.as_bytes())?;
|
push_bytes(&mut preimage, record.selected_profile.as_bytes())?;
|
||||||
push_bytes(&mut preimage, record.storage_root.as_bytes())?;
|
push_bytes(&mut preimage, record.storage_root.as_bytes())?;
|
||||||
push_bytes(&mut preimage, record.runtime_root.as_bytes())?;
|
push_bytes(&mut preimage, record.runtime_root.as_bytes())?;
|
||||||
|
preimage.extend_from_slice(&record.runsc_dcache.to_be_bytes());
|
||||||
push_bytes(&mut preimage, record.image.as_bytes())?;
|
push_bytes(&mut preimage, record.image.as_bytes())?;
|
||||||
push_bool(&mut preimage, record.isolate_gitignored);
|
push_bool(&mut preimage, record.isolate_gitignored);
|
||||||
|
|
||||||
|
|
@ -87,6 +88,12 @@ pub(super) fn validate_structural_configuration(
|
||||||
"unknown configuration schema",
|
"unknown configuration schema",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if configuration.runtime().runsc_dcache > MAX_RUNSC_DCACHE {
|
||||||
|
return Err(ConfigurationError::new(
|
||||||
|
ConfigurationErrorKind::InvalidRuntime,
|
||||||
|
format!("runsc_dcache exceeds {MAX_RUNSC_DCACHE} entries"),
|
||||||
|
));
|
||||||
|
}
|
||||||
for (name, profile) in configuration.profiles() {
|
for (name, profile) in configuration.profiles() {
|
||||||
validate_profile_name(name)?;
|
validate_profile_name(name)?;
|
||||||
validate_text(&profile.image, "profile image")?;
|
validate_text(&profile.image, "profile image")?;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ pub const DOMAIN_STORE_SCHEMA_VERSION: u32 = 1;
|
||||||
pub const STORAGE_CATALOG_SCHEMA_VERSION: u32 = 1;
|
pub const STORAGE_CATALOG_SCHEMA_VERSION: u32 = 1;
|
||||||
pub const TRUSTED_HOST_CONFIGURATION_SCHEMA_ID: &str = "lazaret-trusted-host-config-v1";
|
pub const TRUSTED_HOST_CONFIGURATION_SCHEMA_ID: &str = "lazaret-trusted-host-config-v1";
|
||||||
pub const DEFAULT_PERSISTENT_DIRS: [&str; 5] = ["/root", "/usr", "/var", "/etc", "/opt"];
|
pub const DEFAULT_PERSISTENT_DIRS: [&str; 5] = ["/root", "/usr", "/var", "/etc", "/opt"];
|
||||||
|
pub const DEFAULT_RUNSC_DCACHE: u32 = 50_000;
|
||||||
|
pub const MAX_RUNSC_DCACHE: u32 = 262_144;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
|
|
@ -23,6 +25,25 @@ pub struct NetworkConfigurationV1 {
|
||||||
pub default_deny: Vec<String>,
|
pub default_deny: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct RuntimeConfigurationV1 {
|
||||||
|
#[serde(default = "default_runsc_dcache")]
|
||||||
|
pub runsc_dcache: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RuntimeConfigurationV1 {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
runsc_dcache: DEFAULT_RUNSC_DCACHE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn default_runsc_dcache() -> u32 {
|
||||||
|
DEFAULT_RUNSC_DCACHE
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub enum VolumeKind {
|
pub enum VolumeKind {
|
||||||
|
|
@ -103,6 +124,7 @@ pub struct TrustedHostConfigurationV1 {
|
||||||
schema_id: String,
|
schema_id: String,
|
||||||
storage: StorageConfigurationV1,
|
storage: StorageConfigurationV1,
|
||||||
network: NetworkConfigurationV1,
|
network: NetworkConfigurationV1,
|
||||||
|
runtime: RuntimeConfigurationV1,
|
||||||
profiles: BTreeMap<String, ProfileConfigurationV1>,
|
profiles: BTreeMap<String, ProfileConfigurationV1>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,6 +144,11 @@ impl TrustedHostConfigurationV1 {
|
||||||
&self.network
|
&self.network
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn runtime(&self) -> &RuntimeConfigurationV1 {
|
||||||
|
&self.runtime
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn profiles(&self) -> &BTreeMap<String, ProfileConfigurationV1> {
|
pub const fn profiles(&self) -> &BTreeMap<String, ProfileConfigurationV1> {
|
||||||
&self.profiles
|
&self.profiles
|
||||||
|
|
@ -142,6 +169,8 @@ impl<'de> Deserialize<'de> for TrustedHostConfigurationV1 {
|
||||||
storage: StorageConfigurationV1,
|
storage: StorageConfigurationV1,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
network: NetworkConfigurationV1,
|
network: NetworkConfigurationV1,
|
||||||
|
#[serde(default)]
|
||||||
|
runtime: RuntimeConfigurationV1,
|
||||||
profiles: BTreeMap<String, ProfileConfigurationV1>,
|
profiles: BTreeMap<String, ProfileConfigurationV1>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,6 +189,7 @@ impl<'de> Deserialize<'de> for TrustedHostConfigurationV1 {
|
||||||
schema_id: fields.schema_id,
|
schema_id: fields.schema_id,
|
||||||
storage: fields.storage,
|
storage: fields.storage,
|
||||||
network: fields.network,
|
network: fields.network,
|
||||||
|
runtime: fields.runtime,
|
||||||
profiles: fields.profiles,
|
profiles: fields.profiles,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -192,6 +222,7 @@ pub struct ConfigurationFingerprintRecordV1 {
|
||||||
pub selected_profile: String,
|
pub selected_profile: String,
|
||||||
pub storage_root: HostPath,
|
pub storage_root: HostPath,
|
||||||
pub runtime_root: HostPath,
|
pub runtime_root: HostPath,
|
||||||
|
pub runsc_dcache: u32,
|
||||||
pub image: String,
|
pub image: String,
|
||||||
pub isolate_gitignored: bool,
|
pub isolate_gitignored: bool,
|
||||||
pub persistent_dirs: Vec<String>,
|
pub persistent_dirs: Vec<String>,
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ use lazaret_core::configuration::{
|
||||||
};
|
};
|
||||||
use lazaret_core::identity::HostPath;
|
use lazaret_core::identity::HostPath;
|
||||||
use lazaret_core::records::{
|
use lazaret_core::records::{
|
||||||
ConfigurationFingerprintRecordV1, EnvironmentReference, ResolvedAutoApprovalRule,
|
ConfigurationFingerprintRecordV1, DEFAULT_RUNSC_DCACHE, EnvironmentReference, MAX_RUNSC_DCACHE,
|
||||||
ResolvedVolume, VolumeAccess, VolumeKind,
|
ResolvedAutoApprovalRule, ResolvedVolume, VolumeAccess, VolumeKind,
|
||||||
};
|
};
|
||||||
use static_assertions::assert_not_impl_any;
|
use static_assertions::assert_not_impl_any;
|
||||||
|
|
||||||
|
|
@ -150,6 +150,7 @@ image = "example.invalid/agent:v1"
|
||||||
assert!(parsed.storage().data_root.is_none());
|
assert!(parsed.storage().data_root.is_none());
|
||||||
assert!(parsed.network().default_allow.is_empty());
|
assert!(parsed.network().default_allow.is_empty());
|
||||||
assert!(parsed.network().default_deny.is_empty());
|
assert!(parsed.network().default_deny.is_empty());
|
||||||
|
assert_eq!(parsed.runtime().runsc_dcache, DEFAULT_RUNSC_DCACHE);
|
||||||
|
|
||||||
for (value, expected) in [
|
for (value, expected) in [
|
||||||
("[]", Vec::<String>::new()),
|
("[]", Vec::<String>::new()),
|
||||||
|
|
@ -212,6 +213,47 @@ volumes = [{ host = "/source", container = "/root/source", kind = "socket" }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn runtime_dcache_defaults_accepts_budget_bounds_and_rejects_excess() {
|
||||||
|
let minimal = r#"schema = "lazaret-trusted-host-config-v1"
|
||||||
|
[profiles.default]
|
||||||
|
image = "example.invalid/agent:v1"
|
||||||
|
"#;
|
||||||
|
assert_eq!(
|
||||||
|
parse_trusted_configuration(minimal.as_bytes())
|
||||||
|
.unwrap()
|
||||||
|
.runtime()
|
||||||
|
.runsc_dcache,
|
||||||
|
DEFAULT_RUNSC_DCACHE
|
||||||
|
);
|
||||||
|
for value in [0, MAX_RUNSC_DCACHE] {
|
||||||
|
let explicit = minimal.replace(
|
||||||
|
"[profiles.default]",
|
||||||
|
&format!("[runtime]\nrunsc_dcache = {value}\n[profiles.default]"),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_trusted_configuration(explicit.as_bytes())
|
||||||
|
.unwrap()
|
||||||
|
.runtime()
|
||||||
|
.runsc_dcache,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let excessive = minimal.replace(
|
||||||
|
"[profiles.default]",
|
||||||
|
&format!(
|
||||||
|
"[runtime]\nrunsc_dcache = {}\n[profiles.default]",
|
||||||
|
MAX_RUNSC_DCACHE + 1
|
||||||
|
),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_trusted_configuration(excessive.as_bytes())
|
||||||
|
.unwrap_err()
|
||||||
|
.kind(),
|
||||||
|
ConfigurationErrorKind::InvalidRuntime
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sandbox_layout_is_closed_normalized_and_requires_workspace() {
|
fn sandbox_layout_is_closed_normalized_and_requires_workspace() {
|
||||||
assert!(SandboxLayoutV1::from_protected_destinations(["/proc".into()]).is_err());
|
assert!(SandboxLayoutV1::from_protected_destinations(["/proc".into()]).is_err());
|
||||||
|
|
@ -834,6 +876,7 @@ fn digest_vectors_are_framed_and_order_independent() {
|
||||||
selected_profile: "default".into(),
|
selected_profile: "default".into(),
|
||||||
storage_root: HostPath::new(b"/data".to_vec()),
|
storage_root: HostPath::new(b"/data".to_vec()),
|
||||||
runtime_root: HostPath::new(b"/run/user/1000/lazaret".to_vec()),
|
runtime_root: HostPath::new(b"/run/user/1000/lazaret".to_vec()),
|
||||||
|
runsc_dcache: DEFAULT_RUNSC_DCACHE,
|
||||||
image: "example.invalid/agent:v1".into(),
|
image: "example.invalid/agent:v1".into(),
|
||||||
isolate_gitignored: true,
|
isolate_gitignored: true,
|
||||||
persistent_dirs: vec!["/var".into(), "/root".into()],
|
persistent_dirs: vec!["/var".into(), "/root".into()],
|
||||||
|
|
@ -867,9 +910,9 @@ fn digest_vectors_are_framed_and_order_independent() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
first.as_bytes(),
|
first.as_bytes(),
|
||||||
&[
|
&[
|
||||||
0xd3, 0xba, 0xef, 0x91, 0x21, 0x0f, 0x98, 0x31, 0x6c, 0xea, 0x34, 0xfb, 0x41, 0xbd,
|
0x5f, 0x1d, 0xeb, 0x46, 0xa4, 0xb5, 0x90, 0xc3, 0x47, 0x0b, 0xa0, 0xdf, 0xd6, 0x6e,
|
||||||
0x6c, 0xa5, 0x07, 0xf0, 0xb8, 0x9b, 0x90, 0x77, 0xaf, 0x0a, 0x0e, 0xd0, 0x6a, 0xd6,
|
0x9d, 0x91, 0xdb, 0xf3, 0x75, 0xf6, 0xbe, 0x50, 0x9a, 0x8d, 0xba, 0x4a, 0x3d, 0xae,
|
||||||
0x46, 0xc7, 0x2d, 0xbf,
|
0xf3, 0x05, 0x97, 0x56,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
record.persistent_dirs.reverse();
|
record.persistent_dirs.reverse();
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,7 @@ struct RawTrustedHostConfigurationV1 {
|
||||||
schema_id: String,
|
schema_id: String,
|
||||||
storage: StorageConfigurationV1,
|
storage: StorageConfigurationV1,
|
||||||
network: NetworkConfigurationV1,
|
network: NetworkConfigurationV1,
|
||||||
|
runtime: RuntimeConfigurationV1,
|
||||||
profiles: BTreeMap<String, ProfileConfigurationV1>,
|
profiles: BTreeMap<String, ProfileConfigurationV1>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,7 @@ fn trusted_host_configuration_postcard_dispatch_rejects_unknown_schema() {
|
||||||
schema_id: schema_id.into(),
|
schema_id: schema_id.into(),
|
||||||
storage: StorageConfigurationV1::default(),
|
storage: StorageConfigurationV1::default(),
|
||||||
network: NetworkConfigurationV1::default(),
|
network: NetworkConfigurationV1::default(),
|
||||||
|
runtime: RuntimeConfigurationV1::default(),
|
||||||
profiles: profiles.clone(),
|
profiles: profiles.clone(),
|
||||||
};
|
};
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
|
|
|
||||||
|
|
@ -569,6 +569,7 @@ persistent_dirs = []
|
||||||
selected_profile: "trusted".into(),
|
selected_profile: "trusted".into(),
|
||||||
storage_root: HostPath::new(b"/data/lazaret".to_vec()),
|
storage_root: HostPath::new(b"/data/lazaret".to_vec()),
|
||||||
runtime_root: HostPath::new(b"/run/user/1000/lazaret".to_vec()),
|
runtime_root: HostPath::new(b"/run/user/1000/lazaret".to_vec()),
|
||||||
|
runsc_dcache: DEFAULT_RUNSC_DCACHE,
|
||||||
image: "example.invalid/agent:v1".into(),
|
image: "example.invalid/agent:v1".into(),
|
||||||
isolate_gitignored: true,
|
isolate_gitignored: true,
|
||||||
persistent_dirs: vec!["/root".into()],
|
persistent_dirs: vec!["/root".into()],
|
||||||
|
|
@ -641,8 +642,8 @@ persistent_dirs = []
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
seen.digest(),
|
seen.digest(),
|
||||||
[
|
[
|
||||||
245, 169, 157, 164, 67, 211, 165, 23, 129, 62, 119, 92, 247, 248, 131, 4, 252, 42, 34,
|
23, 80, 80, 177, 148, 141, 234, 213, 240, 108, 167, 148, 252, 121, 212, 128, 5, 195,
|
||||||
214, 207, 60, 126, 219, 81, 68, 159, 6, 26, 88, 233, 108,
|
176, 126, 71, 76, 141, 196, 174, 125, 212, 31, 115, 155, 178, 139,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -693,7 +693,11 @@ fn build_sandbox_bundle_from_source(
|
||||||
.map_err(oci_error)?;
|
.map_err(oci_error)?;
|
||||||
let specification_json = canonical_specification_json(&specification)?;
|
let specification_json = canonical_specification_json(&specification)?;
|
||||||
let bundle_authorization = Sha256::digest(&specification_json).into();
|
let bundle_authorization = Sha256::digest(&specification_json).into();
|
||||||
let command = build_runsc_command(&paths, bundle_authorization);
|
let command = build_runsc_command(
|
||||||
|
&paths,
|
||||||
|
request.configuration.runsc_dcache(),
|
||||||
|
bundle_authorization,
|
||||||
|
);
|
||||||
let runtime_sources =
|
let runtime_sources =
|
||||||
handoff_runtime_sources(&paths, request.terminal.as_ref(), &specification_json);
|
handoff_runtime_sources(&paths, request.terminal.as_ref(), &specification_json);
|
||||||
Ok(SandboxBundle {
|
Ok(SandboxBundle {
|
||||||
|
|
|
||||||
|
|
@ -278,6 +278,7 @@ pub(super) fn build_linux() -> Result<oci_spec::runtime::Linux, SandboxBuildErro
|
||||||
|
|
||||||
pub(super) fn build_runsc_command(
|
pub(super) fn build_runsc_command(
|
||||||
paths: &RuntimePaths,
|
paths: &RuntimePaths,
|
||||||
|
dcache: u32,
|
||||||
bundle_authorization: [u8; 32],
|
bundle_authorization: [u8; 32],
|
||||||
) -> RunscCommand {
|
) -> RunscCommand {
|
||||||
RunscCommand::new(
|
RunscCommand::new(
|
||||||
|
|
@ -292,6 +293,7 @@ pub(super) fn build_runsc_command(
|
||||||
)),
|
)),
|
||||||
OsString::from("-network=host"),
|
OsString::from("-network=host"),
|
||||||
OsString::from("-ignore-cgroups"),
|
OsString::from("-ignore-cgroups"),
|
||||||
|
OsString::from(format!("-dcache={dcache}")),
|
||||||
OsString::from(format!(
|
OsString::from(format!(
|
||||||
"-overlay2=root:dir={}",
|
"-overlay2=root:dir={}",
|
||||||
paths
|
paths
|
||||||
|
|
|
||||||
|
|
@ -373,6 +373,7 @@ fn assert_runtime_command(bundle: &SandboxBundle, fixture: &Fixture) {
|
||||||
format!("-root={runtime_domain}/runsc"),
|
format!("-root={runtime_domain}/runsc"),
|
||||||
"-network=host".to_owned(),
|
"-network=host".to_owned(),
|
||||||
"-ignore-cgroups".to_owned(),
|
"-ignore-cgroups".to_owned(),
|
||||||
|
"-dcache=50000".to_owned(),
|
||||||
format!(
|
format!(
|
||||||
"-overlay2=root:dir={runtime_domain}/runsc-overlay/{}",
|
"-overlay2=root:dir={runtime_domain}/runsc-overlay/{}",
|
||||||
"11".repeat(32)
|
"11".repeat(32)
|
||||||
|
|
@ -402,6 +403,39 @@ fn assert_runtime_command(bundle: &SandboxBundle, fixture: &Fixture) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn configured_dcache_is_fingerprinted_and_passed_to_runsc() {
|
||||||
|
let fixture = Fixture::new();
|
||||||
|
let configuration_path = fixture.tree.path().join("configuration/lazaret.toml");
|
||||||
|
let source = fs::read_to_string(&configuration_path).unwrap();
|
||||||
|
fs::write(
|
||||||
|
&configuration_path,
|
||||||
|
source.replace("[network]", "[runtime]\nrunsc_dcache = 12345\n\n[network]"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let configuration = fixture.reload_configuration();
|
||||||
|
assert_eq!(configuration.runsc_dcache(), 12_345);
|
||||||
|
assert_ne!(
|
||||||
|
configuration.configuration_fingerprint(),
|
||||||
|
fixture.configuration.configuration_fingerprint()
|
||||||
|
);
|
||||||
|
let bundle = build_sandbox_bundle(SandboxBuildRequest {
|
||||||
|
configuration: &configuration,
|
||||||
|
container_id: ContainerId::new([0x11; 32]),
|
||||||
|
expected_network_namespace: current_network_namespace(),
|
||||||
|
root_process: root_process([]),
|
||||||
|
terminal: None,
|
||||||
|
prepared_root: fixture.tree.path().join("prepared-root"),
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
assert!(
|
||||||
|
bundle
|
||||||
|
.command()
|
||||||
|
.arguments()
|
||||||
|
.contains(&"-dcache=12345".into())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn product_init_role_has_exact_terminal_neutral_rootless_bundle_shape() {
|
fn product_init_role_has_exact_terminal_neutral_rootless_bundle_shape() {
|
||||||
let fixture = Fixture::new();
|
let fixture = Fixture::new();
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@ data_root = "~/.local/share/lazaret"
|
||||||
[network]
|
[network]
|
||||||
default_allow = ["192.0.2.53/32", "198.51.100.53/32"]
|
default_allow = ["192.0.2.53/32", "198.51.100.53/32"]
|
||||||
|
|
||||||
|
[runtime]
|
||||||
|
runsc_dcache = 50000
|
||||||
|
|
||||||
[profiles.default]
|
[profiles.default]
|
||||||
image = "docker.io/library/debian:trixie"
|
image = "docker.io/library/debian:trixie"
|
||||||
isolate_gitignored = true
|
isolate_gitignored = true
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,17 @@ An omitted profile `persistent_dirs` field selects `/root`, `/usr`, `/var`,
|
||||||
`/etc`, and `/opt`. An explicit list replaces that default in full, including an
|
`/etc`, and `/opt`. An explicit list replaces that default in full, including an
|
||||||
empty list or paths used by an unorthodox distribution.
|
empty list or paths used by an unorthodox distribution.
|
||||||
|
|
||||||
|
The optional `runtime.runsc_dcache` field sets the maximum number of
|
||||||
|
zero-reference dentries retained by the global runsc gofer-client cache in each
|
||||||
|
Domain sandbox. It defaults to 50,000 and accepts values from 0 through 262,144
|
||||||
|
inclusive; zero disables zero-reference dentry retention. The maximum keeps the
|
||||||
|
cache-entry ceiling at half of the 524,288 per-process descriptor budget,
|
||||||
|
leaving nominal headroom for referenced files and non-cache activity.
|
||||||
|
Configured capacity is allocated on demand, while populated capacity consumes
|
||||||
|
Domain-local sentry and routed-workspace descriptors and memory. Concurrent
|
||||||
|
Domains have independent caches and their host resource consumption is
|
||||||
|
additive.
|
||||||
|
|
||||||
The loader resolves environment references only after structural, path, and
|
The loader resolves environment references only after structural, path, and
|
||||||
network validation. A missing, non-UTF-8, or NUL-containing host value refuses
|
network validation. A missing, non-UTF-8, or NUL-containing host value refuses
|
||||||
the selected profile. Resolved values live only in one move-owned,
|
the selected profile. Resolved values live only in one move-owned,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue