From 82f9a5d7cf2df3b98e1560a85724edff8a726de0 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Tue, 21 Feb 2012 11:42:32 +0100 Subject: [PATCH] implement template download Also added turnkeylinux.com --- PVE/API2/Nodes.pm | 147 ++++++++++++- PVE/APLInfo.pm | 271 ++++++++++++++++-------- PVE/Makefile | 1 + aplinfo/Makefile | 1 + aplinfo/release@turnkeylinux.com.pubkey | 31 +++ bin/cron/daily/pve | 16 +- bin/pveam | 7 +- debian/changelog.Debian | 8 + debian/postinst | 3 +- defines.mk | 2 +- www/manager/Utils.js | 2 + www/manager/storage/ContentView.js | 154 ++++++++++++++ 12 files changed, 533 insertions(+), 110 deletions(-) create mode 100644 aplinfo/release@turnkeylinux.com.pubkey diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm index d8605e10..a819a815 100644 --- a/PVE/API2/Nodes.pm +++ b/PVE/API2/Nodes.pm @@ -9,14 +9,16 @@ use PVE::pvecfg; use PVE::Tools; use PVE::ProcFSTools; use PVE::SafeSyslog; -use PVE::Cluster; +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; @@ -111,6 +113,7 @@ __PACKAGE__->register_method ({ { name => 'ubcfailcnt' }, { name => 'network' }, { name => 'network_changes' }, + { name => 'aplinfo' }, ]; return $result; @@ -746,6 +749,148 @@ __PACKAGE__->register_method({ 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; diff --git a/PVE/APLInfo.pm b/PVE/APLInfo.pm index 26fd791e..5d260a38 100644 --- a/PVE/APLInfo.pm +++ b/PVE/APLInfo.pm @@ -3,30 +3,37 @@ package PVE::APLInfo; use strict; use IO::File; use PVE::SafeSyslog; -use PVE::I18N; use LWP::UserAgent; -use PVE::Config; use POSIX qw(strftime); my $logfile = "/var/log/pveam.log"; +my $aplinfodir = "/var/lib/pve-manager/apl-info"; # Default list of GPG keys allowed to sign aplinfo # #pub 1024D/5CAC72FE 2004-06-24 # Key fingerprint = 9ABD 7E02 AD24 3AD3 C2FB BCCC B0C1 CC22 5CAC 72FE #uid Proxmox Support Team +#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 my $valid_keys = { '9ABD7E02AD243AD3C2FBBCCCB0C1CC225CAC72FE' => 1, # fingerprint 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 { - 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 " . - "--logger-fd=1 --import $keyfile >>$logfile"); + foreach my $key (@keyfiles) { + 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 { @@ -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 { my ($ua, $url, $file, $logfh) = @_; @@ -59,64 +151,43 @@ sub url_get { return 1; } -sub update { - my ($proxy) = @_; +sub download_aplinfo { + my ($ua, $aplurl, $host, $logfd) = @_; - my $aplurl = "http://download.proxmox.com/appliances"; my $aplsrcurl = "$aplurl/aplinfo.dat.gz"; my $aplsigurl = "$aplurl/aplinfo.dat.asc"; - 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(); - - my $tmp = "/tmp/pveam.tmp.$$"; + my $tmp = "$aplinfodir/pveam-${host}.tmp.$$"; my $tmpgz = "$tmp.gz"; 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 { - 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) { - die "update failed - no data\n"; + if (url_get($ua, $aplsrcurl, $tmpgz, $logfd) != 0) { + 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"; } # 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"; - open (CMD, "$cmd|") || + open(CMD, "$cmd|") || die "unable to execute '$cmd': $!\n"; my $line; my $signer = ''; - while (defined ($line = )) { + while (defined($line = )) { chomp $line; - logmsg ($logfd, $line); + logmsg($logfd, $line); # code borrowed from SA 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}; } - close (CMD); + close(CMD); die "unable to verify signature\n" if !$signer; - logmsg ($logfd, "signature valid: $signer"); + logmsg($logfd, "signature valid: $signer"); # test syntax eval { - my $fh = IO::File->new ("<$tmp") || + my $fh = IO::File->new("<$tmp") || die "unable to open file '$tmp' - $!\n"; - PVE::Config::read_aplinfo ($tmp, $fh, 1); - close ($fh); + read_aplinfo($tmp, {}, $aplurl, 1); + close($fh); }; 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"; } - logmsg ($logfd, "update sucessful"); + logmsg($logfd, "update sucessful"); }; my $err = $@; @@ -158,78 +229,90 @@ sub update { unlink $tmpgz; unlink $sigfn; - if ($err) { - logmsg ($logfd, $err); - close ($logfd); - - return 0; - } - - close ($logfd); - - return 1; + die $err if $err; } -sub load_data { - - my $filename = "/var/lib/pve-manager/apl-available"; - - if (! -f $filename) { - system ("cp /usr/share/doc/pve-manager/aplinfo.dat /var/lib/pve-manager/apl-available"); - } +sub get_apl_sources { + + my $urls = []; + push @$urls, "http://download.proxmox.com/appliances"; + push @$urls, "http://releases.turnkeylinux.org/pve"; - return PVE::Config::read_file ('aplinfo'); + return $urls; } -sub display_name { - my ($template) = @_; - - my $templates = load_data (); +sub update { + my ($proxy) = @_; - return $template if !$templates; + my $size; + if (($size = (-s $logfile) || 0) > (1024*50)) { + system ("mv $logfile $logfile.0"); + } + my $logfd = IO::File->new (">>$logfile"); + logmsg($logfd, "starting update"); - my $d = $templates->{'all'}->{$template}; + import_gpg_keys(); - $template =~ s/\.tar\.gz$//; - $template =~ s/_i386$//; + # 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"); - return $template if !$d; + if ($proxy) { + $ua->proxy(['http'], $proxy); + } else { + $ua->env_proxy; + } - return "$d->{package}_$d->{version}"; -} + my $urls = get_apl_sources(); -sub pkginfo { - my ($template) = @_; + mkdir $aplinfodir; - my $templates = load_data (); + 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; + } + } - return undef if !$templates; + close($logfd); - my $d = $templates->{'all'}->{$template}; + return 0 if scalar(@dlerr); - return $d; + return 1; } -sub webnews { - my ($lang) = @_; +sub load_data { - my $templates = load_data (); + my $filename = "$aplinfodir/download.proxmox.com"; + if (! -f $filename) { + mkdir $aplinfodir; + system("cp /usr/share/doc/pve-manager/aplinfo.dat $filename"); + } - my $html = ''; + my $urls = get_apl_sources(); - $html .= __("Welcome to the Proxmox Virtual Environment!"); - $html .= "

"; - $html .= __("For more information please visit our homepage at"); - $html .= " www.proxmox.com."; + my $list = {}; - return $html if !$templates; + foreach my $aplurl (@$urls) { - # my $d = $templates->{'all'}->{"pve-web-news-$lang"} || - my $d = $templates->{all}->{'pve-web-news'}; + eval { - return $html if !$d; + my $uri = URI->new($aplurl); + my $host = $uri->host(); + read_aplinfo("$aplinfodir/$host", $list, $aplurl); + }; + warn $@ if $@; + } - return $d->{description}; + return $list; } 1; diff --git a/PVE/Makefile b/PVE/Makefile index 3a660840..bb3b3c72 100644 --- a/PVE/Makefile +++ b/PVE/Makefile @@ -10,6 +10,7 @@ PERLSOURCE = \ REST.pm \ OpenVZ.pm \ OpenVZMigrate.pm \ + APLInfo.pm \ VZDump.pm all: pvecfg.pm ${SUBDIRS} diff --git a/aplinfo/Makefile b/aplinfo/Makefile index 82049fbb..b416572c 100644 --- a/aplinfo/Makefile +++ b/aplinfo/Makefile @@ -7,6 +7,7 @@ all: install: aplinfo.dat support@proxmox.com.pubkey 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 release@turnkeylinux.com.pubkey ${DESTDIR}${DOCDIR}/release@turnkeylinux.com.pubkey .PHONY: distclean distclean: clean diff --git a/aplinfo/release@turnkeylinux.com.pubkey b/aplinfo/release@turnkeylinux.com.pubkey new file mode 100644 index 00000000..44f9ea3d --- /dev/null +++ b/aplinfo/release@turnkeylinux.com.pubkey @@ -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----- diff --git a/bin/cron/daily/pve b/bin/cron/daily/pve index 69a188e9..d083082a 100644 --- a/bin/cron/daily/pve +++ b/bin/cron/daily/pve @@ -1,7 +1,8 @@ #!/usr/bin/perl -w use strict; -#use PVE::APLInfo; +use PVE::Cluster; +use PVE::APLInfo; use PVE::SafeSyslog; use IO::File; use File::Find; @@ -9,14 +10,11 @@ use File::stat; initlog ('pvedailycron', 'daemon'); -# fixme: update APL info? -#my $pvecfg = PVE::Config::read_file('pvecfg'); -#my $proxy = ($pvecfg && $pvecfg->{http_proxy}) ? $pvecfg->{http_proxy} : undef; - -## update appliance info -#if (!PVE::APLInfo::update()) { -# syslog ('err', "update appliance info failed - see /var/log/pveam.log for details"); -#} +my $dccfg = PVE::Cluster::cfs_read_file('datacenter.cfg'); +eval { PVE::APLInfo::update($dccfg->{http_proxy}); }; +if (my $err = $@) { + syslog ('err', "update appliance info failed - see /var/log/pveam.log for details"); +} sub cleanup_tasks { diff --git a/bin/pveam b/bin/pveam index b85bb3a5..4f1309c3 100755 --- a/bin/pveam +++ b/bin/pveam @@ -2,7 +2,7 @@ use strict; use PVE::Cluster; -#use PVE::APLInfo; +use PVE::APLInfo; if (scalar (@ARGV) != 1) { print STDERR "usage: $0 CMD\n"; @@ -13,9 +13,8 @@ my $cmd = shift; if ($cmd eq 'update') { 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}); - #print STDERR "update failed - see /var/log/pveam.log for details\n"; + exit (0) if PVE::APLInfo::update($dccfg->{http_proxy}); + print STDERR "update failed - see /var/log/pveam.log for details\n"; exit (-1); } else { print STDERR "unknown CMD '$cmd'\n"; diff --git a/debian/changelog.Debian b/debian/changelog.Debian index 45f5f88e..a7dec2da 100644 --- a/debian/changelog.Debian +++ b/debian/changelog.Debian @@ -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 Tue, 21 Feb 2012 11:45:07 +0100 + pve-manager (2.0-30) unstable; urgency=low * add unmount button to openvz GUI diff --git a/debian/postinst b/debian/postinst index d8b76bfe..0074ab76 100755 --- a/debian/postinst +++ b/debian/postinst @@ -37,7 +37,8 @@ case "$1" in 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 ! grep -q '|/usr/bin/pvemailforward' /root/.forward; then diff --git a/defines.mk b/defines.mk index 7036833a..6fbaa955 100644 --- a/defines.mk +++ b/defines.mk @@ -2,7 +2,7 @@ RELEASE=2.0 VERSION=2.0 PACKAGE=pve-manager -PACKAGERELEASE=30 +PACKAGERELEASE=31 BINDIR=${DESTDIR}/usr/bin PERLLIBDIR=${DESTDIR}/usr/share/perl5 diff --git a/www/manager/Utils.js b/www/manager/Utils.js index c3a215dd..c063e9b5 100644 --- a/www/manager/Utils.js +++ b/www/manager/Utils.js @@ -396,6 +396,8 @@ Ext.define('PVE.Utils', { statics: { srvstop: ['SRV', gettext('Stop') ], srvrestart: ['SRV', gettext('Restart') ], srvreload: ['SRV', gettext('Reload') ], + imgcopy: ['', gettext('Copy data') ], + download: ['', gettext('Download') ], vzdump: ['', gettext('Backup') ] }, diff --git a/www/manager/storage/ContentView.js b/www/manager/storage/ContentView.js index 6e0ac65f..515c2db1 100644 --- a/www/manager/storage/ContentView.js +++ b/www/manager/storage/ContentView.js @@ -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', { extend: 'Ext.window.Window', 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'), handler: function() { -- 2.39.5