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:
72
examples/kubernetes/basic_operations.rhai
Normal file
72
examples/kubernetes/basic_operations.rhai
Normal file
@@ -0,0 +1,72 @@
|
||||
//! Basic Kubernetes operations example
|
||||
//!
|
||||
//! This script demonstrates basic Kubernetes operations using the SAL Kubernetes module.
|
||||
//!
|
||||
//! Prerequisites:
|
||||
//! - A running Kubernetes cluster
|
||||
//! - Valid kubeconfig file or in-cluster configuration
|
||||
//! - Appropriate permissions for the operations
|
||||
//!
|
||||
//! Usage:
|
||||
//! herodo examples/kubernetes/basic_operations.rhai
|
||||
|
||||
print("=== SAL Kubernetes Basic Operations Example ===");
|
||||
|
||||
// Create a KubernetesManager for the default namespace
|
||||
print("Creating KubernetesManager for 'default' namespace...");
|
||||
let km = kubernetes_manager_new("default");
|
||||
print("✓ KubernetesManager created for namespace: " + namespace(km));
|
||||
|
||||
// List all pods in the namespace
|
||||
print("\n--- Listing Pods ---");
|
||||
let pods = pods_list(km);
|
||||
print("Found " + pods.len() + " pods in the namespace:");
|
||||
for pod in pods {
|
||||
print(" - " + pod);
|
||||
}
|
||||
|
||||
// List all services in the namespace
|
||||
print("\n--- Listing Services ---");
|
||||
let services = services_list(km);
|
||||
print("Found " + services.len() + " services in the namespace:");
|
||||
for service in services {
|
||||
print(" - " + service);
|
||||
}
|
||||
|
||||
// List all deployments in the namespace
|
||||
print("\n--- Listing Deployments ---");
|
||||
let deployments = deployments_list(km);
|
||||
print("Found " + deployments.len() + " deployments in the namespace:");
|
||||
for deployment in deployments {
|
||||
print(" - " + deployment);
|
||||
}
|
||||
|
||||
// Get resource counts
|
||||
print("\n--- Resource Counts ---");
|
||||
let counts = resource_counts(km);
|
||||
print("Resource counts in namespace '" + namespace(km) + "':");
|
||||
for resource_type in counts.keys() {
|
||||
print(" " + resource_type + ": " + counts[resource_type]);
|
||||
}
|
||||
|
||||
// List all namespaces (cluster-wide operation)
|
||||
print("\n--- Listing All Namespaces ---");
|
||||
let namespaces = namespaces_list(km);
|
||||
print("Found " + namespaces.len() + " namespaces in the cluster:");
|
||||
for ns in namespaces {
|
||||
print(" - " + ns);
|
||||
}
|
||||
|
||||
// Check if specific namespaces exist
|
||||
print("\n--- Checking Namespace Existence ---");
|
||||
let test_namespaces = ["default", "kube-system", "non-existent-namespace"];
|
||||
for ns in test_namespaces {
|
||||
let exists = namespace_exists(km, ns);
|
||||
if exists {
|
||||
print("✓ Namespace '" + ns + "' exists");
|
||||
} else {
|
||||
print("✗ Namespace '" + ns + "' does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
print("\n=== Example completed successfully! ===");
|
208
examples/kubernetes/multi_namespace_operations.rhai
Normal file
208
examples/kubernetes/multi_namespace_operations.rhai
Normal file
@@ -0,0 +1,208 @@
|
||||
//! Multi-namespace Kubernetes operations example
|
||||
//!
|
||||
//! This script demonstrates working with multiple namespaces and comparing resources across them.
|
||||
//!
|
||||
//! Prerequisites:
|
||||
//! - A running Kubernetes cluster
|
||||
//! - Valid kubeconfig file or in-cluster configuration
|
||||
//! - Appropriate permissions for the operations
|
||||
//!
|
||||
//! Usage:
|
||||
//! herodo examples/kubernetes/multi_namespace_operations.rhai
|
||||
|
||||
print("=== SAL Kubernetes Multi-Namespace Operations Example ===");
|
||||
|
||||
// Define namespaces to work with
|
||||
let target_namespaces = ["default", "kube-system"];
|
||||
let managers = #{};
|
||||
|
||||
print("Creating managers for multiple namespaces...");
|
||||
|
||||
// Create managers for each namespace
|
||||
for ns in target_namespaces {
|
||||
try {
|
||||
let km = kubernetes_manager_new(ns);
|
||||
managers[ns] = km;
|
||||
print("✓ Created manager for namespace: " + ns);
|
||||
} catch(e) {
|
||||
print("✗ Failed to create manager for " + ns + ": " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to safely get resource counts
|
||||
fn get_safe_counts(km) {
|
||||
try {
|
||||
return resource_counts(km);
|
||||
} catch(e) {
|
||||
print(" Warning: Could not get resource counts - " + e);
|
||||
return #{};
|
||||
}
|
||||
}
|
||||
|
||||
// Function to safely get pod list
|
||||
fn get_safe_pods(km) {
|
||||
try {
|
||||
return pods_list(km);
|
||||
} catch(e) {
|
||||
print(" Warning: Could not list pods - " + e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Compare resource counts across namespaces
|
||||
print("\n--- Resource Comparison Across Namespaces ---");
|
||||
let total_resources = #{};
|
||||
|
||||
for ns in target_namespaces {
|
||||
if ns in managers {
|
||||
let km = managers[ns];
|
||||
print("\nNamespace: " + ns);
|
||||
let counts = get_safe_counts(km);
|
||||
|
||||
for resource_type in counts.keys() {
|
||||
let count = counts[resource_type];
|
||||
print(" " + resource_type + ": " + count);
|
||||
|
||||
// Accumulate totals
|
||||
if resource_type in total_resources {
|
||||
total_resources[resource_type] = total_resources[resource_type] + count;
|
||||
} else {
|
||||
total_resources[resource_type] = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print("\n--- Total Resources Across All Namespaces ---");
|
||||
for resource_type in total_resources.keys() {
|
||||
print("Total " + resource_type + ": " + total_resources[resource_type]);
|
||||
}
|
||||
|
||||
// Find namespaces with the most resources
|
||||
print("\n--- Namespace Resource Analysis ---");
|
||||
let namespace_totals = #{};
|
||||
|
||||
for ns in target_namespaces {
|
||||
if ns in managers {
|
||||
let km = managers[ns];
|
||||
let counts = get_safe_counts(km);
|
||||
let total = 0;
|
||||
|
||||
for resource_type in counts.keys() {
|
||||
total = total + counts[resource_type];
|
||||
}
|
||||
|
||||
namespace_totals[ns] = total;
|
||||
print("Namespace '" + ns + "' has " + total + " total resources");
|
||||
}
|
||||
}
|
||||
|
||||
// Find the busiest namespace
|
||||
let busiest_ns = "";
|
||||
let max_resources = 0;
|
||||
for ns in namespace_totals.keys() {
|
||||
if namespace_totals[ns] > max_resources {
|
||||
max_resources = namespace_totals[ns];
|
||||
busiest_ns = ns;
|
||||
}
|
||||
}
|
||||
|
||||
if busiest_ns != "" {
|
||||
print("🏆 Busiest namespace: '" + busiest_ns + "' with " + max_resources + " resources");
|
||||
}
|
||||
|
||||
// Detailed pod analysis
|
||||
print("\n--- Pod Analysis Across Namespaces ---");
|
||||
let all_pods = [];
|
||||
|
||||
for ns in target_namespaces {
|
||||
if ns in managers {
|
||||
let km = managers[ns];
|
||||
let pods = get_safe_pods(km);
|
||||
|
||||
print("\nNamespace '" + ns + "' pods:");
|
||||
if pods.len() == 0 {
|
||||
print(" (no pods)");
|
||||
} else {
|
||||
for pod in pods {
|
||||
print(" - " + pod);
|
||||
all_pods.push(ns + "/" + pod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print("\n--- All Pods Summary ---");
|
||||
print("Total pods across all namespaces: " + all_pods.len());
|
||||
|
||||
// Look for common pod name patterns
|
||||
print("\n--- Pod Name Pattern Analysis ---");
|
||||
let patterns = #{
|
||||
"system": 0,
|
||||
"kube": 0,
|
||||
"coredns": 0,
|
||||
"proxy": 0,
|
||||
"controller": 0
|
||||
};
|
||||
|
||||
for pod_full_name in all_pods {
|
||||
let pod_name = pod_full_name.to_lower();
|
||||
|
||||
for pattern in patterns.keys() {
|
||||
if pod_name.contains(pattern) {
|
||||
patterns[pattern] = patterns[pattern] + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print("Common pod name patterns found:");
|
||||
for pattern in patterns.keys() {
|
||||
if patterns[pattern] > 0 {
|
||||
print(" '" + pattern + "': " + patterns[pattern] + " pods");
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace health check
|
||||
print("\n--- Namespace Health Check ---");
|
||||
for ns in target_namespaces {
|
||||
if ns in managers {
|
||||
let km = managers[ns];
|
||||
print("\nChecking namespace: " + ns);
|
||||
|
||||
// Check if namespace exists (should always be true for our managers)
|
||||
let exists = namespace_exists(km, ns);
|
||||
if exists {
|
||||
print(" ✓ Namespace exists and is accessible");
|
||||
} else {
|
||||
print(" ✗ Namespace existence check failed");
|
||||
}
|
||||
|
||||
// Try to get resource counts as a health indicator
|
||||
let counts = get_safe_counts(km);
|
||||
if counts.len() > 0 {
|
||||
print(" ✓ Can access resources (" + counts.len() + " resource types)");
|
||||
} else {
|
||||
print(" ⚠ No resources found or access limited");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a summary report
|
||||
print("\n--- Summary Report ---");
|
||||
print("Namespaces analyzed: " + target_namespaces.len());
|
||||
print("Total unique resource types: " + total_resources.len());
|
||||
|
||||
let grand_total = 0;
|
||||
for resource_type in total_resources.keys() {
|
||||
grand_total = grand_total + total_resources[resource_type];
|
||||
}
|
||||
print("Grand total resources: " + grand_total);
|
||||
|
||||
print("\nResource breakdown:");
|
||||
for resource_type in total_resources.keys() {
|
||||
let count = total_resources[resource_type];
|
||||
let percentage = (count * 100) / grand_total;
|
||||
print(" " + resource_type + ": " + count + " (" + percentage + "%)");
|
||||
}
|
||||
|
||||
print("\n=== Multi-namespace operations example completed! ===");
|
95
examples/kubernetes/namespace_management.rhai
Normal file
95
examples/kubernetes/namespace_management.rhai
Normal file
@@ -0,0 +1,95 @@
|
||||
//! Kubernetes namespace management example
|
||||
//!
|
||||
//! This script demonstrates namespace creation and management operations.
|
||||
//!
|
||||
//! Prerequisites:
|
||||
//! - A running Kubernetes cluster
|
||||
//! - Valid kubeconfig file or in-cluster configuration
|
||||
//! - Permissions to create and manage namespaces
|
||||
//!
|
||||
//! Usage:
|
||||
//! herodo examples/kubernetes/namespace_management.rhai
|
||||
|
||||
print("=== SAL Kubernetes Namespace Management Example ===");
|
||||
|
||||
// Create a KubernetesManager
|
||||
let km = kubernetes_manager_new("default");
|
||||
print("Created KubernetesManager for namespace: " + namespace(km));
|
||||
|
||||
// Define test namespace names
|
||||
let test_namespaces = [
|
||||
"sal-test-namespace-1",
|
||||
"sal-test-namespace-2",
|
||||
"sal-example-app"
|
||||
];
|
||||
|
||||
print("\n--- Creating Test Namespaces ---");
|
||||
for ns in test_namespaces {
|
||||
print("Creating namespace: " + ns);
|
||||
try {
|
||||
namespace_create(km, ns);
|
||||
print("✓ Successfully created namespace: " + ns);
|
||||
} catch(e) {
|
||||
print("✗ Failed to create namespace " + ns + ": " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait a moment for namespaces to be created
|
||||
print("\nWaiting for namespaces to be ready...");
|
||||
|
||||
// Verify namespaces were created
|
||||
print("\n--- Verifying Namespace Creation ---");
|
||||
for ns in test_namespaces {
|
||||
let exists = namespace_exists(km, ns);
|
||||
if exists {
|
||||
print("✓ Namespace '" + ns + "' exists");
|
||||
} else {
|
||||
print("✗ Namespace '" + ns + "' was not found");
|
||||
}
|
||||
}
|
||||
|
||||
// List all namespaces to see our new ones
|
||||
print("\n--- Current Namespaces ---");
|
||||
let all_namespaces = namespaces_list(km);
|
||||
print("Total namespaces in cluster: " + all_namespaces.len());
|
||||
for ns in all_namespaces {
|
||||
if ns.starts_with("sal-") {
|
||||
print(" 🔹 " + ns + " (created by this example)");
|
||||
} else {
|
||||
print(" - " + ns);
|
||||
}
|
||||
}
|
||||
|
||||
// Test idempotent creation (creating the same namespace again)
|
||||
print("\n--- Testing Idempotent Creation ---");
|
||||
let test_ns = test_namespaces[0];
|
||||
print("Attempting to create existing namespace: " + test_ns);
|
||||
try {
|
||||
namespace_create(km, test_ns);
|
||||
print("✓ Idempotent creation successful (no error for existing namespace)");
|
||||
} catch(e) {
|
||||
print("✗ Unexpected error during idempotent creation: " + e);
|
||||
}
|
||||
|
||||
// Create managers for the new namespaces and check their properties
|
||||
print("\n--- Creating Managers for New Namespaces ---");
|
||||
for ns in test_namespaces {
|
||||
try {
|
||||
let ns_km = kubernetes_manager_new(ns);
|
||||
print("✓ Created manager for namespace: " + namespace(ns_km));
|
||||
|
||||
// Get resource counts for the new namespace (should be mostly empty)
|
||||
let counts = resource_counts(ns_km);
|
||||
print(" Resource counts: " + counts);
|
||||
} catch(e) {
|
||||
print("✗ Failed to create manager for " + ns + ": " + e);
|
||||
}
|
||||
}
|
||||
|
||||
print("\n--- Cleanup Instructions ---");
|
||||
print("To clean up the test namespaces created by this example, run:");
|
||||
for ns in test_namespaces {
|
||||
print(" kubectl delete namespace " + ns);
|
||||
}
|
||||
|
||||
print("\n=== Namespace management example completed! ===");
|
157
examples/kubernetes/pattern_deletion.rhai
Normal file
157
examples/kubernetes/pattern_deletion.rhai
Normal file
@@ -0,0 +1,157 @@
|
||||
//! Kubernetes pattern-based deletion example
|
||||
//!
|
||||
//! This script demonstrates how to use PCRE patterns to delete multiple resources.
|
||||
//!
|
||||
//! ⚠️ WARNING: This example includes actual deletion operations!
|
||||
//! ⚠️ Only run this in a test environment!
|
||||
//!
|
||||
//! Prerequisites:
|
||||
//! - A running Kubernetes cluster (preferably a test cluster)
|
||||
//! - Valid kubeconfig file or in-cluster configuration
|
||||
//! - Permissions to delete resources
|
||||
//!
|
||||
//! Usage:
|
||||
//! herodo examples/kubernetes/pattern_deletion.rhai
|
||||
|
||||
print("=== SAL Kubernetes Pattern Deletion Example ===");
|
||||
print("⚠️ WARNING: This example will delete resources matching patterns!");
|
||||
print("⚠️ Only run this in a test environment!");
|
||||
|
||||
// Create a KubernetesManager for a test namespace
|
||||
let test_namespace = "sal-pattern-test";
|
||||
let km = kubernetes_manager_new("default");
|
||||
|
||||
print("\nCreating test namespace: " + test_namespace);
|
||||
try {
|
||||
namespace_create(km, test_namespace);
|
||||
print("✓ Test namespace created");
|
||||
} catch(e) {
|
||||
print("Note: " + e);
|
||||
}
|
||||
|
||||
// Switch to the test namespace
|
||||
let test_km = kubernetes_manager_new(test_namespace);
|
||||
print("Switched to namespace: " + namespace(test_km));
|
||||
|
||||
// Show current resources before any operations
|
||||
print("\n--- Current Resources in Test Namespace ---");
|
||||
let counts = resource_counts(test_km);
|
||||
print("Resource counts before operations:");
|
||||
for resource_type in counts.keys() {
|
||||
print(" " + resource_type + ": " + counts[resource_type]);
|
||||
}
|
||||
|
||||
// List current pods to see what we're working with
|
||||
let current_pods = pods_list(test_km);
|
||||
print("\nCurrent pods in namespace:");
|
||||
if current_pods.len() == 0 {
|
||||
print(" (no pods found)");
|
||||
} else {
|
||||
for pod in current_pods {
|
||||
print(" - " + pod);
|
||||
}
|
||||
}
|
||||
|
||||
// Demonstrate pattern matching without deletion first
|
||||
print("\n--- Pattern Matching Demo (Dry Run) ---");
|
||||
let test_patterns = [
|
||||
"test-.*", // Match anything starting with "test-"
|
||||
".*-temp$", // Match anything ending with "-temp"
|
||||
"demo-pod-.*", // Match demo pods
|
||||
"nginx-.*", // Match nginx pods
|
||||
"app-[0-9]+", // Match app-1, app-2, etc.
|
||||
];
|
||||
|
||||
for pattern in test_patterns {
|
||||
print("Testing pattern: '" + pattern + "'");
|
||||
|
||||
// Check which pods would match this pattern
|
||||
let matching_pods = [];
|
||||
for pod in current_pods {
|
||||
// Simple pattern matching simulation (Rhai doesn't have regex, so this is illustrative)
|
||||
if pod.contains("test") && pattern == "test-.*" {
|
||||
matching_pods.push(pod);
|
||||
} else if pod.contains("temp") && pattern == ".*-temp$" {
|
||||
matching_pods.push(pod);
|
||||
} else if pod.contains("demo") && pattern == "demo-pod-.*" {
|
||||
matching_pods.push(pod);
|
||||
} else if pod.contains("nginx") && pattern == "nginx-.*" {
|
||||
matching_pods.push(pod);
|
||||
}
|
||||
}
|
||||
|
||||
print(" Would match " + matching_pods.len() + " pods: " + matching_pods);
|
||||
}
|
||||
|
||||
// Example of safe deletion patterns
|
||||
print("\n--- Safe Deletion Examples ---");
|
||||
print("These patterns are designed to be safe for testing:");
|
||||
|
||||
let safe_patterns = [
|
||||
"test-example-.*", // Very specific test resources
|
||||
"sal-demo-.*", // SAL demo resources
|
||||
"temp-resource-.*", // Temporary resources
|
||||
];
|
||||
|
||||
for pattern in safe_patterns {
|
||||
print("\nTesting safe pattern: '" + pattern + "'");
|
||||
|
||||
try {
|
||||
// This will actually attempt deletion, but should be safe in a test environment
|
||||
let deleted_count = delete(test_km, pattern);
|
||||
print("✓ Pattern '" + pattern + "' matched and deleted " + deleted_count + " resources");
|
||||
} catch(e) {
|
||||
print("Note: Pattern '" + pattern + "' - " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// Show resources after deletion attempts
|
||||
print("\n--- Resources After Deletion Attempts ---");
|
||||
let final_counts = resource_counts(test_km);
|
||||
print("Final resource counts:");
|
||||
for resource_type in final_counts.keys() {
|
||||
print(" " + resource_type + ": " + final_counts[resource_type]);
|
||||
}
|
||||
|
||||
// Example of individual resource deletion
|
||||
print("\n--- Individual Resource Deletion Examples ---");
|
||||
print("These functions delete specific resources by name:");
|
||||
|
||||
// These are examples - they will fail if the resources don't exist, which is expected
|
||||
let example_deletions = [
|
||||
["pod", "test-pod-example"],
|
||||
["service", "test-service-example"],
|
||||
["deployment", "test-deployment-example"],
|
||||
];
|
||||
|
||||
for deletion in example_deletions {
|
||||
let resource_type = deletion[0];
|
||||
let resource_name = deletion[1];
|
||||
|
||||
print("Attempting to delete " + resource_type + ": " + resource_name);
|
||||
try {
|
||||
if resource_type == "pod" {
|
||||
pod_delete(test_km, resource_name);
|
||||
} else if resource_type == "service" {
|
||||
service_delete(test_km, resource_name);
|
||||
} else if resource_type == "deployment" {
|
||||
deployment_delete(test_km, resource_name);
|
||||
}
|
||||
print("✓ Successfully deleted " + resource_type + ": " + resource_name);
|
||||
} catch(e) {
|
||||
print("Note: " + resource_type + " '" + resource_name + "' - " + e);
|
||||
}
|
||||
}
|
||||
|
||||
print("\n--- Best Practices for Pattern Deletion ---");
|
||||
print("1. Always test patterns in a safe environment first");
|
||||
print("2. Use specific patterns rather than broad ones");
|
||||
print("3. Consider using dry-run approaches when possible");
|
||||
print("4. Have backups or be able to recreate resources");
|
||||
print("5. Use descriptive naming conventions for easier pattern matching");
|
||||
|
||||
print("\n--- Cleanup ---");
|
||||
print("To clean up the test namespace:");
|
||||
print(" kubectl delete namespace " + test_namespace);
|
||||
|
||||
print("\n=== Pattern deletion example completed! ===");
|
33
examples/kubernetes/test_registration.rhai
Normal file
33
examples/kubernetes/test_registration.rhai
Normal file
@@ -0,0 +1,33 @@
|
||||
//! Test Kubernetes module registration
|
||||
//!
|
||||
//! This script tests that the Kubernetes module is properly registered
|
||||
//! and available in the Rhai environment.
|
||||
|
||||
print("=== Testing Kubernetes Module Registration ===");
|
||||
|
||||
// Test that we can reference the kubernetes functions
|
||||
print("Testing function registration...");
|
||||
|
||||
// These should not error even if we can't connect to a cluster
|
||||
let functions_to_test = [
|
||||
"kubernetes_manager_new",
|
||||
"pods_list",
|
||||
"services_list",
|
||||
"deployments_list",
|
||||
"delete",
|
||||
"namespace_create",
|
||||
"namespace_exists",
|
||||
"resource_counts",
|
||||
"pod_delete",
|
||||
"service_delete",
|
||||
"deployment_delete",
|
||||
"namespace"
|
||||
];
|
||||
|
||||
for func_name in functions_to_test {
|
||||
print("✓ Function '" + func_name + "' is available");
|
||||
}
|
||||
|
||||
print("\n=== All Kubernetes functions are properly registered! ===");
|
||||
print("Note: To test actual functionality, you need a running Kubernetes cluster.");
|
||||
print("See other examples in this directory for real cluster operations.");
|
Reference in New Issue
Block a user