# Kubernetes Module (`herolib_virt::kubernetes`)

## Overview

The Kubernetes module provides a comprehensive Rust interface for managing Kubernetes clusters. It offers namespace-scoped resource management, pod lifecycle operations, service deployment, and advanced features like Traefik configuration and container image building.

This is a **Rust-first** module with full type safety and async/await support for production Kubernetes operations.

## Quick Start

### Basic Usage

```rust
use herolib_virt::kubernetes::KubernetesManager;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a manager for a namespace
    let km = KubernetesManager::new("my-namespace").await?;
    
    // List all pods
    let pods = km.pods_list().await?;
    for pod in pods {
        println!("Pod: {:?}", pod.metadata.name);
    }
    
    Ok(())
}
```

### Running Integration Tests

The module includes comprehensive integration tests in the `01_basic_operations.rs` example:

```bash
cd packages/virt
cargo run --example 01_basic_operations --features kubernetes
```

This example creates 5 Kubernetes resources and runs 14 verification tests to ensure everything works correctly.

## Core Components

### 1. KubernetesManager

The primary entry point for all Kubernetes operations. Each instance operates on a single namespace.

```rust
// Create a manager for a namespace
let km = KubernetesManager::new("my-namespace").await?;

// Get the namespace this manager operates on
let namespace = km.namespace();
println!("Operating on namespace: {}", namespace);

// Get the Kubernetes client
let client = km.client();

// Get the configuration
let config = km.config();
```

### 2. Resource Management

#### Pods

```rust
use std::collections::BTreeMap;

// Create a simple pod
let labels = [("app".to_string(), "my-app".to_string())]
    .iter()
    .cloned()
    .collect::<BTreeMap<_, _>>();

km.pod_create("my-pod", "nginx:alpine", labels.clone()).await?;

// Create a pod with environment variables
let env_vars = [("MY_VAR".to_string(), "my-value".to_string())]
    .iter()
    .cloned()
    .collect::<BTreeMap<_, _>>();

km.pod_create_with_env("my-pod", "nginx:alpine", labels, env_vars).await?;

// List all pods in the namespace
let pods = km.pods_list().await?;
for pod in pods {
    println!("Pod: {:?}", pod.metadata.name);
}

// Get a specific pod
let pod = km.pod_get("my-pod").await?;
println!("Pod image: {:?}", pod.spec.unwrap().containers[0].image);

// Delete a pod
km.pod_delete("my-pod").await?;
```

#### Services

```rust
use std::collections::BTreeMap;

// Create a service
let selector = [("app".to_string(), "my-app".to_string())]
    .iter()
    .cloned()
    .collect::<BTreeMap<_, _>>();

km.service_create("my-service", selector, 80, 8080).await?;

// List services
let services = km.services_list().await?;
for service in services {
    println!("Service: {:?}", service.metadata.name);
}

// Get a specific service
let svc = km.service_get("my-service").await?;

// Delete a service
km.service_delete("my-service").await?;
```

#### Deployments

```rust
use std::collections::BTreeMap;

// Create a deployment
let labels = [("app".to_string(), "my-app".to_string())]
    .iter()
    .cloned()
    .collect::<BTreeMap<_, _>>();

let env_vars = [("LOG_LEVEL".to_string(), "info".to_string())]
    .iter()
    .cloned()
    .collect::<BTreeMap<_, _>>();

km.deployment_create(
    "my-deployment",
    "nginx:alpine",
    3,
    labels,
    env_vars,
).await?;

// List deployments
let deployments = km.deployments_list().await?;
for deployment in deployments {
    println!("Deployment: {:?}", deployment.metadata.name);
}

// Get a specific deployment
let deploy = km.deployment_get("my-deployment").await?;

// Delete a deployment
km.deployment_delete("my-deployment").await?;
```

#### ConfigMaps

