17
examples/kubernetes-like/Cargo.toml
Normal file
17
examples/kubernetes-like/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "kubernetes-like"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
nocontrol.workspace = true
|
||||
nocontrol-tui.workspace = true
|
||||
|
||||
anyhow.workspace = true
|
||||
tokio.workspace = true
|
||||
serde.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
tracing.workspace = true
|
||||
rand.workspace = true
|
||||
uuid.workspace = true
|
||||
120
examples/kubernetes-like/src/main.rs
Normal file
120
examples/kubernetes-like/src/main.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use nocontrol::{
|
||||
Operator, OperatorState, Specification,
|
||||
manifests::{Action, Manifest, ManifestMetadata, ManifestState},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
// Setup logging to file
|
||||
let output_file = std::fs::File::create("target/nocontrol.log")?;
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(EnvFilter::from_default_env())
|
||||
.with_writer(output_file)
|
||||
.with_file(false)
|
||||
.with_line_number(false)
|
||||
.with_target(false)
|
||||
.without_time()
|
||||
.init();
|
||||
|
||||
let operator = OperatorState::new(MyOperator {});
|
||||
let control_plane = nocontrol::ControlPlane::new(operator);
|
||||
|
||||
// Add initial manifest
|
||||
control_plane
|
||||
.add_manifest(Manifest {
|
||||
name: "initial-deployment".into(),
|
||||
metadata: ManifestMetadata {},
|
||||
spec: Specifications::Deployment(DeploymentControllerManifest {
|
||||
name: "initial-app".into(),
|
||||
}),
|
||||
})
|
||||
.await?;
|
||||
|
||||
// Spawn random manifest updater
|
||||
tokio::spawn({
|
||||
let control_plane = control_plane.clone();
|
||||
async move {
|
||||
loop {
|
||||
let rand = {
|
||||
use rand::Rng;
|
||||
let mut rng = rand::rng();
|
||||
rng.random_range(3..8)
|
||||
};
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(rand)).await;
|
||||
|
||||
let random = uuid::Uuid::now_v7();
|
||||
|
||||
let _ = control_plane
|
||||
.add_manifest(Manifest {
|
||||
name: "initial-deployment".into(),
|
||||
metadata: ManifestMetadata {},
|
||||
spec: Specifications::Deployment(DeploymentControllerManifest {
|
||||
name: format!("app-{}", &random.to_string()),
|
||||
}),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Spawn control plane
|
||||
tokio::spawn({
|
||||
let control_plane = control_plane.clone();
|
||||
async move {
|
||||
let _ = control_plane.execute().await;
|
||||
}
|
||||
});
|
||||
|
||||
// Run TUI
|
||||
nocontrol_tui::run(control_plane).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MyOperator {}
|
||||
|
||||
impl Operator for MyOperator {
|
||||
type Specifications = Specifications;
|
||||
|
||||
async fn reconcile(
|
||||
&self,
|
||||
desired_manifest: &mut ManifestState<Specifications>,
|
||||
) -> anyhow::Result<Action> {
|
||||
match &desired_manifest.manifest.spec {
|
||||
Specifications::Deployment(spec) => {
|
||||
tracing::info!(
|
||||
"reconciliation was called for name = {}, value = {}",
|
||||
desired_manifest.manifest.name,
|
||||
spec.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Action::Requeue(std::time::Duration::from_secs(10)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub enum Specifications {
|
||||
Deployment(DeploymentControllerManifest),
|
||||
}
|
||||
|
||||
impl Specification for Specifications {
|
||||
fn kind(&self) -> &'static str {
|
||||
match self {
|
||||
Specifications::Deployment(_) => "deployment",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DeploymentControllerManifest {
|
||||
name: String,
|
||||
}
|
||||
Reference in New Issue
Block a user