]> git.proxmox.com Git - pmg-api.git/blobdiff - PMG/API2/Nodes.pm
PMG/API2/Nodes.pm - fix permissions for rrddata
[pmg-api.git] / PMG / API2 / Nodes.pm
index 41d6f2dadf25e8a93c7eedf9ab40afd8f20416b6..a03bf6c7d491583cb70cda4f23d78a462728a0c2 100644 (file)
@@ -2,23 +2,35 @@ package PMG::API2::NodeInfo;
 
 use strict;
 use warnings;
-
 use Time::Local qw(timegm_nocheck);
+use Filesys::Df;
+use Data::Dumper;
 
 use PVE::INotify;
 use PVE::RESTHandler;
 use PVE::JSONSchema qw(get_standard_option);
-use PVE::RESTEnvironment;
+use PMG::RESTEnvironment;
 use PVE::SafeSyslog;
+use PVE::ProcFSTools;
 
+use PMG::pmgcfg;
 use PMG::Ticket;
+use PMG::API2::Subscription;
+use PMG::API2::APT;
 use PMG::API2::Tasks;
 use PMG::API2::Services;
 use PMG::API2::Network;
 use PMG::API2::ClamAV;
+use PMG::API2::Postfix;
+use PMG::API2::MailTracker;
 
 use base qw(PVE::RESTHandler);
 
