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