163 lines
4.7 KiB
Python
163 lines
4.7 KiB
Python
#!/usr/bin/python3
|
|
|
|
# Monitor chronyd
|
|
#
|
|
# Copyright 2019 Bernd Zeimetz <bernd@bzed.de>
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the
|
|
# "Software"), to deal in the Software without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be
|
|
# included in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
from subprocess import Popen, PIPE
|
|
import optparse
|
|
import sys
|
|
|
|
broken_example = """Reference ID : 00000000 ()
|
|
Stratum : 0
|
|
Ref time (UTC) : Thu Jan 01 00:00:00 1970
|
|
System time : 0.000000000 seconds fast of NTP time
|
|
Last offset : +0.000000000 seconds
|
|
RMS offset : 0.000000000 seconds
|
|
Frequency : 8.769 ppm fast
|
|
Residual freq : +0.000 ppm
|
|
Skew : 0.000 ppm
|
|
Root delay : 1.000000000 seconds
|
|
Root dispersion : 1.000000000 seconds
|
|
Update interval : 0.0 seconds
|
|
Leap status : Not synchronised
|
|
"""
|
|
|
|
NAGIOS_STATUS = {
|
|
"OK": 0,
|
|
"WARNING": 1,
|
|
"CRITICAL": 2,
|
|
"UNKNOWN": 3
|
|
}
|
|
|
|
parser = optparse.OptionParser()
|
|
parser.set_usage("%prog [options]")
|
|
parser.add_option(
|
|
"-w", "--warning", dest="warning", metavar="WARNING",
|
|
type="int", default="1000",
|
|
help="time differences in ms (warning)"
|
|
)
|
|
parser.add_option(
|
|
"-c", "--critical", dest="critical", metavar="CRITICAL",
|
|
type="int", default="3000",
|
|
help="time differences in ms (critical)"
|
|
)
|
|
parser.add_option(
|
|
"-W", "--stratum-warning", dest="stratum_warning",
|
|
metavar="STRATUM_WARNING",
|
|
type="int", default="3",
|
|
help="maximum stratum level (warning)"
|
|
)
|
|
parser.add_option(
|
|
"-C", "--stratum-critical", dest="stratum_critical",
|
|
metavar="STRATUM_CRITICAL",
|
|
type="int", default="5",
|
|
help="maximum stratum level (critical)"
|
|
)
|
|
(options, args) = parser.parse_args()
|
|
|
|
chronyc = Popen(
|
|
['chronyc', 'tracking'],
|
|
stdin=PIPE, stdout=PIPE, stderr=PIPE,
|
|
bufsize=-1
|
|
)
|
|
output, error = chronyc.communicate()
|
|
|
|
if chronyc.returncode > 0:
|
|
print(("chronyc failed: {}".format(output)))
|
|
sys.exit(NAGIOS_STATUS['CRITICAL'])
|
|
|
|
output = output.decode().split('\n')
|
|
parsed_output = {}
|
|
|
|
for line in output:
|
|
if ':' not in line:
|
|
continue
|
|
line = line.split(':')
|
|
key = line[0]
|
|
value = ':'.join(line[1:])
|
|
key = key.strip()
|
|
value = value.strip()
|
|
key = key.replace('(', '')
|
|
key = key.replace(')', '')
|
|
key = key.replace(' ', '_')
|
|
key = key.lower()
|
|
|
|
parsed_output[key] = value
|
|
|
|
if '00000000' in parsed_output['reference_id']:
|
|
print("chrony failed to connect to NTP server.")
|
|
sys.exit(NAGIOS_STATUS['CRITICAL'])
|
|
|
|
if int(parsed_output['stratum']) > options.stratum_critical:
|
|
print((
|
|
"chrony stratum too high: {} > {}".format(
|
|
parsed_output['stratum'],
|
|
options.stratum_critical
|
|
)
|
|
))
|
|
sys.exit(NAGIOS_STATUS['CRITICAL'])
|
|
|
|
if int(parsed_output['stratum']) > options.stratum_warning:
|
|
print((
|
|
"chrony stratum too high: {} > {}".format(
|
|
parsed_output['stratum'],
|
|
options.stratum_warning
|
|
)
|
|
))
|
|
sys.exit(NAGIOS_STATUS['WARNING'])
|
|
|
|
system_time = parsed_output['system_time'].split(' ')
|
|
system_time_diff_ms = float(system_time[0]) * 1000
|
|
system_time_desc = ' '.join(system_time[1:])
|
|
|
|
if (system_time_diff_ms > options.critical):
|
|
print((
|
|
"chrony system time {}ms {}. ({}ms > {}ms)".format(
|
|
system_time_diff_ms,
|
|
system_time_desc,
|
|
system_time_diff_ms,
|
|
options.critical
|
|
)
|
|
))
|
|
sys.exit(NAGIOS_STATUS['CRITICAL'])
|
|
|
|
if (system_time_diff_ms > options.warning):
|
|
print((
|
|
"chrony system time {}ms {}. ({}ms > {}ms)".format(
|
|
system_time_diff_ms,
|
|
system_time_desc,
|
|
system_time_diff_ms,
|
|
options.warning
|
|
)
|
|
))
|
|
sys.exit(NAGIOS_STATUS['WARNING'])
|
|
|
|
|
|
print((
|
|
"chrony OK: System Time {}, Stratum {}".format(
|
|
parsed_output['system_time'],
|
|
parsed_output['stratum'],
|
|
)
|
|
))
|
|
sys.exit(NAGIOS_STATUS['OK'])
|