]>
Commit | Line | Data |
---|---|---|
1360e6f0 DM |
1 | package PMG::API2::NodeInfo; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
d934c136 | 5 | use Time::Local qw(timegm_nocheck); |
c1f5acda | 6 | use Filesys::Df; |
ba11e2d3 | 7 | use Data::Dumper; |
d934c136 | 8 | |
1360e6f0 DM |
9 | use PVE::INotify; |
10 | use PVE::RESTHandler; | |
11 | use PVE::JSONSchema qw(get_standard_option); | |
9d82c6bc | 12 | use PMG::RESTEnvironment; |
1360e6f0 | 13 | use PVE::SafeSyslog; |
c1f5acda | 14 | use PVE::ProcFSTools; |
1360e6f0 | 15 | |
c1f5acda | 16 | use PMG::pmgcfg; |
1360e6f0 | 17 | use PMG::Ticket; |
87952a8d | 18 | use PMG::API2::Subscription; |
cc115a48 | 19 | use PMG::API2::APT; |
fa04fcb4 | 20 | use PMG::API2::Tasks; |
163fb58f | 21 | use PMG::API2::Services; |
2551682a | 22 | use PMG::API2::Network; |
d17c5265 | 23 | use PMG::API2::ClamAV; |
b00d2d73 | 24 | use PMG::API2::SpamAssassin; |
70805f7d | 25 | use PMG::API2::Postfix; |
202c952a | 26 | use PMG::API2::MailTracker; |
464f7494 | 27 | use PMG::API2::Backup; |
1360e6f0 DM |
28 | |
29 | use base qw(PVE::RESTHandler); | |
30 | ||
70805f7d DM |
31 | __PACKAGE__->register_method ({ |
32 | subclass => "PMG::API2::Postfix", | |
33 | path => 'postfix', | |
34 | }); | |
35 | ||
d17c5265 DM |
36 | __PACKAGE__->register_method ({ |
37 | subclass => "PMG::API2::ClamAV", | |
38 | path => 'clamav', | |
39 | }); | |
40 | ||
b00d2d73 DC |
41 | __PACKAGE__->register_method ({ |
42 | subclass => "PMG::API2::SpamAssassin", | |
43 | path => 'spamassassin', | |
44 | }); | |
45 | ||
2551682a DM |
46 | __PACKAGE__->register_method ({ |
47 | subclass => "PMG::API2::Network", | |
48 | path => 'network', | |
49 | }); | |
50 | ||
fa04fcb4 DM |
51 | __PACKAGE__->register_method ({ |
52 | subclass => "PMG::API2::Tasks", | |
53 | path => 'tasks', | |
54 | }); | |
55 | ||
163fb58f DM |
56 | __PACKAGE__->register_method ({ |
57 | subclass => "PMG::API2::Services", | |
58 | path => 'services', | |
59 | }); | |
60 | ||
87952a8d DM |
61 | __PACKAGE__->register_method ({ |
62 | subclass => "PMG::API2::Subscription", | |
63 | path => 'subscription', | |
64 | }); | |
65 | ||
cc115a48 DM |
66 | __PACKAGE__->register_method ({ |
67 | subclass => "PMG::API2::APT", | |
68 | path => 'apt', | |
69 | }); | |
70 | ||
202c952a DM |
71 | __PACKAGE__->register_method ({ |
72 | subclass => "PMG::API2::MailTracker", | |
73 | path => 'tracker', | |
74 | }); | |
75 | ||
464f7494 DM |
76 | __PACKAGE__->register_method ({ |
77 | subclass => "PMG::API2::Backup", | |
78 | path => 'backup', | |
79 | }); | |
80 | ||
1360e6f0 DM |
81 | __PACKAGE__->register_method ({ |
82 | name => 'index', | |
83 | path => '', | |
84 | method => 'GET', | |
85 | permissions => { user => 'all' }, | |
86 | description => "Node index.", | |
87 | parameters => { | |
88 | additionalProperties => 0, | |
89 | properties => { | |
90 | node => get_standard_option('pve-node'), | |
91 | }, | |
92 | }, | |
93 | returns => { | |
94 | type => 'array', | |
95 | items => { | |
96 | type => "object", | |
97 | properties => {}, | |
98 | }, | |
99 | links => [ { rel => 'child', href => "{name}" } ], | |
100 | }, | |
101 | code => sub { | |
102 | my ($param) = @_; | |
103 | ||
104 | my $result = [ | |
cc115a48 | 105 | { name => 'apt' }, |
464f7494 | 106 | { name => 'backup' }, |
d17c5265 | 107 | { name => 'clamav' }, |
b00d2d73 | 108 | { name => 'spamassassin' }, |
70805f7d | 109 | { name => 'postfix' }, |
163fb58f | 110 | { name => 'services' }, |
7e4d6e51 | 111 | { name => 'syslog' }, |
fa04fcb4 | 112 | { name => 'tasks' }, |
202c952a | 113 | { name => 'tracker' }, |
d934c136 | 114 | { name => 'time' }, |
c1f5acda | 115 | { name => 'status' }, |
87952a8d | 116 | { name => 'subscription' }, |
6466cf6d | 117 | { name => 'termproxy' }, |
229e2e68 | 118 | { name => 'rrddata' }, |
1360e6f0 DM |
119 | ]; |
120 | ||
121 | return $result; | |
122 | }}); | |
123 | ||
065b2986 DM |
124 | __PACKAGE__->register_method({ |
125 | name => 'rrddata', | |
126 | path => 'rrddata', | |
127 | method => 'GET', | |
128 | protected => 1, # fixme: can we avoid that? | |
129 | proxyto => 'node', | |
127154c3 | 130 | permissions => { check => [ 'admin', 'audit' ] }, |
065b2986 DM |
131 | description => "Read node RRD statistics", |
132 | parameters => { | |
133 | additionalProperties => 0, | |
134 | properties => { | |
135 | node => get_standard_option('pve-node'), | |
136 | timeframe => { | |
137 | description => "Specify the time frame you are interested in.", | |
138 | type => 'string', | |
139 | enum => [ 'hour', 'day', 'week', 'month', 'year' ], | |
140 | }, | |
141 | cf => { | |
142 | description => "The RRD consolidation function", | |
143 | type => 'string', | |
144 | enum => [ 'AVERAGE', 'MAX' ], | |
145 | optional => 1, | |
146 | }, | |
147 | }, | |
148 | }, | |
149 | returns => { | |
150 | type => "array", | |
151 | items => { | |
152 | type => "object", | |
153 | properties => {}, | |
154 | }, | |
155 | }, | |
156 | code => sub { | |
157 | my ($param) = @_; | |
158 | ||
159 | return PMG::Utils::create_rrd_data( | |
160 | "pmg-node-v1.rrd", $param->{timeframe}, $param->{cf}); | |
161 | }}); | |
162 | ||
163 | ||
7e4d6e51 DM |
164 | __PACKAGE__->register_method({ |
165 | name => 'syslog', | |
166 | path => 'syslog', | |
167 | method => 'GET', | |
168 | description => "Read system log", | |
169 | proxyto => 'node', | |
170 | protected => 1, | |
da5777d7 | 171 | permissions => { check => [ 'admin', 'audit' ] }, |
7e4d6e51 DM |
172 | parameters => { |
173 | additionalProperties => 0, | |
174 | properties => { | |
175 | node => get_standard_option('pve-node'), | |
176 | start => { | |
177 | type => 'integer', | |
178 | minimum => 0, | |
179 | optional => 1, | |
180 | }, | |
181 | limit => { | |
182 | type => 'integer', | |
183 | minimum => 0, | |
184 | optional => 1, | |
185 | }, | |
186 | since => { | |
cf49e998 | 187 | type => 'string', |
7e4d6e51 DM |
188 | pattern => '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$', |
189 | description => "Display all log since this date-time string.", | |
190 | optional => 1, | |
191 | }, | |
192 | 'until' => { | |
cf49e998 | 193 | type => 'string', |
7e4d6e51 DM |
194 | pattern => '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$', |
195 | description => "Display all log until this date-time string.", | |
196 | optional => 1, | |
197 | }, | |
cf49e998 DM |
198 | service => { |
199 | description => "Service ID", | |
200 | type => 'string', | |
201 | maxLength => 128, | |
202 | optional => 1, | |
203 | }, | |
7e4d6e51 DM |
204 | }, |
205 | }, | |
206 | returns => { | |
207 | type => 'array', | |
208 | items => { | |
209 | type => "object", | |
210 | properties => { | |
211 | n => { | |
212 | description=> "Line number", | |
213 | type=> 'integer', | |
214 | }, | |
215 | t => { | |
216 | description=> "Line text", | |
217 | type => 'string', | |
218 | } | |
219 | } | |
220 | } | |
221 | }, | |
222 | code => sub { | |
223 | my ($param) = @_; | |
224 | ||
f1c29260 | 225 | my $restenv = PMG::RESTEnvironment->get(); |
7e4d6e51 | 226 | |
cf49e998 | 227 | my $service = $param->{service}; |
ef07e4d0 DM |
228 | $service = PMG::Utils::lookup_real_service_name($service) |
229 | if $service; | |
cf49e998 DM |
230 | |
231 | my ($count, $lines) = PVE::Tools::dump_journal( | |
232 | $param->{start}, $param->{limit}, | |
233 | $param->{since}, $param->{'until'}, $service); | |
7e4d6e51 DM |
234 | |
235 | $restenv->set_result_attrib('total', $count); | |
236 | ||
237 | return $lines; | |
238 | }}); | |
239 | ||
6466cf6d | 240 | |
1360e6f0 | 241 | __PACKAGE__->register_method ({ |
6466cf6d DC |
242 | name => 'termproxy', |
243 | path => 'termproxy', | |
1360e6f0 | 244 | method => 'POST', |
aafcc40e | 245 | permissions => { check => [ 'admin' ] }, |
fa04fcb4 | 246 | protected => 1, |
6466cf6d | 247 | description => "Creates a Terminal proxy.", |
1360e6f0 DM |
248 | parameters => { |
249 | additionalProperties => 0, | |
250 | properties => { | |
251 | node => get_standard_option('pve-node'), | |
5e6e07df DM |
252 | upgrade => { |
253 | type => 'boolean', | |
254 | description => "Run 'apt-get dist-upgrade' instead of normal shell.", | |
255 | optional => 1, | |
256 | default => 0, | |
257 | }, | |
1360e6f0 DM |
258 | }, |
259 | }, | |
260 | returns => { | |
261 | additionalProperties => 0, | |
262 | properties => { | |
263 | user => { type => 'string' }, | |
264 | ticket => { type => 'string' }, | |
265 | port => { type => 'integer' }, | |
266 | upid => { type => 'string' }, | |
267 | }, | |
268 | }, | |
269 | code => sub { | |
270 | my ($param) = @_; | |
271 | ||
272 | my $node = $param->{node}; | |
273 | ||
5e6e07df | 274 | if ($node ne PVE::INotify::nodename()) { |
6466cf6d | 275 | die "termproxy to remote node not implemented"; |
5e6e07df DM |
276 | } |
277 | ||
1360e6f0 DM |
278 | my $authpath = "/nodes/$node"; |
279 | ||
9d82c6bc | 280 | my $restenv = PMG::RESTEnvironment->get(); |
1360e6f0 DM |
281 | my $user = $restenv->get_user(); |
282 | ||
5e6e07df DM |
283 | raise_perm_exc('user != root@pam') if $param->{upgrade} && $user ne 'root@pam'; |
284 | ||
1360e6f0 DM |
285 | my $ticket = PMG::Ticket::assemble_vnc_ticket($user, $authpath); |
286 | ||
287 | my $family = PVE::Tools::get_host_address_family($node); | |
288 | my $port = PVE::Tools::next_vnc_port($family); | |
289 | ||
8e6893c6 DM |
290 | my $shcmd; |
291 | ||
292 | if ($user eq 'root@pam') { | |
5e6e07df DM |
293 | if ($param->{upgrade}) { |
294 | my $upgradecmd = "pmgupgrade --shell"; | |
295 | # $upgradecmd = PVE::Tools::shellquote($upgradecmd) if $remip; | |
296 | $shcmd = [ '/bin/bash', '-c', $upgradecmd ]; | |
297 | } else { | |
298 | $shcmd = [ '/bin/login', '-f', 'root' ]; | |
299 | } | |
8e6893c6 DM |
300 | } else { |
301 | $shcmd = [ '/bin/login' ]; | |
302 | } | |
303 | ||
6466cf6d DC |
304 | my $cmd = ['/usr/bin/termproxy', $port, '--path', $authpath, |
305 | '--', @$shcmd]; | |
1360e6f0 DM |
306 | |
307 | my $realcmd = sub { | |
308 | my $upid = shift; | |
309 | ||
6466cf6d | 310 | syslog ('info', "starting termproxy $upid\n"); |
1360e6f0 DM |
311 | |
312 | my $cmdstr = join (' ', @$cmd); | |
313 | syslog ('info', "launch command: $cmdstr"); | |
314 | ||
6466cf6d | 315 | PVE::Tools::run_command($cmd); |
1360e6f0 DM |
316 | |
317 | return; | |
318 | }; | |
319 | ||
6466cf6d | 320 | my $upid = $restenv->fork_worker('termproxy', "", $user, $realcmd); |
1360e6f0 DM |
321 | |
322 | PVE::Tools::wait_for_vnc_port($port); | |
323 | ||
324 | return { | |
325 | user => $user, | |
326 | ticket => $ticket, | |
327 | port => $port, | |
328 | upid => $upid, | |
329 | }; | |
330 | }}); | |
331 | ||
332 | __PACKAGE__->register_method({ | |
333 | name => 'vncwebsocket', | |
334 | path => 'vncwebsocket', | |
335 | method => 'GET', | |
aafcc40e | 336 | permissions => { check => [ 'admin' ] }, |
1360e6f0 DM |
337 | description => "Opens a weksocket for VNC traffic.", |
338 | parameters => { | |
339 | additionalProperties => 0, | |
340 | properties => { | |
341 | node => get_standard_option('pve-node'), | |
342 | vncticket => { | |
343 | description => "Ticket from previous call to vncproxy.", | |
344 | type => 'string', | |
345 | maxLength => 512, | |
346 | }, | |
347 | port => { | |
348 | description => "Port number returned by previous vncproxy call.", | |
349 | type => 'integer', | |
350 | minimum => 5900, | |
351 | maximum => 5999, | |
352 | }, | |
353 | }, | |
354 | }, | |
355 | returns => { | |
356 | type => "object", | |
357 | properties => { | |
358 | port => { type => 'string' }, | |
359 | }, | |
360 | }, | |
361 | code => sub { | |
362 | my ($param) = @_; | |
363 | ||
364 | my $authpath = "/nodes/$param->{node}"; | |
365 | ||
9d82c6bc | 366 | my $restenv = PMG::RESTEnvironment->get(); |
1360e6f0 DM |
367 | my $user = $restenv->get_user(); |
368 | ||
369 | PMG::Ticket::verify_vnc_ticket($param->{vncticket}, $user, $authpath); | |
370 | ||
371 | my $port = $param->{port}; | |
372 | ||
373 | return { port => $port }; | |
374 | }}); | |
375 | ||
bce9f371 DM |
376 | __PACKAGE__->register_method({ |
377 | name => 'dns', | |
378 | path => 'dns', | |
379 | method => 'GET', | |
380 | description => "Read DNS settings.", | |
381 | proxyto => 'node', | |
aea3488a | 382 | permissions => { check => [ 'admin', 'audit' ] }, |
bce9f371 DM |
383 | parameters => { |
384 | additionalProperties => 0, | |
385 | properties => { | |
386 | node => get_standard_option('pve-node'), | |
387 | }, | |
388 | }, | |
389 | returns => { | |
390 | type => "object", | |
391 | additionalProperties => 0, | |
392 | properties => { | |
393 | search => { | |
394 | description => "Search domain for host-name lookup.", | |
395 | type => 'string', | |
396 | optional => 1, | |
397 | }, | |
398 | dns1 => { | |
399 | description => 'First name server IP address.', | |
400 | type => 'string', | |
401 | optional => 1, | |
402 | }, | |
403 | dns2 => { | |
404 | description => 'Second name server IP address.', | |
405 | type => 'string', | |
406 | optional => 1, | |
407 | }, | |
408 | dns3 => { | |
409 | description => 'Third name server IP address.', | |
410 | type => 'string', | |
411 | optional => 1, | |
412 | }, | |
413 | }, | |
414 | }, | |
415 | code => sub { | |
416 | my ($param) = @_; | |
417 | ||
418 | my $res = PVE::INotify::read_file('resolvconf'); | |
419 | ||
420 | return $res; | |
421 | }}); | |
422 | ||
423 | __PACKAGE__->register_method({ | |
424 | name => 'update_dns', | |
425 | path => 'dns', | |
426 | method => 'PUT', | |
427 | description => "Write DNS settings.", | |
428 | proxyto => 'node', | |
429 | protected => 1, | |
430 | parameters => { | |
431 | additionalProperties => 0, | |
432 | properties => { | |
433 | node => get_standard_option('pve-node'), | |
434 | search => { | |
435 | description => "Search domain for host-name lookup.", | |
436 | type => 'string', | |
437 | }, | |
438 | dns1 => { | |
439 | description => 'First name server IP address.', | |
440 | type => 'string', format => 'ip', | |
441 | optional => 1, | |
442 | }, | |
443 | dns2 => { | |
444 | description => 'Second name server IP address.', | |
445 | type => 'string', format => 'ip', | |
446 | optional => 1, | |
447 | }, | |
448 | dns3 => { | |
449 | description => 'Third name server IP address.', | |
450 | type => 'string', format => 'ip', | |
451 | optional => 1, | |
452 | }, | |
453 | }, | |
454 | }, | |
455 | returns => { type => "null" }, | |
456 | code => sub { | |
457 | my ($param) = @_; | |
458 | ||
459 | PVE::INotify::update_file('resolvconf', $param); | |
460 | ||
461 | return undef; | |
462 | }}); | |
463 | ||
464 | ||
d934c136 DM |
465 | __PACKAGE__->register_method({ |
466 | name => 'time', | |
467 | path => 'time', | |
468 | method => 'GET', | |
469 | description => "Read server time and time zone settings.", | |
470 | proxyto => 'node', | |
aea3488a | 471 | permissions => { check => [ 'admin', 'audit' ] }, |
d934c136 DM |
472 | parameters => { |
473 | additionalProperties => 0, | |
474 | properties => { | |
475 | node => get_standard_option('pve-node'), | |
476 | }, | |
477 | }, | |
478 | returns => { | |
479 | type => "object", | |
480 | additionalProperties => 0, | |
481 | properties => { | |
482 | timezone => { | |
483 | description => "Time zone", | |
484 | type => 'string', | |
485 | }, | |
486 | time => { | |
487 | description => "Seconds since 1970-01-01 00:00:00 UTC.", | |
488 | type => 'integer', | |
489 | minimum => 1297163644, | |
490 | }, | |
491 | localtime => { | |
492 | description => "Seconds since 1970-01-01 00:00:00 (local time)", | |
493 | type => 'integer', | |
494 | minimum => 1297163644, | |
495 | }, | |
496 | }, | |
497 | }, | |
498 | code => sub { | |
499 | my ($param) = @_; | |
500 | ||
501 | my $ctime = time(); | |
502 | my $ltime = timegm_nocheck(localtime($ctime)); | |
503 | my $res = { | |
504 | timezone => PVE::INotify::read_file('timezone'), | |
505 | time => time(), | |
506 | localtime => $ltime, | |
507 | }; | |
508 | ||
509 | return $res; | |
510 | }}); | |
511 | ||
512 | __PACKAGE__->register_method({ | |
513 | name => 'set_timezone', | |
514 | path => 'time', | |
515 | method => 'PUT', | |
516 | description => "Set time zone.", | |
517 | proxyto => 'node', | |
518 | protected => 1, | |
519 | parameters => { | |
520 | additionalProperties => 0, | |
521 | properties => { | |
522 | node => get_standard_option('pve-node'), | |
523 | timezone => { | |
524 | description => "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.", | |
525 | type => 'string', | |
526 | }, | |
527 | }, | |
528 | }, | |
529 | returns => { type => "null" }, | |
530 | code => sub { | |
531 | my ($param) = @_; | |
532 | ||
533 | PVE::INotify::write_file('timezone', $param->{timezone}); | |
534 | ||
535 | return undef; | |
536 | }}); | |
537 | ||
c1f5acda DM |
538 | __PACKAGE__->register_method({ |
539 | name => 'status', | |
540 | path => 'status', | |
541 | method => 'GET', | |
542 | description => "Read server status. This is used by the cluster manager to test the node health.", | |
543 | proxyto => 'node', | |
544 | protected => 1, | |
545 | parameters => { | |
546 | additionalProperties => 0, | |
547 | properties => { | |
548 | node => get_standard_option('pve-node'), | |
549 | }, | |
550 | }, | |
551 | returns => { | |
552 | type => "object", | |
553 | additionalProperties => 1, | |
554 | properties => { | |
555 | time => { | |
556 | description => "Seconds since 1970-01-01 00:00:00 UTC.", | |
557 | type => 'integer', | |
558 | minimum => 1297163644, | |
559 | }, | |
560 | uptime => { | |
561 | description => "The uptime of the system in seconds.", | |
562 | type => 'integer', | |
563 | minimum => 0, | |
564 | }, | |
565 | insync => { | |
566 | description => "Database is synced with other nodes.", | |
567 | type => 'boolean', | |
568 | }, | |
569 | }, | |
570 | }, | |
571 | code => sub { | |
572 | my ($param) = @_; | |
573 | ||
574 | my $restenv = PMG::RESTEnvironment->get(); | |
575 | my $cinfo = $restenv->{cinfo}; | |
576 | ||
577 | my $ctime = time(); | |
578 | ||
579 | my $res = { time => $ctime, insync => 1 }; | |
580 | ||
581 | my $si = PMG::DBTools::cluster_sync_status($cinfo); | |
582 | foreach my $cid (keys %$si) { | |
583 | my $lastsync = $si->{$cid}; | |
584 | my $sdiff = $ctime - $lastsync; | |
585 | $sdiff = 0 if $sdiff < 0; | |
586 | $res->{insync} = 0 if $sdiff > (60*3); | |
587 | } | |
588 | ||
589 | my ($uptime, $idle) = PVE::ProcFSTools::read_proc_uptime(); | |
590 | $res->{uptime} = $uptime; | |
591 | ||
592 | my ($avg1, $avg5, $avg15) = PVE::ProcFSTools::read_loadavg(); | |
593 | $res->{loadavg} = [ $avg1, $avg5, $avg15]; | |
594 | ||
595 | my ($sysname, $nodename, $release, $version, $machine) = POSIX::uname(); | |
596 | ||
597 | $res->{kversion} = "$sysname $release $version"; | |
598 | ||
599 | $res->{cpuinfo} = PVE::ProcFSTools::read_cpuinfo(); | |
600 | ||
601 | my $stat = PVE::ProcFSTools::read_proc_stat(); | |
602 | $res->{cpu} = $stat->{cpu}; | |
603 | $res->{wait} = $stat->{wait}; | |
604 | ||
605 | my $meminfo = PVE::ProcFSTools::read_meminfo(); | |
606 | $res->{memory} = { | |
607 | free => $meminfo->{memfree}, | |
608 | total => $meminfo->{memtotal}, | |
609 | used => $meminfo->{memused}, | |
610 | }; | |
611 | ||
612 | $res->{swap} = { | |
613 | free => $meminfo->{swapfree}, | |
614 | total => $meminfo->{swaptotal}, | |
615 | used => $meminfo->{swapused}, | |
616 | }; | |
617 | ||
618 | $res->{pmgversion} = PMG::pmgcfg::package() . "/" . | |
619 | PMG::pmgcfg::version_text(); | |
620 | ||
621 | my $dinfo = df('/', 1); # output is bytes | |
622 | ||
623 | $res->{rootfs} = { | |
624 | total => $dinfo->{blocks}, | |
625 | avail => $dinfo->{bavail}, | |
626 | used => $dinfo->{used}, | |
d9f4add4 | 627 | free => $dinfo->{blocks} - $dinfo->{used}, |
c1f5acda DM |
628 | }; |
629 | ||
b4df3454 DM |
630 | if (my $subinfo = PVE::INotify::read_file('subscription')) { |
631 | if (my $level = $subinfo->{level}) { | |
632 | $res->{level} = $level; | |
633 | } | |
634 | } | |
635 | ||
c1f5acda DM |
636 | return $res; |
637 | }}); | |
638 | ||
0a327ff4 DM |
639 | __PACKAGE__->register_method({ |
640 | name => 'node_cmd', | |
641 | path => 'status', | |
642 | method => 'POST', | |
aafcc40e | 643 | permissions => { check => [ 'admin' ] }, |
0a327ff4 DM |
644 | protected => 1, |
645 | description => "Reboot or shutdown a node.", | |
646 | proxyto => 'node', | |
647 | parameters => { | |
648 | additionalProperties => 0, | |
649 | properties => { | |
650 | node => get_standard_option('pve-node'), | |
651 | command => { | |
652 | description => "Specify the command.", | |
653 | type => 'string', | |
654 | enum => [qw(reboot shutdown)], | |
655 | }, | |
656 | }, | |
657 | }, | |
658 | returns => { type => "null" }, | |
659 | code => sub { | |
660 | my ($param) = @_; | |
661 | ||
662 | if ($param->{command} eq 'reboot') { | |
663 | system ("(sleep 2;/sbin/reboot)&"); | |
664 | } elsif ($param->{command} eq 'shutdown') { | |
665 | system ("(sleep 2;/sbin/poweroff)&"); | |
666 | } | |
667 | ||
668 | return undef; | |
669 | }}); | |
1360e6f0 DM |
670 | |
671 | package PMG::API2::Nodes; | |
672 | ||
673 | use strict; | |
674 | use warnings; | |
675 | ||
676 | use PVE::RESTHandler; | |
677 | use PVE::JSONSchema qw(get_standard_option); | |
678 | ||
be512f56 DM |
679 | use PMG::RESTEnvironment; |
680 | ||
1360e6f0 DM |
681 | use base qw(PVE::RESTHandler); |
682 | ||
683 | __PACKAGE__->register_method ({ | |
f6dcba61 | 684 | subclass => "PMG::API2::NodeInfo", |
1360e6f0 DM |
685 | path => '{node}', |
686 | }); | |
687 | ||
688 | __PACKAGE__->register_method ({ | |
689 | name => 'index', | |
690 | path => '', | |
691 | method => 'GET', | |
692 | permissions => { user => 'all' }, | |
693 | description => "Cluster node index.", | |
694 | parameters => { | |
695 | additionalProperties => 0, | |
696 | properties => {}, | |
697 | }, | |
698 | returns => { | |
699 | type => 'array', | |
700 | items => { | |
701 | type => "object", | |
702 | properties => {}, | |
703 | }, | |
704 | links => [ { rel => 'child', href => "{node}" } ], | |
705 | }, | |
706 | code => sub { | |
707 | my ($param) = @_; | |
708 | ||
709 | my $nodename = PVE::INotify::nodename(); | |
be512f56 DM |
710 | |
711 | my $res = [ { node => $nodename } ]; | |
712 | ||
713 | my $done = {}; | |
714 | ||
715 | $done->{$nodename} = 1; | |
716 | ||
717 | my $restenv = PMG::RESTEnvironment->get(); | |
718 | my $cinfo = $restenv->{cinfo}; | |
719 | ||
720 | foreach my $ni (values %{$cinfo->{ids}}) { | |
721 | push @$res, { node => $ni->{name} } if !$done->{$ni->{name}}; | |
722 | $done->{$ni->{name}} = 1; | |
723 | } | |
1360e6f0 DM |
724 | |
725 | return $res; | |
726 | }}); | |
727 | ||
728 | ||
729 | 1; |