kanidm_proto/
backup.rs

1//! Relates to backup functionality in the Server
2use std::{fmt::Display, path::Path, str::FromStr};
3
4use serde_with::DeserializeFromStr;
5use sketching::tracing::warn;
6
7#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, DeserializeFromStr)]
8/// Compression types for backups, defaults to Gzip
9pub enum BackupCompression {
10    NoCompression,
11    #[default]
12    Gzip,
13}
14
15impl BackupCompression {
16    pub fn suffix(&self) -> &'static str {
17        match self {
18            BackupCompression::NoCompression => "",
19            BackupCompression::Gzip => ".gz",
20        }
21    }
22
23    pub fn identify_file(filepath: &Path) -> Self {
24        let filename = filepath.file_name().and_then(|s| s.to_str()).unwrap_or("");
25        if filename.ends_with(".gz") {
26            BackupCompression::Gzip
27        } else {
28            BackupCompression::NoCompression
29        }
30    }
31}
32
33impl Display for BackupCompression {
34    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
35        match self {
36            BackupCompression::NoCompression => write!(f, "No Compression"),
37            BackupCompression::Gzip => write!(f, "Gzip"),
38        }
39    }
40}
41
42impl From<Option<String>> for BackupCompression {
43    fn from(opt: Option<String>) -> Self {
44        match opt {
45            Some(s) => BackupCompression::from(s),
46            None => BackupCompression::default(),
47        }
48    }
49}
50
51impl From<String> for BackupCompression {
52    fn from(s: String) -> Self {
53        match s.to_lowercase().as_str() {
54            "gzip" => BackupCompression::Gzip,
55            "none" | "nocompression" => BackupCompression::NoCompression,
56            _ => {
57                warn!(
58                    "Unknown compression type '{}', should be one of nocompression, gzip - defaulting to {}",
59                    s,
60                    BackupCompression::default()
61                );
62                BackupCompression::default()
63            }
64        }
65    }
66}
67
68impl FromStr for BackupCompression {
69    type Err = &'static str;
70
71    fn from_str(s: &str) -> Result<Self, Self::Err> {
72        Ok(s.to_string().into())
73    }
74}
75
76#[test]
77
78fn test_backup_compression_identify() {
79    let gzip_path = Path::new("/var/lib/kanidm/backups/backup-2024-01-01.tar.gz");
80    let no_comp_path = Path::new("/var/lib/kanidm/backups/backup-2024-01-01.tar");
81
82    assert_eq!(
83        BackupCompression::identify_file(gzip_path),
84        BackupCompression::Gzip
85    );
86    assert_eq!(
87        BackupCompression::identify_file(no_comp_path),
88        BackupCompression::NoCompression
89    );
90
91    for (input, expected) in [
92        (vec!["gzip", "Gzip", "GzIp"], BackupCompression::Gzip),
93        (
94            vec!["none", "NoNe", "nocompression", "NoCompression"],
95            BackupCompression::NoCompression,
96        ),
97    ] {
98        for i in input {
99            assert_eq!(
100                BackupCompression::from_str(i).expect("Threw an error?"),
101                expected
102            );
103        }
104    }
105}