1 use anyhow
::{bail, Error}
;
3 use ::serde
::{Deserialize, Serialize}
;
5 use proxmox
::api
::{api, Permission, Router, RpcEnvironment}
;
8 Authid
, VerificationJobConfig
, VerificationJobConfigUpdater
, JOB_ID_SCHEMA
,
9 PROXMOX_CONFIG_DIGEST_SCHEMA
,
11 use pbs_config
::verify
;
13 use crate::config
::acl
::{
15 PRIV_DATASTORE_VERIFY
,
18 use crate::config
::cached_user_info
::CachedUserInfo
;
25 description
: "List configured jobs.",
27 items
: { type: VerificationJobConfig }
,
30 permission
: &Permission
::Anybody
,
31 description
: "Requires Datastore.Audit or Datastore.Verify on datastore.",
34 /// List all verification jobs
35 pub fn list_verification_jobs(
37 mut rpcenv
: &mut dyn RpcEnvironment
,
38 ) -> Result
<Vec
<VerificationJobConfig
>, Error
> {
39 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
40 let user_info
= CachedUserInfo
::new()?
;
42 let required_privs
= PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_VERIFY
;
44 let (config
, digest
) = verify
::config()?
;
46 let list
= config
.convert_to_typed_array("verification")?
;
48 let list
= list
.into_iter()
49 .filter(|job
: &VerificationJobConfig
| {
50 let privs
= user_info
.lookup_privs(&auth_id
, &["datastore", &job
.store
]);
52 privs
& required_privs
!= 00
55 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
66 type: VerificationJobConfig
,
72 permission
: &Permission
::Anybody
,
73 description
: "Requires Datastore.Verify on job's datastore.",
76 /// Create a new verification job.
77 pub fn create_verification_job(
78 config
: VerificationJobConfig
,
79 rpcenv
: &mut dyn RpcEnvironment
80 ) -> Result
<(), Error
> {
81 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
82 let user_info
= CachedUserInfo
::new()?
;
84 user_info
.check_privs(&auth_id
, &["datastore", &config
.store
], PRIV_DATASTORE_VERIFY
, false)?
;
86 let _lock
= verify
::lock_config()?
;
88 let (mut section_config
, _digest
) = verify
::config()?
;
90 if section_config
.sections
.get(&config
.id
).is_some() {
91 bail
!("job '{}' already exists.", config
.id
);
94 section_config
.set_data(&config
.id
, "verification", &config
)?
;
96 verify
::save_config(§ion_config
)?
;
98 crate::server
::jobstate
::create_state_file("verificationjob", &config
.id
)?
;
107 schema
: JOB_ID_SCHEMA
,
111 returns
: { type: VerificationJobConfig }
,
113 permission
: &Permission
::Anybody
,
114 description
: "Requires Datastore.Audit or Datastore.Verify on job's datastore.",
117 /// Read a verification job configuration.
118 pub fn read_verification_job(
120 mut rpcenv
: &mut dyn RpcEnvironment
,
121 ) -> Result
<VerificationJobConfig
, Error
> {
122 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
123 let user_info
= CachedUserInfo
::new()?
;
125 let (config
, digest
) = verify
::config()?
;
127 let verification_job
: VerificationJobConfig
= config
.lookup("verification", &id
)?
;
129 let required_privs
= PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_VERIFY
;
130 user_info
.check_privs(&auth_id
, &["datastore", &verification_job
.store
], required_privs
, true)?
;
132 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
138 #[derive(Serialize, Deserialize)]
139 #[serde(rename_all="kebab-case")]
140 /// Deletable property name
141 pub enum DeletableProperty
{
142 /// Delete the ignore verified property.
144 /// Delete the comment property.
146 /// Delete the job schedule.
148 /// Delete outdated after property.
157 schema
: JOB_ID_SCHEMA
,
160 type: VerificationJobConfigUpdater
,
164 description
: "List of properties to delete.",
168 type: DeletableProperty
,
173 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
178 permission
: &Permission
::Anybody
,
179 description
: "Requires Datastore.Verify on job's datastore.",
182 /// Update verification job config.
183 #[allow(clippy::too_many_arguments)]
184 pub fn update_verification_job(
186 update
: VerificationJobConfigUpdater
,
187 delete
: Option
<Vec
<DeletableProperty
>>,
188 digest
: Option
<String
>,
189 rpcenv
: &mut dyn RpcEnvironment
,
190 ) -> Result
<(), Error
> {
191 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
192 let user_info
= CachedUserInfo
::new()?
;
194 let _lock
= verify
::lock_config()?
;
196 // pass/compare digest
197 let (mut config
, expected_digest
) = verify
::config()?
;
199 if let Some(ref digest
) = digest
{
200 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
201 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
204 let mut data
: VerificationJobConfig
= config
.lookup("verification", &id
)?
;
206 // check existing store
207 user_info
.check_privs(&auth_id
, &["datastore", &data
.store
], PRIV_DATASTORE_VERIFY
, true)?
;
209 if let Some(delete
) = delete
{
210 for delete_prop
in delete
{
212 DeletableProperty
::IgnoreVerified
=> { data.ignore_verified = None; }
,
213 DeletableProperty
::OutdatedAfter
=> { data.outdated_after = None; }
,
214 DeletableProperty
::Comment
=> { data.comment = None; }
,
215 DeletableProperty
::Schedule
=> { data.schedule = None; }
,
220 if let Some(comment
) = update
.comment
{
221 let comment
= comment
.trim().to_string();
222 if comment
.is_empty() {
225 data
.comment
= Some(comment
);
229 if let Some(store
) = update
.store
{
231 user_info
.check_privs(&auth_id
, &["datastore", &store
], PRIV_DATASTORE_VERIFY
, true)?
;
236 if update
.ignore_verified
.is_some() { data.ignore_verified = update.ignore_verified; }
237 if update
.outdated_after
.is_some() { data.outdated_after = update.outdated_after; }
238 let schedule_changed
= data
.schedule
!= update
.schedule
;
239 if update
.schedule
.is_some() { data.schedule = update.schedule; }
241 config
.set_data(&id
, "verification", &data
)?
;
243 verify
::save_config(&config
)?
;
245 if schedule_changed
{
246 crate::server
::jobstate
::update_job_last_run_time("verificationjob", &id
)?
;
257 schema
: JOB_ID_SCHEMA
,
261 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
266 permission
: &Permission
::Anybody
,
267 description
: "Requires Datastore.Verify on job's datastore.",
270 /// Remove a verification job configuration
271 pub fn delete_verification_job(
273 digest
: Option
<String
>,
274 rpcenv
: &mut dyn RpcEnvironment
,
275 ) -> Result
<(), Error
> {
276 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
277 let user_info
= CachedUserInfo
::new()?
;
279 let _lock
= verify
::lock_config()?
;
281 let (mut config
, expected_digest
) = verify
::config()?
;
283 let job
: VerificationJobConfig
= config
.lookup("verification", &id
)?
;
284 user_info
.check_privs(&auth_id
, &["datastore", &job
.store
], PRIV_DATASTORE_VERIFY
, true)?
;
286 if let Some(ref digest
) = digest
{
287 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
288 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
291 match config
.sections
.get(&id
) {
292 Some(_
) => { config.sections.remove(&id); }
,
293 None
=> bail
!("job '{}' does not exist.", id
),
296 verify
::save_config(&config
)?
;
298 crate::server
::jobstate
::remove_state_file("verificationjob", &id
)?
;
303 const ITEM_ROUTER
: Router
= Router
::new()
304 .get(&API_METHOD_READ_VERIFICATION_JOB
)
305 .put(&API_METHOD_UPDATE_VERIFICATION_JOB
)
306 .delete(&API_METHOD_DELETE_VERIFICATION_JOB
);
308 pub const ROUTER
: Router
= Router
::new()
309 .get(&API_METHOD_LIST_VERIFICATION_JOBS
)
310 .post(&API_METHOD_CREATE_VERIFICATION_JOB
)
311 .match_all("id", &ITEM_ROUTER
);