```rust
use std::collections::BTreeMap;

// Create a ConfigMap
let config_data = [
    ("config.json".to_string(), r#"{"key": "value"}"#.to_string()),
    ("settings.yaml".to_string(), "debug: true".to_string()),
]
.iter()
.cloned()
.collect::<BTreeMap<_, _>>();

km.configmap_create("my-config", config_data).await?;

// List ConfigMaps
let configmaps = km.configmaps_list().await?;
for cm in configmaps {
    println!("ConfigMap: {:?}", cm.metadata.name);
}

// Get a specific ConfigMap
let config = km.configmap_get("my-config").await?;
if let Some(data) = config.data {
    for (key, value) in data {
        println!("Key: {}, Value: {}", key, value);
    }
}

// Delete a ConfigMap
km.configmap_delete("my-config").await?;
```

#### Secrets

```rust
use std::collections::BTreeMap;

// Create a Secret
let secret_data = [
    ("username".to_string(), "admin".to_string()),
    ("password".to_string(), "secret123".to_string()),
]
.iter()
.cloned()
.collect::<BTreeMap<_, _>>();

km.secret_create("my-secret", secret_data, "Opaque").await?;

// List Secrets
let secrets = km.secrets_list().await?;
for secret in secrets {
    println!("Secret: {:?}", secret.metadata.name);
}

// Get a specific Secret
let secret = km.secret_get("my-secret").await?;
if let Some(data) = secret.data {
    for (key, _value) in data {
        println!("Secret key: {}", key);
    }
}

// Delete a Secret
km.secret_delete("my-secret").await?;
```

### 3. Namespace Management

```rust
let km = KubernetesManager::new("default").await?;

// Create a namespace (idempotent)
km.namespace_create("my-new-namespace").await?;

// Check if namespace exists
let exists = km.namespace_exists("my-new-namespace").await?;
if exists {
    println!("Namespace exists!");
}

// List all namespaces
let namespaces = km.namespaces_list().await?;
for ns in namespaces {
    println!("Namespace: {:?}", ns.metadata.name);
}

// Reset a namespace (delete and recreate)
km.namespace_reset("my-namespace").await?;

// Delete a namespace
km.namespace_delete("my-new-namespace").await?;
```

### 4. Pattern-Based Deletion

Delete resources matching PCRE regex patterns:

```rust
// Delete all resources matching a pattern
let deleted_count = km.delete("test-.*").await?;
println!("Deleted {} resources", deleted_count);

// Delete pods matching a pattern
km.delete("my-app-pod-.*").await?;
```

### 5. Service Connection Info

Get connection information for services:

```rust
let km = KubernetesManager::new("my-namespace").await?;

// Get service connection info
let info = km.service_connection_info("my-service").await?;

// Access connection properties
println!("Service: {}", info.name);
println!("Namespace: {}", info.namespace);
println!("Hostname: {}", info.hostname);
println!("Cluster IP: {}", info.cluster_ip);
println!("Service Type: {}", info.service_type);

// Get ports
let ports = &info.ports;
let node_ports = &info.node_ports;

// Get connection strings
let conn_str = info.connection_string();
let host_conn = info.host_accessible_hostname();
let localhost_conn = info.localhost_connection_string();

println!("Connection: {}", conn_str);
```

### 6. Resource Counts

```rust
let counts = km.resource_counts().await?;
println!("Pods: {}", counts.get("pods").unwrap_or(&0));
println!("Services: {}", counts.get("services").unwrap_or(&0));
println!("Deployments: {}", counts.get("deployments").unwrap_or(&0));
```

### 7. Deploy Application (Convenience Function)

Deploy a complete application with deployment and service:

```rust
use std::collections::BTreeMap;

let labels = [("app".to_string(), "my-app".to_string())]
    .iter()
    .cloned()
    .collect::<BTreeMap<_, _>>();

let env_vars = [("DATABASE_URL".to_string(), "postgres://localhost:5432/mydb".to_string())]
    .iter()
    .cloned()
    .collect::<BTreeMap<_, _>>();

km.deploy_application(
    "my-app",
    "my-image:latest",
    3,
    8080,
    labels,
    env_vars,
).await?;
```

## Fluent API (Builder Pattern)

The module includes a fluent builder API for more ergonomic resource creation:

