feat: config types and loader
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
08b7f94e4c
commit
8ab3bb2d12
@@ -0,0 +1,141 @@
|
|||||||
|
use anyhow::{Context, Result};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum NodeRole { Primary, Secondary }
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct NodeConfig {
|
||||||
|
pub name: String,
|
||||||
|
pub role: NodeRole,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct HotConfig {
|
||||||
|
pub path: PathBuf,
|
||||||
|
pub max_gb: u64,
|
||||||
|
pub stale_hours: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct WarmConfig {
|
||||||
|
pub projects_path: PathBuf,
|
||||||
|
pub zfs_dataset: String,
|
||||||
|
pub snapshot_retain_hours: u64,
|
||||||
|
pub snapshot_retain_days: u64,
|
||||||
|
pub snapshot_retain_weeks: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct ColdConfig {
|
||||||
|
pub archive_path: PathBuf,
|
||||||
|
pub zfs_dataset: String,
|
||||||
|
pub retain_weeks: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct ReplicationConfig {
|
||||||
|
pub receive_from_peer: Option<bool>,
|
||||||
|
pub peer_user: Option<String>,
|
||||||
|
pub send_to_host: Option<String>,
|
||||||
|
pub send_to_user: Option<String>,
|
||||||
|
pub cold_dataset_on_peer: Option<String>,
|
||||||
|
pub nightly_at: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct Config {
|
||||||
|
pub node: NodeConfig,
|
||||||
|
pub hot: HotConfig,
|
||||||
|
pub warm: WarmConfig,
|
||||||
|
pub cold: Option<ColdConfig>,
|
||||||
|
pub replication: Option<ReplicationConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn load(path: &Path) -> Result<Self> {
|
||||||
|
let content = std::fs::read_to_string(path)
|
||||||
|
.with_context(|| format!("reading config at {}", path.display()))?;
|
||||||
|
toml::from_str(&content)
|
||||||
|
.with_context(|| format!("parsing config at {}", path.display()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_path() -> PathBuf {
|
||||||
|
PathBuf::from("/etc/claw-store/config.toml")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_primary_config() {
|
||||||
|
let toml = r#"
|
||||||
|
[node]
|
||||||
|
name = "architect"
|
||||||
|
role = "primary"
|
||||||
|
|
||||||
|
[hot]
|
||||||
|
path = "/hot/targets"
|
||||||
|
max_gb = 200
|
||||||
|
stale_hours = 48
|
||||||
|
|
||||||
|
[warm]
|
||||||
|
projects_path = "/slab/projects"
|
||||||
|
zfs_dataset = "slab/projects"
|
||||||
|
snapshot_retain_hours = 24
|
||||||
|
snapshot_retain_days = 7
|
||||||
|
snapshot_retain_weeks = 4
|
||||||
|
|
||||||
|
[cold]
|
||||||
|
archive_path = "/data/archive"
|
||||||
|
zfs_dataset = "data/archive"
|
||||||
|
retain_weeks = 12
|
||||||
|
|
||||||
|
[replication]
|
||||||
|
receive_from_peer = true
|
||||||
|
peer_user = "osobh"
|
||||||
|
"#;
|
||||||
|
let cfg: Config = toml::from_str(toml).unwrap();
|
||||||
|
assert_eq!(cfg.node.name, "architect");
|
||||||
|
assert_eq!(cfg.node.role, NodeRole::Primary);
|
||||||
|
assert_eq!(cfg.hot.max_gb, 200);
|
||||||
|
assert!(cfg.cold.is_some());
|
||||||
|
assert_eq!(cfg.cold.unwrap().retain_weeks, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_secondary_config() {
|
||||||
|
let toml = r#"
|
||||||
|
[node]
|
||||||
|
name = "tank"
|
||||||
|
role = "secondary"
|
||||||
|
|
||||||
|
[hot]
|
||||||
|
path = "/hot/targets"
|
||||||
|
max_gb = 300
|
||||||
|
stale_hours = 48
|
||||||
|
|
||||||
|
[warm]
|
||||||
|
projects_path = "/slab/projects"
|
||||||
|
zfs_dataset = "slab/projects"
|
||||||
|
snapshot_retain_hours = 24
|
||||||
|
snapshot_retain_days = 7
|
||||||
|
snapshot_retain_weeks = 4
|
||||||
|
|
||||||
|
[replication]
|
||||||
|
send_to_host = "10.10.0.9"
|
||||||
|
send_to_user = "osobh"
|
||||||
|
cold_dataset_on_peer = "data/archive/tank-projects"
|
||||||
|
nightly_at = "03:30"
|
||||||
|
"#;
|
||||||
|
let cfg: Config = toml::from_str(toml).unwrap();
|
||||||
|
assert_eq!(cfg.node.role, NodeRole::Secondary);
|
||||||
|
assert!(cfg.cold.is_none());
|
||||||
|
let rep = cfg.replication.unwrap();
|
||||||
|
assert_eq!(rep.send_to_host.unwrap(), "10.10.0.9");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
mod config;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("claw-store 0.1.0");
|
println!("claw-store 0.1.0");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user