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
|
|
|
|
2019-11-21 13:53:15 +00:00
|
|
|
use failure::*;
|
2019-04-07 10:18:58 +00:00
|
|
|
use serde_json::{json, Value};
|
|
|
|
|
2019-11-21 12:10:49 +00:00
|
|
|
use proxmox::{sortable, identity};
|
2019-11-21 13:53:15 +00:00
|
|
|
use proxmox::api::list_subdirs_api_method;
|
|
|
|
use proxmox::api::{ApiHandler, ApiMethod, Router, RpcEnvironment};
|
|
|
|
use proxmox::api::router::SubdirMap;
|
|
|
|
use proxmox::api::schema::*;
|
2019-11-21 12:10:49 +00:00
|
|
|
|
|
|
|
use crate::tools;
|
2019-05-09 05:44:09 +00:00
|
|
|
use crate::api2::types::*;
|
2019-04-07 12:36:57 +00:00
|
|
|
use crate::server::{self, UPID};
|
|
|
|
|
|
|
|
fn get_task_status(
|
|
|
|
param: Value,
|
|
|
|
_info: &ApiMethod,
|
2019-06-07 11:10:56 +00:00
|
|
|
_rpcenv: &mut dyn RpcEnvironment,
|
2019-04-07 12:36:57 +00:00
|
|
|
) -> Result<Value, Error> {
|
|
|
|
|
|
|
|
let upid = extract_upid(¶m)?;
|
|
|
|
|
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,
|
|
|
|
"user": upid.username,
|
|
|
|
});
|
|
|
|
|
|
|
|
if crate::server::worker_is_active(&upid) {
|
|
|
|
result["status"] = Value::from("running");
|
2019-04-07 12:36:57 +00:00
|
|
|
} else {
|
2019-04-09 13:12:20 +00:00
|
|
|
let exitstatus = crate::server::upid_read_status(&upid).unwrap_or(String::from("unknown"));
|
|
|
|
result["status"] = Value::from("stopped");
|
|
|
|
result["exitstatus"] = Value::from(exitstatus);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
fn read_task_log(
|
|
|
|
param: Value,
|
|
|
|
_info: &ApiMethod,
|
2019-06-07 11:10:56 +00:00
|
|
|
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
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-09 12:43:30 +00:00
|
|
|
rpcenv.set_result_attrib("total", Value::from(count));
|
|
|
|
|
2019-12-07 14:29:42 +00:00
|
|
|
if test_status {
|
|
|
|
let active = crate::server::worker_is_active(&upid);
|
|
|
|
rpcenv.set_result_attrib("active", Value::from(active));
|
|
|
|
}
|
|
|
|
|
2019-04-07 12:36:57 +00:00
|
|
|
Ok(json!(lines))
|
|
|
|
}
|
2019-04-07 10:18:58 +00:00
|
|
|
|
2019-04-10 11:55:05 +00:00
|
|
|
fn stop_task(
|
|
|
|
param: Value,
|
|
|
|
_info: &ApiMethod,
|
2019-06-07 11:10:56 +00:00
|
|
|
_rpcenv: &mut dyn RpcEnvironment,
|
2019-04-10 11:55:05 +00:00
|
|
|
) -> Result<Value, Error> {
|
|
|
|
|
|
|
|
let upid = extract_upid(¶m)?;
|
|
|
|
|
|
|
|
if crate::server::worker_is_active(&upid) {
|
|
|
|
server::abort_worker_async(upid);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Value::Null)
|
|
|
|
}
|
|
|
|
|
2019-04-07 10:18:58 +00:00
|
|
|
fn list_tasks(
|
|
|
|
param: Value,
|
|
|
|
_info: &ApiMethod,
|
2019-06-07 11:10:56 +00:00
|
|
|
rpcenv: &mut dyn RpcEnvironment,
|
2019-04-07 10:18:58 +00:00
|
|
|
) -> Result<Value, Error> {
|
|
|
|
|
|
|
|
let start = param["start"].as_u64().unwrap_or(0);
|
|
|
|
let limit = param["limit"].as_u64().unwrap_or(50);
|
|
|
|
let errors = param["errors"].as_bool().unwrap_or(false);
|
2019-12-11 09:52:27 +00:00
|
|
|
let running = param["running"].as_bool().unwrap_or(false);
|
2019-04-07 10:18:58 +00:00
|
|
|
|
2019-12-11 11:53:34 +00:00
|
|
|
let store = param["store"].as_str();
|
|
|
|
|
2019-04-07 11:17:19 +00:00
|
|
|
let userfilter = param["userfilter"].as_str();
|
|
|
|
|
2019-04-07 10:18:58 +00:00
|
|
|
let list = server::read_task_list()?;
|
|
|
|
|
|
|
|
let mut result = vec![];
|
|
|
|
|
|
|
|
let mut count = 0;
|
|
|
|
|
|
|
|
for info in list.iter() {
|
|
|
|
let mut entry = json!({
|
|
|
|
"upid": info.upid_str,
|
|
|
|
"node": "localhost",
|
|
|
|
"pid": info.upid.pid,
|
|
|
|
"pstart": info.upid.pstart,
|
|
|
|
"starttime": info.upid.starttime,
|
|
|
|
"type": info.upid.worker_type,
|
|
|
|
"id": info.upid.worker_id,
|
|
|
|
"user": info.upid.username,
|
|
|
|
});
|
|
|
|
|
2019-04-07 11:17:19 +00:00
|
|
|
if let Some(username) = userfilter {
|
|
|
|
if !info.upid.username.contains(username) { continue; }
|
|
|
|
}
|
|
|
|
|
2019-12-11 11:53:34 +00:00
|
|
|
if let Some(store) = store {
|
|
|
|
// Note: useful to select all tasks spawned by proxmox-backup-client
|
|
|
|
let worker_id = match &info.upid.worker_id {
|
|
|
|
Some(w) => w,
|
|
|
|
None => continue, // skip
|
|
|
|
};
|
|
|
|
|
|
|
|
if info.upid.worker_type == "backup" || info.upid.worker_type == "restore" {
|
|
|
|
let prefix = format!("{}_", store);
|
|
|
|
if !worker_id.starts_with(&prefix) { continue; }
|
|
|
|
} else if info.upid.worker_type == "prune" || info.upid.worker_type == "garbage_collection" {
|
|
|
|
if worker_id != store { continue; }
|
|
|
|
} else {
|
|
|
|
continue; // skip
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-07 10:18:58 +00:00
|
|
|
if let Some(ref state) = info.state {
|
2019-12-11 09:52:27 +00:00
|
|
|
if running { continue; }
|
2019-04-07 10:18:58 +00:00
|
|
|
if errors && state.1 == "OK" {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry["endtime"] = Value::from(state.0);
|
|
|
|
entry["status"] = Value::from(state.1.clone());
|
|
|
|
}
|
|
|
|
|
2019-04-07 10:41:24 +00:00
|
|
|
if (count as u64) < start {
|
2019-04-07 10:18:58 +00:00
|
|
|
count += 1;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.len() as u64) < limit { result.push(entry); };
|
|
|
|
}
|
|
|
|
|
|
|
|
rpcenv.set_result_attrib("total", Value::from(count));
|
|
|
|
|
|
|
|
Ok(json!(result))
|
|
|
|
}
|
|
|
|
|
2019-11-21 12:10:49 +00:00
|
|
|
#[sortable]
|
2019-11-21 08:36:41 +00:00
|
|
|
const UPID_API_SUBDIRS: SubdirMap = &[
|
|
|
|
(
|
|
|
|
"log", &Router::new()
|
|
|
|
.get(
|
|
|
|
&ApiMethod::new(
|
|
|
|
&ApiHandler::Sync(&read_task_log),
|
|
|
|
&ObjectSchema::new(
|
|
|
|
"Read task log.",
|
2019-11-21 12:10:49 +00:00
|
|
|
&sorted!([
|
2019-11-21 08:36:41 +00:00
|
|
|
("node", false, &NODE_SCHEMA),
|
2019-12-07 14:29:42 +00:00
|
|
|
( "test-status",
|
|
|
|
true,
|
|
|
|
&BooleanSchema::new(
|
|
|
|
"Test task status, and set result attribute \"active\" accordingly."
|
|
|
|
).schema()
|
|
|
|
),
|
2019-11-21 08:36:41 +00:00
|
|
|
("upid", false, &UPID_SCHEMA),
|
|
|
|
("start", true, &IntegerSchema::new("Start at this line.")
|
|
|
|
.minimum(0)
|
|
|
|
.default(0)
|
|
|
|
.schema()
|
|
|
|
),
|
|
|
|
("limit", true, &IntegerSchema::new("Only list this amount of lines.")
|
|
|
|
.minimum(0)
|
|
|
|
.default(50)
|
|
|
|
.schema()
|
|
|
|
),
|
2019-11-21 12:10:49 +00:00
|
|
|
]),
|
2019-04-07 12:36:57 +00:00
|
|
|
)
|
|
|
|
)
|
2019-11-21 08:36:41 +00:00
|
|
|
)
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"status", &Router::new()
|
|
|
|
.get(
|
|
|
|
&ApiMethod::new(
|
|
|
|
&ApiHandler::Sync(&get_task_status),
|
|
|
|
&ObjectSchema::new(
|
|
|
|
"Get task status.",
|
2019-11-21 12:10:49 +00:00
|
|
|
&sorted!([
|
2019-11-21 08:36:41 +00:00
|
|
|
("node", false, &NODE_SCHEMA),
|
|
|
|
("upid", false, &UPID_SCHEMA),
|
2019-11-21 12:10:49 +00:00
|
|
|
]),
|
2019-11-21 08:36:41 +00:00
|
|
|
)
|
2019-04-07 11:17:19 +00:00
|
|
|
)
|
2019-11-21 08:36:41 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
];
|
|
|
|
|
2019-11-21 12:10:49 +00:00
|
|
|
#[sortable]
|
2019-11-21 08:36:41 +00:00
|
|
|
pub const UPID_API_ROUTER: Router = Router::new()
|
|
|
|
.get(&list_subdirs_api_method!(UPID_API_SUBDIRS))
|
|
|
|
.delete(
|
|
|
|
&ApiMethod::new(
|
|
|
|
&ApiHandler::Sync(&stop_task),
|
|
|
|
&ObjectSchema::new(
|
|
|
|
"Try to stop a task.",
|
2019-11-21 12:10:49 +00:00
|
|
|
&sorted!([
|
2019-11-21 08:36:41 +00:00
|
|
|
("node", false, &NODE_SCHEMA),
|
|
|
|
("upid", false, &UPID_SCHEMA),
|
2019-11-21 12:10:49 +00:00
|
|
|
]),
|
2019-11-21 08:36:41 +00:00
|
|
|
)
|
|
|
|
).protected(true)
|
|
|
|
)
|
|
|
|
.subdirs(&UPID_API_SUBDIRS);
|
|
|
|
|
2019-11-21 12:10:49 +00:00
|
|
|
#[sortable]
|
2019-11-21 08:36:41 +00:00
|
|
|
pub const ROUTER: Router = Router::new()
|
|
|
|
.get(
|
|
|
|
&ApiMethod::new(
|
|
|
|
&ApiHandler::Sync(&list_tasks),
|
|
|
|
&ObjectSchema::new(
|
|
|
|
"List tasks.",
|
2019-11-21 12:10:49 +00:00
|
|
|
&sorted!([
|
2019-11-21 08:36:41 +00:00
|
|
|
("node", false, &NODE_SCHEMA),
|
|
|
|
("start", true, &IntegerSchema::new("List tasks beginning from this offset.")
|
|
|
|
.minimum(0)
|
|
|
|
.default(0)
|
|
|
|
.schema()
|
|
|
|
),
|
|
|
|
("limit", true, &IntegerSchema::new("Only list this amount of tasks.")
|
|
|
|
.minimum(0)
|
|
|
|
.default(50)
|
|
|
|
.schema()
|
|
|
|
),
|
2019-12-11 11:53:34 +00:00
|
|
|
("store", true, &StringSchema::new("Only lists tasks for datastore name.").schema()),
|
2019-12-11 09:52:27 +00:00
|
|
|
("running", true, &BooleanSchema::new("Only list running tasks.").schema()),
|
2019-11-21 08:36:41 +00:00
|
|
|
("errors", true, &BooleanSchema::new("Only list erroneous tasks.").schema()),
|
|
|
|
("userfilter", true, &StringSchema::new("Only list tasks from this user.").schema()),
|
2019-11-21 12:10:49 +00:00
|
|
|
]),
|
2019-11-21 08:36:41 +00:00
|
|
|
)
|
2019-04-07 12:36:57 +00:00
|
|
|
)
|
2019-11-21 08:36:41 +00:00
|
|
|
)
|
|
|
|
.match_all("upid", &UPID_API_ROUTER);
|