src/api2/admin/datastore.rs: pass backup type/id (group) to prune
IMHO, prune over all backup groups is a bit dangerous, considering that more than one user might use a datastore.
This commit is contained in:
parent
7a6cfbd98d
commit
9fdc3ef46f
|
@ -214,6 +214,11 @@ fn prune(
|
||||||
|
|
||||||
let store = param["store"].as_str().unwrap();
|
let store = param["store"].as_str().unwrap();
|
||||||
|
|
||||||
|
let backup_type = tools::required_string_param(¶m, "backup-type")?;
|
||||||
|
let backup_id = tools::required_string_param(¶m, "backup-id")?;
|
||||||
|
|
||||||
|
let group = BackupGroup::new(backup_type, backup_id);
|
||||||
|
|
||||||
let datastore = DataStore::lookup_datastore(store)?;
|
let datastore = DataStore::lookup_datastore(store)?;
|
||||||
|
|
||||||
let mut keep_all = true;
|
let mut keep_all = true;
|
||||||
|
@ -228,61 +233,56 @@ fn prune(
|
||||||
let worker = WorkerTask::new("prune", Some(store.to_owned()), "root@pam", true)?;
|
let worker = WorkerTask::new("prune", Some(store.to_owned()), "root@pam", true)?;
|
||||||
let result = try_block! {
|
let result = try_block! {
|
||||||
if keep_all {
|
if keep_all {
|
||||||
worker.log("No selection - keeping all files.");
|
worker.log("No prune selection - keeping all files.");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
worker.log(format!("Starting prune on store {}", store));
|
worker.log(format!("Starting prune on store {}", store));
|
||||||
}
|
}
|
||||||
|
|
||||||
let backup_list = BackupInfo::list_backups(&datastore.base_path())?;
|
let mut list = group.list_backups(&datastore.base_path())?;
|
||||||
|
|
||||||
let group_hash = group_backups(backup_list);
|
let mut mark = HashSet::new();
|
||||||
|
|
||||||
for (_group_id, mut list) in group_hash {
|
BackupInfo::sort_list(&mut list, false);
|
||||||
|
|
||||||
let mut mark = HashSet::new();
|
if let Some(keep_last) = param["keep-last"].as_u64() {
|
||||||
|
list.iter().take(keep_last as usize).for_each(|info| {
|
||||||
|
mark.insert(info.backup_dir.relative_path());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
BackupInfo::sort_list(&mut list, false);
|
if let Some(keep_daily) = param["keep-daily"].as_u64() {
|
||||||
|
mark_selections(&mut mark, &list, keep_daily as usize, |local_time, _info| {
|
||||||
|
format!("{}/{}/{}", local_time.year(), local_time.month(), local_time.day())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(keep_last) = param["keep-last"].as_u64() {
|
if let Some(keep_weekly) = param["keep-weekly"].as_u64() {
|
||||||
list.iter().take(keep_last as usize).for_each(|info| {
|
mark_selections(&mut mark, &list, keep_weekly as usize, |local_time, _info| {
|
||||||
mark.insert(info.backup_dir.relative_path());
|
format!("{}/{}", local_time.year(), local_time.iso_week().week())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(keep_daily) = param["keep-daily"].as_u64() {
|
if let Some(keep_monthly) = param["keep-monthly"].as_u64() {
|
||||||
mark_selections(&mut mark, &list, keep_daily as usize, |local_time, _info| {
|
mark_selections(&mut mark, &list, keep_monthly as usize, |local_time, _info| {
|
||||||
format!("{}/{}/{}", local_time.year(), local_time.month(), local_time.day())
|
format!("{}/{}", local_time.year(), local_time.month())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(keep_weekly) = param["keep-weekly"].as_u64() {
|
if let Some(keep_yearly) = param["keep-yearly"].as_u64() {
|
||||||
mark_selections(&mut mark, &list, keep_weekly as usize, |local_time, _info| {
|
mark_selections(&mut mark, &list, keep_yearly as usize, |local_time, _info| {
|
||||||
format!("{}/{}", local_time.year(), local_time.iso_week().week())
|
format!("{}/{}", local_time.year(), local_time.year())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(keep_monthly) = param["keep-monthly"].as_u64() {
|
let mut remove_list: Vec<BackupInfo> = list.into_iter()
|
||||||
mark_selections(&mut mark, &list, keep_monthly as usize, |local_time, _info| {
|
.filter(|info| !mark.contains(&info.backup_dir.relative_path())).collect();
|
||||||
format!("{}/{}", local_time.year(), local_time.month())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(keep_yearly) = param["keep-yearly"].as_u64() {
|
BackupInfo::sort_list(&mut remove_list, true);
|
||||||
mark_selections(&mut mark, &list, keep_yearly as usize, |local_time, _info| {
|
|
||||||
format!("{}/{}", local_time.year(), local_time.year())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut remove_list: Vec<BackupInfo> = list.into_iter()
|
for info in remove_list {
|
||||||
.filter(|info| !mark.contains(&info.backup_dir.relative_path())).collect();
|
worker.log(format!("remove {:?}", info.backup_dir));
|
||||||
|
datastore.remove_backup_dir(&info.backup_dir)?;
|
||||||
BackupInfo::sort_list(&mut remove_list, true);
|
|
||||||
|
|
||||||
for info in remove_list {
|
|
||||||
worker.log(format!("remove {:?}", info.backup_dir));
|
|
||||||
datastore.remove_backup_dir(&info.backup_dir)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -336,6 +336,8 @@ fn api_method_prune() -> ApiMethod {
|
||||||
"store",
|
"store",
|
||||||
StringSchema::new("Datastore name.")
|
StringSchema::new("Datastore name.")
|
||||||
)
|
)
|
||||||
|
.required("backup-type", BACKUP_TYPE_SCHEMA.clone())
|
||||||
|
.required("backup-id", BACKUP_ID_SCHEMA.clone())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -840,7 +840,7 @@ fn upload_log(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prune(
|
fn prune(
|
||||||
mut param: Value,
|
param: Value,
|
||||||
_info: &ApiMethod,
|
_info: &ApiMethod,
|
||||||
_rpcenv: &mut dyn RpcEnvironment,
|
_rpcenv: &mut dyn RpcEnvironment,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
|
@ -851,9 +851,14 @@ fn prune(
|
||||||
|
|
||||||
let path = format!("api2/json/admin/datastore/{}/prune", repo.store());
|
let path = format!("api2/json/admin/datastore/{}/prune", repo.store());
|
||||||
|
|
||||||
param.as_object_mut().unwrap().remove("repository");
|
let group = tools::required_string_param(¶m, "group")?;
|
||||||
|
let group = BackupGroup::parse(group)?;
|
||||||
|
|
||||||
let result = client.post(&path, Some(param)).wait()?;
|
let mut args = json!({});
|
||||||
|
args["backup-type"] = group.backup_type().into();
|
||||||
|
args["backup-id"] = group.backup_id().into();
|
||||||
|
|
||||||
|
let result = client.post(&path, Some(args)).wait()?;
|
||||||
|
|
||||||
record_repository(&repo);
|
record_repository(&repo);
|
||||||
|
|
||||||
|
@ -1440,9 +1445,12 @@ We do not extraxt '.pxar' archives when writing to stdandard output.
|
||||||
prune,
|
prune,
|
||||||
proxmox_backup::api2::admin::datastore::add_common_prune_prameters(
|
proxmox_backup::api2::admin::datastore::add_common_prune_prameters(
|
||||||
ObjectSchema::new("Prune backup repository.")
|
ObjectSchema::new("Prune backup repository.")
|
||||||
|
.required("group", StringSchema::new("Backup group."))
|
||||||
.optional("repository", REPO_URL_SCHEMA.clone())
|
.optional("repository", REPO_URL_SCHEMA.clone())
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
.arg_param(vec!["group"])
|
||||||
|
.completion_cb("group", complete_backup_group)
|
||||||
.completion_cb("repository", complete_repository);
|
.completion_cb("repository", complete_repository);
|
||||||
|
|
||||||
let status_cmd_def = CliCommand::new(
|
let status_cmd_def = CliCommand::new(
|
||||||
|
|
Loading…
Reference in New Issue