brokkr-agent::work_orders::build
Rust
Build handler for Shipwright Build integration.
This module handles the execution of build work orders using Shipwright:
- Parsing Build and WorkOrder resources from YAML
- Applying Build resources to the cluster
- Creating BuildRun resources
- Watching BuildRun status until completion
- Extracting results (image digest, errors)
Shipwright Resources
- Build: Reusable template defining git source, build strategy, and output
- BuildRun: Execution instance created from a Build
- ClusterBuildStrategy: Pre-installed strategy (e.g., buildah)
Functions
Section titled “Functions”fn execute_build
Section titled “fn execute_build”pub
async fn execute_build( k8s_client: &K8sClient, yaml_content: &str, work_order_id: &str, deadline: Instant,) -> Result<Option<String>, Box<dyn std::error::Error + Send + Sync>>Executes a build using Shipwright.
This function:
- Parses the YAML content to find Build resources
- Applies Build resources to the cluster
- Creates a BuildRun
- Watches the BuildRun until completion
- Returns the image digest on success or error details on failure
Parameters:
| Name | Type | Description |
|---|---|---|
k8s_client |
&K8sClient |
Kubernetes client |
yaml_content |
&str |
Multi-document YAML containing Build and WorkOrder |
work_order_id |
&str |
Work order ID for labeling resources |
deadline |
Instant |
When the agent stops watching the BuildRun (see build_watch_budget) |
Returns:
Optional result message (image digest on success)
Source
pub async fn execute_build( k8s_client: &K8sClient, yaml_content: &str, work_order_id: &str, deadline: Instant,) -> Result<Option<String>, Box<dyn std::error::Error + Send + Sync>> { info!("Starting build execution for work order {}", work_order_id);
// Parse YAML documents let docs: Vec<serde_yaml::Value> = serde_yaml::Deserializer::from_str(yaml_content) .map(serde_yaml::Value::deserialize) .collect::<Result<Vec<_>, _>>()?;
if docs.is_empty() { return Err("No YAML documents found in work order content".into()); }
// Find Build resources and apply them let mut build_name: Option<String> = None; let mut build_namespace = String::from("default");
for doc in &docs { let api_version = doc.get("apiVersion").and_then(|v| v.as_str()); let kind = doc.get("kind").and_then(|v| v.as_str());
match (api_version, kind) { (Some(av), Some("Build")) if av.starts_with(SHIPWRIGHT_API_GROUP) => { // Apply the Build resource let metadata = doc.get("metadata"); if let Some(name) = metadata .and_then(|m| m.get("name")) .and_then(|n| n.as_str()) { build_name = Some(name.to_string()); } if let Some(ns) = metadata .and_then(|m| m.get("namespace")) .and_then(|n| n.as_str()) { build_namespace = ns.to_string(); }
info!("Applying Shipwright Build resource"); apply_shipwright_resource(k8s_client, doc).await?; } (Some(av), Some("WorkOrder")) if av.starts_with("brokkr.io") => { // Extract buildRef from WorkOrder if present if let Some(spec) = doc.get("spec") && let Some(build_ref) = spec .get("buildRef") .and_then(|b| b.get("name")) .and_then(|n| n.as_str()) && build_name.is_none() { build_name = Some(build_ref.to_string()); } debug!("Found brokkr WorkOrder resource, skipping apply (handled separately)"); } _ => { debug!("Skipping non-build resource: {:?}/{:?}", api_version, kind); } } }
let build_name = build_name.ok_or("No Build resource or buildRef found in YAML content")?; info!( "Using Build '{}' in namespace '{}'", build_name, build_namespace );
// Create BuildRun let buildrun_name = format!( "{}-{}", build_name, &work_order_id[..8.min(work_order_id.len())] ); info!("Creating BuildRun '{}'", buildrun_name);
let _buildrun = create_buildrun( k8s_client, &buildrun_name, &build_name, &build_namespace, work_order_id, ) .await?;
info!( "BuildRun '{}' created, waiting for completion", buildrun_name );
// Watch BuildRun until completion let result = watch_buildrun_completion(k8s_client, &buildrun_name, &build_namespace, deadline).await?;
Ok(result)}