1 use ::serde
::{Deserialize, Serialize}
;
6 use proxmox_router
::{http_bail, Permission, Router, RpcEnvironment}
;
7 use proxmox_schema
::{api, param_bail}
;
10 Authid
, VerificationJobConfig
, VerificationJobConfigUpdater
, JOB_ID_SCHEMA
,
11 PRIV_DATASTORE_AUDIT
, PRIV_DATASTORE_VERIFY
, PROXMOX_CONFIG_DIGEST_SCHEMA
,
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 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")?
;
47 .filter(|job
: &VerificationJobConfig
| {
48 let privs
= user_info
.lookup_privs(&auth_id
, &job
.store_with_ns().acl_path());
50 privs
& required_privs
!= 00
54 rpcenv
["digest"] = hex
::encode(&digest
).into();
64 type: VerificationJobConfig
,
70 permission
: &Permission
::Anybody
,
71 description
: "Requires Datastore.Verify on job's datastore.",
74 /// Create a new verification job.
75 pub fn create_verification_job(
76 config
: VerificationJobConfig
,
77 rpcenv
: &mut dyn RpcEnvironment
,
78 ) -> Result
<(), Error
> {
79 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
80 let user_info
= CachedUserInfo
::new()?
;
82 user_info
.check_privs(
84 &config
.store_with_ns().acl_path(),
85 PRIV_DATASTORE_VERIFY
,
89 let _lock
= verify
::lock_config()?
;
91 let (mut section_config
, _digest
) = verify
::config()?
;
93 if section_config
.sections
.get(&config
.id
).is_some() {
94 param_bail
!("id", "job '{}' already exists.", config
.id
);
97 section_config
.set_data(&config
.id
, "verification", &config
)?
;
99 verify
::save_config(§ion_config
)?
;
101 crate::server
::jobstate
::create_state_file("verificationjob", &config
.id
)?
;
110 schema
: JOB_ID_SCHEMA
,
114 returns
: { type: VerificationJobConfig }
,
116 permission
: &Permission
::Anybody
,
117 description
: "Requires Datastore.Audit or Datastore.Verify on job's datastore.",
120 /// Read a verification job configuration.
121 pub fn read_verification_job(
123 rpcenv
: &mut dyn RpcEnvironment
,
124 ) -> Result
<VerificationJobConfig
, Error
> {
125 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
126 let user_info
= CachedUserInfo
::new()?
;
128 let (config
, digest
) = verify
::config()?
;
130 let verification_job
: VerificationJobConfig
= config
.lookup("verification", &id
)?
;
132 let required_privs
= PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_VERIFY
;
133 user_info
.check_privs(
135 &verification_job
.store_with_ns().acl_path(),
140 rpcenv
["digest"] = hex
::encode(&digest
).into();
146 #[derive(Serialize, Deserialize)]
147 #[serde(rename_all = "kebab-case")]
148 /// Deletable property name
149 pub enum DeletableProperty
{
150 /// Delete the ignore verified property.
152 /// Delete the comment property.
154 /// Delete the job schedule.
156 /// Delete outdated after property.
158 /// Delete namespace property, defaulting to root namespace then.
160 /// Delete max-depth property, defaulting to full recursion again
169 schema
: JOB_ID_SCHEMA
,
172 type: VerificationJobConfigUpdater
,
176 description
: "List of properties to delete.",
180 type: DeletableProperty
,
185 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
190 permission
: &Permission
::Anybody
,
191 description
: "Requires Datastore.Verify on job's datastore.",
194 /// Update verification job config.
195 #[allow(clippy::too_many_arguments)]
196 pub fn update_verification_job(
198 update
: VerificationJobConfigUpdater
,
199 delete
: Option
<Vec
<DeletableProperty
>>,
200 digest
: Option
<String
>,
201 rpcenv
: &mut dyn RpcEnvironment
,
202 ) -> Result
<(), Error
> {
203 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
204 let user_info
= CachedUserInfo
::new()?
;
206 let _lock
= verify
::lock_config()?
;
208 // pass/compare digest
209 let (mut config
, expected_digest
) = verify
::config()?
;
211 if let Some(ref digest
) = digest
{
212 let digest
= <[u8; 32]>::from_hex(digest
)?
;
213 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
216 let mut data
: VerificationJobConfig
= config
.lookup("verification", &id
)?
;
218 // check existing store and NS
219 user_info
.check_privs(
221 &data
.store_with_ns().acl_path(),
222 PRIV_DATASTORE_VERIFY
,
226 if let Some(delete
) = delete
{
227 for delete_prop
in delete
{
229 DeletableProperty
::IgnoreVerified
=> {
230 data
.ignore_verified
= None
;
232 DeletableProperty
::OutdatedAfter
=> {
233 data
.outdated_after
= None
;
235 DeletableProperty
::Comment
=> {
238 DeletableProperty
::Schedule
=> {
239 data
.schedule
= None
;
241 DeletableProperty
::Ns
=> {
244 DeletableProperty
::MaxDepth
=> {
245 data
.max_depth
= None
;
251 if let Some(comment
) = update
.comment
{
252 let comment
= comment
.trim().to_string();
253 if comment
.is_empty() {
256 data
.comment
= Some(comment
);
260 if let Some(store
) = update
.store
{
264 if update
.ignore_verified
.is_some() {
265 data
.ignore_verified
= update
.ignore_verified
;
267 if update
.outdated_after
.is_some() {
268 data
.outdated_after
= update
.outdated_after
;
270 let schedule_changed
= data
.schedule
!= update
.schedule
;
271 if update
.schedule
.is_some() {
272 data
.schedule
= update
.schedule
;
274 if let Some(ns
) = update
.ns
{
279 if let Some(max_depth
) = update
.max_depth
{
280 if max_depth
<= pbs_api_types
::MAX_NAMESPACE_DEPTH
{
281 data
.max_depth
= Some(max_depth
);
285 // check new store and NS
286 user_info
.check_privs(
288 &data
.store_with_ns().acl_path(),
289 PRIV_DATASTORE_VERIFY
,
293 config
.set_data(&id
, "verification", &data
)?
;
295 verify
::save_config(&config
)?
;
297 if schedule_changed
{
298 crate::server
::jobstate
::update_job_last_run_time("verificationjob", &id
)?
;
309 schema
: JOB_ID_SCHEMA
,
313 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
318 permission
: &Permission
::Anybody
,
319 description
: "Requires Datastore.Verify on job's datastore.",
322 /// Remove a verification job configuration
323 pub fn delete_verification_job(
325 digest
: Option
<String
>,
326 rpcenv
: &mut dyn RpcEnvironment
,
327 ) -> Result
<(), Error
> {
328 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
329 let user_info
= CachedUserInfo
::new()?
;
331 let _lock
= verify
::lock_config()?
;
333 let (mut config
, expected_digest
) = verify
::config()?
;
335 let job
: VerificationJobConfig
= config
.lookup("verification", &id
)?
;
336 user_info
.check_privs(
338 &job
.store_with_ns().acl_path(),
339 PRIV_DATASTORE_VERIFY
,
343 if let Some(ref digest
) = digest
{
344 let digest
= <[u8; 32]>::from_hex(digest
)?
;
345 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
348 match config
.sections
.get(&id
) {
350 config
.sections
.remove(&id
);
352 None
=> http_bail
!(NOT_FOUND
, "job '{}' does not exist.", id
),
355 verify
::save_config(&config
)?
;
357 crate::server
::jobstate
::remove_state_file("verificationjob", &id
)?
;
362 const ITEM_ROUTER
: Router
= Router
::new()
363 .get(&API_METHOD_READ_VERIFICATION_JOB
)
364 .put(&API_METHOD_UPDATE_VERIFICATION_JOB
)
365 .delete(&API_METHOD_DELETE_VERIFICATION_JOB
);
367 pub const ROUTER
: Router
= Router
::new()
368 .get(&API_METHOD_LIST_VERIFICATION_JOBS
)
369 .post(&API_METHOD_CREATE_VERIFICATION_JOB
)
370 .match_all("id", &ITEM_ROUTER
);