use std::path::Path;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum KubeconfigTarget {
DataDir,
Operator,
Pod,
Remote,
}
impl KubeconfigTarget {
pub const ALL: [Self; 4] = [Self::DataDir, Self::Pod, Self::Remote, Self::Operator];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SkipReason {
NotConfigured,
TlsDisabled,
NoAdvertiseAddress,
NoPodAddress,
NoHome,
RuntimeDown,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(tag = "status", rename_all = "snake_case")]
pub enum PublishOutcome {
Written {
path: String,
mode: String,
},
Failed {
path: String,
error: String,
},
Skipped {
reason: SkipReason,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PublishRecord {
pub target: KubeconfigTarget,
pub outcome: PublishOutcome,
}
impl PublishRecord {
#[must_use]
pub fn written(target: KubeconfigTarget, path: &Path, mode: u32) -> Self {
Self {
target,
outcome: PublishOutcome::Written {
path: path.display().to_string(),
mode: format!("{mode:04o}"),
},
}
}
#[must_use]
pub fn failed(target: KubeconfigTarget, path: &Path, error: &dyn std::fmt::Display) -> Self {
Self {
target,
outcome: PublishOutcome::Failed {
path: path.display().to_string(),
error: error.to_string(),
},
}
}
#[must_use]
pub const fn skipped(target: KubeconfigTarget, reason: SkipReason) -> Self {
Self {
target,
outcome: PublishOutcome::Skipped { reason },
}
}
#[must_use]
pub fn all_skipped(reason: SkipReason) -> Vec<Self> {
KubeconfigTarget::ALL
.into_iter()
.map(|target| Self::skipped(target, reason))
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_wire_shapes_are_the_control_apis() {
assert_eq!(
serde_json::to_value(PublishRecord::written(
KubeconfigTarget::Operator,
Path::new("/h/.kube/configs/engenho"),
0o640
))
.expect("serialize"),
serde_json::json!({
"target": "operator",
"outcome": {"status": "written", "path": "/h/.kube/configs/engenho", "mode": "0640"},
})
);
assert_eq!(
serde_json::to_value(PublishRecord::skipped(
KubeconfigTarget::Pod,
SkipReason::NoPodAddress
))
.expect("serialize"),
serde_json::json!({"target": "pod", "outcome": {"status": "skipped", "reason": "no_pod_address"}})
);
assert_eq!(PublishRecord::all_skipped(SkipReason::TlsDisabled).len(), 4);
}
}