1 use anyhow
::{bail, Error}
;
3 use ::serde
::{Deserialize, Serialize}
;
5 use proxmox
::api
::{api, Permission, Router, RpcEnvironment}
;
6 use proxmox
::tools
::fs
::open_file_locked
;
8 use crate::api2
::types
::*;
10 use crate::config
::acl
::{
12 PRIV_DATASTORE_VERIFY
,
15 use crate::config
::cached_user_info
::CachedUserInfo
;
17 use crate::config
::verify
::{self, VerificationJobConfig}
;
24 description
: "List configured jobs.",
26 items
: { type: verify::VerificationJobConfig }
,
29 permission
: &Permission
::Anybody
,
30 description
: "Requires Datastore.Audit or Datastore.Verify on datastore.",
33 /// List all verification jobs
34 pub fn list_verification_jobs(
36 mut rpcenv
: &mut dyn RpcEnvironment
,
37 ) -> Result
<Vec
<VerificationJobConfig
>, Error
> {
38 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
39 let user_info
= CachedUserInfo
::new()?
;
41 let required_privs
= PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_VERIFY
;
43 let (config
, digest
) = verify
::config()?
;
45 let list
= config
.convert_to_typed_array("verification")?
;
47 let list
= list
.into_iter()
48 .filter(|job
: &VerificationJobConfig
| {
49 let privs
= user_info
.lookup_privs(&auth_id
, &["datastore", &job
.store
]);
51 privs
& required_privs
!= 00
54 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
65 schema
: JOB_ID_SCHEMA
,
68 schema
: DATASTORE_SCHEMA
,
72 schema
: IGNORE_VERIFIED_BACKUPS_SCHEMA
,
76 schema
: VERIFICATION_OUTDATED_AFTER_SCHEMA
,
80 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
84 schema
: VERIFICATION_SCHEDULE_SCHEMA
,
89 permission
: &Permission
::Anybody
,
90 description
: "Requires Datastore.Verify on job's datastore.",
93 /// Create a new verification job.
94 pub fn create_verification_job(
96 rpcenv
: &mut dyn RpcEnvironment
97 ) -> Result
<(), Error
> {
98 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
99 let user_info
= CachedUserInfo
::new()?
;
101 let verification_job
: verify
::VerificationJobConfig
= serde_json
::from_value(param
)?
;
103 user_info
.check_privs(&auth_id
, &["datastore", &verification_job
.store
], PRIV_DATASTORE_VERIFY
, false)?
;
105 let _lock
= open_file_locked(verify
::VERIFICATION_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0), true)?
;
107 let (mut config
, _digest
) = verify
::config()?
;
109 if config
.sections
.get(&verification_job
.id
).is_some() {
110 bail
!("job '{}' already exists.", verification_job
.id
);
113 config
.set_data(&verification_job
.id
, "verification", &verification_job
)?
;
115 verify
::save_config(&config
)?
;
117 crate::server
::jobstate
::create_state_file("verificationjob", &verification_job
.id
)?
;
126 schema
: JOB_ID_SCHEMA
,
130 returns
: { type: verify::VerificationJobConfig }
,
132 permission
: &Permission
::Anybody
,
133 description
: "Requires Datastore.Audit or Datastore.Verify on job's datastore.",
136 /// Read a verification job configuration.
137 pub fn read_verification_job(
139 mut rpcenv
: &mut dyn RpcEnvironment
,
140 ) -> Result
<VerificationJobConfig
, Error
> {
141 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
142 let user_info
= CachedUserInfo
::new()?
;
144 let (config
, digest
) = verify
::config()?
;
146 let verification_job
: verify
::VerificationJobConfig
= config
.lookup("verification", &id
)?
;
148 let required_privs
= PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_VERIFY
;
149 user_info
.check_privs(&auth_id
, &["datastore", &verification_job
.store
], required_privs
, true)?
;
151 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
157 #[derive(Serialize, Deserialize)]
158 #[serde(rename_all="kebab-case")]
159 /// Deletable property name
160 pub enum DeletableProperty
{
161 /// Delete the ignore verified property.
163 /// Delete the comment property.
165 /// Delete the job schedule.
167 /// Delete outdated after property.
176 schema
: JOB_ID_SCHEMA
,
180 schema
: DATASTORE_SCHEMA
,
184 schema
: IGNORE_VERIFIED_BACKUPS_SCHEMA
,
188 schema
: VERIFICATION_OUTDATED_AFTER_SCHEMA
,
192 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
196 schema
: VERIFICATION_SCHEDULE_SCHEMA
,
199 description
: "List of properties to delete.",
203 type: DeletableProperty
,
208 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
213 permission
: &Permission
::Anybody
,
214 description
: "Requires Datastore.Verify on job's datastore.",
217 /// Update verification job config.
218 #[allow(clippy::too_many_arguments)]
219 pub fn update_verification_job(
221 store
: Option
<String
>,
222 ignore_verified
: Option
<bool
>,
223 outdated_after
: Option
<i64>,
224 comment
: Option
<String
>,
225 schedule
: Option
<String
>,
226 delete
: Option
<Vec
<DeletableProperty
>>,
227 digest
: Option
<String
>,
228 rpcenv
: &mut dyn RpcEnvironment
,
229 ) -> Result
<(), Error
> {
230 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
231 let user_info
= CachedUserInfo
::new()?
;
233 let _lock
= open_file_locked(verify
::VERIFICATION_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0), true)?
;
235 // pass/compare digest
236 let (mut config
, expected_digest
) = verify
::config()?
;
238 if let Some(ref digest
) = digest
{
239 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
240 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
243 let mut data
: verify
::VerificationJobConfig
= config
.lookup("verification", &id
)?
;
245 // check existing store
246 user_info
.check_privs(&auth_id
, &["datastore", &data
.store
], PRIV_DATASTORE_VERIFY
, true)?
;
248 if let Some(delete
) = delete
{
249 for delete_prop
in delete
{
251 DeletableProperty
::IgnoreVerified
=> { data.ignore_verified = None; }
,
252 DeletableProperty
::OutdatedAfter
=> { data.outdated_after = None; }
,
253 DeletableProperty
::Comment
=> { data.comment = None; }
,
254 DeletableProperty
::Schedule
=> { data.schedule = None; }
,
259 if let Some(comment
) = comment
{
260 let comment
= comment
.trim().to_string();
261 if comment
.is_empty() {
264 data
.comment
= Some(comment
);
268 if let Some(store
) = store
{
270 user_info
.check_privs(&auth_id
, &["datastore", &store
], PRIV_DATASTORE_VERIFY
, true)?
;
275 if ignore_verified
.is_some() { data.ignore_verified = ignore_verified; }
276 if outdated_after
.is_some() { data.outdated_after = outdated_after; }
277 let schedule_changed
= data
.schedule
!= schedule
;
278 if schedule
.is_some() { data.schedule = schedule; }
280 config
.set_data(&id
, "verification", &data
)?
;
282 verify
::save_config(&config
)?
;
284 if schedule_changed
{
285 crate::server
::jobstate
::try_update_state_file("verificationjob", &id
)?
;
296 schema
: JOB_ID_SCHEMA
,
300 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
305 permission
: &Permission
::Anybody
,
306 description
: "Requires Datastore.Verify on job's datastore.",
309 /// Remove a verification job configuration
310 pub fn delete_verification_job(
312 digest
: Option
<String
>,
313 rpcenv
: &mut dyn RpcEnvironment
,
314 ) -> Result
<(), Error
> {
315 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
316 let user_info
= CachedUserInfo
::new()?
;
318 let _lock
= open_file_locked(verify
::VERIFICATION_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0), true)?
;
320 let (mut config
, expected_digest
) = verify
::config()?
;
322 let job
: verify
::VerificationJobConfig
= config
.lookup("verification", &id
)?
;
323 user_info
.check_privs(&auth_id
, &["datastore", &job
.store
], PRIV_DATASTORE_VERIFY
, true)?
;
325 if let Some(ref digest
) = digest
{
326 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
327 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
330 match config
.sections
.get(&id
) {
331 Some(_
) => { config.sections.remove(&id); }
,
332 None
=> bail
!("job '{}' does not exist.", id
),
335 verify
::save_config(&config
)?
;
337 crate::server
::jobstate
::remove_state_file("verificationjob", &id
)?
;
342 const ITEM_ROUTER
: Router
= Router
::new()
343 .get(&API_METHOD_READ_VERIFICATION_JOB
)
344 .put(&API_METHOD_UPDATE_VERIFICATION_JOB
)
345 .delete(&API_METHOD_DELETE_VERIFICATION_JOB
);
347 pub const ROUTER
: Router
= Router
::new()
348 .get(&API_METHOD_LIST_VERIFICATION_JOBS
)
349 .post(&API_METHOD_CREATE_VERIFICATION_JOB
)
350 .match_all("id", &ITEM_ROUTER
);