feat(OKDInstallation): Implemented bootstrap of okd worker node, added features to allow both control plane and worker node to use the same bootstrap_okd_node score #198

Merged
wjro merged 2 commits from feat/okd-nodes into master 2025-12-10 19:27:51 +00:00
7 changed files with 395 additions and 292 deletions
Showing only changes of commit d5fadf4f44 - Show all commits

View File

@@ -71,7 +71,6 @@ pub enum HostRole {
Bootstrap, Bootstrap,
ControlPlane, ControlPlane,
Worker, Worker,
Storage,
} }
impl fmt::Display for HostRole { impl fmt::Display for HostRole {
@@ -80,7 +79,6 @@ impl fmt::Display for HostRole {
HostRole::Bootstrap => write!(f, "Bootstrap"), HostRole::Bootstrap => write!(f, "Bootstrap"),
HostRole::ControlPlane => write!(f, "ControlPlane"), HostRole::ControlPlane => write!(f, "ControlPlane"),
HostRole::Worker => write!(f, "Worker"), HostRole::Worker => write!(f, "Worker"),
HostRole::Storage => write!(f, "Storage"),
} }
} }
} }

View File

@@ -1,22 +1,8 @@
use crate::{ use crate::{
data::Version, interpret::Interpret, inventory::HostRole, modules::okd::bootstrap_okd_node::OKDNodeInterpret,
hardware::PhysicalHost, score::Score, topology::HAClusterTopology,
infra::inventory::InventoryRepositoryFactory,
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::{HostRole, Inventory},
modules::{
dhcp::DhcpHostBindingScore,
http::IPxeMacBootFileScore,
inventory::DiscoverHostForRoleScore,
okd::{bootstrap_okd_node::OKDNodeInterpret, templates::BootstrapIpxeTpl},
},
score::Score,
topology::{HAClusterTopology, HostBinding},
}; };
use async_trait::async_trait;
use derive_new::new; use derive_new::new;
use harmony_types::id::Id;
use log::{debug, info};
use serde::Serialize; use serde::Serialize;
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
@@ -30,64 +16,13 @@ pub struct OKDSetup03ControlPlaneScore {}
impl Score<HAClusterTopology> for OKDSetup03ControlPlaneScore { impl Score<HAClusterTopology> for OKDSetup03ControlPlaneScore {
fn create_interpret(&self) -> Box<dyn Interpret<HAClusterTopology>> { fn create_interpret(&self) -> Box<dyn Interpret<HAClusterTopology>> {
Box::new(OKDSetup03ControlPlaneInterpret::new()) // TODO: Implement a step to wait for the control plane nodes to join the cluster
// and for the cluster operators to become available. This would be similar to
// the `wait-for bootstrap-complete` command.
Box::new(OKDNodeInterpret::new(HostRole::ControlPlane))
} }
fn name(&self) -> String { fn name(&self) -> String {
"OKDSetup03ControlPlaneScore".to_string() "OKDSetup03ControlPlaneScore".to_string()
} }
} }
#[derive(Debug, Clone)]
pub struct OKDSetup03ControlPlaneInterpret {
version: Version,
status: InterpretStatus,
}
impl OKDSetup03ControlPlaneInterpret {
pub fn new() -> Self {
let version = Version::from("1.0.0").unwrap();
Self {
version,
status: InterpretStatus::QUEUED,
}
}
}
#[async_trait]
impl Interpret<HAClusterTopology> for OKDSetup03ControlPlaneInterpret {
fn get_name(&self) -> InterpretName {
InterpretName::Custom("OKDSetup03ControlPlane")
}
fn get_version(&self) -> Version {
self.version.clone()
}
fn get_status(&self) -> InterpretStatus {
self.status.clone()
}
fn get_children(&self) -> Vec<Id> {
vec![]
}
async fn execute(
&self,
inventory: &Inventory,
topology: &HAClusterTopology,
) -> Result<Outcome, InterpretError> {
OKDNodeInterpret::new(HostRole::ControlPlane)
.execute(inventory, topology)
.await?;
// TODO: Implement a step to wait for the control plane nodes to join the cluster
// and for the cluster operators to become available. This would be similar to
// the `wait-for bootstrap-complete` command.
info!("[ControlPlane] Provisioning initiated. Monitor the cluster convergence manually.");
Ok(Outcome::success(
"Control plane provisioning has been successfully initiated.".into(),
))
}
}

View File

