Projet

Général

Profil

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

root / plugins / systemd / timesync_status @ 44b604cd

Historique | Voir | Annoter | Télécharger (3,11 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
GPLv2
48
'''
49

    
50

    
51
def parse_time(value):
52
    value = value.strip()
53
    if ' ' in value:
54
        return sum(parse_time(x) for x in value.split(' '))
55

    
56
    match = re.match(r'^([+-]?[0-9.]+)([a-z]+)$', value)
57
    if not match:
58
        raise ValueError('Invalid time ' + value)
59

    
60
    value = float(match.group(1))
61
    suffix = match.group(2)
62

    
63
    if suffix == 'min':
64
        value *= 60
65
    elif suffix == 'ms':
66
        value /= 1000
67
    elif suffix == 'us':
68
        value /= 1e6
69

    
70
    return value
71

    
72

    
73
def parse_response(data):
74
    values = {}
75
    for line in data.splitlines():
76
        k, v = line.split(': ', 1)
77
        values[k.strip()] = v.strip()
78

    
79
    return values
80

    
81

    
82
def retrieve():
83
    result = subprocess.run(['timedatectl', 'timesync-status'], capture_output=True)
84
    if result.returncode != 0:
85
        sys.exit('timedatectl failed')
86

    
87
    output = result.stdout.decode('utf-8')
88
    values = parse_response(output)
89

    
90
    print('offset.value', parse_time(values['Offset']))
91
    print('delay.value', parse_time(values['Delay']))
92
    print('delay.extinfo', 'Server', values['Server'])
93
    print('jitter.value', parse_time(values['Jitter']))
94
    print('poll.value', parse_time(values['Poll interval'].split('(')[0]))
95

    
96

    
97
def autoconf():
98
    result = subprocess.run(['timedatectl', 'status'], capture_output=True)
99
    if result.returncode != 0:
100
        print('no (failed to run timedatectl)')
101
        return
102

    
103
    values = parse_response(result.stdout.decode('utf-8'))
104
    if values['NTP service'] == 'active':
105
        print('yes')
106
    else:
107
        print('no (ntp service not running)')
108

    
109

    
110
def config():
111
    print(textwrap.dedent('''\
112
            graph_title Timesync status
113
            graph_vlabel s
114
            graph_category time
115

    
116
            offset.label Offset
117
            offset.info Time difference between source and local
118

    
119
            delay.label Delay
120
            delay.info Roundtrip time to the NTP-server
121

    
122
            jitter.label Jitter
123
            jitter.info Difference in offset between two subsequent samples
124

    
125
            poll.label Polling time
126
            poll.info Time between two subsequent NTP-polls
127
    '''))
128

    
129

    
130
if __name__ == '__main__':
131
    if len(sys.argv) == 1:
132
        retrieve()
133
    elif sys.argv[1] == 'config':
134
        config()
135
    elif sys.argv[1] == 'autoconf':
136
        autoconf()