]> git.proxmox.com Git - pve-manager.git/blob - lib/PVE/API2/Tasks.pm
imported from svn 'pve-manager/pve2'
[pve-manager.git] / lib / PVE / API2 / Tasks.pm
1 package PVE::API2::Tasks;
2
3 use strict;
4 use warnings;
5 use POSIX;
6 use IO::File;
7 use File::ReadBackwards;
8 use PVE::Tools;
9 use PVE::SafeSyslog;
10 use PVE::RESTHandler;
11 use PVE::ProcFSTools;
12 use PVE::RPCEnvironment;
13 use PVE::JSONSchema qw(get_standard_option);
14 use PVE::AccessControl;
15
16 use base qw(PVE::RESTHandler);
17
18 __PACKAGE__->register_method({
19 name => 'node_tasks',
20 path => '',
21 method => 'GET',
22 permissions => { user => 'all' },
23 description => "Read task list for one node (finished tasks).",
24 proxyto => 'node',
25 parameters => {
26 additionalProperties => 0,
27 properties => {
28 node => get_standard_option('pve-node'),
29 start => {
30 type => 'integer',
31 minimum => 0,
32 optional => 1,
33 },
34 limit => {
35 type => 'integer',
36 minimum => 0,
37 optional => 1,
38 },
39 userfilter => {
40 type => 'string',
41 optional => 1,
42 },
43 errors => {
44 type => 'boolean',
45 optional => 1,
46 },
47 },
48 },
49 returns => {
50 type => 'array',
51 items => {
52 type => "object",
53 properties => {
54 upid => { type => 'string' },
55 },
56 },
57 links => [ { rel => 'child', href => "{upid}" } ],
58 },
59 code => sub {
60 my ($param) = @_;
61
62 my $rpcenv = PVE::RPCEnvironment::get();
63 my $user = $rpcenv->get_user();
64
65 my $res = [];
66
67 my $filename = "/var/log/pve/tasks/index";
68
69 my $node = $param->{node};
70 my $start = $param->{start} || 0;
71 my $limit = $param->{limit} || 50;
72 my $userfilter = $param->{userfilter};
73 my $errors = $param->{errors};
74
75 my $count = 0;
76 my $line;
77
78 my $auditor = $rpcenv->check($user, "/nodes/$node", [ 'Sys.Audit' ]);
79
80 my $parse_line = sub {
81 if ($line =~ m/^(\S+)(\s([0-9A-Za-z]{8})(\s(\S.*))?)?$/) {
82 my $upid = $1;
83 my $endtime = $3;
84 my $status = $5;
85 if ((my $task = PVE::Tools::upid_decode($upid, 1))) {
86 return if $userfilter && $task->{user} !~ m/\Q$userfilter\E/i;
87 next if !($auditor || $user eq $task->{user});
88
89 return if $errors && $status && $status eq 'OK';
90
91 return if $count++ < $start;
92 return if $limit <= 0;
93
94 $task->{upid} = $upid;
95 $task->{endtime} = hex($endtime) if $endtime;
96 $task->{status} = $status if $status;
97 push @$res, $task;
98 $limit--;
99 }
100 }
101 };
102
103 if (my $bw = File::ReadBackwards->new($filename)) {
104 while (defined ($line = $bw->readline)) {
105 &$parse_line();
106 }
107 $bw->close();
108 }
109 if (my $bw = File::ReadBackwards->new("$filename.1")) {
110 while (defined ($line = $bw->readline)) {
111 &$parse_line();
112 }
113 $bw->close();
114 }
115
116 $rpcenv->set_result_count($count);
117
118 return $res;
119 }});
120
121 __PACKAGE__->register_method({
122 name => 'upid_index',
123 path => '{upid}',
124 method => 'GET',
125 description => '', # index helper
126 permissions => { user => 'all' },
127 parameters => {
128 additionalProperties => 0,
129 properties => {
130 node => get_standard_option('pve-node'),
131 upid => { type => 'string' },
132 }
133 },
134 returns => {
135 type => 'array',
136 items => {
137 type => "object",
138 properties => {},
139 },
140 links => [ { rel => 'child', href => "{name}" } ],
141 },
142 code => sub {
143 my ($param) = @_;
144
145 return [
146 { name => 'log' },
147 { name => 'status' }
148 ];
149 }});
150
151 __PACKAGE__->register_method({
152 name => 'stop_task',
153 path => '{upid}',
154 method => 'DELETE',
155 description => 'Stop a task.',
156 permissions => { user => 'all' },
157 protected => 1,
158 proxyto => 'node',
159 parameters => {
160 additionalProperties => 0,
161 properties => {
162 node => get_standard_option('pve-node'),
163 upid => { type => 'string' },
164 }
165 },
166 returns => { type => 'null' },
167 code => sub {
168 my ($param) = @_;
169
170 my ($task, $filename) = PVE::Tools::upid_decode($param->{upid}, 1);
171 raise_param_exc({ upid => "unable to parse worker upid" }) if !$task;
172 raise_param_exc({ upid => "no such task" }) if ! -f $filename;
173
174 my $rpcenv = PVE::RPCEnvironment::get();
175 my $user = $rpcenv->get_user();
176 my $node = $param->{node};
177
178 my $sysadmin = $rpcenv->check($user, "/nodes/$node", [ 'Sys.Console' ]);
179 die "Permission check failed\n"
180 if !($sysadmin || $user eq $task->{user});
181
182 my $pstart = PVE::ProcFSTools::read_proc_starttime($task->{pid});
183 $task->{status} = ($pstart && ($pstart == $task->{pstart})) ?
184 'running' : 'stopped';
185
186 die "not implemented - fixme";
187
188 return undef;
189 }});
190
191 __PACKAGE__->register_method({
192 name => 'read_task_log',
193 path => '{upid}/log',
194 method => 'GET',
195 permissions => { user => 'all' },
196 protected => 1,
197 description => "Read task log.",
198 proxyto => 'node',
199 parameters => {
200 additionalProperties => 0,
201 properties => {
202 node => get_standard_option('pve-node'),
203 upid => { type => 'string' },
204 start => {
205 type => 'integer',
206 minimum => 0,
207 optional => 1,
208 },
209 limit => {
210 type => 'integer',
211 minimum => 0,
212 optional => 1,
213 },
214 },
215 },
216 returns => {
217 type => 'array',
218 items => {
219 type => "object",
220 properties => {
221 n => {
222 description=> "Line number",
223 type=> 'integer',
224 },
225 t => {
226 description=> "Line text",
227 type => 'string',
228 }
229 }
230 }
231 },
232 code => sub {
233 my ($param) = @_;
234
235 my ($task, $filename) = PVE::Tools::upid_decode($param->{upid}, 1);
236 raise_param_exc({ upid => "unable to parse worker upid" }) if !$task;
237
238 my $lines = [];
239
240 my $rpcenv = PVE::RPCEnvironment::get();
241 my $user = $rpcenv->get_user();
242 my $node = $param->{node};
243
244 my $auditor = $rpcenv->check($user, "/nodes/$node", [ 'Sys.Audit' ]);
245 die "Permission check failed\n"
246 if !($auditor || $user eq $task->{user});
247
248 my $fh = IO::File->new($filename, "r");
249 raise_param_exc({ upid => "no such task - unable to open file - $!" }) if !$fh;
250
251 my $start = $param->{start} || 0;
252 my $limit = $param->{limit} || 50;
253 my $count = 0;
254 my $line;
255 while (defined ($line = <$fh>)) {
256 next if $count++ < $start;
257 next if $limit <= 0;
258 chomp $line;
259 push @$lines, { n => $count, t => $line};
260 $limit--;
261 }
262
263 close($fh);
264
265 # HACK: ExtJS store.guaranteeRange() does not like empty array
266 # so we add a line
267 if (!$count) {
268 $count++;
269 push @$lines, { n => $count, t => "no content"};
270 }
271
272 $rpcenv->set_result_count($count);
273
274 return $lines;
275 }});
276
277 __PACKAGE__->register_method({
278 name => 'read_task_status',
279 path => '{upid}/status',
280 method => 'GET',
281 permissions => { user => 'all' },
282 protected => 1,
283 description => "Read task status.",
284 proxyto => 'node',
285 parameters => {
286 additionalProperties => 0,
287 properties => {
288 node => get_standard_option('pve-node'),
289 upid => { type => 'string' },
290 },
291 },
292 returns => {
293 type => "object",
294 properties => {
295 pid => {
296 type => 'integer'
297 },
298 status => {
299 type => 'string', enum => ['running', 'stopped'],
300 },
301 },
302 },
303 code => sub {
304 my ($param) = @_;
305
306 my ($task, $filename) = PVE::Tools::upid_decode($param->{upid}, 1);
307 raise_param_exc({ upid => "unable to parse worker upid" }) if !$task;
308 raise_param_exc({ upid => "no such task" }) if ! -f $filename;
309
310 my $lines = [];
311
312 my $rpcenv = PVE::RPCEnvironment::get();
313 my $user = $rpcenv->get_user();
314 my $node = $param->{node};
315
316 my $auditor = $rpcenv->check($user, "/nodes/$node", [ 'Sys.Audit' ]);
317 die "Permission check failed\n"
318 if !($auditor || $user eq $task->{user});
319
320 my $pstart = PVE::ProcFSTools::read_proc_starttime($task->{pid});
321 $task->{status} = ($pstart && ($pstart == $task->{pstart})) ?
322 'running' : 'stopped';
323
324 $task->{upid} = $param->{upid}; # include upid
325
326 return $task;
327 }});