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