]> git.proxmox.com Git - pmg-api.git/blob - PMG/API2/Nodes.pm
add ClamAV API, depend on clamav-unofficial-sigs
[pmg-api.git] / PMG / API2 / Nodes.pm
1 package PMG::API2::NodeInfo;
2
3 use strict;
4 use warnings;
5
6 use Time::Local qw(timegm_nocheck);
7
8 use PVE::INotify;
9 use PVE::RESTHandler;
10 use PVE::JSONSchema qw(get_standard_option);
11 use PVE::RESTEnvironment;
12 use PVE::SafeSyslog;
13
14 use PMG::Ticket;
15 use PMG::API2::Tasks;
16 use PMG::API2::Services;
17 use PMG::API2::Network;
18 use PMG::API2::ClamAV;
19
20 use base qw(PVE::RESTHandler);
21
22 __PACKAGE__->register_method ({
23 subclass => "PMG::API2::ClamAV",
24 path => 'clamav',
25 });
26
27 __PACKAGE__->register_method ({
28 subclass => "PMG::API2::Network",
29 path => 'network',
30 });
31
32 __PACKAGE__->register_method ({
33 subclass => "PMG::API2::Tasks",
34 path => 'tasks',
35 });
36
37 __PACKAGE__->register_method ({
38 subclass => "PMG::API2::Services",
39 path => 'services',
40 });
41
42 __PACKAGE__->register_method ({
43 name => 'index',
44 path => '',
45 method => 'GET',
46 permissions => { user => 'all' },
47 description => "Node index.",
48 parameters => {
49 additionalProperties => 0,
50 properties => {
51 node => get_standard_option('pve-node'),
52 },
53 },
54 returns => {
55 type => 'array',
56 items => {
57 type => "object",
58 properties => {},
59 },
60 links => [ { rel => 'child', href => "{name}" } ],
61 },
62 code => sub {
63 my ($param) = @_;
64
65 my $result = [
66 { name => 'clamav' },
67 { name => 'services' },
68 { name => 'syslog' },
69 { name => 'tasks' },
70 { name => 'time' },
71 { name => 'vncshell' },
72 ];
73
74 return $result;
75 }});
76
77 __PACKAGE__->register_method({
78 name => 'syslog',
79 path => 'syslog',
80 method => 'GET',
81 description => "Read system log",
82 proxyto => 'node',
83 protected => 1,
84 parameters => {
85 additionalProperties => 0,
86 properties => {
87 node => get_standard_option('pve-node'),
88 start => {
89 type => 'integer',
90 minimum => 0,
91 optional => 1,
92 },
93 limit => {
94 type => 'integer',
95 minimum => 0,
96 optional => 1,
97 },
98 since => {
99 type=> 'string',
100 pattern => '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$',
101 description => "Display all log since this date-time string.",
102 optional => 1,
103 },
104 'until' => {
105 type=> 'string',
106 pattern => '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$',
107 description => "Display all log until this date-time string.",
108 optional => 1,
109 },
110 },
111 },
112 returns => {
113 type => 'array',
114 items => {
115 type => "object",
116 properties => {
117 n => {
118 description=> "Line number",
119 type=> 'integer',
120 },
121 t => {
122 description=> "Line text",
123 type => 'string',
124 }
125 }
126 }
127 },
128 code => sub {
129 my ($param) = @_;
130
131 my $restenv = PVE::RESTEnvironment::get();
132
133 my ($count, $lines) = PVE::Tools::dump_journal($param->{start}, $param->{limit},
134 $param->{since}, $param->{'until'});
135
136 $restenv->set_result_attrib('total', $count);
137
138 return $lines;
139 }});
140
141 __PACKAGE__->register_method ({
142 name => 'vncshell',
143 path => 'vncshell',
144 method => 'POST',
145 protected => 1,
146 description => "Creates a VNC Shell proxy.",
147 parameters => {
148 additionalProperties => 0,
149 properties => {
150 node => get_standard_option('pve-node'),
151 websocket => {
152 optional => 1,
153 type => 'boolean',
154 description => "use websocket instead of standard vnc.",
155 default => 1,
156 },
157 },
158 },
159 returns => {
160 additionalProperties => 0,
161 properties => {
162 user => { type => 'string' },
163 ticket => { type => 'string' },
164 port => { type => 'integer' },
165 upid => { type => 'string' },
166 },
167 },
168 code => sub {
169 my ($param) = @_;
170
171 my $node = $param->{node};
172
173 # we only implement the websocket based VNC here
174 my $websocket = $param->{websocket} // 1;
175 die "standard VNC not implemented" if !$websocket;
176
177 my $authpath = "/nodes/$node";
178
179 my $restenv = PVE::RESTEnvironment->get();
180 my $user = $restenv->get_user();
181
182 my $ticket = PMG::Ticket::assemble_vnc_ticket($user, $authpath);
183
184 my $family = PVE::Tools::get_host_address_family($node);
185 my $port = PVE::Tools::next_vnc_port($family);
186
187 my $cmd = ['/usr/bin/vncterm', '-rfbport', $port,
188 '-timeout', 10, '-notls', '-listen', 'localhost',
189 '-c', '/usr/bin/top'];
190
191 my $realcmd = sub {
192 my $upid = shift;
193
194 syslog ('info', "starting vnc proxy $upid\n");
195
196 my $cmdstr = join (' ', @$cmd);
197 syslog ('info', "launch command: $cmdstr");
198
199 eval {
200 foreach my $k (keys %ENV) {
201 next if $k eq 'PATH' || $k eq 'TERM' || $k eq 'USER' || $k eq 'HOME';
202 delete $ENV{$k};
203 }
204 $ENV{PWD} = '/';
205
206 $ENV{PVE_VNC_TICKET} = $ticket; # pass ticket to vncterm
207
208 PVE::Tools::run_command($cmd, errmsg => "vncterm failed");
209 };
210 if (my $err = $@) {
211 syslog('err', $err);
212 }
213
214 return;
215 };
216
217 my $upid = $restenv->fork_worker('vncshell', "", $user, $realcmd);
218
219 PVE::Tools::wait_for_vnc_port($port);
220
221 return {
222 user => $user,
223 ticket => $ticket,
224 port => $port,
225 upid => $upid,
226 };
227 }});
228
229 __PACKAGE__->register_method({
230 name => 'vncwebsocket',
231 path => 'vncwebsocket',
232 method => 'GET',
233 description => "Opens a weksocket for VNC traffic.",
234 parameters => {
235 additionalProperties => 0,
236 properties => {
237 node => get_standard_option('pve-node'),
238 vncticket => {
239 description => "Ticket from previous call to vncproxy.",
240 type => 'string',
241 maxLength => 512,
242 },
243 port => {
244 description => "Port number returned by previous vncproxy call.",
245 type => 'integer',
246 minimum => 5900,
247 maximum => 5999,
248 },
249 },
250 },
251 returns => {
252 type => "object",
253 properties => {
254 port => { type => 'string' },
255 },
256 },
257 code => sub {
258 my ($param) = @_;
259
260 my $authpath = "/nodes/$param->{node}";
261
262 my $restenv = PVE::RESTEnvironment->get();
263 my $user = $restenv->get_user();
264
265 PMG::Ticket::verify_vnc_ticket($param->{vncticket}, $user, $authpath);
266
267 my $port = $param->{port};
268
269 return { port => $port };
270 }});
271
272 __PACKAGE__->register_method({
273 name => 'dns',
274 path => 'dns',
275 method => 'GET',
276 description => "Read DNS settings.",
277 proxyto => 'node',
278 parameters => {
279 additionalProperties => 0,
280 properties => {
281 node => get_standard_option('pve-node'),
282 },
283 },
284 returns => {
285 type => "object",
286 additionalProperties => 0,
287 properties => {
288 search => {
289 description => "Search domain for host-name lookup.",
290 type => 'string',
291 optional => 1,
292 },
293 dns1 => {
294 description => 'First name server IP address.',
295 type => 'string',
296 optional => 1,
297 },
298 dns2 => {
299 description => 'Second name server IP address.',
300 type => 'string',
301 optional => 1,
302 },
303 dns3 => {
304 description => 'Third name server IP address.',
305 type => 'string',
306 optional => 1,
307 },
308 },
309 },
310 code => sub {
311 my ($param) = @_;
312
313 my $res = PVE::INotify::read_file('resolvconf');
314
315 return $res;
316 }});
317
318 __PACKAGE__->register_method({
319 name => 'update_dns',
320 path => 'dns',
321 method => 'PUT',
322 description => "Write DNS settings.",
323 proxyto => 'node',
324 protected => 1,
325 parameters => {
326 additionalProperties => 0,
327 properties => {
328 node => get_standard_option('pve-node'),
329 search => {
330 description => "Search domain for host-name lookup.",
331 type => 'string',
332 },
333 dns1 => {
334 description => 'First name server IP address.',
335 type => 'string', format => 'ip',
336 optional => 1,
337 },
338 dns2 => {
339 description => 'Second name server IP address.',
340 type => 'string', format => 'ip',
341 optional => 1,
342 },
343 dns3 => {
344 description => 'Third name server IP address.',
345 type => 'string', format => 'ip',
346 optional => 1,
347 },
348 },
349 },
350 returns => { type => "null" },
351 code => sub {
352 my ($param) = @_;
353
354 PVE::INotify::update_file('resolvconf', $param);
355
356 return undef;
357 }});
358
359
360 __PACKAGE__->register_method({
361 name => 'time',
362 path => 'time',
363 method => 'GET',
364 description => "Read server time and time zone settings.",
365 proxyto => 'node',
366 parameters => {
367 additionalProperties => 0,
368 properties => {
369 node => get_standard_option('pve-node'),
370 },
371 },
372 returns => {
373 type => "object",
374 additionalProperties => 0,
375 properties => {
376 timezone => {
377 description => "Time zone",
378 type => 'string',
379 },
380 time => {
381 description => "Seconds since 1970-01-01 00:00:00 UTC.",
382 type => 'integer',
383 minimum => 1297163644,
384 },
385 localtime => {
386 description => "Seconds since 1970-01-01 00:00:00 (local time)",
387 type => 'integer',
388 minimum => 1297163644,
389 },
390 },
391 },
392 code => sub {
393 my ($param) = @_;
394
395 my $ctime = time();
396 my $ltime = timegm_nocheck(localtime($ctime));
397 my $res = {
398 timezone => PVE::INotify::read_file('timezone'),
399 time => time(),
400 localtime => $ltime,
401 };
402
403 return $res;
404 }});
405
406 __PACKAGE__->register_method({
407 name => 'set_timezone',
408 path => 'time',
409 method => 'PUT',
410 description => "Set time zone.",
411 proxyto => 'node',
412 protected => 1,
413 parameters => {
414 additionalProperties => 0,
415 properties => {
416 node => get_standard_option('pve-node'),
417 timezone => {
418 description => "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.",
419 type => 'string',
420 },
421 },
422 },
423 returns => { type => "null" },
424 code => sub {
425 my ($param) = @_;
426
427 PVE::INotify::write_file('timezone', $param->{timezone});
428
429 return undef;
430 }});
431
432
433 package PMG::API2::Nodes;
434
435 use strict;
436 use warnings;
437
438 use PVE::RESTHandler;
439 use PVE::JSONSchema qw(get_standard_option);
440
441 use base qw(PVE::RESTHandler);
442
443 __PACKAGE__->register_method ({
444 subclass => "PMG::API2::NodeInfo",
445 path => '{node}',
446 });
447
448 __PACKAGE__->register_method ({
449 name => 'index',
450 path => '',
451 method => 'GET',
452 permissions => { user => 'all' },
453 description => "Cluster node index.",
454 parameters => {
455 additionalProperties => 0,
456 properties => {},
457 },
458 returns => {
459 type => 'array',
460 items => {
461 type => "object",
462 properties => {},
463 },
464 links => [ { rel => 'child', href => "{node}" } ],
465 },
466 code => sub {
467 my ($param) = @_;
468
469 my $nodename = PVE::INotify::nodename();
470 my $res = [
471 { node => $nodename },
472 ];
473
474 return $res;
475 }});
476
477
478 1;