@cryptotaxi247 / netdata-1 / commits / 18c90c6d6

add fail2ban plugin

lgz committed Dec 28, 2016 at 00:53 UTC 18c90c6d6c707600fddd6dcd7ab149b3e3b6d611
1 file changed +91
python.d/fail2ban.chart.py new
+91
@@ -0,0 +1,91 @@
1 +# -*- coding: utf-8 -*-
2 +# Description: fail2ban log netdata python.d module
3 +# Author: l2isbad
4 +
5 +from base import LogService
6 +from re import compile
7 +try:
8 + from itertools import filterfalse
9 +except ImportError:
10 + from itertools import ifilterfalse as filterfalse
11 +from os import access as is_accessible, R_OK
12 +
13 +priority = 60000
14 +retries = 60
15 +regex = compile(r'([A-Za-z-]+\]) enabled = ([a-z]+)')
16 +
17 +ORDER = ['jails_group']
18 +
19 +
20 +class Service(LogService):
21 + def __init__(self, configuration=None, name=None):
22 + LogService.__init__(self, configuration=configuration, name=name)
23 + self.order = ORDER
24 + self.log_path = self.configuration.get('log_path', '/var/log/fail2ban.log')
25 + self.conf_path = self.configuration.get('conf_path', '/etc/fail2ban/jail.local')
26 + self.default_jails = ['ssh']
27 + try:
28 + self.exclude = self.configuration['exclude'].split()
29 + except (KeyError, AttributeError):
30 + self.exclude = []
31 +
32 +
33 + def _get_data(self):
34 + """
35 + Parse new log lines
36 + :return: dict
37 + """
38 +
39 + # If _get_raw_data returns empty list (no new lines in log file) we will send to Netdata this
40 + self.data = {jail: 0 for jail in self.jails_list}
41 +
42 + try:
43 + raw = self._get_raw_data()
44 + if raw is None:
45 + return None
46 + elif not raw:
47 + return self.data
48 + except (ValueError, AttributeError):
49 + return None
50 +
51 + # Fail2ban logs looks like
52 + # 2016-12-25 12:36:04,711 fail2ban.actions[2455]: WARNING [ssh] Ban 178.156.32.231
53 + self.data = dict(
54 + zip(
55 + self.jails_list,
56 + [len(list(filterfalse(lambda line: (jail + '] Ban') not in line, raw))) for jail in self.jails_list]
57 + ))
58 +
59 + return self.data
60 +
61 + def check(self):
62 +
63 + # Check "log_path" is accessible.
64 + # If NOT STOP plugin
65 + if not is_accessible(self.log_path, R_OK):
66 + self.error('Cannot access file %s' % (self.log_path))
67 + return False
68 +
69 + # Check "conf_path" is accessible.
70 + # If "conf_path" is accesible try to parse it to find enabled jails
71 + if is_accessible(self.conf_path, R_OK):
72 + with open(self.conf_path, 'rt') as jails_conf:
73 + jails_list = regex.findall(' '.join(jails_conf.read().split()))
74 + self.jails_list = [jail[:-1] for jail, status in jails_list if status == 'true']
75 + else:
76 + self.jails_list = []
77 + self.error('Cannot access jail.local file %s.' % (self.conf_path))
78 +
79 + # If for some reason parse failed we still can START with default jails_list.
80 + self.jails_list = [jail for jail in self.jails_list if jail not in self.exclude]\
81 + if self.jails_list else self.default_jails
82 + self.create_dimensions()
83 + self.info('Plugin succefully started. Jails: %s' % (self.jails_list))
84 + return True
85 +
86 + def create_dimensions(self):
87 + self.definitions = {'jails_group':
88 + {'options':
89 + [None, "Jails ban statistics", "bans/s", 'Jails', 'jail.ban', 'line'], 'lines': []}}
90 + for jail in self.jails_list:
91 + self.definitions['jails_group']['lines'].append([jail, jail, 'absolute'])