use crate::core::types::Resource;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Observability {
Observed { alt: &'static str },
Unobservable(&'static str),
Unmigrated(&'static str),
}
pub fn classify(field: &str) -> Option<Observability> {
Some(match field {
"path" => Observability::Observed {
alt: "/tmp/forjar-alt-path",
},
"content" => Observability::Observed {
alt: "forjar-alt-content",
},
"source" => Observability::Observed {
alt: "//forjar-alt/share",
},
"fs_type" => Observability::Observed { alt: "nfs" },
"options" => Observability::Observed { alt: "ro" },
"owner" => Observability::Observed { alt: "nobody" },
"group" => Observability::Observed { alt: "nogroup" },
"mode" => Observability::Observed { alt: "0600" },
"version" => Observability::Observed {
alt: "0.0.1-forjar-alt",
},
"packages" => Observability::Observed {
alt: "forjar-alt-package",
},
"state" => Observability::Observed { alt: "absent" },
"target" => Observability::Observed {
alt: "/tmp/forjar-alt-target",
},
"provider" => Observability::Unobservable(
"selects the mechanism, not the state; the host cannot report which \
provider installed a thing",
),
"name" => Observability::Unobservable("an identifier, not a property of the host"),
"fstype" => Observability::Observed { alt: "nfs" },
"shell" => Observability::Observed {
alt: "/usr/sbin/nologin",
},
"home" => Observability::Observed {
alt: "/tmp/forjar-alt-home",
},
"image" => Observability::Observed {
alt: "forjar/alt-image:0",
},
"ports" => Observability::Observed { alt: "9999:9999" },
"port" => Observability::Observed { alt: "9999" },
"volumes" => Observability::Observed {
alt: "/tmp/forjar-alt-vol",
},
"environment" => Observability::Observed {
alt: "FORJAR_ALT=1",
},
"restart" => Observability::Observed { alt: "no" },
"schedule" => Observability::Observed { alt: "0 0 31 2 *" },
"command" => Observability::Observed {
alt: "true # forjar-alt",
},
"overlay_ip" => Observability::Observed { alt: "10.42.0.254" },
"overlay_iface" => Observability::Observed { alt: "forjar-alt0" },
"protocol" => Observability::Observed { alt: "udp" },
"from" => Observability::Observed {
alt: "10.42.0.0/24",
},
"action" => Observability::Unobservable(
"names an operation to perform, not a state the host can report",
),
"restart_on" => Observability::Unobservable(
"a trigger condition, not observable state; the host cannot say what \
would have restarted it",
),
_ => return None,
})
}
pub fn hashed_fields() -> Vec<String> {
use crate::core::planner::hashing::hash_desired_state;
let base = Resource::default();
let base_hash = hash_desired_state(&base);
let Ok(serde_json::Value::Object(map)) = serde_json::to_value(&base) else {
return Vec::new();
};
let mut out = Vec::new();
for key in map.keys() {
let mut probe = map.clone();
probe.insert(key.clone(), serde_json::json!("forjar-probe-sentinel"));
let as_list = {
let mut p = map.clone();
p.insert(key.clone(), serde_json::json!(["forjar-probe-sentinel"]));
p
};
for candidate in [probe, as_list] {
if let Ok(r) = serde_json::from_value::<Resource>(serde_json::Value::Object(candidate))
{
if hash_desired_state(&r) != base_hash {
out.push(key.clone());
break;
}
}
}
}
out.sort();
out.dedup();
out
}
#[cfg(test)]
mod tests;