use anyhow::Result;
use std::collections::HashMap;
use std::sync::Arc;
use uuid::Uuid;
use crate::cluster::store::ClusterStore;
use tatara_core::cluster::types::NodeMeta;
use tatara_core::domain::allocation::Allocation;
use tatara_core::domain::job::{Job, JobStatus};
use tatara_core::domain::node::{Node, NodeStatus};
pub struct ClusterStoreAdapter {
store: Arc<ClusterStore>,
}
impl ClusterStoreAdapter {
pub fn new(store: Arc<ClusterStore>) -> Self {
Self { store }
}
pub async fn list_jobs(&self) -> Vec<Job> {
self.store.list_jobs().await
}
pub async fn list_nodes(&self) -> Vec<Node> {
self.store
.list_nodes()
.await
.into_iter()
.map(node_meta_to_node)
.collect()
}
pub async fn scheduling_generation(&self) -> u64 {
let state = self.store.state().await;
state.scheduling_generation
}
pub async fn put_job(&self, job: Job) -> Result<()> {
self.store.put_job(job).await?;
Ok(())
}
pub async fn update_job_status(&self, job_id: &str, status: JobStatus) -> Result<()> {
self.store.update_job_status(job_id, status).await?;
Ok(())
}
pub async fn put_allocation(&self, alloc: Allocation) -> Result<()> {
self.store.put_allocation(alloc).await?;
Ok(())
}
pub async fn is_leader(&self) -> bool {
self.store.is_leader().await
}
}
fn node_meta_to_node(meta: NodeMeta) -> Node {
let mut attributes = HashMap::new();
attributes.insert("os".to_string(), meta.os.clone());
attributes.insert("arch".to_string(), meta.arch.clone());
attributes.insert("hostname".to_string(), meta.hostname.clone());
Node {
id: format!("{}", meta.node_id),
address: meta.http_addr.clone(),
status: if meta.eligible {
NodeStatus::Ready
} else {
NodeStatus::Draining
},
eligible: meta.eligible,
total_resources: meta.total_resources,
available_resources: meta.available_resources,
attributes,
drivers: meta.drivers,
last_heartbeat: meta.joined_at,
allocations: Vec::new(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Utc;
use tatara_core::cluster::types::NodeRoles;
use tatara_core::domain::job::Resources;
#[test]
fn test_node_meta_conversion() {
let meta = NodeMeta {
node_id: 42,
hostname: "test-host".to_string(),
http_addr: "127.0.0.1:4646".to_string(),
gossip_addr: "127.0.0.1:5679".to_string(),
raft_addr: "127.0.0.1:4649".to_string(),
os: "darwin".to_string(),
arch: "aarch64".to_string(),
roles: NodeRoles::default(),
drivers: vec![],
total_resources: Resources {
cpu_mhz: 4000,
memory_mb: 8192,
},
available_resources: Resources {
cpu_mhz: 3000,
memory_mb: 6144,
},
allocations_running: 2,
joined_at: Utc::now(),
version: "0.2.0".to_string(),
eligible: true,
wireguard_pubkey: None,
tunnel_address: None,
};
let node = node_meta_to_node(meta);
assert_eq!(node.id, "42");
assert_eq!(node.status, NodeStatus::Ready);
assert!(node.eligible);
assert_eq!(node.attributes["arch"], "aarch64");
assert_eq!(node.total_resources.cpu_mhz, 4000);
}
}