use std::path::PathBuf;
pub const IMAGE_EXEC: &str = "/usr/local/bin/bifrost";
pub const K8S_STATE_DIR: &str = "/var/lib/bifrost";
fn home() -> PathBuf {
std::env::var_os("HOME").map(PathBuf::from).unwrap_or_else(|| PathBuf::from("/"))
}
pub fn installed_state_dir(name: &str, system: bool) -> PathBuf {
if system {
PathBuf::from("/var/lib").join(name)
} else {
home().join(".local/state").join(name)
}
}
pub fn env_file_path(name: &str, system: bool) -> PathBuf {
if system {
PathBuf::from("/etc").join(name).join(format!("{name}.env"))
} else {
home().join(".config/systemd/user").join(format!("{name}.env"))
}
}
pub fn systemd_spec(lc: &skidbladnir::service::Lifecycle, name: &str, system: bool) -> skidbladnir::systemd::SystemdServiceSpec {
let spec = lc.systemd_spec();
if spec.has_secrets() {
spec.with_env_file(env_file_path(name, system).to_string_lossy())
} else {
spec
}
}
fn scope(system: bool) -> skidbladnir::systemd::Scope {
if system { skidbladnir::systemd::Scope::System } else { skidbladnir::systemd::Scope::User }
}
pub fn unit_text(lc: &skidbladnir::service::Lifecycle, name: &str, system: bool) -> String {
skidbladnir::systemd::systemd_unit_scoped(&systemd_spec(lc, name, system), scope(system))
}
pub fn install(lc: &skidbladnir::service::Lifecycle, name: &str, system: bool) -> anyhow::Result<()> {
skidbladnir::systemd::install_systemd_scoped(&systemd_spec(lc, name, system), scope(system))
}
pub fn remove_env_file(name: &str, system: bool) -> std::io::Result<bool> {
match std::fs::remove_file(env_file_path(name, system)) {
Ok(()) => Ok(true),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(false),
Err(e) => Err(e),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn secrets_go_to_an_env_file_the_unit_names_and_never_inline() {
let spec = skidbladnir::service::ServiceSpec::new("bf", "d", "/usr/local/bin/bifrost")
.scope(skidbladnir::systemd::Scope::System)
.secret_env("MINIO_SECRET_KEY", "hunter2");
let lc = skidbladnir::service::Lifecycle::new(spec);
let sys = systemd_spec(&lc, "bf", true);
sys.validate().expect("secrets + env file is a valid spec");
let unit = unit_text(&lc, "bf", true);
assert!(unit.contains("EnvironmentFile=/etc/bf/bf.env"), "{unit}");
assert!(!unit.contains("hunter2"));
assert!(skidbladnir::systemd::env_file(&sys).contains("hunter2"));
}
#[test]
fn no_secrets_no_env_file() {
let spec = skidbladnir::service::ServiceSpec::new("bf", "d", "/x");
let lc = skidbladnir::service::Lifecycle::new(spec);
assert!(!unit_text(&lc, "bf", false).contains("EnvironmentFile="));
}
#[test]
fn the_user_env_file_sits_beside_the_user_unit() {
assert!(env_file_path("bf", false).ends_with(".config/systemd/user/bf.env"));
}
}