From 2ff70db0b1d0bbdc833b0f917759daf8d1677d5d Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Fri, 6 Jun 2025 13:52:40 -0400 Subject: [PATCH] wip: Tenant example project --- Cargo.lock | 15 ++++ adr/tenant/NetworkPolicy.yaml | 41 ++++++++++ adr/tenant/TestDeployment.yaml | 95 +++++++++++++++++++++++ harmony/src/domain/data/id.rs | 6 ++ harmony/src/domain/topology/tenant/mod.rs | 22 ++++++ harmony/src/modules/tenant/mod.rs | 2 +- 6 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 adr/tenant/NetworkPolicy.yaml create mode 100644 adr/tenant/TestDeployment.yaml diff --git a/Cargo.lock b/Cargo.lock index 7c721b1..ded4c85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1070,6 +1070,21 @@ dependencies = [ "url", ] +[[package]] +name = "example-tenant" +version = "0.1.0" +dependencies = [ + "cidr", + "env_logger", + "harmony", + "harmony_cli", + "harmony_macros", + "harmony_types", + "log", + "tokio", + "url", +] + [[package]] name = "example-tui" version = "0.1.0" diff --git a/adr/tenant/NetworkPolicy.yaml b/adr/tenant/NetworkPolicy.yaml new file mode 100644 index 0000000..5bb1c71 --- /dev/null +++ b/adr/tenant/NetworkPolicy.yaml @@ -0,0 +1,41 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: tenant-isolation-policy + namespace: testtenant +spec: + podSelector: {} # Selects all pods in the namespace + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: {} # Allow from all pods in the same namespace + egress: + - to: + - podSelector: {} # Allow to all pods in the same namespace + - to: + - podSelector: {} + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: openshift-dns # Target the openshift-dns namespace + # Note, only opening port 53 is not enough, will have to dig deeper into this one eventually + # ports: + # - protocol: UDP + # port: 53 + # - protocol: TCP + # port: 53 + # Allow egress to public internet only + - to: + - ipBlock: + cidr: 0.0.0.0/0 + except: + - 10.0.0.0/8 # RFC1918 + - 172.16.0.0/12 # RFC1918 + - 192.168.0.0/16 # RFC1918 + - 169.254.0.0/16 # Link-local + - 127.0.0.0/8 # Loopback + - 224.0.0.0/4 # Multicast + - 240.0.0.0/4 # Reserved + - 100.64.0.0/10 # Carrier-grade NAT + - 0.0.0.0/8 # Reserved diff --git a/adr/tenant/TestDeployment.yaml b/adr/tenant/TestDeployment.yaml new file mode 100644 index 0000000..a075ba8 --- /dev/null +++ b/adr/tenant/TestDeployment.yaml @@ -0,0 +1,95 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: testtenant +--- +apiVersion: v1 +kind: Namespace +metadata: + name: testtenant2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-web + namespace: testtenant +spec: + replicas: 1 + selector: + matchLabels: + app: test-web + template: + metadata: + labels: + app: test-web + spec: + containers: + - name: nginx + image: nginxinc/nginx-unprivileged + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: test-web + namespace: testtenant +spec: + selector: + app: test-web + ports: + - port: 80 + targetPort: 8080 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-client + namespace: testtenant +spec: + replicas: 1 + selector: + matchLabels: + app: test-client + template: + metadata: + labels: + app: test-client + spec: + containers: + - name: curl + image: curlimages/curl:latest + command: ["/bin/sh", "-c", "sleep 3600"] +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-web + namespace: testtenant2 +spec: + replicas: 1 + selector: + matchLabels: + app: test-web + template: + metadata: + labels: + app: test-web + spec: + containers: + - name: nginx + image: nginxinc/nginx-unprivileged + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: test-web + namespace: testtenant2 +spec: + selector: + app: test-web + ports: + - port: 80 + targetPort: 8080 diff --git a/harmony/src/domain/data/id.rs b/harmony/src/domain/data/id.rs index e215eb4..b9f9e7a 100644 --- a/harmony/src/domain/data/id.rs +++ b/harmony/src/domain/data/id.rs @@ -16,3 +16,9 @@ impl std::fmt::Display for Id { f.write_str(&self.value) } } + +impl Default for Id { + fn default() -> Self { + todo!() + } +} diff --git a/harmony/src/domain/topology/tenant/mod.rs b/harmony/src/domain/topology/tenant/mod.rs index e1e93a2..4bbefef 100644 --- a/harmony/src/domain/topology/tenant/mod.rs +++ b/harmony/src/domain/topology/tenant/mod.rs @@ -27,6 +27,28 @@ pub struct TenantConfig { pub labels_or_tags: HashMap, } +impl Default for TenantConfig { + fn default() -> Self { + let id = Id::default(); + Self { + name: format!("tenant_{id}"), + id, + resource_limits: ResourceLimits { + cpu_request_cores: 4.0, + cpu_limit_cores: 4.0, + memory_request_gb: 4.0, + memory_limit_gb: 4.0, + storage_total_gb: 20.0, + }, + network_policy: TenantNetworkPolicy { + default_inter_tenant_ingress: InterTenantIngressPolicy::DenyAll, + default_internet_egress: InternetEgressPolicy::AllowAll, + }, + labels_or_tags: HashMap::new(), + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] pub struct ResourceLimits { /// Requested/guaranteed CPU cores (e.g., 2.0). diff --git a/harmony/src/modules/tenant/mod.rs b/harmony/src/modules/tenant/mod.rs index 5ee212c..72412ec 100644 --- a/harmony/src/modules/tenant/mod.rs +++ b/harmony/src/modules/tenant/mod.rs @@ -14,7 +14,7 @@ use crate::{ #[derive(Debug, Serialize, Clone)] pub struct TenantScore { - config: TenantConfig, + pub config: TenantConfig, } impl Score for TenantScore {