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