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
#!/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
GNU General Public License v2.0 only
48

    
49
SPDX-License-Identifier: LGPL-2.0-only
50

    
51
=cut
52
'''
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
    if len(sys.argv) == 1 or sys.argv[1] == 'fetch':
136
        retrieve()
137
    elif sys.argv[1] == 'config':
138
        config()
139
    elif sys.argv[1] == 'autoconf':
140
        autoconf()