Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / systemd / timesync_status @ 0e43e779

Historique | Voir | Annoter | Télécharger (3,21 ko)

1 44b604cd Bert Peters
#!/usr/bin/env python3
2
import re
3
import subprocess
4
import sys
5
import textwrap
6
7
8
'''
9
=head1 NAME
10
11
timesync_status - monitor ntp status with systemd-timesyncd
12
13
=head1 APPLICABLE SYSTEMS
14
15
All systems using systemd-timesyncd as its NTP-client. However, this
16
plugin itself also needs Python 3.5+ to call subprocess.run.
17
18
=head1 CONFIGURATION
19
20
This plugin should work out-of-the-box with autoconf. It does expect
21
timedatectl to be on $PATH, but that should always be the case in a
22
normal system.
23
24
=head1 INTERPRETATION
25
26
This plugin shows a graph with one line for every NTP metric it measure.
27
Metrics are shown with their usual name, and are explained in their
28
respective info fields.
29
30
This plugin issues no warnings or critical states.
31
32
=head1 MAGIC MARKERS
33
34
 #%# family=auto
35
 #%# capabilities=autoconf
36
37
=head1 VERSION
38
39
1.0
40
41
=head1 AUTHOR
42
43
Bert Peters <bert@bertptrs.nl>
44
45
=head1 LICENSE
46
47 c6f88968 Lars Kruse
GNU General Public License v2.0 only
48
49
SPDX-License-Identifier: LGPL-2.0-only
50
51
=cut
52 44b604cd Bert Peters
'''
53
54
55
def parse_time(value):
56
    value = value.strip()
57
    if ' ' in value:
58
        return sum(parse_time(x) for x in value.split(' '))
59
60
    match = re.match(r'^([+-]?[0-9.]+)([a-z]+)$', value)
61
    if not match:
62
        raise ValueError('Invalid time ' + value)
63
64
    value = float(match.group(1))
65
    suffix = match.group(2)
66
67
    if suffix == 'min':
68
        value *= 60
69
    elif suffix == 'ms':
70
        value /= 1000
71
    elif suffix == 'us':
72
        value /= 1e6
73
74
    return value
75
76
77
def parse_response(data):
78
    values = {}
79
    for line in data.splitlines():
80
        k, v = line.split(': ', 1)
81
        values[k.strip()] = v.strip()
82
83
    return values
84
85
86
def retrieve():
87
    result = subprocess.run(['timedatectl', 'timesync-status'], capture_output=True)
88
    if result.returncode != 0:
89
        sys.exit('timedatectl failed')
90
91
    output = result.stdout.decode('utf-8')
92
    values = parse_response(output)
93
94
    print('offset.value', parse_time(values['Offset']))
95
    print('delay.value', parse_time(values['Delay']))
96
    print('delay.extinfo', 'Server', values['Server'])
97
    print('jitter.value', parse_time(values['Jitter']))
98
    print('poll.value', parse_time(values['Poll interval'].split('(')[0]))
99
100
101
def autoconf():
102
    result = subprocess.run(['timedatectl', 'status'], capture_output=True)
103
    if result.returncode != 0:
104
        print('no (failed to run timedatectl)')
105
        return
106
107
    values = parse_response(result.stdout.decode('utf-8'))
108
    if values['NTP service'] == 'active':
109
        print('yes')
110
    else:
111
        print('no (ntp service not running)')
112
113
114
def config():
115
    print(textwrap.dedent('''\
116
            graph_title Timesync status
117
            graph_vlabel s
118
            graph_category time
119
120
            offset.label Offset
121
            offset.info Time difference between source and local
122
123
            delay.label Delay
124
            delay.info Roundtrip time to the NTP-server
125
126
            jitter.label Jitter
127
            jitter.info Difference in offset between two subsequent samples
128
129
            poll.label Polling time
130
            poll.info Time between two subsequent NTP-polls
131
    '''))
132
133
134
if __name__ == '__main__':
135 0e43e779 Simone Rossetto
    if len(sys.argv) == 1 or sys.argv[1] == 'fetch':
136 44b604cd Bert Peters
        retrieve()
137
    elif sys.argv[1] == 'config':
138
        config()
139
    elif sys.argv[1] == 'autoconf':
140
        autoconf()