]> git.proxmox.com Git - pve-manager.git/blame - PVE/API2/APT.pm
use shorter login message
[pve-manager.git] / PVE / API2 / APT.pm
CommitLineData
21299915
DM
1package PVE::API2::APT;
2
3use strict;
4use warnings;
cd0bc36b 5use File::stat ();
21299915
DM
6
7use PVE::Tools qw(extract_param);
8use PVE::SafeSyslog;
9use PVE::INotify;
10use PVE::Exception qw(raise_param_exc);
11use PVE::RESTHandler;
12use PVE::RPCEnvironment;
13
cd0bc36b 14use JSON;
21299915
DM
15use PVE::JSONSchema qw(get_standard_option);
16
17use AptPkg::Cache;
18use AptPkg::Version;
19use AptPkg::PkgRecords;
20
21my $apt_cache;
22
23my $get_apt_cache = sub {
24
25 return $apt_cache if $apt_cache;
26
27 $apt_cache = AptPkg::Cache->new() || die "unable to initialize AptPkg::Cache\n";
28
29 return $apt_cache;
30};
31
32use base qw(PVE::RESTHandler);
33
34__PACKAGE__->register_method({
35 name => 'index',
36 path => '',
37 method => 'GET',
38 description => "Directory index for apt (Advanced Package Tool).",
39 permissions => {
40 user => 'all',
41 },
42 parameters => {
43 additionalProperties => 0,
44 properties => {
45 node => get_standard_option('pve-node'),
46 },
47 },
48 returns => {
49 type => "array",
50 items => {
51 type => "object",
52 properties => {
53 id => { type => 'string' },
54 },
55 },
56 links => [ { rel => 'child', href => "{id}" } ],
57 },
58 code => sub {
59 my ($param) = @_;
60
61 my $res = [
62 { id => 'update' },
63 { id => 'upgrade' },
64 { id => 'changelog' },
65 ];
66
67 return $res;
68 }});
69
70my $assemble_pkginfo = sub {
71 my ($pkgname, $info, $current_ver, $candidate_ver) = @_;
72
00d48356
DM
73 my $changelog_url;
74 foreach my $verfile (@{$candidate_ver->{FileList}}) {
75 my $pkgfile = $verfile->{File};
76 my $origin = $pkgfile->{Origin};
77 my $comp = $pkgfile->{Component};
78 if ($origin && $comp) {
79 my $pkgver = $candidate_ver->{VerStr};
371dcc92
DM
80 $pkgver =~ s/^\d+://; # strip epoch
81 my $srcpkg = $info->{SourcePkg} || $pkgname;
82 my $firstLetter = substr($srcpkg, 0, 1);
00d48356
DM
83 if ($origin eq 'Debian') {
84 $changelog_url = "http://packages.debian.org/changelogs/pool/main/" .
371dcc92 85 "$firstLetter/$srcpkg/${srcpkg}_$pkgver/changelog";
00d48356
DM
86 }
87 last;
88 }
89 }
90
21299915
DM
91 my $data = {
92 Package => $info->{Name},
93 Title => $info->{ShortDesc},
94 };
95
00d48356
DM
96 $data->{ChangeLogUrl} = $changelog_url if $changelog_url;
97
21299915
DM
98 if (my $desc = $info->{LongDesc}) {
99 $desc =~ s/^.*\n\s?//; # remove first line
100 $desc =~ s/\n / /g;
101 $data->{Description} = $desc;
102 }
103
104 foreach my $k (qw(Section Arch Priority)) {
105 $data->{$k} = $candidate_ver->{$k};
106 }
107
108 $data->{Version} = $candidate_ver->{VerStr};
109 $data->{OldVersion} = $current_ver->{VerStr};
110
111 return $data;
112};
113
4806bc69
DM
114# we try to cache results
115my $pve_pkgstatus_fn = "/var/lib/pve-manager/pkgupdates";
116
117my $update_pve_pkgstatus = sub {
118
119 my $pkglist = [];
120
121 my $cache = &$get_apt_cache();
122 my $policy = $cache->policy;
123 my $pkgrecords = $cache->packages();
124
125 foreach my $pkgname (keys %$cache) {
126 my $p = $cache->{$pkgname};
127 next if $p->{SelectedState} ne 'Install';
128 my $current_ver = $p->{CurrentVer};
129 my $candidate_ver = $policy->candidate($p);
130
131 if ($current_ver->{VerStr} ne $candidate_ver->{VerStr}) {
132 my $info = $pkgrecords->lookup($pkgname);
133 my $res = &$assemble_pkginfo($pkgname, $info, $current_ver, $candidate_ver);
134 push @$pkglist, $res;
135 }
136 }
137
138 PVE::Tools::file_set_contents($pve_pkgstatus_fn, encode_json($pkglist));
139
140 return $pkglist;
141};
142
21299915
DM
143__PACKAGE__->register_method({
144 name => 'list_updates',
145 path => 'update',
146 method => 'GET',
147 description => "List available updates.",
148 permissions => {
149 check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
150 },
151 protected => 1,
152 proxyto => 'node',
153 parameters => {
154 additionalProperties => 0,
155 properties => {
156 node => get_standard_option('pve-node'),
157 },
158 },
159 returns => {
160 type => "array",
161 items => {
162 type => "object",
163 properties => {},
164 },
165 },
166 code => sub {
167 my ($param) = @_;
168
cd0bc36b
DM
169 if (my $st1 = File::stat::stat($pve_pkgstatus_fn)) {
170 my $st2 = File::stat::stat("/var/cache/apt/pkgcache.bin");
171 my $st3 = File::stat::stat("/var/lib/dpkg/status");
172
c2d3fbe0 173 if ($st2->mtime <= $st1->mtime && $st3->mtime <= $st1->mtime) {
cd0bc36b
DM
174 my $data;
175 eval {
176 my $jsonstr = PVE::Tools::file_get_contents($pve_pkgstatus_fn, 5*1024*1024);
177 $data = decode_json($jsonstr);
178 };
179 if (my $err = $@) {
180 warn "error readin cached package status in $pve_pkgstatus_fn\n";
181 # continue and overwrite cache with new content
182 } else {
183 return $data;
184 }
185 }
186 }
187
4806bc69
DM
188 my $pkglist = &$update_pve_pkgstatus();
189
190 return $pkglist;
191 }});
192
193__PACKAGE__->register_method({
194 name => 'update_database',
195 path => 'update',
196 method => 'POST',
197 description => "This is used to resynchronize the package index files from their sources (apt-get update).",
198 permissions => {
199 check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
200 },
201 protected => 1,
202 proxyto => 'node',
203 parameters => {
204 additionalProperties => 0,
205 properties => {
206 node => get_standard_option('pve-node'),
207 },
208 },
209 returns => {
210 type => 'string',
211 },
212 code => sub {
213 my ($param) = @_;
214
215 my $rpcenv = PVE::RPCEnvironment::get();
21299915 216
4806bc69 217 my $authuser = $rpcenv->get_user();
21299915 218
4806bc69
DM
219 my $realcmd = sub {
220 my $upid = shift;
21299915 221
4806bc69 222 my $cmd = ['apt-get', 'update'];
21299915 223
4806bc69
DM
224 print "starting apt-get update\n";
225
226 PVE::Tools::run_command($cmd);
227
228 &$update_pve_pkgstatus();
229
230 return;
231 };
232
c2d3fbe0
DM
233 return $rpcenv->fork_worker('aptupdate', undef, $authuser, $realcmd);
234
235 }});
236
237__PACKAGE__->register_method({
238 name => 'upgrade',
239 path => 'upgrade',
240 method => 'POST',
241 description => "Install the newest versions of all packages (apt-get dist-upgrade).",
242 permissions => {
243 check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
244 },
245 protected => 1,
246 proxyto => 'node',
247 parameters => {
248 additionalProperties => 0,
249 properties => {
250 node => get_standard_option('pve-node'),
251 },
252 },
253 returns => {
254 type => 'string',
255 },
256 code => sub {
257 my ($param) = @_;
258
259 my $rpcenv = PVE::RPCEnvironment::get();
260
261 my $authuser = $rpcenv->get_user();
262
263 my $realcmd = sub {
264 my $upid = shift;
265
266 my $cmd = ['apt-get', 'dist-upgrade', '--assume-yes'];
267
268 print "starting apt-get dist-upgrade\n";
269
270 $ENV{DEBIAN_FRONTEND} = 'noninteractive';
271
272 PVE::Tools::run_command($cmd);
273
274 &$update_pve_pkgstatus();
275
276 return;
277 };
278
279 return $rpcenv->fork_worker('aptupgrade', undef, $authuser, $realcmd);
cd0bc36b 280
21299915
DM
281 }});
282
2831;