1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (c) Facebook, Inc. and its affiliates.
use enum_iterator::IntoEnumIterator;
use log::warn;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Write;

use rd_util::*;

const SYSREQ_DOC: &str = "\
//
// rd-agent system requirements report
//
// satisfied: List of satifised system requirements
// missed: List of missed system requirements
// scr_dev_model: Scratch storage device model string
// scr_dev_fwrev: Scratch storage device firmware revision string
// scr_dev_size: Scratch storage device size
// swap_size: Swap size
//
";

lazy_static::lazy_static! {
    pub static ref ALL_SYSREQS_SET: BTreeSet<SysReq> = SysReq::into_enum_iter().collect();
}

#[derive(
    Debug,
    Clone,
    Copy,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    IntoEnumIterator,
    Serialize,
    Deserialize,
)]
pub enum SysReq {
    Controllers,
    Freezer,
    MemCgRecursiveProt,
    MemShadowInodeProt, // Enforced only by resctl-bench
    IoCost,
    IoCostVer,
    NoOtherIoControllers,
    AnonBalance,
    Btrfs,
    BtrfsAsyncDiscard,
    NoCompositeStorage,
    IoSched,
    NoWbt,
    SwapOnScratch,
    Swap,
    Oomd,
    NoSysOomd,
    HostCriticalServices,
    DepsBase,
    DepsIoCostCoefGen,
    DepsSide,
    DepsLinuxBuild,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct MissedSysReqs {
    #[serde(flatten)]
    pub map: BTreeMap<SysReq, Vec<String>>,
}

impl MissedSysReqs {
    pub fn add_quiet(&mut self, req: SysReq, msg: &str) {
        match self.map.get_mut(&req) {
            Some(msgs) => msgs.push(msg.to_string()),
            None => {
                self.map.insert(req, vec![msg.to_string()]);
            }
        }
    }

    pub fn add(&mut self, req: SysReq, msg: &str) {
        self.add_quiet(req, msg);
        warn!("cfg: {}", msg);
    }

    pub fn format<'a>(&self, out: &mut Box<dyn Write + 'a>) {
        writeln!(
            out,
            "Missed sysreqs: {}",
            &self
                .map
                .keys()
                .map(|x| format!("{:?}", x))
                .collect::<Vec<String>>()
                .join(", ")
        )
        .unwrap();

        for (_req, msgs) in self.map.iter() {
            for msg in msgs.iter() {
                writeln!(out, "    * {}", msg).unwrap();
            }
        }
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct SysReqsReport {
    pub satisfied: BTreeSet<SysReq>,
    pub missed: MissedSysReqs,
    pub kernel_version: String,
    pub agent_version: String,
    pub hashd_version: String,
    pub nr_cpus: usize,
    pub total_memory: usize,
    pub total_swap: usize,
    pub scr_dev: String,
    pub scr_devnr: (u32, u32),
    pub scr_dev_model: String,
    pub scr_dev_fwrev: String,
    pub scr_dev_size: u64,
    pub scr_dev_iosched: String,
    pub enforce: super::EnforceConfig,
}

impl JsonLoad for SysReqsReport {}

impl JsonSave for SysReqsReport {
    fn preamble() -> Option<String> {
        Some(SYSREQ_DOC.to_string())
    }
}