add prune jobs api
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
@ -5,7 +5,8 @@ use anyhow::Error;
|
||||
use proxmox_sys::{task_log, task_warn};
|
||||
|
||||
use pbs_api_types::{
|
||||
Authid, BackupNamespace, Operation, PruneOptions, PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE,
|
||||
print_store_and_ns, Authid, KeepOptions, Operation, PruneJobOptions, PRIV_DATASTORE_MODIFY,
|
||||
PRIV_DATASTORE_PRUNE,
|
||||
};
|
||||
use pbs_datastore::prune::compute_prune_info;
|
||||
use pbs_datastore::DataStore;
|
||||
@ -17,13 +18,14 @@ use crate::server::jobstate::Job;
|
||||
pub fn prune_datastore(
|
||||
worker: Arc<WorkerTask>,
|
||||
auth_id: Authid,
|
||||
prune_options: PruneOptions,
|
||||
prune_options: PruneJobOptions,
|
||||
datastore: Arc<DataStore>,
|
||||
ns: BackupNamespace,
|
||||
max_depth: usize,
|
||||
dry_run: bool,
|
||||
) -> Result<(), Error> {
|
||||
let store = &datastore.name();
|
||||
let max_depth = prune_options
|
||||
.max_depth
|
||||
.unwrap_or(pbs_api_types::MAX_NAMESPACE_DEPTH);
|
||||
let depth_str = if max_depth == pbs_api_types::MAX_NAMESPACE_DEPTH {
|
||||
" down to full depth".to_string()
|
||||
} else if max_depth > 0 {
|
||||
@ -31,23 +33,18 @@ pub fn prune_datastore(
|
||||
} else {
|
||||
"non-recursive".to_string()
|
||||
};
|
||||
if ns.is_root() {
|
||||
task_log!(
|
||||
worker,
|
||||
"Starting datastore prune on store '{store}', {depth_str}"
|
||||
);
|
||||
} else {
|
||||
task_log!(
|
||||
worker,
|
||||
"Starting datastore prune on store '{store}' namespace '{ns}', {depth_str}"
|
||||
);
|
||||
}
|
||||
let ns = prune_options.ns.clone().unwrap_or_default();
|
||||
task_log!(
|
||||
worker,
|
||||
"Starting datastore prune on {}, {depth_str}",
|
||||
print_store_and_ns(store, &ns),
|
||||
);
|
||||
|
||||
if dry_run {
|
||||
task_log!(worker, "(dry test run)");
|
||||
}
|
||||
|
||||
let keep_all = !pbs_datastore::prune::keeps_something(&prune_options);
|
||||
let keep_all = !prune_options.keeps_something();
|
||||
|
||||
if keep_all {
|
||||
task_log!(worker, "No prune selection - keeping all files.");
|
||||
@ -55,7 +52,7 @@ pub fn prune_datastore(
|
||||
task_log!(
|
||||
worker,
|
||||
"retention options: {}",
|
||||
pbs_datastore::prune::cli_options_string(&prune_options)
|
||||
cli_prune_options_string(&prune_options)
|
||||
);
|
||||
}
|
||||
|
||||
@ -71,7 +68,7 @@ pub fn prune_datastore(
|
||||
let ns = group.backup_ns();
|
||||
let list = group.list_backups()?;
|
||||
|
||||
let mut prune_info = compute_prune_info(list, &prune_options)?;
|
||||
let mut prune_info = compute_prune_info(list, &prune_options.keep)?;
|
||||
prune_info.reverse(); // delete older snapshots first
|
||||
|
||||
task_log!(
|
||||
@ -104,9 +101,60 @@ pub fn prune_datastore(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn cli_prune_options_string(options: &PruneJobOptions) -> String {
|
||||
let mut opts = Vec::new();
|
||||
|
||||
if let Some(ns) = &options.ns {
|
||||
if !ns.is_root() {
|
||||
opts.push(format!("--ns {}", ns));
|
||||
}
|
||||
}
|
||||
if let Some(max_depth) = options.max_depth {
|
||||
// FIXME: don't add if it's the default?
|
||||
opts.push(format!("--max-depth {max_depth}"));
|
||||
}
|
||||
|
||||
cli_keep_options(&mut opts, &options.keep);
|
||||
|
||||
opts.join(" ")
|
||||
}
|
||||
|
||||
pub(crate) fn cli_keep_options(opts: &mut Vec<String>, options: &KeepOptions) {
|
||||
if let Some(count) = options.keep_last {
|
||||
if count > 0 {
|
||||
opts.push(format!("--keep-last {}", count));
|
||||
}
|
||||
}
|
||||
if let Some(count) = options.keep_hourly {
|
||||
if count > 0 {
|
||||
opts.push(format!("--keep-hourly {}", count));
|
||||
}
|
||||
}
|
||||
if let Some(count) = options.keep_daily {
|
||||
if count > 0 {
|
||||
opts.push(format!("--keep-daily {}", count));
|
||||
}
|
||||
}
|
||||
if let Some(count) = options.keep_weekly {
|
||||
if count > 0 {
|
||||
opts.push(format!("--keep-weekly {}", count));
|
||||
}
|
||||
}
|
||||
if let Some(count) = options.keep_monthly {
|
||||
if count > 0 {
|
||||
opts.push(format!("--keep-monthly {}", count));
|
||||
}
|
||||
}
|
||||
if let Some(count) = options.keep_yearly {
|
||||
if count > 0 {
|
||||
opts.push(format!("--keep-yearly {}", count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_prune_job(
|
||||
mut job: Job,
|
||||
prune_options: PruneOptions,
|
||||
prune_options: PruneJobOptions,
|
||||
store: String,
|
||||
auth_id: &Authid,
|
||||
schedule: Option<String>,
|
||||
@ -115,8 +163,12 @@ pub fn do_prune_job(
|
||||
|
||||
let worker_type = job.jobtype().to_string();
|
||||
let auth_id = auth_id.clone();
|
||||
// TODO include namespace info here once this becomes namespace-aware/configurable
|
||||
let worker_id = format!("{store}");
|
||||
let worker_id = match &prune_options.ns {
|
||||
Some(ns) if ns.is_root() => format!("{store}"),
|
||||
Some(ns) => format!("{store}:{ns}"),
|
||||
None => format!("{store}"),
|
||||
};
|
||||
|
||||
let upid_str = WorkerTask::new_thread(
|
||||
&worker_type,
|
||||
Some(worker_id),
|
||||
@ -131,15 +183,7 @@ pub fn do_prune_job(
|
||||
task_log!(worker, "task triggered by schedule '{}'", event_str);
|
||||
}
|
||||
|
||||
let result = prune_datastore(
|
||||
worker.clone(),
|
||||
auth_id,
|
||||
prune_options,
|
||||
datastore,
|
||||
BackupNamespace::default(),
|
||||
pbs_api_types::MAX_NAMESPACE_DEPTH,
|
||||
false,
|
||||
);
|
||||
let result = prune_datastore(worker.clone(), auth_id, prune_options, datastore, false);
|
||||
|
||||
let status = worker.create_state(&result);
|
||||
|
||||
|
Reference in New Issue
Block a user