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