use std::collections::BTreeMap;
use std::path::Path;
use std::sync::Arc;
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use clawft_types::placement::engine::WorkloadSpec;
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use crate::workload_ctl::PlaneError;
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use crate::workload_pkg::TrustAnchors;
use crate::workload_pkg::{ManifestEnvelope, ManifestError};
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
use crate::workload_runtime::VerifiedWorkload;
mod cog;
mod health;
mod project;
#[cfg(test)]
mod tests;
#[cfg(all(test, feature = "workload-runtime", feature = "mesh", unix, feature = "native"))]
mod project_tests;
pub use cog::CogKind;
pub use health::{Health, HealthSample, HealthSpec, SampleState, judge_process};
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix, feature = "native"))]
pub use project::{ProjectFacts, ProjectPrepareError, prepare_project};
pub use project::{KIND_PROJECT, ProjectKind, project_healthy};
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
pub use cog::load_cog_shaped;
pub const MAX_KIND_LEN: usize = 32;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("unknown workload kind {0:?}")]
pub struct UnknownKind(pub String);
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("workload kind {0:?} is already registered")]
pub struct DuplicateKind(pub String);
pub trait WorkloadKind: Send + Sync {
fn id(&self) -> &'static str;
fn validate(&self, envelope: &ManifestEnvelope) -> Result<(), ManifestError>;
fn health(&self) -> HealthSpec {
HealthSpec::default()
}
fn judge(&self, sample: &HealthSample) -> Health {
judge_process(sample)
}
fn migratable(&self) -> bool {
true
}
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
fn load(
&self,
package_dir: &Path,
anchors: &TrustAnchors,
kinds: &KindRegistry,
) -> Result<VerifiedWorkload, PlaneError>;
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
fn spec(&self, workload: &VerifiedWorkload) -> Result<WorkloadSpec, String>;
#[cfg(all(feature = "workload-runtime", feature = "mesh", unix))]
fn adapters(&self) -> &'static [&'static str];
}
#[derive(Clone, Default)]
pub struct KindRegistry {
kinds: BTreeMap<&'static str, Arc<dyn WorkloadKind>>,
}
impl KindRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn builtin() -> Self {
let mut r = Self::new();
r.register(Arc::new(CogKind))
.expect("builtin kind ids are distinct");
r.register(Arc::new(ProjectKind))
.expect("builtin kind ids are distinct");
r
}
pub fn register(&mut self, kind: Arc<dyn WorkloadKind>) -> Result<(), DuplicateKind> {
let id = kind.id();
if self.kinds.contains_key(id) {
return Err(DuplicateKind(id.to_string()));
}
self.kinds.insert(id, kind);
Ok(())
}
pub fn get(&self, id: &str) -> Option<&Arc<dyn WorkloadKind>> {
self.kinds.get(id)
}
pub fn require(&self, id: &str) -> Result<&Arc<dyn WorkloadKind>, UnknownKind> {
self.get(id)
.ok_or_else(|| UnknownKind(id.chars().take(MAX_KIND_LEN).collect()))
}
pub fn ids(&self) -> Vec<&'static str> {
self.kinds.keys().copied().collect()
}
}
impl std::fmt::Debug for KindRegistry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_set().entries(self.kinds.keys()).finish()
}
}
pub fn validate_envelope(
registry: &KindRegistry,
envelope: &ManifestEnvelope,
) -> Result<(), ManifestError> {
registry.require(&envelope.kind)?.validate(envelope)
}
pub fn peek_manifest_kind(package_dir: &Path) -> Option<String> {
use crate::workload_pkg::verify::read_bounded;
use crate::workload_pkg::{MANIFEST_FILE, MAX_MANIFEST_BYTES};
let bytes = read_bounded(
&package_dir.join(MANIFEST_FILE),
MANIFEST_FILE,
MAX_MANIFEST_BYTES as u64,
)
.ok()?;
peek_kind_in(&bytes)
}
pub fn peek_kind_in(manifest: &[u8]) -> Option<String> {
use crate::workload_pkg::manifest::valid_token;
let doc: serde_json::Value = serde_json::from_slice(manifest).ok()?;
let kind = doc.get("kind")?.as_str()?;
valid_token(kind, MAX_KIND_LEN).then(|| kind.to_string())
}