Skip to content

Commit 5061595

Browse files
committed
Add kube checkers
1 parent c332089 commit 5061595

6 files changed

Lines changed: 177 additions & 64 deletions

File tree

src/checkers/postinstall/kube.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use async_trait::async_trait;
2+
use futures::{FutureExt, future::join_all};
3+
use log::debug;
4+
5+
use crate::helpers::{
6+
CheckGroup, CheckGroupCategory, CheckGroupResult, CheckResult,
7+
CheckResultValue::{Errored, Failed, Passed},
8+
host_executor::HostNamespaceExecutor,
9+
services as svchelpers,
10+
};
11+
12+
const GROUP_IDENTIFIER: &str = "kubernetes";
13+
const NAME: &str = "Kubernetes Capability Checks";
14+
15+
pub struct KubeChecks {
16+
host_executor: HostNamespaceExecutor,
17+
}
18+
19+
impl KubeChecks {
20+
pub fn new(host_executor: HostNamespaceExecutor) -> Self {
21+
KubeChecks { host_executor }
22+
}
23+
24+
/// Run all the recorders asynchronously, then
25+
/// join and collect the results.
26+
pub async fn run_all(&self) -> CheckGroupResult {
27+
let results = join_all([self.check_cri().boxed(), self.check_kubelet().boxed()]).await;
28+
29+
let mut group_result = Passed;
30+
for res in results.iter() {
31+
// Set group result to Failed if we failed and aren't already in an Errored state
32+
if !matches!(group_result, Errored(_)) && matches!(res.result, Failed(_)) {
33+
group_result = Failed(String::from("group failed"));
34+
}
35+
36+
if matches!(res.result, Errored(_)) {
37+
group_result = Errored(String::from("group errored"));
38+
}
39+
}
40+
41+
CheckGroupResult {
42+
name: NAME.to_string(),
43+
result: group_result,
44+
results,
45+
}
46+
}
47+
48+
async fn check_cri(&self) -> CheckResult {
49+
let name = "Protect CRI daemon status";
50+
let sname = "protect-cri";
51+
let init = svchelpers::detect_init_system(&self.host_executor).await;
52+
debug!("detected init system: {:?}\n", init);
53+
54+
match svchelpers::is_running(&self.host_executor, sname.into(), init).await {
55+
Ok(true) => CheckResult::new(name, Passed),
56+
Ok(false) => CheckResult::new(name, Failed(format!("{} not running", &sname))),
57+
Err(e) => CheckResult::new(
58+
name,
59+
Errored(format!("failed to check service {sname}: {e}")),
60+
),
61+
}
62+
}
63+
64+
async fn check_kubelet(&self) -> CheckResult {
65+
let name = "kubelet status";
66+
let sname = "kubelet";
67+
let init = svchelpers::detect_init_system(&self.host_executor).await;
68+
debug!("detected init system: {:?}\n", init);
69+
70+
match svchelpers::is_running(&self.host_executor, sname.into(), init).await {
71+
Ok(true) => CheckResult::new(name, Passed),
72+
Ok(false) => CheckResult::new(name, Failed(format!("{} not running", &sname))),
73+
Err(e) => CheckResult::new(
74+
name,
75+
Errored(format!("failed to check service {sname}: {e}")),
76+
),
77+
}
78+
}
79+
}
80+
81+
#[async_trait]
82+
impl CheckGroup for KubeChecks {
83+
fn id(&self) -> &str {
84+
GROUP_IDENTIFIER
85+
}
86+
87+
fn name(&self) -> &str {
88+
NAME
89+
}
90+
91+
fn description(&self) -> &str {
92+
"Check status of Kubernetes integration"
93+
}
94+
95+
async fn run(&self) -> CheckGroupResult {
96+
self.run_all().await
97+
}
98+
99+
fn category(&self) -> CheckGroupCategory {
100+
CheckGroupCategory::Optional("Kubernetes feature not available on this system".into())
101+
}
102+
}

src/checkers/postinstall/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod guest_type;
22
pub mod kernel;
3+
pub mod kube;
34
pub mod services;

