use k8s_maestro::{
clients::MaestroK8sClient, MaestroClientBuilder, WorkflowBuilder, PythonStepBuilder, ResourceLimits,
};
use k8s_maestro::steps::{WorkFlowStep, ExecutableWorkFlowStep};
use std::time::Duration;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
log::set_max_level(log::LevelFilter::Info);
env_logger::init();
println!("=== K8s Maestro Python Step Examples ===\n");
println!("Note: This example demonstrates the API usage patterns.");
println!("In production, you would need a valid Kubernetes configuration.\n");
println!("Creating Kubernetes client...");
let k8s_client = MaestroK8sClient::new().await?;
println!("✓ Kubernetes client created\n");
println!("Creating Maestro client (dry run mode)...");
let maestro_client = MaestroClientBuilder::new()
.with_namespace("default")
.with_dry_run(true) .build()?;
println!("✓ Maestro client created in dry-run mode\n");
example_basic_python_step(&k8s_client).await?;
example_python_with_requirements(&k8s_client).await?;
example_python_with_resource_limits(&k8s_client).await?;
example_python_with_environment_variables(&k8s_client).await?;
example_python_workflow(&k8s_client, &maestro_client).await?;
println!("\n=== All examples completed successfully ===");
Ok(())
}
async fn example_basic_python_step(k8s_client: &MaestroK8sClient) -> anyhow::Result<()> {
println!("Example 1: Basic Python step with inline code");
println!("─────────────────────────────────────────────");
let python_code = r#"
import sys
print("Hello from Python step!")
print(f"Python version: {sys.version}")
print("Processing data...")
# Simple data processing
data = [1, 2, 3, 4, 5]
result = sum(data)
print(f"Sum of {data} = {result}")
"#;
let step = PythonStepBuilder::new()
.with_name("basic-python-step")
.with_code(python_code)
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("✓ Created basic Python step: {}", step.step_id());
println!(" - Inline code: {} bytes", python_code.len());
println!(" - Default image: python:3.12-slim");
let result = step.execute()?;
println!("✓ Step execution result: {:?}", result.status);
Ok(())
}
async fn example_python_with_requirements(k8s_client: &MaestroK8sClient) -> anyhow::Result<()> {
println!("\nExample 2: Python step with package requirements");
println!("─────────────────────────────────────────────────");
let python_code = r#"
import pandas as pd
import numpy as np
# Create a sample dataset
data = {
'name': ['Alice', 'Bob', 'Charlie'],
'age': [25, 30, 35],
'city': ['NYC', 'LA', 'SF']
}
df = pd.DataFrame(data)
print("Created DataFrame:")
print(df)
# Calculate statistics
print(f"\nAverage age: {df['age'].mean()}")
print(f"Age range: {df['age'].min()} - {df['age'].max()}")
"#;
let requirements = vec![
"pandas>=2.0.0",
"numpy>=1.24.0",
];
let step = PythonStepBuilder::new()
.with_name("python-with-requirements")
.with_code(python_code)
.with_requirements(&requirements)
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("✓ Created Python step with requirements: {}", step.step_id());
println!(" - Packages: {}", requirements.join(", "));
println!(" - Code size: {} bytes", python_code.len());
let result = step.execute()?;
println!("✓ Step execution result: {:?}", result.status);
Ok(())
}
async fn example_python_with_resource_limits(k8s_client: &MaestroK8sClient) -> anyhow::Result<()> {
println!("\nExample 3: Python step with resource limits");
println!("───────────────────────────────────────────");
let python_code = r#"
import time
import psutil
import os
print("Starting resource-intensive task...")
print(f"Available memory: {psutil.virtual_memory().available / (1024**3):.2f} GB")
# Simulate some work
for i in range(5):
print(f"Processing iteration {i+1}/5")
time.sleep(1)
print("Task completed!")
"#;
let resource_limits = ResourceLimits::new()
.with_cpu("500m") .with_cpu_request("250m") .with_memory("512Mi") .with_memory_request("256Mi");
let step = PythonStepBuilder::new()
.with_name("python-with-limits")
.with_code(python_code)
.with_requirements(&["psutil>=5.9.0"])
.with_resource_limits(resource_limits)
.with_timeout(Duration::from_secs(60))
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("✓ Created Python step with resource limits: {}", step.step_id());
println!(" - CPU limit: 500m");
println!(" - CPU request: 250m");
println!(" - Memory limit: 512Mi");
println!(" - Memory request: 256Mi");
println!(" - Timeout: 60 seconds");
let result = step.execute()?;
println!("✓ Step execution result: {:?}", result.status);
Ok(())
}
async fn example_python_with_environment_variables(k8s_client: &MaestroK8sClient) -> anyhow::Result<()> {
println!("\nExample 4: Python step with environment variables");
println!("──────────────────────────────────────────────────");
let python_code = r#"
import os
import json
# Access environment variables
database_url = os.getenv('DATABASE_URL')
api_key = os.getenv('API_KEY')
debug_mode = os.getenv('DEBUG_MODE')
batch_size = os.getenv('BATCH_SIZE', '100')
print("Configuration loaded:")
print(f" Database URL: {database_url}")
print(f" API Key: {api_key[:10]}..." if api_key else " API Key: Not set")
print(f" Debug Mode: {debug_mode}")
print(f" Batch Size: {batch_size}")
# Simulate processing with configuration
config = {
'database_url': database_url,
'debug': debug_mode == 'true',
'batch_size': int(batch_size)
}
print(f"\nProcessing with config: {json.dumps(config, indent=2)}")
print("Processing complete!")
"#;
let step = PythonStepBuilder::new()
.with_name("python-with-env-vars")
.with_code(python_code)
.with_env("DATABASE_URL", "postgresql://localhost:5432/mydb")
.with_env("API_KEY", "sk-proj-abc123xyz789")
.with_env("DEBUG_MODE", "true")
.with_env("BATCH_SIZE", "50")
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("✓ Created Python step with environment variables: {}", step.step_id());
println!(" - DATABASE_URL: postgresql://localhost:5432/mydb");
println!(" - API_KEY: sk-proj-*** (redacted)");
println!(" - DEBUG_MODE: true");
println!(" - BATCH_SIZE: 50");
let result = step.execute()?;
println!("✓ Step execution result: {:?}", result.status);
Ok(())
}
async fn example_python_workflow(
k8s_client: &MaestroK8sClient,
maestro_client: &k8s_maestro::MaestroClient,
) -> anyhow::Result<()> {
println!("\nExample 5: Complete workflow with multiple Python steps");
println!("──────────────────────────────────────────────────────────");
let prepare_step = PythonStepBuilder::new()
.with_name("prepare-data")
.with_code(r#"
import json
data = {'records': [i for i in range(100)]}
with open('/output/data.json', 'w') as f:
json.dump(data, f)
print(f"Prepared {len(data['records'])} records")
"#)
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
let process_step = PythonStepBuilder::new()
.with_name("process-data")
.with_code(r#"
import json
with open('/output/data.json', 'r') as f:
data = json.load(f)
processed = [x * 2 for x in data['records']]
print(f"Processed {len(processed)} records")
print(f"Sample results: {processed[:5]}")
"#)
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
let analyze_step = PythonStepBuilder::new()
.with_name("analyze-data")
.with_code(r#"
import json
with open('/output/data.json', 'r') as f:
data = json.load(f)
records = data['records']
print(f"Analysis Results:")
print(f" Count: {len(records)}")
print(f" Min: {min(records)}")
print(f" Max: {max(records)}")
print(f" Sum: {sum(records)}")
print(f" Average: {sum(records)/len(records):.2f}")
"#)
.with_client(k8s_client.clone())
.with_dry_run(true)
.build()?;
println!("✓ Created 3 Python steps:");
println!(" 1. prepare-data - Data preparation");
println!(" 2. process-data - Data processing");
println!(" 3. analyze-data - Data analysis");
let workflow = WorkflowBuilder::new()
.with_name("python-data-pipeline")
.with_namespace("default")
.add_step(prepare_step)
.add_step(process_step)
.add_step(analyze_step)
.with_parallelism(1) .build()?;
println!("\n✓ Built workflow: {}", workflow.name);
println!(" - Steps: {}", workflow.steps.len());
println!(" - Parallelism: 1 (sequential execution)");
let created = maestro_client.create_workflow(workflow)?;
println!("✓ Workflow created (dry run): {}", created.name());
println!(" - Workflow ID: {}", created.id());
println!(" - Namespace: {}", created.namespace());
Ok(())
}