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 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 async_trait::async_trait;
|
||||||
use derive_new::new;
|
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 serde_json::json;
|
||||||
|
|
||||||
use super::{ResourceLimits, TenantConfig, TenantManager, TenantNetworkPolicy};
|
use super::{ResourceLimits, TenantConfig, TenantManager, TenantNetworkPolicy};
|
||||||
@ -13,9 +21,29 @@ pub struct K8sTenantManager {
|
|||||||
k8s_client: Arc<K8sClient>,
|
k8s_client: Arc<K8sClient>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl K8sTenantManager {
|
||||||
impl TenantManager for K8sTenantManager {
|
fn get_namespace_name(&self, config: &TenantConfig) -> String {
|
||||||
async fn provision_tenant(&self, config: &TenantConfig) -> Result<(), ExecutorError> {
|
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!(
|
let namespace = json!(
|
||||||
{
|
{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
@ -25,14 +53,19 @@ impl TenantManager for K8sTenantManager {
|
|||||||
"harmony.nationtech.io/tenant.id": config.id,
|
"harmony.nationtech.io/tenant.id": config.id,
|
||||||
"harmony.nationtech.io/tenant.name": config.name,
|
"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");
|
serde_json::from_value(namespace).map_err(|e| {
|
||||||
|
ExecutorError::ConfigurationError(format!(
|
||||||
let namespace: Namespace = serde_json::from_value(namespace).unwrap();
|
"Could not build TenantManager Namespace. {}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_resource_quota(&self, config: &TenantConfig) -> Result<ResourceQuota, ExecutorError> {
|
||||||
let resource_quota = json!(
|
let resource_quota = json!(
|
||||||
{
|
{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
@ -47,7 +80,7 @@ impl TenantManager for K8sTenantManager {
|
|||||||
"harmony.nationtech.io/tenant.id": config.id,
|
"harmony.nationtech.io/tenant.id": config.id,
|
||||||
"harmony.nationtech.io/tenant.name": config.name,
|
"harmony.nationtech.io/tenant.name": config.name,
|
||||||
},
|
},
|
||||||
"namespace": config.name,
|
"namespace": self.get_namespace_name(config),
|
||||||
},
|
},
|
||||||
"spec": {
|
"spec": {
|
||||||
"hard": {
|
"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!({
|
let network_policy = json!({
|
||||||
"apiVersion": "networking.k8s.io/v1",
|
"apiVersion": "networking.k8s.io/v1",
|
||||||
"kind": "NetworkPolicy",
|
"kind": "NetworkPolicy",
|
||||||
@ -80,17 +121,87 @@ impl TenantManager for K8sTenantManager {
|
|||||||
},
|
},
|
||||||
"spec": {
|
"spec": {
|
||||||
"podSelector": {},
|
"podSelector": {},
|
||||||
"egress": [],
|
"egress": [
|
||||||
"ingress": [],
|
{ "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": [
|
"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(
|
async fn update_tenant_resource_limits(
|
||||||
&self,
|
&self,
|
||||||
tenant_name: &str,
|
tenant_id: &Id,
|
||||||
new_limits: &ResourceLimits,
|
new_limits: &ResourceLimits,
|
||||||
) -> Result<(), ExecutorError> {
|
) -> Result<(), ExecutorError> {
|
||||||
todo!()
|
todo!()
|
||||||
@ -98,13 +209,13 @@ impl TenantManager for K8sTenantManager {
|
|||||||
|
|
||||||
async fn update_tenant_network_policy(
|
async fn update_tenant_network_policy(
|
||||||
&self,
|
&self,
|
||||||
tenant_name: &str,
|
tenant_id: &Id,
|
||||||
new_policy: &TenantNetworkPolicy,
|
new_policy: &TenantNetworkPolicy,
|
||||||
) -> Result<(), ExecutorError> {
|
) -> Result<(), ExecutorError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn deprovision_tenant(&self, tenant_name: &str) -> Result<(), ExecutorError> {
|
async fn deprovision_tenant(&self, tenant_id: &Id) -> Result<(), ExecutorError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,31 +16,20 @@ pub trait TenantManager {
|
|||||||
async fn provision_tenant(&self, config: &TenantConfig) -> Result<(), ExecutorError>;
|
async fn provision_tenant(&self, config: &TenantConfig) -> Result<(), ExecutorError>;
|
||||||
|
|
||||||
/// Updates the resource limits for an existing tenant.
|
/// 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(
|
async fn update_tenant_resource_limits(
|
||||||
&self,
|
&self,
|
||||||
tenant_name: &str,
|
tenant_id: &Id,
|
||||||
new_limits: &ResourceLimits,
|
new_limits: &ResourceLimits,
|
||||||
) -> Result<(), ExecutorError>;
|
) -> Result<(), ExecutorError>;
|
||||||
|
|
||||||
/// Updates the high-level network isolation policy for an existing tenant.
|
/// 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(
|
async fn update_tenant_network_policy(
|
||||||
&self,
|
&self,
|
||||||
tenant_name: &str,
|
tenant_id: &Id,
|
||||||
new_policy: &TenantNetworkPolicy,
|
new_policy: &TenantNetworkPolicy,
|
||||||
) -> Result<(), ExecutorError>;
|
) -> Result<(), ExecutorError>;
|
||||||
|
|
||||||
/// Decommissions an existing tenant, removing its isolated context and associated resources.
|
/// Decommissions an existing tenant, removing its isolated context and associated resources.
|
||||||
/// This operation should be idempotent.
|
/// This operation should be idempotent.
|
||||||
///
|
async fn deprovision_tenant(&self, tenant_id: &Id) -> Result<(), ExecutorError>;
|
||||||
/// # Arguments
|
|
||||||
/// * `tenant_name`: The logical name of the tenant to deprovision.
|
|
||||||
async fn deprovision_tenant(&self, tenant_name: &str) -> Result<(), ExecutorError>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user