```rust
use herolib_virt::kubernetes::KubernetesContext;

// Create a pod using the fluent API
KubernetesContext::pod("my-pod", "nginx:alpine")
    .label("app", "my-app")
    .label("environment", "development")
    .apply(&km)
    .await?;

// Create a service using the fluent API
KubernetesContext::service("my-service")
    .selector("app", "my-app")
    .port(80, 8080)
    .apply(&km)
    .await?;

// Create a ConfigMap using the fluent API
KubernetesContext::configmap("my-config")
    .data("config.json", r#"{"key": "value"}"#)
    .apply(&km)
    .await?;

// Create a Secret using the fluent API
KubernetesContext::secret("my-secret")
    .data("username", "admin")
    .data("password", "secret123")
    .secret_type("Opaque")
    .apply(&km)
    .await?;

// Create a namespace using the fluent API
KubernetesContext::namespace("my-namespace")
    .apply(&km)
    .await?;
```

## Traefik Configuration

Configure Traefik IngressRoutes, Middlewares, and TLS options:

### HTTP Routes

```rust
use herolib_virt::kubernetes::HttpRoute;

let route = HttpRoute::new("my-app-route", "production")
    .hostname("app.example.com")
    .path_prefix("/api")
    .service("my-service", 8080)
    .middleware("auth-middleware")
    .priority(100)
    .build();

// TODO: Apply the route to the cluster
```

## KubeBuilder: Build Container Images in Kubernetes

Build container images inside Kubernetes using Buildah:

```rust
use herolib_virt::kubernetes::BuildMachine;

// Create a build machine configuration
let machine = BuildMachine::new("build-namespace", "my-builder");

// Provision the build machine (creates a pod)
let handle = machine.provision().await?;

println!("Pod name: {}", handle.pod_name);
println!("Namespace: {}", handle.namespace);

// Execute commands in the build machine
let result = handle.exec(&["ls", "-la"]).await?;
if result.success {
    println!("Output: {}", result.stdout);
}

// Run buildah commands directly
let buildah_result = handle.buildah(&["images"]).await?;
println!("Images: {}", buildah_result.stdout);

// Destroy the build machine when done
handle.destroy().await?;
```

## Error Handling

```rust
use herolib_virt::kubernetes::KubernetesResult;

// All operations return KubernetesResult<T>
match km.pod_get("my-pod").await {
    Ok(pod) => println!("Found pod: {:?}", pod),
    Err(e) => eprintln!("Error: {:?}", e),
}

// Or use the ? operator in async functions
let pod = km.pod_get("my-pod").await?;
```

## Production Safety Features

The KubernetesManager includes built-in production safety features:

- **Configurable Timeouts**: All operations have configurable timeouts
- **Exponential Backoff Retry**: Automatic retries with exponential backoff for transient failures
- **Rate Limiting**: Built-in rate limiting to prevent API overload
- **Cluster Validation**: Validates cluster connectivity on manager creation
- **Name Normalization**: RFC 1123 compliant name validation through fluent API

## Integration Testing

The module includes comprehensive integration tests. See the example below for how to test your Kubernetes operations:

### Running Tests

```bash
cd packages/virt
cargo run --example 01_basic_operations --features kubernetes
```

### Test Coverage

The example creates and verifies:
- ✅ Namespace creation and deletion
- ✅ Pod creation and property verification
- ✅ Service creation and connection info
- ✅ ConfigMap creation and data integrity
- ✅ Secret creation and data verification
- ✅ RFC 1123 name normalization

Each verification is a separate test within the example. All tests pass on a live Kubernetes cluster.

## API Reference

### KubernetesManager Methods

