]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/node/tasks.rs
src/api2/admin/datastore/backup/service.rs: move service code into extra file
[proxmox-backup.git] / src / api2 / node / tasks.rs
CommitLineData
063ca5be
DM
1use failure::*;
2
5a12c0e2 3use crate::tools;
063ca5be
DM
4use crate::api_schema::*;
5use crate::api_schema::router::*;
6use serde_json::{json, Value};
5a12c0e2
DM
7use std::sync::Arc;
8use std::fs::File;
9use std::io::{BufRead,BufReader};
063ca5be 10
5a12c0e2
DM
11use crate::server::{self, UPID};
12
13fn get_task_status(
14 param: Value,
15 _info: &ApiMethod,
16 _rpcenv: &mut RpcEnvironment,
17) -> Result<Value, Error> {
18
19 let upid = extract_upid(&param)?;
20
c360bd73
DM
21 let mut result = json!({
22 "upid": param["upid"],
23 "node": upid.node,
24 "pid": upid.pid,
25 "pstart": upid.pstart,
26 "starttime": upid.starttime,
27 "type": upid.worker_type,
28 "id": upid.worker_id,
29 "user": upid.username,
30 });
31
32 if crate::server::worker_is_active(&upid) {
33 result["status"] = Value::from("running");
5a12c0e2 34 } else {
c360bd73
DM
35 let exitstatus = crate::server::upid_read_status(&upid).unwrap_or(String::from("unknown"));
36 result["status"] = Value::from("stopped");
37 result["exitstatus"] = Value::from(exitstatus);
5a12c0e2
DM
38 };
39
40 Ok(result)
41}
42
43fn extract_upid(param: &Value) -> Result<UPID, Error> {
44
45 let upid_str = tools::required_string_param(&param, "upid")?;
46
47 let upid = match upid_str.parse::<UPID>() {
48 Ok(v) => v,
49 Err(err) => bail!("unable to parse UPID '{}' - {}", upid_str, err),
50 };
51
52 Ok(upid)
53}
54
55fn read_task_log(
56 param: Value,
57 _info: &ApiMethod,
d8d40dd0 58 rpcenv: &mut RpcEnvironment,
5a12c0e2
DM
59) -> Result<Value, Error> {
60
61 let upid = extract_upid(&param)?;
62 let start = param["start"].as_u64().unwrap_or(0);
63 let mut limit = param["limit"].as_u64().unwrap_or(50);
64 let mut count: u64 = 0;
65
66 let path = upid.log_path();
67
68 let file = File::open(path)?;
69
70 let mut lines: Vec<Value> = vec![];
71
72 for line in BufReader::new(file).lines() {
73 match line {
74 Ok(line) => {
75 count += 1;
76 if count < start { continue };
77 if limit <= 0 { continue };
78
79 lines.push(json!({ "n": count, "t": line }));
80
81 limit -= 1;
82 }
83 Err(err) => {
84 log::error!("reading task log failed: {}", err);
85 break;
86 }
87 }
88 }
89
d8d40dd0
DM
90 rpcenv.set_result_attrib("total", Value::from(count));
91
5a12c0e2
DM
92 Ok(json!(lines))
93}
063ca5be 94
a665dea1
DM
95fn stop_task(
96 param: Value,
97 _info: &ApiMethod,
98 _rpcenv: &mut RpcEnvironment,
99) -> Result<Value, Error> {
100
101 let upid = extract_upid(&param)?;
102
103 if crate::server::worker_is_active(&upid) {
104 server::abort_worker_async(upid);
105 }
106
107 Ok(Value::Null)
108}
109
063ca5be
DM
110fn list_tasks(
111 param: Value,
112 _info: &ApiMethod,
113 rpcenv: &mut RpcEnvironment,
114) -> Result<Value, Error> {
115
116 let start = param["start"].as_u64().unwrap_or(0);
117 let limit = param["limit"].as_u64().unwrap_or(50);
118 let errors = param["errors"].as_bool().unwrap_or(false);
119
d2a2e02b
DM
120 let userfilter = param["userfilter"].as_str();
121
063ca5be
DM
122 let list = server::read_task_list()?;
123
124 let mut result = vec![];
125
126 let mut count = 0;
127
128 for info in list.iter() {
129 let mut entry = json!({
130 "upid": info.upid_str,
131 "node": "localhost",
132 "pid": info.upid.pid,
133 "pstart": info.upid.pstart,
134 "starttime": info.upid.starttime,
135 "type": info.upid.worker_type,
136 "id": info.upid.worker_id,
137 "user": info.upid.username,
138 });
139
d2a2e02b
DM
140 if let Some(username) = userfilter {
141 if !info.upid.username.contains(username) { continue; }
142 }
143
063ca5be
DM
144 if let Some(ref state) = info.state {
145 if errors && state.1 == "OK" {
146 continue;
147 }
148
149 entry["endtime"] = Value::from(state.0);
150 entry["status"] = Value::from(state.1.clone());
151 }
152
3c3bee2e 153 if (count as u64) < start {
063ca5be
DM
154 count += 1;
155 continue;
156 } else {
157 count += 1;
158 }
159
160 if (result.len() as u64) < limit { result.push(entry); };
161 }
162
163 rpcenv.set_result_attrib("total", Value::from(count));
164
165 Ok(json!(result))
166}
167
168pub fn router() -> Router {
169
d8d40dd0 170 let upid_schema: Arc<Schema> = Arc::new(
5a12c0e2
DM
171 StringSchema::new("Unique Process/Task ID.")
172 .max_length(256)
173 .into()
174 );
175
176 let upid_api = Router::new()
a665dea1
DM
177 .delete(ApiMethod::new(
178 stop_task,
179 ObjectSchema::new("Try to stop a task.")
180 .required("node", crate::api2::node::NODE_SCHEMA.clone())
181 .required("upid", upid_schema.clone())).protected(true)
182
183 )
5a12c0e2
DM
184 .subdir(
185 "log", Router::new()
186 .get(
187 ApiMethod::new(
188 read_task_log,
189 ObjectSchema::new("Read task log.")
d8d40dd0 190 .required("node", crate::api2::node::NODE_SCHEMA.clone())
5a12c0e2
DM
191 .required("upid", upid_schema.clone())
192 .optional(
193 "start",
194 IntegerSchema::new("Start at this line.")
195 .minimum(0)
196 .default(0)
197 )
198 .optional(
199 "limit",
200 IntegerSchema::new("Only list this amount of lines.")
201 .minimum(0)
202 .default(50)
203 )
204 )
205 )
206 )
207 .subdir(
208 "status", Router::new()
209 .get(
210 ApiMethod::new(
211 get_task_status,
212 ObjectSchema::new("Get task status.")
d8d40dd0 213 .required("node", crate::api2::node::NODE_SCHEMA.clone())
5a12c0e2
DM
214 .required("upid", upid_schema.clone()))
215 )
13f1cc17
DM
216 )
217 .list_subdirs();
5a12c0e2
DM
218
219
063ca5be
DM
220 let route = Router::new()
221 .get(ApiMethod::new(
222 list_tasks,
223 ObjectSchema::new("List tasks.")
d8d40dd0 224 .required("node", crate::api2::node::NODE_SCHEMA.clone())
063ca5be
DM
225 .optional(
226 "start",
227 IntegerSchema::new("List tasks beginning from this offset.")
228 .minimum(0)
229 .default(0)
230 )
231 .optional(
232 "limit",
233 IntegerSchema::new("Only list this amount of tasks.")
234 .minimum(0)
235 .default(50)
236 )
237 .optional(
238 "errors",
239 BooleanSchema::new("Only list erroneous tasks.")
240 )
d2a2e02b
DM
241 .optional(
242 "userfilter",
243 StringSchema::new("Only list tasks from this user.")
244 )
245 )
5a12c0e2
DM
246 )
247 .match_all("upid", upid_api);
063ca5be
DM
248
249 route
250}