clawft_kernel/workload_ctl/
cog_kind.rs1use clawft_types::placement::engine::{
17 Execution, ExecutionVariant, PlacementPolicy, TrustTier, WorkloadRequirements, WorkloadSpec,
18};
19use clawft_types::placement::{
20 AttrPredicate, CapabilityId, MemoryDemand, PlacementTypeError, Requirement,
21};
22
23use crate::workload_runtime::VerifiedWorkload;
24
25const ARCH_ORDER: &[&str] = &["aarch64", "armv7", "x86_64"];
27
28fn exact(id: &str) -> Result<Requirement, PlacementTypeError> {
29 Ok(Requirement::exact(CapabilityId::new(id)?))
30}
31
32fn runtime(prefix: &str, attr: &str, arch: &str) -> Result<Requirement, PlacementTypeError> {
33 Requirement::prefix(prefix)?.try_with_where(AttrPredicate::has(attr, arch))
34}
35
36pub fn arch_routes(arch: &str) -> Result<Vec<ExecutionVariant>, PlacementTypeError> {
38 Ok(vec![
39 ExecutionVariant {
40 name: format!("{arch}-native"),
41 execution: Execution::Native,
42 requirements: vec![
43 exact(&format!("cpu.arch.{arch}"))?,
44 exact("os.linux")?,
45 runtime("runtime.native", "arches_native", arch)?,
46 ],
47 },
48 ExecutionVariant {
49 name: format!("{arch}-container"),
50 execution: Execution::Native,
51 requirements: vec![runtime("runtime.container", "arches_native", arch)?],
52 },
53 ExecutionVariant {
54 name: format!("{arch}-emulated"),
55 execution: Execution::Emulated,
56 requirements: vec![runtime("runtime.container", "arches_emulated", arch)?],
57 },
58 ])
59}
60
61pub fn route_of(variant: &str) -> &str {
64 variant.rsplit('-').next().unwrap_or(variant)
65}
66
67pub fn arch_of(variant: &str) -> &str {
69 variant.split('-').next().unwrap_or(variant)
70}
71
72pub fn cog_workload_spec(w: &VerifiedWorkload) -> Result<WorkloadSpec, String> {
75 let p = w.signed("placement").map_err(|e| e.to_string())?;
76 let mut arches: Vec<&str> = ARCH_ORDER
77 .iter()
78 .copied()
79 .filter(|a| p.binaries.contains_key(*a))
80 .collect();
81 let mut extra: Vec<&str> = p
83 .binaries
84 .keys()
85 .map(String::as_str)
86 .filter(|a| !ARCH_ORDER.contains(a))
87 .collect();
88 extra.sort_unstable();
89 arches.extend(extra);
90 if arches.is_empty() {
91 return Err("package has no binaries".into());
92 }
93 let mut variants = Vec::new();
94 for a in arches {
95 variants.extend(arch_routes(a).map_err(|e| e.to_string())?);
96 }
97 let mut refs = vec![p.package_id.clone()];
98 refs.extend(p.signer_keys.iter().cloned());
99 refs.extend(p.artifact_hashes.iter().cloned());
100 let spec = WorkloadSpec {
101 kind: w.kind.clone(),
102 name: w.id.clone(),
103 requirements: WorkloadRequirements {
104 common: Vec::new(),
105 variants,
106 memory: MemoryDemand {
107 host_bytes: u64::from(p.spec.resources.ram_mb) << 20,
108 accel_bytes: 0,
109 },
110 },
111 policy: PlacementPolicy {
112 min_trust: TrustTier::Paired,
113 revocable_refs: refs,
114 ..PlacementPolicy::default()
115 },
116 };
117 spec.validate().map_err(|e| e.to_string())?;
118 Ok(spec)
119}