From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 485A56072B for ; Thu, 8 Oct 2020 10:23:28 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 3D6D0C765 for ; Thu, 8 Oct 2020 10:22:58 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [212.186.127.180]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id E5008C548 for ; Thu, 8 Oct 2020 10:22:56 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id B095345C48 for ; Thu, 8 Oct 2020 10:22:56 +0200 (CEST) Date: Thu, 8 Oct 2020 10:22:55 +0200 From: Wolfgang Bumiller To: Hannes Laimer Cc: pbs-devel@lists.proxmox.com Message-ID: <20201008082255.x73lsqkt6r7payt4@olga.proxmox.com> References: <20201007090324.42928-1-h.laimer@proxmox.com> <20201007090324.42928-4-h.laimer@proxmox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20201007090324.42928-4-h.laimer@proxmox.com> User-Agent: NeoMutt/20180716 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.018 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [verify.rs, config.rs, data.store] Subject: Re: [pbs-devel] [PATCH v2 proxmox-backup 03/15] api2: add verify job config endpoint X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 08 Oct 2020 08:23:28 -0000 On Wed, Oct 07, 2020 at 11:03:12AM +0200, Hannes Laimer wrote: > Signed-off-by: Hannes Laimer > --- > src/api2/config.rs | 2 + > src/api2/config/verify.rs | 275 ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 277 insertions(+) > create mode 100644 src/api2/config/verify.rs > > diff --git a/src/api2/config.rs b/src/api2/config.rs > index be7397c8..7a5129c7 100644 > --- a/src/api2/config.rs > +++ b/src/api2/config.rs > @@ -4,11 +4,13 @@ use proxmox::list_subdirs_api_method; > pub mod datastore; > pub mod remote; > pub mod sync; > +pub mod verify; > > const SUBDIRS: SubdirMap = &[ > ("datastore", &datastore::ROUTER), > ("remote", &remote::ROUTER), > ("sync", &sync::ROUTER), > + ("verify", &verify::ROUTER) > ]; > > pub const ROUTER: Router = Router::new() > diff --git a/src/api2/config/verify.rs b/src/api2/config/verify.rs > new file mode 100644 > index 00000000..9897aaf9 > --- /dev/null > +++ b/src/api2/config/verify.rs > @@ -0,0 +1,275 @@ > +use anyhow::{bail, Error}; > +use serde_json::Value; > +use ::serde::{Deserialize, Serialize}; > + > +use proxmox::api::{api, Router, RpcEnvironment}; > +use proxmox::tools::fs::open_file_locked; > + > +use crate::api2::types::*; > +use crate::config::verify::{self, VerifyJobConfig}; > + > +#[api( > + input: { > + properties: {}, > + }, > + returns: { > + description: "List configured jobs.", > + type: Array, > + items: { type: verify::VerifyJobConfig }, > + }, > +)] > +/// List all verify jobs > +pub fn list_verify_jobs( > + _param: Value, > + mut rpcenv: &mut dyn RpcEnvironment, > +) -> Result, Error> { > + > + let (config, digest) = verify::config()?; > + > + let list = config.convert_to_typed_array("verify")?; > + > + rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into(); > + > + Ok(list) > +} > + > + > +#[api( > + protected: true, > + input: { > + properties: { > + id: { > + schema: JOB_ID_SCHEMA, > + }, > + store: { > + schema: DATASTORE_SCHEMA, > + }, > + "ignore-verified": { > + optional: true, > + schema: IGNORE_VERIFIED_BACKUPS_SCHEMA, > + }, > + "outdated-after": { > + optional: true, > + schema: VERIFICATION_OUTDATED_AFTER_SCHEMA, > + }, > + comment: { > + optional: true, > + schema: SINGLE_LINE_COMMENT_SCHEMA, > + }, > + schedule: { > + optional: true, > + schema: VERIFY_SCHEDULE_SCHEMA, > + }, > + } > + } > +)] > +/// Create a new verify job. > +pub fn create_verify_job(param: Value) -> Result<(), Error> { > + > + let _lock = open_file_locked(verify::VERIFY_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?; > + > + let verify_job: verify::VerifyJobConfig = serde_json::from_value(param.clone())?; > + > + let (mut config, _digest) = verify::config()?; > + > + if let Some(_) = config.sections.get(&verify_job.id) { > + bail!("job '{}' already exists.", verify_job.id); > + } > + > + config.set_data(&verify_job.id, "verify", &verify_job)?; > + > + verify::save_config(&config)?; > + > + crate::config::jobstate::create_state_file("verifyjob", &verify_job.id)?; > + > + Ok(()) > +} > + > +#[api( > + input: { > + properties: { > + id: { > + schema: JOB_ID_SCHEMA, > + }, > + }, > + }, > + returns: { > + description: "The verify job configuration.", > + type: verify::VerifyJobConfig, > + }, > +)] > +/// Read a verify job configuration. > +pub fn read_verify_job( > + id: String, > + mut rpcenv: &mut dyn RpcEnvironment, > +) -> Result { > + let (config, digest) = verify::config()?; > + > + let verify_job = config.lookup("verify", &id)?; > + rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into(); > + > + Ok(verify_job) > +} > + > +#[api()] > +#[derive(Serialize, Deserialize)] > +#[serde(rename_all="kebab-case")] > +#[allow(non_camel_case_types)] You already `rename-all`, please drop the non-camel-case-types and just use standard style. > +/// Deletable property name > +pub enum DeletableProperty { > + /// Delete ignore verified > + ignore_verified, > + /// Delete the comment property. > + comment, > + /// Delete the job schedule. > + schedule, > + /// Delete outdated_after. > + outdated_after > +} > + > +#[api( > + protected: true, > + input: { > + properties: { > + id: { > + schema: JOB_ID_SCHEMA, > + }, > + store: { > + optional: true, > + schema: DATASTORE_SCHEMA, > + }, > + "ignore-verified": { > + optional: true, > + schema: IGNORE_VERIFIED_BACKUPS_SCHEMA, > + }, > + "outdated-after": { > + optional: true, > + schema: VERIFICATION_OUTDATED_AFTER_SCHEMA, > + }, > + comment: { > + optional: true, > + schema: SINGLE_LINE_COMMENT_SCHEMA, > + }, > + schedule: { > + optional: true, > + schema: VERIFY_SCHEDULE_SCHEMA, > + }, ^ This is the part that needs actual fixing in the schema, because this is where all the properties become optional. (That wouldn't striclty be necessary, though, I mean most of the time we have the complete data available already anyway before doing the call...) But before this can be fixed in the `#[api]` macro it needs to be fixed in the schema code itself. > + delete: { > + description: "List of properties to delete.", > + type: Array, > + optional: true, > + items: { > + type: DeletableProperty, > + } > + }, > + digest: { > + optional: true, > + schema: PROXMOX_CONFIG_DIGEST_SCHEMA, > + }, > + }, > + }, > +)] > +/// Update verify job config. > +pub fn update_verify_job( > + id: String, > + store: Option, > + ignore_verified: Option, > + outdated_after: Option, > + comment: Option, > + schedule: Option, > + delete: Option>, > + digest: Option, > +) -> Result<(), Error> { > + > + let _lock = open_file_locked(verify::VERIFY_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?; > + > + // pass/compare digest > + let (mut config, expected_digest) = verify::config()?; > + > + if let Some(ref digest) = digest { > + let digest = proxmox::tools::hex_to_digest(digest)?; > + crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?; > + } > + > + let mut data: verify::VerifyJobConfig = config.lookup("verify", &id)?; > + > + if let Some(delete) = delete { > + for delete_prop in delete { > + match delete_prop { > + DeletableProperty::ignore_verified => { data.ignore_verified = None; }, > + DeletableProperty::outdated_after => { data.outdated_after = None; }, > + DeletableProperty::comment => { data.comment = None; }, > + DeletableProperty::schedule => { data.schedule = None; }, > + } > + } > + } > + > + if let Some(comment) = comment { > + let comment = comment.trim().to_string(); > + if comment.is_empty() { > + data.comment = None; > + } else { > + data.comment = Some(comment); > + } > + } > + > + if let Some(store) = store { data.store = store; } > + > + if ignore_verified.is_some() { data.ignore_verified = ignore_verified; } > + if outdated_after.is_some() { data.outdated_after = outdated_after; } > + if schedule.is_some() { data.schedule = schedule; } > + > + config.set_data(&id, "verify", &data)?; > + > + verify::save_config(&config)?; > + > + Ok(()) > +} > + > +#[api( > + protected: true, > + input: { > + properties: { > + id: { > + schema: JOB_ID_SCHEMA, > + }, > + digest: { > + optional: true, > + schema: PROXMOX_CONFIG_DIGEST_SCHEMA, > + }, > + }, > + }, > +)] > +/// Remove a verify job configuration > +pub fn delete_verify_job(id: String, digest: Option) -> Result<(), Error> { > + > + let _lock = open_file_locked(verify::VERIFY_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?; > + > + let (mut config, expected_digest) = verify::config()?; > + > + if let Some(ref digest) = digest { > + let digest = proxmox::tools::hex_to_digest(digest)?; > + crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?; > + } > + > + match config.sections.get(&id) { > + Some(_) => { config.sections.remove(&id); }, > + None => bail!("job '{}' does not exist.", id), > + } > + > + verify::save_config(&config)?; > + > + crate::config::jobstate::remove_state_file("verifyjob", &id)?; > + > + Ok(()) > +} > + > +const ITEM_ROUTER: Router = Router::new() > + .get(&API_METHOD_READ_VERIFY_JOB) > + .put(&API_METHOD_UPDATE_VERIFY_JOB) > + .delete(&API_METHOD_DELETE_VERIFY_JOB); > + > +pub const ROUTER: Router = Router::new() > + .get(&API_METHOD_LIST_VERIFY_JOBS) > + .post(&API_METHOD_CREATE_VERIFY_JOB) > + .match_all("id", &ITEM_ROUTER); > \ No newline at end of file > -- > 2.20.1