api-types: introduce BackupType enum and Group/Dir api types
The type is a real enum. All are API types and implement Display and FromStr. The ordering is the same as it is in pbs-datastore. Also, they are now flattened into a few structs instead of being copied manually. Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com> Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
committed by
Thomas Lamprecht
parent
33eb23d57e
commit
988d575dbb
@ -5,7 +5,8 @@ use std::str::FromStr;
|
||||
use anyhow::{bail, format_err, Error};
|
||||
|
||||
use pbs_api_types::{
|
||||
GroupFilter, BACKUP_DATE_REGEX, BACKUP_FILE_REGEX, GROUP_PATH_REGEX, SNAPSHOT_PATH_REGEX,
|
||||
BackupType, GroupFilter, BACKUP_DATE_REGEX, BACKUP_FILE_REGEX, GROUP_PATH_REGEX,
|
||||
SNAPSHOT_PATH_REGEX,
|
||||
};
|
||||
|
||||
use super::manifest::MANIFEST_BLOB_NAME;
|
||||
@ -14,7 +15,7 @@ use super::manifest::MANIFEST_BLOB_NAME;
|
||||
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
||||
pub struct BackupGroup {
|
||||
/// Type of backup
|
||||
backup_type: String,
|
||||
backup_type: BackupType,
|
||||
/// Unique (for this type) ID
|
||||
backup_id: String,
|
||||
}
|
||||
@ -44,15 +45,15 @@ impl std::cmp::PartialOrd for BackupGroup {
|
||||
}
|
||||
|
||||
impl BackupGroup {
|
||||
pub fn new<T: Into<String>, U: Into<String>>(backup_type: T, backup_id: U) -> Self {
|
||||
pub fn new<T: Into<String>>(backup_type: BackupType, backup_id: T) -> Self {
|
||||
Self {
|
||||
backup_type: backup_type.into(),
|
||||
backup_type,
|
||||
backup_id: backup_id.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn backup_type(&self) -> &str {
|
||||
&self.backup_type
|
||||
pub fn backup_type(&self) -> BackupType {
|
||||
self.backup_type
|
||||
}
|
||||
|
||||
pub fn backup_id(&self) -> &str {
|
||||
@ -62,7 +63,7 @@ impl BackupGroup {
|
||||
pub fn group_path(&self) -> PathBuf {
|
||||
let mut relative_path = PathBuf::new();
|
||||
|
||||
relative_path.push(&self.backup_type);
|
||||
relative_path.push(self.backup_type.as_str());
|
||||
|
||||
relative_path.push(&self.backup_id);
|
||||
|
||||
@ -85,7 +86,7 @@ impl BackupGroup {
|
||||
}
|
||||
|
||||
let backup_dir =
|
||||
BackupDir::with_rfc3339(&self.backup_type, &self.backup_id, backup_time)?;
|
||||
BackupDir::with_rfc3339(self.backup_type, &self.backup_id, backup_time)?;
|
||||
let files = list_backup_files(l2_fd, backup_time)?;
|
||||
|
||||
let protected = backup_dir.is_protected(base_path.to_owned());
|
||||
@ -162,12 +163,24 @@ impl BackupGroup {
|
||||
Ok(group) => &group == self,
|
||||
Err(_) => false, // shouldn't happen if value is schema-checked
|
||||
},
|
||||
GroupFilter::BackupType(backup_type) => self.backup_type() == backup_type,
|
||||
GroupFilter::BackupType(backup_type) => self.backup_type().as_str() == backup_type,
|
||||
GroupFilter::Regex(regex) => regex.is_match(&self.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&BackupGroup> for pbs_api_types::BackupGroup {
|
||||
fn from(group: &BackupGroup) -> pbs_api_types::BackupGroup {
|
||||
(group.backup_type, group.backup_id.clone()).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BackupGroup> for pbs_api_types::BackupGroup {
|
||||
fn from(group: BackupGroup) -> pbs_api_types::BackupGroup {
|
||||
(group.backup_type, group.backup_id).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BackupGroup {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let backup_type = self.backup_type();
|
||||
@ -188,7 +201,7 @@ impl std::str::FromStr for BackupGroup {
|
||||
.ok_or_else(|| format_err!("unable to parse backup group path '{}'", path))?;
|
||||
|
||||
Ok(Self {
|
||||
backup_type: cap.get(1).unwrap().as_str().to_owned(),
|
||||
backup_type: cap.get(1).unwrap().as_str().parse()?,
|
||||
backup_id: cap.get(2).unwrap().as_str().to_owned(),
|
||||
})
|
||||
}
|
||||
@ -208,28 +221,26 @@ pub struct BackupDir {
|
||||
}
|
||||
|
||||
impl BackupDir {
|
||||
pub fn new<T, U>(backup_type: T, backup_id: U, backup_time: i64) -> Result<Self, Error>
|
||||
pub fn new<T>(backup_type: BackupType, backup_id: T, backup_time: i64) -> Result<Self, Error>
|
||||
where
|
||||
T: Into<String>,
|
||||
U: Into<String>,
|
||||
{
|
||||
let group = BackupGroup::new(backup_type.into(), backup_id.into());
|
||||
let group = BackupGroup::new(backup_type, backup_id.into());
|
||||
BackupDir::with_group(group, backup_time)
|
||||
}
|
||||
|
||||
pub fn with_rfc3339<T, U, V>(
|
||||
backup_type: T,
|
||||
backup_id: U,
|
||||
backup_time_string: V,
|
||||
pub fn with_rfc3339<T, U>(
|
||||
backup_type: BackupType,
|
||||
backup_id: T,
|
||||
backup_time_string: U,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
T: Into<String>,
|
||||
U: Into<String>,
|
||||
V: Into<String>,
|
||||
{
|
||||
let backup_time_string = backup_time_string.into();
|
||||
let backup_time = proxmox_time::parse_rfc3339(&backup_time_string)?;
|
||||
let group = BackupGroup::new(backup_type.into(), backup_id.into());
|
||||
let group = BackupGroup::new(backup_type, backup_id.into());
|
||||
Ok(Self {
|
||||
group,
|
||||
backup_time,
|
||||
@ -283,6 +294,22 @@ impl BackupDir {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&BackupDir> for pbs_api_types::BackupDir {
|
||||
fn from(dir: &BackupDir) -> pbs_api_types::BackupDir {
|
||||
(
|
||||
pbs_api_types::BackupGroup::from(dir.group.clone()),
|
||||
dir.backup_time,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BackupDir> for pbs_api_types::BackupDir {
|
||||
fn from(dir: BackupDir) -> pbs_api_types::BackupDir {
|
||||
(pbs_api_types::BackupGroup::from(dir.group), dir.backup_time).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for BackupDir {
|
||||
type Err = Error;
|
||||
|
||||
@ -295,7 +322,7 @@ impl std::str::FromStr for BackupDir {
|
||||
.ok_or_else(|| format_err!("unable to parse backup snapshot path '{}'", path))?;
|
||||
|
||||
BackupDir::with_rfc3339(
|
||||
cap.get(1).unwrap().as_str(),
|
||||
cap.get(1).unwrap().as_str().parse()?,
|
||||
cap.get(2).unwrap().as_str(),
|
||||
cap.get(3).unwrap().as_str(),
|
||||
)
|
||||
|
@ -18,8 +18,8 @@ use proxmox_sys::WorkerTaskContext;
|
||||
use proxmox_sys::{task_log, task_warn};
|
||||
|
||||
use pbs_api_types::{
|
||||
Authid, ChunkOrder, DataStoreConfig, DatastoreTuning, GarbageCollectionStatus, HumanByte,
|
||||
Operation, BACKUP_DATE_REGEX, BACKUP_ID_REGEX, BACKUP_TYPE_REGEX, UPID,
|
||||
Authid, BackupType, ChunkOrder, DataStoreConfig, DatastoreTuning, GarbageCollectionStatus,
|
||||
HumanByte, Operation, BACKUP_DATE_REGEX, BACKUP_ID_REGEX, UPID,
|
||||
};
|
||||
use pbs_config::{open_backup_lockfile, BackupLockGuard, ConfigVersionCache};
|
||||
|
||||
@ -494,7 +494,7 @@ impl DataStore {
|
||||
) -> Result<(Authid, DirLockGuard), Error> {
|
||||
// create intermediate path first:
|
||||
let mut full_path = self.base_path();
|
||||
full_path.push(backup_group.backup_type());
|
||||
full_path.push(backup_group.backup_type().as_str());
|
||||
std::fs::create_dir_all(&full_path)?;
|
||||
|
||||
full_path.push(backup_group.backup_id());
|
||||
@ -1113,7 +1113,7 @@ impl Iterator for ListSnapshots {
|
||||
/// A iterator for a (single) level of Backup Groups
|
||||
pub struct ListGroups {
|
||||
type_fd: proxmox_sys::fs::ReadDir,
|
||||
id_state: Option<(String, proxmox_sys::fs::ReadDir)>,
|
||||
id_state: Option<(BackupType, proxmox_sys::fs::ReadDir)>,
|
||||
}
|
||||
|
||||
impl ListGroups {
|
||||
@ -1130,7 +1130,7 @@ impl Iterator for ListGroups {
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
if let Some((ref group_type, ref mut id_fd)) = self.id_state {
|
||||
if let Some((group_type, ref mut id_fd)) = self.id_state {
|
||||
let item = match id_fd.next() {
|
||||
Some(item) => item,
|
||||
None => {
|
||||
@ -1162,7 +1162,7 @@ impl Iterator for ListGroups {
|
||||
Some(nix::dir::Type::Directory) => {} // OK
|
||||
_ => continue,
|
||||
}
|
||||
if BACKUP_TYPE_REGEX.is_match(name) {
|
||||
if let Ok(group_type) = BackupType::from_str(name) {
|
||||
// found a backup group type, descend into it to scan all IDs in it
|
||||
// by switching to the id-state branch
|
||||
let base_fd = entry.parent_fd();
|
||||
@ -1170,7 +1170,7 @@ impl Iterator for ListGroups {
|
||||
Ok(dirfd) => dirfd,
|
||||
Err(err) => return Some(Err(err.into())),
|
||||
};
|
||||
self.id_state = Some((name.to_owned(), id_dirfd));
|
||||
self.id_state = Some((group_type, id_dirfd));
|
||||
}
|
||||
}
|
||||
continue; // file did not match regex or isn't valid utf-8
|
||||
|
@ -6,7 +6,7 @@ use anyhow::{bail, format_err, Error};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use pbs_api_types::{CryptMode, Fingerprint};
|
||||
use pbs_api_types::{BackupType, CryptMode, Fingerprint};
|
||||
use pbs_tools::crypt_config::CryptConfig;
|
||||
|
||||
use crate::BackupDir;
|
||||
@ -50,7 +50,7 @@ impl FileInfo {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct BackupManifest {
|
||||
backup_type: String,
|
||||
backup_type: BackupType,
|
||||
backup_id: String,
|
||||
backup_time: i64,
|
||||
files: Vec<FileInfo>,
|
||||
@ -87,7 +87,7 @@ pub fn archive_type<P: AsRef<Path>>(archive_name: P) -> Result<ArchiveType, Erro
|
||||
impl BackupManifest {
|
||||
pub fn new(snapshot: BackupDir) -> Self {
|
||||
Self {
|
||||
backup_type: snapshot.group().backup_type().into(),
|
||||
backup_type: snapshot.group().backup_type(),
|
||||
backup_id: snapshot.group().backup_id().into(),
|
||||
backup_time: snapshot.backup_time(),
|
||||
files: Vec::new(),
|
||||
|
Reference in New Issue
Block a user