feat(okd installation): Process works nicely all the way up to setting the bootstrap host binding in opnsense automatically! Next step : generate the mac address boot file for bootstrap host, install ignition files and the cluster will booooooooot
Some checks failed
Run Check Script / check (pull_request) Failing after 33s
Some checks failed
Run Check Script / check (pull_request) Failing after 33s
This commit is contained in:
parent
f6e665f990
commit
a353249eec
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT host_id FROM host_role_mapping WHERE role = ?",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "host_id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "2ea29df2326f7c84bd4100ad510a3fd4878dc2e217dc83f9bf45a402dfd62a91"
|
||||||
|
}
|
@ -16,7 +16,7 @@
|
|||||||
{
|
{
|
||||||
"name": "data: Json<PhysicalHost>",
|
"name": "data: Json<PhysicalHost>",
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"type_info": "Null"
|
"type_info": "Blob"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
@ -50,12 +50,12 @@ pub async fn get_topology() -> HAClusterTopology {
|
|||||||
dhcp_server: opnsense.clone(),
|
dhcp_server: opnsense.clone(),
|
||||||
dns_server: opnsense.clone(),
|
dns_server: opnsense.clone(),
|
||||||
control_plane: vec![LogicalHost {
|
control_plane: vec![LogicalHost {
|
||||||
ip: ip!("10.100.8.20"),
|
ip: ip!("192.168.1.20"),
|
||||||
name: "cp0".to_string(),
|
name: "cp0".to_string(),
|
||||||
}],
|
}],
|
||||||
bootstrap_host: LogicalHost {
|
bootstrap_host: LogicalHost {
|
||||||
ip: ip!("10.100.8.20"),
|
ip: ip!("192.168.1.20"),
|
||||||
name: "cp0".to_string(),
|
name: "bootstrap".to_string(),
|
||||||
},
|
},
|
||||||
workers: vec![],
|
workers: vec![],
|
||||||
switch: vec![],
|
switch: vec![],
|
||||||
|
@ -29,6 +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 save_role_mapping(
|
async fn save_role_mapping(
|
||||||
&self,
|
&self,
|
||||||
role: &HostRole,
|
role: &HostRole,
|
||||||
|
@ -46,14 +46,15 @@ impl InventoryRepository for SqliteInventoryRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
let _row = sqlx::query_as!(
|
let row = sqlx::query_as!(
|
||||||
DbHost,
|
DbHost,
|
||||||
r#"SELECT id, version_id, data as "data: Json<PhysicalHost>" FROM physical_hosts WHERE id = ? ORDER BY version_id DESC LIMIT 1"#,
|
r#"SELECT id, version_id, data as "data: Json<PhysicalHost>" FROM physical_hosts WHERE id = ? ORDER BY version_id DESC LIMIT 1"#,
|
||||||
host_id
|
host_id
|
||||||
)
|
)
|
||||||
.fetch_optional(&self.pool)
|
.fetch_optional(&self.pool)
|
||||||
.await?;
|
.await?;
|
||||||
todo!()
|
|
||||||
|
Ok(row.map(|r| r.data.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_all_hosts(&self) -> Result<Vec<PhysicalHost>, RepoError> {
|
async fn get_all_hosts(&self) -> Result<Vec<PhysicalHost>, RepoError> {
|
||||||
@ -107,6 +108,36 @@ impl InventoryRepository for SqliteInventoryRepository {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
async fn get_host_for_role(&self, role: HostRole) -> Result<Vec<PhysicalHost>, RepoError> {
|
||||||
|
struct HostIdRow {
|
||||||
|
host_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let role_str = format!("{:?}", role);
|
||||||
|
|
||||||
|
let host_id_rows = sqlx::query_as!(
|
||||||
|
HostIdRow,
|
||||||
|
"SELECT host_id FROM host_role_mapping WHERE role = ?",
|
||||||
|
role_str
|
||||||
|
)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut hosts = Vec::with_capacity(host_id_rows.len());
|
||||||
|
for row in host_id_rows {
|
||||||
|
match self.get_latest_by_id(&row.host_id).await? {
|
||||||
|
Some(host) => hosts.push(host),
|
||||||
|
None => {
|
||||||
|
log::warn!(
|
||||||
|
"Found a role mapping for host_id '{}', but the host does not exist in the physical_hosts table. This may indicate a data integrity issue.",
|
||||||
|
row.host_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(hosts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use sqlx::types::Json;
|
use sqlx::types::Json;
|
||||||
@ -115,4 +146,3 @@ struct DbHost {
|
|||||||
id: String,
|
id: String,
|
||||||
version_id: String,
|
version_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use harmony_types::id::Id;
|
use harmony_types::id::Id;
|
||||||
use log::info;
|
use log::{info, trace};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -177,7 +177,7 @@ impl DhcpHostBindingInterpret {
|
|||||||
.collect();
|
.collect();
|
||||||
info!("DHCPStaticEntry : {:?}", dhcp_entries);
|
info!("DHCPStaticEntry : {:?}", dhcp_entries);
|
||||||
|
|
||||||
info!("DHCP server : {:?}", dhcp_server);
|
trace!("DHCP server : {:?}", dhcp_server);
|
||||||
|
|
||||||
let number_new_entries = dhcp_entries.len();
|
let number_new_entries = dhcp_entries.len();
|
||||||
|
|
||||||
|
@ -411,11 +411,22 @@ impl OKDSetup02BootstrapInterpret {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_bootstrap_node<'a>(&self, inventory: &'a Inventory) -> &'a PhysicalHost {
|
async fn get_bootstrap_node(
|
||||||
inventory
|
&self,
|
||||||
.worker_host
|
_inventory: &Inventory,
|
||||||
.first()
|
) -> Result<PhysicalHost, InterpretError> {
|
||||||
.expect("At least one worker host is required to be used as bootstrap node")
|
let repo = InventoryRepositoryFactory::build().await?;
|
||||||
|
match repo
|
||||||
|
.get_host_for_role(HostRole::Bootstrap)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
{
|
||||||
|
Some(host) => Ok(host),
|
||||||
|
None => Err(InterpretError::new(
|
||||||
|
"No bootstrap node available".to_string(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn configure_host_binding(
|
async fn configure_host_binding(
|
||||||
@ -425,7 +436,7 @@ impl OKDSetup02BootstrapInterpret {
|
|||||||
) -> Result<(), InterpretError> {
|
) -> Result<(), InterpretError> {
|
||||||
let binding = HostBinding {
|
let binding = HostBinding {
|
||||||
logical_host: topology.bootstrap_host.clone(),
|
logical_host: topology.bootstrap_host.clone(),
|
||||||
physical_host: self.get_bootstrap_node(inventory).clone(),
|
physical_host: self.get_bootstrap_node(inventory).await?,
|
||||||
};
|
};
|
||||||
info!("Configuring host binding for bootstrap node {binding:?}");
|
info!("Configuring host binding for bootstrap node {binding:?}");
|
||||||
|
|
||||||
@ -444,7 +455,7 @@ impl OKDSetup02BootstrapInterpret {
|
|||||||
) -> Result<(), InterpretError> {
|
) -> Result<(), InterpretError> {
|
||||||
// Placeholder: use Harmony templates to emit {MAC}.ipxe selecting SCOS live + bootstrap ignition.
|
// Placeholder: use Harmony templates to emit {MAC}.ipxe selecting SCOS live + bootstrap ignition.
|
||||||
info!("[Bootstrap] Rendering per-MAC PXE for bootstrap node");
|
info!("[Bootstrap] Rendering per-MAC PXE for bootstrap node");
|
||||||
let bootstrap_node = self.get_bootstrap_node(inventory);
|
let bootstrap_node = self.get_bootstrap_node(inventory).await?;
|
||||||
IPxeMacBootFileScore {
|
IPxeMacBootFileScore {
|
||||||
mac_address: bootstrap_node.get_mac_address(),
|
mac_address: bootstrap_node.get_mac_address(),
|
||||||
content: todo!("templace for bootstrap node"),
|
content: todo!("templace for bootstrap node"),
|
||||||
|
Loading…
Reference in New Issue
Block a user