Skip to main content

edera_check/checkers/preinstall/
kernel.rs

1use 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};
10
11const GROUP_IDENTIFIER: &str = "kernel";
12const NAME: &str = "Kernel Checks";
13// TODO (bml) assemble actual list
14const REQUIRED_MODULES: &[&str] = &["nf_tables", "msr"];
15
16pub struct KernelChecks {
17    host_executor: HostNamespaceExecutor,
18}
19
20impl KernelChecks {
21    pub fn new(host_executor: HostNamespaceExecutor) -> Self {
22        KernelChecks { host_executor }
23    }
24
25    /// Run all the checkers asynchronously, then
26    /// join and collect the results.
27    pub async fn run_all(&self) -> CheckGroupResult {
28        let results = join_all([self.has_modules().boxed()]).await;
29
30        let mut group_result = Passed;
31        for res in results.iter() {
32            // Set group result to Failed if we failed and aren't already in an Errored state
33            if !matches!(group_result, Errored(_)) && matches!(res.result, Failed(_)) {
34                group_result = Failed("".into());
35            }
36
37            if matches!(res.result, Errored(_)) {
38                group_result = Errored("".into());
39            }
40        }
41
42        CheckGroupResult {
43            name: NAME.to_string(),
44            result: group_result,
45            results,
46        }
47    }
48
49    /// Checks that `nf_tables` and `msr` are either built into or loaded by the running kernel.
50    ///
51    /// Manual equivalent:
52    /// ```sh
53    /// grep -E 'nf_tables|msr' /lib/modules/$(uname -r)/modules.builtin
54    /// grep -E '^nf_tables |^msr ' /proc/modules
55    /// ```
56    pub async fn has_modules(&self) -> CheckResult {
57        let name = String::from("Host Has Necessary Modules");
58
59        let required_modules: Vec<String> =
60            REQUIRED_MODULES.iter().map(|s| s.to_string()).collect();
61
62        // Search builtin modules
63        let remaining = match khelper::find_builtins(&self.host_executor, &required_modules).await {
64            Ok(r) => r,
65            Err(e) => {
66                return CheckResult::new(&name, Errored(format!("getting kernel builtins {e}")));
67            }
68        };
69
70        // Search loaded modules
71        let remaining = match khelper::find_loaded(&self.host_executor, &remaining).await {
72            Ok(r) => r,
73            Err(e) => {
74                return CheckResult::new(&name, Errored(format!("getting kernel modules {e}")));
75            }
76        };
77        if !remaining.is_empty() {
78            return CheckResult::new(&name, Failed(format!("missing {:?}", remaining)));
79        }
80
81        CheckResult::new(&name, Passed)
82    }
83}
84
85#[async_trait]
86impl CheckGroup for KernelChecks {
87    fn id(&self) -> &str {
88        GROUP_IDENTIFIER
89    }
90
91    fn name(&self) -> &str {
92        NAME
93    }
94
95    fn description(&self) -> &str {
96        "Kernel requirement checks"
97    }
98
99    async fn run(&self) -> CheckGroupResult {
100        self.run_all().await
101    }
102
103    fn category(&self) -> CheckGroupCategory {
104        CheckGroupCategory::Required
105    }
106}