1 use std::{
2     any::Any,
3     fs::File,
4     io::Write,
5     path::{Path, PathBuf},
6     {fmt, fs},
7 };
8 
9 use serde::{de::DeserializeOwned, Serialize};
10 
11 use crate::commons::{error::KrillIoError, util::file, util::KrillVersion};
12 
13 //------------ KeyStoreKey ---------------------------------------------------
14 
15 #[derive(Clone, Debug)]
16 pub struct KeyStoreKey {
17     scope: Option<String>,
18     name: String,
19 }
20 
21 impl KeyStoreKey {
new(scope: Option<String>, name: String) -> Self22     pub fn new(scope: Option<String>, name: String) -> Self {
23         KeyStoreKey { scope, name }
24     }
25 
simple(name: String) -> Self26     pub fn simple(name: String) -> Self {
27         KeyStoreKey { scope: None, name }
28     }
29 
scoped(scope: String, name: String) -> Self30     pub fn scoped(scope: String, name: String) -> Self {
31         KeyStoreKey {
32             scope: Some(scope),
33             name,
34         }
35     }
36 
scope(&self) -> Option<&String>37     pub fn scope(&self) -> Option<&String> {
38         self.scope.as_ref()
39     }
40 
name(&self) -> &str41     pub fn name(&self) -> &str {
42         &self.name
43     }
44 
sub_scope(&self, new: &str) -> Self45     pub fn sub_scope(&self, new: &str) -> Self {
46         if new.is_empty() {
47             self.clone()
48         } else {
49             let scope = match self.scope.as_ref() {
50                 Some(existing) => format!("{}/{}", existing, new),
51                 None => new.to_string(),
52             };
53             KeyStoreKey {
54                 scope: Some(scope),
55                 name: self.name.clone(),
56             }
57         }
58     }
59 
archived(&self) -> Self60     pub fn archived(&self) -> Self {
61         self.sub_scope("archived")
62     }
63 
corrupt(&self) -> Self64     pub fn corrupt(&self) -> Self {
65         self.sub_scope("corrupt")
66     }
67 
surplus(&self) -> Self68     pub fn surplus(&self) -> Self {
69         self.sub_scope("surplus")
70     }
71 }
72 
73 impl fmt::Display for KeyStoreKey {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result74     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75         match self.scope.as_ref() {
76             Some(scope) => write!(f, "{}/{}", scope, self.name),
77             None => write!(f, "{}", self.name),
78         }
79     }
80 }
81 
82 /// Using an enum here, because we expect to have more implementations in future.
83 /// Not using generics because it's harder on the compiler.
84 #[derive(Debug)]
85 pub enum KeyValueStore {
86     Disk(KeyValueStoreDiskImpl),
87 }
88 
89 impl KeyValueStore {
disk(work_dir: &Path, name_space: &str) -> Result<Self, KeyValueError>90     pub fn disk(work_dir: &Path, name_space: &str) -> Result<Self, KeyValueError> {
91         let mut base = work_dir.to_path_buf();
92         base.push(name_space);
93 
94         if !base.exists() {
95             file::create_dir(&base)?;
96         }
97 
98         Ok(KeyValueStore::Disk(KeyValueStoreDiskImpl { base }))
99     }
100 
101     /// Stores a key value pair, serialized as json, overwrite existing
store<V: Any + Serialize>(&self, key: &KeyStoreKey, value: &V) -> Result<(), KeyValueError>102     pub fn store<V: Any + Serialize>(&self, key: &KeyStoreKey, value: &V) -> Result<(), KeyValueError> {
103         match self {
104             KeyValueStore::Disk(disk_store) => disk_store.store(key, value),
105         }
106     }
107 
108     /// Stores a new key value pair, returns an error if the key exists
store_new<V: Any + Serialize>(&self, key: &KeyStoreKey, value: &V) -> Result<(), KeyValueError>109     pub fn store_new<V: Any + Serialize>(&self, key: &KeyStoreKey, value: &V) -> Result<(), KeyValueError> {
110         match self {
111             KeyValueStore::Disk(disk_store) => disk_store.store_new(key, value),
112         }
113     }
114 
115     /// Gets a value for a key, returns an error if the value cannot be deserialized,
116     /// returns None if it cannot be found.
get<V: DeserializeOwned>(&self, key: &KeyStoreKey) -> Result<Option<V>, KeyValueError>117     pub fn get<V: DeserializeOwned>(&self, key: &KeyStoreKey) -> Result<Option<V>, KeyValueError> {
118         match self {
119             KeyValueStore::Disk(disk_store) => disk_store.get(key),
120         }
121     }
122 
123     /// Returns whether a key exists
has(&self, key: &KeyStoreKey) -> Result<bool, KeyValueError>124     pub fn has(&self, key: &KeyStoreKey) -> Result<bool, KeyValueError> {
125         match self {
126             KeyValueStore::Disk(disk_store) => Ok(disk_store.has(key)),
127         }
128     }
129 
130     /// Delete a key-value pair
drop_key(&self, key: &KeyStoreKey) -> Result<(), KeyValueError>131     pub fn drop_key(&self, key: &KeyStoreKey) -> Result<(), KeyValueError> {
132         match self {
133             KeyValueStore::Disk(disk_store) => disk_store.drop_key(key),
134         }
135     }
136 
137     /// Delete a scope
drop_scope(&self, scope: &str) -> Result<(), KeyValueError>138     pub fn drop_scope(&self, scope: &str) -> Result<(), KeyValueError> {
139         match self {
140             KeyValueStore::Disk(disk_store) => disk_store.drop_scope(scope),
141         }
142     }
143 
144     /// Move a value from one key to another
move_key(&self, from: &KeyStoreKey, to: &KeyStoreKey) -> Result<(), KeyValueError>145     pub fn move_key(&self, from: &KeyStoreKey, to: &KeyStoreKey) -> Result<(), KeyValueError> {
146         match self {
147             KeyValueStore::Disk(disk_store) => disk_store.move_key(from, to),
148         }
149     }
150 
151     /// Archive a key
archive(&self, key: &KeyStoreKey) -> Result<(), KeyValueError>152     pub fn archive(&self, key: &KeyStoreKey) -> Result<(), KeyValueError> {
153         self.move_key(key, &key.archived())
154     }
155 
156     /// Archive a key to an arbitrary scope
archive_to(&self, key: &KeyStoreKey, scope: &str) -> Result<(), KeyValueError>157     pub fn archive_to(&self, key: &KeyStoreKey, scope: &str) -> Result<(), KeyValueError> {
158         self.move_key(key, &key.sub_scope(scope))
159     }
160 
161     /// Archive a key as corrupt
archive_corrupt(&self, key: &KeyStoreKey) -> Result<(), KeyValueError>162     pub fn archive_corrupt(&self, key: &KeyStoreKey) -> Result<(), KeyValueError> {
163         self.move_key(key, &key.corrupt())
164     }
165 
166     /// Archive a key as surplus
archive_surplus(&self, key: &KeyStoreKey) -> Result<(), KeyValueError>167     pub fn archive_surplus(&self, key: &KeyStoreKey) -> Result<(), KeyValueError> {
168         self.move_key(key, &key.surplus())
169     }
170 
171     /// Returns all 1st level scopes
scopes(&self) -> Result<Vec<String>, KeyValueError>172     pub fn scopes(&self) -> Result<Vec<String>, KeyValueError> {
173         match self {
174             KeyValueStore::Disk(disk_store) => disk_store.scopes(),
175         }
176     }
177 
178     /// Archives the content of a scope to sub-scope in that scope
scope_archive(&self, scope: &str, sub_scope: &str) -> Result<(), KeyValueError>179     pub fn scope_archive(&self, scope: &str, sub_scope: &str) -> Result<(), KeyValueError> {
180         match self {
181             KeyValueStore::Disk(disk_store) => disk_store.scope_archive(scope, sub_scope),
182         }
183     }
184 
185     /// Returns whether a scope exists
has_scope(&self, scope: String) -> Result<bool, KeyValueError>186     pub fn has_scope(&self, scope: String) -> Result<bool, KeyValueError> {
187         match self {
188             KeyValueStore::Disk(disk_store) => Ok(disk_store.has_scope(scope)),
189         }
190     }
191 
192     /// Returns all keys under a scope (scopes are exact strings, 'sub'-scopes
193     /// would need to be specified explicitly.. e.g. 'ca' and 'ca/archived' are
194     /// two distinct scopes.
195     ///
196     /// If matching is not empty then the key must contain the given `&str`.
keys(&self, scope: Option<String>, matching: &str) -> Result<Vec<KeyStoreKey>, KeyValueError>197     pub fn keys(&self, scope: Option<String>, matching: &str) -> Result<Vec<KeyStoreKey>, KeyValueError> {
198         match self {
199             KeyValueStore::Disk(disk_store) => disk_store.keys(scope, matching),
200         }
201     }
202 
203     /// Returns the version of a key store.
204     /// KeyStore use a specific key-value pair to track their version. If the key is absent it
205     /// is assumed that the version was from before Krill 0.6.0. An error is returned if the key
206     /// is present, but the value is corrupt or not recognized.
version(&self) -> Result<KrillVersion, KeyValueError>207     pub fn version(&self) -> Result<KrillVersion, KeyValueError> {
208         let key = KeyStoreKey::simple("version".to_string());
209         self.get(&key)
210             .map(|version_opt| version_opt.unwrap_or_else(KrillVersion::v0_5_0_or_before))
211     }
212 
213     /// Returns whether the version of this key store predates the given version.
214     /// KeyStore use a specific key-value pair to track their version. If the key is absent it
215     /// is assumed that the version was from before Krill 0.6.0. An error is returned if the key
216     /// is present, but the value is corrupt or not recognized.
version_is_before(&self, later: KrillVersion) -> Result<bool, KeyValueError>217     pub fn version_is_before(&self, later: KrillVersion) -> Result<bool, KeyValueError> {
218         let version = self.version()?;
219         Ok(version < later)
220     }
221 }
222 
223 impl KeyValueStore {}
224 
225 /// This type can store and retrieve values to/from disk, using json
226 /// serialization
227 #[derive(Debug)]
228 pub struct KeyValueStoreDiskImpl {
229     base: PathBuf,
230 }
231 
232 impl KeyValueStoreDiskImpl {
file_path(&self, key: &KeyStoreKey) -> PathBuf233     fn file_path(&self, key: &KeyStoreKey) -> PathBuf {
234         let mut path = self.scope_path(key.scope.as_ref());
235         path.push(key.name());
236         path
237     }
238 
239     /// creates a file path, prefixing the name with '.' much like vi
swap_file_path(&self, key: &KeyStoreKey) -> PathBuf240     fn swap_file_path(&self, key: &KeyStoreKey) -> PathBuf {
241         let mut path = self.scope_path(key.scope.as_ref());
242         path.push(format!(".{}", key.name()));
243         path
244     }
245 
scope_path<P: AsRef<Path>>(&self, scope: Option<P>) -> PathBuf246     fn scope_path<P: AsRef<Path>>(&self, scope: Option<P>) -> PathBuf {
247         let mut path = self.base.clone();
248         if let Some(scope) = scope {
249             path.push(scope);
250         }
251         path
252     }
253 
store<V: Any + Serialize>(&self, key: &KeyStoreKey, value: &V) -> Result<(), KeyValueError>254     fn store<V: Any + Serialize>(&self, key: &KeyStoreKey, value: &V) -> Result<(), KeyValueError> {
255         let swap_file_path = self.swap_file_path(key);
256         let file_path = self.file_path(key);
257         let mut swap_file = file::create_file_with_path(&swap_file_path)?;
258         let json = serde_json::to_string_pretty(value)?;
259         swap_file.write_all(json.as_ref()).map_err(|e| {
260             KrillIoError::new(
261                 format!("Could not write to tmp file: {}", swap_file_path.to_string_lossy()),
262                 e,
263             )
264         })?;
265 
266         fs::rename(&swap_file_path, &file_path).map_err(|e| {
267             KrillIoError::new(
268                 format!(
269                     "Could not rename tmp file {} to {}",
270                     swap_file_path.to_string_lossy(),
271                     file_path.to_string_lossy()
272                 ),
273                 e,
274             )
275         })?;
276 
277         Ok(())
278     }
279 
store_new<V: Any + Serialize>(&self, key: &KeyStoreKey, value: &V) -> Result<(), KeyValueError>280     fn store_new<V: Any + Serialize>(&self, key: &KeyStoreKey, value: &V) -> Result<(), KeyValueError> {
281         let path = self.file_path(key);
282         if path.exists() {
283             Err(KeyValueError::DuplicateKey(key.clone()))
284         } else {
285             let mut f = file::create_file_with_path(&path)?;
286             let json = serde_json::to_string_pretty(value)?;
287             f.write_all(json.as_ref()).map_err(|e| {
288                 KrillIoError::new(
289                     format!(
290                         "Could not store value for key '{}' in file '{}'",
291                         key.to_string(),
292                         path.to_string_lossy()
293                     ),
294                     e,
295                 )
296             })?;
297             Ok(())
298         }
299     }
300 
get<V: DeserializeOwned>(&self, key: &KeyStoreKey) -> Result<Option<V>, KeyValueError>301     fn get<V: DeserializeOwned>(&self, key: &KeyStoreKey) -> Result<Option<V>, KeyValueError> {
302         let path = self.file_path(key);
303         let path_str = path.to_string_lossy().into_owned();
304 
305         if path.exists() {
306             let f = File::open(path).map_err(|e| {
307                 KrillIoError::new(
308                     format!(
309                         "Could not read value for key '{}' from file '{}'",
310                         key.to_string(),
311                         path_str
312                     ),
313                     e,
314                 )
315             })?;
316             let v = serde_json::from_reader(f)?;
317             Ok(Some(v))
318         } else {
319             trace!("Could not find file at: {}", path_str);
320             Ok(None)
321         }
322     }
323 
has(&self, key: &KeyStoreKey) -> bool324     pub fn has(&self, key: &KeyStoreKey) -> bool {
325         let path = self.file_path(key);
326         path.exists()
327     }
328 
drop_key(&self, key: &KeyStoreKey) -> Result<(), KeyValueError>329     pub fn drop_key(&self, key: &KeyStoreKey) -> Result<(), KeyValueError> {
330         let path = self.file_path(key);
331         if path.exists() {
332             fs::remove_file(&path).map_err(|e| {
333                 KrillIoError::new(
334                     format!(
335                         "Could not drop key '{}', removing file '{}' failed",
336                         key.to_string(),
337                         path.to_string_lossy()
338                     ),
339                     e,
340                 )
341             })?;
342         }
343         Ok(())
344     }
345 
drop_scope(&self, scope: &str) -> Result<(), KeyValueError>346     pub fn drop_scope(&self, scope: &str) -> Result<(), KeyValueError> {
347         let path = self.scope_path(Some(&scope.to_string()));
348         if path.exists() {
349             fs::remove_dir_all(&path).map_err(|e| {
350                 KrillIoError::new(
351                     format!(
352                         "Could not drop scope '{}', removing dir '{}' failed",
353                         scope,
354                         path.to_string_lossy()
355                     ),
356                     e,
357                 )
358             })?;
359         }
360         Ok(())
361     }
362 
move_key(&self, from: &KeyStoreKey, to: &KeyStoreKey) -> Result<(), KeyValueError>363     pub fn move_key(&self, from: &KeyStoreKey, to: &KeyStoreKey) -> Result<(), KeyValueError> {
364         let from_path = self.file_path(from);
365         let to_path = self.file_path(to);
366 
367         if !from_path.exists() {
368             Err(KeyValueError::UnknownKey(from.clone()))
369         } else {
370             if let Some(parent) = to_path.parent() {
371                 if !parent.exists() {
372                     fs::create_dir(parent).map_err(|e| {
373                         KrillIoError::new(
374                             format!(
375                                 "Could not rename key from '{}' to '{}'. Creating parent dir '{}' failed.",
376                                 from,
377                                 to,
378                                 parent.to_string_lossy()
379                             ),
380                             e,
381                         )
382                     })?;
383                 }
384             }
385 
386             fs::rename(from_path, to_path)
387                 .map_err(|e| KrillIoError::new(format!("Could not rename key from '{}' to '{}'", from, to,), e))?;
388             Ok(())
389         }
390     }
391 
has_scope(&self, scope: String) -> bool392     fn has_scope(&self, scope: String) -> bool {
393         self.scope_path(Some(&scope)).exists()
394     }
395 
scopes(&self) -> Result<Vec<String>, KeyValueError>396     fn scopes(&self) -> Result<Vec<String>, KeyValueError> {
397         Self::read_dir(&self.base, false, true)
398     }
399 
scope_archive(&self, scope: &str, sub_scope: &str) -> Result<(), KeyValueError>400     fn scope_archive(&self, scope: &str, sub_scope: &str) -> Result<(), KeyValueError> {
401         let scope_path = self.scope_path(Some(scope));
402         let tmp_path = self.scope_path(Some(format!(".{}", scope)));
403         let end_path = self.scope_path(Some(format!("{}/{}", scope, sub_scope)));
404 
405         fs::rename(&scope_path, &tmp_path).map_err(|e| {
406             KrillIoError::new(
407                 format!(
408                     "Could not archive scope contents, rename from dir '{}' to tmp dir '{}' failed",
409                     scope_path.to_string_lossy(),
410                     tmp_path.to_string_lossy()
411                 ),
412                 e,
413             )
414         })?;
415         fs::create_dir_all(&scope_path).map_err(|e| {
416             KrillIoError::new(
417                 format!(
418                     "Could not archive scope contents, recreating scope dir '{}' failed",
419                     scope_path.to_string_lossy(),
420                 ),
421                 e,
422             )
423         })?;
424         fs::rename(&tmp_path, &end_path).map_err(|e| {
425             KrillIoError::new(
426                 format!(
427                     "Could not archive scope contents, rename tmp dir with contents '{}' into archive path '{}' failed",
428                     tmp_path.to_string_lossy(),
429                     end_path.to_string_lossy(),
430                 ),
431                 e,
432             )
433         })?;
434 
435         Ok(())
436     }
437 
keys(&self, scope: Option<String>, matching: &str) -> Result<Vec<KeyStoreKey>, KeyValueError>438     fn keys(&self, scope: Option<String>, matching: &str) -> Result<Vec<KeyStoreKey>, KeyValueError> {
439         let path = self.scope_path(scope.as_ref());
440 
441         let mut res = vec![];
442         for name in Self::read_dir(&path, true, false)? {
443             if matching.is_empty() || name.contains(matching) {
444                 match scope.as_ref() {
445                     None => res.push(KeyStoreKey::simple(name)),
446                     Some(scope) => res.push(KeyStoreKey::scoped(scope.clone(), name)),
447                 }
448             }
449         }
450 
451         Ok(res)
452     }
453 
read_dir(dir: &Path, files: bool, dirs: bool) -> Result<Vec<String>, KeyValueError>454     fn read_dir(dir: &Path, files: bool, dirs: bool) -> Result<Vec<String>, KeyValueError> {
455         match fs::read_dir(dir) {
456             Err(e) => Err(KeyValueError::IoError(KrillIoError::new(
457                 format!("Could not read directory {}", dir.to_string_lossy()),
458                 e,
459             ))),
460             Ok(dir) => {
461                 let mut res = vec![];
462 
463                 for d in dir.flatten() {
464                     let path = d.path();
465                     if (dirs && path.is_dir()) || (files && path.is_file()) {
466                         if let Some(name) = path.file_name() {
467                             res.push(name.to_string_lossy().to_string())
468                         }
469                     }
470                 }
471 
472                 Ok(res)
473             }
474         }
475     }
476 }
477 
478 //------------ KeyValueError -------------------------------------------------
479 
480 /// This type defines possible Errors for KeyStore
481 #[derive(Debug)]
482 pub enum KeyValueError {
483     IoError(KrillIoError),
484     JsonError(serde_json::Error),
485     UnknownKey(KeyStoreKey),
486     DuplicateKey(KeyStoreKey),
487 }
488 
489 impl From<KrillIoError> for KeyValueError {
from(e: KrillIoError) -> Self490     fn from(e: KrillIoError) -> Self {
491         KeyValueError::IoError(e)
492     }
493 }
494 
495 impl From<serde_json::Error> for KeyValueError {
from(e: serde_json::Error) -> Self496     fn from(e: serde_json::Error) -> Self {
497         KeyValueError::JsonError(e)
498     }
499 }
500 
501 impl fmt::Display for KeyValueError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result502     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
503         match self {
504             KeyValueError::IoError(e) => write!(f, "I/O error: {}", e),
505             KeyValueError::JsonError(e) => write!(f, "JSON error: {}", e),
506             KeyValueError::UnknownKey(key) => write!(f, "Unknown key: {}", key),
507             KeyValueError::DuplicateKey(key) => write!(f, "Duplicate key: {}", key),
508         }
509     }
510 }
511 
512 //------------ Tests ---------------------------------------------------------
513 
514 #[cfg(test)]
515 mod tests {
516 
517     use super::*;
518     use crate::test;
519 
520     #[test]
disk_store_move_key()521     fn disk_store_move_key() {
522         test::test_under_tmp(|d| {
523             let store = KeyValueStore::disk(&d, "store").unwrap();
524 
525             let content = "abc".to_string();
526             let id = "id".to_string();
527             let key = KeyStoreKey::simple(id);
528             let target = key.archived();
529 
530             store.store(&key, &content).unwrap();
531 
532             let mut expected_file_path = d.clone();
533             expected_file_path.push("store");
534             expected_file_path.push("id");
535             assert!(expected_file_path.exists());
536 
537             store.move_key(&key, &target).unwrap();
538 
539             let mut expected_target = d;
540             expected_target.push("store");
541             expected_target.push("archived");
542             expected_target.push("id");
543 
544             assert!(!expected_file_path.exists());
545             assert!(expected_target.exists());
546         })
547     }
548 }
549