use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum SupervisorKind {
Manual,
Systemd,
Kubernetes,
}
pub fn detect_supervisor() -> Option<SupervisorKind> {
detect_supervisor_in(&std::env::vars().collect::<std::collections::HashMap<_, _>>())
}
pub fn detect_supervisor_in(
env: &std::collections::HashMap<String, String>,
) -> Option<SupervisorKind> {
if env.get("VTC_SUPERVISED").map(|v| v.as_str()) == Some("1") {
return Some(SupervisorKind::Manual);
}
if env.get("NOTIFY_SOCKET").is_some_and(|v| !v.is_empty()) {
return Some(SupervisorKind::Systemd);
}
if env
.get("KUBERNETES_SERVICE_HOST")
.is_some_and(|v| !v.is_empty())
{
return Some(SupervisorKind::Kubernetes);
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
fn env_with(pairs: &[(&str, &str)]) -> HashMap<String, String> {
pairs
.iter()
.map(|(k, v)| ((*k).to_string(), (*v).to_string()))
.collect()
}
#[test]
fn empty_env_returns_none() {
assert_eq!(detect_supervisor_in(&HashMap::new()), None);
}
#[test]
fn vtc_supervised_1_wins_first() {
let env = env_with(&[
("VTC_SUPERVISED", "1"),
("NOTIFY_SOCKET", "/run/systemd/notify"),
("KUBERNETES_SERVICE_HOST", "10.0.0.1"),
]);
assert_eq!(detect_supervisor_in(&env), Some(SupervisorKind::Manual));
}
#[test]
fn vtc_supervised_other_values_dont_match() {
for v in ["0", "true", "yes", "TRUE", " 1", "1 "] {
let env = env_with(&[("VTC_SUPERVISED", v)]);
assert_eq!(
detect_supervisor_in(&env),
None,
"VTC_SUPERVISED={v:?} must not enable",
);
}
}
#[test]
fn notify_socket_detects_systemd() {
let env = env_with(&[("NOTIFY_SOCKET", "/run/systemd/notify")]);
assert_eq!(detect_supervisor_in(&env), Some(SupervisorKind::Systemd));
}
#[test]
fn empty_notify_socket_does_not_match() {
let env = env_with(&[("NOTIFY_SOCKET", "")]);
assert_eq!(detect_supervisor_in(&env), None);
}
#[test]
fn kubernetes_service_host_detects_pod() {
let env = env_with(&[("KUBERNETES_SERVICE_HOST", "10.0.0.1")]);
assert_eq!(detect_supervisor_in(&env), Some(SupervisorKind::Kubernetes));
}
#[test]
fn detection_priority_systemd_over_kubernetes() {
let env = env_with(&[
("NOTIFY_SOCKET", "/run/systemd/notify"),
("KUBERNETES_SERVICE_HOST", "10.0.0.1"),
]);
assert_eq!(detect_supervisor_in(&env), Some(SupervisorKind::Systemd));
}
}