use std::collections::HashMap;
use super::{
global::{Defaults, NpxcConfig},
package::{MountConfig, PackageConfig, StorageConfig},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NetworkPolicy {
None,
Named(String),
Allowlist { allow: Vec<String> },
}
impl std::fmt::Display for NetworkPolicy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NetworkPolicy::None => write!(f, "none"),
NetworkPolicy::Named(name) => write!(f, "{name}"),
NetworkPolicy::Allowlist { allow } => {
write!(f, "allowlist ({} rule(s))", allow.len())
}
}
}
}
#[derive(Debug, Clone)]
pub struct EffectiveConfig {
pub node_image: String,
pub container_cli: String,
pub network: NetworkPolicy,
pub memory: String,
pub cpus: String,
pub mount_mode: String,
pub log_level: String,
pub strategies: Vec<String>,
pub heuristic_absolute_prefix: bool,
pub heuristic_home_prefix: bool,
pub heuristic_uri_prefix: Vec<String>,
pub version: Option<String>,
pub path_arguments: HashMap<String, Vec<String>>,
pub non_path_arguments: HashMap<String, Vec<String>>,
pub env: HashMap<String, String>,
pub env_passthrough: Vec<String>,
pub storage: Option<StorageConfig>,
pub mounts: Vec<MountConfig>,
}
#[must_use]
pub fn merge(global: &NpxcConfig, pkg: Option<&PackageConfig>) -> EffectiveConfig {
let d = &global.defaults;
let p = &global.paths;
let (memory, cpus) = match pkg.and_then(|c| c.runtime.as_ref()) {
Some(rt) => (
rt.memory.clone().unwrap_or_else(|| d.memory.clone()),
rt.cpus.clone().unwrap_or_else(|| d.cpus.clone()),
),
None => (d.memory.clone(), d.cpus.clone()),
};
let network = resolve_network_policy(pkg, d);
let (version, path_arguments, non_path_arguments, env, env_passthrough, storage, mounts) =
match pkg {
Some(c) => (
c.version.clone(),
c.path_arguments.clone(),
c.non_path_arguments.clone(),
c.env.clone(),
c.env_passthrough.clone(),
c.storage.clone(),
c.mounts.clone(),
),
None => (
None,
HashMap::new(),
HashMap::new(),
HashMap::new(),
Vec::new(),
None,
Vec::new(),
),
};
EffectiveConfig {
node_image: d.node_image.clone(),
container_cli: d.container_cli.clone(),
network,
memory,
cpus,
mount_mode: d.mount_mode.clone(),
log_level: d.log_level.clone(),
strategies: p.strategies.clone(),
heuristic_absolute_prefix: p.heuristic.absolute_prefix,
heuristic_home_prefix: p.heuristic.home_prefix,
heuristic_uri_prefix: p.heuristic.uri_prefix.clone(),
version,
path_arguments,
non_path_arguments,
env,
env_passthrough,
storage,
mounts,
}
}
fn resolve_network_policy(pkg: Option<&PackageConfig>, d: &Defaults) -> NetworkPolicy {
if let Some(nc) = pkg.and_then(|c| c.network.as_ref()) {
return match nc.mode.as_str() {
"allowlist" => NetworkPolicy::Allowlist {
allow: nc.allow.clone(),
},
"open" => NetworkPolicy::Named("default".to_string()),
"none" => NetworkPolicy::None,
other => NetworkPolicy::Named(other.to_string()),
};
}
let legacy = pkg
.and_then(|c| c.runtime.as_ref())
.and_then(|r| r.network.clone())
.unwrap_or_else(|| d.network.clone());
match legacy.as_str() {
"none" => NetworkPolicy::None,
other => NetworkPolicy::Named(other.to_string()),
}
}