]>
Commit | Line | Data |
---|---|---|
aff192e6 DM |
1 | package PVE::APLInfo; |
2 | ||
3 | use strict; | |
609801c5 | 4 | use warnings; |
aff192e6 DM |
5 | use IO::File; |
6 | use PVE::SafeSyslog; | |
c351eda9 | 7 | use PVE::Tools; |
aff192e6 | 8 | use LWP::UserAgent; |
aff192e6 DM |
9 | use POSIX qw(strftime); |
10 | ||
11 | my $logfile = "/var/log/pveam.log"; | |
c9164975 | 12 | my $aplinfodir = "/var/lib/pve-manager/apl-info"; |
aff192e6 | 13 | |
aff192e6 DM |
14 | sub 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 |
26 | sub 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 | ||
105 | sub 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 |
121 | sub 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 |
139 | sub 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 |
204 | sub 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 |
213 | sub 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 | 256 | sub 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 | ||
276 | 1; | |
277 |