tape: add namespaces mapping type
and the relevant parser for it Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
parent
999293bbca
commit
be97e0a55b
|
@ -1464,6 +1464,39 @@ pub const ADMIN_DATASTORE_PRUNE_RETURN_TYPE: ReturnType = ReturnType {
|
||||||
.schema(),
|
.schema(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
properties: {
|
||||||
|
store: {
|
||||||
|
schema: DATASTORE_SCHEMA,
|
||||||
|
},
|
||||||
|
"max-depth": {
|
||||||
|
schema: NS_MAX_DEPTH_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
/// A namespace mapping
|
||||||
|
pub struct TapeRestoreNamespace {
|
||||||
|
/// The source datastore
|
||||||
|
pub store: String,
|
||||||
|
/// The source namespace. Root namespace if omitted.
|
||||||
|
pub source: Option<BackupNamespace>,
|
||||||
|
/// The target namespace,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub target: Option<BackupNamespace>,
|
||||||
|
/// The (optional) recursion depth
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub max_depth: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TAPE_RESTORE_NAMESPACE_SCHEMA: Schema = StringSchema::new("A namespace mapping")
|
||||||
|
.format(&ApiStringFormat::PropertyString(
|
||||||
|
&TapeRestoreNamespace::API_SCHEMA,
|
||||||
|
))
|
||||||
|
.schema();
|
||||||
|
|
||||||
/// Parse snapshots in the form 'ns/foo/ns/bar/ct/100/1970-01-01T00:00:00Z'
|
/// Parse snapshots in the form 'ns/foo/ns/bar/ct/100/1970-01-01T00:00:00Z'
|
||||||
/// into a [`BackupNamespace`] and [`BackupDir`]
|
/// into a [`BackupNamespace`] and [`BackupDir`]
|
||||||
pub fn parse_ns_and_snapshot(input: &str) -> Result<(BackupNamespace, BackupDir), Error> {
|
pub fn parse_ns_and_snapshot(input: &str) -> Result<(BackupNamespace, BackupDir), Error> {
|
||||||
|
|
|
@ -10,16 +10,17 @@ use serde_json::Value;
|
||||||
|
|
||||||
use proxmox_io::ReadExt;
|
use proxmox_io::ReadExt;
|
||||||
use proxmox_router::{Permission, Router, RpcEnvironment, RpcEnvironmentType};
|
use proxmox_router::{Permission, Router, RpcEnvironment, RpcEnvironmentType};
|
||||||
use proxmox_schema::api;
|
use proxmox_schema::{api, ApiType};
|
||||||
use proxmox_section_config::SectionConfigData;
|
use proxmox_section_config::SectionConfigData;
|
||||||
use proxmox_sys::fs::{replace_file, CreateOptions};
|
use proxmox_sys::fs::{replace_file, CreateOptions};
|
||||||
use proxmox_sys::{task_log, task_warn, WorkerTaskContext};
|
use proxmox_sys::{task_log, task_warn, WorkerTaskContext};
|
||||||
use proxmox_uuid::Uuid;
|
use proxmox_uuid::Uuid;
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid, BackupNamespace, CryptMode, Operation, Userid, DATASTORE_MAP_ARRAY_SCHEMA,
|
Authid, BackupNamespace, CryptMode, Operation, TapeRestoreNamespace, Userid,
|
||||||
DATASTORE_MAP_LIST_SCHEMA, DRIVE_NAME_SCHEMA, PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY,
|
DATASTORE_MAP_ARRAY_SCHEMA, DATASTORE_MAP_LIST_SCHEMA, DRIVE_NAME_SCHEMA, MAX_NAMESPACE_DEPTH,
|
||||||
PRIV_TAPE_READ, TAPE_RESTORE_SNAPSHOT_SCHEMA, UPID_SCHEMA,
|
PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY, PRIV_TAPE_READ, TAPE_RESTORE_SNAPSHOT_SCHEMA,
|
||||||
|
UPID_SCHEMA,
|
||||||
};
|
};
|
||||||
use pbs_config::CachedUserInfo;
|
use pbs_config::CachedUserInfo;
|
||||||
use pbs_datastore::dynamic_index::DynamicIndexReader;
|
use pbs_datastore::dynamic_index::DynamicIndexReader;
|
||||||
|
@ -56,6 +57,71 @@ pub struct DataStoreMap {
|
||||||
default: Option<Arc<DataStore>>,
|
default: Option<Arc<DataStore>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct NamespaceMap {
|
||||||
|
map: HashMap<String, HashMap<BackupNamespace, (BackupNamespace, usize)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<String>> for NamespaceMap {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(mappings: Vec<String>) -> Result<Self, Error> {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
|
let mappings = mappings.into_iter().map(|s| {
|
||||||
|
let value = TapeRestoreNamespace::API_SCHEMA.parse_property_string(&s)?;
|
||||||
|
let value: TapeRestoreNamespace = serde_json::from_value(value)?;
|
||||||
|
Ok::<_, Error>(value)
|
||||||
|
});
|
||||||
|
|
||||||
|
for mapping in mappings {
|
||||||
|
let mapping = mapping?;
|
||||||
|
let source = mapping.source.unwrap_or_default();
|
||||||
|
let target = mapping.target.unwrap_or_default();
|
||||||
|
let max_depth = mapping.max_depth.unwrap_or(MAX_NAMESPACE_DEPTH);
|
||||||
|
|
||||||
|
let ns_map: &mut HashMap<BackupNamespace, (BackupNamespace, usize)> =
|
||||||
|
map.entry(mapping.store).or_insert_with(HashMap::new);
|
||||||
|
|
||||||
|
if ns_map.insert(source, (target, max_depth)).is_some() {
|
||||||
|
bail!("duplicate mapping found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self { map })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NamespaceMap {
|
||||||
|
fn used_namespaces<'a>(&self, datastore: &str) -> HashSet<BackupNamespace> {
|
||||||
|
let mut set = HashSet::new();
|
||||||
|
if let Some(mapping) = self.map.get(datastore) {
|
||||||
|
for (ns, _) in mapping.values() {
|
||||||
|
set.insert(ns.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_namespaces(&self, source_ds: &str, source_ns: &BackupNamespace) -> Vec<BackupNamespace> {
|
||||||
|
if let Some(mapping) = self.map.get(source_ds) {
|
||||||
|
return mapping
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(ns, (target_ns, max_depth))| {
|
||||||
|
// filter out prefixes which are too long
|
||||||
|
if ns.depth() > source_ns.depth() || source_ns.depth() - ns.depth() > *max_depth
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
source_ns.map_prefix(ns, target_ns).ok()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<String> for DataStoreMap {
|
impl TryFrom<String> for DataStoreMap {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue