microvms_domain/
preflight.rs1use crate::error::Error;
12use crate::region::{MEASURED_REGIONS, Region};
13
14#[derive(Clone, Debug, PartialEq)]
16pub struct Check {
17 pub name: &'static str,
18 pub ok: bool,
19 pub fatal: bool,
21 pub ran: bool,
23 pub detail: String,
24 pub remedy: String,
26}
27
28impl Check {
29 pub fn pass(name: &'static str, detail: impl Into<String>) -> Self {
30 Self {
31 name,
32 ok: true,
33 fatal: true,
34 ran: true,
35 detail: detail.into(),
36 remedy: String::new(),
37 }
38 }
39
40 pub fn fail(name: &'static str, detail: impl Into<String>, remedy: impl Into<String>) -> Self {
41 Self {
42 name,
43 ok: false,
44 fatal: true,
45 ran: true,
46 detail: detail.into(),
47 remedy: remedy.into(),
48 }
49 }
50
51 pub fn not_run(name: &'static str, reason: impl Into<String>) -> Self {
53 Self {
54 ran: false,
55 ..Self::fail(
56 name,
57 format!("not run: {}", reason.into()),
58 "fix the check above",
59 )
60 }
61 }
62
63 #[must_use]
65 pub fn advisory(mut self) -> Self {
66 self.fatal = false;
67 self
68 }
69}
70
71pub fn healthy(checks: &[Check]) -> bool {
73 checks
74 .iter()
75 .filter(|check| check.fatal)
76 .all(|check| check.ok)
77}
78
79#[derive(Clone, Debug)]
81pub struct PreflightReport {
82 pub region: Option<Region>,
84 pub checks: Vec<Check>,
86}
87
88impl PreflightReport {
89 pub fn ok(&self) -> bool {
91 healthy(&self.checks)
92 }
93
94 pub fn check(&self, name: &str) -> Option<&Check> {
96 self.checks.iter().find(|check| check.name == name)
97 }
98}
99
100fn known_regions() -> String {
101 MEASURED_REGIONS.join(", ")
102}
103
104pub fn region_check(resolved: &Result<Region, Error>) -> Check {
108 match resolved {
109 Ok(region) if region.is_measured() => {
110 Check::pass("region", format!("{region} is a known MicroVMs region"))
111 }
112 Ok(region) => Check::fail(
113 "region",
114 format!("{region} is not a region AWS was measured running MicroVMs in"),
115 format!(
116 "known: {} (measured 2026-10-24). If AWS has not launched MicroVMs here, a call \
117 can fail with an AccessDeniedException and a null message, and the service \
118 check below can still pass",
119 known_regions()
120 ),
121 )
122 .advisory(),
123 Err(error) => Check::fail(
124 "region",
125 error.to_string(),
126 format!("known: {}", known_regions()),
127 ),
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn only_a_fatal_failure_is_unhealthy() {
137 let advisory = Check::fail("region", "unlisted", "see below").advisory();
138 assert!(healthy(&[Check::pass("a", "fine"), advisory.clone()]));
139 assert!(!healthy(&[
140 advisory,
141 Check::not_run("service", "no region")
142 ]));
143 assert!(!Check::not_run("service", "no region").ran);
144 }
145
146 #[test]
147 fn the_region_line_passes_a_measured_region_and_advises_on_any_other() {
148 assert!(region_check(&Ok(Region::US_EAST_1)).ok);
149 assert!(region_check(&Ok("eu-central-1".parse().unwrap())).ok);
150 let unlisted = region_check(&Ok("xx-new-1".parse().unwrap()));
151 assert!(!unlisted.ok && !unlisted.fatal, "{unlisted:?}");
152 let refused = region_check(&Err(Error::invalid_arg("no region")));
153 assert!(!refused.ok && refused.fatal, "{refused:?}");
154 assert!(refused.remedy.contains("us-east-1"), "{refused:?}");
155 }
156}