]>
Commit | Line | Data |
---|---|---|
61f05679 | 1 | use std::sync::Arc; |
b8d90798 | 2 | |
61f05679 | 3 | use anyhow::Error; |
b8d90798 | 4 | |
b2065dc7 | 5 | use pbs_datastore::backup_info::BackupInfo; |
89725197 DM |
6 | use pbs_datastore::prune::compute_prune_info; |
7 | use pbs_api_types::{Authid, PRIV_DATASTORE_MODIFY, PruneOptions}; | |
ba3d7e19 | 8 | use pbs_config::CachedUserInfo; |
b9700a9f DM |
9 | use pbs_tools::{task_log, task_warn}; |
10 | use proxmox_rest_server::WorkerTask; | |
c23192d3 | 11 | |
b8d90798 | 12 | use crate::{ |
b2065dc7 | 13 | backup::DataStore, |
b8d90798 | 14 | server::jobstate::Job, |
b9700a9f | 15 | }; |
b8d90798 | 16 | |
61f05679 DC |
17 | pub 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 |
94 | pub 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 | } |