| Crates.io | nocontrol |
| lib.rs | nocontrol |
| version | 0.0.3 |
| created_at | 2026-01-07 09:37:06.60569+00 |
| updated_at | 2026-01-12 11:07:23.671395+00 |
| description | No control is an early version of a distributed work-stealing orchestrator |
| homepage | |
| repository | https://git.kjuulh.io/kjuulh/nocontrol |
| max_upload_size | |
| id | 2027885 |
| size | 67,132 |
A Rust library for building Kubernetes-style reconciliation controllers. Define your desired state with manifests and let nocontrol continuously reconcile them.
Add to your Cargo.toml:
[package]
...
[dependencies]
nocontrol = "0.0.1"
...
Note: Requires Rust nightly (edition 2024).
use nocontrol::{
ControlPlane, Operator, OperatorState, Specification,
manifests::{Action, Manifest, ManifestMetadata, ManifestState},
};
use serde::{Deserialize, Serialize};
// 1. Define your specification
#[derive(Clone, Serialize, Deserialize)]
struct MySpec {
replicas: u32,
}
impl Specification for MySpec {
fn kind(&self) -> &'static str {
"MyResource"
}
}
// 2. Implement the Operator trait
#[derive(Clone)]
struct MyOperator;
impl Operator for MyOperator {
type Specifications = MySpec;
async fn reconcile(
&self,
manifest: &mut ManifestState<MySpec>,
) -> anyhow::Result<Action> {
println!("Reconciling: {}", manifest.manifest.name);
// Your reconciliation logic here
// ...
// Requeue after 30 seconds
Ok(Action::Requeue(std::time::Duration::from_secs(30)))
}
}
// 3. Run the control plane
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let operator = OperatorState::new(MyOperator);
let control_plane = ControlPlane::new(operator);
// Add a manifest
control_plane.add_manifest(Manifest {
name: "my-resource".into(),
metadata: ManifestMetadata {},
spec: MySpec { replicas: 3 },
}).await?;
// Run the reconciliation loop
control_plane.execute().await
}
Configure the operator with OperatorConfig:
use nocontrol::{OperatorConfig, OperatorState};
use std::time::Duration;
let config = OperatorConfig {
resync_interval: Duration::from_secs(10 * 60), // 10 minutes
..Default::default()
};
let operator = OperatorState::new_with_config(MyOperator, config);
Return from reconcile() to control scheduling:
Action::None - No follow-up reconciliationAction::Requeue(duration) - Reconcile again after the specified delayMIT