TenantManager_impl_k8s_anywhere #47
@ -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