]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/config/verify.rs
update to first proxmox crate split
[proxmox-backup.git] / src / api2 / config / verify.rs
CommitLineData
9b2bad7a
HL
1use anyhow::{bail, Error};
2use serde_json::Value;
3use ::serde::{Deserialize, Serialize};
4
6ef1b649
WB
5use proxmox_router::{Router, RpcEnvironment, Permission};
6use proxmox_schema::api;
9b2bad7a 7
e3619d41 8use pbs_api_types::{
ffa403b5 9 Authid, VerificationJobConfig, VerificationJobConfigUpdater, JOB_ID_SCHEMA,
8cc3760e 10 PROXMOX_CONFIG_DIGEST_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_VERIFY,
e3619d41 11};
802189f7 12use pbs_config::verify;
b7ce2e57 13
ba3d7e19 14use pbs_config::CachedUserInfo;
9b2bad7a
HL
15
16#[api(
17 input: {
18 properties: {},
19 },
20 returns: {
21 description: "List configured jobs.",
22 type: Array,
e3619d41 23 items: { type: VerificationJobConfig },
9b2bad7a 24 },
b7ce2e57 25 access: {
35c80d69
FG
26 permission: &Permission::Anybody,
27 description: "Requires Datastore.Audit or Datastore.Verify on datastore.",
b7ce2e57 28 },
9b2bad7a
HL
29)]
30/// List all verification jobs
31pub fn list_verification_jobs(
32 _param: Value,
33 mut rpcenv: &mut dyn RpcEnvironment,
34) -> Result<Vec<VerificationJobConfig>, Error> {
35c80d69
FG
35 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
36 let user_info = CachedUserInfo::new()?;
37
38 let required_privs = PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_VERIFY;
9b2bad7a
HL
39
40 let (config, digest) = verify::config()?;
41
42 let list = config.convert_to_typed_array("verification")?;
43
35c80d69
FG
44 let list = list.into_iter()
45 .filter(|job: &VerificationJobConfig| {
46 let privs = user_info.lookup_privs(&auth_id, &["datastore", &job.store]);
47
48 privs & required_privs != 00
49 }).collect();
50
9b2bad7a
HL
51 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
52
53 Ok(list)
54}
55
56
57#[api(
58 protected: true,
59 input: {
60 properties: {
ffa403b5
DM
61 config: {
62 type: VerificationJobConfig,
63 flatten: true,
9b2bad7a 64 },
ffa403b5 65 },
b7ce2e57
FG
66 },
67 access: {
35c80d69
FG
68 permission: &Permission::Anybody,
69 description: "Requires Datastore.Verify on job's datastore.",
b7ce2e57 70 },
9b2bad7a
HL
71)]
72/// Create a new verification job.
35c80d69 73pub fn create_verification_job(
ffa403b5 74 config: VerificationJobConfig,
35c80d69
FG
75 rpcenv: &mut dyn RpcEnvironment
76) -> Result<(), Error> {
77 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
78 let user_info = CachedUserInfo::new()?;
9b2bad7a 79
ffa403b5 80 user_info.check_privs(&auth_id, &["datastore", &config.store], PRIV_DATASTORE_VERIFY, false)?;
35c80d69 81
802189f7 82 let _lock = verify::lock_config()?;
35c80d69 83
ffa403b5 84 let (mut section_config, _digest) = verify::config()?;
9b2bad7a 85
ffa403b5
DM
86 if section_config.sections.get(&config.id).is_some() {
87 bail!("job '{}' already exists.", config.id);
9b2bad7a
HL
88 }
89
ffa403b5 90 section_config.set_data(&config.id, "verification", &config)?;
9b2bad7a 91
ffa403b5 92 verify::save_config(&section_config)?;
9b2bad7a 93
ffa403b5 94 crate::server::jobstate::create_state_file("verificationjob", &config.id)?;
9b2bad7a
HL
95
96 Ok(())
97}
98
99#[api(
100 input: {
101 properties: {
102 id: {
103 schema: JOB_ID_SCHEMA,
104 },
105 },
106 },
e3619d41 107 returns: { type: VerificationJobConfig },
b7ce2e57 108 access: {
35c80d69
FG
109 permission: &Permission::Anybody,
110 description: "Requires Datastore.Audit or Datastore.Verify on job's datastore.",
b7ce2e57 111 },
9b2bad7a
HL
112)]
113/// Read a verification job configuration.
114pub fn read_verification_job(
115 id: String,
116 mut rpcenv: &mut dyn RpcEnvironment,
117) -> Result<VerificationJobConfig, Error> {
35c80d69
FG
118 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
119 let user_info = CachedUserInfo::new()?;
120
9b2bad7a
HL
121 let (config, digest) = verify::config()?;
122
e3619d41 123 let verification_job: VerificationJobConfig = config.lookup("verification", &id)?;
35c80d69
FG
124
125 let required_privs = PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_VERIFY;
126 user_info.check_privs(&auth_id, &["datastore", &verification_job.store], required_privs, true)?;
127
9b2bad7a
HL
128 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
129
130 Ok(verification_job)
131}
132
133#[api()]
134#[derive(Serialize, Deserialize)]
135#[serde(rename_all="kebab-case")]
136/// Deletable property name
137pub enum DeletableProperty {
138 /// Delete the ignore verified property.
139 IgnoreVerified,
140 /// Delete the comment property.
141 Comment,
142 /// Delete the job schedule.
143 Schedule,
144 /// Delete outdated after property.
145 OutdatedAfter
146}
147
148#[api(
149 protected: true,
150 input: {
151 properties: {
152 id: {
153 schema: JOB_ID_SCHEMA,
154 },
ffa403b5
DM
155 update: {
156 type: VerificationJobConfigUpdater,
157 flatten: true,
9b2bad7a
HL
158 },
159 delete: {
160 description: "List of properties to delete.",
161 type: Array,
162 optional: true,
163 items: {
164 type: DeletableProperty,
165 }
166 },
167 digest: {
168 optional: true,
169 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
170 },
171 },
172 },
b7ce2e57 173 access: {
35c80d69
FG
174 permission: &Permission::Anybody,
175 description: "Requires Datastore.Verify on job's datastore.",
b7ce2e57 176 },
9b2bad7a
HL
177)]
178/// Update verification job config.
367c0ff7 179#[allow(clippy::too_many_arguments)]
9b2bad7a
HL
180pub fn update_verification_job(
181 id: String,
ffa403b5 182 update: VerificationJobConfigUpdater,
9b2bad7a
HL
183 delete: Option<Vec<DeletableProperty>>,
184 digest: Option<String>,
35c80d69 185 rpcenv: &mut dyn RpcEnvironment,
9b2bad7a 186) -> Result<(), Error> {
35c80d69
FG
187 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
188 let user_info = CachedUserInfo::new()?;
9b2bad7a 189
802189f7 190 let _lock = verify::lock_config()?;
9b2bad7a
HL
191
192 // pass/compare digest
193 let (mut config, expected_digest) = verify::config()?;
194
195 if let Some(ref digest) = digest {
196 let digest = proxmox::tools::hex_to_digest(digest)?;
197 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
198 }
199
e3619d41 200 let mut data: VerificationJobConfig = config.lookup("verification", &id)?;
9b2bad7a 201
35c80d69
FG
202 // check existing store
203 user_info.check_privs(&auth_id, &["datastore", &data.store], PRIV_DATASTORE_VERIFY, true)?;
204
205 if let Some(delete) = delete {
9b2bad7a
HL
206 for delete_prop in delete {
207 match delete_prop {
208 DeletableProperty::IgnoreVerified => { data.ignore_verified = None; },
209 DeletableProperty::OutdatedAfter => { data.outdated_after = None; },
210 DeletableProperty::Comment => { data.comment = None; },
211 DeletableProperty::Schedule => { data.schedule = None; },
212 }
213 }
214 }
215
ffa403b5 216 if let Some(comment) = update.comment {
9b2bad7a
HL
217 let comment = comment.trim().to_string();
218 if comment.is_empty() {
219 data.comment = None;
220 } else {
221 data.comment = Some(comment);
222 }
223 }
224
ffa403b5 225 if let Some(store) = update.store {
35c80d69
FG
226 // check new store
227 user_info.check_privs(&auth_id, &["datastore", &store], PRIV_DATASTORE_VERIFY, true)?;
228 data.store = store;
229 }
230
9b2bad7a 231
ffa403b5
DM
232 if update.ignore_verified.is_some() { data.ignore_verified = update.ignore_verified; }
233 if update.outdated_after.is_some() { data.outdated_after = update.outdated_after; }
234 let schedule_changed = data.schedule != update.schedule;
235 if update.schedule.is_some() { data.schedule = update.schedule; }
9b2bad7a
HL
236
237 config.set_data(&id, "verification", &data)?;
238
239 verify::save_config(&config)?;
240
951fe0cb 241 if schedule_changed {
37a634f5 242 crate::server::jobstate::update_job_last_run_time("verificationjob", &id)?;
951fe0cb
DC
243 }
244
9b2bad7a
HL
245 Ok(())
246}
247
248#[api(
249 protected: true,
250 input: {
251 properties: {
252 id: {
253 schema: JOB_ID_SCHEMA,
254 },
255 digest: {
256 optional: true,
257 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
258 },
259 },
260 },
b7ce2e57 261 access: {
35c80d69
FG
262 permission: &Permission::Anybody,
263 description: "Requires Datastore.Verify on job's datastore.",
b7ce2e57 264 },
9b2bad7a
HL
265)]
266/// Remove a verification job configuration
35c80d69
FG
267pub fn delete_verification_job(
268 id: String,
269 digest: Option<String>,
270 rpcenv: &mut dyn RpcEnvironment,
271) -> Result<(), Error> {
272 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
273 let user_info = CachedUserInfo::new()?;
9b2bad7a 274
802189f7 275 let _lock = verify::lock_config()?;
9b2bad7a
HL
276
277 let (mut config, expected_digest) = verify::config()?;
278
e3619d41 279 let job: VerificationJobConfig = config.lookup("verification", &id)?;
35c80d69
FG
280 user_info.check_privs(&auth_id, &["datastore", &job.store], PRIV_DATASTORE_VERIFY, true)?;
281
9b2bad7a
HL
282 if let Some(ref digest) = digest {
283 let digest = proxmox::tools::hex_to_digest(digest)?;
284 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
285 }
286
287 match config.sections.get(&id) {
288 Some(_) => { config.sections.remove(&id); },
289 None => bail!("job '{}' does not exist.", id),
290 }
291
292 verify::save_config(&config)?;
293
1298618a 294 crate::server::jobstate::remove_state_file("verificationjob", &id)?;
9b2bad7a
HL
295
296 Ok(())
297}
298
299const ITEM_ROUTER: Router = Router::new()
300 .get(&API_METHOD_READ_VERIFICATION_JOB)
301 .put(&API_METHOD_UPDATE_VERIFICATION_JOB)
302 .delete(&API_METHOD_DELETE_VERIFICATION_JOB);
303
304pub const ROUTER: Router = Router::new()
305 .get(&API_METHOD_LIST_VERIFICATION_JOBS)
306 .post(&API_METHOD_CREATE_VERIFICATION_JOB)
1298618a 307 .match_all("id", &ITEM_ROUTER);