api: admin/datastore: add new 'prune-datastore' api call

to prune the whole datastore at once, with the given parameters.
We need a new api call since this can take a while and we need to start
a worker for this. The exisiting api call returns a list of removed/kept
snapshots and is synchronous.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2021-07-16 10:53:26 +02:00 committed by Dietmar Maurer
parent 8e0b852f24
commit 9805207aa5
2 changed files with 69 additions and 3 deletions

View File

@ -820,7 +820,7 @@ pub fn verify(
permission: &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_PRUNE, true), permission: &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_PRUNE, true),
}, },
)] )]
/// Prune the datastore /// Prune a group on the datastore
pub fn prune( pub fn prune(
backup_id: String, backup_id: String,
backup_type: String, backup_type: String,
@ -922,6 +922,62 @@ pub fn prune(
Ok(json!(prune_result)) Ok(json!(prune_result))
} }
#[api(
input: {
properties: {
"dry-run": {
optional: true,
type: bool,
default: false,
description: "Just show what prune would do, but do not delete anything.",
},
"prune-options": {
type: PruneOptions,
flatten: true,
},
store: {
schema: DATASTORE_SCHEMA,
},
},
},
returns: {
schema: UPID_SCHEMA,
},
access: {
permission: &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_PRUNE, true),
},
)]
/// Prune the datastore
pub fn prune_datastore(
dry_run: bool,
prune_options: PruneOptions,
store: String,
_param: Value,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<String, Error> {
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
let datastore = DataStore::lookup_datastore(&store)?;
let upid_str = WorkerTask::new_thread(
"prune",
Some(store.clone()),
auth_id.clone(),
false,
move |worker| crate::server::prune_datastore(
worker.clone(),
auth_id,
prune_options,
&store,
datastore,
dry_run
),
)?;
Ok(upid_str)
}
#[api( #[api(
input: { input: {
properties: { properties: {
@ -1844,6 +1900,11 @@ const DATASTORE_INFO_SUBDIRS: SubdirMap = &[
&Router::new() &Router::new()
.post(&API_METHOD_PRUNE) .post(&API_METHOD_PRUNE)
), ),
(
"prune-datastore",
&Router::new()
.post(&API_METHOD_PRUNE_DATASTORE)
),
( (
"pxar-file-download", "pxar-file-download",
&Router::new() &Router::new()

View File

@ -19,9 +19,14 @@ pub fn prune_datastore(
prune_options: PruneOptions, prune_options: PruneOptions,
store: &str, store: &str,
datastore: Arc<DataStore>, datastore: Arc<DataStore>,
dry_run: bool,
) -> Result<(), Error> { ) -> Result<(), Error> {
task_log!(worker, "Starting datastore prune on store \"{}\"", store); task_log!(worker, "Starting datastore prune on store \"{}\"", store);
if dry_run {
task_log!(worker, "(dry test run)");
}
let keep_all = !prune_options.keeps_something(); let keep_all = !prune_options.keeps_something();
if keep_all { if keep_all {
@ -69,7 +74,7 @@ pub fn prune_datastore(
group.backup_id(), group.backup_id(),
info.backup_dir.backup_time_string() info.backup_dir.backup_time_string()
); );
if !keep { if !keep && !dry_run {
if let Err(err) = datastore.remove_backup_dir(&info.backup_dir, false) { if let Err(err) = datastore.remove_backup_dir(&info.backup_dir, false) {
task_warn!( task_warn!(
worker, worker,
@ -108,7 +113,7 @@ pub fn do_prune_job(
task_log!(worker, "task triggered by schedule '{}'", event_str); task_log!(worker, "task triggered by schedule '{}'", event_str);
} }
let result = prune_datastore(worker.clone(), auth_id, prune_options, &store, datastore); let result = prune_datastore(worker.clone(), auth_id, prune_options, &store, datastore, false);
let status = worker.create_state(&result); let status = worker.create_state(&result);