feat: Invetory inspection score that dumps the inventory in a readable way, also quite a few fixes on okd installation scores
This commit is contained in:
parent
f31d21f9da
commit
1640e6d7a3
@ -149,6 +149,98 @@ impl PhysicalHost {
|
||||
parts.join(" | ")
|
||||
}
|
||||
|
||||
pub fn parts_list(&self) -> String {
|
||||
let PhysicalHost {
|
||||
id,
|
||||
category,
|
||||
network,
|
||||
storage,
|
||||
labels,
|
||||
memory_modules,
|
||||
cpus,
|
||||
} = self;
|
||||
|
||||
let mut parts_list = String::new();
|
||||
parts_list.push_str("\n\n=====================");
|
||||
parts_list.push_str(&format!("\nHost ID {id}"));
|
||||
parts_list.push_str("\n=====================");
|
||||
parts_list.push_str("\n\n=====================");
|
||||
parts_list.push_str(&format!("\nCPU count {}", cpus.len()));
|
||||
parts_list.push_str("\n=====================");
|
||||
cpus.iter().for_each(|c| {
|
||||
let CPU {
|
||||
model,
|
||||
vendor,
|
||||
cores,
|
||||
threads,
|
||||
frequency_mhz,
|
||||
} = c;
|
||||
parts_list.push_str(&format!(
|
||||
"\n{vendor} {model}, {cores}/{threads} {}Ghz",
|
||||
*frequency_mhz as f64 / 1000.0
|
||||
));
|
||||
});
|
||||
|
||||
parts_list.push_str("\n\n=====================");
|
||||
parts_list.push_str(&format!("\nNetwork Interfaces count {}", network.len()));
|
||||
parts_list.push_str("\n=====================");
|
||||
network.iter().for_each(|nic| {
|
||||
parts_list.push_str(&format!(
|
||||
"\nNic({} {}Gbps mac({}) ipv4({}), ipv6({})",
|
||||
nic.name,
|
||||
nic.speed_mbps.unwrap_or(0) / 1000,
|
||||
nic.mac_address,
|
||||
nic.ipv4_addresses.join(","),
|
||||
nic.ipv6_addresses.join(",")
|
||||
));
|
||||
});
|
||||
|
||||
parts_list.push_str("\n\n=====================");
|
||||
parts_list.push_str(&format!("\nStorage drives count {}", storage.len()));
|
||||
parts_list.push_str("\n=====================");
|
||||
storage.iter().for_each(|drive| {
|
||||
let StorageDrive {
|
||||
name,
|
||||
model,
|
||||
serial,
|
||||
size_bytes,
|
||||
logical_block_size: _,
|
||||
physical_block_size: _,
|
||||
rotational: _,
|
||||
wwn: _,
|
||||
interface_type,
|
||||
smart_status,
|
||||
} = drive;
|
||||
parts_list.push_str(&format!(
|
||||
"\n{name} {}Gb {model} {interface_type} smart({smart_status:?}) {serial}",
|
||||
size_bytes / 1000 / 1000 / 1000
|
||||
));
|
||||
});
|
||||
|
||||
parts_list.push_str("\n\n=====================");
|
||||
parts_list.push_str(&format!("\nMemory modules count {}", memory_modules.len()));
|
||||
parts_list.push_str("\n=====================");
|
||||
memory_modules.iter().for_each(|mem| {
|
||||
let MemoryModule {
|
||||
size_bytes,
|
||||
speed_mhz,
|
||||
manufacturer,
|
||||
part_number,
|
||||
serial_number,
|
||||
rank,
|
||||
} = mem;
|
||||
parts_list.push_str(&format!(
|
||||
"\n{}Gb, {}Mhz, Manufacturer ({}), Part Number ({})",
|
||||
size_bytes / 1000 / 1000 / 1000,
|
||||
speed_mhz.unwrap_or(0),
|
||||
manufacturer.as_ref().unwrap_or(&String::new()),
|
||||
part_number.as_ref().unwrap_or(&String::new()),
|
||||
));
|
||||
});
|
||||
|
||||
parts_list
|
||||
}
|
||||
|
||||
pub fn cluster_mac(&self) -> MacAddress {
|
||||
self.network
|
||||
.first()
|
||||
|
@ -18,6 +18,7 @@ impl InventoryFilter {
|
||||
use derive_new::new;
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::EnumIter;
|
||||
|
||||
use crate::hardware::{ManagementInterface, ManualManagementInterface};
|
||||
|
||||
@ -63,7 +64,7 @@ impl Inventory {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, sqlx::Type, Clone)]
|
||||
#[derive(Debug, Serialize, Deserialize, sqlx::Type, Clone, EnumIter)]
|
||||
pub enum HostRole {
|
||||
Bootstrap,
|
||||
ControlPlane,
|
||||
|
@ -29,7 +29,7 @@ pub trait InventoryRepository: Send + Sync + 'static {
|
||||
async fn save(&self, host: &PhysicalHost) -> Result<(), RepoError>;
|
||||
async fn get_latest_by_id(&self, host_id: &str) -> Result<Option<PhysicalHost>, RepoError>;
|
||||
async fn get_all_hosts(&self) -> Result<Vec<PhysicalHost>, RepoError>;
|
||||
async fn get_host_for_role(&self, role: HostRole) -> Result<Vec<PhysicalHost>, RepoError>;
|
||||
async fn get_host_for_role(&self, role: &HostRole) -> Result<Vec<PhysicalHost>, RepoError>;
|
||||
async fn save_role_mapping(
|
||||
&self,
|
||||
role: &HostRole,
|
||||
|
@ -109,7 +109,7 @@ impl InventoryRepository for SqliteInventoryRepository {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_host_for_role(&self, role: HostRole) -> Result<Vec<PhysicalHost>, RepoError> {
|
||||
async fn get_host_for_role(&self, role: &HostRole) -> Result<Vec<PhysicalHost>, RepoError> {
|
||||
struct HostIdRow {
|
||||
host_id: String,
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ impl<T: Topology> Interpret<T> for DiscoverHostForRoleInterpret {
|
||||
Ok(choice) => {
|
||||
info!("Selected {} as the bootstrap node.", choice.summary());
|
||||
host_repo
|
||||
.save_role_mapping(&HostRole::Bootstrap, &choice)
|
||||
.save_role_mapping(&self.score.role, &choice)
|
||||
.await?;
|
||||
host = choice;
|
||||
break;
|
||||
|
72
harmony/src/modules/inventory/inspect.rs
Normal file
72
harmony/src/modules/inventory/inspect.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use async_trait::async_trait;
|
||||
use harmony_types::id::Id;
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::{
|
||||
data::Version,
|
||||
infra::inventory::InventoryRepositoryFactory,
|
||||
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
||||
inventory::{HostRole, Inventory},
|
||||
score::Score,
|
||||
topology::Topology,
|
||||
};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct InspectInventoryScore {}
|
||||
|
||||
impl<T: Topology> Score<T> for InspectInventoryScore {
|
||||
fn name(&self) -> String {
|
||||
"InspectInventoryScore".to_string()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(InspectInventoryInterpret {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InspectInventoryInterpret;
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology> Interpret<T> for InspectInventoryInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
_topology: &T,
|
||||
) -> Result<Outcome, InterpretError> {
|
||||
let repo = InventoryRepositoryFactory::build().await?;
|
||||
for role in HostRole::iter() {
|
||||
info!("Inspecting hosts for role {role:?}");
|
||||
let hosts = repo.get_host_for_role(&role).await?;
|
||||
info!("Hosts with role {role:?} : {}", hosts.len());
|
||||
hosts.iter().enumerate().for_each(|(idx, h)| {
|
||||
info!(
|
||||
"Found host index {idx} with role {role:?} => \n{}\n{}",
|
||||
h.summary(),
|
||||
h.parts_list()
|
||||
)
|
||||
});
|
||||
}
|
||||
Ok(Outcome::success(
|
||||
"Inventory inspection complete".to_string(),
|
||||
))
|
||||
}
|
||||
fn get_name(&self) -> InterpretName {
|
||||
InterpretName::Custom("InspectInventoryInterpret")
|
||||
}
|
||||
|
||||
fn get_version(&self) -> Version {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_status(&self) -> InterpretStatus {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_children(&self) -> Vec<Id> {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
mod discovery;
|
||||
pub mod inspect;
|
||||
pub use discovery::*;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
@ -100,7 +100,7 @@ When you can dig them, confirm to continue.
|
||||
let repo = InventoryRepositoryFactory::build().await?;
|
||||
|
||||
while bootstrap_host.is_none() {
|
||||
let hosts = repo.get_host_for_role(HostRole::Bootstrap).await?;
|
||||
let hosts = repo.get_host_for_role(&HostRole::Bootstrap).await?;
|
||||
bootstrap_host = hosts.into_iter().next().to_owned();
|
||||
DiscoverHostForRoleScore {
|
||||
role: HostRole::Bootstrap,
|
||||
|
@ -67,7 +67,7 @@ impl OKDSetup02BootstrapInterpret {
|
||||
async fn get_bootstrap_node(&self) -> Result<PhysicalHost, InterpretError> {
|
||||
let repo = InventoryRepositoryFactory::build().await?;
|
||||
match repo
|
||||
.get_host_for_role(HostRole::Bootstrap)
|
||||
.get_host_for_role(&HostRole::Bootstrap)
|
||||
.await?
|
||||
.into_iter()
|
||||
.next()
|
||||
|
@ -66,7 +66,7 @@ impl OKDSetup03ControlPlaneInterpret {
|
||||
) -> Result<Vec<PhysicalHost>, InterpretError> {
|
||||
const REQUIRED_HOSTS: usize = 3;
|
||||
let repo = InventoryRepositoryFactory::build().await?;
|
||||
let mut control_plane_hosts = repo.get_host_for_role(HostRole::ControlPlane).await?;
|
||||
let mut control_plane_hosts = repo.get_host_for_role(&HostRole::ControlPlane).await?;
|
||||
|
||||
while control_plane_hosts.len() < REQUIRED_HOSTS {
|
||||
info!(
|
||||
@ -80,7 +80,7 @@ impl OKDSetup03ControlPlaneInterpret {
|
||||
}
|
||||
.interpret(inventory, topology)
|
||||
.await?;
|
||||
control_plane_hosts = repo.get_host_for_role(HostRole::ControlPlane).await?;
|
||||
control_plane_hosts = repo.get_host_for_role(&HostRole::ControlPlane).await?;
|
||||
}
|
||||
|
||||
if control_plane_hosts.len() < REQUIRED_HOSTS {
|
||||
|
Loading…
Reference in New Issue
Block a user