1 use std
::process
::{Command, Stdio}
;
4 use serde_json
::{json, Value}
;
6 use proxmox
::{sortable, identity}
;
7 use proxmox
::api
::list_subdirs_api_method
;
8 use proxmox
::api
::{ApiHandler, ApiMethod, Router, RpcEnvironment}
;
9 use proxmox
::api
::router
::SubdirMap
;
10 use proxmox
::api
::schema
::*;
12 use crate::api2
::types
::*;
15 static SERVICE_NAME_LIST
: [&str; 7] = [
17 "proxmox-backup-proxy",
25 fn real_service_name(service
: &str) -> &str {
27 // since postfix package 3.1.0-3.1 the postfix unit is only here
28 // to manage subinstances, of which the default is called "-".
29 // This is where we look for the daemon status
31 if service
== "postfix" {
38 fn get_full_service_state(service
: &str) -> Result
<Value
, Error
> {
40 let real_service_name
= real_service_name(service
);
42 let mut child
= Command
::new("/bin/systemctl")
43 .args(&["show", real_service_name
])
44 .stdout(Stdio
::piped())
47 use std
::io
::{BufRead,BufReader}
;
49 let mut result
= json
!({}
);
51 if let Some(ref mut stdout
) = child
.stdout
{
52 for line
in BufReader
::new(stdout
).lines() {
55 let mut iter
= line
.splitn(2, '
='
);
56 let key
= iter
.next();
57 let value
= iter
.next();
58 if let (Some(key
), Some(value
)) = (key
, value
) {
59 result
[key
] = Value
::from(value
);
63 log
::error
!("reading service config failed: {}", err
);
71 let status
= child
.wait().unwrap();
72 if !status
.success() {
73 bail
!("systemctl show failed with {}", status
);
79 fn json_service_state(service
: &str, status
: Value
) -> Value
{
81 if let Some(desc
) = status
["Description"].as_str() {
82 let name
= status
["Name"].as_str().unwrap_or(service
);
83 let state
= status
["SubState"].as_str().unwrap_or("unknown");
99 _rpcenv
: &mut dyn RpcEnvironment
,
100 ) -> Result
<Value
, Error
> {
102 let mut list
= vec
![];
104 for service
in &SERVICE_NAME_LIST
{
105 match get_full_service_state(service
) {
107 let state
= json_service_state(service
, status
);
108 if state
!= Value
::Null
{
112 Err(err
) => log
::error
!("{}", err
),
116 Ok(Value
::from(list
))
119 fn get_service_state(
122 _rpcenv
: &mut dyn RpcEnvironment
,
123 ) -> Result
<Value
, Error
> {
125 let service
= tools
::required_string_param(¶m
, "service")?
;
127 if !SERVICE_NAME_LIST
.contains(&service
) {
128 bail
!("unknown service name '{}'", service
);
131 let status
= get_full_service_state(service
)?
;
133 Ok(json_service_state(service
, status
))
136 fn run_service_command(service
: &str, cmd
: &str) -> Result
<Value
, Error
> {
138 // fixme: run background worker (fork_worker) ???
141 "start"|"stop"|"restart"|"reload" => {}
,
142 _
=> bail
!("unknown service command '{}'", cmd
),
145 if service
== "proxmox-backup" && cmd
!= "restart" {
146 bail
!("invalid service cmd '{} {}'", service
, cmd
);
149 let real_service_name
= real_service_name(service
);
151 let status
= Command
::new("/bin/systemctl")
152 .args(&[cmd
, real_service_name
])
155 if !status
.success() {
156 bail
!("systemctl {} failed with {}", cmd
, status
);
165 _rpcenv
: &mut dyn RpcEnvironment
,
166 ) -> Result
<Value
, Error
> {
168 let service
= tools
::required_string_param(¶m
, "service")?
;
170 log
::info
!("starting service {}", service
);
172 run_service_command(service
, "start")
178 _rpcenv
: &mut dyn RpcEnvironment
,
179 ) -> Result
<Value
, Error
> {
181 let service
= tools
::required_string_param(¶m
, "service")?
;
183 log
::info
!("stoping service {}", service
);
185 run_service_command(service
, "stop")
191 _rpcenv
: &mut dyn RpcEnvironment
,
192 ) -> Result
<Value
, Error
> {
194 let service
= tools
::required_string_param(¶m
, "service")?
;
196 log
::info
!("re-starting service {}", service
);
198 if service
== "proxmox-backup-proxy" {
199 // special case, avoid aborting running tasks
200 run_service_command(service
, "reload")
202 run_service_command(service
, "restart")
209 _rpcenv
: &mut dyn RpcEnvironment
,
210 ) -> Result
<Value
, Error
> {
212 let service
= tools
::required_string_param(¶m
, "service")?
;
214 log
::info
!("reloading service {}", service
);
216 run_service_command(service
, "reload")
220 const SERVICE_ID_SCHEMA
: Schema
= StringSchema
::new("Service ID.")
225 const SERVICE_SUBDIRS
: SubdirMap
= &[
227 "reload", &Router
::new()
230 &ApiHandler
::Sync(&reload_service
),
234 ("node", false, &NODE_SCHEMA
),
235 ("service", false, &SERVICE_ID_SCHEMA
),
242 "restart", &Router
::new()
245 &ApiHandler
::Sync(&restart_service
),
249 ("node", false, &NODE_SCHEMA
),
250 ("service", false, &SERVICE_ID_SCHEMA
),
257 "start", &Router
::new()
260 &ApiHandler
::Sync(&start_service
),
264 ("node", false, &NODE_SCHEMA
),
265 ("service", false, &SERVICE_ID_SCHEMA
),
272 "state", &Router
::new()
275 &ApiHandler
::Sync(&get_service_state
),
277 "Read service properties.",
279 ("node", false, &NODE_SCHEMA
),
280 ("service", false, &SERVICE_ID_SCHEMA
),
287 "stop", &Router
::new()
290 &ApiHandler
::Sync(&stop_service
),
294 ("node", false, &NODE_SCHEMA
),
295 ("service", false, &SERVICE_ID_SCHEMA
),
303 const SERVICE_ROUTER
: Router
= Router
::new()
304 .get(&list_subdirs_api_method
!(SERVICE_SUBDIRS
))
305 .subdirs(SERVICE_SUBDIRS
);
308 pub const ROUTER
: Router
= Router
::new()
311 &ApiHandler
::Sync(&list_services
),
314 &sorted
!([ ("node", false, &NODE_SCHEMA
) ]),
318 "Returns a list of systemd services.",
322 ("service", false, &SERVICE_ID_SCHEMA
),
323 ("name", false, &StringSchema
::new("systemd service name.").schema()),
324 ("desc", false, &StringSchema
::new("systemd service description.").schema()),
325 ("state", false, &StringSchema
::new("systemd service 'SubState'.").schema()),
331 .match_all("service", &SERVICE_ROUTER
);