]> git.proxmox.com Git - pve-manager.git/blame - PVE/APLInfo.pm
followup: refactor & code cleanup
[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 9use POSIX qw(strftime);
07e5f4f7 10use PVE::pvecfg;
aff192e6
DM
11
12my $logfile = "/var/log/pveam.log";
c9164975 13my $aplinfodir = "/var/lib/pve-manager/apl-info";
aff192e6 14
aff192e6
DM
15sub 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
27sub 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
106sub 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
122sub 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
140sub 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
205sub 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
214sub 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 258sub 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
2781;
279