add ns-recursive and acl/authid aware backup group iter
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
d4037525a8
commit
8e82cc807c
100
src/backup/hierarchy.rs
Normal file
100
src/backup/hierarchy.rs
Normal file
@ -0,0 +1,100 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Error;
|
||||
|
||||
use pbs_api_types::{
|
||||
Authid, BackupNamespace, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY,
|
||||
};
|
||||
use pbs_config::CachedUserInfo;
|
||||
use pbs_datastore::{backup_info::BackupGroup, DataStore, ListGroups, ListNamespacesRecursive};
|
||||
|
||||
/// A priviledge aware iterator for all backup groups in all Namespaces below an anchor namespace,
|
||||
/// most often that will be the `BackupNamespace::root()` one.
|
||||
///
|
||||
/// Is basically just a filter-iter for pbs_datastore::ListNamespacesRecursive including access and
|
||||
/// optional owner checks.
|
||||
pub struct ListAccessibleBackupGroups {
|
||||
store: Arc<DataStore>,
|
||||
auth_id: Option<Authid>,
|
||||
user_info: Arc<CachedUserInfo>,
|
||||
state: Option<ListGroups>,
|
||||
ns_iter: ListNamespacesRecursive,
|
||||
}
|
||||
|
||||
impl ListAccessibleBackupGroups {
|
||||
// TODO: builder pattern
|
||||
|
||||
pub fn new(
|
||||
store: Arc<DataStore>,
|
||||
ns: BackupNamespace,
|
||||
max_depth: usize,
|
||||
auth_id: Option<Authid>,
|
||||
) -> Result<Self, Error> {
|
||||
let ns_iter = ListNamespacesRecursive::new_max_depth(Arc::clone(&store), ns, max_depth)?;
|
||||
Ok(ListAccessibleBackupGroups {
|
||||
auth_id,
|
||||
ns_iter,
|
||||
state: None,
|
||||
store: store,
|
||||
user_info: CachedUserInfo::new()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ListAccessibleBackupGroups {
|
||||
type Item = Result<BackupGroup, Error>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
const PRIVS_OK: u64 = PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_BACKUP | PRIV_DATASTORE_AUDIT;
|
||||
loop {
|
||||
if let Some(ref mut state) = self.state {
|
||||
match state.next() {
|
||||
Some(Ok(group)) => {
|
||||
if let Some(auth_id) = &self.auth_id {
|
||||
match self.store.owns_backup(
|
||||
&group.backup_ns(),
|
||||
group.group(),
|
||||
&auth_id,
|
||||
) {
|
||||
Ok(is_owner) if is_owner => return Some(Ok(group)),
|
||||
Ok(_) => continue,
|
||||
Err(err) => return Some(Err(err)),
|
||||
}
|
||||
} else {
|
||||
return Some(Ok(group));
|
||||
}
|
||||
}
|
||||
Some(Err(err)) => return Some(Err(err)),
|
||||
None => {
|
||||
self.state = None; // level exhausted, need to check next NS
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match self.ns_iter.next() {
|
||||
Some(Ok(ns)) => {
|
||||
if let Some(auth_id) = &self.auth_id {
|
||||
let info = &self.user_info;
|
||||
let privs = if ns.is_root() {
|
||||
info.lookup_privs(&auth_id, &["datastore", self.store.name()])
|
||||
} else {
|
||||
info.lookup_privs(
|
||||
&auth_id,
|
||||
&["datastore", self.store.name(), &ns.to_string()],
|
||||
)
|
||||
};
|
||||
if privs & PRIVS_OK == 0 {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
self.state = match ListGroups::new(Arc::clone(&self.store), ns) {
|
||||
Ok(iter) => Some(iter),
|
||||
Err(err) => return Some(Err(err)),
|
||||
};
|
||||
}
|
||||
Some(Err(err)) => return Some(Err(err)),
|
||||
None => return None, // exhausted with all NS -> done
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,3 +5,6 @@ pub const CATALOG_NAME: &str = "catalog.pcat1.didx";
|
||||
|
||||
mod verify;
|
||||
pub use verify::*;
|
||||
|
||||
mod hierarchy;
|
||||
pub use hierarchy::*;
|
||||
|
Loading…
Reference in New Issue
Block a user