1 use anyhow
::{bail, Error}
;
3 use ::serde
::{Deserialize, Serialize}
;
6 use proxmox_router
::{Router, RpcEnvironment, Permission}
;
7 use proxmox_schema
::{api, param_bail}
;
10 Authid
, VerificationJobConfig
, VerificationJobConfigUpdater
, JOB_ID_SCHEMA
,
11 PROXMOX_CONFIG_DIGEST_SCHEMA
, PRIV_DATASTORE_AUDIT
, PRIV_DATASTORE_VERIFY
,
13 use pbs_config
::verify
;
15 use pbs_config
::CachedUserInfo
;
22 description
: "List configured jobs.",
24 items
: { type: VerificationJobConfig }
,
27 permission
: &Permission
::Anybody
,
28 description
: "Requires Datastore.Audit or Datastore.Verify on datastore.",
31 /// List all verification jobs
32 pub fn list_verification_jobs(
34 mut rpcenv
: &mut dyn RpcEnvironment
,
35 ) -> Result
<Vec
<VerificationJobConfig
>, Error
> {
36 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
37 let user_info
= CachedUserInfo
::new()?
;
39 let required_privs
= PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_VERIFY
;
41 let (config
, digest
) = verify
::config()?
;
43 let list
= config
.convert_to_typed_array("verification")?
;
45 let list
= list
.into_iter()
46 .filter(|job
: &VerificationJobConfig
| {
47 let privs
= user_info
.lookup_privs(&auth_id
, &["datastore", &job
.store
]);
49 privs
& required_privs
!= 00
52 rpcenv
["digest"] = hex
::encode(&digest
).into();
63 type: VerificationJobConfig
,
69 permission
: &Permission
::Anybody
,
70 description
: "Requires Datastore.Verify on job's datastore.",
73 /// Create a new verification job.
74 pub fn create_verification_job(
75 config
: VerificationJobConfig
,
76 rpcenv
: &mut dyn RpcEnvironment
77 ) -> Result
<(), Error
> {
78 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
79 let user_info
= CachedUserInfo
::new()?
;
81 user_info
.check_privs(&auth_id
, &["datastore", &config
.store
], PRIV_DATASTORE_VERIFY
, false)?
;
83 let _lock
= verify
::lock_config()?
;
85 let (mut section_config
, _digest
) = verify
::config()?
;
87 if section_config
.sections
.get(&config
.id
).is_some() {
88 param_bail
!("id", "job '{}' already exists.", config
.id
);
91 section_config
.set_data(&config
.id
, "verification", &config
)?
;
93 verify
::save_config(§ion_config
)?
;
95 crate::server
::jobstate
::create_state_file("verificationjob", &config
.id
)?
;
104 schema
: JOB_ID_SCHEMA
,
108 returns
: { type: VerificationJobConfig }
,
110 permission
: &Permission
::Anybody
,
111 description
: "Requires Datastore.Audit or Datastore.Verify on job's datastore.",
114 /// Read a verification job configuration.
115 pub fn read_verification_job(
117 mut rpcenv
: &mut dyn RpcEnvironment
,
118 ) -> Result
<VerificationJobConfig
, Error
> {
119 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
120 let user_info
= CachedUserInfo
::new()?
;
122 let (config
, digest
) = verify
::config()?
;
124 let verification_job
: VerificationJobConfig
= config
.lookup("verification", &id
)?
;
126 let required_privs
= PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_VERIFY
;
127 user_info
.check_privs(&auth_id
, &["datastore", &verification_job
.store
], required_privs
, true)?
;
129 rpcenv
["digest"] = hex
::encode(&digest
).into();
135 #[derive(Serialize, Deserialize)]
136 #[serde(rename_all="kebab-case")]
137 /// Deletable property name
138 pub enum DeletableProperty
{
139 /// Delete the ignore verified property.
141 /// Delete the comment property.
143 /// Delete the job schedule.
145 /// Delete outdated after property.
154 schema
: JOB_ID_SCHEMA
,
157 type: VerificationJobConfigUpdater
,
161 description
: "List of properties to delete.",
165 type: DeletableProperty
,
170 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
175 permission
: &Permission
::Anybody
,
176 description
: "Requires Datastore.Verify on job's datastore.",
179 /// Update verification job config.
180 #[allow(clippy::too_many_arguments)]
181 pub fn update_verification_job(
183 update
: VerificationJobConfigUpdater
,
184 delete
: Option
<Vec
<DeletableProperty
>>,
185 digest
: Option
<String
>,
186 rpcenv
: &mut dyn RpcEnvironment
,
187 ) -> Result
<(), Error
> {
188 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
189 let user_info
= CachedUserInfo
::new()?
;
191 let _lock
= verify
::lock_config()?
;
193 // pass/compare digest
194 let (mut config
, expected_digest
) = verify
::config()?
;
196 if let Some(ref digest
) = digest
{
197 let digest
= <[u8; 32]>::from_hex(digest
)?
;
198 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
201 let mut data
: VerificationJobConfig
= config
.lookup("verification", &id
)?
;
203 // check existing store
204 user_info
.check_privs(&auth_id
, &["datastore", &data
.store
], PRIV_DATASTORE_VERIFY
, true)?
;
206 if let Some(delete
) = delete
{
207 for delete_prop
in delete
{
209 DeletableProperty
::IgnoreVerified
=> { data.ignore_verified = None; }
,
210 DeletableProperty
::OutdatedAfter
=> { data.outdated_after = None; }
,
211 DeletableProperty
::Comment
=> { data.comment = None; }
,
212 DeletableProperty
::Schedule
=> { data.schedule = None; }
,
217 if let Some(comment
) = update
.comment
{
218 let comment
= comment
.trim().to_string();
219 if comment
.is_empty() {
222 data
.comment
= Some(comment
);
226 if let Some(store
) = update
.store
{
228 user_info
.check_privs(&auth_id
, &["datastore", &store
], PRIV_DATASTORE_VERIFY
, true)?
;
233 if update
.ignore_verified
.is_some() { data.ignore_verified = update.ignore_verified; }
234 if update
.outdated_after
.is_some() { data.outdated_after = update.outdated_after; }
235 let schedule_changed
= data
.schedule
!= update
.schedule
;
236 if update
.schedule
.is_some() { data.schedule = update.schedule; }
238 config
.set_data(&id
, "verification", &data
)?
;
240 verify
::save_config(&config
)?
;
242 if schedule_changed
{
243 crate::server
::jobstate
::update_job_last_run_time("verificationjob", &id
)?
;
254 schema
: JOB_ID_SCHEMA
,
258 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
263 permission
: &Permission
::Anybody
,
264 description
: "Requires Datastore.Verify on job's datastore.",
267 /// Remove a verification job configuration
268 pub fn delete_verification_job(
270 digest
: Option
<String
>,
271 rpcenv
: &mut dyn RpcEnvironment
,
272 ) -> Result
<(), Error
> {
273 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
274 let user_info
= CachedUserInfo
::new()?
;
276 let _lock
= verify
::lock_config()?
;
278 let (mut config
, expected_digest
) = verify
::config()?
;
280 let job
: VerificationJobConfig
= config
.lookup("verification", &id
)?
;
281 user_info
.check_privs(&auth_id
, &["datastore", &job
.store
], PRIV_DATASTORE_VERIFY
, true)?
;
283 if let Some(ref digest
) = digest
{
284 let digest
= <[u8; 32]>::from_hex(digest
)?
;
285 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
288 match config
.sections
.get(&id
) {
289 Some(_
) => { config.sections.remove(&id); }
,
290 None
=> bail
!("job '{}' does not exist.", id
),
293 verify
::save_config(&config
)?
;
295 crate::server
::jobstate
::remove_state_file("verificationjob", &id
)?
;
300 const ITEM_ROUTER
: Router
= Router
::new()
301 .get(&API_METHOD_READ_VERIFICATION_JOB
)
302 .put(&API_METHOD_UPDATE_VERIFICATION_JOB
)
303 .delete(&API_METHOD_DELETE_VERIFICATION_JOB
);
305 pub const ROUTER
: Router
= Router
::new()
306 .get(&API_METHOD_LIST_VERIFICATION_JOBS
)
307 .post(&API_METHOD_CREATE_VERIFICATION_JOB
)
308 .match_all("id", &ITEM_ROUTER
);