]> arthur.barton.de Git - netdata.git/commitdiff
fail2ban_plugin: can read config files from "conf_dir" now
authorIlya <ilyamaschenko@gmail.com>
Fri, 17 Feb 2017 13:01:36 +0000 (22:01 +0900)
committerIlya <ilyamaschenko@gmail.com>
Fri, 17 Feb 2017 13:01:36 +0000 (22:01 +0900)
python.d/fail2ban.chart.py

index 2d80282c68897f761b97495d9064eddb24abfb58..dbbc1946703837d54407636f748c771a9ae83521 100644 (file)
@@ -4,16 +4,18 @@
 
 from base import LogService
 from re import compile
+
 try:
     from itertools import filterfalse
 except ImportError:
     from itertools import ifilterfalse as filterfalse
 from os import access as is_accessible, R_OK
+from os.path import isdir
+from glob import glob
 
 priority = 60000
 retries = 60
-regex = compile(r'([A-Za-z-]+\]) enabled = ([a-z]+)')
-
+REGEX = compile(r'\[([A-Za-z-]+)][^\[\]]*? enabled = true')
 ORDER = ['jails_group']
 
 
@@ -23,22 +25,17 @@ class Service(LogService):
         self.order = ORDER
         self.log_path = self.configuration.get('log_path', '/var/log/fail2ban.log')
         self.conf_path = self.configuration.get('conf_path', '/etc/fail2ban/jail.local')
-        self.default_jails = ['ssh']
+        self.conf_dir = self.configuration.get('conf_dir', '')
         try:
             self.exclude = self.configuration['exclude'].split()
         except (KeyError, AttributeError):
             self.exclude = []
-        
 
     def _get_data(self):
         """
         Parse new log lines
         :return: dict
         """
-
-        # If _get_raw_data returns empty list (no new lines in log file) we will send to Netdata this
-        self.data = {jail: 0 for jail in self.jails_list}
-        
         try:
             raw = self._get_raw_data()
             if raw is None:
@@ -50,42 +47,69 @@ class Service(LogService):
 
         # Fail2ban logs looks like
         # 2016-12-25 12:36:04,711 fail2ban.actions[2455]: WARNING [ssh] Ban 178.156.32.231
-        self.data = dict(
+        data = dict(
             zip(
                 self.jails_list,
                 [len(list(filterfalse(lambda line: (jail + '] Ban') not in line, raw))) for jail in self.jails_list]
             ))
 
+        for jail in data:
+            self.data[jail] += data[jail]
+
         return self.data
 
     def check(self):
-            
+
         # Check "log_path" is accessible.
         # If NOT STOP plugin
         if not is_accessible(self.log_path, R_OK):
-            self.error('Cannot access file %s' % (self.log_path))
+            self.error('Cannot access file %s' % self.log_path)
             return False
+        if not isdir(self.conf_dir):
+            self.conf_dir = None
 
-        # Check "conf_path" is accessible.
-        # If "conf_path" is accesible try to parse it to find enabled jails
-        if is_accessible(self.conf_path, R_OK):
-            with open(self.conf_path, 'rt') as jails_conf:
-                jails_list = regex.findall(' '.join(jails_conf.read().split()))
-            self.jails_list = [jail[:-1] for jail, status in jails_list if status == 'true']
+        # If "conf_dir" not specified (or not a dir) plugin will use "conf_path"
+        if not self.conf_dir:
+            if is_accessible(self.conf_path, R_OK):
+                with open(self.conf_path, 'rt') as jails_conf:
+                    jails_list = REGEX.findall(' '.join(jails_conf.read().split()))
+                self.jails_list = jails_list
+            else:
+                self.jails_list = list()
+                self.error('Cannot access jail configuration file %s.' % self.conf_path)
+        # If "conf_dir" is specified and "conf_dir" is dir plugin will use "conf_dir"
         else:
-            self.jails_list = []
-            self.error('Cannot access jail.local file %s.' % (self.conf_path))
-        
+            dot_local = glob(self.conf_dir + '/*.local')  # *.local jail configurations files
+            dot_conf = glob(self.conf_dir + '/*.conf')  # *.conf jail configuration files
+
+            if not any([dot_local, dot_conf]):
+                self.error('%s is empty or not readable' % self.conf_dir)
+            # According "man jail.conf" files could be *.local AND *.conf
+            # *.conf files parsed first. Changes in *.local overrides configuration in *.conf
+            if dot_conf:
+                dot_local.extend([conf for conf in dot_conf if conf[:-5] not in [local[:-6] for local in dot_local]])
+            # Make sure all files are readable
+            dot_local = [conf for conf in dot_local if is_accessible(conf, R_OK)]
+            if dot_local:
+                enabled_jails = list()
+                for jail_conf in dot_local:
+                    with open(jail_conf, 'rt') as conf:
+                        enabled_jails.extend(REGEX.findall(' '.join(conf.read().split())))
+                self.jails_list = list(set(enabled_jails))
+            else:
+                self.jails_list = list()
+                self.error('Files in %s not readable' % self.conf_dir)
+
         # If for some reason parse failed we still can START with default jails_list.
-        self.jails_list = [jail for jail in self.jails_list if jail not in self.exclude]\
-                                              if self.jails_list else self.default_jails
+        self.jails_list = list(set(self.jails_list) - set(self.exclude)) or ['ssh']
+        self.data = dict([(jail, 0) for jail in self.jails_list])
         self.create_dimensions()
-        self.info('Plugin succefully started. Jails: %s' % (self.jails_list))
+        self.info('Plugin successfully started. Jails: %s' % self.jails_list)
         return True
 
     def create_dimensions(self):
-        self.definitions = {'jails_group':
-                                {'options':
-                                     [None, "Jails ban statistics", "bans/s", 'Jails', 'jail.ban', 'line'], 'lines': []}}
+        self.definitions = {
+            'jails_group': {'options': [None, "Jails ban statistics", "bans/s", 'Jails', 'jail.ban', 'line'],
+                            'lines': []}}
         for jail in self.jails_list:
-            self.definitions['jails_group']['lines'].append([jail, jail, 'absolute'])
+            self.definitions['jails_group']['lines'].append([jail, jail, 'incremental'])