implement template download
Also added turnkeylinux.com
This commit is contained in:
parent
8710f2803a
commit
c916497537
@ -9,14 +9,16 @@ use PVE::pvecfg;
|
|||||||
use PVE::Tools;
|
use PVE::Tools;
|
||||||
use PVE::ProcFSTools;
|
use PVE::ProcFSTools;
|
||||||
use PVE::SafeSyslog;
|
use PVE::SafeSyslog;
|
||||||
use PVE::Cluster;
|
use PVE::Cluster qw(cfs_read_file);
|
||||||
use PVE::INotify;
|
use PVE::INotify;
|
||||||
use PVE::Exception qw(raise raise_perm_exc);
|
use PVE::Exception qw(raise raise_perm_exc);
|
||||||
use PVE::RESTHandler;
|
use PVE::RESTHandler;
|
||||||
use PVE::RPCEnvironment;
|
use PVE::RPCEnvironment;
|
||||||
use PVE::JSONSchema qw(get_standard_option);
|
use PVE::JSONSchema qw(get_standard_option);
|
||||||
use PVE::AccessControl;
|
use PVE::AccessControl;
|
||||||
|
use PVE::Storage;
|
||||||
use PVE::OpenVZ;
|
use PVE::OpenVZ;
|
||||||
|
use PVE::APLInfo;
|
||||||
use PVE::API2::Services;
|
use PVE::API2::Services;
|
||||||
use PVE::API2::Network;
|
use PVE::API2::Network;
|
||||||
use PVE::API2::Tasks;
|
use PVE::API2::Tasks;
|
||||||
@ -111,6 +113,7 @@ __PACKAGE__->register_method ({
|
|||||||
{ name => 'ubcfailcnt' },
|
{ name => 'ubcfailcnt' },
|
||||||
{ name => 'network' },
|
{ name => 'network' },
|
||||||
{ name => 'network_changes' },
|
{ name => 'network_changes' },
|
||||||
|
{ name => 'aplinfo' },
|
||||||
];
|
];
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@ -746,6 +749,148 @@ __PACKAGE__->register_method({
|
|||||||
return undef;
|
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;
|
package PVE::API2::Nodes;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
285
PVE/APLInfo.pm
285
PVE/APLInfo.pm
@ -3,30 +3,37 @@ package PVE::APLInfo;
|
|||||||
use strict;
|
use strict;
|
||||||
use IO::File;
|
use IO::File;
|
||||||
use PVE::SafeSyslog;
|
use PVE::SafeSyslog;
|
||||||
use PVE::I18N;
|
|
||||||
use LWP::UserAgent;
|
use LWP::UserAgent;
|
||||||
use PVE::Config;
|
|
||||||
use POSIX qw(strftime);
|
use POSIX qw(strftime);
|
||||||
|
|
||||||
my $logfile = "/var/log/pveam.log";
|
my $logfile = "/var/log/pveam.log";
|
||||||
|
my $aplinfodir = "/var/lib/pve-manager/apl-info";
|
||||||
|
|
||||||
# Default list of GPG keys allowed to sign aplinfo
|
# Default list of GPG keys allowed to sign aplinfo
|
||||||
#
|
#
|
||||||
#pub 1024D/5CAC72FE 2004-06-24
|
#pub 1024D/5CAC72FE 2004-06-24
|
||||||
# Key fingerprint = 9ABD 7E02 AD24 3AD3 C2FB BCCC B0C1 CC22 5CAC 72FE
|
# Key fingerprint = 9ABD 7E02 AD24 3AD3 C2FB BCCC B0C1 CC22 5CAC 72FE
|
||||||
#uid Proxmox Support Team <support@proxmox.com>
|
#uid Proxmox Support Team <support@proxmox.com>
|
||||||
|
#pub 2048R/A16EB94D 2008-08-15 [expires: 2023-08-12]
|
||||||
|
# Key fingerprint = 694C FF26 795A 29BA E07B 4EB5 85C2 5E95 A16E B94D
|
||||||
|
#uid Turnkey Linux Release Key <release@turnkeylinux.com>
|
||||||
|
|
||||||
my $valid_keys = {
|
my $valid_keys = {
|
||||||
'9ABD7E02AD243AD3C2FBBCCCB0C1CC225CAC72FE' => 1, # fingerprint support@proxmox.com
|
'9ABD7E02AD243AD3C2FBBCCCB0C1CC225CAC72FE' => 1, # fingerprint support@proxmox.com
|
||||||
'25CAC72FE' => 1, # keyid support@proxmox.com
|
'25CAC72FE' => 1, # keyid support@proxmox.com
|
||||||
|
'694CFF26795A29BAE07B4EB585C25E95A16EB94D' => 1, # fingerprint release@turnkeylinux.com
|
||||||
|
'A16EB94D' => 1, # keyid release@turnkeylinux.com
|
||||||
};
|
};
|
||||||
|
|
||||||
sub import_gpg_keys {
|
sub import_gpg_keys {
|
||||||
|
|
||||||
my $keyfile = '/usr/share/doc/pve-manager/support@proxmox.com.pubkey';
|
my @keyfiles = ('support@proxmox.com.pubkey', 'release@turnkeylinux.com.pubkey');
|
||||||
|
|
||||||
return system ("/usr/bin/gpg --batch --no-tty --status-fd=1 -q " .
|
foreach my $key (@keyfiles) {
|
||||||
"--logger-fd=1 --import $keyfile >>$logfile");
|
my $fn = "/usr/share/doc/pve-manager/$key";
|
||||||
|
system ("/usr/bin/gpg --batch --no-tty --status-fd=1 -q " .
|
||||||
|
"--logger-fd=1 --import $fn >>$logfile");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub logmsg {
|
sub logmsg {
|
||||||
@ -41,6 +48,91 @@ sub logmsg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub read_aplinfo {
|
||||||
|
my ($filename, $list, $source, $update) = @_;
|
||||||
|
|
||||||
|
my $fh = IO::File->new("<$filename") ||
|
||||||
|
die "unable to open file '$filename' - $!\n";
|
||||||
|
|
||||||
|
local $/ = "";
|
||||||
|
|
||||||
|
eval {
|
||||||
|
while (my $rec = <$fh>) {
|
||||||
|
chomp $rec;
|
||||||
|
|
||||||
|
my $res = {};
|
||||||
|
|
||||||
|
while ($rec) {
|
||||||
|
|
||||||
|
if ($rec =~ s/^Description:\s*([^\n]*)(\n\s+.*)*$//si) {
|
||||||
|
$res->{headline} = $1;
|
||||||
|
my $long = $2;
|
||||||
|
$long =~ s/\n\s+/ /g;
|
||||||
|
$long =~ s/^\s+//g;
|
||||||
|
$long =~ s/\s+$//g;
|
||||||
|
$res->{description} = $long;
|
||||||
|
} elsif ($rec =~ s/^Version:\s*(.*\S)\s*\n//i) {
|
||||||
|
my $version = $1;
|
||||||
|
if ($version =~ m/^(\d[a-zA-Z0-9\.\+\-\:\~]*)-(\d+)$/) {
|
||||||
|
$res->{version} = $version;
|
||||||
|
} else {
|
||||||
|
my $msg = "unable to parse appliance record: version = '$version'\n";
|
||||||
|
$update ? die $msg : warn $msg;
|
||||||
|
}
|
||||||
|
} elsif ($rec =~ s/^Type:\s*(.*\S)\s*\n//i) {
|
||||||
|
my $type = $1;
|
||||||
|
if ($type =~ m/^(openvz)$/) {
|
||||||
|
$res->{type} = $type;
|
||||||
|
} else {
|
||||||
|
my $msg = "unable to parse appliance record: unknown type '$type'\n";
|
||||||
|
$update ? die $msg : warn $msg;
|
||||||
|
}
|
||||||
|
} elsif ($rec =~ s/^([^:]+):\s*(.*\S)\s*\n//) {
|
||||||
|
$res->{lc $1} = $2;
|
||||||
|
} else {
|
||||||
|
my $msg = "unable to parse appliance record: $rec\n";
|
||||||
|
$update ? die $msg : warn $msg;
|
||||||
|
$res = {};
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($res->{'package'} eq 'pve-web-news' && $res->{description}) {
|
||||||
|
$list->{'all'}->{$res->{'package'}} = $res;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
$res->{section} = 'unknown' if !$res->{section};
|
||||||
|
|
||||||
|
if ($res->{'package'} && $res->{type} && $res->{os} && $res->{version} &&
|
||||||
|
$res->{infopage}) {
|
||||||
|
my $template;
|
||||||
|
if ($res->{location}) {
|
||||||
|
$template = $res->{location};
|
||||||
|
$template =~ s|.*/([^/]+.tar.gz)|$1|;
|
||||||
|
} else {
|
||||||
|
$template = "$res->{os}-$res->{package}_$res->{version}_i386.tar.gz";
|
||||||
|
$template =~ s/$res->{os}-$res->{os}-/$res->{os}-/;
|
||||||
|
}
|
||||||
|
$res->{source} = $source;
|
||||||
|
$res->{template} = $template;
|
||||||
|
$list->{$res->{section}}->{$template} = $res;
|
||||||
|
$list->{'all'}->{$template} = $res;
|
||||||
|
} else {
|
||||||
|
my $msg = "found incomplete appliance records\n";
|
||||||
|
$update ? die $msg : warn $msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
my $err = $@;
|
||||||
|
|
||||||
|
close($fh);
|
||||||
|
|
||||||
|
die $err if $err;
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
sub url_get {
|
sub url_get {
|
||||||
my ($ua, $url, $file, $logfh) = @_;
|
my ($ua, $url, $file, $logfh) = @_;
|
||||||
|
|
||||||
@ -59,64 +151,43 @@ sub url_get {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub update {
|
sub download_aplinfo {
|
||||||
my ($proxy) = @_;
|
my ($ua, $aplurl, $host, $logfd) = @_;
|
||||||
|
|
||||||
my $aplurl = "http://download.proxmox.com/appliances";
|
|
||||||
my $aplsrcurl = "$aplurl/aplinfo.dat.gz";
|
my $aplsrcurl = "$aplurl/aplinfo.dat.gz";
|
||||||
my $aplsigurl = "$aplurl/aplinfo.dat.asc";
|
my $aplsigurl = "$aplurl/aplinfo.dat.asc";
|
||||||
|
|
||||||
my $size;
|
my $tmp = "$aplinfodir/pveam-${host}.tmp.$$";
|
||||||
if (($size = (-s $logfile) || 0) > (1024*50)) {
|
|
||||||
system ("mv $logfile $logfile.0");
|
|
||||||
}
|
|
||||||
my $logfd = IO::File->new (">>$logfile");
|
|
||||||
logmsg ($logfd, "starting update");
|
|
||||||
|
|
||||||
import_gpg_keys();
|
|
||||||
|
|
||||||
my $tmp = "/tmp/pveam.tmp.$$";
|
|
||||||
my $tmpgz = "$tmp.gz";
|
my $tmpgz = "$tmp.gz";
|
||||||
my $sigfn = "$tmp.asc";
|
my $sigfn = "$tmp.asc";
|
||||||
|
|
||||||
# this code works for ftp and http
|
|
||||||
# always use passive ftp
|
|
||||||
local $ENV{FTP_PASSIVE} = 1;
|
|
||||||
my $ua = LWP::UserAgent->new;
|
|
||||||
$ua->agent("PVE/1.0");
|
|
||||||
|
|
||||||
if ($proxy) {
|
|
||||||
$ua->proxy(['http'], $proxy);
|
|
||||||
} else {
|
|
||||||
$ua->env_proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
if (url_get ($ua, $aplsigurl, $sigfn, $logfd) != 0) {
|
|
||||||
die "update failed - no signature\n";
|
if (url_get($ua, $aplsigurl, $sigfn, $logfd) != 0) {
|
||||||
|
die "update failed - no signature file '$sigfn'\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url_get ($ua, $aplsrcurl, $tmpgz, $logfd) != 0) {
|
if (url_get($ua, $aplsrcurl, $tmpgz, $logfd) != 0) {
|
||||||
die "update failed - no data\n";
|
die "update failed - no data file '$aplsrcurl'\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (system ("zcat -f $tmpgz >$tmp 2>/dev/null") != 0) {
|
if (system("zcat -f $tmpgz >$tmp 2>/dev/null") != 0) {
|
||||||
die "update failed: unable to unpack '$tmpgz'\n";
|
die "update failed: unable to unpack '$tmpgz'\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
# verify signature
|
# verify signature
|
||||||
|
|
||||||
my $cmd = "/usr/bin/gpg --verify --batch --no-tty --status-fd=1 -q " .
|
my $cmd = "/usr/bin/gpg --verify --trust-model always --batch --no-tty --status-fd=1 -q " .
|
||||||
"--logger-fd=1 $sigfn $tmp";
|
"--logger-fd=1 $sigfn $tmp";
|
||||||
|
|
||||||
open (CMD, "$cmd|") ||
|
open(CMD, "$cmd|") ||
|
||||||
die "unable to execute '$cmd': $!\n";
|
die "unable to execute '$cmd': $!\n";
|
||||||
|
|
||||||
my $line;
|
my $line;
|
||||||
my $signer = '';
|
my $signer = '';
|
||||||
while (defined ($line = <CMD>)) {
|
while (defined($line = <CMD>)) {
|
||||||
chomp $line;
|
chomp $line;
|
||||||
logmsg ($logfd, $line);
|
logmsg($logfd, $line);
|
||||||
|
|
||||||
# code borrowed from SA
|
# code borrowed from SA
|
||||||
next if $line !~ /^\Q[GNUPG:]\E (?:VALID|GOOD)SIG (\S{8,40})/;
|
next if $line !~ /^\Q[GNUPG:]\E (?:VALID|GOOD)SIG (\S{8,40})/;
|
||||||
@ -130,26 +201,26 @@ sub update {
|
|||||||
$signer = $key if (length $key > length $signer) && $valid_keys->{$key};
|
$signer = $key if (length $key > length $signer) && $valid_keys->{$key};
|
||||||
}
|
}
|
||||||
|
|
||||||
close (CMD);
|
close(CMD);
|
||||||
|
|
||||||
die "unable to verify signature\n" if !$signer;
|
die "unable to verify signature\n" if !$signer;
|
||||||
|
|
||||||
logmsg ($logfd, "signature valid: $signer");
|
logmsg($logfd, "signature valid: $signer");
|
||||||
|
|
||||||
# test syntax
|
# test syntax
|
||||||
eval {
|
eval {
|
||||||
my $fh = IO::File->new ("<$tmp") ||
|
my $fh = IO::File->new("<$tmp") ||
|
||||||
die "unable to open file '$tmp' - $!\n";
|
die "unable to open file '$tmp' - $!\n";
|
||||||
PVE::Config::read_aplinfo ($tmp, $fh, 1);
|
read_aplinfo($tmp, {}, $aplurl, 1);
|
||||||
close ($fh);
|
close($fh);
|
||||||
};
|
};
|
||||||
die "update failed: $@" if $@;
|
die "update failed: $@" if $@;
|
||||||
|
|
||||||
if (system ("mv $tmp /var/lib/pve-manager/apl-available 2>/dev/null") != 0) {
|
if (system("mv $tmp $aplinfodir/$host 2>/dev/null") != 0) {
|
||||||
die "update failed: unable to store data\n";
|
die "update failed: unable to store data\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
logmsg ($logfd, "update sucessful");
|
logmsg($logfd, "update sucessful");
|
||||||
};
|
};
|
||||||
|
|
||||||
my $err = $@;
|
my $err = $@;
|
||||||
@ -158,78 +229,90 @@ sub update {
|
|||||||
unlink $tmpgz;
|
unlink $tmpgz;
|
||||||
unlink $sigfn;
|
unlink $sigfn;
|
||||||
|
|
||||||
if ($err) {
|
die $err if $err;
|
||||||
logmsg ($logfd, $err);
|
}
|
||||||
close ($logfd);
|
|
||||||
|
|
||||||
return 0;
|
sub get_apl_sources {
|
||||||
|
|
||||||
|
my $urls = [];
|
||||||
|
push @$urls, "http://download.proxmox.com/appliances";
|
||||||
|
push @$urls, "http://releases.turnkeylinux.org/pve";
|
||||||
|
|
||||||
|
return $urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub update {
|
||||||
|
my ($proxy) = @_;
|
||||||
|
|
||||||
|
my $size;
|
||||||
|
if (($size = (-s $logfile) || 0) > (1024*50)) {
|
||||||
|
system ("mv $logfile $logfile.0");
|
||||||
|
}
|
||||||
|
my $logfd = IO::File->new (">>$logfile");
|
||||||
|
logmsg($logfd, "starting update");
|
||||||
|
|
||||||
|
import_gpg_keys();
|
||||||
|
|
||||||
|
# this code works for ftp and http
|
||||||
|
# always use passive ftp
|
||||||
|
local $ENV{FTP_PASSIVE} = 1;
|
||||||
|
my $ua = LWP::UserAgent->new;
|
||||||
|
$ua->agent("PVE/1.0");
|
||||||
|
|
||||||
|
if ($proxy) {
|
||||||
|
$ua->proxy(['http'], $proxy);
|
||||||
|
} else {
|
||||||
|
$ua->env_proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $urls = get_apl_sources();
|
||||||
|
|
||||||
|
mkdir $aplinfodir;
|
||||||
|
|
||||||
|
my @dlerr = ();
|
||||||
|
foreach my $aplurl (@$urls) {
|
||||||
|
eval {
|
||||||
|
my $uri = URI->new($aplurl);
|
||||||
|
my $host = $uri->host();
|
||||||
|
download_aplinfo($ua, $aplurl, $host, $logfd);
|
||||||
|
};
|
||||||
|
if (my $err = $@) {
|
||||||
|
logmsg ($logfd, $err);
|
||||||
|
push @dlerr, $aplurl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close ($logfd);
|
close($logfd);
|
||||||
|
|
||||||
|
return 0 if scalar(@dlerr);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub load_data {
|
sub load_data {
|
||||||
|
|
||||||
my $filename = "/var/lib/pve-manager/apl-available";
|
my $filename = "$aplinfodir/download.proxmox.com";
|
||||||
|
|
||||||
if (! -f $filename) {
|
if (! -f $filename) {
|
||||||
system ("cp /usr/share/doc/pve-manager/aplinfo.dat /var/lib/pve-manager/apl-available");
|
mkdir $aplinfodir;
|
||||||
|
system("cp /usr/share/doc/pve-manager/aplinfo.dat $filename");
|
||||||
}
|
}
|
||||||
|
|
||||||
return PVE::Config::read_file ('aplinfo');
|
my $urls = get_apl_sources();
|
||||||
}
|
|
||||||
|
|
||||||
sub display_name {
|
my $list = {};
|
||||||
my ($template) = @_;
|
|
||||||
|
|
||||||
my $templates = load_data ();
|
foreach my $aplurl (@$urls) {
|
||||||
|
|
||||||
return $template if !$templates;
|
eval {
|
||||||
|
|
||||||
my $d = $templates->{'all'}->{$template};
|
my $uri = URI->new($aplurl);
|
||||||
|
my $host = $uri->host();
|
||||||
|
read_aplinfo("$aplinfodir/$host", $list, $aplurl);
|
||||||
|
};
|
||||||
|
warn $@ if $@;
|
||||||
|
}
|
||||||
|
|
||||||
$template =~ s/\.tar\.gz$//;
|
return $list;
|
||||||
$template =~ s/_i386$//;
|
|
||||||
|
|
||||||
return $template if !$d;
|
|
||||||
|
|
||||||
return "$d->{package}_$d->{version}";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub pkginfo {
|
|
||||||
my ($template) = @_;
|
|
||||||
|
|
||||||
my $templates = load_data ();
|
|
||||||
|
|
||||||
return undef if !$templates;
|
|
||||||
|
|
||||||
my $d = $templates->{'all'}->{$template};
|
|
||||||
|
|
||||||
return $d;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub webnews {
|
|
||||||
my ($lang) = @_;
|
|
||||||
|
|
||||||
my $templates = load_data ();
|
|
||||||
|
|
||||||
my $html = '';
|
|
||||||
|
|
||||||
$html .= __("<b>Welcome</b> to the Proxmox Virtual Environment!");
|
|
||||||
$html .= "<br><br>";
|
|
||||||
$html .= __("For more information please visit our homepage at");
|
|
||||||
$html .= " <a href='http://www.proxmox.com' target='_blank'>www.proxmox.com</a>.";
|
|
||||||
|
|
||||||
return $html if !$templates;
|
|
||||||
|
|
||||||
# my $d = $templates->{'all'}->{"pve-web-news-$lang"} ||
|
|
||||||
my $d = $templates->{all}->{'pve-web-news'};
|
|
||||||
|
|
||||||
return $html if !$d;
|
|
||||||
|
|
||||||
return $d->{description};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -10,6 +10,7 @@ PERLSOURCE = \
|
|||||||
REST.pm \
|
REST.pm \
|
||||||
OpenVZ.pm \
|
OpenVZ.pm \
|
||||||
OpenVZMigrate.pm \
|
OpenVZMigrate.pm \
|
||||||
|
APLInfo.pm \
|
||||||
VZDump.pm
|
VZDump.pm
|
||||||
|
|
||||||
all: pvecfg.pm ${SUBDIRS}
|
all: pvecfg.pm ${SUBDIRS}
|
||||||
|
@ -7,6 +7,7 @@ all:
|
|||||||
install: aplinfo.dat support@proxmox.com.pubkey
|
install: aplinfo.dat support@proxmox.com.pubkey
|
||||||
install -D -m 0644 aplinfo.dat ${DESTDIR}${DOCDIR}/aplinfo.dat
|
install -D -m 0644 aplinfo.dat ${DESTDIR}${DOCDIR}/aplinfo.dat
|
||||||
install -D -m 0644 support@proxmox.com.pubkey ${DESTDIR}${DOCDIR}/support@proxmox.com.pubkey
|
install -D -m 0644 support@proxmox.com.pubkey ${DESTDIR}${DOCDIR}/support@proxmox.com.pubkey
|
||||||
|
install -D -m 0644 release@turnkeylinux.com.pubkey ${DESTDIR}${DOCDIR}/release@turnkeylinux.com.pubkey
|
||||||
|
|
||||||
.PHONY: distclean
|
.PHONY: distclean
|
||||||
distclean: clean
|
distclean: clean
|
||||||
|
31
aplinfo/release@turnkeylinux.com.pubkey
Normal file
31
aplinfo/release@turnkeylinux.com.pubkey
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: GnuPG v1.4.10 (GNU/Linux)
|
||||||
|
|
||||||
|
mQENBEilXh0BCADtICrXzrAP7Q5fFzAMrQYvpSrWn7+UUbmMn35fEpS9IzAbZSDX
|
||||||
|
24nBG8LTuWDXqbmT0lqam/rkTrVQpZFeSimcZx1Y68iG+Iw6BJvK3XrfaCFUUeyy
|
||||||
|
+JTgHNr73N03jQ6LS/wkjCQQ3YLD4vrI+ti1bs24QOavnDad8oqYMbSDBhqeiOkE
|
||||||
|
97THg0afEhxiq2C13SW5aHlSmGw0EulKGfa/0MmIFmmztE7Vz1qumbd75p6bheDK
|
||||||
|
HhtdHz5L2zDOK0C98h6oYKBnEr+anfXRPgEQAs3qNm1zRcgjd9xyF3KKuRQZoTAK
|
||||||
|
8kyYoFI09C+rPs7Cm438k7GSr4pHDWwb+GDBABEBAAG0NFR1cm5rZXkgTGludXgg
|
||||||
|
UmVsZWFzZSBLZXkgPHJlbGVhc2VAdHVybmtleWxpbnV4LmNvbT6JARwEEAECAAYF
|
||||||
|
AklrWbAACgkQbeyW07BngNkbzAf/XkA+TMcWQ4i0/Epi4zEp9Fb+gtPZnzvHFqcG
|
||||||
|
lb/l79hcxiw/JfadOa+BqdKGmTyPreu/yLAPE2GIc9Z8cMsiTTWu1ILy1TmXYw2e
|
||||||
|
Zx8AmpqeV4Jzn4ygLuimNpyguCIRhSnyjvtXOX2Jf2ZpwbNT6rD3gmAJca3onVLu
|
||||||
|
cTGpJX1JWmmnc8aXmUzX7KjC/4EGg0ShxGC00WCaQnaHp1QDQ0rWMm3la/wyZj/1
|
||||||
|
27n69PMjjfcpDow1jJ45QPykRxV/gRnS++ymPHkQFERACYtIS9MAbzOXwCoLprci
|
||||||
|
J9lOEIU/fc0wzmnZaRenLzmh/hhLkCKw30ByRECD89n7kVE7uYkBHAQTAQIABgUC
|
||||||
|
SKVgagAKCRDA8gC1FJezDGJAB/9DvOR3ZcW6vWoV9BwSOjgJTDKOePQ6C4wUOHF1
|
||||||
|
sDu0EKQTzJhD4/ca0KN7NiAx9D4I+2FQS9ZnqyIATWGqNeMdSgnuo5iq79eQ4pZn
|
||||||
|
Quor2hzrzeHdoPZHDRt7CzChMztXg8CwipPhzTrXBaWKQuomxpvt93RgQS+Ktt5S
|
||||||
|
rojoEDj1/lCgfm4D/XnVns31h5RQ9q+YMpbGOOVTCW1oxo74X++n8R1C4DuX0sxv
|
||||||
|
Vqyu28lwOrLcbV4Ur7xjAjSjXM4q1cX/Bxt1KeLtVR8FTK+6TNQoZNycx46Yw2G4
|
||||||
|
38PPVrFmvunNBgB30iO08SUZ9mULU47BQcZ8WdqrewzaQkwEiQE8BBMBAgAmBQJI
|
||||||
|
pV4dAhsDBQkcMgSABgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQhcJelaFuuU3N
|
||||||
|
+Qf/fhpcQROYB00dU7E0LJ3iP5cwUALJebbmKlNmoCNoqskZ4JS+hvy4AJmxsf2M
|
||||||
|
UdlMUTL8TwOxyfNDj4kfXv4phNw4X47TwUU3OBXcQNpFf9em3zJG2WID8EesGX8Z
|
||||||
|
nGsCpOWhwOiBo5LfrFqCaCet3gUXaRjmuVcUkEyHmFd0TyWljEhINCS9wqQk55TO
|
||||||
|
juRigCGGEvxB8i6b4o64rVc6EVZizzLUzvXDgDOaqxSsYrKt34ezPgGpRQgy/HNF
|
||||||
|
C6LTLFlxJvwG42YZETK3S1R1RAVZQ6II4pl8Et3iU8aFoot64zx+GnFI62/krcG6
|
||||||
|
5ul/98lS4h1xGJfl6U0NIu8tjw==
|
||||||
|
=DmER
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
@ -1,7 +1,8 @@
|
|||||||
#!/usr/bin/perl -w
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
#use PVE::APLInfo;
|
use PVE::Cluster;
|
||||||
|
use PVE::APLInfo;
|
||||||
use PVE::SafeSyslog;
|
use PVE::SafeSyslog;
|
||||||
use IO::File;
|
use IO::File;
|
||||||
use File::Find;
|
use File::Find;
|
||||||
@ -9,14 +10,11 @@ use File::stat;
|
|||||||
|
|
||||||
initlog ('pvedailycron', 'daemon');
|
initlog ('pvedailycron', 'daemon');
|
||||||
|
|
||||||
# fixme: update APL info?
|
my $dccfg = PVE::Cluster::cfs_read_file('datacenter.cfg');
|
||||||
#my $pvecfg = PVE::Config::read_file('pvecfg');
|
eval { PVE::APLInfo::update($dccfg->{http_proxy}); };
|
||||||
#my $proxy = ($pvecfg && $pvecfg->{http_proxy}) ? $pvecfg->{http_proxy} : undef;
|
if (my $err = $@) {
|
||||||
|
syslog ('err', "update appliance info failed - see /var/log/pveam.log for details");
|
||||||
## update appliance info
|
}
|
||||||
#if (!PVE::APLInfo::update()) {
|
|
||||||
# syslog ('err', "update appliance info failed - see /var/log/pveam.log for details");
|
|
||||||
#}
|
|
||||||
|
|
||||||
sub cleanup_tasks {
|
sub cleanup_tasks {
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use PVE::Cluster;
|
use PVE::Cluster;
|
||||||
#use PVE::APLInfo;
|
use PVE::APLInfo;
|
||||||
|
|
||||||
if (scalar (@ARGV) != 1) {
|
if (scalar (@ARGV) != 1) {
|
||||||
print STDERR "usage: $0 CMD\n";
|
print STDERR "usage: $0 CMD\n";
|
||||||
@ -13,9 +13,8 @@ my $cmd = shift;
|
|||||||
|
|
||||||
if ($cmd eq 'update') {
|
if ($cmd eq 'update') {
|
||||||
my $dccfg = PVE::Cluster::cfs_read_file('datacenter.cfg');
|
my $dccfg = PVE::Cluster::cfs_read_file('datacenter.cfg');
|
||||||
die "sorry, this is currently not implemented\n";
|
exit (0) if PVE::APLInfo::update($dccfg->{http_proxy});
|
||||||
#exit (0) if PVE::APLInfo::update($dccfg->{http_proxy});
|
print STDERR "update failed - see /var/log/pveam.log for details\n";
|
||||||
#print STDERR "update failed - see /var/log/pveam.log for details\n";
|
|
||||||
exit (-1);
|
exit (-1);
|
||||||
} else {
|
} else {
|
||||||
print STDERR "unknown CMD '$cmd'\n";
|
print STDERR "unknown CMD '$cmd'\n";
|
||||||
|
8
debian/changelog.Debian
vendored
8
debian/changelog.Debian
vendored
@ -1,3 +1,11 @@
|
|||||||
|
pve-manager (2.0-31) unstable; urgency=low
|
||||||
|
|
||||||
|
* add template download GUI
|
||||||
|
|
||||||
|
* include turnkey appliances in download list.
|
||||||
|
|
||||||
|
-- Proxmox Support Team <support@proxmox.com> Tue, 21 Feb 2012 11:45:07 +0100
|
||||||
|
|
||||||
pve-manager (2.0-30) unstable; urgency=low
|
pve-manager (2.0-30) unstable; urgency=low
|
||||||
|
|
||||||
* add unmount button to openvz GUI
|
* add unmount button to openvz GUI
|
||||||
|
3
debian/postinst
vendored
3
debian/postinst
vendored
@ -37,7 +37,8 @@ case "$1" in
|
|||||||
|
|
||||||
mkdir /etc/pve 2>/dev/null || true
|
mkdir /etc/pve 2>/dev/null || true
|
||||||
|
|
||||||
test -e /var/lib/pve-manager/apl-available || cp /usr/share/doc/pve-manager/aplinfo.dat /var/lib/pve-manager/apl-available
|
# remove old APL dir
|
||||||
|
rm -rf /var/lib/pve-manager/apl-available
|
||||||
|
|
||||||
if test -f /root/.forward; then
|
if test -f /root/.forward; then
|
||||||
if ! grep -q '|/usr/bin/pvemailforward' /root/.forward; then
|
if ! grep -q '|/usr/bin/pvemailforward' /root/.forward; then
|
||||||
|
@ -2,7 +2,7 @@ RELEASE=2.0
|
|||||||
|
|
||||||
VERSION=2.0
|
VERSION=2.0
|
||||||
PACKAGE=pve-manager
|
PACKAGE=pve-manager
|
||||||
PACKAGERELEASE=30
|
PACKAGERELEASE=31
|
||||||
|
|
||||||
BINDIR=${DESTDIR}/usr/bin
|
BINDIR=${DESTDIR}/usr/bin
|
||||||
PERLLIBDIR=${DESTDIR}/usr/share/perl5
|
PERLLIBDIR=${DESTDIR}/usr/share/perl5
|
||||||
|
@ -396,6 +396,8 @@ Ext.define('PVE.Utils', { statics: {
|
|||||||
srvstop: ['SRV', gettext('Stop') ],
|
srvstop: ['SRV', gettext('Stop') ],
|
||||||
srvrestart: ['SRV', gettext('Restart') ],
|
srvrestart: ['SRV', gettext('Restart') ],
|
||||||
srvreload: ['SRV', gettext('Reload') ],
|
srvreload: ['SRV', gettext('Reload') ],
|
||||||
|
imgcopy: ['', gettext('Copy data') ],
|
||||||
|
download: ['', gettext('Download') ],
|
||||||
vzdump: ['', gettext('Backup') ]
|
vzdump: ['', gettext('Backup') ]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,3 +1,146 @@
|
|||||||
|
Ext.define('PVE.grid.TemplateSelector', {
|
||||||
|
extend: 'Ext.grid.GridPanel',
|
||||||
|
|
||||||
|
alias: ['widget.pveTemplateSelector'],
|
||||||
|
|
||||||
|
initComponent : function() {
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
if (!me.nodename) {
|
||||||
|
throw "no node name specified";
|
||||||
|
}
|
||||||
|
|
||||||
|
var baseurl = "/nodes/" + me.nodename + "/aplinfo";
|
||||||
|
var store = new Ext.data.Store({
|
||||||
|
model: 'pve-aplinfo',
|
||||||
|
groupField: 'section',
|
||||||
|
proxy: {
|
||||||
|
type: 'pve',
|
||||||
|
url: '/api2/json' + baseurl
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var sm = Ext.create('Ext.selection.RowModel', {});
|
||||||
|
|
||||||
|
var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
|
||||||
|
groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
|
||||||
|
});
|
||||||
|
|
||||||
|
var reload = function() {
|
||||||
|
store.load();
|
||||||
|
};
|
||||||
|
|
||||||
|
PVE.Utils.monStoreErrors(me, store);
|
||||||
|
|
||||||
|
Ext.apply(me, {
|
||||||
|
store: store,
|
||||||
|
selModel: sm,
|
||||||
|
stateful: false,
|
||||||
|
viewConfig: {
|
||||||
|
trackOver: false
|
||||||
|
},
|
||||||
|
features: [ groupingFeature ],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
header: gettext('Type'),
|
||||||
|
width: 80,
|
||||||
|
dataIndex: 'type'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: gettext('Package'),
|
||||||
|
flex: 1,
|
||||||
|
dataIndex: 'package'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: gettext('Version'),
|
||||||
|
width: 80,
|
||||||
|
dataIndex: 'version'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: gettext('Description'),
|
||||||
|
flex: 1.5,
|
||||||
|
dataIndex: 'headline'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
listeners: {
|
||||||
|
afterRender: reload
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
me.callParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
}, function() {
|
||||||
|
|
||||||
|
Ext.define('pve-aplinfo', {
|
||||||
|
extend: 'Ext.data.Model',
|
||||||
|
fields: [
|
||||||
|
'template', 'type', 'package', 'version', 'headline', 'infopage',
|
||||||
|
'description', 'os', 'section'
|
||||||
|
],
|
||||||
|
idProperty: 'template'
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
Ext.define('PVE.storage.TemplateDownload', {
|
||||||
|
extend: 'Ext.window.Window',
|
||||||
|
alias: ['widget.pveTemplateDownload'],
|
||||||
|
|
||||||
|
modal: true,
|
||||||
|
|
||||||
|
initComponent : function() {
|
||||||
|
/*jslint confusion: true */
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
var grid = Ext.create('PVE.grid.TemplateSelector', {
|
||||||
|
width: 600,
|
||||||
|
height: 400,
|
||||||
|
border: false,
|
||||||
|
autoScroll: true,
|
||||||
|
nodename: me.nodename
|
||||||
|
});
|
||||||
|
|
||||||
|
var sm = grid.getSelectionModel();
|
||||||
|
|
||||||
|
var submitBtn = Ext.create('PVE.button.Button', {
|
||||||
|
text: gettext('Download'),
|
||||||
|
disabled: true,
|
||||||
|
selModel: sm,
|
||||||
|
handler: function(button, event, rec) {
|
||||||
|
PVE.Utils.API2Request({
|
||||||
|
url: '/nodes/' + me.nodename + '/aplinfo',
|
||||||
|
params: {
|
||||||
|
storage: me.storage,
|
||||||
|
template: rec.data.template
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
failure: function (response, opts) {
|
||||||
|
Ext.Msg.alert('Error', response.htmlStatus);
|
||||||
|
},
|
||||||
|
success: function(response, options) {
|
||||||
|
var upid = response.result.data;
|
||||||
|
|
||||||
|
var win = Ext.create('PVE.window.TaskViewer', {
|
||||||
|
upid: upid
|
||||||
|
});
|
||||||
|
win.show();
|
||||||
|
me.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ext.applyIf(me, {
|
||||||
|
title: gettext('Template download'),
|
||||||
|
items: grid,
|
||||||
|
buttons: [ submitBtn ]
|
||||||
|
});
|
||||||
|
|
||||||
|
me.callParent();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Ext.define('PVE.storage.Upload', {
|
Ext.define('PVE.storage.Upload', {
|
||||||
extend: 'Ext.window.Window',
|
extend: 'Ext.window.Window',
|
||||||
alias: ['widget.pveStorageUpload'],
|
alias: ['widget.pveStorageUpload'],
|
||||||
@ -279,6 +422,17 @@ Ext.define('PVE.storage.ContentView', {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: gettext('Templates'),
|
||||||
|
handler: function() {
|
||||||
|
var win = Ext.create('PVE.storage.TemplateDownload', {
|
||||||
|
nodename: nodename,
|
||||||
|
storage: storage
|
||||||
|
});
|
||||||
|
win.show();
|
||||||
|
win.on('destroy', reload);
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: gettext('Upload'),
|
text: gettext('Upload'),
|
||||||
handler: function() {
|
handler: function() {
|
||||||
|
Loading…
Reference in New Issue
Block a user