]> git.proxmox.com Git - proxmox-backup.git/blame - src/server/prune_job.rs
move worker_task.rs into proxmox-rest-server crate
[proxmox-backup.git] / src / server / prune_job.rs
CommitLineData
61f05679 1use std::sync::Arc;
b8d90798 2
61f05679 3use anyhow::Error;
b8d90798 4
b2065dc7 5use pbs_datastore::backup_info::BackupInfo;
89725197
DM
6use pbs_datastore::prune::compute_prune_info;
7use pbs_api_types::{Authid, PRIV_DATASTORE_MODIFY, PruneOptions};
ba3d7e19 8use pbs_config::CachedUserInfo;
b9700a9f
DM
9use pbs_tools::{task_log, task_warn};
10use proxmox_rest_server::WorkerTask;
c23192d3 11
b8d90798 12use crate::{
b2065dc7 13 backup::DataStore,
b8d90798 14 server::jobstate::Job,
b9700a9f 15 };
b8d90798 16
61f05679
DC
17pub fn prune_datastore(
18 worker: Arc<WorkerTask>,
8e0b852f 19 auth_id: Authid,
61f05679
DC
20 prune_options: PruneOptions,
21 store: &str,
22 datastore: Arc<DataStore>,
9805207a 23 dry_run: bool,
61f05679
DC
24) -> Result<(), Error> {
25 task_log!(worker, "Starting datastore prune on store \"{}\"", store);
26
9805207a
DC
27 if dry_run {
28 task_log!(worker, "(dry test run)");
29 }
30
89725197 31 let keep_all = !pbs_datastore::prune::keeps_something(&prune_options);
0052dc6d
DC
32
33 if keep_all {
34 task_log!(worker, "No prune selection - keeping all files.");
35 } else {
36 task_log!(
37 worker,
38 "retention options: {}",
89725197 39 pbs_datastore::prune::cli_options_string(&prune_options)
0052dc6d
DC
40 );
41 }
61f05679 42
8e0b852f
DC
43 let user_info = CachedUserInfo::new()?;
44 let privs = user_info.lookup_privs(&auth_id, &["datastore", store]);
45 let has_privs = privs & PRIV_DATASTORE_MODIFY != 0;
46
61f05679
DC
47 let base_path = datastore.base_path();
48
49 let groups = BackupInfo::list_backup_groups(&base_path)?;
50 for group in groups {
51 let list = group.list_backups(&base_path)?;
8e0b852f
DC
52
53 if !has_privs && !datastore.owns_backup(&group, &auth_id)? {
54 continue;
55 }
56
61f05679
DC
57 let mut prune_info = compute_prune_info(list, &prune_options)?;
58 prune_info.reverse(); // delete older snapshots first
59
60 task_log!(
61 worker,
62 "Starting prune on store \"{}\" group \"{}/{}\"",
63 store,
64 group.backup_type(),
65 group.backup_id()
66 );
67
0052dc6d
DC
68 for (info, mut keep) in prune_info {
69 if keep_all { keep = true; }
61f05679
DC
70 task_log!(
71 worker,
72 "{} {}/{}/{}",
73 if keep { "keep" } else { "remove" },
74 group.backup_type(),
75 group.backup_id(),
76 info.backup_dir.backup_time_string()
77 );
9805207a 78 if !keep && !dry_run {
61f05679
DC
79 if let Err(err) = datastore.remove_backup_dir(&info.backup_dir, false) {
80 task_warn!(
81 worker,
82 "failed to remove dir {:?}: {}",
83 info.backup_dir.relative_path(),
84 err,
85 );
86 }
87 }
88 }
89 }
90
91 Ok(())
92}
93
b8d90798
HL
94pub fn do_prune_job(
95 mut job: Job,
96 prune_options: PruneOptions,
97 store: String,
98 auth_id: &Authid,
99 schedule: Option<String>,
100) -> Result<String, Error> {
101 let datastore = DataStore::lookup_datastore(&store)?;
102
103 let worker_type = job.jobtype().to_string();
8e0b852f 104 let auth_id = auth_id.clone();
b8d90798
HL
105 let upid_str = WorkerTask::new_thread(
106 &worker_type,
107 Some(job.jobname().to_string()),
049a22a3 108 auth_id.to_string(),
b8d90798
HL
109 false,
110 move |worker| {
111 job.start(&worker.upid().to_string())?;
112
61f05679
DC
113 if let Some(event_str) = schedule {
114 task_log!(worker, "task triggered by schedule '{}'", event_str);
115 }
b8d90798 116
9805207a 117 let result = prune_datastore(worker.clone(), auth_id, prune_options, &store, datastore, false);
b8d90798
HL
118
119 let status = worker.create_state(&result);
120
121 if let Err(err) = job.finish(status) {
122 eprintln!(
123 "could not finish job state for {}: {}",
124 job.jobtype().to_string(),
125 err
126 );
127 }
128
129 result
130 },
131 )?;
132 Ok(upid_str)
133}