use edera_check::checkers::postinstall::{
guest_type::GuestTypeChecks, kernel::PostinstallKernelChecks, kube::KubeChecks,
services::ServiceChecks,
};
use crate::{booted_under_edera, create_base_path, create_gzip_from, write_group_report};
use edera_check::recorders::postinstall::system::SystemRecorder as postrecorder;
use anyhow::Result;
use console::style;
use edera_check::helpers::{
CheckGroup, CheckGroupCategory,
CheckResultValue::{Errored, Failed, Passed},
host_executor::HostNamespaceExecutor,
};
use anyhow::{anyhow, bail};
use std::{collections::HashSet, env, path::PathBuf, process};
pub async fn do_postinstall(
list_only: bool,
record_hostinfo: bool,
only_checks: Vec<String>,
report_dir: Option<String>,
) -> Result<()> {
let host_executor = HostNamespaceExecutor::new();
let mut groups: Vec<Box<dyn CheckGroup>> = vec![
Box::new(GuestTypeChecks::new(host_executor.clone())),
Box::new(PostinstallKernelChecks::new(host_executor.clone())),
Box::new(ServiceChecks::new(host_executor.clone())),
Box::new(KubeChecks::new(host_executor.clone())),
];
if record_hostinfo {
groups.push(Box::new(postrecorder::new(host_executor.clone())));
}
if list_only {
let id_w = groups
.iter()
.map(|g| g.id().len())
.max()
.unwrap_or(0)
.max("ID".len());
let cat_w = groups
.iter()
.map(|g| g.category().to_string().len())
.max()
.unwrap_or(0)
.max("Category".len());
println!(
"Available postinstall check groups (selectively run checks with '--only-checks <ID>'):\n"
);
println!(" {:<id_w$} {:<cat_w$} Description", "ID", "Category");
println!(
" {}",
"-".repeat(id_w + 2 + cat_w + 2 + "Description".len())
);
for group in &groups {
let cat = group.category().to_string();
println!(
" {}{} {}{} {}",
style(group.id()).cyan().bold(),
" ".repeat(id_w - group.id().len()),
style(&cat).white().bold(),
" ".repeat(cat_w - cat.len()),
group.description()
);
}
return Ok(());
}
match booted_under_edera(&host_executor).await {
Ok(true) => {}
Ok(false) => {
println!(
"{}",
style("Edera not installed. Run `edera-check preinstall` instead.")
.red()
.bold()
);
process::exit(1);
}
Err(e) => {
bail!("Error: {}", e);
}
};
if record_hostinfo {
println!(
"Collecting information about the current host as part of locally-generated postinstall report."
);
println!("The information collected will remain on this host.");
}
if !only_checks.is_empty() {
let valid_ids: HashSet<_> = groups.iter().map(|g| g.id().to_string()).collect();
only_checks.iter().for_each(|id| {
if !valid_ids.contains(id) {
println!("{} '{}'", style("Unknown Check:").yellow(), style(id).red());
}
});
groups.retain(|group| only_checks.contains(&group.id().to_string()));
}
groups.sort_by_key(|g| g.category());
let mut required_groups_result = Passed;
let mut all_groups_result = Passed;
let hostname = host_executor
.spawn_in_host_ns(async { std::fs::read_to_string("/etc/hostname").unwrap() })
.await?;
let base_dir = if let Some(dir) = report_dir {
PathBuf::from(dir)
} else {
env::temp_dir()
};
let base_path = create_base_path(base_dir, hostname.trim(), "postinstall")
.map_err(|e| anyhow!("failed to create bundle base path: {e}"))?;
for group in groups {
println!(
"{} {} [{}] - {}",
style("Running Group").cyan(),
style(group.name()).cyan().bold(),
style(group.category()).white().bold(),
group.description()
);
let check_group_result = group.run().await;
check_group_result.log_individual_checks();
check_group_result.log_group(group.category());
if matches!(check_group_result.result, Failed(_)) {
if matches!(group.category(), CheckGroupCategory::Required)
&& !matches!(required_groups_result, Errored(_))
{
required_groups_result = Failed(String::from("group failed"));
} else if !matches!(all_groups_result, Errored(_)) {
all_groups_result = Failed(String::from("group failed"));
}
}
if matches!(check_group_result.result, Errored(_)) {
if matches!(group.category(), CheckGroupCategory::Required) {
required_groups_result = Errored(String::from("group errored"));
} else {
all_groups_result = Errored(String::from("group errored"));
}
}
write_group_report(group, &check_group_result, &base_path)?;
}
create_gzip_from(base_path, host_executor.clone()).await?;
match required_groups_result {
Errored(_) | Failed(_) => bail!("Required postinstall checks did not pass"),
_ => Ok(()),
}
}