]> git.proxmox.com Git - pve-manager.git/blame - PVE/API2/Services.pm
api2: network: improve code readability
[pve-manager.git] / PVE / API2 / Services.pm
CommitLineData
aff192e6
DM
1package PVE::API2::Services;
2
3use strict;
4use warnings;
5
6use PVE::Tools;
7use PVE::SafeSyslog;
8use PVE::Cluster;
9use PVE::INotify;
10use PVE::Exception qw(raise_param_exc);
11use PVE::RESTHandler;
12use PVE::RPCEnvironment;
13use PVE::JSONSchema qw(get_standard_option);
14use PVE::AccessControl;
15use IO::File;
16
17use base qw(PVE::RESTHandler);
18
50d4dc17 19my $service_name_list = [
b188fcd8 20 'chrony',
50d4dc17 21 'corosync',
b188fcd8
DC
22 'cron',
23 'ksmtuned',
24 'postfix',
25 'pve-cluster',
50d4dc17 26 'pve-firewall',
50d4dc17
DM
27 'pve-ha-crm',
28 'pve-ha-lrm',
b188fcd8
DC
29 'pvedaemon',
30 'pvefw-logger',
31 'pveproxy',
7aa5b131 32 'pvescheduler',
b188fcd8
DC
33 'pvestatd',
34 'spiceproxy',
50d4dc17
DM
35 'sshd',
36 'syslog',
48197df2 37 'systemd-journald',
28b699bc 38 'systemd-timesyncd',
05d5632d 39];
d438bb3e
TL
40my $essential_services = {
41 pveproxy => 1,
42 pvedaemon => 1,
43 'pve-cluster' => 1,
44};
50d4dc17 45
7a581660
EK
46# since postfix package 3.1.0-3.1 the postfix unit is only here to
47# manage subinstances, of which the default is called "-".
48# This is where we look for the daemon status
49my $unit_extra_names = {
50 postfix => 'postfix@-'
51};
52
50d4dc17
DM
53my $get_full_service_state = sub {
54 my ($service) = @_;
7a581660 55 $service = $unit_extra_names->{$service} if $unit_extra_names->{$service};
50d4dc17 56 my $res;
05d5632d 57
50d4dc17
DM
58 my $parser = sub {
59 my $line = shift;
60 if ($line =~ m/^([^=\s]+)=(.*)$/) {
61 $res->{$1} = $2;
62 }
63 };
64
05d5632d
TL
65 PVE::Tools::run_command(['systemctl', 'show', $service], outfunc => $parser);
66
50d4dc17 67 return $res;
aff192e6
DM
68};
69
50d4dc17
DM
70my $static_service_list;
71
72sub get_service_list {
73
74 return $static_service_list if $static_service_list;
05d5632d 75
50d4dc17
DM
76 my $list = {};
77 foreach my $name (@$service_name_list) {
5fa0c204 78 my $ss = eval { $get_full_service_state->($name) };
50d4dc17
DM
79 warn $@ if $@;
80 next if !$ss;
81 next if !defined($ss->{Description});
82 $list->{$name} = { name => $name, desc => $ss->{Description} };
83 }
84
85 $static_service_list = $list;
05d5632d 86
50d4dc17
DM
87 return $static_service_list;
88}
89
90
c661ad50
DM
91my $service_prop_desc = {
92 description => "Service ID",
93 type => 'string',
50d4dc17 94 enum => $service_name_list,
c661ad50
DM
95};
96
aff192e6
DM
97my $service_cmd = sub {
98 my ($service, $cmd) = @_;
99
100 my $initd_cmd;
101
d438bb3e 102 die "unknown service command '$cmd'\n" if $cmd !~ m/^(start|stop|restart|reload|try-reload-or-restart)$/;
aff192e6 103
d438bb3e
TL
104 if ($essential_services->{$service} && $cmd eq 'stop') {
105 die "invalid service cmd '$service $cmd': refusing to stop essential service!\n";
50d4dc17 106 }
d438bb3e 107
50d4dc17 108 PVE::Tools::run_command(['systemctl', $cmd, $service]);
aff192e6
DM
109};
110
111my $service_state = sub {
112 my ($service) = @_;
113
3546270c
TL
114 my $res = { state => 'unknown' };
115
116 my $ss = eval { $get_full_service_state->($service) };
50d4dc17 117 if (my $err = $@) {
3546270c 118 return $res;
aff192e6 119 }
4ec19e84
TL
120 my $state = $ss->{SubState} || 'unknown';
121 if ($state eq 'dead' && $ss->{Type} && $ss->{Type} eq 'oneshot' && $ss->{Result}) {
122 $res->{state} = $ss->{Result};
123 } else {
124 $res->{state} = $ss->{SubState} || 'unknown';
125 }
ad7dd5a9
TL
126
127 if ($ss->{LoadState} eq 'not-found') {
128 $res->{'unit-state'} = 'not-found'; # not installed
129 } else {
130 $res->{'unit-state'} = $ss->{UnitFileState} || 'unknown';
131 }
3546270c 132 $res->{'active-state'} = $ss->{ActiveState} || 'unknown';
aff192e6 133
3546270c 134 return $res;
aff192e6
DM
135};
136
137__PACKAGE__->register_method ({
6d9807b6
TL
138 name => 'index',
139 path => '',
aff192e6
DM
140 method => 'GET',
141 permissions => {
7d020b42 142 check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
aff192e6
DM
143 },
144 description => "Service list.",
145 proxyto => 'node',
146 protected => 1,
147 parameters => {
6d9807b6 148 additionalProperties => 0,
aff192e6
DM
149 properties => {
150 node => get_standard_option('pve-node'),
151 },
152 },
153 returns => {
154 type => 'array',
155 items => {
156 type => "object",
157 properties => {},
158 },
159 links => [ { rel => 'child', href => "{service}" } ],
160 },
161 code => sub {
162 my ($param) = @_;
6d9807b6 163
50d4dc17 164 my $service_list = get_service_list();
6d9807b6 165
3546270c
TL
166 my $res = [];
167 for my $id (sort keys %{$service_list}) {
168 my $state = $service_state->($id);
6d9807b6 169 push @$res, {
aff192e6
DM
170 service => $id,
171 name => $service_list->{$id}->{name},
172 desc => $service_list->{$id}->{desc},
3546270c 173 %$state,
aff192e6
DM
174 };
175 }
176
177 return $res;
178 }});
179
c661ad50
DM
180__PACKAGE__->register_method({
181 name => 'srvcmdidx',
6d9807b6 182 path => '{service}',
aff192e6 183 method => 'GET',
c661ad50 184 description => "Directory index",
461e4a46
DM
185 permissions => {
186 check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
187 },
c661ad50 188 parameters => {
6d9807b6 189 additionalProperties => 0,
c661ad50
DM
190 properties => {
191 node => get_standard_option('pve-node'),
192 service => $service_prop_desc,
193 },
194 },
195 returns => {
196 type => 'array',
197 items => {
198 type => "object",
199 properties => {
200 subdir => { type => 'string' },
201 },
202 },
203 links => [ { rel => 'child', href => "{subdir}" } ],
204 },
205 code => sub {
206 my ($param) = @_;
207
208 my $res = [
209 { subdir => 'state' },
210 { subdir => 'start' },
211 { subdir => 'stop' },
212 { subdir => 'restart' },
213 { subdir => 'reload' },
214 ];
6d9807b6 215
c661ad50
DM
216 return $res;
217 }});
218
219__PACKAGE__->register_method ({
6d9807b6
TL
220 name => 'service_state',
221 path => '{service}/state',
c661ad50 222 method => 'GET',
aff192e6 223 permissions => {
7d020b42 224 check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
aff192e6
DM
225 },
226 description => "Read service properties",
227 proxyto => 'node',
228 protected => 1,
229 parameters => {
6d9807b6 230 additionalProperties => 0,
aff192e6
DM
231 properties => {
232 node => get_standard_option('pve-node'),
c661ad50 233 service => $service_prop_desc,
aff192e6
DM
234 },
235 },
236 returns => {
237 type => "object",
238 properties => {},
239 },
240 code => sub {
241 my ($param) = @_;
6d9807b6 242
3546270c
TL
243 my $id = $param->{service};
244
50d4dc17 245 my $service_list = get_service_list();
6d9807b6 246
3546270c
TL
247 my $si = $service_list->{$id};
248
249 my $state = $service_state->($id);
250
aff192e6
DM
251 return {
252 service => $param->{service},
253 name => $si->{name},
254 desc => $si->{desc},
3546270c 255 %$state,
aff192e6
DM
256 };
257 }});
258
259__PACKAGE__->register_method ({
6d9807b6
TL
260 name => 'service_start',
261 path => '{service}/start',
c661ad50
DM
262 method => 'POST',
263 description => "Start service.",
461e4a46
DM
264 permissions => {
265 check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
266 },
aff192e6
DM
267 proxyto => 'node',
268 protected => 1,
269 parameters => {
6d9807b6 270 additionalProperties => 0,
aff192e6
DM
271 properties => {
272 node => get_standard_option('pve-node'),
c661ad50
DM
273 service => $service_prop_desc,
274 },
275 },
6d9807b6 276 returns => {
c661ad50
DM
277 type => 'string',
278 },
279 code => sub {
280 my ($param) = @_;
6d9807b6 281
c661ad50
DM
282 my $rpcenv = PVE::RPCEnvironment::get();
283
284 my $user = $rpcenv->get_user();
285
c661ad50
DM
286 my $realcmd = sub {
287 my $upid = shift;
288
289 syslog('info', "starting service $param->{service}: $upid\n");
290
05d5632d 291 $service_cmd->($param->{service}, 'start');
c661ad50
DM
292
293 };
294
295 return $rpcenv->fork_worker('srvstart', $param->{service}, $user, $realcmd);
296 }});
297
298__PACKAGE__->register_method ({
6d9807b6
TL
299 name => 'service_stop',
300 path => '{service}/stop',
c661ad50
DM
301 method => 'POST',
302 description => "Stop service.",
461e4a46
DM
303 permissions => {
304 check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
305 },
c661ad50
DM
306 proxyto => 'node',
307 protected => 1,
308 parameters => {
6d9807b6 309 additionalProperties => 0,
c661ad50
DM
310 properties => {
311 node => get_standard_option('pve-node'),
312 service => $service_prop_desc,
313 },
314 },
6d9807b6 315 returns => {
c661ad50
DM
316 type => 'string',
317 },
318 code => sub {
319 my ($param) = @_;
6d9807b6 320
c661ad50
DM
321 my $rpcenv = PVE::RPCEnvironment::get();
322
323 my $user = $rpcenv->get_user();
324
c661ad50
DM
325 my $realcmd = sub {
326 my $upid = shift;
327
76189130 328 syslog('info', "stopping service $param->{service}: $upid\n");
c661ad50 329
05d5632d 330 $service_cmd->($param->{service}, 'stop');
c661ad50
DM
331
332 };
333
334 return $rpcenv->fork_worker('srvstop', $param->{service}, $user, $realcmd);
335 }});
336
337__PACKAGE__->register_method ({
05d5632d
TL
338 name => 'service_restart',
339 path => '{service}/restart',
c661ad50 340 method => 'POST',
3cd0759a 341 description => "Hard restart service. Use reload if you want to reduce interruptions.",
461e4a46
DM
342 permissions => {
343 check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
344 },
c661ad50
DM
345 proxyto => 'node',
346 protected => 1,
347 parameters => {
05d5632d 348 additionalProperties => 0,
c661ad50
DM
349 properties => {
350 node => get_standard_option('pve-node'),
351 service => $service_prop_desc,
aff192e6
DM
352 },
353 },
6d9807b6 354 returns => {
c661ad50
DM
355 type => 'string',
356 },
aff192e6
DM
357 code => sub {
358 my ($param) = @_;
c661ad50 359
05d5632d 360 my $rpcenv = PVE::RPCEnvironment::get();
c661ad50
DM
361 my $user = $rpcenv->get_user();
362
c661ad50
DM
363 my $realcmd = sub {
364 my $upid = shift;
c661ad50
DM
365 syslog('info', "re-starting service $param->{service}: $upid\n");
366
05d5632d 367 $service_cmd->($param->{service}, 'restart');
c661ad50
DM
368 };
369
370 return $rpcenv->fork_worker('srvrestart', $param->{service}, $user, $realcmd);
371 }});
372
373__PACKAGE__->register_method ({
05d5632d
TL
374 name => 'service_reload',
375 path => '{service}/reload',
c661ad50 376 method => 'POST',
3cd0759a 377 description => "Reload service. Falls back to restart if service cannot be reloaded.",
461e4a46
DM
378 permissions => {
379 check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
380 },
c661ad50
DM
381 proxyto => 'node',
382 protected => 1,
383 parameters => {
05d5632d 384 additionalProperties => 0,
c661ad50
DM
385 properties => {
386 node => get_standard_option('pve-node'),
387 service => $service_prop_desc,
388 },
389 },
6d9807b6 390 returns => {
c661ad50
DM
391 type => 'string',
392 },
393 code => sub {
394 my ($param) = @_;
c661ad50 395
05d5632d 396 my $rpcenv = PVE::RPCEnvironment::get();
c661ad50
DM
397 my $user = $rpcenv->get_user();
398
c661ad50
DM
399 my $realcmd = sub {
400 my $upid = shift;
c661ad50
DM
401 syslog('info', "reloading service $param->{service}: $upid\n");
402
3cd0759a 403 $service_cmd->($param->{service}, 'try-reload-or-restart');
c661ad50
DM
404
405 };
406
407 return $rpcenv->fork_worker('srvreload', $param->{service}, $user, $realcmd);
aff192e6 408 }});