From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup v2 1/9] server: change status of a task from a string to an enum
Date: Tue, 11 Aug 2020 11:57:16 +0200 [thread overview]
Message-ID: <20200811095724.26896-2-d.csapak@proxmox.com> (raw)
In-Reply-To: <20200811095724.26896-1-d.csapak@proxmox.com>
representing a state via an enum makes more sense in this case
we also implement FromStr and Display to make it easy to convet from/to
a string
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
new in v2
src/api2/admin/sync.rs | 2 +-
src/api2/node/tasks.rs | 8 ++--
src/api2/types/mod.rs | 2 +-
src/server/worker_task.rs | 88 ++++++++++++++++++++++++++++++---------
4 files changed, 74 insertions(+), 26 deletions(-)
diff --git a/src/api2/admin/sync.rs b/src/api2/admin/sync.rs
index f06625f6..79af03bc 100644
--- a/src/api2/admin/sync.rs
+++ b/src/api2/admin/sync.rs
@@ -56,7 +56,7 @@ pub fn list_sync_jobs(
if let Some(task) = last_tasks.get(&job.id) {
job.last_run_upid = Some(task.upid_str.clone());
if let Some((endtime, status)) = &task.state {
- job.last_run_state = Some(String::from(status));
+ job.last_run_state = Some(status.to_string());
job.last_run_endtime = Some(*endtime);
last = *endtime;
}
diff --git a/src/api2/node/tasks.rs b/src/api2/node/tasks.rs
index 6917869e..0bb043d9 100644
--- a/src/api2/node/tasks.rs
+++ b/src/api2/node/tasks.rs
@@ -10,7 +10,7 @@ use proxmox::{identity, list_subdirs_api_method, sortable};
use crate::tools;
use crate::api2::types::*;
-use crate::server::{self, UPID};
+use crate::server::{self, UPID, TaskState};
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
use crate::config::cached_user_info::CachedUserInfo;
@@ -105,9 +105,9 @@ async fn get_task_status(
if crate::server::worker_is_active(&upid).await? {
result["status"] = Value::from("running");
} else {
- let exitstatus = crate::server::upid_read_status(&upid).unwrap_or(String::from("unknown"));
+ let exitstatus = crate::server::upid_read_status(&upid).unwrap_or(TaskState::Unknown);
result["status"] = Value::from("stopped");
- result["exitstatus"] = Value::from(exitstatus);
+ result["exitstatus"] = Value::from(exitstatus.to_string());
};
Ok(result)
@@ -352,7 +352,7 @@ pub fn list_tasks(
if let Some(ref state) = info.state {
if running { continue; }
- if errors && state.1 == "OK" {
+ if errors && state.1 == crate::server::TaskState::OK {
continue;
}
}
diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs
index fb386d46..a619810d 100644
--- a/src/api2/types/mod.rs
+++ b/src/api2/types/mod.rs
@@ -595,7 +595,7 @@ impl From<crate::server::TaskListInfo> for TaskListItem {
fn from(info: crate::server::TaskListInfo) -> Self {
let (endtime, status) = info
.state
- .map_or_else(|| (None, None), |(a,b)| (Some(a), Some(b)));
+ .map_or_else(|| (None, None), |(a,b)| (Some(a), Some(b.to_string())));
TaskListItem {
upid: info.upid_str,
diff --git a/src/server/worker_task.rs b/src/server/worker_task.rs
index 852f3ecc..876666d6 100644
--- a/src/server/worker_task.rs
+++ b/src/server/worker_task.rs
@@ -11,6 +11,7 @@ use futures::*;
use lazy_static::lazy_static;
use nix::unistd::Pid;
use serde_json::{json, Value};
+use serde::{Serialize, Deserialize};
use tokio::sync::oneshot;
use proxmox::sys::linux::procfs;
@@ -190,8 +191,8 @@ pub fn create_task_log_dirs() -> Result<(), Error> {
}
/// Read exits status from task log file
-pub fn upid_read_status(upid: &UPID) -> Result<String, Error> {
- let mut status = String::from("unknown");
+pub fn upid_read_status(upid: &UPID) -> Result<TaskState, Error> {
+ let mut status = TaskState::Unknown;
let path = upid.log_path();
@@ -212,12 +213,8 @@ pub fn upid_read_status(upid: &UPID) -> Result<String, Error> {
match iter.next() {
None => continue,
Some(rest) => {
- if rest == "OK" {
- status = String::from(rest);
- } else if rest.starts_with("WARNINGS: ") {
- status = String::from(rest);
- } else if rest.starts_with("ERROR: ") {
- status = String::from(&rest[7..]);
+ if let Ok(state) = rest.parse() {
+ status = state;
}
}
}
@@ -226,6 +223,59 @@ pub fn upid_read_status(upid: &UPID) -> Result<String, Error> {
Ok(status)
}
+/// Task State
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+pub enum TaskState {
+ /// The Task ended with an undefined state
+ Unknown,
+ /// The Task ended and there were no errors or warnings
+ OK,
+ /// The Task had 'count' amount of warnings and no errors
+ Warning { count: u64 },
+ /// The Task ended with the error described in 'message'
+ Error { message: String },
+}
+
+impl TaskState {
+ fn result_text(&self) -> String {
+ match self {
+ TaskState::Error { message } => format!("TASK ERROR: {}", message),
+ other => format!("TASK {}", other),
+ }
+ }
+}
+
+impl std::fmt::Display for TaskState {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ TaskState::Unknown => write!(f, "unknown"),
+ TaskState::OK => write!(f, "OK"),
+ TaskState::Warning { count } => write!(f, "WARNINGS: {}", count),
+ TaskState::Error { message } => write!(f, "{}", message),
+ }
+ }
+}
+
+impl std::str::FromStr for TaskState {
+ type Err = Error;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ if s == "unknown" {
+ Ok(TaskState::Unknown)
+ } else if s == "OK" {
+ Ok(TaskState::OK)
+ } else if s.starts_with("WARNINGS: ") {
+ let count: u64 = s[10..].parse()?;
+ Ok(TaskState::Warning{ count })
+ } else if s.len() > 0 {
+ let message = if s.starts_with("ERROR: ") { &s[7..] } else { s }.to_string();
+ Ok(TaskState::Error{ message })
+ } else {
+ bail!("unable to parse Task Status '{}'", s);
+ }
+ }
+}
+
/// Task details including parsed UPID
///
/// If there is no `state`, the task is still running.
@@ -236,9 +286,7 @@ pub struct TaskListInfo {
/// UPID string representation
pub upid_str: String,
/// Task `(endtime, status)` if already finished
- ///
- /// The `status` is either `unknown`, `OK`, `WARN`, or `ERROR: ...`
- pub state: Option<(i64, String)>, // endtime, status
+ pub state: Option<(i64, TaskState)>, // endtime, status
}
// atomically read/update the task list, update status of finished tasks
@@ -278,14 +326,14 @@ fn update_active_workers(new_upid: Option<&UPID>) -> Result<Vec<TaskListInfo>, E
None => {
println!("Detected stopped UPID {}", upid_str);
let status = upid_read_status(&upid)
- .unwrap_or_else(|_| String::from("unknown"));
+ .unwrap_or_else(|_| TaskState::Unknown);
finish_list.push(TaskListInfo {
upid, upid_str, state: Some((Local::now().timestamp(), status))
});
},
Some((endtime, status)) => {
finish_list.push(TaskListInfo {
- upid, upid_str, state: Some((endtime, status))
+ upid, upid_str, state: Some((endtime, status.parse()?))
})
}
}
@@ -503,23 +551,23 @@ impl WorkerTask {
Ok(upid_str)
}
- /// get the Text of the result
- pub fn get_log_text(&self, result: &Result<(), Error>) -> String {
-
+ /// create state from self and a result
+ pub fn create_state(&self, result: &Result<(), Error>) -> TaskState {
let warn_count = self.data.lock().unwrap().warn_count;
if let Err(err) = result {
- format!("ERROR: {}", err)
+ TaskState::Error { message: err.to_string() }
} else if warn_count > 0 {
- format!("WARNINGS: {}", warn_count)
+ TaskState::Warning { count: warn_count }
} else {
- "OK".to_string()
+ TaskState::OK
}
}
/// Log task result, remove task from running list
pub fn log_result(&self, result: &Result<(), Error>) {
- self.log(format!("TASK {}", self.get_log_text(result)));
+ let state = self.create_state(result);
+ self.log(state.result_text());
WORKER_TASK_LIST.lock().unwrap().remove(&self.upid.task_id);
let _ = update_active_workers(None);
--
2.20.1
next prev parent reply other threads:[~2020-08-11 9:57 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-11 9:57 [pbs-devel] [PATCH proxmox-backup v2 0/9] improve syncjob handling Dominik Csapak
2020-08-11 9:57 ` Dominik Csapak [this message]
2020-08-11 9:57 ` [pbs-devel] [PATCH proxmox-backup v2 2/9] config: add JobState helper Dominik Csapak
2020-08-17 8:33 ` Wolfgang Bumiller
2020-08-11 9:57 ` [pbs-devel] [PATCH proxmox-backup v2 3/9] api/{pull, sync}: refactor to do_sync_job Dominik Csapak
2020-08-11 9:57 ` [pbs-devel] [PATCH proxmox-backup v2 4/9] api2/pull: extend do_sync_job to also handle schedule and jobstate Dominik Csapak
2020-08-11 9:57 ` [pbs-devel] [PATCH proxmox-backup v2 5/9] syncjob: use do_sync_job also for scheduled sync jobs Dominik Csapak
2020-08-11 9:57 ` [pbs-devel] [PATCH proxmox-backup v2 6/9] syncjob: use JobState for determining when to run next scheduled sync Dominik Csapak
2020-08-11 9:57 ` [pbs-devel] [PATCH proxmox-backup v2 7/9] api2/admin/sync: use JobState for faster access to state info Dominik Csapak
2020-08-11 9:57 ` [pbs-devel] [PATCH proxmox-backup v2 8/9] ui: syncjob: improve task text rendering Dominik Csapak
2020-08-11 9:57 ` [pbs-devel] [PATCH proxmox-backup v2 9/9] ui: syncjob: make some columns smaller Dominik Csapak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200811095724.26896-2-d.csapak@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal