use clawft_types::placement::engine::{
Execution, ExecutionVariant, PlacementPolicy, TrustTier, WorkloadRequirements, WorkloadSpec,
};
use clawft_types::placement::{
AttrPredicate, CapabilityId, MemoryDemand, PlacementTypeError, Requirement,
};
use crate::workload_runtime::VerifiedWorkload;
const ARCH_ORDER: &[&str] = &["aarch64", "armv7", "x86_64"];
fn exact(id: &str) -> Result<Requirement, PlacementTypeError> {
Ok(Requirement::exact(CapabilityId::new(id)?))
}
fn runtime(prefix: &str, attr: &str, arch: &str) -> Result<Requirement, PlacementTypeError> {
Requirement::prefix(prefix)?.try_with_where(AttrPredicate::has(attr, arch))
}
pub fn arch_routes(arch: &str) -> Result<Vec<ExecutionVariant>, PlacementTypeError> {
Ok(vec![
ExecutionVariant {
name: format!("{arch}-native"),
execution: Execution::Native,
requirements: vec![
exact(&format!("cpu.arch.{arch}"))?,
exact("os.linux")?,
runtime("runtime.native", "arches_native", arch)?,
],
},
ExecutionVariant {
name: format!("{arch}-container"),
execution: Execution::Native,
requirements: vec![runtime("runtime.container", "arches_native", arch)?],
},
ExecutionVariant {
name: format!("{arch}-emulated"),
execution: Execution::Emulated,
requirements: vec![runtime("runtime.container", "arches_emulated", arch)?],
},
])
}
pub fn route_of(variant: &str) -> &str {
variant.rsplit('-').next().unwrap_or(variant)
}
pub fn arch_of(variant: &str) -> &str {
variant.split('-').next().unwrap_or(variant)
}
pub fn cog_workload_spec(w: &VerifiedWorkload) -> Result<WorkloadSpec, String> {
let p = w.signed("placement").map_err(|e| e.to_string())?;
let mut arches: Vec<&str> = ARCH_ORDER
.iter()
.copied()
.filter(|a| p.binaries.contains_key(*a))
.collect();
let mut extra: Vec<&str> = p
.binaries
.keys()
.map(String::as_str)
.filter(|a| !ARCH_ORDER.contains(a))
.collect();
extra.sort_unstable();
arches.extend(extra);
if arches.is_empty() {
return Err("package has no binaries".into());
}
let mut variants = Vec::new();
for a in arches {
variants.extend(arch_routes(a).map_err(|e| e.to_string())?);
}
let mut refs = vec![p.package_id.clone()];
refs.extend(p.signer_keys.iter().cloned());
refs.extend(p.artifact_hashes.iter().cloned());
let spec = WorkloadSpec {
kind: w.kind.clone(),
name: w.id.clone(),
requirements: WorkloadRequirements {
common: Vec::new(),
variants,
memory: MemoryDemand {
host_bytes: u64::from(p.spec.resources.ram_mb) << 20,
accel_bytes: 0,
},
},
policy: PlacementPolicy {
min_trust: TrustTier::Paired,
revocable_refs: refs,
..PlacementPolicy::default()
},
};
spec.validate().map_err(|e| e.to_string())?;
Ok(spec)
}