feat: Tenant manager k8s implementation progress : ResourceQuota, NetworkPolicy and Namespace look good. Still WIP
This commit is contained in:
parent
8c65aef127
commit
6cf61ae67c
@ -1,9 +1,17 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{executors::ExecutorError, topology::k8s::K8sClient};
|
||||
use crate::{data::Id, executors::ExecutorError, topology::k8s::K8sClient};
|
||||
use async_trait::async_trait;
|
||||
use derive_new::new;
|
||||
use k8s_openapi::api::core::v1::Namespace;
|
||||
use k8s_openapi::{
|
||||
NamespaceResourceScope,
|
||||
api::{
|
||||
core::v1::{Namespace, ResourceQuota},
|
||||
networking::v1::NetworkPolicy,
|
||||
},
|
||||
};
|
||||
use kube::Resource;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde_json::json;
|
||||
|
||||
use super::{ResourceLimits, TenantConfig, TenantManager, TenantNetworkPolicy};
|
||||
@ -13,9 +21,29 @@ pub struct K8sTenantManager {
|
||||
k8s_client: Arc<K8sClient>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TenantManager for K8sTenantManager {
|
||||
async fn provision_tenant(&self, config: &TenantConfig) -> Result<(), ExecutorError> {
|
||||
impl K8sTenantManager {
|
||||
fn get_namespace_name(&self, config: &TenantConfig) -> String {
|
||||
config.name.clone()
|
||||
}
|
||||
|
||||
fn ensure_constraints(&self, namespace: &Namespace) -> Result<(), ExecutorError> {
|
||||
todo!("Validate that when tenant already exists (by id) that name has not changed");
|
||||
todo!("Make sure other Tenant constraints are respected by this k8s implementation");
|
||||
}
|
||||
|
||||
async fn apply_resource<
|
||||
K: Resource + std::fmt::Debug + Sync + DeserializeOwned + Default + serde::Serialize + Clone,
|
||||
>(
|
||||
&self,
|
||||
resource: K,
|
||||
) -> Result<K, ExecutorError>
|
||||
where
|
||||
<K as kube::Resource>::DynamicType: Default,
|
||||
{
|
||||
todo!("Apply tenant labels on resource and apply resource with k8s client properly")
|
||||
}
|
||||
|
||||
fn build_namespace(&self, config: &TenantConfig) -> Result<Namespace, ExecutorError> {
|
||||
let namespace = json!(
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
@ -25,14 +53,19 @@ impl TenantManager for K8sTenantManager {
|
||||
"harmony.nationtech.io/tenant.id": config.id,
|
||||
"harmony.nationtech.io/tenant.name": config.name,
|
||||
},
|
||||
"name": config.name,
|
||||
"name": self.get_namespace_name(config),
|
||||
},
|
||||
}
|
||||
);
|
||||
todo!("Validate that when tenant already exists (by id) that name has not changed");
|
||||
|
||||
let namespace: Namespace = serde_json::from_value(namespace).unwrap();
|
||||
serde_json::from_value(namespace).map_err(|e| {
|
||||
ExecutorError::ConfigurationError(format!(
|
||||
"Could not build TenantManager Namespace. {}",
|
||||
e
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_resource_quota(&self, config: &TenantConfig) -> Result<ResourceQuota, ExecutorError> {
|
||||
let resource_quota = json!(
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
@ -47,7 +80,7 @@ impl TenantManager for K8sTenantManager {
|
||||
"harmony.nationtech.io/tenant.id": config.id,
|
||||
"harmony.nationtech.io/tenant.name": config.name,
|
||||
},
|
||||
"namespace": config.name,
|
||||
"namespace": self.get_namespace_name(config),
|
||||
},
|
||||
"spec": {
|
||||
"hard": {
|
||||
@ -71,7 +104,15 @@ impl TenantManager for K8sTenantManager {
|
||||
}
|
||||
|
||||
);
|
||||
serde_json::from_value(resource_quota).map_err(|e| {
|
||||
ExecutorError::ConfigurationError(format!(
|
||||
"Could not build TenantManager ResourceQuota. {}",
|
||||
e
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_network_policy(&self, config: &TenantConfig) -> Result<NetworkPolicy, ExecutorError> {
|
||||
let network_policy = json!({
|
||||
"apiVersion": "networking.k8s.io/v1",
|
||||
"kind": "NetworkPolicy",
|
||||
@ -80,17 +121,87 @@ impl TenantManager for K8sTenantManager {
|
||||
},
|
||||
"spec": {
|
||||
"podSelector": {},
|
||||
"egress": [],
|
||||
"ingress": [],
|
||||
"egress": [
|
||||
{ "to": [ {"podSelector": {}}]},
|
||||
{ "to":
|
||||
[
|
||||
{
|
||||
"podSelector": {},
|
||||
"namespaceSelector": {
|
||||
"matchLabels": {
|
||||
"kubernetes.io/metadata.name":"openshift-dns"
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{ "to": [
|
||||
{
|
||||
"ipBlock": {
|
||||
|
||||
"cidr": "0.0.0.0/0",
|
||||
// See https://en.wikipedia.org/wiki/Reserved_IP_addresses
|
||||
"except": [
|
||||
"10.0.0.0/8",
|
||||
"172.16.0.0/12",
|
||||
"192.168.0.0/16",
|
||||
"192.0.0.0/24",
|
||||
"192.0.2.0/24",
|
||||
"192.88.99.0/24",
|
||||
"192.18.0.0/15",
|
||||
"198.51.100.0/24",
|
||||
"169.254.0.0/16",
|
||||
"203.0.113.0/24",
|
||||
"127.0.0.0/8",
|
||||
|
||||
// Not sure we should block this one as it is
|
||||
// used for multicast. But better block more than less.
|
||||
"224.0.0.0/4",
|
||||
"240.0.0.0/4",
|
||||
"100.64.0.0/10",
|
||||
"233.252.0.0/24",
|
||||
"0.0.0.0/8",
|
||||
],
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
"ingress": [
|
||||
{ "from": [ {"podSelector": {}}]}
|
||||
],
|
||||
"policyTypes": [
|
||||
"Ingress", "Egress",
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
serde_json::from_value(network_policy).map_err(|e| {
|
||||
ExecutorError::ConfigurationError(format!(
|
||||
"Could not build TenantManager NetworkPolicy. {}",
|
||||
e
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TenantManager for K8sTenantManager {
|
||||
async fn provision_tenant(&self, config: &TenantConfig) -> Result<(), ExecutorError> {
|
||||
let namespace = self.build_namespace(config)?;
|
||||
let resource_quota = self.build_resource_quota(config)?;
|
||||
let network_policy = self.build_network_policy(config)?;
|
||||
|
||||
self.ensure_constraints(&namespace)?;
|
||||
self.apply_resource(namespace).await?;
|
||||
self.apply_resource(resource_quota).await?;
|
||||
self.apply_resource(network_policy).await?;
|
||||
todo!();
|
||||
}
|
||||
|
||||
async fn update_tenant_resource_limits(
|
||||
&self,
|
||||
tenant_name: &str,
|
||||
tenant_id: &Id,
|
||||
new_limits: &ResourceLimits,
|
||||
) -> Result<(), ExecutorError> {
|
||||
todo!()
|
||||
@ -98,13 +209,13 @@ impl TenantManager for K8sTenantManager {
|
||||
|
||||
async fn update_tenant_network_policy(
|
||||
&self,
|
||||
tenant_name: &str,
|
||||
tenant_id: &Id,
|
||||
new_policy: &TenantNetworkPolicy,
|
||||
) -> Result<(), ExecutorError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn deprovision_tenant(&self, tenant_name: &str) -> Result<(), ExecutorError> {
|
||||
async fn deprovision_tenant(&self, tenant_id: &Id) -> Result<(), ExecutorError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -16,31 +16,20 @@ pub trait TenantManager {
|
||||
async fn provision_tenant(&self, config: &TenantConfig) -> Result<(), ExecutorError>;
|
||||
|
||||
/// Updates the resource limits for an existing tenant.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `tenant_name`: The logical name of the tenant to update.
|
||||
/// * `new_limits`: The new set of resource limits to apply.
|
||||
async fn update_tenant_resource_limits(
|
||||
&self,
|
||||
tenant_name: &str,
|
||||
tenant_id: &Id,
|
||||
new_limits: &ResourceLimits,
|
||||
) -> Result<(), ExecutorError>;
|
||||
|
||||
/// Updates the high-level network isolation policy for an existing tenant.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `tenant_name`: The logical name of the tenant to update.
|
||||
/// * `new_policy`: The new network policy to apply.
|
||||
async fn update_tenant_network_policy(
|
||||
&self,
|
||||
tenant_name: &str,
|
||||
tenant_id: &Id,
|
||||
new_policy: &TenantNetworkPolicy,
|
||||
) -> Result<(), ExecutorError>;
|
||||
|
||||
/// Decommissions an existing tenant, removing its isolated context and associated resources.
|
||||
/// This operation should be idempotent.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `tenant_name`: The logical name of the tenant to deprovision.
|
||||
async fn deprovision_tenant(&self, tenant_name: &str) -> Result<(), ExecutorError>;
|
||||
async fn deprovision_tenant(&self, tenant_id: &Id) -> Result<(), ExecutorError>;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user