Modify according PR comments from l2isbad
- Improve configuration code - Fix multiple jobs - Modify SocketService to get bytes if requested - Remove now obsolete code in module ntp
Sven Mäder committed
Feb 14, 2018 at 21:50 UTC
f70aa5c2262b1e874db69a4a899b298e67d43e5f
3 files changed
+39
-74
python.d/README.md
+12
@@ -1525,6 +1525,18 @@ peer_names: yes
1525
peer_filter: '(127\..*)|(.*\.example\.com)'
1526
```
1527
1528
+Sample (multiple jobs):
1529
+
1530
+Note: `ntp.conf` on host `otherhost` must be configured to allow queries from our local host by including a line like `restrict <IP> nomodify notrap nopeer`.
1531
+
1532
+```yaml
1533
+local:
1534
+ host: 'localhost'
1535
+
1536
+otherhost:
1537
+ host: 'otherhost'
1538
+```
1539
+
1540
If no configuration is given, module will attempt to connect to `ntpd` on `::1:123` or `127.0.0.1:123`. Peer names are resolved using reverse dns lookup of the source address. Local peers (127.*) are hidden by default, use `peer_filter: '.*'` to show all. To disable reverse lookup and show ip addresses instead, use `peer_names: no`. Any dots `.` are replaced with dashes `-`.
1541
1542
---
python.d/ntp.chart.py
+13
-66
@@ -7,7 +7,7 @@ import struct
7
import re
8
9
from itertools import cycle
10
-from base import SocketService
10
+from bases.FrameworkServices.SocketService import SocketService
11
12
# default module values
13
update_every = 1
@@ -131,18 +131,17 @@ class Service(SocketService):
131
self.regex_data = re.compile(r'([a-z_]+)=([0-9-]+(?:\.[0-9]+)?)(?=,)')
132
self.order = None
133
self.definitions = None
134
+ self.peer_names = self.configuration.get('peer_names', True)
135
+ peer_filter_start = r'^((0\.0\.0\.0)|('
136
+ peer_filter_end = r'))$'
137
+ peer_filter_default = r'127\..*'
138
+ peer_filter_custom = str(self.configuration.get('peer_filter', peer_filter_default))
139
140
try:
136
- peer_filter = r'^((0\.0\.0\.0)|(' + str(self.configuration['peer_filter']) + r'))$'
137
- except (KeyError, TypeError):
138
- self.error('error parsing peer_filter')
139
- peer_filter = r'^((0\.0\.0\.0)|(127\..*))$'
140
- self.regex_peer_filter = re.compile(peer_filter)
141
-
142
- try:
143
- self.peer_names = bool((self.configuration['peer_names']))
144
- except (KeyError, TypeError):
145
- self.peer_names = True
141
+ self.regex_peer_filter = re.compile(peer_filter_start + peer_filter_custom + peer_filter_end)
142
+ except re.error as error:
143
+ self.error('Pattern compile error. Using defaults.')
144
+ self.regex_peer_filter = re.compile(peer_filter_start + peer_filter_default + peer_filter_end)
145
146
def create_charts(self):
147
"""
@@ -151,12 +150,12 @@ class Service(SocketService):
150
Adds all peers whith valid data.
151
"""
152
# Create systemvars charts
154
- self.order = ORDER
155
- self.definitions = CHARTS
153
+ self.order = list(ORDER)
154
+ self.definitions = dict(CHARTS)
155
156
# Get peer ids
157
self.request = self.get_header(0, 'readstat')
159
- peer_ids = self.get_peer_ids(self._get_raw_data_bytes())
158
+ peer_ids = self.get_peer_ids(self._get_raw_data(raw=True))
159
160
# Get peers
161
peers = self.get_peers(peer_ids)
@@ -325,58 +324,6 @@ class Service(SocketService):
324
325
return data
326
328
- def _receive_bytes(self):
329
- """
330
- Receive data from socket
331
- :return: bytestr
332
- """
333
- data = b""
334
- while True:
335
- self.debug('receiving response')
336
- try:
337
- buf = self._sock.recv(4096)
338
- except Exception as error:
339
- self._socket_error('failed to receive response: {0}'.format(error))
340
- self._disconnect()
341
- break
342
-
343
- if buf is None or len(buf) == 0: # handle server disconnect
344
- if data == b"":
345
- self._socket_error('unexpectedly disconnected')
346
- else:
347
- self.debug('server closed the connection')
348
- self._disconnect()
349
- break
350
-
351
- self.debug('received data')
352
- data += buf
353
- if self._check_raw_data(data):
354
- break
355
-
356
- self.debug('final response: {0}'.format(data))
357
- return data
358
-
359
- def _get_raw_data_bytes(self):
360
- """
361
- Get raw data with low-level "socket" module.
362
- :return: bytestr
363
- """
364
- if self._sock is None:
365
- self._connect()
366
- if self._sock is None:
367
- return None
368
-
369
- # Send request if it is needed
370
- if not self._send():
371
- return None
372
-
373
- data = self._receive_bytes()
374
-
375
- if not self._keep_alive:
376
- self._disconnect()
377
-
378
- return data
379
-
327
def get_header(self, associd=0, operation='readvar'):
328
"""
329
Constructs the NTP Control Message header:
python.d/python_modules/bases/FrameworkServices/SocketService.py
+14
-8
@@ -163,12 +163,15 @@ class SocketService(SimpleService):
163
return False
164
return True
165
166
- def _receive(self):
166
+ def _receive(self, raw=False):
167
"""
168
Receive data from socket
169
- :return: str
169
+ :param raw: set `True` to return bytes
170
+ :type raw: bool
171
+ :return: decoded str or raw bytes
172
+ :rtype: str/bytes
173
"""
171
- data = ""
174
+ data = "" if not raw else b""
175
while True:
176
self.debug('receiving response')
177
try:
@@ -179,7 +182,7 @@ class SocketService(SimpleService):
182
break
183
184
if buf is None or len(buf) == 0: # handle server disconnect
182
- if data == "":
185
+ if data == "" or data == b"":
186
self._socket_error('unexpectedly disconnected')
187
else:
188
self.debug('server closed the connection')
@@ -187,17 +190,20 @@ class SocketService(SimpleService):
190
break
191
192
self.debug('received data')
190
- data += buf.decode('utf-8', 'ignore')
193
+ data += buf.decode('utf-8', 'ignore') if not raw else buf
194
if self._check_raw_data(data):
195
break
196
197
self.debug('final response: {0}'.format(data))
198
return data
199
197
- def _get_raw_data(self):
200
+ def _get_raw_data(self, raw=False):
201
"""
202
Get raw data with low-level "socket" module.
200
- :return: str
203
+ :param raw: set `True` to return bytes
204
+ :type raw: bool
205
+ :return: decoded data (str) or raw data (bytes)
206
+ :rtype: str/bytes
207
"""
208
if self._sock is None:
209
self._connect()
@@ -208,7 +214,7 @@ class SocketService(SimpleService):
214
if not self._send():
215
return None
216
211
- data = self._receive()
217
+ data = self._receive(raw)
218
219
if not self._keep_alive:
220
self._disconnect()