+__PACKAGE__->register_method ({
+    subclass => "PMG::API2::Postfix",
+    path => 'postfix',
+});
+
 __PACKAGE__->register_method ({
     subclass => "PMG::API2::ClamAV",
     path => 'clamav',
@@ -39,6 +51,21 @@ __PACKAGE__->register_method ({
     path => 'services',
 });
 
+__PACKAGE__->register_method ({
+    subclass => "PMG::API2::Subscription",
+    path => 'subscription',
+});
+
+__PACKAGE__->register_method ({
+    subclass => "PMG::API2::APT",
+    path => 'apt',
+});
+
+__PACKAGE__->register_method ({
+    subclass => "PMG::API2::MailTracker",
+    path => 'tracker',
+});
+
 __PACKAGE__->register_method ({
     name => 'index',
     path => '',
@@ -63,17 +90,63 @@ __PACKAGE__->register_method ({
        my ($param) = @_;
 
        my $result = [
+           { name => 'apt' },
            { name => 'clamav' },
+           { name => 'postfix' },
            { name => 'services' },
            { name => 'syslog' },
            { name => 'tasks' },
+           { name => 'tracker' },
            { name => 'time' },
+           { name => 'status' },
+           { name => 'subscription' },
            { name => 'vncshell' },
+           { name => 'rrddata' },
        ];
 
        return $result;
     }});
 
+__PACKAGE__->register_method({
+    name => 'rrddata',
+    path => 'rrddata',
+    method => 'GET',
+    protected => 1, # fixme: can we avoid that?
+    proxyto => 'node',
+    permissions => { check => [ 'admin', 'audit' ] },
+    description => "Read node RRD statistics",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           timeframe => {
+               description => "Specify the time frame you are interested in.",
+               type => 'string',
+               enum => [ 'hour', 'day', 'week', 'month', 'year' ],
+           },
+           cf => {
+               description => "The RRD consolidation function",
+               type => 'string',
+               enum => [ 'AVERAGE', 'MAX' ],
+               optional => 1,
+           },
+       },
+    },
+    returns => {
+       type => "array",
+       items => {
+           type => "object",
+           properties => {},
+       },
+    },
+    code => sub {
+       my ($param) = @_;
+
+       return PMG::Utils::create_rrd_data(
+           "pmg-node-v1.rrd", $param->{timeframe}, $param->{cf});
+    }});
+
+
 __PACKAGE__->register_method({
     name => 'syslog',
     path => 'syslog',
@@ -96,17 +169,23 @@ __PACKAGE__->register_method({
                optional => 1,
            },
            since => {
-               type=> 'string',
+               type => 'string',
                pattern => '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$',
                description => "Display all log since this date-time string.",
                optional => 1,
            },
            'until' => {
-               type=> 'string',
+               type => 'string',
                pattern => '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$',
                description => "Display all log until this date-time string.",
                optional => 1,
            },
+           service => {
+               description => "Service ID",
+               type => 'string',
+               maxLength => 128,
+               optional => 1,
+           },
        },
     },
     returns => {
@@ -128,10 +207,15 @@ __PACKAGE__->register_method({
     code => sub {
        my ($param) = @_;
 
-       my $restenv = PVE::RESTEnvironment::get();
+       my $restenv = PMG::RESTEnvironment->get();
+
+       my $service = $param->{service};
+       $service = PMG::Utils::lookup_real_service_name($service)
+           if $service;
 
-       my ($count, $lines) = PVE::Tools::dump_journal($param->{start}, $param->{limit},
-                                                      $param->{since}, $param->{'until'});
+       my ($count, $lines) = PVE::Tools::dump_journal(
+           $param->{start}, $param->{limit},
+           $param->{since}, $param->{'until'}, $service);
 
        $restenv->set_result_attrib('total', $count);
 
@@ -148,6 +232,12 @@ __PACKAGE__->register_method ({
        additionalProperties => 0,
        properties => {
            node => get_standard_option('pve-node'),
+           upgrade => {
+               type => 'boolean',
+               description => "Run 'apt-get dist-upgrade' instead of normal shell.",
+               optional => 1,
+               default => 0,
+           },
            websocket => {
                optional => 1,
                type => 'boolean',
@@ -170,15 +260,21 @@ __PACKAGE__->register_method ({
 
        my $node = $param->{node};
 
+       if ($node ne PVE::INotify::nodename()) {
+           die "vncproxy to remote node not implemented";
+       }
+
        # we only implement the websocket based VNC here
        my $websocket = $param->{websocket} // 1;
        die "standard VNC not implemented" if !$websocket;
 
        my $authpath = "/nodes/$node";
 
-       my $restenv = PVE::RESTEnvironment->get();
+       my $restenv = PMG::RESTEnvironment->get();
        my $user = $restenv->get_user();
 
+       raise_perm_exc('user != root@pam') if $param->{upgrade} && $user ne 'root@pam';
+
        my $ticket = PMG::Ticket::assemble_vnc_ticket($user, $authpath);
 
        my $family = PVE::Tools::get_host_address_family($node);
@@ -187,7 +283,13 @@ __PACKAGE__->register_method ({
        my $shcmd;
 
        if ($user eq 'root@pam') {
-           $shcmd = [ '/bin/login', '-f', 'root' ];
+           if ($param->{upgrade}) {
+               my $upgradecmd = "pmgupgrade --shell";
+               # $upgradecmd = PVE::Tools::shellquote($upgradecmd) if $remip;
+               $shcmd = [ '/bin/bash', '-c', $upgradecmd ];
+           } else {
+               $shcmd = [ '/bin/login', '-f', 'root' ];
+           }
        } else {
            $shcmd = [ '/bin/login' ];
        }
@@ -267,7 +369,7 @@ __PACKAGE__->register_method({
 
        my $authpath = "/nodes/$param->{node}";
 
-       my $restenv = PVE::RESTEnvironment->get();
+       my $restenv = PMG::RESTEnvironment->get();
        my $user = $restenv->get_user();
 
        PMG::Ticket::verify_vnc_ticket($param->{vncticket}, $user, $authpath);
@@ -437,6 +539,107 @@ __PACKAGE__->register_method({
        return undef;
     }});
 
+__PACKAGE__->register_method({
+    name => 'status',
+    path => 'status',
+    method => 'GET',
+    description => "Read server status. This is used by the cluster manager to test the node health.",
+    proxyto => 'node',
+    protected => 1,
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+       },
+    },
+    returns => {
+       type => "object",
+       additionalProperties => 1,
+       properties => {
+           time => {
+               description => "Seconds since 1970-01-01 00:00:00 UTC.",
+               type => 'integer',
+               minimum => 1297163644,
+           },
+           uptime => {
+               description => "The uptime of the system in seconds.",
+               type => 'integer',
+               minimum => 0,
+           },
+           insync => {
+               description => "Database is synced with other nodes.",
+               type => 'boolean',
+           },
+        },
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $restenv = PMG::RESTEnvironment->get();
+       my $cinfo = $restenv->{cinfo};
+
+       my $ctime = time();
+
+       my $res = { time => $ctime, insync => 1 };
+
+       my $si = PMG::DBTools::cluster_sync_status($cinfo);
+       foreach my $cid (keys %$si) {
+           my $lastsync = $si->{$cid};
+           my $sdiff = $ctime - $lastsync;
+           $sdiff = 0 if $sdiff < 0;
+           $res->{insync} = 0 if $sdiff > (60*3);
+       }
+
+       my ($uptime, $idle) = PVE::ProcFSTools::read_proc_uptime();
+       $res->{uptime} = $uptime;
+
+       my ($avg1, $avg5, $avg15) = PVE::ProcFSTools::read_loadavg();
+       $res->{loadavg} = [ $avg1, $avg5, $avg15];
+
+       my ($sysname, $nodename, $release, $version, $machine) = POSIX::uname();
+
+       $res->{kversion} = "$sysname $release $version";
+
+       $res->{cpuinfo} = PVE::ProcFSTools::read_cpuinfo();
+
+       my $stat = PVE::ProcFSTools::read_proc_stat();
+       $res->{cpu} = $stat->{cpu};
+       $res->{wait} = $stat->{wait};
+
+       my $meminfo = PVE::ProcFSTools::read_meminfo();
+       $res->{memory} = {
+           free => $meminfo->{memfree},
+           total => $meminfo->{memtotal},
+           used => $meminfo->{memused},
+       };
+
+       $res->{swap} = {
+           free => $meminfo->{swapfree},
+           total => $meminfo->{swaptotal},
+           used => $meminfo->{swapused},
+       };
+
+       $res->{pmgversion} = PMG::pmgcfg::package() . "/" .
+           PMG::pmgcfg::version_text();
+
+       my $dinfo = df('/', 1); # output is bytes
+
+       $res->{rootfs} = {
+           total => $dinfo->{blocks},
+           avail => $dinfo->{bavail},
+           used => $dinfo->{used},
+           free => $dinfo->{bavail} - $dinfo->{used},
+       };
+
+       if (my $subinfo = PVE::INotify::read_file('subscription')) {
+           if (my $level = $subinfo->{level}) {
+               $res->{level} = $level;
+           }
+       }
+
+       return $res;
+   }});
+
 
 package PMG::API2::Nodes;
 
@@ -446,6 +649,8 @@ use warnings;
 use PVE::RESTHandler;
 use PVE::JSONSchema qw(get_standard_option);
 
+use PMG::RESTEnvironment;
+
 use base qw(PVE::RESTHandler);
 
 __PACKAGE__->register_method ({
@@ -475,9 +680,20 @@ __PACKAGE__->register_method ({
        my ($param) = @_;
 
        my $nodename =  PVE::INotify::nodename();
-       my $res = [
-          { node => $nodename },
-       ];
+
+       my $res = [ { node => $nodename } ];
+
+       my $done = {};
+
+       $done->{$nodename} = 1;
+
+       my $restenv = PMG::RESTEnvironment->get();
+       my $cinfo = $restenv->{cinfo};
+
+       foreach my $ni (values %{$cinfo->{ids}}) {
+           push @$res, { node => $ni->{name} } if !$done->{$ni->{name}};
+           $done->{$ni->{name}} = 1;
+       }
 
        return $res;
     }});