Skip to main content

isoloom_render/
error.rs

1//! Why a backend didn't render an environment: the one error every backend reports, so the
2//! registry (`isoloom-targets`) and the command line read each the same way.
3
4use isoloom_plan::Refusal;
5use isoloom_spec::model::Target;
6
7/// Why a backend didn't render an environment.
8#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
9#[non_exhaustive]
10pub enum Error {
11    /// The environment needs a capability the backend lacks (the plan's refusal).
12    #[error("{}: {refusal}", target.id())]
13    Refused {
14        /// The backend's target.
15        target: Target,
16        /// The requirement it can't meet.
17        refusal: Refusal,
18    },
19    /// The backend refuses the environment for a limit of its own target.
20    #[error("{}: {what}", target.id())]
21    Unsupported {
22        /// The target that refuses.
23        target: Target,
24        /// What it doesn't support, as the refusal reads.
25        what: String,
26    },
27}
28
29impl Error {
30    /// The target whose backend refused.
31    #[must_use]
32    pub fn target(&self) -> Target {
33        match self {
34            Error::Refused { target, .. } | Error::Unsupported { target, .. } => *target,
35        }
36    }
37
38    /// Why, as the refusal reads after its target.
39    #[must_use]
40    pub fn reason(&self) -> String {
41        match self {
42            Error::Refused { refusal, .. } => refusal.to_string(),
43            Error::Unsupported { what, .. } => what.clone(),
44        }
45    }
46}
47
48/// A result whose error is this crate's [`Error`].
49pub type Result<T, E = Error> = std::result::Result<T, E>;
50
51#[cfg(test)]
52mod tests {
53    use isoloom_plan::{Refusal, Requirement};
54    use isoloom_spec::model::Target;
55
56    use super::Error;
57
58    #[test]
59    fn each_error_reads_as_its_target_then_why() {
60        let refused = Error::Refused {
61            target: Target::Kubernetes,
62            refusal: Refusal {
63                requirement: Requirement::MachineAliases,
64            },
65        };
66        assert_eq!(
67            refused.to_string(),
68            "kubernetes: machine `aliases` (dotted DNS names) aren't Kubernetes Service names"
69        );
70        let unsupported = Error::Unsupported {
71            target: Target::Proxmox,
72            what: "machine `w`: no image".to_owned(),
73        };
74        assert_eq!(unsupported.to_string(), "proxmox: machine `w`: no image");
75        assert_eq!((refused.target(), unsupported.target()), (Target::Kubernetes, Target::Proxmox));
76        assert_eq!(unsupported.reason(), "machine `w`: no image");
77        assert_eq!(refused.reason(), "machine `aliases` (dotted DNS names) aren't Kubernetes Service names");
78    }
79}