feat: Add Kubernetes module to SAL
- Add Kubernetes cluster management and operations - Include pod, service, and deployment management - Implement pattern-based resource deletion - Support namespace creation and management - Provide Rhai scripting wrappers for all functions - Include production safety features (timeouts, retries, rate limiting)
This commit is contained in:
		
							
								
								
									
										113
									
								
								kubernetes/src/config.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								kubernetes/src/config.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
//! Configuration for production safety features
 | 
			
		||||
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
/// Configuration for Kubernetes operations with production safety features
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct KubernetesConfig {
 | 
			
		||||
    /// Timeout for individual API operations
 | 
			
		||||
    pub operation_timeout: Duration,
 | 
			
		||||
    
 | 
			
		||||
    /// Maximum number of retry attempts for failed operations
 | 
			
		||||
    pub max_retries: u32,
 | 
			
		||||
    
 | 
			
		||||
    /// Base delay for exponential backoff retry strategy
 | 
			
		||||
    pub retry_base_delay: Duration,
 | 
			
		||||
    
 | 
			
		||||
    /// Maximum delay between retries
 | 
			
		||||
    pub retry_max_delay: Duration,
 | 
			
		||||
    
 | 
			
		||||
    /// Rate limiting: maximum requests per second
 | 
			
		||||
    pub rate_limit_rps: u32,
 | 
			
		||||
    
 | 
			
		||||
    /// Rate limiting: burst capacity
 | 
			
		||||
    pub rate_limit_burst: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for KubernetesConfig {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            // Conservative timeout for production
 | 
			
		||||
            operation_timeout: Duration::from_secs(30),
 | 
			
		||||
            
 | 
			
		||||
            // Reasonable retry attempts
 | 
			
		||||
            max_retries: 3,
 | 
			
		||||
            
 | 
			
		||||
            // Exponential backoff starting at 1 second
 | 
			
		||||
            retry_base_delay: Duration::from_secs(1),
 | 
			
		||||
            
 | 
			
		||||
            // Maximum 30 seconds between retries
 | 
			
		||||
            retry_max_delay: Duration::from_secs(30),
 | 
			
		||||
            
 | 
			
		||||
            // Conservative rate limiting: 10 requests per second
 | 
			
		||||
            rate_limit_rps: 10,
 | 
			
		||||
            
 | 
			
		||||
            // Allow small bursts
 | 
			
		||||
            rate_limit_burst: 20,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl KubernetesConfig {
 | 
			
		||||
    /// Create a new configuration with custom settings
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self::default()
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Set operation timeout
 | 
			
		||||
    pub fn with_timeout(mut self, timeout: Duration) -> Self {
 | 
			
		||||
        self.operation_timeout = timeout;
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Set retry configuration
 | 
			
		||||
    pub fn with_retries(mut self, max_retries: u32, base_delay: Duration, max_delay: Duration) -> Self {
 | 
			
		||||
        self.max_retries = max_retries;
 | 
			
		||||
        self.retry_base_delay = base_delay;
 | 
			
		||||
        self.retry_max_delay = max_delay;
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Set rate limiting configuration
 | 
			
		||||
    pub fn with_rate_limit(mut self, rps: u32, burst: u32) -> Self {
 | 
			
		||||
        self.rate_limit_rps = rps;
 | 
			
		||||
        self.rate_limit_burst = burst;
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Create configuration optimized for high-throughput environments
 | 
			
		||||
    pub fn high_throughput() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            operation_timeout: Duration::from_secs(60),
 | 
			
		||||
            max_retries: 5,
 | 
			
		||||
            retry_base_delay: Duration::from_millis(500),
 | 
			
		||||
            retry_max_delay: Duration::from_secs(60),
 | 
			
		||||
            rate_limit_rps: 50,
 | 
			
		||||
            rate_limit_burst: 100,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Create configuration optimized for low-latency environments
 | 
			
		||||
    pub fn low_latency() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            operation_timeout: Duration::from_secs(10),
 | 
			
		||||
            max_retries: 2,
 | 
			
		||||
            retry_base_delay: Duration::from_millis(100),
 | 
			
		||||
            retry_max_delay: Duration::from_secs(5),
 | 
			
		||||
            rate_limit_rps: 20,
 | 
			
		||||
            rate_limit_burst: 40,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Create configuration for development/testing
 | 
			
		||||
    pub fn development() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            operation_timeout: Duration::from_secs(120),
 | 
			
		||||
            max_retries: 1,
 | 
			
		||||
            retry_base_delay: Duration::from_millis(100),
 | 
			
		||||
            retry_max_delay: Duration::from_secs(2),
 | 
			
		||||
            rate_limit_rps: 100,
 | 
			
		||||
            rate_limit_burst: 200,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								kubernetes/src/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								kubernetes/src/error.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
//! Error types for SAL Kubernetes operations
 | 
			
		||||
 | 
			
		||||
use thiserror::Error;
 | 
			
		||||
 | 
			
		||||
/// Errors that can occur during Kubernetes operations
 | 
			
		||||
#[derive(Error, Debug)]
 | 
			
		||||
pub enum KubernetesError {
 | 
			
		||||
    /// Kubernetes API client error
 | 
			
		||||
    #[error("Kubernetes API error: {0}")]
 | 
			
		||||
    ApiError(#[from] kube::Error),
 | 
			
		||||
 | 
			
		||||
    /// Configuration error
 | 
			
		||||
    #[error("Configuration error: {0}")]
 | 
			
		||||
    ConfigError(String),
 | 
			
		||||
 | 
			
		||||
    /// Resource not found error
 | 
			
		||||
    #[error("Resource not found: {0}")]
 | 
			
		||||
    ResourceNotFound(String),
 | 
			
		||||
 | 
			
		||||
    /// Invalid resource name or pattern
 | 
			
		||||
    #[error("Invalid resource name or pattern: {0}")]
 | 
			
		||||
    InvalidResourceName(String),
 | 
			
		||||
 | 
			
		||||
    /// Regular expression error
 | 
			
		||||
    #[error("Regular expression error: {0}")]
 | 
			
		||||
    RegexError(#[from] regex::Error),
 | 
			
		||||
 | 
			
		||||
    /// Serialization/deserialization error
 | 
			
		||||
    #[error("Serialization error: {0}")]
 | 
			
		||||
    SerializationError(#[from] serde_json::Error),
 | 
			
		||||
 | 
			
		||||
    /// YAML parsing error
 | 
			
		||||
    #[error("YAML error: {0}")]
 | 
			
		||||
    YamlError(#[from] serde_yaml::Error),
 | 
			
		||||
 | 
			
		||||
    /// Generic operation error
 | 
			
		||||
    #[error("Operation failed: {0}")]
 | 
			
		||||
    OperationError(String),
 | 
			
		||||
 | 
			
		||||
    /// Namespace error
 | 
			
		||||
    #[error("Namespace error: {0}")]
 | 
			
		||||
    NamespaceError(String),
 | 
			
		||||
 | 
			
		||||
    /// Permission denied error
 | 
			
		||||
    #[error("Permission denied: {0}")]
 | 
			
		||||
    PermissionDenied(String),
 | 
			
		||||
 | 
			
		||||
    /// Timeout error
 | 
			
		||||
    #[error("Operation timed out: {0}")]
 | 
			
		||||
    Timeout(String),
 | 
			
		||||
 | 
			
		||||
    /// Generic error wrapper
 | 
			
		||||
    #[error("Generic error: {0}")]
 | 
			
		||||
    Generic(#[from] anyhow::Error),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl KubernetesError {
 | 
			
		||||
    /// Create a new configuration error
 | 
			
		||||
    pub fn config_error(msg: impl Into<String>) -> Self {
 | 
			
		||||
        Self::ConfigError(msg.into())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Create a new operation error
 | 
			
		||||
    pub fn operation_error(msg: impl Into<String>) -> Self {
 | 
			
		||||
        Self::OperationError(msg.into())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Create a new namespace error
 | 
			
		||||
    pub fn namespace_error(msg: impl Into<String>) -> Self {
 | 
			
		||||
        Self::NamespaceError(msg.into())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Create a new permission denied error
 | 
			
		||||
    pub fn permission_denied(msg: impl Into<String>) -> Self {
 | 
			
		||||
        Self::PermissionDenied(msg.into())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Create a new timeout error
 | 
			
		||||
    pub fn timeout(msg: impl Into<String>) -> Self {
 | 
			
		||||
        Self::Timeout(msg.into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Result type for Kubernetes operations
 | 
			
		||||
pub type KubernetesResult<T> = Result<T, KubernetesError>;
 | 
			
		||||
							
								
								
									
										1238
									
								
								kubernetes/src/kubernetes_manager.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1238
									
								
								kubernetes/src/kubernetes_manager.rs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										49
									
								
								kubernetes/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								kubernetes/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
//! SAL Kubernetes: Kubernetes cluster management and operations
 | 
			
		||||
//!
 | 
			
		||||
//! This package provides Kubernetes cluster management functionality including:
 | 
			
		||||
//! - Namespace-scoped resource management via KubernetesManager
 | 
			
		||||
//! - Pod listing and management
 | 
			
		||||
//! - Resource deletion with PCRE pattern matching
 | 
			
		||||
//! - Namespace creation and management
 | 
			
		||||
//! - Support for various Kubernetes resources (pods, services, deployments, etc.)
 | 
			
		||||
//!
 | 
			
		||||
//! # Example
 | 
			
		||||
//!
 | 
			
		||||
//! ```rust
 | 
			
		||||
//! use sal_kubernetes::KubernetesManager;
 | 
			
		||||
//!
 | 
			
		||||
//! #[tokio::main]
 | 
			
		||||
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
//!     // Create a manager for the "default" namespace
 | 
			
		||||
//!     let km = KubernetesManager::new("default").await?;
 | 
			
		||||
//!     
 | 
			
		||||
//!     // List all pods in the namespace
 | 
			
		||||
//!     let pods = km.pods_list().await?;
 | 
			
		||||
//!     println!("Found {} pods", pods.len());
 | 
			
		||||
//!     
 | 
			
		||||
//!     // Create a namespace (idempotent)
 | 
			
		||||
//!     km.namespace_create("my-namespace").await?;
 | 
			
		||||
//!     
 | 
			
		||||
//!     // Delete resources matching a pattern
 | 
			
		||||
//!     km.delete("test-.*").await?;
 | 
			
		||||
//!     
 | 
			
		||||
//!     Ok(())
 | 
			
		||||
//! }
 | 
			
		||||
//! ```
 | 
			
		||||
 | 
			
		||||
pub mod config;
 | 
			
		||||
pub mod error;
 | 
			
		||||
pub mod kubernetes_manager;
 | 
			
		||||
 | 
			
		||||
// Rhai integration module
 | 
			
		||||
#[cfg(feature = "rhai")]
 | 
			
		||||
pub mod rhai;
 | 
			
		||||
 | 
			
		||||
// Re-export main types for convenience
 | 
			
		||||
pub use config::KubernetesConfig;
 | 
			
		||||
pub use error::KubernetesError;
 | 
			
		||||
pub use kubernetes_manager::KubernetesManager;
 | 
			
		||||
 | 
			
		||||
// Re-export commonly used Kubernetes types
 | 
			
		||||
pub use k8s_openapi::api::apps::v1::{Deployment, ReplicaSet};
 | 
			
		||||
pub use k8s_openapi::api::core::v1::{Namespace, Pod, Service};
 | 
			
		||||
							
								
								
									
										555
									
								
								kubernetes/src/rhai.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										555
									
								
								kubernetes/src/rhai.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,555 @@
 | 
			
		||||
//! Rhai wrappers for Kubernetes module functions
 | 
			
		||||
//!
 | 
			
		||||
//! This module provides Rhai wrappers for the functions in the Kubernetes module,
 | 
			
		||||
//! enabling scripting access to Kubernetes operations.
 | 
			
		||||
 | 
			
		||||
use crate::{KubernetesError, KubernetesManager};
 | 
			
		||||
use rhai::{Array, Dynamic, Engine, EvalAltResult, Map};
 | 
			
		||||
 | 
			
		||||
/// Helper function to execute async operations with proper runtime handling
 | 
			
		||||
fn execute_async<F, T>(future: F) -> Result<T, Box<EvalAltResult>>
 | 
			
		||||
where
 | 
			
		||||
    F: std::future::Future<Output = Result<T, KubernetesError>>,
 | 
			
		||||
{
 | 
			
		||||
    match tokio::runtime::Handle::try_current() {
 | 
			
		||||
        Ok(handle) => handle
 | 
			
		||||
            .block_on(future)
 | 
			
		||||
            .map_err(kubernetes_error_to_rhai_error),
 | 
			
		||||
        Err(_) => {
 | 
			
		||||
            // No runtime available, create a new one
 | 
			
		||||
            let rt = tokio::runtime::Runtime::new().map_err(|e| {
 | 
			
		||||
                Box::new(EvalAltResult::ErrorRuntime(
 | 
			
		||||
                    format!("Failed to create Tokio runtime: {}", e).into(),
 | 
			
		||||
                    rhai::Position::NONE,
 | 
			
		||||
                ))
 | 
			
		||||
            })?;
 | 
			
		||||
            rt.block_on(future).map_err(kubernetes_error_to_rhai_error)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a new KubernetesManager for the specified namespace
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `namespace` - The Kubernetes namespace to operate on
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<KubernetesManager, Box<EvalAltResult>>` - The manager instance or an error
 | 
			
		||||
fn kubernetes_manager_new(namespace: String) -> Result<KubernetesManager, Box<EvalAltResult>> {
 | 
			
		||||
    execute_async(KubernetesManager::new(namespace))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// List all pods in the namespace
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<Array, Box<EvalAltResult>>` - Array of pod names or an error
 | 
			
		||||
fn pods_list(km: &mut KubernetesManager) -> Result<Array, Box<EvalAltResult>> {
 | 
			
		||||
    let pods = execute_async(km.pods_list())?;
 | 
			
		||||
 | 
			
		||||
    let pod_names: Array = pods
 | 
			
		||||
        .iter()
 | 
			
		||||
        .filter_map(|pod| pod.metadata.name.as_ref())
 | 
			
		||||
        .map(|name| Dynamic::from(name.clone()))
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    Ok(pod_names)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// List all services in the namespace
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<Array, Box<EvalAltResult>>` - Array of service names or an error
 | 
			
		||||
fn services_list(km: &mut KubernetesManager) -> Result<Array, Box<EvalAltResult>> {
 | 
			
		||||
    let services = execute_async(km.services_list())?;
 | 
			
		||||
 | 
			
		||||
    let service_names: Array = services
 | 
			
		||||
        .iter()
 | 
			
		||||
        .filter_map(|service| service.metadata.name.as_ref())
 | 
			
		||||
        .map(|name| Dynamic::from(name.clone()))
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    Ok(service_names)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// List all deployments in the namespace
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<Array, Box<EvalAltResult>>` - Array of deployment names or an error
 | 
			
		||||
fn deployments_list(km: &mut KubernetesManager) -> Result<Array, Box<EvalAltResult>> {
 | 
			
		||||
    let deployments = execute_async(km.deployments_list())?;
 | 
			
		||||
 | 
			
		||||
    let deployment_names: Array = deployments
 | 
			
		||||
        .iter()
 | 
			
		||||
        .filter_map(|deployment| deployment.metadata.name.as_ref())
 | 
			
		||||
        .map(|name| Dynamic::from(name.clone()))
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    Ok(deployment_names)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete resources matching a PCRE pattern
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
/// * `pattern` - PCRE pattern to match resource names against
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<i64, Box<EvalAltResult>>` - Number of resources deleted or an error
 | 
			
		||||
/// Create a pod with a single container
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the pod
 | 
			
		||||
/// * `image` - Container image to use
 | 
			
		||||
/// * `labels` - Optional labels as a Map
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<String, Box<EvalAltResult>>` - Pod name or an error
 | 
			
		||||
fn pod_create(
 | 
			
		||||
    km: &mut KubernetesManager,
 | 
			
		||||
    name: String,
 | 
			
		||||
    image: String,
 | 
			
		||||
    labels: Map,
 | 
			
		||||
) -> Result<String, Box<EvalAltResult>> {
 | 
			
		||||
    let labels_map: Option<std::collections::HashMap<String, String>> = if labels.is_empty() {
 | 
			
		||||
        None
 | 
			
		||||
    } else {
 | 
			
		||||
        Some(
 | 
			
		||||
            labels
 | 
			
		||||
                .into_iter()
 | 
			
		||||
                .map(|(k, v)| (k.to_string(), v.to_string()))
 | 
			
		||||
                .collect(),
 | 
			
		||||
        )
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let pod = execute_async(km.pod_create(&name, &image, labels_map))?;
 | 
			
		||||
    Ok(pod.metadata.name.unwrap_or(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a service
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the service
 | 
			
		||||
/// * `selector` - Labels to select pods as a Map
 | 
			
		||||
/// * `port` - Port to expose
 | 
			
		||||
/// * `target_port` - Target port on pods (optional, defaults to port)
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<String, Box<EvalAltResult>>` - Service name or an error
 | 
			
		||||
fn service_create(
 | 
			
		||||
    km: &mut KubernetesManager,
 | 
			
		||||
    name: String,
 | 
			
		||||
    selector: Map,
 | 
			
		||||
    port: i64,
 | 
			
		||||
    target_port: i64,
 | 
			
		||||
) -> Result<String, Box<EvalAltResult>> {
 | 
			
		||||
    let selector_map: std::collections::HashMap<String, String> = selector
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|(k, v)| (k.to_string(), v.to_string()))
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    let target_port_opt = if target_port == 0 {
 | 
			
		||||
        None
 | 
			
		||||
    } else {
 | 
			
		||||
        Some(target_port as i32)
 | 
			
		||||
    };
 | 
			
		||||
    let service =
 | 
			
		||||
        execute_async(km.service_create(&name, selector_map, port as i32, target_port_opt))?;
 | 
			
		||||
    Ok(service.metadata.name.unwrap_or(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a deployment
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the deployment
 | 
			
		||||
/// * `image` - Container image to use
 | 
			
		||||
/// * `replicas` - Number of replicas
 | 
			
		||||
/// * `labels` - Optional labels as a Map
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<String, Box<EvalAltResult>>` - Deployment name or an error
 | 
			
		||||
fn deployment_create(
 | 
			
		||||
    km: &mut KubernetesManager,
 | 
			
		||||
    name: String,
 | 
			
		||||
    image: String,
 | 
			
		||||
    replicas: i64,
 | 
			
		||||
    labels: Map,
 | 
			
		||||
) -> Result<String, Box<EvalAltResult>> {
 | 
			
		||||
    let labels_map: Option<std::collections::HashMap<String, String>> = if labels.is_empty() {
 | 
			
		||||
        None
 | 
			
		||||
    } else {
 | 
			
		||||
        Some(
 | 
			
		||||
            labels
 | 
			
		||||
                .into_iter()
 | 
			
		||||
                .map(|(k, v)| (k.to_string(), v.to_string()))
 | 
			
		||||
                .collect(),
 | 
			
		||||
        )
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let deployment =
 | 
			
		||||
        execute_async(km.deployment_create(&name, &image, replicas as i32, labels_map))?;
 | 
			
		||||
    Ok(deployment.metadata.name.unwrap_or(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a ConfigMap
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the ConfigMap
 | 
			
		||||
/// * `data` - Data as a Map
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<String, Box<EvalAltResult>>` - ConfigMap name or an error
 | 
			
		||||
fn configmap_create(
 | 
			
		||||
    km: &mut KubernetesManager,
 | 
			
		||||
    name: String,
 | 
			
		||||
    data: Map,
 | 
			
		||||
) -> Result<String, Box<EvalAltResult>> {
 | 
			
		||||
    let data_map: std::collections::HashMap<String, String> = data
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|(k, v)| (k.to_string(), v.to_string()))
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    let configmap = execute_async(km.configmap_create(&name, data_map))?;
 | 
			
		||||
    Ok(configmap.metadata.name.unwrap_or(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a Secret
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the Secret
 | 
			
		||||
/// * `data` - Data as a Map (will be base64 encoded)
 | 
			
		||||
/// * `secret_type` - Type of secret (optional, defaults to "Opaque")
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<String, Box<EvalAltResult>>` - Secret name or an error
 | 
			
		||||
fn secret_create(
 | 
			
		||||
    km: &mut KubernetesManager,
 | 
			
		||||
    name: String,
 | 
			
		||||
    data: Map,
 | 
			
		||||
    secret_type: String,
 | 
			
		||||
) -> Result<String, Box<EvalAltResult>> {
 | 
			
		||||
    let data_map: std::collections::HashMap<String, String> = data
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|(k, v)| (k.to_string(), v.to_string()))
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    let secret_type_opt = if secret_type.is_empty() {
 | 
			
		||||
        None
 | 
			
		||||
    } else {
 | 
			
		||||
        Some(secret_type.as_str())
 | 
			
		||||
    };
 | 
			
		||||
    let secret = execute_async(km.secret_create(&name, data_map, secret_type_opt))?;
 | 
			
		||||
    Ok(secret.metadata.name.unwrap_or(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get a pod by name
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the pod to get
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<String, Box<EvalAltResult>>` - Pod name or an error
 | 
			
		||||
fn pod_get(km: &mut KubernetesManager, name: String) -> Result<String, Box<EvalAltResult>> {
 | 
			
		||||
    let pod = execute_async(km.pod_get(&name))?;
 | 
			
		||||
    Ok(pod.metadata.name.unwrap_or(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get a service by name
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the service to get
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<String, Box<EvalAltResult>>` - Service name or an error
 | 
			
		||||
fn service_get(km: &mut KubernetesManager, name: String) -> Result<String, Box<EvalAltResult>> {
 | 
			
		||||
    let service = execute_async(km.service_get(&name))?;
 | 
			
		||||
    Ok(service.metadata.name.unwrap_or(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get a deployment by name
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the deployment to get
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<String, Box<EvalAltResult>>` - Deployment name or an error
 | 
			
		||||
fn deployment_get(km: &mut KubernetesManager, name: String) -> Result<String, Box<EvalAltResult>> {
 | 
			
		||||
    let deployment = execute_async(km.deployment_get(&name))?;
 | 
			
		||||
    Ok(deployment.metadata.name.unwrap_or(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn delete(km: &mut KubernetesManager, pattern: String) -> Result<i64, Box<EvalAltResult>> {
 | 
			
		||||
    let deleted_count = execute_async(km.delete(&pattern))?;
 | 
			
		||||
 | 
			
		||||
    Ok(deleted_count as i64)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a namespace (idempotent operation)
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
/// * `name` - The name of the namespace to create
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<(), Box<EvalAltResult>>` - Success or an error
 | 
			
		||||
fn namespace_create(km: &mut KubernetesManager, name: String) -> Result<(), Box<EvalAltResult>> {
 | 
			
		||||
    execute_async(km.namespace_create(&name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a namespace (destructive operation)
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the namespace to delete
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<(), Box<EvalAltResult>>` - Success or an error
 | 
			
		||||
fn namespace_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box<EvalAltResult>> {
 | 
			
		||||
    execute_async(km.namespace_delete(&name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Check if a namespace exists
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
/// * `name` - The name of the namespace to check
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<bool, Box<EvalAltResult>>` - True if namespace exists, false otherwise
 | 
			
		||||
fn namespace_exists(km: &mut KubernetesManager, name: String) -> Result<bool, Box<EvalAltResult>> {
 | 
			
		||||
    execute_async(km.namespace_exists(&name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// List all namespaces
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<Array, Box<EvalAltResult>>` - Array of namespace names or an error
 | 
			
		||||
fn namespaces_list(km: &mut KubernetesManager) -> Result<Array, Box<EvalAltResult>> {
 | 
			
		||||
    let namespaces = execute_async(km.namespaces_list())?;
 | 
			
		||||
 | 
			
		||||
    let namespace_names: Array = namespaces
 | 
			
		||||
        .iter()
 | 
			
		||||
        .filter_map(|ns| ns.metadata.name.as_ref())
 | 
			
		||||
        .map(|name| Dynamic::from(name.clone()))
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    Ok(namespace_names)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get resource counts for the namespace
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<Map, Box<EvalAltResult>>` - Map of resource counts by type or an error
 | 
			
		||||
fn resource_counts(km: &mut KubernetesManager) -> Result<Map, Box<EvalAltResult>> {
 | 
			
		||||
    let counts = execute_async(km.resource_counts())?;
 | 
			
		||||
 | 
			
		||||
    let mut rhai_map = Map::new();
 | 
			
		||||
    for (key, value) in counts {
 | 
			
		||||
        rhai_map.insert(key.into(), Dynamic::from(value as i64));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(rhai_map)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a specific pod by name
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
/// * `name` - The name of the pod to delete
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<(), Box<EvalAltResult>>` - Success or an error
 | 
			
		||||
fn pod_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box<EvalAltResult>> {
 | 
			
		||||
    execute_async(km.pod_delete(&name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a specific service by name
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
/// * `name` - The name of the service to delete
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<(), Box<EvalAltResult>>` - Success or an error
 | 
			
		||||
fn service_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box<EvalAltResult>> {
 | 
			
		||||
    execute_async(km.service_delete(&name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a specific deployment by name
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
/// * `name` - The name of the deployment to delete
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<(), Box<EvalAltResult>>` - Success or an error
 | 
			
		||||
fn deployment_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box<EvalAltResult>> {
 | 
			
		||||
    execute_async(km.deployment_delete(&name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a ConfigMap by name
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the ConfigMap to delete
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<(), Box<EvalAltResult>>` - Success or an error
 | 
			
		||||
fn configmap_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box<EvalAltResult>> {
 | 
			
		||||
    execute_async(km.configmap_delete(&name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a Secret by name
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - Mutable reference to KubernetesManager
 | 
			
		||||
/// * `name` - Name of the Secret to delete
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<(), Box<EvalAltResult>>` - Success or an error
 | 
			
		||||
fn secret_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box<EvalAltResult>> {
 | 
			
		||||
    execute_async(km.secret_delete(&name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the namespace this manager operates on
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `km` - The KubernetesManager instance
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `String` - The namespace name
 | 
			
		||||
fn kubernetes_manager_namespace(km: &mut KubernetesManager) -> String {
 | 
			
		||||
    km.namespace().to_string()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Register Kubernetes module functions with the Rhai engine
 | 
			
		||||
///
 | 
			
		||||
/// # Arguments
 | 
			
		||||
///
 | 
			
		||||
/// * `engine` - The Rhai engine to register the functions with
 | 
			
		||||
///
 | 
			
		||||
/// # Returns
 | 
			
		||||
///
 | 
			
		||||
/// * `Result<(), Box<EvalAltResult>>` - Ok if registration was successful, Err otherwise
 | 
			
		||||
pub fn register_kubernetes_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
 | 
			
		||||
    // Register KubernetesManager type
 | 
			
		||||
    engine.register_type::<KubernetesManager>();
 | 
			
		||||
 | 
			
		||||
    // Register KubernetesManager constructor and methods
 | 
			
		||||
    engine.register_fn("kubernetes_manager_new", kubernetes_manager_new);
 | 
			
		||||
    engine.register_fn("namespace", kubernetes_manager_namespace);
 | 
			
		||||
 | 
			
		||||
    // Register resource listing functions
 | 
			
		||||
    engine.register_fn("pods_list", pods_list);
 | 
			
		||||
    engine.register_fn("services_list", services_list);
 | 
			
		||||
    engine.register_fn("deployments_list", deployments_list);
 | 
			
		||||
    engine.register_fn("namespaces_list", namespaces_list);
 | 
			
		||||
 | 
			
		||||
    // Register resource creation methods (object-oriented style)
 | 
			
		||||
    engine.register_fn("create_pod", pod_create);
 | 
			
		||||
    engine.register_fn("create_service", service_create);
 | 
			
		||||
    engine.register_fn("create_deployment", deployment_create);
 | 
			
		||||
    engine.register_fn("create_configmap", configmap_create);
 | 
			
		||||
    engine.register_fn("create_secret", secret_create);
 | 
			
		||||
 | 
			
		||||
    // Register resource get methods
 | 
			
		||||
    engine.register_fn("get_pod", pod_get);
 | 
			
		||||
    engine.register_fn("get_service", service_get);
 | 
			
		||||
    engine.register_fn("get_deployment", deployment_get);
 | 
			
		||||
 | 
			
		||||
    // Register resource management methods
 | 
			
		||||
    engine.register_fn("delete", delete);
 | 
			
		||||
    engine.register_fn("delete_pod", pod_delete);
 | 
			
		||||
    engine.register_fn("delete_service", service_delete);
 | 
			
		||||
    engine.register_fn("delete_deployment", deployment_delete);
 | 
			
		||||
    engine.register_fn("delete_configmap", configmap_delete);
 | 
			
		||||
    engine.register_fn("delete_secret", secret_delete);
 | 
			
		||||
 | 
			
		||||
    // Register namespace methods (object-oriented style)
 | 
			
		||||
    engine.register_fn("create_namespace", namespace_create);
 | 
			
		||||
    engine.register_fn("delete_namespace", namespace_delete);
 | 
			
		||||
    engine.register_fn("namespace_exists", namespace_exists);
 | 
			
		||||
 | 
			
		||||
    // Register utility functions
 | 
			
		||||
    engine.register_fn("resource_counts", resource_counts);
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper function for error conversion
 | 
			
		||||
fn kubernetes_error_to_rhai_error(error: KubernetesError) -> Box<EvalAltResult> {
 | 
			
		||||
    Box::new(EvalAltResult::ErrorRuntime(
 | 
			
		||||
        format!("Kubernetes error: {}", error).into(),
 | 
			
		||||
        rhai::Position::NONE,
 | 
			
		||||
    ))
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user