feat: create score + example to create a machineconfig resource to configured system reserved parameters #262

Merged
johnride merged 2 commits from feat/system-reserved-machine-config into master 2026-04-15 14:41:13 +00:00
8 changed files with 214 additions and 0 deletions

25
Cargo.lock generated
View File

@@ -1262,6 +1262,22 @@ dependencies = [
"url",
]
[[package]]
name = "brocade-switch-oricom-configuration"
version = "0.1.0"
dependencies = [
"async-trait",
"brocade",
"env_logger",
"harmony",
"harmony_cli",
"harmony_macros",
"harmony_types",
"log",
"serde",
"tokio",
]
[[package]]
name = "brotli"
version = "8.0.2"
@@ -2889,6 +2905,15 @@ dependencies = [
"url",
]
[[package]]
name = "example-okd-system-reserved"
version = "0.1.0"
dependencies = [
"harmony",
"harmony_cli",
"tokio",
]
[[package]]
name = "example-openbao"
version = "0.1.0"

View File

@@ -0,0 +1,12 @@
[package]
name = "example-okd-system-reserved"
edition = "2024"
version.workspace = true
readme.workspace = true
license.workspace = true
publish = false
[dependencies]
harmony = { path = "../../harmony" }
harmony_cli = { path = "../../harmony_cli" }
tokio = { workspace = true }

View File

@@ -0,0 +1,5 @@
export HARMONY_SECRET_NAMESPACE=okd-system-reserved-example
export HARMONY_SECRET_STORE=file
export HARMONY_DATABASE_URL=sqlite://harmony_okd_system_reserved.sqlite
export HARMONY_USE_LOCAL_K3D=false
export RUST_LOG=harmony=debug

View File

@@ -0,0 +1,25 @@
use harmony::{
inventory::Inventory,
modules::okd::system_reserved_score::{MachineConfigPool, SystemReservedScore},
topology::K8sAnywhereTopology,
};
#[tokio::main]
async fn main() {
harmony_cli::cli_logger::init();
let master_score = SystemReservedScore {
pool: MachineConfigPool::Master,
memory: "0.5Gi".to_string(),
..Default::default()
};
harmony_cli::run(
Inventory::autoload(),
K8sAnywhereTopology::from_env(),
vec![Box::new(master_score)],
None,
)
.await
.unwrap();
}

View File

@@ -0,0 +1,47 @@
use k8s_openapi::apimachinery::pkg::apis::meta::v1::LabelSelector;
use kube::{CustomResource, api::ObjectMeta};
use serde::{Deserialize, Serialize};
#[derive(CustomResource, Deserialize, Serialize, Clone, Debug)]
#[kube(
group = "machineconfiguration.openshift.io",
version = "v1",
kind = "KubeletConfig",
plural = "kubeletconfigs",
namespaced = false,
schema = "disabled"
)]
#[serde(rename_all = "camelCase")]
pub struct KubeletConfigSpec {
pub machine_config_pool_selector: LabelSelector,
pub kubelet_config: KubeletConfigInner,
}
impl Default for KubeletConfig {
fn default() -> Self {
Self {
metadata: ObjectMeta::default(),
spec: KubeletConfigSpec {
machine_config_pool_selector: LabelSelector::default(),
kubelet_config: KubeletConfigInner::default(),
},
}
}
}
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct KubeletConfigInner {
#[serde(skip_serializing_if = "Option::is_none")]
pub system_reserved: Option<SystemReserved>,
}
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
pub struct SystemReserved {
#[serde(skip_serializing_if = "Option::is_none")]
pub memory: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpu: Option<String>,
#[serde(rename = "ephemeral-storage", skip_serializing_if = "Option::is_none")]
pub ephemeral_storage: Option<String>,
}

View File

@@ -1,3 +1,4 @@
pub mod ingresses_config;
pub mod kubelet_config;
pub mod nmstate;
pub mod route;

View File

@@ -26,3 +26,4 @@ pub use bootstrap_06_installation_report::*;
pub use bootstrap_persist_network_bond::*;
pub mod crd;
pub mod host_network;
pub mod system_reserved_score;

View File

@@ -0,0 +1,98 @@
use std::collections::BTreeMap;
use k8s_openapi::apimachinery::pkg::apis::meta::v1::LabelSelector;
use kube::api::ObjectMeta;
use serde::Serialize;
use crate::{
interpret::Interpret,
modules::{
k8s::resource::K8sResourceScore,
okd::crd::kubelet_config::{
KubeletConfig, KubeletConfigInner, KubeletConfigSpec, SystemReserved,
},
},
score::Score,
topology::{K8sclient, Topology},
};
#[derive(Debug, Clone, Copy, Serialize)]
pub enum MachineConfigPool {
Master,
Worker,
}
impl MachineConfigPool {
fn label_key(&self) -> &'static str {
match self {
Self::Master => "pools.operator.machineconfiguration.openshift.io/master",
Self::Worker => "pools.operator.machineconfiguration.openshift.io/worker",
}
}
fn default_resource_name(&self) -> &'static str {
match self {
Self::Master => "master-system-reserved",
Self::Worker => "worker-system-reserved",
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct SystemReservedScore {
pub pool: MachineConfigPool,
pub memory: String,
pub cpu: Option<String>,
pub ephemeral_storage: Option<String>,
pub resource_name: Option<String>,
}
impl Default for SystemReservedScore {
fn default() -> Self {
Self {
pool: MachineConfigPool::Master,
memory: "3.5Gi".to_string(),
cpu: None,
ephemeral_storage: None,
resource_name: None,
}
}
}
impl<T: Topology + K8sclient> Score<T> for SystemReservedScore {
fn name(&self) -> String {
"SystemReservedScore".to_string()
}
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
let mut match_labels = BTreeMap::new();
match_labels.insert(self.pool.label_key().to_string(), String::new());
let name = self
.resource_name
.clone()
.unwrap_or_else(|| self.pool.default_resource_name().to_string());
let kc = KubeletConfig {
metadata: ObjectMeta {
name: Some(name),
..Default::default()
},
spec: KubeletConfigSpec {
machine_config_pool_selector: LabelSelector {
match_labels: Some(match_labels),
match_expressions: None,
},
kubelet_config: KubeletConfigInner {
system_reserved: Some(SystemReserved {
memory: Some(self.memory.clone()),
cpu: self.cpu.clone(),
ephemeral_storage: self.ephemeral_storage.clone(),
}),
},
},
};
K8sResourceScore::single(kc, None).create_interpret()
}
}