use k8s_maestro::{
clients::MaestroK8sClient,
entities::MaestroContainer,
steps::{KubeJobStepBuilder, KubePodStepBuilder, KubeWorkFlowStep, ResourceLimits, RestartPolicy, WorkFlowStep},
};
use std::collections::BTreeMap;
#[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> {
log::set_max_level(log::LevelFilter::Info);
println!("=== Rust Step Examples with K8s Maestro ===\n");
println!("Creating Kubernetes client...");
let k8s_client = MaestroK8sClient::new().await?;
example_basic_rust_job(&k8s_client).await?;
example_rust_job_with_resources(&k8s_client).await?;
example_parallel_rust_job(&k8s_client).await?;
example_rust_pod_with_sidecar(&k8s_client).await?;
example_rust_pipeline(&k8s_client).await?;
println!("\n=== All examples completed successfully ===");
Ok(())
}
async fn example_basic_rust_job(k8s_client: &MaestroK8sClient) -> anyhow::Result<()> {
println!("Example 1: Basic Rust job with minimal configuration");
let job = KubeJobStepBuilder::new()
.with_name("rust-basic-job")
.with_namespace("default")
.add_container(Box::new(
MaestroContainer::new("rust:1.75-slim", "rust-app")
.set_arguments(&[
"sh".to_string(),
"-c".to_string(),
"echo 'Hello from Rust!' && rustc --version".to_string(),
]),
))
.with_client(k8s_client.clone())
.with_dry_run(true) .build()?;
println!("Created job: {}", job.step_id());
println!("Namespace: {}", job.namespace());
println!("Resource: {}", job.resource_name());
println!("Dry run: No actual Kubernetes resources created\n");
Ok(())
}
async fn example_rust_job_with_resources(
k8s_client: &MaestroK8sClient,
) -> anyhow::Result<()> {
println!("Example 2: Rust job with resource limits and environment variables");
let mut env_vars = BTreeMap::new();
env_vars.insert("RUST_LOG".to_string(), "info".to_string());
env_vars.insert("RUST_BACKTRACE".to_string(), "1".to_string());
env_vars.insert("APP_ENVIRONMENT".to_string(), "production".to_string());
let resource_limits = ResourceLimits::new()
.with_cpu("1000m") .with_memory("2Gi") .with_cpu_request("500m") .with_memory_request("1Gi");
let job = KubeJobStepBuilder::new()
.with_name("rust-resource-job")
.with_namespace("default")
.add_container(Box::new(
MaestroContainer::new("rust:1.75-slim", "rust-processor")
.set_arguments(&[
"sh".to_string(),
"-c".to_string(),
"cargo build --release && ./target/release/processor".to_string(),
])
.set_environment_variables(env_vars)
.set_resource_bounds(resource_limits),
))
.with_backoff_limit(3) .with_ttl_seconds(3600) .with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("Created job: {}", job.step_id());
println!("Resource limits: CPU 1000m, Memory 2Gi");
println!("Environment: RUST_LOG=info, APP_ENVIRONMENT=production");
println!("Retry policy: Up to 3 retries on failure\n");
Ok(())
}
async fn example_parallel_rust_job(k8s_client: &MaestroK8sClient) -> anyhow::Result<()> {
println!("Example 3: Rust job with parallel processing configuration");
let job = KubeJobStepBuilder::new()
.with_name("rust-parallel-job")
.with_namespace("default")
.add_container(Box::new(
MaestroContainer::new("rust:1.75-slim", "parallel-processor")
.set_arguments(&[
"sh".to_string(),
"-c".to_string(),
"cargo run --release -- --parallel --threads 8".to_string(),
]),
))
.with_parallelism(4) .with_completions(10) .with_backoff_limit(6)
.with_restart_policy(RestartPolicy::OnFailure)
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("Created job: {}", job.step_id());
println!("Parallel execution: 4 concurrent pods");
println!("Total workload: 10 job completions");
println!("Use case: Parallel CSV/Parquet processing with Rayon\n");
Ok(())
}
async fn example_rust_pod_with_sidecar(
k8s_client: &MaestroK8sClient,
) -> anyhow::Result<()> {
println!("Example 4: Rust pod with sidecar for logging");
let job = KubePodStepBuilder::new()
.with_name("rust-app-with-logging")
.with_namespace("default")
.add_container(Box::new(
MaestroContainer::new("rust:1.75-slim", "rust-application")
.set_arguments(&[
"sh".to_string(),
"-c".to_string(),
"cargo run --release > /app/logs/app.log 2>&1".to_string(),
]),
))
.add_sidecar(Box::new(
MaestroContainer::new("fluent/fluent-bit:2.2", "log-collector")
.set_arguments(&[
"fluent-bit".to_string(),
"-i".to_string(),
"tail".to_string(),
"-p".to_string(),
"path=/app/logs/app.log".to_string(),
"-o".to_string(),
"stdout".to_string(),
]),
))
.with_restart_policy(RestartPolicy::OnFailure)
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("Created pod: {}", job.step_id());
println!("Main container: Rust application writing logs");
println!("Sidecar container: Fluent Bit log forwarding");
println!("Architecture: Classic sidecar pattern for log aggregation\n");
Ok(())
}
async fn example_rust_pipeline(k8s_client: &MaestroK8sClient) -> anyhow::Result<()> {
println!("Example 5: Data processing pipeline with multiple steps");
let ingestion_job = KubeJobStepBuilder::new()
.with_name("rust-data-ingestion")
.with_namespace("default")
.add_container(Box::new(
MaestroContainer::new("rust:1.75-slim", "ingestion")
.set_arguments(&[
"sh".to_string(),
"-c".to_string(),
"cargo run --bin ingest -- --source s3://data-bucket/input/".to_string(),
]),
))
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("Step 1: Data ingestion - {}", ingestion_job.step_id());
let transform_job = KubeJobStepBuilder::new()
.with_name("rust-data-transform")
.with_namespace("default")
.add_container(Box::new(
MaestroContainer::new("rust:1.75-slim", "transform")
.set_arguments(&[
"sh".to_string(),
"-c".to_string(),
"cargo run --bin transform -- --parallel --format parquet".to_string(),
])
.set_resource_bounds(
ResourceLimits::new()
.with_cpu("2000m")
.with_memory("4Gi")
.with_cpu_request("1000m")
.with_memory_request("2Gi"),
),
))
.with_parallelism(8)
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("Step 2: Data transformation - {}", transform_job.step_id());
println!("Configuration: 8 parallel workers, high memory allocation");
let validation_job = KubeJobStepBuilder::new()
.with_name("rust-data-validation")
.with_namespace("default")
.add_container(Box::new(
MaestroContainer::new("rust:1.75-slim", "validation")
.set_arguments(&[
"sh".to_string(),
"-c".to_string(),
"cargo test --bin validate -- --nocapture".to_string(),
]),
))
.with_backoff_limit(2)
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("Step 3: Data validation - {}", validation_job.step_id());
println!("Pipeline: Ingest -> Transform -> Validate");
println!("All steps configured with dry_run: true\n");
Ok(())
}