//! 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(future: F) -> Result> where F: std::future::Future>, { 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>` - The manager instance or an error fn kubernetes_manager_new(namespace: String) -> Result> { execute_async(KubernetesManager::new(namespace)) } /// List all pods in the namespace /// /// # Arguments /// /// * `km` - The KubernetesManager instance /// /// # Returns /// /// * `Result>` - Array of pod names or an error fn pods_list(km: &mut KubernetesManager) -> Result> { 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 of service names or an error fn services_list(km: &mut KubernetesManager) -> Result> { 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 of deployment names or an error fn deployments_list(km: &mut KubernetesManager) -> Result> { 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>` - 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>` - Pod name or an error fn pod_create( km: &mut KubernetesManager, name: String, image: String, 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(), ) }; 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>` - Service name or an error fn service_create( km: &mut KubernetesManager, name: String, selector: Map, port: i64, target_port: i64, ) -> Result> { let selector_map: std::collections::HashMap = 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>` - Deployment name or an error fn deployment_create( km: &mut KubernetesManager, name: String, image: String, replicas: 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(), ) }; 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>` - ConfigMap name or an error fn configmap_create( km: &mut KubernetesManager, name: String, data: Map, ) -> Result> { let data_map: std::collections::HashMap = 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>` - Secret name or an error fn secret_create( km: &mut KubernetesManager, name: String, data: Map, secret_type: String, ) -> Result> { let data_map: std::collections::HashMap = 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>` - Pod name or an error fn pod_get(km: &mut KubernetesManager, name: String) -> Result> { 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>` - Service name or an error fn service_get(km: &mut KubernetesManager, name: String) -> Result> { 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>` - Deployment name or an error fn deployment_get(km: &mut KubernetesManager, name: String) -> Result> { let deployment = execute_async(km.deployment_get(&name))?; Ok(deployment.metadata.name.unwrap_or(name)) } fn delete(km: &mut KubernetesManager, pattern: String) -> Result> { 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>` - Success or an error fn namespace_create(km: &mut KubernetesManager, name: String) -> Result<(), Box> { 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>` - Success or an error fn namespace_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box> { 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>` - True if namespace exists, false otherwise fn namespace_exists(km: &mut KubernetesManager, name: String) -> Result> { execute_async(km.namespace_exists(&name)) } /// List all namespaces /// /// # Arguments /// /// * `km` - The KubernetesManager instance /// /// # Returns /// /// * `Result>` - Array of namespace names or an error fn namespaces_list(km: &mut KubernetesManager) -> Result> { 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 of resource counts by type or an error fn resource_counts(km: &mut KubernetesManager) -> Result> { 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>` - Success or an error fn pod_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box> { 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>` - Success or an error fn service_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box> { 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>` - Success or an error fn deployment_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box> { 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>` - Success or an error fn configmap_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box> { 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>` - Success or an error fn secret_delete(km: &mut KubernetesManager, name: String) -> Result<(), Box> { 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>` - Ok if registration was successful, Err otherwise pub fn register_kubernetes_module(engine: &mut Engine) -> Result<(), Box> { // Register KubernetesManager type engine.register_type::(); // 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 { Box::new(EvalAltResult::ErrorRuntime( format!("Kubernetes error: {}", error).into(), rhai::Position::NONE, )) }