2 use std
::io
::{BufRead, BufReader}
;
5 use serde_json
::{json, Value}
;
7 use proxmox
::{sortable, identity}
;
8 use proxmox
::api
::list_subdirs_api_method
;
9 use proxmox
::api
::{ApiHandler, ApiMethod, Router, RpcEnvironment}
;
10 use proxmox
::api
::router
::SubdirMap
;
11 use proxmox
::api
::schema
::*;
14 use crate::api2
::types
::*;
15 use crate::server
::{self, UPID}
;
20 _rpcenv
: &mut dyn RpcEnvironment
,
21 ) -> Result
<Value
, Error
> {
23 let upid
= extract_upid(¶m
)?
;
25 let mut result
= json
!({
26 "upid": param
["upid"],
29 "pstart": upid
.pstart
,
30 "starttime": upid
.starttime
,
31 "type": upid
.worker_type
,
33 "user": upid
.username
,
36 if crate::server
::worker_is_active(&upid
) {
37 result
["status"] = Value
::from("running");
39 let exitstatus
= crate::server
::upid_read_status(&upid
).unwrap_or(String
::from("unknown"));
40 result
["status"] = Value
::from("stopped");
41 result
["exitstatus"] = Value
::from(exitstatus
);
47 fn extract_upid(param
: &Value
) -> Result
<UPID
, Error
> {
49 let upid_str
= tools
::required_string_param(¶m
, "upid")?
;
51 upid_str
.parse
::<UPID
>()
57 rpcenv
: &mut dyn RpcEnvironment
,
58 ) -> Result
<Value
, Error
> {
60 let upid
= extract_upid(¶m
)?
;
62 let test_status
= param
["test-status"].as_bool().unwrap_or(false);
64 let start
= param
["start"].as_u64().unwrap_or(0);
65 let mut limit
= param
["limit"].as_u64().unwrap_or(50);
67 let mut count
: u64 = 0;
69 let path
= upid
.log_path();
71 let file
= File
::open(path
)?
;
73 let mut lines
: Vec
<Value
> = vec
![];
75 for line
in BufReader
::new(file
).lines() {
79 if count
< start { continue }
;
80 if limit
== 0 { continue }
;
82 lines
.push(json
!({ "n": count, "t": line }
));
87 log
::error
!("reading task log failed: {}", err
);
93 rpcenv
.set_result_attrib("total", Value
::from(count
));
96 let active
= crate::server
::worker_is_active(&upid
);
97 rpcenv
.set_result_attrib("active", Value
::from(active
));
106 _rpcenv
: &mut dyn RpcEnvironment
,
107 ) -> Result
<Value
, Error
> {
109 let upid
= extract_upid(¶m
)?
;
111 if crate::server
::worker_is_active(&upid
) {
112 server
::abort_worker_async(upid
);
121 rpcenv
: &mut dyn RpcEnvironment
,
122 ) -> Result
<Value
, Error
> {
124 let start
= param
["start"].as_u64().unwrap_or(0);
125 let limit
= param
["limit"].as_u64().unwrap_or(50);
126 let errors
= param
["errors"].as_bool().unwrap_or(false);
127 let running
= param
["running"].as_bool().unwrap_or(false);
129 let store
= param
["store"].as_str();
131 let userfilter
= param
["userfilter"].as_str();
133 let list
= server
::read_task_list()?
;
135 let mut result
= vec
![];
139 for info
in list
.iter() {
140 let mut entry
= json
!({
141 "upid": info
.upid_str
,
143 "pid": info
.upid
.pid
,
144 "pstart": info
.upid
.pstart
,
145 "starttime": info
.upid
.starttime
,
146 "type": info
.upid
.worker_type
,
147 "id": info
.upid
.worker_id
,
148 "user": info
.upid
.username
,
151 if let Some(username
) = userfilter
{
152 if !info
.upid
.username
.contains(username
) { continue; }
155 if let Some(store
) = store
{
156 // Note: useful to select all tasks spawned by proxmox-backup-client
157 let worker_id
= match &info
.upid
.worker_id
{
159 None
=> continue, // skip
162 if info
.upid
.worker_type
== "backup" || info
.upid
.worker_type
== "restore" ||
163 info
.upid
.worker_type
== "prune"
165 let prefix
= format
!("{}_", store
);
166 if !worker_id
.starts_with(&prefix
) { continue; }
167 } else if info
.upid
.worker_type
== "garbage_collection" {
168 if worker_id
!= store { continue; }
174 if let Some(ref state
) = info
.state
{
175 if running { continue; }
176 if errors
&& state
.1 == "OK" {
180 entry
["endtime"] = Value
::from(state
.0);
181 entry
["status"] = Value
::from(state
.1.clone());
184 if (count
as u64) < start
{
191 if (result
.len() as u64) < limit { result.push(entry); }
;
194 rpcenv
.set_result_attrib("total", Value
::from(count
));
200 const UPID_API_SUBDIRS
: SubdirMap
= &[
202 "log", &Router
::new()
205 &ApiHandler
::Sync(&read_task_log
),
209 ("node", false, &NODE_SCHEMA
),
213 "Test task status, and set result attribute \"active\" accordingly."
216 ("upid", false, &UPID_SCHEMA
),
217 ("start", true, &IntegerSchema
::new("Start at this line.")
222 ("limit", true, &IntegerSchema
::new("Only list this amount of lines.")
233 "status", &Router
::new()
236 &ApiHandler
::Sync(&get_task_status
),
240 ("node", false, &NODE_SCHEMA
),
241 ("upid", false, &UPID_SCHEMA
),
250 pub const UPID_API_ROUTER
: Router
= Router
::new()
251 .get(&list_subdirs_api_method
!(UPID_API_SUBDIRS
))
254 &ApiHandler
::Sync(&stop_task
),
256 "Try to stop a task.",
258 ("node", false, &NODE_SCHEMA
),
259 ("upid", false, &UPID_SCHEMA
),
264 .subdirs(&UPID_API_SUBDIRS
);
267 pub const ROUTER
: Router
= Router
::new()
270 &ApiHandler
::Sync(&list_tasks
),
274 ("node", false, &NODE_SCHEMA
),
275 ("start", true, &IntegerSchema
::new("List tasks beginning from this offset.")
280 ("limit", true, &IntegerSchema
::new("Only list this amount of tasks.")
285 ("store", true, &DATASTORE_SCHEMA
),
286 ("running", true, &BooleanSchema
::new("Only list running tasks.").schema()),
287 ("errors", true, &BooleanSchema
::new("Only list erroneous tasks.").schema()),
288 ("userfilter", true, &StringSchema
::new("Only list tasks from this user.").schema()),
293 .match_all("upid", &UPID_API_ROUTER
);