prune datastore: support max-depth and improve priv checks
use the relatively new variant of ListAccessibleBackupGroups to also allow pruning the groups that one doesn't own but has the respective privileges on their namespace level. This was previously handled by the API endpoint itself, which was ok as long as only one level was looked at. Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
65aba79a9b
commit
e3c26aea31
@ -1063,6 +1063,10 @@ pub fn prune(
|
||||
type: BackupNamespace,
|
||||
optional: true,
|
||||
},
|
||||
"max-depth": {
|
||||
schema: NS_MAX_DEPTH_SCHEMA,
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
returns: {
|
||||
@ -1079,6 +1083,7 @@ pub fn prune_datastore(
|
||||
prune_options: PruneOptions,
|
||||
store: String,
|
||||
ns: Option<BackupNamespace>,
|
||||
max_depth: Option<usize>,
|
||||
_param: Value,
|
||||
rpcenv: &mut dyn RpcEnvironment,
|
||||
) -> Result<String, Error> {
|
||||
@ -1090,15 +1095,21 @@ pub fn prune_datastore(
|
||||
|
||||
let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
|
||||
|
||||
// FIXME: add max-depth
|
||||
|
||||
let upid_str = WorkerTask::new_thread(
|
||||
"prune",
|
||||
Some(worker_id),
|
||||
auth_id.to_string(),
|
||||
to_stdout,
|
||||
move |worker| {
|
||||
crate::server::prune_datastore(worker, auth_id, prune_options, datastore, ns, dry_run)
|
||||
crate::server::prune_datastore(
|
||||
worker,
|
||||
auth_id,
|
||||
prune_options,
|
||||
datastore,
|
||||
ns,
|
||||
max_depth.unwrap_or(MAX_NAMESPACE_DEPTH), // canoot rely on schema default
|
||||
dry_run,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
|
@ -4,12 +4,14 @@ use anyhow::Error;
|
||||
|
||||
use proxmox_sys::{task_log, task_warn};
|
||||
|
||||
use pbs_api_types::{Authid, BackupNamespace, Operation, PruneOptions, PRIV_DATASTORE_MODIFY};
|
||||
use pbs_config::CachedUserInfo;
|
||||
use pbs_api_types::{
|
||||
Authid, BackupNamespace, Operation, PruneOptions, PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE,
|
||||
};
|
||||
use pbs_datastore::prune::compute_prune_info;
|
||||
use pbs_datastore::DataStore;
|
||||
use proxmox_rest_server::WorkerTask;
|
||||
|
||||
use crate::backup::ListAccessibleBackupGroups;
|
||||
use crate::server::jobstate::Job;
|
||||
|
||||
pub fn prune_datastore(
|
||||
@ -18,7 +20,7 @@ pub fn prune_datastore(
|
||||
prune_options: PruneOptions,
|
||||
datastore: Arc<DataStore>,
|
||||
ns: BackupNamespace,
|
||||
//max_depth: Option<usize>, // FIXME
|
||||
max_depth: usize,
|
||||
dry_run: bool,
|
||||
) -> Result<(), Error> {
|
||||
let store = &datastore.name();
|
||||
@ -47,26 +49,24 @@ pub fn prune_datastore(
|
||||
);
|
||||
}
|
||||
|
||||
let user_info = CachedUserInfo::new()?;
|
||||
let privs = user_info.lookup_privs(&auth_id, &["datastore", store]);
|
||||
let has_privs = privs & PRIV_DATASTORE_MODIFY != 0;
|
||||
|
||||
// FIXME: Namespace recursion!
|
||||
for group in datastore.iter_backup_groups(ns.clone())? {
|
||||
let ns_recursed = &ns; // remove_backup_dir might need the inner one
|
||||
for group in ListAccessibleBackupGroups::new_with_privs(
|
||||
&datastore,
|
||||
ns.clone(),
|
||||
max_depth,
|
||||
Some(PRIV_DATASTORE_MODIFY), // overides the owner check
|
||||
Some(PRIV_DATASTORE_PRUNE), // additionally required if owner
|
||||
Some(&auth_id),
|
||||
)? {
|
||||
let group = group?;
|
||||
let ns = group.backup_ns();
|
||||
let list = group.list_backups()?;
|
||||
|
||||
if !has_privs && !datastore.owns_backup(&ns_recursed, group.as_ref(), &auth_id)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut prune_info = compute_prune_info(list, &prune_options)?;
|
||||
prune_info.reverse(); // delete older snapshots first
|
||||
|
||||
task_log!(
|
||||
worker,
|
||||
"Pruning group \"{}/{}\"",
|
||||
"Pruning group {ns}:\"{}/{}\"",
|
||||
group.backup_type(),
|
||||
group.backup_id()
|
||||
);
|
||||
@ -83,9 +83,7 @@ pub fn prune_datastore(
|
||||
info.backup_dir.backup_time_string()
|
||||
);
|
||||
if !keep && !dry_run {
|
||||
if let Err(err) =
|
||||
datastore.remove_backup_dir(ns_recursed, info.backup_dir.as_ref(), false)
|
||||
{
|
||||
if let Err(err) = datastore.remove_backup_dir(ns, info.backup_dir.as_ref(), false) {
|
||||
let path = info.backup_dir.relative_path();
|
||||
task_warn!(worker, "failed to remove dir {path:?}: {err}");
|
||||
}
|
||||
@ -128,6 +126,7 @@ pub fn do_prune_job(
|
||||
prune_options,
|
||||
datastore,
|
||||
BackupNamespace::default(),
|
||||
pbs_api_types::MAX_NAMESPACE_DEPTH,
|
||||
false,
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user