diff --git a/harmony/src/domain/topology/k8s_anywhere.rs b/harmony/src/domain/topology/k8s_anywhere.rs index 9153b73..7743cae 100644 --- a/harmony/src/domain/topology/k8s_anywhere.rs +++ b/harmony/src/domain/topology/k8s_anywhere.rs @@ -15,9 +15,7 @@ use crate::{ }; use super::{ - HelmCommand, K8sclient, Topology, - k8s::K8sClient, - tenant::{ResourceLimits, TenantConfig, TenantManager, TenantNetworkPolicy}, + k8s::K8sClient, tenant::{k8s::K8sTenantManager, ResourceLimits, TenantConfig, TenantManager, TenantNetworkPolicy}, HelmCommand, K8sclient, Topology }; struct K8sState { @@ -34,8 +32,10 @@ enum K8sSource { pub struct K8sAnywhereTopology { k8s_state: OnceCell>, + tenant_manager: K8sTenantManager, } + #[async_trait] impl K8sclient for K8sAnywhereTopology { async fn k8s_client(&self) -> Result, String> { @@ -216,80 +216,29 @@ impl Topology for K8sAnywhereTopology { impl HelmCommand for K8sAnywhereTopology {} +#[async_trait] impl TenantManager for K8sAnywhereTopology { - fn provision_tenant<'life0, 'life1, 'async_trait>( - &'life0 self, - config: &'life1 TenantConfig, - ) -> ::core::pin::Pin< - Box< - dyn ::core::future::Future> - + ::core::marker::Send - + 'async_trait, - >, - > - where - 'life0: 'async_trait, - 'life1: 'async_trait, - Self: 'async_trait, - { - todo!() + async fn provision_tenant(&self, config: &TenantConfig) -> Result<(), ExecutorError> { + self.tenant_manager.provision_tenant(config).await } - fn update_tenant_resource_limits<'life0, 'life1, 'life2, 'async_trait>( - &'life0 self, - tenant_name: &'life1 str, - new_limits: &'life2 ResourceLimits, - ) -> ::core::pin::Pin< - Box< - dyn ::core::future::Future> - + ::core::marker::Send - + 'async_trait, - >, - > - where - 'life0: 'async_trait, - 'life1: 'async_trait, - 'life2: 'async_trait, - Self: 'async_trait, - { - todo!() + async fn update_tenant_resource_limits( + &self, + tenant_name: &str, + new_limits: &ResourceLimits, + ) -> Result<(), ExecutorError> { + self.tenant_manager.update_tenant_resource_limits(tenant_name, new_limits).await } - fn update_tenant_network_policy<'life0, 'life1, 'life2, 'async_trait>( - &'life0 self, - tenant_name: &'life1 str, - new_policy: &'life2 TenantNetworkPolicy, - ) -> ::core::pin::Pin< - Box< - dyn ::core::future::Future> - + ::core::marker::Send - + 'async_trait, - >, - > - where - 'life0: 'async_trait, - 'life1: 'async_trait, - 'life2: 'async_trait, - Self: 'async_trait, - { - todo!() + async fn update_tenant_network_policy( + &self, + tenant_name: &str, + new_policy: &TenantNetworkPolicy, + ) -> Result<(), ExecutorError> { + self.tenant_manager.update_tenant_network_policy(tenant_name, new_policy).await } - fn deprovision_tenant<'life0, 'life1, 'async_trait>( - &'life0 self, - tenant_name: &'life1 str, - ) -> ::core::pin::Pin< - Box< - dyn ::core::future::Future> - + ::core::marker::Send - + 'async_trait, - >, - > - where - 'life0: 'async_trait, - 'life1: 'async_trait, - Self: 'async_trait, - { - todo!() + async fn deprovision_tenant(&self, tenant_name: &str) -> Result<(), ExecutorError> { + self.tenant_manager.deprovision_tenant(tenant_name).await } } diff --git a/harmony/src/domain/topology/tenant/k8s.rs b/harmony/src/domain/topology/tenant/k8s.rs new file mode 100644 index 0000000..24837a0 --- /dev/null +++ b/harmony/src/domain/topology/tenant/k8s.rs @@ -0,0 +1,88 @@ +use std::sync::Arc; + +use crate::{executors::ExecutorError, topology::k8s::K8sClient}; +use async_trait::async_trait; +use k8s_openapi::api::core::v1::Namespace; +use serde_json::json; + +use super::{ResourceLimits, TenantConfig, TenantManager, TenantNetworkPolicy}; + +pub struct K8sTenantManager { + k8s_client: Arc, +} + +#[async_trait] +impl TenantManager for K8sTenantManager { + async fn provision_tenant(&self, config: &TenantConfig) -> Result<(), ExecutorError> { + let namespace = json!( + { + "apiVersion": "v1", + "kind": "Namespace", + "metadata": { + "labels": { + "harmony.nationtech.io/tenant.id": config.id, + "name": config.name, + + }, + "name": config.name, + }, + } + ); + todo!("Validate that when tenant already exists (by id) that name has not changed"); + + let namespace: Namespace = serde_json::from_value(namespace).unwrap(); + + + let resource_quota = json!( + { + "apiVersion": "v1", + "kind": "List", + "items": [ + { + "apiVersion": "v1", + "kind": "ResourceQuota", + "metadata": { + "name": config.name + }, + "spec": { + "hard": { + "cpu": config.resource_limits.cpu_limit_cores, + "memory": format!("{:.3}Gi", config.resource_limits.memory_limit_gb), + }, + "scopeSelector": { + "matchExpressions": [ + { + "operator": "In", + "scopeName": "PriorityClass", + "values": ["high"] + } + ] + } + } + } + ] + } + + ); + } + + async fn update_tenant_resource_limits( + &self, + tenant_name: &str, + new_limits: &ResourceLimits, + ) -> Result<(), ExecutorError> { + todo!() + } + + async fn update_tenant_network_policy( + &self, + tenant_name: &str, + new_policy: &TenantNetworkPolicy, + ) -> Result<(), ExecutorError> { + todo!() + } + + async fn deprovision_tenant(&self, tenant_name: &str) -> Result<(), ExecutorError> { + todo!() + } +} diff --git a/harmony/src/domain/topology/tenant/mod.rs b/harmony/src/domain/topology/tenant/mod.rs index 0704a34..dc016e7 100644 --- a/harmony/src/domain/topology/tenant/mod.rs +++ b/harmony/src/domain/topology/tenant/mod.rs @@ -1,4 +1,5 @@ mod manager; +pub mod k8s; pub use manager::*; use serde::{Deserialize, Serialize}; @@ -29,17 +30,17 @@ pub struct TenantConfig { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] pub struct ResourceLimits { /// Requested/guaranteed CPU cores (e.g., 2.0). - pub cpu_request_cores: Option, + pub cpu_request_cores: f32, /// Maximum CPU cores the tenant can burst to (e.g., 4.0). - pub cpu_limit_cores: Option, + pub cpu_limit_cores: f32, /// Requested/guaranteed memory in Gigabytes (e.g., 8.0). - pub memory_request_gb: Option, + pub memory_request_gb: f32, /// Maximum memory in Gigabytes tenant can burst to (e.g., 16.0). - pub memory_limit_gb: Option, + pub memory_limit_gb: f32, /// Total persistent storage allocation in Gigabytes across all volumes. - pub storage_total_gb: Option, + pub storage_total_gb: f32, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]