src/checkers/postinstall/services.rs

Lines changed: 7 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,17 @@
1-
use anyhow::{Result, bail};
21
use async_trait::async_trait;
32
use futures::{FutureExt, future::join_all};
43
use log::debug;
5-
use std::process::Command;
64

75
use crate::helpers::{
86
CheckGroup, CheckGroupCategory, CheckGroupResult, CheckResult,
97
CheckResultValue::{Errored, Failed, Passed},
108
host_executor::HostNamespaceExecutor,
9+
services as svchelpers,
1110
};
1211

1312
const GROUP_IDENTIFIER: &str = "services";
1413
const NAME: &str = "Service Status Checks";
1514

16-
#[derive(Debug, Clone, Copy, PartialEq)]
17-
enum InitSystem {
18-
Systemd,
19-
OpenRC,
20-
Unknown,
21-
}
22-
2315
pub struct ServiceChecks {
2416
host_executor: HostNamespaceExecutor,
2517
}
@@ -61,10 +53,10 @@ impl ServiceChecks {
6153
async fn check_daemon(&self) -> CheckResult {
6254
let name = "Protect daemon status";
6355
let sname = "protect-daemon";
64-
let init = self.detect_init_system().await;
56+
let init = svchelpers::detect_init_system(&self.host_executor).await;
6557
debug!("detected init system: {:?}\n", init);
6658

67-
match self.is_running(sname.into(), init).await {
59+
match svchelpers::is_running(&self.host_executor, sname.into(), init).await {
6860
Ok(true) => CheckResult::new(name, Passed),
6961
Ok(false) => CheckResult::new(name, Failed(format!("{} not running", &sname))),
7062
Err(e) => CheckResult::new(
@@ -77,10 +69,10 @@ impl ServiceChecks {
7769
async fn check_storage(&self) -> CheckResult {
7870
let name = "Protect storage daemon status";
7971
let sname = "protect-storage";
80-
let init = self.detect_init_system().await;
72+
let init = svchelpers::detect_init_system(&self.host_executor).await;
8173
debug!("detected init system: {:?}\n", init);
8274

83-
match self.is_running(sname.into(), init).await {
75+
match svchelpers::is_running(&self.host_executor, sname.into(), init).await {
8476
Ok(true) => CheckResult::new(name, Passed),
8577
Ok(false) => CheckResult::new(name, Failed(format!("{} not running", &sname))),
8678
Err(e) => CheckResult::new(
@@ -93,10 +85,10 @@ impl ServiceChecks {
9385
async fn check_network(&self) -> CheckResult {
9486
let name = "Protect network daemon status";
9587
let sname = "protect-network";
96-
let init = self.detect_init_system().await;
88+
let init = svchelpers::detect_init_system(&self.host_executor).await;
9789
debug!("detected init system: {:?}\n", init);
9890

99-
match self.is_running(sname.into(), init).await {
91+
match svchelpers::is_running(&self.host_executor, sname.into(), init).await {
10092
Ok(true) => CheckResult::new(name, Passed),
10193
Ok(false) => CheckResult::new(name, Failed(format!("{} not running", &sname))),
10294
Err(e) => CheckResult::new(
@@ -105,54 +97,6 @@ impl ServiceChecks {
10597
),
10698
}
10799
}
108-
109-
async fn detect_init_system(&self) -> InitSystem {
110-
self.host_executor
111-
.spawn_in_host_ns(async move {
112-
// Check if systemd is PID 1
113-
if let Ok(output) = Command::new("ps").args(["-p", "1", "-o", "comm="]).output() {
114-
let comm = String::from_utf8_lossy(&output.stdout);
115-
if comm.trim() == "systemd" {
116-
return InitSystem::Systemd;
117-
}
118-
}
119-
120-
// otherwise, check if rc-service exists (OpenRC)
121-
if Command::new("which")
122-
.arg("rc-service")
123-
.output()
124-
.map(|o| o.status.success())
125-
.unwrap_or(false)
126-
{
127-
return InitSystem::OpenRC;
128-
}
129-
InitSystem::Unknown
130-
})
131-
.await
132-
.unwrap_or(InitSystem::Unknown)
133-
}
134-
135-
async fn is_running(&self, service: String, init: InitSystem) -> Result<bool> {
136-
self.host_executor
137-
.spawn_in_host_ns(async move {
138-
match init {
139-
InitSystem::Systemd => {
140-
let status = Command::new("systemctl")
141-
.args(["is-active", "--quiet", &service])
142-
.status()?;
143-
Ok(status.success())
144-
}
145-
InitSystem::OpenRC => {
146-
let status = Command::new("rc-service")
147-
.args([&service, "status"])
148-
.status()?;
149-
Ok(status.success())
150-
}
151-
InitSystem::Unknown => bail!("unknown init system"),
152-
}
153-
})
154-
.await?
155-
}
156100
}
157101

158102
#[async_trait]

src/helpers/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod host_executor;
22
pub mod kernel;
3+
pub mod services;
34

45
use async_trait::async_trait;
56
use console::{Emoji, style};

src/helpers/services.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use anyhow::{Result, bail};
2+
use std::process::Command;
3+
4+
use crate::helpers::host_executor::HostNamespaceExecutor;
5+
6+
#[derive(Debug, Clone, Copy, PartialEq)]
7+
pub enum InitSystem {
8+
Systemd,
9+
OpenRC,
10+
Unknown,
11+
}
12+
13+
pub async fn detect_init_system(host_executor: &HostNamespaceExecutor) -> InitSystem {
14+
host_executor
15+
.spawn_in_host_ns(async move {
16+
// Check if systemd is PID 1
17+
if let Ok(output) = Command::new("ps").args(["-p", "1", "-o", "comm="]).output() {
18+
let comm = String::from_utf8_lossy(&output.stdout);
19+
if comm.trim() == "systemd" {
20+
return InitSystem::Systemd;
21+
}
22+
}
23+
24+
// otherwise, check if rc-service exists (OpenRC)
25+
if Command::new("which")
26+
.arg("rc-service")
27+
.output()
28+
.map(|o| o.status.success())
29+
.unwrap_or(false)
30+
{
31+
return InitSystem::OpenRC;
32+
}
33+
InitSystem::Unknown
34+
})
35+
.await
36+
.unwrap_or(InitSystem::Unknown)
37+
}
38+
39+
pub async fn is_running(
40+
host_executor: &HostNamespaceExecutor,
41+
service: String,
42+
init: InitSystem,
43+
) -> Result<bool> {
44+
host_executor
45+
.spawn_in_host_ns(async move {
46+
match init {
47+
InitSystem::Systemd => {
48+
let status = Command::new("systemctl")
49+
.args(["is-active", "--quiet", &service])
50+
.status()?;
51+
Ok(status.success())
52+
}
53+
InitSystem::OpenRC => {
54+
let status = Command::new("rc-service")
55+
.args([&service, "status"])
56+
.status()?;
57+
Ok(status.success())
58+
}
59+
InitSystem::Unknown => bail!("unknown init system"),
60+
}
61+
})
62+
.await?
63+
}

src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use checkers::preinstall::{
88
};
99

1010
use checkers::postinstall::{
11-
guest_type::GuestTypeChecks, kernel::PostinstallKernelChecks, services::ServiceChecks,
11+
guest_type::GuestTypeChecks, kernel::PostinstallKernelChecks, kube::KubeChecks,
12+
services::ServiceChecks,
1213
};
1314

1415
use clap::{Parser, Subcommand};
@@ -271,6 +272,7 @@ async fn main() -> Result<()> {
271272
Box::new(GuestTypeChecks::new(host_executor.clone())),
272273
Box::new(PostinstallKernelChecks::new(host_executor.clone())),
273274
Box::new(ServiceChecks::new(host_executor.clone())),
275+
Box::new(KubeChecks::new(host_executor.clone())),
274276
];
275277

276278
if record_hostinfo {

0 commit comments

Comments
 (0)