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