]>
git.proxmox.com Git - pmg-api.git/blob - PMG/API2/Nodes.pm
1 package PMG
::API2
::NodeInfo
;
5 use Time
::Local
qw(timegm_nocheck);
11 use PVE
::JSONSchema
qw(get_standard_option);
12 use PMG
::RESTEnvironment
;
19 use PMG
::API2
::Subscription
;
22 use PMG
::API2
::Services
;
23 use PMG
::API2
::Network
;
24 use PMG
::API2
::ClamAV
;
25 use PMG
::API2
::SpamAssassin
;
26 use PMG
::API2
::Postfix
;
27 use PMG
::API2
::MailTracker
;
28 use PMG
::API2
::Backup
;
30 use base
qw(PVE::RESTHandler);
32 __PACKAGE__-
>register_method ({
33 subclass
=> "PMG::API2::Postfix",
37 __PACKAGE__-
>register_method ({
38 subclass
=> "PMG::API2::ClamAV",
42 __PACKAGE__-
>register_method ({
43 subclass
=> "PMG::API2::SpamAssassin",
44 path
=> 'spamassassin',
47 __PACKAGE__-
>register_method ({
48 subclass
=> "PMG::API2::Network",
52 __PACKAGE__-
>register_method ({
53 subclass
=> "PMG::API2::Tasks",
57 __PACKAGE__-
>register_method ({
58 subclass
=> "PMG::API2::Services",
62 __PACKAGE__-
>register_method ({
63 subclass
=> "PMG::API2::Subscription",
64 path
=> 'subscription',
67 __PACKAGE__-
>register_method ({
68 subclass
=> "PMG::API2::APT",
72 __PACKAGE__-
>register_method ({
73 subclass
=> "PMG::API2::MailTracker",
77 __PACKAGE__-
>register_method ({
78 subclass
=> "PMG::API2::Backup",
82 __PACKAGE__-
>register_method ({
86 permissions
=> { user
=> 'all' },
87 description
=> "Node index.",
89 additionalProperties
=> 0,
91 node
=> get_standard_option
('pve-node'),
100 links
=> [ { rel
=> 'child', href
=> "{name}" } ],
107 { name
=> 'backup' },
108 { name
=> 'clamav' },
109 { name
=> 'spamassassin' },
110 { name
=> 'postfix' },
111 { name
=> 'services' },
112 { name
=> 'syslog' },
114 { name
=> 'tracker' },
116 { name
=> 'report' },
117 { name
=> 'status' },
118 { name
=> 'subscription' },
119 { name
=> 'termproxy' },
120 { name
=> 'rrddata' },
126 __PACKAGE__-
>register_method({
132 permissions
=> { check
=> [ 'admin', 'audit' ] },
133 description
=> "Gather various system information about a node",
135 additionalProperties
=> 0,
137 node
=> get_standard_option
('pve-node'),
144 return PMG
::Report
::generate
();
147 __PACKAGE__-
>register_method({
151 protected
=> 1, # fixme: can we avoid that?
153 permissions
=> { check
=> [ 'admin', 'audit' ] },
154 description
=> "Read node RRD statistics",
156 additionalProperties
=> 0,
158 node
=> get_standard_option
('pve-node'),
160 description
=> "Specify the time frame you are interested in.",
162 enum
=> [ 'hour', 'day', 'week', 'month', 'year' ],
165 description
=> "The RRD consolidation function",
167 enum
=> [ 'AVERAGE', 'MAX' ],
182 return PMG
::Utils
::create_rrd_data
(
183 "pmg-node-v1.rrd", $param->{timeframe
}, $param->{cf
});
187 __PACKAGE__-
>register_method({
191 description
=> "Read system log",
194 permissions
=> { check
=> [ 'admin', 'audit' ] },
196 additionalProperties
=> 0,
198 node
=> get_standard_option
('pve-node'),
211 pattern
=> '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$',
212 description
=> "Display all log since this date-time string.",
217 pattern
=> '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$',
218 description
=> "Display all log until this date-time string.",
222 description
=> "Service ID",
235 description
=> "Line number",
239 description
=> "Line text",
248 my $restenv = PMG
::RESTEnvironment-
>get();
250 my $service = $param->{service
};
251 $service = PMG
::Utils
::lookup_real_service_name
($service)
254 my ($count, $lines) = PVE
::Tools
::dump_journal
(
255 $param->{start
}, $param->{limit
},
256 $param->{since
}, $param->{'until'}, $service);
258 $restenv->set_result_attrib('total', $count);
263 __PACKAGE__-
>register_method({
267 description
=> "Read Journal",
269 permissions
=> { check
=> [ 'admin', 'audit' ] },
272 additionalProperties
=> 0,
274 node
=> get_standard_option
('pve-node'),
277 description
=> "Display all log since this UNIX epoch.",
282 description
=> "Display all log until this UNIX epoch.",
286 description
=> "Limit to the last X lines.",
291 description
=> "Start after the given Cursor.",
296 description
=> "End before the given Cursor.",
317 my $cmd = ["/usr/bin/mini-journalreader"];
318 push @$cmd, '-n', $param->{lastentries
} if $param->{lastentries
};
319 push @$cmd, '-b', $param->{since
} if $param->{since
};
320 push @$cmd, '-e', $param->{until} if $param->{until};
321 push @$cmd, '-f', $param->{startcursor
} if $param->{startcursor
};
322 push @$cmd, '-t', $param->{endcursor
} if $param->{endcursor
};
324 PVE
::Tools
::run_command
($cmd, outfunc
=> $parser);
330 __PACKAGE__-
>register_method ({
334 permissions
=> { check
=> [ 'admin' ] },
336 description
=> "Creates a Terminal proxy.",
338 additionalProperties
=> 0,
340 node
=> get_standard_option
('pve-node'),
343 description
=> "Run 'apt-get dist-upgrade' instead of normal shell.",
350 additionalProperties
=> 0,
352 user
=> { type
=> 'string' },
353 ticket
=> { type
=> 'string' },
354 port
=> { type
=> 'integer' },
355 upid
=> { type
=> 'string' },
361 my $node = $param->{node
};
363 if ($node ne PVE
::INotify
::nodename
()) {
364 die "termproxy to remote node not implemented";
367 my $authpath = "/nodes/$node";
369 my $restenv = PMG
::RESTEnvironment-
>get();
370 my $user = $restenv->get_user();
372 raise_perm_exc
('user != root@pam') if $param->{upgrade
} && $user ne 'root@pam';
374 my $ticket = PMG
::Ticket
::assemble_vnc_ticket
($user, $authpath);
376 my $family = PVE
::Tools
::get_host_address_family
($node);
377 my $port = PVE
::Tools
::next_vnc_port
($family);
381 if ($user eq 'root@pam') {
382 if ($param->{upgrade
}) {
383 my $upgradecmd = "pmgupgrade --shell";
384 # $upgradecmd = PVE::Tools::shellquote($upgradecmd) if $remip;
385 $shcmd = [ '/bin/bash', '-c', $upgradecmd ];
387 $shcmd = [ '/bin/login', '-f', 'root' ];
390 $shcmd = [ '/bin/login' ];
393 my $cmd = ['/usr/bin/termproxy', $port, '--path', $authpath,
399 syslog
('info', "starting termproxy $upid\n");
401 my $cmdstr = join (' ', @$cmd);
402 syslog
('info', "launch command: $cmdstr");
404 PVE
::Tools
::run_command
($cmd);
409 my $upid = $restenv->fork_worker('termproxy', "", $user, $realcmd);
411 PVE
::Tools
::wait_for_vnc_port
($port);
421 __PACKAGE__-
>register_method({
422 name
=> 'vncwebsocket',
423 path
=> 'vncwebsocket',
425 permissions
=> { check
=> [ 'admin' ] },
426 description
=> "Opens a weksocket for VNC traffic.",
428 additionalProperties
=> 0,
430 node
=> get_standard_option
('pve-node'),
432 description
=> "Ticket from previous call to vncproxy.",
437 description
=> "Port number returned by previous vncproxy call.",
447 port
=> { type
=> 'string' },
453 my $authpath = "/nodes/$param->{node}";
455 my $restenv = PMG
::RESTEnvironment-
>get();
456 my $user = $restenv->get_user();
458 PMG
::Ticket
::verify_vnc_ticket
($param->{vncticket
}, $user, $authpath);
460 my $port = $param->{port
};
462 return { port
=> $port };
465 __PACKAGE__-
>register_method({
469 description
=> "Read DNS settings.",
471 permissions
=> { check
=> [ 'admin', 'audit' ] },
473 additionalProperties
=> 0,
475 node
=> get_standard_option
('pve-node'),
480 additionalProperties
=> 0,
483 description
=> "Search domain for host-name lookup.",
488 description
=> 'First name server IP address.',
493 description
=> 'Second name server IP address.',
498 description
=> 'Third name server IP address.',
507 my $res = PVE
::INotify
::read_file
('resolvconf');
512 __PACKAGE__-
>register_method({
513 name
=> 'update_dns',
516 description
=> "Write DNS settings.",
520 additionalProperties
=> 0,
522 node
=> get_standard_option
('pve-node'),
524 description
=> "Search domain for host-name lookup.",
528 description
=> 'First name server IP address.',
529 type
=> 'string', format
=> 'ip',
533 description
=> 'Second name server IP address.',
534 type
=> 'string', format
=> 'ip',
538 description
=> 'Third name server IP address.',
539 type
=> 'string', format
=> 'ip',
544 returns
=> { type
=> "null" },
548 PVE
::INotify
::update_file
('resolvconf', $param);
554 __PACKAGE__-
>register_method({
558 description
=> "Read server time and time zone settings.",
560 permissions
=> { check
=> [ 'admin', 'audit' ] },
562 additionalProperties
=> 0,
564 node
=> get_standard_option
('pve-node'),
569 additionalProperties
=> 0,
572 description
=> "Time zone",
576 description
=> "Seconds since 1970-01-01 00:00:00 UTC.",
578 minimum
=> 1297163644,
581 description
=> "Seconds since 1970-01-01 00:00:00 (local time)",
583 minimum
=> 1297163644,
591 my $ltime = timegm_nocheck
(localtime($ctime));
593 timezone
=> PVE
::INotify
::read_file
('timezone'),
601 __PACKAGE__-
>register_method({
602 name
=> 'set_timezone',
605 description
=> "Set time zone.",
609 additionalProperties
=> 0,
611 node
=> get_standard_option
('pve-node'),
613 description
=> "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.",
618 returns
=> { type
=> "null" },
622 PVE
::INotify
::write_file
('timezone', $param->{timezone
});
627 __PACKAGE__-
>register_method({
631 description
=> "Read server status. This is used by the cluster manager to test the node health.",
633 permissions
=> { check
=> [ 'admin', 'qmanager', 'audit' ] },
636 additionalProperties
=> 0,
638 node
=> get_standard_option
('pve-node'),
643 additionalProperties
=> 1,
646 description
=> "Seconds since 1970-01-01 00:00:00 UTC.",
648 minimum
=> 1297163644,
651 description
=> "The uptime of the system in seconds.",
656 description
=> "Database is synced with other nodes.",
664 my $restenv = PMG
::RESTEnvironment-
>get();
665 my $cinfo = $restenv->{cinfo
};
669 my $res = { time => $ctime, insync
=> 1 };
671 my $si = PMG
::DBTools
::cluster_sync_status
($cinfo);
672 foreach my $cid (keys %$si) {
673 my $lastsync = $si->{$cid};
674 my $sdiff = $ctime - $lastsync;
675 $sdiff = 0 if $sdiff < 0;
676 $res->{insync
} = 0 if $sdiff > (60*3);
679 my ($uptime, $idle) = PVE
::ProcFSTools
::read_proc_uptime
();
680 $res->{uptime
} = $uptime;
682 my ($avg1, $avg5, $avg15) = PVE
::ProcFSTools
::read_loadavg
();
683 $res->{loadavg
} = [ $avg1, $avg5, $avg15];
685 my ($sysname, $nodename, $release, $version, $machine) = POSIX
::uname
();
687 $res->{kversion
} = "$sysname $release $version";
689 $res->{cpuinfo
} = PVE
::ProcFSTools
::read_cpuinfo
();
691 my $stat = PVE
::ProcFSTools
::read_proc_stat
();
692 $res->{cpu
} = $stat->{cpu
};
693 $res->{wait} = $stat->{wait};
695 my $meminfo = PVE
::ProcFSTools
::read_meminfo
();
697 free
=> $meminfo->{memfree
},
698 total
=> $meminfo->{memtotal
},
699 used
=> $meminfo->{memused
},
703 free
=> $meminfo->{swapfree
},
704 total
=> $meminfo->{swaptotal
},
705 used
=> $meminfo->{swapused
},
708 $res->{pmgversion
} = PMG
::pmgcfg
::package() . "/" .
709 PMG
::pmgcfg
::version_text
();
711 my $dinfo = df
('/', 1); # output is bytes
714 total
=> $dinfo->{blocks
},
715 avail
=> $dinfo->{bavail
},
716 used
=> $dinfo->{used
},
717 free
=> $dinfo->{blocks
} - $dinfo->{used
},
720 if (my $subinfo = PVE
::INotify
::read_file
('subscription')) {
721 if (my $level = $subinfo->{level
}) {
722 $res->{level
} = $level;
729 __PACKAGE__-
>register_method({
733 permissions
=> { check
=> [ 'admin' ] },
735 description
=> "Reboot or shutdown a node.",
738 additionalProperties
=> 0,
740 node
=> get_standard_option
('pve-node'),
742 description
=> "Specify the command.",
744 enum
=> [qw(reboot shutdown)],
748 returns
=> { type
=> "null" },
752 if ($param->{command
} eq 'reboot') {
753 system ("(sleep 2;/sbin/reboot)&");
754 } elsif ($param->{command
} eq 'shutdown') {
755 system ("(sleep 2;/sbin/poweroff)&");
761 package PMG
::API2
::Nodes
;
766 use PVE
::RESTHandler
;
767 use PVE
::JSONSchema
qw(get_standard_option);
769 use PMG
::RESTEnvironment
;
771 use base
qw(PVE::RESTHandler);
773 __PACKAGE__-
>register_method ({
774 subclass
=> "PMG::API2::NodeInfo",
778 __PACKAGE__-
>register_method ({
782 permissions
=> { user
=> 'all' },
783 description
=> "Cluster node index.",
785 additionalProperties
=> 0,
794 links
=> [ { rel
=> 'child', href
=> "{node}" } ],
799 my $nodename = PVE
::INotify
::nodename
();
801 my $res = [ { node
=> $nodename } ];
805 $done->{$nodename} = 1;
807 my $restenv = PMG
::RESTEnvironment-
>get();
808 my $cinfo = $restenv->{cinfo
};
810 foreach my $ni (values %{$cinfo->{ids
}}) {
811 push @$res, { node
=> $ni->{name
} } if !$done->{$ni->{name
}};
812 $done->{$ni->{name
}} = 1;