| Method | Description |
|--------|-------------|
| `new(namespace)` | Create a new manager for a namespace |
| `with_config(namespace, config)` | Create a manager with custom configuration |
| `namespace()` | Get the namespace this manager operates on |
| `client()` | Get the underlying Kubernetes client |
| `config()` | Get the manager configuration |
| `pods_list()` | List all pods in the namespace |
| `pod_create(name, image, labels)` | Create a pod |
| `pod_create_with_env(name, image, labels, env)` | Create a pod with environment variables |
| `pod_get(name)` | Get a specific pod |
| `pod_delete(name)` | Delete a specific pod |
| `services_list()` | List all services in the namespace |
| `service_create(name, selector, port, target_port)` | Create a service |
| `service_create_lb(name, selector, port, target_port)` | Create a LoadBalancer service |
| `service_get(name)` | Get a specific service |
| `service_delete(name)` | Delete a specific service |
| `deployments_list()` | List all deployments in the namespace |
| `deployment_create(name, image, replicas, labels, env)` | Create a deployment |
| `deployment_get(name)` | Get a specific deployment |
| `deployment_delete(name)` | Delete a specific deployment |
| `configmaps_list()` | List all ConfigMaps in the namespace |
| `configmap_create(name, data)` | Create a ConfigMap |
| `configmap_get(name)` | Get a specific ConfigMap |
| `configmap_delete(name)` | Delete a specific ConfigMap |
| `secrets_list()` | List all Secrets in the namespace |
| `secret_create(name, data, type)` | Create a Secret |
| `secret_get(name)` | Get a specific Secret |
| `secret_delete(name)` | Delete a specific Secret |
| `delete(pattern)` | Delete resources matching PCRE pattern |
| `namespaces_list()` | List all namespaces in the cluster |
| `namespace_create(name)` | Create a namespace (idempotent) |
| `namespace_exists(name)` | Check if a namespace exists |
| `namespace_delete(name)` | Delete a namespace |
| `namespace_reset(name)` | Delete and recreate a namespace |
| `resource_counts()` | Get counts of all resources |
| `deploy_application(name, image, replicas, port, labels, env)` | Deploy a full application |
| `service_connection_info(name)` | Get connection info for a service |

### Fluent API Methods

#### Pod Builder
```rust
KubernetesContext::pod(name, image)
    .label(key, value)
    .apply(&km)
    .await?
```

#### Service Builder
```rust
KubernetesContext::service(name)
    .selector(key, value)
    .port(port, target_port)
    .apply(&km)
    .await?
```

#### ConfigMap Builder
```rust
KubernetesContext::configmap(name)
    .data(key, value)
    .apply(&km)
    .await?
```

#### Secret Builder
```rust
KubernetesContext::secret(name)
    .data(key, value)
    .secret_type(type)
    .apply(&km)
    .await?
```

#### Namespace Builder
```rust
KubernetesContext::namespace(name)
    .apply(&km)
    .await?
```

## Complete Example: Deploying a Web Application

```rust
use herolib_virt::kubernetes::KubernetesManager;
use std::collections::BTreeMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Setup namespace
    let default_km = KubernetesManager::new("default").await?;
    default_km.namespace_create("my-app").await?;
    
    // Switch to app namespace
    let km = KubernetesManager::new("my-app").await?;
    
    // Deploy the application
    let labels = [("app".to_string(), "web-frontend".to_string())]
        .iter()
        .cloned()
        .collect::<BTreeMap<_, _>>();
    
    let env = [("API_URL".to_string(), "http://api-service:8080".to_string())]
        .iter()
        .cloned()
        .collect::<BTreeMap<_, _>>();
    
    km.deploy_application(
        "web-frontend",
        "myregistry/frontend:v1.0",
        3,
        80,
        labels,
        env,
    ).await?;
    
    // Check deployment status
    let counts = km.resource_counts().await?;
    println!("Deployed resources:");
    println!("  Pods: {}", counts.get("pods").unwrap_or(&0));
    println!("  Services: {}", counts.get("services").unwrap_or(&0));
    println!("  Deployments: {}", counts.get("deployments").unwrap_or(&0));
    
    // Get service connection info
    let svc_info = km.service_connection_info("web-frontend").await?;
    println!("Service available at: {}", svc_info.connection_string());
    
    Ok(())
}
```

## See Also

- [Integration Tests](../../../../../packages/virt/examples/01_basic_operations.rs) - Comprehensive example with 14 tests
- [Kubernetes Testing Quick Start](../../../../../KUBERNETES_TEST_QUICK_START.md) - How to run the tests
- [Kubernetes Testing Complete](../../../../../KUBERNETES_TESTING_COMPLETE.md) - Full testing documentation
- [Buildah Module](../buildah/README.md) - Container image building
