mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-04-29 14:56:42 +00:00
962 lines
21 KiB
Perl
962 lines
21 KiB
Perl
package PVE::API2::Nodes::Nodeinfo;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use POSIX;
|
|
use Filesys::Df;
|
|
use Time::Local qw(timegm_nocheck);
|
|
use PVE::pvecfg;
|
|
use PVE::Tools;
|
|
use PVE::ProcFSTools;
|
|
use PVE::SafeSyslog;
|
|
use PVE::Cluster qw(cfs_read_file);
|
|
use PVE::INotify;
|
|
use PVE::Exception qw(raise raise_perm_exc);
|
|
use PVE::RESTHandler;
|
|
use PVE::RPCEnvironment;
|
|
use PVE::JSONSchema qw(get_standard_option);
|
|
use PVE::AccessControl;
|
|
use PVE::Storage;
|
|
use PVE::OpenVZ;
|
|
use PVE::APLInfo;
|
|
use PVE::API2::Services;
|
|
use PVE::API2::Network;
|
|
use PVE::API2::Tasks;
|
|
use PVE::API2::Storage::Scan;
|
|
use PVE::API2::Storage::Status;
|
|
use PVE::API2::Qemu;
|
|
use PVE::API2::OpenVZ;
|
|
use PVE::API2::VZDump;
|
|
use JSON;
|
|
|
|
use base qw(PVE::RESTHandler);
|
|
|
|
__PACKAGE__->register_method ({
|
|
subclass => "PVE::API2::Qemu",
|
|
path => 'qemu',
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
subclass => "PVE::API2::OpenVZ",
|
|
path => 'openvz',
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
subclass => "PVE::API2::VZDump",
|
|
path => 'vzdump',
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
subclass => "PVE::API2::Services",
|
|
path => 'services',
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
subclass => "PVE::API2::Network",
|
|
path => 'network',
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
subclass => "PVE::API2::Tasks",
|
|
path => 'tasks',
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
subclass => "PVE::API2::Storage::Scan",
|
|
path => 'scan',
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
subclass => "PVE::API2::Storage::Status",
|
|
path => 'storage',
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'index',
|
|
path => '',
|
|
method => 'GET',
|
|
permissions => { user => 'all' },
|
|
description => "Node index.",
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => {
|
|
type => 'array',
|
|
items => {
|
|
type => "object",
|
|
properties => {},
|
|
},
|
|
links => [ { rel => 'child', href => "{name}" } ],
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $result = [
|
|
{ name => 'version' },
|
|
{ name => 'syslog' },
|
|
{ name => 'status' },
|
|
{ name => 'tasks' },
|
|
{ name => 'rrd' }, # fixme: remove?
|
|
{ name => 'rrddata' },# fixme: remove?
|
|
{ name => 'vncshell' },
|
|
{ name => 'time' },
|
|
{ name => 'dns' },
|
|
{ name => 'services' },
|
|
{ name => 'scan' },
|
|
{ name => 'storage' },
|
|
{ name => 'qemu' },
|
|
{ name => 'openvz' },
|
|
{ name => 'vzdump' },
|
|
{ name => 'ubcfailcnt' },
|
|
{ name => 'network' },
|
|
{ name => 'network_changes' },
|
|
{ name => 'aplinfo' },
|
|
];
|
|
|
|
return $result;
|
|
}});
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'version',
|
|
path => 'version',
|
|
method => 'GET',
|
|
proxyto => 'node',
|
|
permissions => { user => 'all' },
|
|
description => "API version details",
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => {
|
|
type => "object",
|
|
properties => {
|
|
version => { type => 'string' },
|
|
release => { type => 'string' },
|
|
repoid => { type => 'string' },
|
|
},
|
|
},
|
|
code => sub {
|
|
my ($resp, $param) = @_;
|
|
|
|
return PVE::pvecfg::version_info();
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'beancounters_failcnt',
|
|
path => 'ubcfailcnt',
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
|
|
},
|
|
method => 'GET',
|
|
proxyto => 'node',
|
|
protected => 1, # openvz /proc entries are only readable by root
|
|
description => "Get user_beancounters failcnt for all active containers.",
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => {
|
|
type => 'array',
|
|
items => {
|
|
type => "object",
|
|
properties => {
|
|
id => { type => 'string' },
|
|
failcnt => { type => 'number' },
|
|
},
|
|
},
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $ubchash = PVE::OpenVZ::read_user_beancounters();
|
|
|
|
my $res = [];
|
|
foreach my $vmid (keys %$ubchash) {
|
|
next if !$vmid;
|
|
push @$res, { id => $vmid, failcnt => $ubchash->{$vmid}->{failcntsum} };
|
|
|
|
}
|
|
return $res;
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'network_changes',
|
|
path => 'network_changes',
|
|
method => 'GET',
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
|
|
},
|
|
description => "Get network configuration changes (diff) since last boot.",
|
|
proxyto => 'node',
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => { type => "string" },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $res = PVE::INotify::read_file('interfaces', 1);
|
|
|
|
return $res->{changes} || '';
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'revert_network_changes',
|
|
path => 'network_changes',
|
|
method => 'DELETE',
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
|
|
},
|
|
protected => 1,
|
|
description => "Revert network configuration changes.",
|
|
proxyto => 'node',
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => { type => "null" },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
unlink "/etc/network/interfaces.new";
|
|
|
|
return undef;
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'status',
|
|
path => 'status',
|
|
method => 'GET',
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
|
|
},
|
|
description => "Read node status",
|
|
proxyto => 'node',
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => {
|
|
type => "object",
|
|
properties => {
|
|
|
|
},
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $res = {
|
|
uptime => 0,
|
|
idle => 0,
|
|
};
|
|
|
|
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->{pveversion} = PVE::pvecfg::package() . "/" .
|
|
PVE::pvecfg::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},
|
|
};
|
|
|
|
return $res;
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'node_cmd',
|
|
path => 'status',
|
|
method => 'POST',
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.PowerMgmt' ]],
|
|
},
|
|
protected => 1,
|
|
description => "Reboot or shutdown a node.",
|
|
proxyto => 'node',
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
command => {
|
|
description => "Specify the command.",
|
|
type => 'string',
|
|
enum => [qw(reboot shutdown)],
|
|
},
|
|
},
|
|
},
|
|
returns => { type => "null" },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
if ($param->{command} eq 'reboot') {
|
|
system ("(sleep 2;/sbin/reboot)&");
|
|
} elsif ($param->{command} eq 'shutdown') {
|
|
system ("(sleep 2;/sbin/poweroff)&");
|
|
}
|
|
|
|
return undef;
|
|
}});
|
|
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'rrd',
|
|
path => 'rrd',
|
|
method => 'GET',
|
|
protected => 1, # fixme: can we avoid that?
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
|
|
},
|
|
description => "Read node RRD statistics (returns PNG)",
|
|
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' ],
|
|
},
|
|
ds => {
|
|
description => "The list of datasources you want to display.",
|
|
type => 'string', format => 'pve-configid-list',
|
|
},
|
|
cf => {
|
|
description => "The RRD consolidation function",
|
|
type => 'string',
|
|
enum => [ 'AVERAGE', 'MAX' ],
|
|
optional => 1,
|
|
},
|
|
},
|
|
},
|
|
returns => {
|
|
type => "object",
|
|
properties => {
|
|
filename => { type => 'string' },
|
|
},
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
return PVE::Cluster::create_rrd_graph(
|
|
"pve2-node/$param->{node}", $param->{timeframe},
|
|
$param->{ds}, $param->{cf});
|
|
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'rrddata',
|
|
path => 'rrddata',
|
|
method => 'GET',
|
|
protected => 1, # fixme: can we avoid that?
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.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 PVE::Cluster::create_rrd_data(
|
|
"pve2-node/$param->{node}", $param->{timeframe}, $param->{cf});
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'syslog',
|
|
path => 'syslog',
|
|
method => 'GET',
|
|
description => "Read system log",
|
|
proxyto => 'node',
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Syslog' ]],
|
|
},
|
|
protected => 1,
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
start => {
|
|
type => 'integer',
|
|
minimum => 0,
|
|
optional => 1,
|
|
},
|
|
limit => {
|
|
type => 'integer',
|
|
minimum => 0,
|
|
optional => 1,
|
|
},
|
|
},
|
|
},
|
|
returns => {
|
|
type => 'array',
|
|
items => {
|
|
type => "object",
|
|
properties => {
|
|
n => {
|
|
description=> "Line number",
|
|
type=> 'integer',
|
|
},
|
|
t => {
|
|
description=> "Line text",
|
|
type => 'string',
|
|
}
|
|
}
|
|
}
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $rpcenv = PVE::RPCEnvironment::get();
|
|
my $user = $rpcenv->get_user();
|
|
my $node = $param->{node};
|
|
|
|
my ($count, $lines) = PVE::Tools::dump_logfile("/var/log/syslog", $param->{start}, $param->{limit});
|
|
|
|
$rpcenv->set_result_attrib('total', $count);
|
|
|
|
return $lines;
|
|
}});
|
|
|
|
my $sslcert;
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'vncshell',
|
|
path => 'vncshell',
|
|
method => 'POST',
|
|
protected => 1,
|
|
permissions => {
|
|
description => "Restricted to users on realm 'pam'",
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Console' ]],
|
|
},
|
|
description => "Creates a VNC Shell proxy.",
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
user => { type => 'string' },
|
|
ticket => { type => 'string' },
|
|
cert => { type => 'string' },
|
|
port => { type => 'integer' },
|
|
upid => { type => 'string' },
|
|
},
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $rpcenv = PVE::RPCEnvironment::get();
|
|
|
|
my ($user, undef, $realm) = PVE::AccessControl::verify_username($rpcenv->get_user());
|
|
|
|
raise_perm_exc("realm != pam") if $realm ne 'pam';
|
|
|
|
my $node = $param->{node};
|
|
|
|
my $authpath = "/nodes/$node";
|
|
|
|
my $ticket = PVE::AccessControl::assemble_vnc_ticket($user, $authpath);
|
|
|
|
$sslcert = PVE::Tools::file_get_contents("/etc/pve/pve-root-ca.pem", 8192)
|
|
if !$sslcert;
|
|
|
|
my $port = PVE::Tools::next_vnc_port();
|
|
|
|
my $remip;
|
|
|
|
if ($node ne PVE::INotify::nodename()) {
|
|
$remip = PVE::Cluster::remote_node_ip($node);
|
|
}
|
|
|
|
# NOTE: vncterm VNC traffic is already TLS encrypted,
|
|
# so we select the fastest chipher here (or 'none'?)
|
|
my $remcmd = $remip ?
|
|
['/usr/bin/ssh', '-c', 'blowfish-cbc', '-t', $remip] : [];
|
|
|
|
my $shcmd = $user eq 'root@pam' ? [ "/bin/bash", "-l" ] : [ "/bin/login" ];
|
|
|
|
my $timeout = 10;
|
|
|
|
my @cmd = ('/usr/bin/vncterm', '-rfbport', $port,
|
|
'-timeout', $timeout, '-authpath', $authpath,
|
|
'-perm', 'Sys.Console', '-c', @$remcmd, @$shcmd);
|
|
|
|
my $realcmd = sub {
|
|
my $upid = shift;
|
|
|
|
syslog ('info', "starting vnc proxy $upid\n");
|
|
|
|
my $cmdstr = join (' ', @cmd);
|
|
syslog ('info', "launch command: $cmdstr");
|
|
|
|
if (system(@cmd) != 0) {
|
|
my $msg = "vncterm failed - $?";
|
|
syslog ('err', $msg);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
};
|
|
|
|
my $upid = $rpcenv->fork_worker('vncshell', "", $user, $realcmd);
|
|
|
|
return {
|
|
user => $user,
|
|
ticket => $ticket,
|
|
port => $port,
|
|
upid => $upid,
|
|
cert => $sslcert,
|
|
};
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'dns',
|
|
path => 'dns',
|
|
method => 'GET',
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
|
|
},
|
|
description => "Read DNS settings.",
|
|
proxyto => 'node',
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => {
|
|
type => "object",
|
|
additionalProperties => 0,
|
|
properties => {
|
|
search => {
|
|
description => "Search domain for host-name lookup.",
|
|
type => 'string',
|
|
optional => 1,
|
|
},
|
|
dns1 => {
|
|
description => 'First name server IP address.',
|
|
type => 'string',
|
|
optional => 1,
|
|
},
|
|
dns2 => {
|
|
description => 'Second name server IP address.',
|
|
type => 'string',
|
|
optional => 1,
|
|
},
|
|
dns3 => {
|
|
description => 'Third name server IP address.',
|
|
type => 'string',
|
|
optional => 1,
|
|
},
|
|
},
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $res = PVE::INotify::read_file('resolvconf');
|
|
|
|
return $res;
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'update_dns',
|
|
path => 'dns',
|
|
method => 'PUT',
|
|
description => "Write DNS settings.",
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
|
|
},
|
|
proxyto => 'node',
|
|
protected => 1,
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
search => {
|
|
description => "Search domain for host-name lookup.",
|
|
type => 'string',
|
|
},
|
|
dns1 => {
|
|
description => 'First name server IP address.',
|
|
type => 'string', format => 'ipv4',
|
|
optional => 1,
|
|
},
|
|
dns2 => {
|
|
description => 'Second name server IP address.',
|
|
type => 'string', format => 'ipv4',
|
|
optional => 1,
|
|
},
|
|
dns3 => {
|
|
description => 'Third name server IP address.',
|
|
type => 'string', format => 'ipv4',
|
|
optional => 1,
|
|
},
|
|
},
|
|
},
|
|
returns => { type => "null" },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
PVE::INotify::update_file('resolvconf', $param);
|
|
|
|
return undef;
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'time',
|
|
path => 'time',
|
|
method => 'GET',
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
|
|
},
|
|
description => "Read server time and time zone settings.",
|
|
proxyto => 'node',
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => {
|
|
type => "object",
|
|
additionalProperties => 0,
|
|
properties => {
|
|
timezone => {
|
|
description => "Time zone",
|
|
type => 'string',
|
|
},
|
|
time => {
|
|
description => "Seconds since 1970-01-01 00:00:00 UTC.",
|
|
type => 'integer',
|
|
minimum => 1297163644,
|
|
},
|
|
localtime => {
|
|
description => "Seconds since 1970-01-01 00:00:00 (local time)",
|
|
type => 'integer',
|
|
minimum => 1297163644,
|
|
},
|
|
},
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $ctime = time();
|
|
my $ltime = timegm_nocheck(localtime($ctime));
|
|
my $res = {
|
|
timezone => PVE::INotify::read_file('timezone'),
|
|
time => time(),
|
|
localtime => $ltime,
|
|
};
|
|
|
|
return $res;
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'set_timezone',
|
|
path => 'time',
|
|
method => 'PUT',
|
|
description => "Set time zone.",
|
|
permissions => {
|
|
check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
|
|
},
|
|
proxyto => 'node',
|
|
protected => 1,
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
timezone => {
|
|
description => "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.",
|
|
type => 'string',
|
|
},
|
|
},
|
|
},
|
|
returns => { type => "null" },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
PVE::INotify::write_file('timezone', $param->{timezone});
|
|
|
|
return undef;
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'aplinfo',
|
|
path => 'aplinfo',
|
|
method => 'GET',
|
|
permissions => {
|
|
user => 'all',
|
|
},
|
|
description => "Get list of appliances.",
|
|
proxyto => 'node',
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
},
|
|
},
|
|
returns => {
|
|
type => 'array',
|
|
items => {
|
|
type => "object",
|
|
properties => {},
|
|
},
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $res = [];
|
|
|
|
my $list = PVE::APLInfo::load_data();
|
|
|
|
foreach my $template (keys %{$list->{all}}) {
|
|
my $pd = $list->{all}->{$template};
|
|
next if $pd->{'package'} eq 'pve-web-news';
|
|
push @$res, $pd;
|
|
}
|
|
|
|
return $res;
|
|
}});
|
|
|
|
__PACKAGE__->register_method({
|
|
name => 'apl_download',
|
|
path => 'aplinfo',
|
|
method => 'POST',
|
|
permissions => {
|
|
check => ['perm', '/storage/{storage}', ['Datastore.AllocateTemplate']],
|
|
},
|
|
description => "Download appliance templates.",
|
|
proxyto => 'node',
|
|
protected => 1,
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
storage => get_standard_option('pve-storage-id'),
|
|
template => { type => 'string', maxLength => 255 },
|
|
},
|
|
},
|
|
returns => { type => "string" },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $rpcenv = PVE::RPCEnvironment::get();
|
|
|
|
my $user = $rpcenv->get_user();
|
|
|
|
my $node = $param->{node};
|
|
|
|
my $list = PVE::APLInfo::load_data();
|
|
|
|
my $template = $param->{template};
|
|
my $pd = $list->{all}->{$template};
|
|
|
|
raise_param_exc({ template => "no such template"}) if !$pd;
|
|
|
|
my $cfg = cfs_read_file("storage.cfg");
|
|
my $scfg = PVE::Storage::storage_check_enabled($cfg, $param->{storage}, $node);
|
|
|
|
die "cannot download to storage type '$scfg->{type}'"
|
|
if !($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs');
|
|
|
|
die "unknown template type '$pd->{type}'\n" if $pd->{type} ne 'openvz';
|
|
|
|
die "storage '$param->{storage}' does not support templates\n"
|
|
if !$scfg->{content}->{vztmpl};
|
|
|
|
my $src = $pd->{location};
|
|
my $tmpldir = PVE::Storage::get_vztmpl_dir($cfg, $param->{storage});
|
|
my $dest = "$tmpldir/$template";
|
|
my $tmpdest = "$tmpldir/${template}.tmp.$$";
|
|
|
|
my $worker = sub {
|
|
my $upid = shift;
|
|
|
|
print "starting template download from: $src\n";
|
|
print "target file: $dest\n";
|
|
|
|
eval {
|
|
|
|
if (-f $dest) {
|
|
my $md5 = (split (/\s/, `md5sum '$dest'`))[0];
|
|
|
|
if ($md5 && (lc($md5) eq lc($pd->{md5sum}))) {
|
|
print "file already exists $md5 - no need to download\n";
|
|
return;
|
|
}
|
|
}
|
|
|
|
local %ENV;
|
|
my $dccfg = PVE::Cluster::cfs_read_file('datacenter.cfg');
|
|
if ($dccfg->{http_proxy}) {
|
|
$ENV{http_proxy} = $dccfg->{http_proxy};
|
|
}
|
|
|
|
my @cmd = ('/usr/bin/wget', '--progress=dot:mega', '-O', $tmpdest, $src);
|
|
if (system (@cmd) != 0) {
|
|
die "download failed - $!\n";
|
|
}
|
|
|
|
my $md5 = (split (/\s/, `md5sum '$tmpdest'`))[0];
|
|
|
|
if (!$md5 || (lc($md5) ne lc($pd->{md5sum}))) {
|
|
die "wrong checksum: $md5 != $pd->{md5sum}\n";
|
|
}
|
|
|
|
if (system ('mv', $tmpdest, $dest) != 0) {
|
|
die "unable to save file - $!\n";
|
|
}
|
|
};
|
|
my $err = $@;
|
|
|
|
unlink $tmpdest;
|
|
|
|
if ($err) {
|
|
print "\n";
|
|
die $err if $err;
|
|
}
|
|
|
|
print "download finished\n";
|
|
};
|
|
|
|
return $rpcenv->fork_worker('download', undef, $user, $worker);
|
|
}});
|
|
|
|
package PVE::API2::Nodes;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use PVE::SafeSyslog;
|
|
use PVE::Cluster;
|
|
use PVE::RESTHandler;
|
|
use PVE::RPCEnvironment;
|
|
|
|
use base qw(PVE::RESTHandler);
|
|
|
|
__PACKAGE__->register_method ({
|
|
subclass => "PVE::API2::Nodes::Nodeinfo",
|
|
path => '{node}',
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'index',
|
|
path => '',
|
|
method => 'GET',
|
|
permissions => { user => 'all' },
|
|
description => "Cluster node index.",
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {},
|
|
},
|
|
returns => {
|
|
type => 'array',
|
|
items => {
|
|
type => "object",
|
|
properties => {},
|
|
},
|
|
links => [ { rel => 'child', href => "{name}" } ],
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $clinfo = PVE::Cluster::get_clinfo();
|
|
my $res = [];
|
|
|
|
my $nodename = PVE::INotify::nodename();
|
|
my $nodelist = $clinfo->{nodelist};
|
|
|
|
my $rrd = PVE::Cluster::rrd_dump();
|
|
|
|
my @nodes = $nodelist ? (keys %$nodelist) : $nodename;
|
|
|
|
foreach my $node (@nodes) {
|
|
my $entry = { name => $node };
|
|
if (my $d = $rrd->{"pve2-node/$node"}) {
|
|
|
|
$entry->{uptime} = $d->[0];
|
|
$entry->{maxcpu} = $d->[3];
|
|
$entry->{cpu} = $d->[4];
|
|
$entry->{maxmem} = $d->[6];
|
|
$entry->{mem} = $d->[7];
|
|
$entry->{maxdisk} = $d->[10];
|
|
$entry->{disk} = $d->[11];
|
|
}
|
|
|
|
push @$res, $entry;
|
|
}
|
|
|
|
return $res;
|
|
}});
|
|
|
|
1;
|