2019-11-21 13:53:15 +00:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::{BufRead, BufReader};
|
2019-04-07 10:18:58 +00:00
|
|
|
|
2020-11-06 10:23:09 +00:00
|
|
|
use anyhow::{bail, Error};
|
2019-04-07 10:18:58 +00:00
|
|
|
use serde_json::{json, Value};
|
|
|
|
|
2020-08-06 13:46:01 +00:00
|
|
|
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
2019-11-21 13:53:15 +00:00
|
|
|
use proxmox::api::router::SubdirMap;
|
2020-01-21 11:28:01 +00:00
|
|
|
use proxmox::{identity, list_subdirs_api_method, sortable};
|
2019-11-21 12:10:49 +00:00
|
|
|
|
|
|
|
use crate::tools;
|
2020-11-06 10:23:09 +00:00
|
|
|
|
2019-05-09 05:44:09 +00:00
|
|
|
use crate::api2::types::*;
|
2020-11-06 10:23:09 +00:00
|
|
|
use crate::api2::pull::check_pull_privs;
|
|
|
|
|
2020-09-28 13:32:09 +00:00
|
|
|
use crate::server::{self, UPID, TaskState, TaskListInfoIterator};
|
2020-11-06 10:23:09 +00:00
|
|
|
use crate::config::acl::{
|
|
|
|
PRIV_DATASTORE_MODIFY,
|
|
|
|
PRIV_DATASTORE_VERIFY,
|
|
|
|
PRIV_SYS_AUDIT,
|
|
|
|
PRIV_SYS_MODIFY,
|
|
|
|
};
|
2020-04-30 08:05:50 +00:00
|
|
|
use crate::config::cached_user_info::CachedUserInfo;
|
|
|
|
|
2020-11-06 10:23:09 +00:00
|
|
|
// matches respective job execution privileges
|
|
|
|
fn check_job_privs(auth_id: &Authid, user_info: &CachedUserInfo, upid: &UPID) -> Result<(), Error> {
|
|
|
|
match (upid.worker_type.as_str(), &upid.worker_id) {
|
|
|
|
("verificationjob", Some(workerid)) => {
|
|
|
|
if let Some(captures) = VERIFICATION_JOB_WORKER_ID_REGEX.captures(&workerid) {
|
|
|
|
if let Some(store) = captures.get(1) {
|
|
|
|
return user_info.check_privs(&auth_id,
|
|
|
|
&["datastore", store.as_str()],
|
|
|
|
PRIV_DATASTORE_VERIFY,
|
|
|
|
true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
("syncjob", Some(workerid)) => {
|
|
|
|
if let Some(captures) = SYNC_JOB_WORKER_ID_REGEX.captures(&workerid) {
|
|
|
|
let remote = captures.get(1);
|
|
|
|
let remote_store = captures.get(2);
|
|
|
|
let local_store = captures.get(3);
|
|
|
|
|
|
|
|
if let (Some(remote), Some(remote_store), Some(local_store)) =
|
|
|
|
(remote, remote_store, local_store) {
|
|
|
|
|
|
|
|
return check_pull_privs(&auth_id,
|
|
|
|
local_store.as_str(),
|
|
|
|
remote.as_str(),
|
|
|
|
remote_store.as_str(),
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
("garbage_collection", Some(workerid)) => {
|
|
|
|
return user_info.check_privs(&auth_id,
|
|
|
|
&["datastore", &workerid],
|
|
|
|
PRIV_DATASTORE_MODIFY,
|
|
|
|
true)
|
|
|
|
},
|
|
|
|
("prune", Some(workerid)) => {
|
|
|
|
return user_info.check_privs(&auth_id,
|
|
|
|
&["datastore",
|
|
|
|
&workerid],
|
|
|
|
PRIV_DATASTORE_MODIFY,
|
|
|
|
true);
|
|
|
|
},
|
|
|
|
_ => bail!("not a scheduled job task"),
|
|
|
|
};
|
|
|
|
|
|
|
|
bail!("not a scheduled job task");
|
|
|
|
}
|
|
|
|
|
2020-11-09 15:01:21 +00:00
|
|
|
// get the store out of the worker_id
|
|
|
|
fn check_job_store(upid: &UPID, store: &str) -> bool {
|
|
|
|
match (upid.worker_type.as_str(), &upid.worker_id) {
|
|
|
|
(workertype, Some(workerid)) if workertype.starts_with("verif") => {
|
|
|
|
if let Some(captures) = VERIFICATION_JOB_WORKER_ID_REGEX.captures(&workerid) {
|
|
|
|
if let Some(jobstore) = captures.get(1) {
|
|
|
|
return store == jobstore.as_str();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return workerid == store;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
("syncjob", Some(workerid)) => {
|
|
|
|
if let Some(captures) = SYNC_JOB_WORKER_ID_REGEX.captures(&workerid) {
|
|
|
|
if let Some(local_store) = captures.get(3) {
|
|
|
|
return store == local_store.as_str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
("prune", Some(workerid))
|
|
|
|
| ("backup", Some(workerid))
|
|
|
|
| ("garbage_collection", Some(workerid)) => {
|
|
|
|
return workerid == store || workerid.starts_with(&format!("{}:", store));
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
};
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2020-10-15 09:27:47 +00:00
|
|
|
fn check_task_access(auth_id: &Authid, upid: &UPID) -> Result<(), Error> {
|
|
|
|
let task_auth_id = &upid.auth_id;
|
|
|
|
if auth_id == task_auth_id
|
|
|
|
|| (task_auth_id.is_token() && &Authid::from(task_auth_id.user().clone()) == auth_id) {
|
2020-11-06 10:23:09 +00:00
|
|
|
// task owner can always read
|
2020-10-15 09:27:47 +00:00
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
let user_info = CachedUserInfo::new()?;
|
2020-11-06 10:23:09 +00:00
|
|
|
|
2021-01-20 16:23:51 +00:00
|
|
|
// access to all tasks
|
|
|
|
// or task == job which the user/token could have configured/manually executed
|
|
|
|
|
|
|
|
user_info.check_privs(auth_id, &["system", "tasks"], PRIV_SYS_AUDIT, false)
|
|
|
|
.or_else(|_| check_job_privs(&auth_id, &user_info, upid))
|
|
|
|
.or_else(|_| bail!("task access not allowed"))
|
2020-10-15 09:27:47 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-07 12:36:57 +00:00
|
|
|
|
2020-04-16 15:47:21 +00:00
|
|
|
#[api(
|
|
|
|
input: {
|
|
|
|
properties: {
|
|
|
|
node: {
|
|
|
|
schema: NODE_SCHEMA,
|
|
|
|
},
|
|
|
|
upid: {
|
|
|
|
schema: UPID_SCHEMA,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
returns: {
|
2020-10-19 07:39:06 +00:00
|
|
|
description: "Task status information.",
|
2020-04-16 15:47:21 +00:00
|
|
|
properties: {
|
|
|
|
node: {
|
|
|
|
schema: NODE_SCHEMA,
|
|
|
|
},
|
|
|
|
upid: {
|
|
|
|
schema: UPID_SCHEMA,
|
|
|
|
},
|
|
|
|
pid: {
|
|
|
|
type: i64,
|
|
|
|
description: "The Unix PID.",
|
|
|
|
},
|
|
|
|
pstart: {
|
|
|
|
type: u64,
|
|
|
|
description: "The Unix process start time from `/proc/pid/stat`",
|
|
|
|
},
|
|
|
|
starttime: {
|
|
|
|
type: i64,
|
|
|
|
description: "The task start time (Epoch)",
|
|
|
|
},
|
|
|
|
"type": {
|
|
|
|
type: String,
|
|
|
|
description: "Worker type (arbitrary ASCII string)",
|
|
|
|
},
|
|
|
|
id: {
|
|
|
|
type: String,
|
|
|
|
optional: true,
|
|
|
|
description: "Worker ID (arbitrary ASCII string)",
|
|
|
|
},
|
|
|
|
user: {
|
2020-10-15 09:27:47 +00:00
|
|
|
type: Userid,
|
2020-04-16 15:47:21 +00:00
|
|
|
},
|
2020-10-15 09:27:47 +00:00
|
|
|
tokenid: {
|
|
|
|
type: Tokenname,
|
|
|
|
optional: true,
|
|
|
|
},
|
2020-04-16 15:47:21 +00:00
|
|
|
status: {
|
|
|
|
type: String,
|
|
|
|
description: "'running' or 'stopped'",
|
|
|
|
},
|
|
|
|
exitstatus: {
|
|
|
|
type: String,
|
|
|
|
optional: true,
|
|
|
|
description: "'OK', 'Error: <msg>', or 'unkwown'.",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
access: {
|
2020-10-19 07:39:06 +00:00
|
|
|
description: "Users can access their own tasks, or need Sys.Audit on /system/tasks.",
|
2020-04-30 08:05:50 +00:00
|
|
|
permission: &Permission::Anybody,
|
2020-04-16 15:47:21 +00:00
|
|
|
},
|
|
|
|
)]
|
|
|
|
/// Get task status.
|
2020-05-07 06:30:38 +00:00
|
|
|
async fn get_task_status(
|
2019-04-07 12:36:57 +00:00
|
|
|
param: Value,
|
2020-04-30 08:05:50 +00:00
|
|
|
rpcenv: &mut dyn RpcEnvironment,
|
2019-04-07 12:36:57 +00:00
|
|
|
) -> Result<Value, Error> {
|
|
|
|
|
|
|
|
let upid = extract_upid(¶m)?;
|
|
|
|
|
2020-10-23 11:33:21 +00:00
|
|
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
2020-10-15 09:27:47 +00:00
|
|
|
check_task_access(&auth_id, &upid)?;
|
2020-04-30 08:05:50 +00:00
|
|
|
|
2019-04-09 13:12:20 +00:00
|
|
|
let mut result = json!({
|
|
|
|
"upid": param["upid"],
|
|
|
|
"node": upid.node,
|
|
|
|
"pid": upid.pid,
|
|
|
|
"pstart": upid.pstart,
|
|
|
|
"starttime": upid.starttime,
|
|
|
|
"type": upid.worker_type,
|
|
|
|
"id": upid.worker_id,
|
2020-10-15 09:27:47 +00:00
|
|
|
"user": upid.auth_id.user(),
|
2019-04-09 13:12:20 +00:00
|
|
|
});
|
|
|
|
|
2020-10-15 09:27:47 +00:00
|
|
|
if upid.auth_id.is_token() {
|
|
|
|
result["tokenid"] = Value::from(upid.auth_id.tokenname().unwrap().as_str());
|
|
|
|
}
|
|
|
|
|
2020-05-07 06:30:38 +00:00
|
|
|
if crate::server::worker_is_active(&upid).await? {
|
2019-04-09 13:12:20 +00:00
|
|
|
result["status"] = Value::from("running");
|
2019-04-07 12:36:57 +00:00
|
|
|
} else {
|
2020-08-13 12:30:17 +00:00
|
|
|
let exitstatus = crate::server::upid_read_status(&upid).unwrap_or(TaskState::Unknown { endtime: 0 });
|
2019-04-09 13:12:20 +00:00
|
|
|
result["status"] = Value::from("stopped");
|
2020-08-13 08:29:13 +00:00
|
|
|
result["exitstatus"] = Value::from(exitstatus.to_string());
|
2019-04-07 12:36:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn extract_upid(param: &Value) -> Result<UPID, Error> {
|
|
|
|
|
|
|
|
let upid_str = tools::required_string_param(¶m, "upid")?;
|
|
|
|
|
2019-12-10 12:45:56 +00:00
|
|
|
upid_str.parse::<UPID>()
|
2019-04-07 12:36:57 +00:00
|
|
|
}
|
|
|
|
|
2020-04-16 15:47:21 +00:00
|
|
|
#[api(
|
|
|
|
input: {
|
|
|
|
properties: {
|
|
|
|
node: {
|
|
|
|
schema: NODE_SCHEMA,
|
|
|
|
},
|
|
|
|
upid: {
|
|
|
|
schema: UPID_SCHEMA,
|
|
|
|
},
|
|
|
|
"test-status": {
|
|
|
|
type: bool,
|
|
|
|
optional: true,
|
|
|
|
description: "Test task status, and set result attribute \"active\" accordingly.",
|
|
|
|
},
|
|
|
|
start: {
|
|
|
|
type: u64,
|
|
|
|
optional: true,
|
|
|
|
description: "Start at this line.",
|
|
|
|
default: 0,
|
|
|
|
},
|
|
|
|
limit: {
|
|
|
|
type: u64,
|
|
|
|
optional: true,
|
|
|
|
description: "Only list this amount of lines.",
|
|
|
|
default: 50,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
access: {
|
2020-04-30 08:05:50 +00:00
|
|
|
description: "Users can access there own tasks, or need Sys.Audit on /system/tasks.",
|
|
|
|
permission: &Permission::Anybody,
|
2020-04-16 15:47:21 +00:00
|
|
|
},
|
|
|
|
)]
|
|
|
|
/// Read task log.
|
2020-05-07 06:30:38 +00:00
|
|
|
async fn read_task_log(
|
2019-04-07 12:36:57 +00:00
|
|
|
param: Value,
|
2020-05-18 07:57:35 +00:00
|
|
|
mut rpcenv: &mut dyn RpcEnvironment,
|
2019-04-07 12:36:57 +00:00
|
|
|
) -> Result<Value, Error> {
|
|
|
|
|
|
|
|
let upid = extract_upid(¶m)?;
|
2019-12-07 14:29:42 +00:00
|
|
|
|
2020-10-23 11:33:21 +00:00
|
|
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
2020-04-30 08:05:50 +00:00
|
|
|
|
2020-10-15 09:27:47 +00:00
|
|
|
check_task_access(&auth_id, &upid)?;
|
2020-04-30 08:05:50 +00:00
|
|
|
|
2019-12-07 14:29:42 +00:00
|
|
|
let test_status = param["test-status"].as_bool().unwrap_or(false);
|
|
|
|
|
2019-04-07 12:36:57 +00:00
|
|
|
let start = param["start"].as_u64().unwrap_or(0);
|
|
|
|
let mut limit = param["limit"].as_u64().unwrap_or(50);
|
2019-12-07 14:29:42 +00:00
|
|
|
|
2019-04-07 12:36:57 +00:00
|
|
|
let mut count: u64 = 0;
|
|
|
|
|
|
|
|
let path = upid.log_path();
|
|
|
|
|
|
|
|
let file = File::open(path)?;
|
|
|
|
|
|
|
|
let mut lines: Vec<Value> = vec![];
|
|
|
|
|
|
|
|
for line in BufReader::new(file).lines() {
|
|
|
|
match line {
|
|
|
|
Ok(line) => {
|
|
|
|
count += 1;
|
|
|
|
if count < start { continue };
|
2019-10-25 16:04:37 +00:00
|
|
|
if limit == 0 { continue };
|
2019-04-07 12:36:57 +00:00
|
|
|
|
|
|
|
lines.push(json!({ "n": count, "t": line }));
|
|
|
|
|
|
|
|
limit -= 1;
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
log::error!("reading task log failed: {}", err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-18 07:57:35 +00:00
|
|
|
rpcenv["total"] = Value::from(count);
|
2019-04-09 12:43:30 +00:00
|
|
|
|
2019-12-07 14:29:42 +00:00
|
|
|
if test_status {
|
2020-05-07 06:30:38 +00:00
|
|
|
let active = crate::server::worker_is_active(&upid).await?;
|
2020-05-18 07:57:35 +00:00
|
|
|
rpcenv["active"] = Value::from(active);
|
2019-12-07 14:29:42 +00:00
|
|
|
}
|
|
|
|
|
2019-04-07 12:36:57 +00:00
|
|
|
Ok(json!(lines))
|
|
|
|
}
|
2019-04-07 10:18:58 +00:00
|
|
|
|
2020-04-16 15:47:21 +00:00
|
|
|
#[api(
|
|
|
|
protected: true,
|
|
|
|
input: {
|
|
|
|
properties: {
|
|
|
|
node: {
|
|
|
|
schema: NODE_SCHEMA,
|
|
|
|
},
|
|
|
|
upid: {
|
|
|
|
schema: UPID_SCHEMA,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
access: {
|
2020-04-30 08:05:50 +00:00
|
|
|
description: "Users can stop there own tasks, or need Sys.Modify on /system/tasks.",
|
|
|
|
permission: &Permission::Anybody,
|
2020-04-16 15:47:21 +00:00
|
|
|
},
|
|
|
|
)]
|
|
|
|
/// Try to stop a task.
|
2019-04-10 11:55:05 +00:00
|
|
|
fn stop_task(
|
|
|
|
param: Value,
|
2020-04-30 08:05:50 +00:00
|
|
|
rpcenv: &mut dyn RpcEnvironment,
|
2019-04-10 11:55:05 +00:00
|
|
|
) -> Result<Value, Error> {
|
|
|
|
|
|
|
|
let upid = extract_upid(¶m)?;
|
|
|
|
|
2020-10-23 11:33:21 +00:00
|
|
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
2020-04-30 08:05:50 +00:00
|
|
|
|
2020-10-23 11:33:21 +00:00
|
|
|
if auth_id != upid.auth_id {
|
2020-04-30 08:05:50 +00:00
|
|
|
let user_info = CachedUserInfo::new()?;
|
2020-10-23 11:33:21 +00:00
|
|
|
user_info.check_privs(&auth_id, &["system", "tasks"], PRIV_SYS_MODIFY, false)?;
|
2020-04-30 08:05:50 +00:00
|
|
|
}
|
|
|
|
|
2020-05-07 06:30:38 +00:00
|
|
|
server::abort_worker_async(upid);
|
2019-04-10 11:55:05 +00:00
|
|
|
|
|
|
|
Ok(Value::Null)
|
|
|
|
}
|
|
|
|
|
2020-01-28 09:57:33 +00:00
|
|
|
#[api(
|
|
|
|
input: {
|
|
|
|
properties: {
|
|
|
|
node: {
|
|
|
|
schema: NODE_SCHEMA
|
|
|
|
},
|
|
|
|
start: {
|
|
|
|
type: u64,
|
|
|
|
description: "List tasks beginning from this offset.",
|
|
|
|
default: 0,
|
|
|
|
optional: true,
|
|
|
|
},
|
|
|
|
limit: {
|
|
|
|
type: u64,
|
2020-10-30 14:02:11 +00:00
|
|
|
description: "Only list this amount of tasks. (0 means no limit)",
|
2020-01-28 09:57:33 +00:00
|
|
|
default: 50,
|
|
|
|
optional: true,
|
|
|
|
},
|
|
|
|
store: {
|
|
|
|
schema: DATASTORE_SCHEMA,
|
|
|
|
optional: true,
|
|
|
|
},
|
|
|
|
running: {
|
|
|
|
type: bool,
|
|
|
|
description: "Only list running tasks.",
|
|
|
|
optional: true,
|
2020-04-30 09:51:56 +00:00
|
|
|
default: false,
|
2020-01-28 09:57:33 +00:00
|
|
|
},
|
|
|
|
errors: {
|
|
|
|
type: bool,
|
|
|
|
description: "Only list erroneous tasks.",
|
|
|
|
optional:true,
|
2020-04-30 09:51:56 +00:00
|
|
|
default: false,
|
2020-01-28 09:57:33 +00:00
|
|
|
},
|
|
|
|
userfilter: {
|
2020-08-06 13:46:01 +00:00
|
|
|
optional: true,
|
2020-01-28 09:57:33 +00:00
|
|
|
type: String,
|
|
|
|
description: "Only list tasks from this user.",
|
|
|
|
},
|
2020-10-30 14:02:12 +00:00
|
|
|
since: {
|
|
|
|
type: i64,
|
|
|
|
description: "Only list tasks since this UNIX epoch.",
|
|
|
|
optional: true,
|
|
|
|
},
|
2020-10-30 14:02:14 +00:00
|
|
|
until: {
|
|
|
|
type: i64,
|
|
|
|
description: "Only list tasks until this UNIX epoch.",
|
|
|
|
optional: true,
|
|
|
|
},
|
2020-10-30 14:02:12 +00:00
|
|
|
typefilter: {
|
|
|
|
optional: true,
|
|
|
|
type: String,
|
|
|
|
description: "Only list tasks whose type contains this.",
|
|
|
|
},
|
|
|
|
statusfilter: {
|
|
|
|
optional: true,
|
|
|
|
type: Array,
|
|
|
|
description: "Only list tasks which have any one of the listed status.",
|
|
|
|
items: {
|
|
|
|
type: TaskStateType,
|
|
|
|
},
|
|
|
|
},
|
2020-01-28 09:57:33 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
returns: {
|
|
|
|
description: "A list of tasks.",
|
|
|
|
type: Array,
|
2020-01-28 10:22:06 +00:00
|
|
|
items: { type: TaskListItem },
|
2020-01-28 09:57:33 +00:00
|
|
|
},
|
2020-04-16 15:47:21 +00:00
|
|
|
access: {
|
2020-04-30 08:05:50 +00:00
|
|
|
description: "Users can only see there own tasks, unless the have Sys.Audit on /system/tasks.",
|
|
|
|
permission: &Permission::Anybody,
|
2020-04-16 15:47:21 +00:00
|
|
|
},
|
2020-01-28 09:57:33 +00:00
|
|
|
)]
|
|
|
|
/// List tasks.
|
2021-01-25 13:42:59 +00:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-01-30 12:28:25 +00:00
|
|
|
pub fn list_tasks(
|
2020-04-30 09:51:56 +00:00
|
|
|
start: u64,
|
|
|
|
limit: u64,
|
|
|
|
errors: bool,
|
|
|
|
running: bool,
|
2020-09-25 14:13:17 +00:00
|
|
|
userfilter: Option<String>,
|
2020-10-30 14:02:12 +00:00
|
|
|
since: Option<i64>,
|
2020-10-30 14:02:14 +00:00
|
|
|
until: Option<i64>,
|
2020-10-30 14:02:12 +00:00
|
|
|
typefilter: Option<String>,
|
|
|
|
statusfilter: Option<Vec<TaskStateType>>,
|
2019-04-07 10:18:58 +00:00
|
|
|
param: Value,
|
2020-05-18 07:57:35 +00:00
|
|
|
mut rpcenv: &mut dyn RpcEnvironment,
|
2020-01-28 10:22:06 +00:00
|
|
|
) -> Result<Vec<TaskListItem>, Error> {
|
2019-04-07 10:18:58 +00:00
|
|
|
|
2020-10-23 11:33:21 +00:00
|
|
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
2020-04-30 08:05:50 +00:00
|
|
|
let user_info = CachedUserInfo::new()?;
|
2020-10-23 11:33:21 +00:00
|
|
|
let user_privs = user_info.lookup_privs(&auth_id, &["system", "tasks"]);
|
2020-04-30 08:05:50 +00:00
|
|
|
|
|
|
|
let list_all = (user_privs & PRIV_SYS_AUDIT) != 0;
|
|
|
|
|
2019-12-11 11:53:34 +00:00
|
|
|
let store = param["store"].as_str();
|
|
|
|
|
2020-09-28 13:32:09 +00:00
|
|
|
let list = TaskListInfoIterator::new(running)?;
|
2020-10-30 14:02:11 +00:00
|
|
|
let limit = if limit > 0 { limit as usize } else { usize::MAX };
|
2019-04-07 11:17:19 +00:00
|
|
|
|
2020-09-28 13:32:09 +00:00
|
|
|
let result: Vec<TaskListItem> = list
|
2020-10-30 14:02:14 +00:00
|
|
|
.skip_while(|info| {
|
|
|
|
match (info, until) {
|
|
|
|
(Ok(info), Some(until)) => info.upid.starttime > until,
|
|
|
|
(Ok(_), None) => false,
|
|
|
|
(Err(_), _) => false,
|
|
|
|
}
|
|
|
|
})
|
2020-10-30 14:02:12 +00:00
|
|
|
.take_while(|info| {
|
|
|
|
match (info, since) {
|
|
|
|
(Ok(info), Some(since)) => info.upid.starttime > since,
|
|
|
|
(Ok(_), None) => true,
|
|
|
|
(Err(_), _) => false,
|
|
|
|
}
|
|
|
|
})
|
2020-09-28 13:32:09 +00:00
|
|
|
.filter_map(|info| {
|
|
|
|
let info = match info {
|
|
|
|
Ok(info) => info,
|
|
|
|
Err(_) => return None,
|
|
|
|
};
|
2020-04-30 08:05:50 +00:00
|
|
|
|
2020-10-15 09:27:47 +00:00
|
|
|
if !list_all && check_task_access(&auth_id, &info.upid).is_err() {
|
|
|
|
return None;
|
|
|
|
}
|
2019-04-07 10:18:58 +00:00
|
|
|
|
2020-10-23 11:33:21 +00:00
|
|
|
if let Some(needle) = &userfilter {
|
|
|
|
if !info.upid.auth_id.to_string().contains(needle) { return None; }
|
2019-04-07 11:17:19 +00:00
|
|
|
}
|
|
|
|
|
2019-12-11 11:53:34 +00:00
|
|
|
if let Some(store) = store {
|
2020-11-09 15:01:21 +00:00
|
|
|
if !check_job_store(&info.upid, store) {
|
|
|
|
return None;
|
2019-12-11 11:53:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-30 14:02:12 +00:00
|
|
|
if let Some(typefilter) = &typefilter {
|
|
|
|
if !info.upid.worker_type.contains(typefilter) {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match (&info.state, &statusfilter) {
|
|
|
|
(Some(_), _) if running => return None,
|
|
|
|
(Some(crate::server::TaskState::OK { .. }), _) if errors => return None,
|
|
|
|
(Some(state), Some(filters)) => {
|
|
|
|
if !filters.contains(&state.tasktype()) {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
(None, Some(_)) => return None,
|
2020-09-28 13:32:09 +00:00
|
|
|
_ => {},
|
2019-04-07 10:18:58 +00:00
|
|
|
}
|
|
|
|
|
2020-09-28 13:32:09 +00:00
|
|
|
Some(info.into())
|
|
|
|
}).skip(start as usize)
|
2020-10-30 14:02:11 +00:00
|
|
|
.take(limit)
|
2020-09-28 13:32:09 +00:00
|
|
|
.collect();
|
2019-04-07 10:18:58 +00:00
|
|
|
|
2020-09-28 13:32:09 +00:00
|
|
|
let mut count = result.len() + start as usize;
|
2021-01-19 09:27:59 +00:00
|
|
|
if !result.is_empty() && result.len() >= limit { // we have a 'virtual' entry as long as we have any new
|
2020-09-28 13:32:09 +00:00
|
|
|
count += 1;
|
2019-04-07 10:18:58 +00:00
|
|
|
}
|
|
|
|
|
2020-05-18 07:57:35 +00:00
|
|
|
rpcenv["total"] = Value::from(count);
|
2019-04-07 10:18:58 +00:00
|
|
|
|
2020-06-12 12:57:58 +00:00
|
|
|
Ok(result)
|
2019-04-07 10:18:58 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 12:10:49 +00:00
|
|
|
#[sortable]
|
2020-04-16 15:47:21 +00:00
|
|
|
const UPID_API_SUBDIRS: SubdirMap = &sorted!([
|
2019-11-21 08:36:41 +00:00
|
|
|
(
|
|
|
|
"log", &Router::new()
|
2020-04-16 15:47:21 +00:00
|
|
|
.get(&API_METHOD_READ_TASK_LOG)
|
2019-11-21 08:36:41 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
"status", &Router::new()
|
2020-04-16 15:47:21 +00:00
|
|
|
.get(&API_METHOD_GET_TASK_STATUS)
|
2019-11-21 08:36:41 +00:00
|
|
|
)
|
2020-04-16 15:47:21 +00:00
|
|
|
]);
|
2019-11-21 08:36:41 +00:00
|
|
|
|
|
|
|
pub const UPID_API_ROUTER: Router = Router::new()
|
|
|
|
.get(&list_subdirs_api_method!(UPID_API_SUBDIRS))
|
2020-04-16 15:47:21 +00:00
|
|
|
.delete(&API_METHOD_STOP_TASK)
|
2019-11-21 08:36:41 +00:00
|
|
|
.subdirs(&UPID_API_SUBDIRS);
|
|
|
|
|
|
|
|
pub const ROUTER: Router = Router::new()
|
2020-01-28 09:57:33 +00:00
|
|
|
.get(&API_METHOD_LIST_TASKS)
|
2019-11-21 08:36:41 +00:00
|
|
|
.match_all("upid", &UPID_API_ROUTER);
|