From 99e121b0d8084ada6095f9c6a3666501619d46eb Mon Sep 17 00:00:00 2001 From: Mahmoud-Emad Date: Tue, 8 Jul 2025 16:37:10 +0300 Subject: [PATCH] feat: Providing some clusters for kubernetes --- examples/kubernetes/clusters/generic.rs | 97 ++++++++++++++++++++++ examples/kubernetes/clusters/postgres.rhai | 45 ++++++++++ examples/kubernetes/clusters/postgres.rs | 73 ++++++++++++++++ examples/kubernetes/clusters/redis.rhai | 44 ++++++++++ examples/kubernetes/clusters/redis.rs | 72 ++++++++++++++++ kubernetes/examples/generic.rs | 97 ++++++++++++++++++++++ kubernetes/examples/postgres.rs | 73 ++++++++++++++++ kubernetes/examples/redis.rs | 72 ++++++++++++++++ kubernetes/src/kubernetes_manager.rs | 65 +++++++++++++++ kubernetes/src/rhai.rs | 41 +++++++++ 10 files changed, 679 insertions(+) create mode 100644 examples/kubernetes/clusters/generic.rs create mode 100644 examples/kubernetes/clusters/postgres.rhai create mode 100644 examples/kubernetes/clusters/postgres.rs create mode 100644 examples/kubernetes/clusters/redis.rhai create mode 100644 examples/kubernetes/clusters/redis.rs create mode 100644 kubernetes/examples/generic.rs create mode 100644 kubernetes/examples/postgres.rs create mode 100644 kubernetes/examples/redis.rs diff --git a/examples/kubernetes/clusters/generic.rs b/examples/kubernetes/clusters/generic.rs new file mode 100644 index 0000000..94b7c66 --- /dev/null +++ b/examples/kubernetes/clusters/generic.rs @@ -0,0 +1,97 @@ +//! Generic Application Deployment Example +//! +//! This example shows how to deploy any containerized application using the +//! KubernetesManager convenience methods. This works for any Docker image. + +use sal_kubernetes::KubernetesManager; +use std::collections::HashMap; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create Kubernetes manager + let km = KubernetesManager::new("default").await?; + + // Example 1: Simple web server deployment + println!("=== Example 1: Simple Nginx Web Server ==="); + + km.deploy_application("web-server", "nginx:latest", 2, 80, None) + .await?; + println!("āœ… Nginx web server deployed!"); + + // Example 2: Node.js application with labels + println!("\n=== Example 2: Node.js Application ==="); + + let mut node_labels = HashMap::new(); + node_labels.insert("app".to_string(), "node-app".to_string()); + node_labels.insert("tier".to_string(), "backend".to_string()); + node_labels.insert("environment".to_string(), "production".to_string()); + + km.deploy_application( + "node-app", // name + "node:18-alpine", // image + 3, // replicas - scale to 3 instances + 3000, // port + Some(node_labels), // labels + ) + .await?; + + println!("āœ… Node.js application deployed!"); + + // Example 3: Database deployment (any database) + println!("\n=== Example 3: MongoDB Database ==="); + + let mut mongo_labels = HashMap::new(); + mongo_labels.insert("app".to_string(), "mongodb".to_string()); + mongo_labels.insert("type".to_string(), "database".to_string()); + mongo_labels.insert("engine".to_string(), "mongodb".to_string()); + + km.deploy_application( + "mongodb", // name + "mongo:6.0", // image + 1, // replicas - single instance for simplicity + 27017, // port + Some(mongo_labels), // labels + ) + .await?; + + println!("āœ… MongoDB deployed!"); + + // Check status of all deployments + println!("\n=== Checking Deployment Status ==="); + + let deployments = km.deployments_list().await?; + + for deployment in &deployments { + if let Some(name) = &deployment.metadata.name { + let total_replicas = deployment + .spec + .as_ref() + .and_then(|s| s.replicas) + .unwrap_or(0); + let ready_replicas = deployment + .status + .as_ref() + .and_then(|s| s.ready_replicas) + .unwrap_or(0); + + println!( + "{}: {}/{} replicas ready", + name, ready_replicas, total_replicas + ); + } + } + + println!("\nšŸŽ‰ All deployments completed!"); + println!("\nšŸ’” Key Points:"); + println!(" • Any Docker image can be deployed using this simple interface"); + println!(" • Use labels to organize and identify your applications"); + println!( + " • The same method works for databases, web servers, APIs, and any containerized app" + ); + println!(" • For advanced configuration, use the individual KubernetesManager methods"); + println!( + " • Environment variables and resource limits can be added via direct Kubernetes API" + ); + + Ok(()) +} diff --git a/examples/kubernetes/clusters/postgres.rhai b/examples/kubernetes/clusters/postgres.rhai new file mode 100644 index 0000000..75cd9bf --- /dev/null +++ b/examples/kubernetes/clusters/postgres.rhai @@ -0,0 +1,45 @@ +//! PostgreSQL Cluster Deployment Example (Rhai) +//! +//! This script shows how to deploy a PostgreSQL cluster using Rhai scripting +//! with the KubernetesManager convenience methods. + +print("=== PostgreSQL Cluster Deployment ==="); + +// Create Kubernetes manager for the database namespace +print("Creating Kubernetes manager for 'database' namespace..."); +let km = kubernetes_manager_new("database"); +print("āœ“ Kubernetes manager created"); + +// Create PostgreSQL cluster using the convenience method +print("\nDeploying PostgreSQL cluster..."); + +try { + // Deploy PostgreSQL using the convenience method + let result = deploy_application(km, "postgres-cluster", "postgres:15", 2, 5432, #{ + "app": "postgres-cluster", + "type": "database", + "engine": "postgresql" + }); + print("āœ“ " + result); + + print("\nāœ… PostgreSQL cluster deployed successfully!"); + + print("\nšŸ“‹ Connection Information:"); + print(" Host: postgres-cluster.database.svc.cluster.local"); + print(" Port: 5432"); + print(" Database: postgres (default)"); + print(" Username: postgres (default)"); + + print("\nšŸ”§ To connect from another pod:"); + print(" psql -h postgres-cluster.database.svc.cluster.local -U postgres"); + + print("\nšŸ’” Next steps:"); + print(" • Set POSTGRES_PASSWORD environment variable"); + print(" • Configure persistent storage"); + print(" • Set up backup and monitoring"); + +} catch(e) { + print("āŒ Failed to deploy PostgreSQL cluster: " + e); +} + +print("\n=== Deployment Complete ==="); diff --git a/examples/kubernetes/clusters/postgres.rs b/examples/kubernetes/clusters/postgres.rs new file mode 100644 index 0000000..dbbd389 --- /dev/null +++ b/examples/kubernetes/clusters/postgres.rs @@ -0,0 +1,73 @@ +//! PostgreSQL Cluster Deployment Example +//! +//! This example shows how to deploy a PostgreSQL cluster using the +//! KubernetesManager convenience methods. + +use sal_kubernetes::KubernetesManager; +use std::collections::HashMap; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create Kubernetes manager for the database namespace + let km = KubernetesManager::new("database").await?; + + // Configure PostgreSQL-specific labels + let mut labels = HashMap::new(); + labels.insert("app".to_string(), "postgres-cluster".to_string()); + labels.insert("type".to_string(), "database".to_string()); + labels.insert("engine".to_string(), "postgresql".to_string()); + + // Deploy the PostgreSQL cluster using the convenience method + println!("Deploying PostgreSQL cluster..."); + km.deploy_application( + "postgres-cluster", // name + "postgres:15", // image + 2, // replicas (1 master + 1 replica) + 5432, // port + Some(labels), // labels + ) + .await?; + + println!("āœ… PostgreSQL cluster deployed successfully!"); + + // Check deployment status + let deployments = km.deployments_list().await?; + let postgres_deployment = deployments + .iter() + .find(|d| d.metadata.name.as_ref() == Some(&"postgres-cluster".to_string())); + + if let Some(deployment) = postgres_deployment { + let total_replicas = deployment + .spec + .as_ref() + .and_then(|s| s.replicas) + .unwrap_or(0); + let ready_replicas = deployment + .status + .as_ref() + .and_then(|s| s.ready_replicas) + .unwrap_or(0); + + println!( + "Deployment status: {}/{} replicas ready", + ready_replicas, total_replicas + ); + } + + println!("\nšŸ“‹ Connection Information:"); + println!(" Host: postgres-cluster.database.svc.cluster.local"); + println!(" Port: 5432"); + println!(" Database: postgres (default)"); + println!(" Username: postgres (default)"); + println!(" Password: Set POSTGRES_PASSWORD environment variable"); + + println!("\nšŸ”§ To connect from another pod:"); + println!(" psql -h postgres-cluster.database.svc.cluster.local -U postgres"); + + println!("\nšŸ’” Next steps:"); + println!(" • Set environment variables for database credentials"); + println!(" • Add persistent volume claims for data storage"); + println!(" • Configure backup and monitoring"); + + Ok(()) +} diff --git a/examples/kubernetes/clusters/redis.rhai b/examples/kubernetes/clusters/redis.rhai new file mode 100644 index 0000000..939f87e --- /dev/null +++ b/examples/kubernetes/clusters/redis.rhai @@ -0,0 +1,44 @@ +//! Redis Cluster Deployment Example (Rhai) +//! +//! This script shows how to deploy a Redis cluster using Rhai scripting +//! with the KubernetesManager convenience methods. + +print("=== Redis Cluster Deployment ==="); + +// Create Kubernetes manager for the cache namespace +print("Creating Kubernetes manager for 'cache' namespace..."); +let km = kubernetes_manager_new("cache"); +print("āœ“ Kubernetes manager created"); + +// Create Redis cluster using the convenience method +print("\nDeploying Redis cluster..."); + +try { + // Deploy Redis using the convenience method + let result = deploy_application(km, "redis-cluster", "redis:7-alpine", 3, 6379, #{ + "app": "redis-cluster", + "type": "cache", + "engine": "redis" + }); + print("āœ“ " + result); + + print("\nāœ… Redis cluster deployed successfully!"); + + print("\nšŸ“‹ Connection Information:"); + print(" Host: redis-cluster.cache.svc.cluster.local"); + print(" Port: 6379"); + + print("\nšŸ”§ To connect from another pod:"); + print(" redis-cli -h redis-cluster.cache.svc.cluster.local"); + + print("\nšŸ’” Next steps:"); + print(" • Configure Redis authentication"); + print(" • Set up Redis clustering configuration"); + print(" • Add persistent storage"); + print(" • Configure memory policies"); + +} catch(e) { + print("āŒ Failed to deploy Redis cluster: " + e); +} + +print("\n=== Deployment Complete ==="); diff --git a/examples/kubernetes/clusters/redis.rs b/examples/kubernetes/clusters/redis.rs new file mode 100644 index 0000000..fb27832 --- /dev/null +++ b/examples/kubernetes/clusters/redis.rs @@ -0,0 +1,72 @@ +//! Redis Cluster Deployment Example +//! +//! This example shows how to deploy a Redis cluster using the +//! KubernetesManager convenience methods. + +use sal_kubernetes::KubernetesManager; +use std::collections::HashMap; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create Kubernetes manager for the cache namespace + let km = KubernetesManager::new("cache").await?; + + // Configure Redis-specific labels + let mut labels = HashMap::new(); + labels.insert("app".to_string(), "redis-cluster".to_string()); + labels.insert("type".to_string(), "cache".to_string()); + labels.insert("engine".to_string(), "redis".to_string()); + + // Deploy the Redis cluster using the convenience method + println!("Deploying Redis cluster..."); + km.deploy_application( + "redis-cluster", // name + "redis:7-alpine", // image + 3, // replicas (Redis cluster nodes) + 6379, // port + Some(labels), // labels + ) + .await?; + + println!("āœ… Redis cluster deployed successfully!"); + + // Check deployment status + let deployments = km.deployments_list().await?; + let redis_deployment = deployments + .iter() + .find(|d| d.metadata.name.as_ref() == Some(&"redis-cluster".to_string())); + + if let Some(deployment) = redis_deployment { + let total_replicas = deployment + .spec + .as_ref() + .and_then(|s| s.replicas) + .unwrap_or(0); + let ready_replicas = deployment + .status + .as_ref() + .and_then(|s| s.ready_replicas) + .unwrap_or(0); + + println!( + "Deployment status: {}/{} replicas ready", + ready_replicas, total_replicas + ); + } + + println!("\nšŸ“‹ Connection Information:"); + println!(" Host: redis-cluster.cache.svc.cluster.local"); + println!(" Port: 6379"); + println!(" Password: Configure REDIS_PASSWORD environment variable"); + + println!("\nšŸ”§ To connect from another pod:"); + println!(" redis-cli -h redis-cluster.cache.svc.cluster.local"); + + println!("\nšŸ’” Next steps:"); + println!(" • Configure Redis authentication with environment variables"); + println!(" • Set up Redis clustering configuration"); + println!(" • Add persistent volume claims for data persistence"); + println!(" • Configure memory limits and eviction policies"); + + Ok(()) +} diff --git a/kubernetes/examples/generic.rs b/kubernetes/examples/generic.rs new file mode 100644 index 0000000..94b7c66 --- /dev/null +++ b/kubernetes/examples/generic.rs @@ -0,0 +1,97 @@ +//! Generic Application Deployment Example +//! +//! This example shows how to deploy any containerized application using the +//! KubernetesManager convenience methods. This works for any Docker image. + +use sal_kubernetes::KubernetesManager; +use std::collections::HashMap; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create Kubernetes manager + let km = KubernetesManager::new("default").await?; + + // Example 1: Simple web server deployment + println!("=== Example 1: Simple Nginx Web Server ==="); + + km.deploy_application("web-server", "nginx:latest", 2, 80, None) + .await?; + println!("āœ… Nginx web server deployed!"); + + // Example 2: Node.js application with labels + println!("\n=== Example 2: Node.js Application ==="); + + let mut node_labels = HashMap::new(); + node_labels.insert("app".to_string(), "node-app".to_string()); + node_labels.insert("tier".to_string(), "backend".to_string()); + node_labels.insert("environment".to_string(), "production".to_string()); + + km.deploy_application( + "node-app", // name + "node:18-alpine", // image + 3, // replicas - scale to 3 instances + 3000, // port + Some(node_labels), // labels + ) + .await?; + + println!("āœ… Node.js application deployed!"); + + // Example 3: Database deployment (any database) + println!("\n=== Example 3: MongoDB Database ==="); + + let mut mongo_labels = HashMap::new(); + mongo_labels.insert("app".to_string(), "mongodb".to_string()); + mongo_labels.insert("type".to_string(), "database".to_string()); + mongo_labels.insert("engine".to_string(), "mongodb".to_string()); + + km.deploy_application( + "mongodb", // name + "mongo:6.0", // image + 1, // replicas - single instance for simplicity + 27017, // port + Some(mongo_labels), // labels + ) + .await?; + + println!("āœ… MongoDB deployed!"); + + // Check status of all deployments + println!("\n=== Checking Deployment Status ==="); + + let deployments = km.deployments_list().await?; + + for deployment in &deployments { + if let Some(name) = &deployment.metadata.name { + let total_replicas = deployment + .spec + .as_ref() + .and_then(|s| s.replicas) + .unwrap_or(0); + let ready_replicas = deployment + .status + .as_ref() + .and_then(|s| s.ready_replicas) + .unwrap_or(0); + + println!( + "{}: {}/{} replicas ready", + name, ready_replicas, total_replicas + ); + } + } + + println!("\nšŸŽ‰ All deployments completed!"); + println!("\nšŸ’” Key Points:"); + println!(" • Any Docker image can be deployed using this simple interface"); + println!(" • Use labels to organize and identify your applications"); + println!( + " • The same method works for databases, web servers, APIs, and any containerized app" + ); + println!(" • For advanced configuration, use the individual KubernetesManager methods"); + println!( + " • Environment variables and resource limits can be added via direct Kubernetes API" + ); + + Ok(()) +} diff --git a/kubernetes/examples/postgres.rs b/kubernetes/examples/postgres.rs new file mode 100644 index 0000000..dbbd389 --- /dev/null +++ b/kubernetes/examples/postgres.rs @@ -0,0 +1,73 @@ +//! PostgreSQL Cluster Deployment Example +//! +//! This example shows how to deploy a PostgreSQL cluster using the +//! KubernetesManager convenience methods. + +use sal_kubernetes::KubernetesManager; +use std::collections::HashMap; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create Kubernetes manager for the database namespace + let km = KubernetesManager::new("database").await?; + + // Configure PostgreSQL-specific labels + let mut labels = HashMap::new(); + labels.insert("app".to_string(), "postgres-cluster".to_string()); + labels.insert("type".to_string(), "database".to_string()); + labels.insert("engine".to_string(), "postgresql".to_string()); + + // Deploy the PostgreSQL cluster using the convenience method + println!("Deploying PostgreSQL cluster..."); + km.deploy_application( + "postgres-cluster", // name + "postgres:15", // image + 2, // replicas (1 master + 1 replica) + 5432, // port + Some(labels), // labels + ) + .await?; + + println!("āœ… PostgreSQL cluster deployed successfully!"); + + // Check deployment status + let deployments = km.deployments_list().await?; + let postgres_deployment = deployments + .iter() + .find(|d| d.metadata.name.as_ref() == Some(&"postgres-cluster".to_string())); + + if let Some(deployment) = postgres_deployment { + let total_replicas = deployment + .spec + .as_ref() + .and_then(|s| s.replicas) + .unwrap_or(0); + let ready_replicas = deployment + .status + .as_ref() + .and_then(|s| s.ready_replicas) + .unwrap_or(0); + + println!( + "Deployment status: {}/{} replicas ready", + ready_replicas, total_replicas + ); + } + + println!("\nšŸ“‹ Connection Information:"); + println!(" Host: postgres-cluster.database.svc.cluster.local"); + println!(" Port: 5432"); + println!(" Database: postgres (default)"); + println!(" Username: postgres (default)"); + println!(" Password: Set POSTGRES_PASSWORD environment variable"); + + println!("\nšŸ”§ To connect from another pod:"); + println!(" psql -h postgres-cluster.database.svc.cluster.local -U postgres"); + + println!("\nšŸ’” Next steps:"); + println!(" • Set environment variables for database credentials"); + println!(" • Add persistent volume claims for data storage"); + println!(" • Configure backup and monitoring"); + + Ok(()) +} diff --git a/kubernetes/examples/redis.rs b/kubernetes/examples/redis.rs new file mode 100644 index 0000000..fb27832 --- /dev/null +++ b/kubernetes/examples/redis.rs @@ -0,0 +1,72 @@ +//! Redis Cluster Deployment Example +//! +//! This example shows how to deploy a Redis cluster using the +//! KubernetesManager convenience methods. + +use sal_kubernetes::KubernetesManager; +use std::collections::HashMap; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create Kubernetes manager for the cache namespace + let km = KubernetesManager::new("cache").await?; + + // Configure Redis-specific labels + let mut labels = HashMap::new(); + labels.insert("app".to_string(), "redis-cluster".to_string()); + labels.insert("type".to_string(), "cache".to_string()); + labels.insert("engine".to_string(), "redis".to_string()); + + // Deploy the Redis cluster using the convenience method + println!("Deploying Redis cluster..."); + km.deploy_application( + "redis-cluster", // name + "redis:7-alpine", // image + 3, // replicas (Redis cluster nodes) + 6379, // port + Some(labels), // labels + ) + .await?; + + println!("āœ… Redis cluster deployed successfully!"); + + // Check deployment status + let deployments = km.deployments_list().await?; + let redis_deployment = deployments + .iter() + .find(|d| d.metadata.name.as_ref() == Some(&"redis-cluster".to_string())); + + if let Some(deployment) = redis_deployment { + let total_replicas = deployment + .spec + .as_ref() + .and_then(|s| s.replicas) + .unwrap_or(0); + let ready_replicas = deployment + .status + .as_ref() + .and_then(|s| s.ready_replicas) + .unwrap_or(0); + + println!( + "Deployment status: {}/{} replicas ready", + ready_replicas, total_replicas + ); + } + + println!("\nšŸ“‹ Connection Information:"); + println!(" Host: redis-cluster.cache.svc.cluster.local"); + println!(" Port: 6379"); + println!(" Password: Configure REDIS_PASSWORD environment variable"); + + println!("\nšŸ”§ To connect from another pod:"); + println!(" redis-cli -h redis-cluster.cache.svc.cluster.local"); + + println!("\nšŸ’” Next steps:"); + println!(" • Configure Redis authentication with environment variables"); + println!(" • Set up Redis clustering configuration"); + println!(" • Add persistent volume claims for data persistence"); + println!(" • Configure memory limits and eviction policies"); + + Ok(()) +} diff --git a/kubernetes/src/kubernetes_manager.rs b/kubernetes/src/kubernetes_manager.rs index 91e5fa5..c8732f0 100644 --- a/kubernetes/src/kubernetes_manager.rs +++ b/kubernetes/src/kubernetes_manager.rs @@ -1202,6 +1202,71 @@ impl KubernetesManager { log::info!("Deleted namespace '{}'", name); Ok(()) } + + /// Deploy a complete application with deployment and service + /// + /// This convenience method creates both a deployment and a service for an application, + /// making it easy to deploy complete containerized applications with a single call. + /// + /// # Arguments + /// + /// * `name` - The name for both deployment and service + /// * `image` - The container image to deploy + /// * `replicas` - Number of replicas to create + /// * `port` - The port the application listens on + /// * `labels` - Optional labels for the resources + /// + /// # Returns + /// + /// * `KubernetesResult<()>` - Success or an error + /// + /// # Example + /// + /// ```rust,no_run + /// use sal_kubernetes::KubernetesManager; + /// use std::collections::HashMap; + /// + /// #[tokio::main] + /// async fn main() -> Result<(), Box> { + /// let km = KubernetesManager::new("default").await?; + /// + /// let mut labels = HashMap::new(); + /// labels.insert("app".to_string(), "my-app".to_string()); + /// + /// km.deploy_application("my-app", "node:18", 3, 3000, Some(labels)).await?; + /// Ok(()) + /// } + /// ``` + pub async fn deploy_application( + &self, + name: &str, + image: &str, + replicas: i32, + port: i32, + labels: Option>, + ) -> KubernetesResult<()> { + log::info!("Deploying application '{}' with image '{}'", name, image); + + // Create deployment + self.deployment_create(name, image, replicas, labels.clone()) + .await?; + + // Create service selector - use app=name if no labels provided + let selector = if let Some(ref labels) = labels { + labels.clone() + } else { + let mut default_selector = HashMap::new(); + default_selector.insert("app".to_string(), name.to_string()); + default_selector + }; + + // Create service + self.service_create(name, selector, port, Some(port)) + .await?; + + log::info!("Successfully deployed application '{}'", name); + Ok(()) + } } /// Determine if a Kubernetes API error is retryable diff --git a/kubernetes/src/rhai.rs b/kubernetes/src/rhai.rs index c2251a0..3189793 100644 --- a/kubernetes/src/rhai.rs +++ b/kubernetes/src/rhai.rs @@ -409,6 +409,44 @@ fn resource_counts(km: &mut KubernetesManager) -> Result Ok(rhai_map) } +/// Deploy a complete application with deployment and service +/// +/// # Arguments +/// +/// * `km` - Mutable reference to KubernetesManager +/// * `name` - Name of the application +/// * `image` - Container image to use +/// * `replicas` - Number of replicas +/// * `port` - Port the application listens on +/// * `labels` - Optional labels as a Map +/// +/// # Returns +/// +/// * `Result>` - Success message or an error +fn deploy_application( + km: &mut KubernetesManager, + name: String, + image: String, + replicas: i64, + port: i64, + labels: Map, +) -> Result> { + let labels_map: Option> = if labels.is_empty() { + None + } else { + Some( + labels + .into_iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(), + ) + }; + + execute_async(km.deploy_application(&name, &image, replicas as i32, port as i32, labels_map))?; + + Ok(format!("Successfully deployed application '{}'", name)) +} + /// Delete a specific pod by name /// /// # Arguments @@ -543,6 +581,9 @@ pub fn register_kubernetes_module(engine: &mut Engine) -> Result<(), Box