From mboxrd@z Thu Jan 1 00:00:00 1970
Return-Path: <dcsapak@zita.proxmox.com>
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 A449B6A146
for <pbs-devel@lists.proxmox.com>; Tue, 11 Aug 2020 11:57:58 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
by firstgate.proxmox.com (Proxmox) with ESMTP id 8206D1BC8F
for <pbs-devel@lists.proxmox.com>; Tue, 11 Aug 2020 11:57:28 +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 2F4E71BC7A
for <pbs-devel@lists.proxmox.com>; Tue, 11 Aug 2020 11:57:26 +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 F026A4459C
for <pbs-devel@lists.proxmox.com>; Tue, 11 Aug 2020 11:57:25 +0200 (CEST)
From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Date: Tue, 11 Aug 2020 11:57:17 +0200
Message-Id: <20200811095724.26896-3-d.csapak@proxmox.com>
X-Mailer: git-send-email 2.20.1
In-Reply-To: <20200811095724.26896-1-d.csapak@proxmox.com>
References: <20200811095724.26896-1-d.csapak@proxmox.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results: 0
AWL -0.049 Adjusted score from AWL reputation of From: address
KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery
methods
NO_DNS_FOR_FROM 0.379 Envelope sender has no MX or A DNS records
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_NONE 0.001 SPF: sender does not publish an 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. [jobstate.rs, config.rs, proxmox-backup-api.rs]
Subject: [pbs-devel] [PATCH proxmox-backup v2 2/9] config: add JobState
helper
X-BeenThere: pbs-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox Backup Server development discussion
<pbs-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pbs-devel>,
<mailto:pbs-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pbs-devel/>
List-Post: <mailto:pbs-devel@lists.proxmox.com>
List-Help: <mailto:pbs-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel>,
<mailto:pbs-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Tue, 11 Aug 2020 09:57:58 -0000
this is intended to be a generic helper to (de)serialize job states
(e.g., sync, verify, and so on)
writes a json file into '/var/lib/proxmox-backup/jobstates/TYPE-ID.json'
the api creates the directory with the correct permissions, like
the rrd directory
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
changes from v1:
* JobState is now an enum
* use dietmars suggestions
src/bin/proxmox-backup-api.rs | 1 +
src/config.rs | 1 +
src/config/jobstate.rs | 125 ++++++++++++++++++++++++++++++++++
3 files changed, 127 insertions(+)
create mode 100644 src/config/jobstate.rs
diff --git a/src/bin/proxmox-backup-api.rs b/src/bin/proxmox-backup-api.rs
index 9dde46c0..ea306cf0 100644
--- a/src/bin/proxmox-backup-api.rs
+++ b/src/bin/proxmox-backup-api.rs
@@ -37,6 +37,7 @@ async fn run() -> Result<(), Error> {
config::update_self_signed_cert(false)?;
proxmox_backup::rrd::create_rrdb_dir()?;
+ proxmox_backup::config::jobstate::create_jobstate_dir()?;
if let Err(err) = generate_auth_key() {
bail!("unable to generate auth key - {}", err);
diff --git a/src/config.rs b/src/config.rs
index 2aeccaec..c2ac6da1 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -18,6 +18,7 @@ use crate::buildcfg;
pub mod acl;
pub mod cached_user_info;
pub mod datastore;
+pub mod jobstate;
pub mod network;
pub mod remote;
pub mod sync;
diff --git a/src/config/jobstate.rs b/src/config/jobstate.rs
new file mode 100644
index 00000000..0e8a3115
--- /dev/null
+++ b/src/config/jobstate.rs
@@ -0,0 +1,125 @@
+use std::fs::File;
+use std::path::{Path, PathBuf};
+use std::time::Duration;
+
+use serde::{Serialize, Deserialize};
+use anyhow::{bail, Error, format_err};
+use proxmox::tools::fs::{file_read_optional_string, replace_file, create_path, CreateOptions, open_file_locked};
+
+use crate::tools::epoch_now_u64;
+use crate::server::TaskState;
+
+#[serde(rename_all="kebab-case")]
+#[derive(Serialize,Deserialize)]
+pub enum JobState {
+ Created { time: i64 },
+ Started { upid: String },
+ Finished { upid: String, endtime: i64, state: TaskState }
+}
+
+const JOB_STATE_BASEDIR: &str = "/var/lib/proxmox-backup/jobstates";
+
+/// Create jobstate stat dir with correct permission
+pub fn create_jobstate_dir() -> Result<(), Error> {
+
+ let backup_user = crate::backup::backup_user()?;
+ let opts = CreateOptions::new()
+ .owner(backup_user.uid)
+ .group(backup_user.gid);
+
+ create_path(JOB_STATE_BASEDIR, None, Some(opts))
+ .map_err(|err: Error| format_err!("unable to create rrdb stat dir - {}", err))?;
+
+ Ok(())
+}
+
+fn get_path(jobtype: &str, jobname: &str) -> Result<PathBuf, Error> {
+ let mut path = PathBuf::from(JOB_STATE_BASEDIR);
+ path.push(format!("{}-{}.json", jobtype, jobname));
+ Ok(path)
+}
+
+fn get_lock<P>(path: P) -> Result<File, Error>
+where
+ P: AsRef<Path>
+{
+ let mut path = path.as_ref().to_path_buf();
+ path.set_extension("lck");
+ open_file_locked(path, Duration::new(10, 0))
+}
+
+pub fn remove_state_file(jobtype: &str, jobname: &str) -> Result<(), Error> {
+ let path = get_path(jobtype, jobname)?;
+ let _lock = get_lock(&path)?;
+ std::fs::remove_file(&path).map_err(|err|
+ format_err!("cannot remove statefile for {} - {}: {}", jobtype, jobname, err)
+ )
+}
+
+impl JobState {
+ pub fn new(upid: &str) -> Self {
+ JobState::Started{
+ upid: upid.to_string(),
+ }
+ }
+
+ pub fn finish(&mut self, state: TaskState) -> Result<(), Error> {
+ let upid = match self {
+ JobState::Created { .. } => bail!("cannot finish when not started"),
+ JobState::Started { upid } => upid,
+ JobState::Finished { upid, .. } => upid,
+ }.to_string();
+
+ let endtime: i64 = epoch_now_u64()? as i64;
+
+ *self = JobState::Finished {
+ upid,
+ endtime,
+ state,
+ };
+
+ Ok(())
+ }
+
+ pub fn try_read_or_create(jobtype: &str, jobname: &str) -> Result<Self, Error> {
+ let path = get_path(jobtype, jobname)?;
+
+ let lock = get_lock(&path)?;
+
+ if let Some(state) = file_read_optional_string(path)? {
+ Ok(serde_json::from_str(&state)?)
+ } else {
+ let state = JobState::Created {
+ time: epoch_now_u64()? as i64
+ };
+ state.write_state(jobtype, jobname, Some(lock))?;
+ Ok(state)
+ }
+ }
+
+ pub fn write_state(&self, jobtype: &str, jobname: &str, lock: Option<File>) -> Result<(), Error> {
+ let serialized = serde_json::to_string(&self)?;
+ let path = get_path(jobtype, jobname)?;
+
+ let _lock = if let Some(lock) = lock {
+ lock
+ } else {
+ get_lock(&path)?
+ };
+
+ let backup_user = crate::backup::backup_user()?;
+ let mode = nix::sys::stat::Mode::from_bits_truncate(0o0644);
+ // set the correct owner/group/permissions while saving file
+ // owner(rw) = backup, group(r)= backup
+ let options = CreateOptions::new()
+ .perm(mode)
+ .owner(backup_user.uid)
+ .group(backup_user.gid);
+
+ replace_file(
+ path,
+ serialized.as_bytes(),
+ options,
+ )
+ }
+}
--
2.20.1