Skip to main content

zlayer_core/
config.rs

1//! Configuration structures for `ZLayer`
2
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5use std::time::Duration;
6
7/// Main agent configuration
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
9pub struct AgentConfig {
10    /// Deployment name this agent belongs to
11    pub deployment_name: String,
12
13    /// Unique node identifier
14    pub node_id: String,
15
16    /// Raft consensus configuration
17    #[serde(default)]
18    pub raft: RaftConfig,
19
20    /// Overlay network configuration
21    #[serde(default)]
22    pub overlay: OverlayAgentConfig,
23
24    /// Data directory for state persistence
25    #[serde(default = "default_data_dir")]
26    pub data_dir: PathBuf,
27
28    /// Metrics configuration
29    #[serde(default)]
30    pub metrics: MetricsConfig,
31
32    /// Logging configuration
33    #[serde(default)]
34    pub logging: LoggingConfig,
35
36    /// Registry authentication configuration
37    #[serde(default)]
38    pub auth: crate::auth::AuthConfig,
39}
40
41fn default_data_dir() -> PathBuf {
42    zlayer_paths::ZLayerDirs::default_data_dir()
43}
44
45/// Raft consensus configuration
46#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
47pub struct RaftConfig {
48    /// Address to bind for Raft RPC
49    pub raft_addr: String,
50
51    /// Advertised address for other nodes to connect
52    pub advertise_addr: Option<String>,
53
54    /// Snapshot threshold (number of logs before snapshot)
55    #[serde(default = "default_snapshot_threshold")]
56    pub snapshot_threshold: u64,
57
58    /// Snapshot policy (logs since last snapshot)
59    #[serde(default = "default_snapshot_policy_count")]
60    pub snapshot_policy_count: u64,
61
62    /// Election timeout minimum
63    #[serde(default = "default_election_timeout_min")]
64    pub election_timeout_min: u64,
65
66    /// Election timeout maximum
67    #[serde(default = "default_election_timeout_max")]
68    pub election_timeout_max: u64,
69
70    /// Heartbeat interval
71    #[serde(default = "default_heartbeat_interval")]
72    pub heartbeat_interval: u64,
73}
74
75impl Default for RaftConfig {
76    fn default() -> Self {
77        Self {
78            raft_addr: "0.0.0.0:27001".to_string(),
79            advertise_addr: None,
80            snapshot_threshold: default_snapshot_threshold(),
81            snapshot_policy_count: default_snapshot_policy_count(),
82            election_timeout_min: default_election_timeout_min(),
83            election_timeout_max: default_election_timeout_max(),
84            heartbeat_interval: default_heartbeat_interval(),
85        }
86    }
87}
88
89fn default_snapshot_threshold() -> u64 {
90    10000
91}
92
93fn default_snapshot_policy_count() -> u64 {
94    8000
95}
96
97fn default_election_timeout_min() -> u64 {
98    150
99}
100
101fn default_election_timeout_max() -> u64 {
102    300
103}
104
105fn default_heartbeat_interval() -> u64 {
106    50
107}
108
109/// Overlay network configuration for agents
110#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
111pub struct OverlayAgentConfig {
112    /// Overlay private key (x25519)
113    pub private_key: String,
114
115    /// Overlay public key (derived from private key)
116    pub public_key: Option<String>,
117
118    /// Listen port for overlay network (`WireGuard` protocol)
119    #[serde(default = "default_wg_port")]
120    pub wg_port: u16,
121
122    /// Global overlay network configuration
123    #[serde(default)]
124    pub global: GlobalOverlayConfig,
125
126    /// DNS configuration
127    #[serde(default)]
128    pub dns: DnsConfig,
129}
130
131impl Default for OverlayAgentConfig {
132    fn default() -> Self {
133        Self {
134            private_key: String::new(),
135            public_key: None,
136            wg_port: default_wg_port(),
137            global: GlobalOverlayConfig::default(),
138            dns: DnsConfig::default(),
139        }
140    }
141}
142
143fn default_wg_port() -> u16 {
144    51820
145}
146
147/// Global overlay network configuration
148#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
149pub struct GlobalOverlayConfig {
150    /// Overlay network CIDR (e.g., "10.0.0.0/8")
151    #[serde(default = "default_overlay_cidr")]
152    pub overlay_cidr: String,
153
154    /// Peer discovery interval
155    #[serde(default = "default_peer_discovery")]
156    pub peer_discovery_interval: Duration,
157}
158
159impl Default for GlobalOverlayConfig {
160    fn default() -> Self {
161        Self {
162            overlay_cidr: default_overlay_cidr(),
163            peer_discovery_interval: default_peer_discovery(),
164        }
165    }
166}
167
168fn default_overlay_cidr() -> String {
169    "10.0.0.0/8".to_string()
170}
171
172fn default_peer_discovery() -> Duration {
173    Duration::from_secs(30)
174}
175
176/// DNS configuration
177#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
178pub struct DnsConfig {
179    /// DNS listen address
180    #[serde(default = "default_dns_addr")]
181    pub listen_addr: String,
182
183    /// DNS TLD for global overlay
184    #[serde(default = "default_global_tld")]
185    pub global_tld: String,
186
187    /// DNS TLD for service-scoped overlay
188    #[serde(default = "default_service_tld")]
189    pub service_tld: String,
190}
191
192impl Default for DnsConfig {
193    fn default() -> Self {
194        Self {
195            listen_addr: default_dns_addr(),
196            global_tld: default_global_tld(),
197            service_tld: default_service_tld(),
198        }
199    }
200}
201
202fn default_dns_addr() -> String {
203    "0.0.0.0:53".to_string()
204}
205
206fn default_global_tld() -> String {
207    "global".to_string()
208}
209
210fn default_service_tld() -> String {
211    "service".to_string()
212}
213
214/// Metrics configuration
215#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
216pub struct MetricsConfig {
217    /// Enable metrics collection
218    #[serde(default = "default_metrics_enabled")]
219    pub enabled: bool,
220
221    /// Metrics exposition address
222    #[serde(default = "default_metrics_addr")]
223    pub listen_addr: String,
224
225    /// Metrics path
226    #[serde(default = "default_metrics_path")]
227    pub path: String,
228}
229
230impl Default for MetricsConfig {
231    fn default() -> Self {
232        Self {
233            enabled: default_metrics_enabled(),
234            listen_addr: default_metrics_addr(),
235            path: default_metrics_path(),
236        }
237    }
238}
239
240fn default_metrics_enabled() -> bool {
241    true
242}
243
244fn default_metrics_addr() -> String {
245    "0.0.0.0:9090".to_string()
246}
247
248fn default_metrics_path() -> String {
249    "/metrics".to_string()
250}
251
252/// Logging configuration
253#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
254pub struct LoggingConfig {
255    /// Log level (trace, debug, info, warn, error)
256    #[serde(default = "default_log_level")]
257    pub level: String,
258
259    /// Log format (json, pretty)
260    #[serde(default = "default_log_format")]
261    pub format: String,
262
263    /// Log to stdout
264    #[serde(default = "default_log_stdout")]
265    pub stdout: bool,
266
267    /// Log file path
268    pub file: Option<PathBuf>,
269}
270
271impl Default for LoggingConfig {
272    fn default() -> Self {
273        Self {
274            level: default_log_level(),
275            format: default_log_format(),
276            stdout: default_log_stdout(),
277            file: None,
278        }
279    }
280}
281
282fn default_log_level() -> String {
283    "info".to_string()
284}
285
286fn default_log_format() -> String {
287    "json".to_string()
288}
289
290fn default_log_stdout() -> bool {
291    true
292}
293
294#[cfg(test)]
295mod tests {
296    use super::*;
297
298    #[test]
299    fn test_agent_config_default() {
300        let config = AgentConfig {
301            deployment_name: "test".to_string(),
302            node_id: "node-1".to_string(),
303            ..Default::default()
304        };
305        assert_eq!(config.deployment_name, "test");
306        assert_eq!(config.node_id, "node-1");
307    }
308}