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