@@ -1,15 +1,9 @@
use async_trait::async_trait;
use derive_new::new; use derive_new::new;
use harmony_types::id::Id;
use serde::Serialize; use serde::Serialize;
use crate::{ use crate::{
data::Version, interpret::Interpret, inventory::HostRole, modules::okd::bootstrap_okd_node::OKDNodeInterpret,
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}, score::Score, topology::HAClusterTopology,
inventory::{HostRole, Inventory},
modules::okd::bootstrap_okd_node::OKDNodeInterpret,
score::Score,
topology::HAClusterTopology,
}; };
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
@@ -23,56 +17,10 @@ pub struct OKDSetup04WorkersScore {}
impl Score<HAClusterTopology> for OKDSetup04WorkersScore { impl Score<HAClusterTopology> for OKDSetup04WorkersScore {
fn create_interpret(&self) -> Box<dyn Interpret<HAClusterTopology>> { fn create_interpret(&self) -> Box<dyn Interpret<HAClusterTopology>> {
Box::new(OKDSetup04WorkersInterpret::new()) Box::new(OKDNodeInterpret::new(HostRole::Worker))
} }
fn name(&self) -> String { fn name(&self) -> String {
"OKDSetup04WorkersScore".to_string() "OKDSetup04WorkersScore".to_string()
} }
} }
#[derive(Debug, Clone)]
pub struct OKDSetup04WorkersInterpret {
version: Version,
status: InterpretStatus,
}
impl OKDSetup04WorkersInterpret {
pub fn new() -> Self {
let version = Version::from("1.0.0").unwrap();
Self {
version,
status: InterpretStatus::QUEUED,
}
}
}
#[async_trait]
impl Interpret<HAClusterTopology> for OKDSetup04WorkersInterpret {
fn get_name(&self) -> InterpretName {
InterpretName::Custom("OKDSetup04Workers")
}
fn get_version(&self) -> Version {
self.version.clone()
}
fn get_status(&self) -> InterpretStatus {
self.status.clone()
}
fn get_children(&self) -> Vec<Id> {
vec![]
}
async fn execute(
&self,
inventory: &Inventory,
topology: &HAClusterTopology,
) -> Result<Outcome, InterpretError> {
OKDNodeInterpret::new(HostRole::Worker)
.execute(inventory, topology)
.await?;
Ok(Outcome::success("Workers provisioned".into()))
}
}

View File

@@ -26,11 +26,11 @@ use crate::{
}; };
#[derive(Debug, Clone, Serialize, new)] #[derive(Debug, Clone, Serialize, new)]
pub struct OKDNodeScore { pub struct OKDNodeInstallationScore {
host_role: HostRole, host_role: HostRole,
} }
impl Score<HAClusterTopology> for OKDNodeScore { impl Score<HAClusterTopology> for OKDNodeInstallationScore {
fn name(&self) -> String { fn name(&self) -> String {
"OKDNodeScore".to_string() "OKDNodeScore".to_string()
} }
@@ -55,7 +55,6 @@ impl OKDNodeInterpret {
HostRole::Bootstrap => &BootstrapRole, HostRole::Bootstrap => &BootstrapRole,
HostRole::ControlPlane => &ControlPlaneRole, HostRole::ControlPlane => &ControlPlaneRole,
HostRole::Worker => &WorkerRole, HostRole::Worker => &WorkerRole,
HostRole::Storage => &StorageRole,
} }
} }
@@ -263,10 +262,18 @@ impl Interpret<HAClusterTopology> for OKDNodeInterpret {
// 4. Reboot the nodes to start the OS installation. // 4. Reboot the nodes to start the OS installation.
self.reboot_targets(&nodes).await?; self.reboot_targets(&nodes).await?;
// TODO: Implement a step to validate that the installation of the nodes is
// TODO: Implement a step to wait for the control plane nodes to join the cluster // complete and for the cluster operators to become available.
// and for the cluster operators to become available. This would be similar to //
// the `wait-for bootstrap-complete` command. // The OpenShift installer only provides two wait commands which currently need to be
// run manually:
// - `openshift-install wait-for bootstrap-complete`
// - `openshift-install wait-for install-complete`
//
// There is no installer command that waits specifically for worker node
// provisioning. Worker nodes join asynchronously (via ignition + CSR approval),
// and the cluster becomes fully functional only once all nodes are Ready and the
// cluster operators report Available=True.
info!( info!(
"[{}] Provisioning initiated. Monitor the cluster convergence manually.", "[{}] Provisioning initiated. Monitor the cluster convergence manually.",
self.host_role self.host_role

View File

@@ -52,18 +52,3 @@ impl OKDRoleProperties for WorkerRole {
&t.workers &t.workers
} }
} }
//TODO unsure if this is to be implemented here or not
impl OKDRoleProperties for StorageRole {
fn ignition_file(&self) -> &'static str {
todo!()
}
fn required_hosts(&self) -> usize {
todo!()
}
fn logical_hosts<'a>(&self, t: &'a HAClusterTopology) -> &'a Vec<LogicalHost> {
todo!()
}
}