]> git.proxmox.com Git - pve-manager.git/blame - PVE/APLInfo.pm
REST/RPCEnvironment's check_worker is a method now
[pve-manager.git] / PVE / APLInfo.pm
CommitLineData
aff192e6
DM
1package PVE::APLInfo;
2
3use strict;
609801c5 4use warnings;
aff192e6
DM
5use IO::File;
6use PVE::SafeSyslog;
c351eda9 7use PVE::Tools;
aff192e6 8use LWP::UserAgent;
aff192e6
DM
9use POSIX qw(strftime);
10
11my $logfile = "/var/log/pveam.log";
c9164975 12my $aplinfodir = "/var/lib/pve-manager/apl-info";
aff192e6 13
aff192e6
DM
14sub logmsg {
15 my ($logfd, $msg) = @_;
16
17 chomp $msg;
18
19 my $tstr = strftime ("%b %d %H:%M:%S", localtime);
20
21 foreach my $line (split (/\n/, $msg)) {
22 print $logfd "$tstr $line\n";
23 }
24}
25
6de794eb
DM
26sub read_aplinfo_from_fh {
27 my ($fh, $list, $source, $update) = @_;
c9164975
DM
28
29 local $/ = "";
30
6de794eb
DM
31 while (my $rec = <$fh>) {
32 chomp $rec;
c9164975 33
6de794eb
DM
34 my $res = {};
35
36 while ($rec) {
37
38 if ($rec =~ s/^Description:\s*([^\n]*)(\n\s+.*)*$//si) {
39 $res->{headline} = $1;
648af5ab 40 my $long = $2 || '';
6de794eb
DM
41 $long =~ s/\n\s+/ /g;
42 $long =~ s/^\s+//g;
43 $long =~ s/\s+$//g;
44 $res->{description} = $long;
45 } elsif ($rec =~ s/^Version:\s*(.*\S)\s*\n//i) {
46 my $version = $1;
f6b20cf9 47 if ($version =~ m/^(\d[a-zA-Z0-9\.\+\-\:\~]*)(-(\d+))?$/) {
6de794eb 48 $res->{version} = $version;
c9164975 49 } else {
6de794eb
DM
50 my $msg = "unable to parse appliance record: version = '$version'\n";
51 $update ? die $msg : warn $msg;
c9164975 52 }
6de794eb
DM
53 } elsif ($rec =~ s/^Type:\s*(.*\S)\s*\n//i) {
54 my $type = $1;
55 if ($type =~ m/^(openvz|lxc)$/) {
56 $res->{type} = $type;
c9164975 57 } else {
6de794eb
DM
58 my $msg = "unable to parse appliance record: unknown type '$type'\n";
59 $update ? die $msg : warn $msg;
c9164975 60 }
6de794eb
DM
61 } elsif ($rec =~ s/^([^:]+):\s*(.*\S)\s*\n//) {
62 $res->{lc $1} = $2;
c9164975 63 } else {
6de794eb 64 my $msg = "unable to parse appliance record: $rec\n";
c9164975 65 $update ? die $msg : warn $msg;
6de794eb
DM
66 $res = {};
67 last;
68 }
69 }
70
71 if ($res->{'package'} eq 'pve-web-news' && $res->{description}) {
72 $list->{'all'}->{$res->{'package'}} = $res;
73 next;
74 }
75
76 $res->{section} = 'unknown' if !$res->{section};
77
78 if ($res->{'package'} && $res->{type} && $res->{os} && $res->{version} &&
79 $res->{infopage}) {
80 my $template;
81 if ($res->{location}) {
82 $template = $res->{location};
7a07d675
DM
83 $template =~ s|.*/([^/]+.tar.[gx]z)$|$1|;
84 if ($res->{location} !~ m|^([a-zA-Z]+)\://|) {
85 # relative localtion (no http:// prefix)
86 $res->{location} = "$source/$res->{location}";
87 }
6de794eb 88 } else {
07c1e6b0
DM
89 my $arch = $res->{architecture} || 'i386';
90 $template = "$res->{os}-$res->{package}_$res->{version}_$arch.tar.gz";
6de794eb 91 $template =~ s/$res->{os}-$res->{os}-/$res->{os}-/;
4886fe07 92 $res->{location} = "$source/$res->{section}/$template";
c9164975 93 }
6de794eb
DM
94 $res->{source} = $source;
95 $res->{template} = $template;
96 $list->{$res->{section}}->{$template} = $res;
97 $list->{'all'}->{$template} = $res;
98 } else {
99 my $msg = "found incomplete appliance records\n";
100 $update ? die $msg : warn $msg;
c9164975 101 }
6de794eb
DM
102 }
103}
104
105sub read_aplinfo {
106 my ($filename, $list, $source, $update) = @_;
107
108 my $fh = IO::File->new("<$filename") ||
109 die "unable to open file '$filename' - $!\n";
110
111 eval { read_aplinfo_from_fh($fh, $list, $source, $update); };
c9164975
DM
112 my $err = $@;
113
114 close($fh);
115
116 die $err if $err;
117
118 return $list;
119}
120
aff192e6
DM
121sub url_get {
122 my ($ua, $url, $file, $logfh) = @_;
123
124 my $req = HTTP::Request->new(GET => $url);
125
126 logmsg ($logfh, "start download $url");
127 my $res = $ua->request($req, $file);
128
129 if ($res->is_success) {
130 logmsg ($logfh, "download finished: " . $res->status_line);
131 return 0;
132 }
133
134 logmsg ($logfh, "download failed: " . $res->status_line);
135
136 return 1;
137}
138
c9164975
DM
139sub download_aplinfo {
140 my ($ua, $aplurl, $host, $logfd) = @_;
aff192e6 141
aff192e6
DM
142 my $aplsrcurl = "$aplurl/aplinfo.dat.gz";
143 my $aplsigurl = "$aplurl/aplinfo.dat.asc";
144
c9164975 145 my $tmp = "$aplinfodir/pveam-${host}.tmp.$$";
aff192e6
DM
146 my $tmpgz = "$tmp.gz";
147 my $sigfn = "$tmp.asc";
148
aff192e6 149 eval {
c9164975
DM
150
151 if (url_get($ua, $aplsigurl, $sigfn, $logfd) != 0) {
152 die "update failed - no signature file '$sigfn'\n";
aff192e6
DM
153 }
154
c9164975
DM
155 if (url_get($ua, $aplsrcurl, $tmpgz, $logfd) != 0) {
156 die "update failed - no data file '$aplsrcurl'\n";
aff192e6
DM
157 }
158
c351eda9
FG
159 eval {
160 PVE::Tools::run_command(["gunzip", "-f", $tmpgz]);
161 };
162 die "update failed: unable to unpack '$tmpgz'\n" if $@;
aff192e6 163
aff192e6 164
aff192e6 165
868801cb
FG
166 # verify signature
167 my $trustedkeyring = "/usr/share/doc/pve-manager/trustedkeys.gpg";
168 my $cmd = "/usr/bin/gpgv -q --keyring $trustedkeyring $sigfn $tmp";
169
170 eval {
171 my $logfunc = sub {
172 my $line = shift;
173 logmsg($logfd, "signature verification: $line");
174 };
175
176 PVE::Tools::run_command($cmd,
177 outfunc => $logfunc,
178 errfunc => $logfunc);
179 };
180 die "unable to verify signature - $@\n" if $@;
aff192e6
DM
181
182 # test syntax
183 eval {
c9164975 184 read_aplinfo($tmp, {}, $aplurl, 1);
aff192e6
DM
185 };
186 die "update failed: $@" if $@;
187
c351eda9 188 if (!rename($tmp, "$aplinfodir/$host")) {
aff192e6
DM
189 die "update failed: unable to store data\n";
190 }
191
c9164975 192 logmsg($logfd, "update sucessful");
aff192e6
DM
193 };
194
195 my $err = $@;
196
197 unlink $tmp;
198 unlink $tmpgz;
199 unlink $sigfn;
200
c9164975 201 die $err if $err;
aff192e6
DM
202}
203
c9164975
DM
204sub get_apl_sources {
205
206 my $urls = [];
648af5ab 207 push @$urls, "http://download.proxmox.com/images";
06399fd7 208 push @$urls, "https://releases.turnkeylinux.org/pve";
aff192e6 209
c9164975 210 return $urls;
aff192e6
DM
211}
212
c9164975
DM
213sub update {
214 my ($proxy) = @_;
aff192e6 215
c9164975
DM
216 my $size;
217 if (($size = (-s $logfile) || 0) > (1024*50)) {
c351eda9 218 rename($logfile, "$logfile.0");
c9164975
DM
219 }
220 my $logfd = IO::File->new (">>$logfile");
221 logmsg($logfd, "starting update");
aff192e6 222
c9164975
DM
223 my $ua = LWP::UserAgent->new;
224 $ua->agent("PVE/1.0");
aff192e6 225
c9164975 226 if ($proxy) {
49ee2d1a 227 $ua->proxy(['http', 'https'], $proxy);
c9164975
DM
228 } else {
229 $ua->env_proxy;
230 }
aff192e6 231
c9164975 232 my $urls = get_apl_sources();
aff192e6 233
c9164975 234 mkdir $aplinfodir;
aff192e6 235
c9164975
DM
236 my @dlerr = ();
237 foreach my $aplurl (@$urls) {
238 eval {
239 my $uri = URI->new($aplurl);
240 my $host = $uri->host();
241 download_aplinfo($ua, $aplurl, $host, $logfd);
242 };
243 if (my $err = $@) {
244 logmsg ($logfd, $err);
245 push @dlerr, $aplurl;
246 }
247 }
aff192e6 248
c9164975 249 close($logfd);
aff192e6 250
c9164975 251 return 0 if scalar(@dlerr);
aff192e6 252
c9164975 253 return 1;
aff192e6
DM
254}
255
c9164975 256sub load_data {
aff192e6 257
75a6a7f5 258 my $urls = get_apl_sources();
aff192e6 259
c9164975 260 my $list = {};
aff192e6 261
c9164975 262 foreach my $aplurl (@$urls) {
aff192e6 263
c9164975 264 eval {
aff192e6 265
c9164975
DM
266 my $uri = URI->new($aplurl);
267 my $host = $uri->host();
268 read_aplinfo("$aplinfodir/$host", $list, $aplurl);
269 };
270 warn $@ if $@;
271 }
aff192e6 272
c9164975 273 return $list;
aff192e6
DM
274}
275
2761;
277