Skip to content

Commit eb588ef

Browse files
committed
Add needrestart_info.py to monitore needrestart.
Signed-off-by: RomainMou <[email protected]>
1 parent 3018120 commit eb588ef

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

Diff for: needrestart_info.py

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#!/usr/bin/env python3
2+
#
3+
#
4+
# Description: Expose metrics from needrestart.
5+
#
6+
# This script runs needrestart in batch mode. It will never ask for input
7+
# and will never restart or upgrade anything.
8+
#
9+
# Dependencies: python >= 3.5, python3-prometheus-client, needrestart
10+
#
11+
# Authors: RomainMou
12+
13+
import time
14+
import subprocess
15+
from collections import Counter
16+
from enum import Enum
17+
from prometheus_client import (
18+
CollectorRegistry,
19+
Gauge,
20+
generate_latest,
21+
)
22+
23+
24+
class KernelStatus(Enum):
25+
UNKNOWN = 0
26+
CURRENT = 1
27+
ABI_UPGRADE = 2
28+
VERSION_UPGRADE = 3
29+
30+
31+
class MicroCodeStatus(Enum):
32+
UNKNOWN = 0
33+
CURRENT = 1
34+
OBSELETE = 2
35+
36+
37+
class NeedrestartParser:
38+
def __init__(self, needrestart_output):
39+
# Some default value
40+
self.timestamp = int(time.time())
41+
self.version = None
42+
self.kernel_status = None
43+
self.microcode_status = None
44+
self.kernel_current_version = ""
45+
self.kernel_expected_version = ""
46+
self.microcode_current_version = ""
47+
self.microcode_expected_version = ""
48+
needrestart_counter = Counter()
49+
50+
# Parse the cmd output
51+
for line in needrestart_output.stdout.decode().splitlines():
52+
key, value = line.split(": ")
53+
if key == "NEEDRESTART-VER":
54+
self.version = value
55+
# Kernel informations
56+
elif key == "NEEDRESTART-KCUR":
57+
self.kernel_current_version = value
58+
elif key == "NEEDRESTART-KEXP":
59+
self.kernel_expected_version = value
60+
elif key == "NEEDRESTART-KSTA":
61+
self.kernel_status = KernelStatus(int(value))
62+
# Microcode informations
63+
elif key == "NEEDRESTART-UCCUR":
64+
self.microcode_current_version = value
65+
elif key == "NEEDRESTART-UCEXP":
66+
self.microcode_expected_version = value
67+
elif key == "NEEDRESTART-UCSTA":
68+
self.microcode_status = MicroCodeStatus(int(value))
69+
# Count the others
70+
else:
71+
needrestart_counter.update({key})
72+
73+
self.services_count = needrestart_counter["NEEDRESTART-SVC"]
74+
self.containers_count = needrestart_counter["NEEDRESTART-CONT"]
75+
self.sessions_count = needrestart_counter["NEEDRESTART-SESS"]
76+
77+
78+
def _write_timestamp(registry, needrestart_data):
79+
g = Gauge(
80+
"needrestart_timestamp",
81+
"information about the version and when it was last run",
82+
labelnames=["version"],
83+
registry=registry,
84+
)
85+
g.labels(needrestart_data.version).set(needrestart_data.timestamp)
86+
87+
88+
def _write_kernel(registry, needrestart_data):
89+
if needrestart_data.kernel_status:
90+
e = Gauge(
91+
"needrestart_kernel_status",
92+
"information about the kernel status",
93+
labelnames=["current", "expected"],
94+
registry=registry,
95+
)
96+
e.labels(
97+
needrestart_data.kernel_current_version,
98+
needrestart_data.kernel_expected_version,
99+
).set(needrestart_data.kernel_status.value)
100+
101+
102+
def _write_microcode(registry, needrestart_data):
103+
if needrestart_data.microcode_status:
104+
e = Gauge(
105+
"needrestart_microcode_status",
106+
"information about the microcode status",
107+
labelnames=["current", "expected"],
108+
registry=registry,
109+
)
110+
e.labels(
111+
needrestart_data.microcode_current_version,
112+
needrestart_data.microcode_expected_version,
113+
).set(needrestart_data.microcode_status.value)
114+
115+
116+
def _write_services(registry, needrestart_data):
117+
g = Gauge(
118+
"needrestart_services_count",
119+
"number of services requiring a restart",
120+
registry=registry,
121+
)
122+
g.set(needrestart_data.services_count)
123+
124+
125+
def _write_containers(registry, needrestart_data):
126+
g = Gauge(
127+
"needrestart_containers_count",
128+
"number of containers requiring a restart",
129+
registry=registry,
130+
)
131+
g.set(needrestart_data.containers_count)
132+
133+
134+
def _write_sessions(registry, needrestart_data):
135+
g = Gauge(
136+
"needrestart_sessions_count",
137+
"number of sessions requiring a restart",
138+
registry=registry,
139+
)
140+
g.set(needrestart_data.sessions_count)
141+
142+
143+
def _main():
144+
registry = CollectorRegistry()
145+
needrestart_data = NeedrestartParser(
146+
subprocess.run(["needrestart", "-b"], stdout=subprocess.PIPE)
147+
)
148+
149+
_write_timestamp(registry, needrestart_data)
150+
_write_kernel(registry, needrestart_data)
151+
_write_microcode(registry, needrestart_data)
152+
_write_services(registry, needrestart_data)
153+
_write_containers(registry, needrestart_data)
154+
_write_sessions(registry, needrestart_data)
155+
156+
print(generate_latest(registry).decode(), end="")
157+
158+
159+
if __name__ == "__main__":
160+
_main()

0 commit comments

Comments
 (0)