Skip to content

Commit 3cfef85

Browse files
authored
Merge pull request #7 from adam-trhon/feature/systemd-get-services-json
Feature/systemd get services json
2 parents 9cec7bc + 5c3f3f1 commit 3cfef85

File tree

1 file changed

+93
-30
lines changed

1 file changed

+93
-30
lines changed

labgridhelper/linux.py

Lines changed: 93 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,102 @@
11
from labgrid.protocol import CommandProtocol
2+
import json
3+
import re
4+
5+
def get_systemd_version(command):
6+
"""Returns systemd version retrieved by parsing output of `systemd --version`
7+
8+
Args:
9+
command (CommandProtocol): An instance of a Driver implementing the CommandProtocol
10+
11+
Returns:
12+
int: systemd version number
13+
"""
14+
assert isinstance(command, CommandProtocol), "command must be a CommandProtocol"
15+
16+
out = command.run_check("systemctl --version")
17+
out = out[0]
18+
19+
parsed = re.search(r'^systemd\s+(?P<version>\d+)\s+', out)
20+
if not parsed:
21+
raise ValueError("Systemd version output changed")
22+
return int(parsed.group("version"))
223

324
def get_systemd_status(command):
25+
"""Returns parsed output of systemd Manager's ListUnits DBus command
26+
27+
Args:
28+
command (CommandProtocol): An instance of a Driver implementing the CommandProtocol
29+
30+
Returns:
31+
dict: dictionary of service names to their properties
32+
"""
433
assert isinstance(command, CommandProtocol), "command must be a CommandProtocol"
5-
# TODO: Use busctl --json if systemd>239
634
array_notation = "a(ssssssouso)"
7-
out = command.run_check(
8-
"busctl call --no-pager org.freedesktop.systemd1 \
9-
/org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnits"
10-
)
1135

12-
out = out[0]
13-
if array_notation not in out:
14-
raise ValueError("Systemd ListUnits output changed")
15-
out = out[len(array_notation):]
16-
array_length = int(out[:out.index('"')].strip(" "))
17-
out = out[out.index('"')+1:-1]
18-
out = out.split('\" \"')
19-
data = iter(out)
20-
services = {}
21-
for _ in range(array_length):
22-
name = next(data)
23-
services[name] = {}
24-
services[name]["description"] = next(data)
25-
services[name]["load"] = next(data)
26-
services[name]["active"] = next(data)
27-
services[name]["sub"] = next(data)
28-
services[name]["follow"] = next(data)
29-
path_and_id = next(data)
30-
pos = path_and_id.index('"')
31-
services[name]["path"] = path_and_id[:pos]
32-
services[name]["id"] = int(path_and_id[pos+1:-1].strip(" "))
33-
services[name]["type"] = path_and_id[path_and_id.rfind('"'):]
34-
services[name]["objpath"] = next(data)
35-
36-
return services
36+
def get_systemd_status_json(command):
37+
out = command.run_check(
38+
"busctl call --json=short --no-pager org.freedesktop.systemd1 \
39+
/org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnits"
40+
)
41+
out = out[0]
42+
out = json.loads(out)
43+
if out["type"] != array_notation:
44+
raise ValueError("Systemd ListUnits output changed")
45+
46+
services = {}
47+
for record in out["data"][0]:
48+
data = iter(record)
49+
name = next(data)
50+
services[name] = {}
51+
services[name]["description"] = next(data)
52+
services[name]["load"] = next(data)
53+
services[name]["active"] = next(data)
54+
services[name]["sub"] = next(data)
55+
services[name]["follow"] = next(data)
56+
services[name]["path"] = next(data)
57+
services[name]["id"] = int(next(data))
58+
services[name]["type"] = next(data)
59+
services[name]["objpath"] = next(data)
60+
61+
return services
62+
63+
def get_systemd_status_raw(command):
64+
out = command.run_check(
65+
"busctl call --no-pager org.freedesktop.systemd1 \
66+
/org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnits"
67+
)
68+
69+
out = out[0]
70+
if array_notation not in out:
71+
raise ValueError("Systemd ListUnits output changed")
72+
out = out[len(array_notation):]
73+
array_length = int(out[:out.index('"')].strip(" "))
74+
out = out[out.index('"')+1:-1]
75+
out = out.split('\" \"')
76+
data = iter(out)
77+
services = {}
78+
for _ in range(array_length):
79+
name = next(data)
80+
services[name] = {}
81+
services[name]["description"] = next(data)
82+
services[name]["load"] = next(data)
83+
services[name]["active"] = next(data)
84+
services[name]["sub"] = next(data)
85+
services[name]["follow"] = next(data)
86+
path_and_id = next(data)
87+
pos = path_and_id.index('"')
88+
services[name]["path"] = path_and_id[:pos]
89+
services[name]["id"] = int(path_and_id[pos+1:-1].strip(" "))
90+
services[name]["type"] = path_and_id[path_and_id.rfind('"'):]
91+
services[name]["objpath"] = next(data)
92+
93+
return services
94+
95+
if get_systemd_version(command) > 239:
96+
return get_systemd_status_json(command)
97+
else:
98+
return get_systemd_status_raw(command)
99+
37100

38101
def get_commands(command, directories=None):
39102
"""Returns the commands of a running linux system

0 commit comments

Comments
 (0)