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 E3BE860659 for ; Thu, 8 Oct 2020 09:50:33 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id CF1FABEB0 for ; Thu, 8 Oct 2020 09:50:03 +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) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id C35FEBEA5 for ; Thu, 8 Oct 2020 09:50:02 +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 8F09745C36 for ; Thu, 8 Oct 2020 09:50:02 +0200 (CEST) Date: Thu, 8 Oct 2020 09:50:01 +0200 From: Wolfgang Bumiller To: Hannes Laimer Cc: pbs-devel@lists.proxmox.com Message-ID: <20201008075001.ehfl3nstli3djlyq@olga.proxmox.com> References: <20201007090324.42928-1-h.laimer@proxmox.com> <20201007090324.42928-3-h.laimer@proxmox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20201007090324.42928-3-h.laimer@proxmox.com> User-Agent: NeoMutt/20180716 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.019 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. [config.rs, verify.rs] Subject: Re: [pbs-devel] [PATCH v2 proxmox-backup 02/15] add verify job config 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 07:50:34 -0000 On Wed, Oct 07, 2020 at 11:03:11AM +0200, Hannes Laimer wrote: > Signed-off-by: Hannes Laimer > --- > src/config.rs | 1 + > src/config/verify.rs | 189 +++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 190 insertions(+) > create mode 100644 src/config/verify.rs > > diff --git a/src/config.rs b/src/config.rs > index c2ac6da1..ab7fc81a 100644 > --- a/src/config.rs > +++ b/src/config.rs > @@ -23,6 +23,7 @@ pub mod network; > pub mod remote; > pub mod sync; > pub mod user; > +pub mod verify; > > /// Check configuration directory permissions > /// > diff --git a/src/config/verify.rs b/src/config/verify.rs > new file mode 100644 > index 00000000..7c92a16e > --- /dev/null > +++ b/src/config/verify.rs > @@ -0,0 +1,189 @@ > +use anyhow::{Error}; > +use lazy_static::lazy_static; > +use std::collections::HashMap; > +use serde::{Serialize, Deserialize}; > + > +use proxmox::api::{ > + api, > + schema::*, > + section_config::{ > + SectionConfig, > + SectionConfigData, > + SectionConfigPlugin, > + } > +}; > + > +use proxmox::tools::{fs::replace_file, fs::CreateOptions}; > + > +use crate::api2::types::*; > + > +lazy_static! { > + static ref CONFIG: SectionConfig = init(); > +} > + > + > +#[api( > + 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, > + }, > + } > +)] > +#[serde(rename_all="kebab-case")] > +#[derive(Serialize,Deserialize)] > +/// Verify Job > +pub struct VerifyJobConfig { First things first - can we name this `VerificationJobConfig`? I'm not a fan of using a verb here... > + pub id: String, > + pub store: String, > + #[serde(skip_serializing_if="Option::is_none")] > + pub ignore_verified: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub outdated_after: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub comment: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub schedule: Option, > +} > + > +// FIXME: generate duplicate schemas/structs from one listing? Why though? So my question there is, what is this supposed to actually represent? It is a separate struct and it contains the keys from the other struct, but how do they relate to each other? (And I mean apart from "we do this in PVE, too", I do not consider that a good argument...) Do you really need all of these fields in there or really just the id? And if you want/need all the info as part of the state, what's stopping you from simply using an actual struct member of type `VerifyJobConfig` instead of flattening it out? > +#[api( > + 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, > + }, > + "next-run": { > + description: "Estimated time of the next run (UNIX epoch).", > + optional: true, > + type: Integer, > + }, > + "last-run-state": { > + description: "Result of the last run.", > + optional: true, > + type: String, > + }, > + "last-run-upid": { > + description: "Task UPID of the last run.", > + optional: true, > + type: String, > + }, > + "last-run-endtime": { > + description: "Endtime of the last run.", > + optional: true, > + type: Integer, > + }, > + } > +)] > +#[serde(rename_all="kebab-case")] > +#[derive(Serialize,Deserialize)] > +/// Status of Verify Job > +pub struct VerifyJobStatus { > + pub id: String, > + pub store: String, > + #[serde(skip_serializing_if="Option::is_none")] > + pub ignore_verified: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub outdated_after: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub comment: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub schedule: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub next_run: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub last_run_state: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub last_run_upid: Option, > + #[serde(skip_serializing_if="Option::is_none")] > + pub last_run_endtime: Option, > +} > + > + > +fn init() -> SectionConfig { > + let obj_schema = match VerifyJobConfig::API_SCHEMA { > + Schema::Object(ref obj_schema) => obj_schema, > + _ => unreachable!(), > + }; > + > + let plugin = SectionConfigPlugin::new("verify".to_string(), Some(String::from("id")), obj_schema); > + let mut config = SectionConfig::new(&JOB_ID_SCHEMA); > + config.register_plugin(plugin); > + > + config > +} > + > +pub const VERIFY_CFG_FILENAME: &str = "/etc/proxmox-backup/verify.cfg"; > +pub const VERIFY_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.verify.lck"; > + > +pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> { > + > + let content = proxmox::tools::fs::file_read_optional_string(VERIFY_CFG_FILENAME)?; > + let content = content.unwrap_or(String::from("")); Use `unwrap_or_else(String::new)`. > + > + let digest = openssl::sha::sha256(content.as_bytes()); > + let data = CONFIG.parse(VERIFY_CFG_FILENAME, &content)?; > + Ok((data, digest)) > +} > + > +pub fn save_config(config: &SectionConfigData) -> Result<(), Error> { > + let raw = CONFIG.write(VERIFY_CFG_FILENAME, &config)?; > + > + let backup_user = crate::backup::backup_user()?; > + let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640); > + // set the correct owner/group/permissions while saving file > + // owner(rw) = root, group(r)= backup > + > + let options = CreateOptions::new() > + .perm(mode) > + .owner(nix::unistd::ROOT) > + .group(backup_user.gid); > + > + replace_file(VERIFY_CFG_FILENAME, raw.as_bytes(), options)?; > + > + Ok(()) > +} > + > +// shell completion helper > +pub fn complete_verify_job_id(_arg: &str, _param: &HashMap) -> Vec { > + match config() { > + Ok((data, _digest)) => data.sections.iter().map(|(id, _)| id.to_string()).collect(), > + Err(_) => return vec![], > + } > +} > \ No newline at end of file > -- > 2.20.1