use std::path::PathBuf; use figment::{ providers::{Env, Format, Json, Toml}, Figment, Metadata, Provider, }; use hickory_proto::rr::Name; use serde::{Deserialize, Serialize}; /// libvirt storage pool configuration #[derive(Clone, Debug, Serialize, Deserialize)] pub struct StorageConfig { /// The primary storage pool, allocated to all VMs. pub primary_pool: String, /// The secondary storage pool, allocated to any VMs that require slower storage. pub secondary_pool: String, /// Pool containing cloud-init base images. pub base_image_pool: String, } /// Provides the basic SOA (Start-of-Authority) for the internal DNS zone. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SOAConfig { pub nzr_domain: Name, pub contact: Name, pub refresh: i32, pub retry: i32, pub expire: i32, } /// DNS server configuration. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DNSConfig { pub listen_addr: String, pub port: u16, pub default_zone: Name, pub soa: SOAConfig, } /// DHCP server configuration. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DHCPConfig { pub listen_addr: String, pub port: u16, } /// Cloud-init configuration, used by omyacid. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct CloudConfig { pub listen_addr: String, pub port: u16, pub http_addr: Option, pub admin_user: String, } impl CloudConfig { pub fn http_addr(&self) -> String { if let Some(http_addr) = &self.http_addr { if http_addr.ends_with('/') { http_addr.clone() } else { format!("{}/", http_addr) } } else { format!("http://{}:{}/", self.listen_addr, self.port) } } } /// Server<->Client RPC configuration. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct RPCConfig { pub socket_path: PathBuf, pub admin_group: Option, } /// The root configuration struct. #[derive(Debug, Serialize, Deserialize)] pub struct Config { pub rpc: RPCConfig, pub log_level: String, /// Where database information should be stored. pub db_uri: String, pub qemu_img_path: Option, /// The libvirt URI to use for connections; e.g. `qemu:///system`. pub libvirt_uri: String, pub storage: StorageConfig, pub dns: DNSConfig, pub dhcp: DHCPConfig, pub cloud: CloudConfig, } impl Default for Config { fn default() -> Self { Self { log_level: "WARN".to_owned(), qemu_img_path: None, rpc: RPCConfig { socket_path: PathBuf::from("/var/run/nazrin/nzrd.sock"), admin_group: None, }, db_uri: "sqlite:/var/lib/nazrin/main_sql.db".to_owned(), libvirt_uri: match std::env::var("LIBVIRT_URI") { Ok(v) => v, Err(_) => String::from("qemu:///system"), }, storage: StorageConfig { primary_pool: "pri".to_owned(), secondary_pool: "data".to_owned(), base_image_pool: "images".to_owned(), }, dns: DNSConfig { listen_addr: "127.0.0.1".to_owned(), port: 5353, default_zone: Name::from_utf8("servers.local").unwrap(), soa: SOAConfig { nzr_domain: Name::from_utf8("nzr.local").unwrap(), contact: Name::from_utf8("admin.nzr.local").unwrap(), refresh: 86400, retry: 7200, expire: 3_600_000, }, }, dhcp: DHCPConfig { listen_addr: "127.0.0.1".to_owned(), port: 67, }, cloud: CloudConfig { listen_addr: "0.0.0.0".to_owned(), port: 80, http_addr: None, admin_user: "admin".to_owned(), }, } } } impl Provider for Config { fn metadata(&self) -> figment::Metadata { Metadata::named("Nazrin config") } fn data( &self, ) -> Result, figment::Error> { figment::providers::Serialized::defaults(Config::default()).data() } fn profile(&self) -> Option { None } } impl Config { pub fn figment() -> Figment { let mut fig = Figment::from(Config::default()).merge(Toml::file("/etc/nazrin.conf")); #[allow(deprecated)] if let Some(mut home) = std::env::home_dir() { home.push(".nazrin.conf"); fig = fig.merge(Json::file(home)); } fig.merge(Env::prefixed("NZR_")) } }