Skip to main content

rebuilderd_common/
config.rs

1use crate::auth::AuthConfig;
2use crate::errors::*;
3use chrono::Duration;
4use serde::Deserialize;
5use std::collections::HashMap;
6use std::fs;
7use std::path::{Path, PathBuf};
8
9pub const IDLE_DELAY: u64 = 180;
10pub const PING_DEADLINE: i64 = PING_INTERVAL as i64 * 9;
11pub const PING_INTERVAL: u64 = 60;
12pub const WORKER_DELAY: u64 = 3;
13pub const API_ERROR_DELAY: u64 = 30;
14
15pub const DEFAULT_RETRY_DELAY_BASE: i64 = 24;
16
17pub const DEFAULT_INITIAL_DELAY: i64 = 0;
18
19pub fn load<P: AsRef<Path>>(path: Option<P>) -> Result<ConfigFile> {
20    let mut config = ConfigFile::default();
21
22    if let Some(c) = load_from("/etc/rebuilderd.conf")? {
23        config.update(c);
24    }
25
26    if let Ok(path) = config_path()
27        && let Some(c) = load_from(path)?
28    {
29        config.update(c);
30    }
31
32    if let Some(path) = path {
33        let c = load_from(path)?.ok_or_else(|| format_err!("Failed to read config file"))?;
34        config.update(c);
35    }
36
37    Ok(config)
38}
39
40fn config_path() -> Result<PathBuf> {
41    let config_dir =
42        dirs_next::config_dir().ok_or_else(|| format_err!("Failed to find config dir"))?;
43    Ok(config_dir.join("rebuilderd.conf"))
44}
45
46fn load_from<P: AsRef<Path>>(path: P) -> Result<Option<ConfigFile>> {
47    if let Ok(buf) = fs::read_to_string(path.as_ref()) {
48        debug!("loading config file {:?}", path.as_ref());
49        let config = toml::from_str(&buf).context("Failed to load config")?;
50        Ok(Some(config))
51    } else {
52        Ok(None)
53    }
54}
55
56#[derive(Debug, Default, Clone, Deserialize)]
57pub struct ConfigFile {
58    #[serde(default)]
59    pub http: HttpConfig,
60    #[serde(default)]
61    pub auth: AuthConfig,
62    #[serde(default)]
63    pub endpoints: HashMap<String, EndpointConfig>,
64    #[serde(default)]
65    pub worker: WorkerConfig,
66    #[serde(default)]
67    pub schedule: ScheduleConfig,
68}
69
70impl ConfigFile {
71    pub fn update(&mut self, c: ConfigFile) {
72        self.http.update(c.http);
73        self.auth.update(c.auth);
74        for (k, v) in c.endpoints {
75            if let Some(o) = self.endpoints.get_mut(&k) {
76                o.update(v);
77            } else {
78                self.endpoints.insert(k, v);
79            }
80        }
81        self.worker.update(c.worker);
82        self.schedule.update(c.schedule);
83    }
84}
85
86#[derive(Debug, Default, Clone, Deserialize)]
87pub struct HttpConfig {
88    pub bind_addr: Option<String>,
89    pub real_ip_header: Option<String>,
90    pub post_body_size_limit: Option<usize>,
91    pub transparently_sign_attestations: Option<bool>,
92    pub endpoint: Option<String>,
93}
94
95impl HttpConfig {
96    pub fn update(&mut self, c: HttpConfig) {
97        if c.bind_addr.is_some() {
98            self.bind_addr = c.bind_addr;
99        }
100        if c.real_ip_header.is_some() {
101            self.real_ip_header = c.real_ip_header;
102        }
103        if c.endpoint.is_some() {
104            self.endpoint = c.endpoint;
105        }
106    }
107}
108
109#[derive(Debug, Default, Clone, Deserialize)]
110pub struct EndpointConfig {
111    pub cookie: String,
112}
113
114impl EndpointConfig {
115    pub fn update(&mut self, c: EndpointConfig) {
116        self.cookie = c.cookie;
117    }
118}
119
120#[derive(Debug, Default, Clone, Deserialize)]
121pub struct WorkerConfig {
122    #[serde(default)]
123    pub authorized_workers: Vec<String>,
124    pub signup_secret: Option<String>,
125}
126
127impl WorkerConfig {
128    pub fn update(&mut self, c: WorkerConfig) {
129        if !c.authorized_workers.is_empty() {
130            self.authorized_workers = c.authorized_workers;
131        }
132        if c.signup_secret.is_some() {
133            self.signup_secret = c.signup_secret;
134        }
135    }
136}
137
138#[derive(Debug, Default, Clone, Deserialize)]
139pub struct ScheduleConfig {
140    pub retry_delay_base: Option<i64>,
141    pub max_retries: Option<i32>,
142    pub initial_delay: Option<i64>,
143}
144
145impl ScheduleConfig {
146    pub fn update(&mut self, c: ScheduleConfig) {
147        if c.retry_delay_base.is_some() {
148            self.retry_delay_base = c.retry_delay_base;
149        }
150
151        if c.initial_delay.is_some() {
152            self.initial_delay = c.initial_delay;
153        }
154
155        if c.max_retries.is_some() {
156            self.max_retries = c.max_retries;
157        }
158    }
159
160    pub fn retry_delay_base(&self) -> i64 {
161        self.retry_delay_base.unwrap_or(DEFAULT_RETRY_DELAY_BASE)
162    }
163
164    pub fn initial_delay(&self) -> Duration {
165        let seconds = self.initial_delay.unwrap_or(DEFAULT_INITIAL_DELAY);
166        Duration::seconds(seconds)
167    }
168
169    pub fn max_retries(&self) -> Option<i32> {
170        self.max_retries
171    }
172}