edera_check/checkers/postinstall/
kernel.rs1use crate::helpers::{
2 CheckGroup, CheckGroupCategory, CheckGroupResult, CheckResult,
3 CheckResultValue::{Errored, Failed, Passed},
4 host_executor::HostNamespaceExecutor,
5 kernel as khelper,
6};
7
8use async_trait::async_trait;
9use futures::{FutureExt, future::join_all};
10use procfs::sys::kernel;
11
12const GROUP_IDENTIFIER: &str = "kernel";
13const NAME: &str = "Postinstall Kernel Checks";
14
15const REQUIRED_MODULES: &[&str] = &[
18 "nf_tables",
19 "xen_evtchn",
20 "xen-privcmd",
21 "xen-netback",
22 "xen-pciback",
23 "xen-blkback",
24 "xen-gntdev",
25 "xen-gntalloc",
26];
27
28const KVER_FLOOR_PATCH: u16 = 0;
29const KVER_FLOOR_MINOR: u8 = 15;
30const KVER_FLOOR_MAJOR: u8 = 5;
31
32pub struct PostinstallKernelChecks {
33 host_executor: HostNamespaceExecutor,
34}
35
36impl PostinstallKernelChecks {
37 pub fn new(host_executor: HostNamespaceExecutor) -> Self {
38 PostinstallKernelChecks { host_executor }
39 }
40
41 pub async fn run_all(&self) -> CheckGroupResult {
44 let results = join_all([self.has_modules().boxed(), self.version_is_good().boxed()]).await;
45
46 let mut group_result = Passed;
47 for res in results.iter() {
48 if !matches!(group_result, Errored(_)) && matches!(res.result, Failed(_)) {
50 group_result = Failed("".into());
51 }
52
53 if matches!(res.result, Errored(_)) {
54 group_result = Errored("".into());
55 }
56 }
57
58 CheckGroupResult {
59 name: NAME.to_string(),
60 result: group_result,
61 results,
62 }
63 }
64
65 pub async fn version_is_good(&self) -> CheckResult {
72 let name = String::from("Host Kernel Version Is Good");
73 let floor = kernel::Version::new(KVER_FLOOR_MAJOR, KVER_FLOOR_MINOR, KVER_FLOOR_PATCH);
74
75 let passed = khelper::host_kver_above_floor(&self.host_executor, floor).await;
76
77 match passed {
78 Err(e) => CheckResult::new(&name, Errored(e.to_string())),
79 Ok(true) => CheckResult::new(&name, Passed),
80 Ok(false) => CheckResult::new(
81 &name,
82 Failed(String::from("current kernel version is unsupported")),
83 ),
84 }
85 }
86
87 pub async fn has_modules(&self) -> CheckResult {
101 let name = String::from("Host Has Necessary Modules");
102
103 let required_modules: Vec<String> =
104 REQUIRED_MODULES.iter().map(|s| s.to_string()).collect();
105
106 let remaining = match khelper::find_builtins(&self.host_executor, &required_modules).await {
108 Ok(r) => r,
109 Err(e) => {
110 return CheckResult::new(&name, Errored(format!("getting kernel builtins {e}")));
111 }
112 };
113
114 let remaining = match khelper::find_loaded(&self.host_executor, &remaining).await {
116 Ok(r) => r,
117 Err(e) => {
118 return CheckResult::new(&name, Errored(format!("getting kernel modules {e}")));
119 }
120 };
121
122 let remaining = match khelper::find_loadable(&self.host_executor, &remaining).await {
124 Ok(r) => r,
125 Err(e) => {
126 return CheckResult::new(&name, Errored(format!("getting kernel modules {e}")));
127 }
128 };
129 if !remaining.is_empty() {
130 return CheckResult::new(&name, Failed(format!("missing {:?}", remaining)));
131 }
132
133 CheckResult::new(&name, Passed)
134 }
135}
136
137#[async_trait]
138impl CheckGroup for PostinstallKernelChecks {
139 fn id(&self) -> &str {
140 GROUP_IDENTIFIER
141 }
142
143 fn name(&self) -> &str {
144 NAME
145 }
146
147 fn description(&self) -> &str {
148 "Postinstall kernel validation checks"
149 }
150
151 async fn run(&self) -> CheckGroupResult {
152 self.run_all().await
153 }
154
155 fn category(&self) -> CheckGroupCategory {
156 CheckGroupCategory::Required
157 }
158}