use crate::core::types::Resource;
pub fn check_script(resource: &Resource) -> String {
let name = resource.name.as_deref().unwrap_or("unknown");
let mut checks = vec!["set -euo pipefail".to_string()];
if resource.cpuset.is_some() || resource.memory_limit.is_some() {
checks.push(format!(
"if [ -d '/sys/fs/cgroup/forjar-{name}' ]; then echo 'cgroup:present:{name}'; else echo 'cgroup:absent:{name}'; fi"
));
}
if let Some(ref chroot) = resource.chroot_dir {
checks.push(format!(
"if [ -d '{chroot}' ]; then echo 'chroot:present:{name}'; else echo 'chroot:absent:{name}'; fi"
));
}
if let Some(ref merged) = resource.overlay_merged {
checks.push(format!(
"if mountpoint -q '{merged}' 2>/dev/null; then echo 'overlay:mounted:{name}'; else echo 'overlay:unmounted:{name}'; fi"
));
}
if resource.netns {
checks.push(format!(
"if ip netns list 2>/dev/null | grep -q 'forjar-{name}'; then echo 'netns:present:{name}'; else echo 'netns:absent:{name}'; fi"
));
}
if checks.len() == 1 {
checks.push(format!("echo 'pepita:{name}:unconfigured'"));
}
checks.join("\n")
}
pub fn apply_script(resource: &Resource) -> String {
let name = resource.name.as_deref().unwrap_or("unknown");
let state = resource.state.as_deref().unwrap_or("present");
match state {
"absent" => apply_absent(name, resource),
_ => apply_present(name, resource),
}
}
fn apply_absent(name: &str, resource: &Resource) -> String {
let mut lines = vec!["set -euo pipefail".to_string()];
if let Some(ref merged) = resource.overlay_merged {
lines.push(format!("umount '{merged}' 2>/dev/null || true"));
}
if resource.netns {
lines.push(format!("ip netns del 'forjar-{name}' 2>/dev/null || true"));
}
if resource.cpuset.is_some() || resource.memory_limit.is_some() {
lines.push(format!(
"rmdir '/sys/fs/cgroup/forjar-{name}' 2>/dev/null || true"
));
}
if let Some(ref chroot) = resource.chroot_dir {
lines.push(format!("if [ -d '{chroot}' ]; then rm -rf '{chroot}'; fi"));
}
lines.join("\n")
}
fn apply_present(name: &str, resource: &Resource) -> String {
let mut lines = vec!["set -euo pipefail".to_string()];
if let Some(ref chroot) = resource.chroot_dir {
lines.push(format!("mkdir -p '{chroot}'"));
}
if resource.cpuset.is_some() || resource.memory_limit.is_some() {
let cgroup_path = format!("/sys/fs/cgroup/forjar-{name}");
lines.push(format!("mkdir -p '{cgroup_path}'"));
if let Some(limit) = resource.memory_limit {
lines.push(format!("echo '{limit}' > '{cgroup_path}/memory.max'"));
}
if let Some(ref cpuset) = resource.cpuset {
lines.push(format!("echo '{cpuset}' > '{cgroup_path}/cpuset.cpus'"));
}
}
if let Some(ref merged) = resource.overlay_merged {
let lower = resource.overlay_lower.as_deref().unwrap_or("/");
let upper = resource
.overlay_upper
.as_deref()
.unwrap_or("/tmp/forjar-upper");
let work = resource
.overlay_work
.as_deref()
.unwrap_or("/tmp/forjar-work");
lines.push(format!("mkdir -p '{lower}' '{upper}' '{work}' '{merged}'"));
lines.push(format!(
"mount -t overlay overlay -o lowerdir='{lower}',upperdir='{upper}',workdir='{work}' '{merged}'"
));
}
if resource.netns {
let ns_name = format!("forjar-{name}");
lines.push(format!("ip netns add '{ns_name}' 2>/dev/null || true"));
lines.push(format!("ip netns exec '{ns_name}' ip link set lo up"));
}
if resource.seccomp {
lines.push(format!(
"echo 'seccomp:enabled' # Seccomp filtering active for forjar-{name}"
));
}
lines.join("\n")
}
pub fn state_query_script(resource: &Resource) -> String {
let name = resource.name.as_deref().unwrap_or("unknown");
let mut queries = vec!["set -euo pipefail".to_string()];
if resource.cpuset.is_some() || resource.memory_limit.is_some() {
let cgroup_path = format!("/sys/fs/cgroup/forjar-{name}");
queries.push(format!(
"cat '{cgroup_path}/memory.max' 2>/dev/null && echo 'cgroup={name}' || echo 'cgroup=MISSING:{name}'"
));
}
if let Some(ref merged) = resource.overlay_merged {
queries.push(format!(
"mountpoint -q '{merged}' 2>/dev/null && echo 'overlay={name}' || echo 'overlay=MISSING:{name}'"
));
}
if resource.netns {
queries.push(format!(
"ip netns list 2>/dev/null | grep -q 'forjar-{name}' && echo 'netns={name}' || echo 'netns=MISSING:{name}'"
));
}
if let Some(ref chroot) = resource.chroot_dir {
queries.push(format!(
"[ -d '{chroot}' ] && echo 'chroot={name}' || echo 'chroot=MISSING:{name}'"
));
}
if queries.len() == 1 {
queries.push(format!("echo 'pepita={name}:unconfigured'"));
}
queries.join("\n")
}
#[cfg(test)]
mod tests;