Compare commits
2 Commits
be385dccff
...
ecc461a33f
Author | SHA1 | Date | |
---|---|---|---|
|
ecc461a33f | ||
|
1640e6d7a3 |
@ -149,6 +149,98 @@ impl PhysicalHost {
|
|||||||
parts.join(" | ")
|
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 {
|
pub fn cluster_mac(&self) -> MacAddress {
|
||||||
self.network
|
self.network
|
||||||
.first()
|
.first()
|
||||||
|
@ -18,6 +18,7 @@ impl InventoryFilter {
|
|||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use log::info;
|
use log::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use strum::EnumIter;
|
||||||
|
|
||||||
use crate::hardware::{ManagementInterface, ManualManagementInterface};
|
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 {
|
pub enum HostRole {
|
||||||
Bootstrap,
|
Bootstrap,
|
||||||
ControlPlane,
|
ControlPlane,
|
||||||
|
@ -29,7 +29,7 @@ pub trait InventoryRepository: Send + Sync + 'static {
|
|||||||
async fn save(&self, host: &PhysicalHost) -> Result<(), RepoError>;
|
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_latest_by_id(&self, host_id: &str) -> Result<Option<PhysicalHost>, RepoError>;
|
||||||
async fn get_all_hosts(&self) -> Result<Vec<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(
|
async fn save_role_mapping(
|
||||||
&self,
|
&self,
|
||||||
role: &HostRole,
|
role: &HostRole,
|
||||||
|
@ -109,7 +109,7 @@ impl InventoryRepository for SqliteInventoryRepository {
|
|||||||
Ok(())
|
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 {
|
struct HostIdRow {
|
||||||
host_id: String,
|
host_id: String,
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ impl<T: Topology> Interpret<T> for DiscoverHostForRoleInterpret {
|
|||||||
Ok(choice) => {
|
Ok(choice) => {
|
||||||
info!("Selected {} as the bootstrap node.", choice.summary());
|
info!("Selected {} as the bootstrap node.", choice.summary());
|
||||||
host_repo
|
host_repo
|
||||||
.save_role_mapping(&HostRole::Bootstrap, &choice)
|
.save_role_mapping(&self.score.role, &choice)
|
||||||
.await?;
|
.await?;
|
||||||
host = choice;
|
host = choice;
|
||||||
break;
|
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;
|
mod discovery;
|
||||||
|
pub mod inspect;
|
||||||
pub use discovery::*;
|
pub use discovery::*;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
@ -100,7 +100,7 @@ When you can dig them, confirm to continue.
|
|||||||
let repo = InventoryRepositoryFactory::build().await?;
|
let repo = InventoryRepositoryFactory::build().await?;
|
||||||
|
|
||||||
while bootstrap_host.is_none() {
|
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();
|
bootstrap_host = hosts.into_iter().next().to_owned();
|
||||||
DiscoverHostForRoleScore {
|
DiscoverHostForRoleScore {
|
||||||
role: HostRole::Bootstrap,
|
role: HostRole::Bootstrap,
|
||||||
|
@ -67,7 +67,7 @@ impl OKDSetup02BootstrapInterpret {
|
|||||||
async fn get_bootstrap_node(&self) -> Result<PhysicalHost, InterpretError> {
|
async fn get_bootstrap_node(&self) -> Result<PhysicalHost, InterpretError> {
|
||||||
let repo = InventoryRepositoryFactory::build().await?;
|
let repo = InventoryRepositoryFactory::build().await?;
|
||||||
match repo
|
match repo
|
||||||
.get_host_for_role(HostRole::Bootstrap)
|
.get_host_for_role(&HostRole::Bootstrap)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.next()
|
.next()
|
||||||
|
@ -66,7 +66,7 @@ impl OKDSetup03ControlPlaneInterpret {
|
|||||||
) -> Result<Vec<PhysicalHost>, InterpretError> {
|
) -> Result<Vec<PhysicalHost>, InterpretError> {
|
||||||
const REQUIRED_HOSTS: usize = 3;
|
const REQUIRED_HOSTS: usize = 3;
|
||||||
let repo = InventoryRepositoryFactory::build().await?;
|
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 {
|
while control_plane_hosts.len() < REQUIRED_HOSTS {
|
||||||
info!(
|
info!(
|
||||||
@ -80,7 +80,7 @@ impl OKDSetup03ControlPlaneInterpret {
|
|||||||
}
|
}
|
||||||
.interpret(inventory, topology)
|
.interpret(inventory, topology)
|
||||||
.await?;
|
.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 {
|
if control_plane_hosts.len() < REQUIRED_HOSTS {
|
||||||
|
Loading…
Reference in New Issue
Block a user