def get_all_active_checks(self): checks = [] deps_error = [] for plugin_data in self.plugins_checks: plugin_name = plugin_data['type'] # Load plugin plugin_info = PluginRegister.get_plugin(plugin_name) if not plugin_info: print('Plugin {} does not exist'.format(plugin_name)) exit(1) # Configure plugin try: plugin = plugin_info['plugin_cls']( plugin_data.get('config', {}) ) except DependencyError as e: deps_error.append(str(e)) continue # Launch plugin checks for check in plugin_data['checks']: func_name = plugin_info['checks'].get(check['type']) if func_name is None: print('Unknown check {} on plugin {}'.format(check['type'], plugin_name)) exit(1) check_func = getattr(plugin, func_name) # An empty string is a valid check name check_name = check.get( 'name', '{}_{}'.format(plugin_name, check['type']) ).lower() check_periodicity = (check.get('periodicity') or self.periodicity) checks.append(Check(check_name, check_periodicity, check_func, check)) if deps_error: for error in deps_error: print(error) exit(1) # Check duplicate name names = [check.name for check in checks] duplicates_names = {name: names.count(name) for name in names if names.count(name) > 1} for name, count in duplicates_names.items(): print("check name {} was found {} times, please add name" " field to theses checks".format(name, count)) if duplicates_names: exit(1) return checks
from sauna.plugins import Plugin, PluginRegister my_plugin = PluginRegister('HTTP') @my_plugin.plugin() class HTTP(Plugin): def __init__(self, config): super().__init__(config) try: import requests self.requests = requests except ImportError: from ... import DependencyError raise DependencyError(self.__class__.__name__, 'requests', 'requests', 'python3-requests') @my_plugin.check() def request(self, check_config): code = check_config.get('code', 200) content = check_config.get('content', '') try: r = self._do_http_request(check_config) except Exception as e: return Plugin.STATUS_CRIT, '{}'.format(e) if r.status_code != code: return (Plugin.STATUS_CRIT, 'Got status code {} instead of {}'.format( r.status_code, code))
def test_get_plugin(self): import sauna sauna.Sauna.import_submodules('sauna.plugins.ext') load_plugin = PluginRegister.get_plugin('Load') self.assert_(issubclass(load_plugin['plugin_cls'], Plugin)) self.assertIsNone(PluginRegister.get_plugin('Unknown'))
import re import socket from sauna.plugins import (Plugin, bytes_to_human, human_to_bytes, PluginRegister) my_plugin = PluginRegister('Memcached') @my_plugin.plugin() class Memcached(Plugin): def __init__(self, config): super().__init__(config) self.config = { 'host': config.get('host', 'localhost'), 'port': config.get('port', 11211), 'timeout': config.get('timeout', 5) } self._stats = None @my_plugin.check() def accepting_connections(self, check_config): try: accept_connections = self.stats['accepting_conns'] == 1 except OSError as e: return (Plugin.STATUS_CRIT, 'Memcached is not accepting connections: {}'.format(e)) if accept_connections: return Plugin.STATUS_OK, 'Memcached is accepting connections' else: return Plugin.STATUS_CRIT, 'Memcached is not accepting connections'
import time from datetime import timedelta import os from sauna.plugins import Plugin, PluginRegister my_plugin = PluginRegister('Ntpd') @my_plugin.plugin() class Ntpd(Plugin): def __init__(self, config): super().__init__(config) self.config = { 'stats_dir': config.get('stats_dir', '/var/log/ntpstats') } self._last_loop_stats = None @property def last_loop_stats(self): loopstats_file = os.path.join(self.config['stats_dir'], 'loopstats') if not self._last_loop_stats: with open(loopstats_file) as f: last_line_items = f.readlines()[-1].split() self._last_loop_stats = { 'timestamp': int(os.stat(loopstats_file).st_mtime), 'offset': float(last_line_items[2]) } return self._last_loop_stats @my_plugin.check()
from sauna.plugins import Plugin, human_to_bytes, bytes_to_human,\ PluginRegister my_plugin = PluginRegister('Disque') @my_plugin.plugin() class Disque(Plugin): def __init__(self, config): super().__init__(config) try: import redis self.redis = redis except ImportError: from ... import DependencyError raise DependencyError(self.__class__.__name__, 'redis-py', 'redis', 'python3-redis') self._disque_info = None @my_plugin.check() def used_memory(self, check_config): status = self._value_to_status_less(self.disque_info['used_memory'], check_config, human_to_bytes) output = 'Used memory: {}'.format( self.disque_info['used_memory_human']) return status, output @my_plugin.check() def used_memory_rss(self, check_config): status = self._value_to_status_less( self.disque_info['used_memory_rss'], check_config, human_to_bytes)
from sauna.plugins import Plugin, PluginRegister my_plugin = PluginRegister('MDStat') @my_plugin.plugin() class MDStat(Plugin): def __init__(self, config): super().__init__(config) try: import pymdstat self.pymdstat = pymdstat except ImportError: from ... import DependencyError raise DependencyError(self.__class__.__name__, 'pymdstat', 'pymdstat') self._md_stats = None @property def md_stats(self): if not self._md_stats: self._md_stats = self.pymdstat.MdStat().get_stats() return self._md_stats @my_plugin.check() def status(self, check_config): if not self.md_stats['arrays']: return self.STATUS_UNKNOWN, 'No RAID array detected' for array_name, array_infos in self.md_stats['arrays'].items(): if array_infos['status'] != 'active':
import time from datetime import timedelta from sauna.plugins import Plugin, PluginRegister my_plugin = PluginRegister('PuppetAgent') @my_plugin.plugin() class PuppetAgent(Plugin): def __init__(self, config): super().__init__(config) self.config = { 'summary_path': config.get('summary_path', '/var/lib/puppet/state/last_run_summary.yaml') } self._last_run_summary = None @property def last_run_summary(self): import yaml if not self._last_run_summary: with open(self.config['summary_path']) as f: self._last_run_summary = yaml.safe_load(f) return self._last_run_summary @my_plugin.check() def last_run_delta(self, check_config): current_time = int(time.time()) last_run_time = self.last_run_summary['time']['last_run']
from sauna.plugins import Plugin, human_to_bytes, bytes_to_human,\ PluginRegister my_plugin = PluginRegister('Redis') @my_plugin.plugin() class Redis(Plugin): def __init__(self, config): super().__init__(config) try: import redis self.redis = redis except ImportError: from ... import DependencyError raise DependencyError(self.__class__.__name__, 'redis-py', 'redis', 'python3-redis') self._redis_info = None @my_plugin.check() def used_memory(self, check_config): status = self._value_to_status_less(self.redis_info['used_memory'], check_config, human_to_bytes) output = 'Used memory: {}'.format(self.redis_info['used_memory_human']) return status, output @my_plugin.check() def used_memory_rss(self, check_config): status = self._value_to_status_less(self.redis_info['used_memory_rss'], check_config, human_to_bytes) output = 'Used memory RSS: {}'.format(
from sauna.plugins.base import PsutilPlugin from sauna.plugins import human_to_bytes, bytes_to_human, PluginRegister my_plugin = PluginRegister('Memory') @my_plugin.plugin() class Memory(PsutilPlugin): def __init__(self, config): super().__init__(config) self._virtual_memory = None self._swap_memory = None @my_plugin.check() def available(self, check_config): available = self.virtual_memory.available return (self._value_to_status_more(available, check_config, human_to_bytes), 'Memory available: {}'.format(bytes_to_human(available))) @my_plugin.check() def used_percent(self, check_config): used_percent = self.virtual_memory.percent check_config = self._strip_percent_sign_from_check_config(check_config) return (self._value_to_status_less(used_percent, check_config), 'Memory used: {}%'.format(used_percent)) @my_plugin.check() def swap_used_percent(self, check_config): swap_used_percent = self.swap_memory.percent check_config = self._strip_percent_sign_from_check_config(check_config)
import socket from sauna.plugins import Plugin, PluginRegister my_plugin = PluginRegister('SimpleDomain') @my_plugin.plugin() class SimpleDomain(Plugin): @my_plugin.check() def request(self, check_config): domain = check_config.get('domain') if check_config.get('ip_version') == 6: af = socket.AF_INET6 elif check_config.get('ip_version') == 4: af = socket.AF_INET else: af = 0 try: result = socket.getaddrinfo(domain, 0, af) except Exception as e: return Plugin.STATUS_CRIT, '{}'.format(e) ips = [ip[4][0] for ip in result] return ( Plugin.STATUS_OK, 'Domain was resolved with {}'.format(', '.join(ips)) )
import re from sauna.plugins import PluginRegister from sauna.plugins.base import PsutilPlugin my_plugin = PluginRegister('Processes') @my_plugin.plugin() class Processes(PsutilPlugin): @my_plugin.check() def count(self, check_config): num_pids = len(self.psutil.pids()) return (self._value_to_status_less(num_pids, check_config), '{} processes'.format(num_pids)) @my_plugin.check() def zombies(self, check_config): zombies = [ p for p in self.psutil.process_iter() if p.status() == 'zombie' ] num_zombies = len(zombies) return (self._value_to_status_less(num_zombies, check_config), '{} zombies'.format(num_zombies)) def _count_running_processes(self, check_config): """Count the number of times a process is running. Processes are identified by their first argument 'exec' and additional 'args'. :rtype int
import socket import re import subprocess from sauna.plugins import Plugin from sauna.plugins import PluginRegister my_plugin = PluginRegister('Postfix') @my_plugin.plugin() class Postfix(Plugin): def __init__(self, config): super().__init__(config) self.config = { 'host': config.get('host', 'localhost'), 'port': config.get('port', 4280), 'timeout': config.get('timeout', 5), 'method': config.get('method', 'mailq') } self._mailq_output = None @my_plugin.check() def queue_size(self, check_config): queue_size = self._get_queue_size() return (self._value_to_status_less(queue_size, check_config), '{} mail(s) in queue'.format(queue_size)) @property def mailq_output(self): if not self._mailq_output:
from sauna.plugins import Plugin, PluginRegister from sauna.plugins.ext.http import HTTP from sauna import DependencyError import re import json my_plugin = PluginRegister('HTTP-JSON') @my_plugin.plugin() class HTTPJSON(HTTP): def __init__(self, config): super().__init__(config) try: import jsonpath_rw as jsonpath self.jsonpath = jsonpath except ImportError: raise DependencyError(self.__class__.__name__, 'jsonpath_rw', pypi='jsonpath-rw') @my_plugin.check() def request(self, check_config): code = check_config.get('code', 200) expect = check_config.get('expect', None) try: r = self._do_http_request(check_config) except Exception as e: return Plugin.STATUS_CRIT, '{}'.format(e)
import xmlrpc.client import http.client import socket from sauna.plugins import Plugin, PluginRegister my_plugin = PluginRegister('Supervisor') @my_plugin.plugin() class Supervisor(Plugin): def __init__(self, config): super().__init__(config) serverurl = config.get('serverurl', 'unix:///var/run/supervisor.sock') timeout = config.get('timeout', 5) if serverurl.startswith('unix://'): serverurl = serverurl.replace('unix://', '', 1) # xmlrpc.client does not support Unix sockets, so we must provide # a custom transport layer transport = UnixStreamTransport(serverurl, timeout=timeout) server = xmlrpc.client.ServerProxy('http://noop', transport=transport) else: transport = CustomHTTPTransport(timeout=timeout) server = xmlrpc.client.ServerProxy(serverurl, transport=transport) rpc_namespace = config.get('rpc_namespace', 'supervisor') self.supervisor = getattr(server, rpc_namespace) self.supervisor_addr = serverurl
import os from sauna.plugins import Plugin from sauna.plugins import PluginRegister my_plugin = PluginRegister('Load') @my_plugin.plugin() class Load(Plugin): def __init__(self, config): super().__init__(config) self._load = None @my_plugin.check() def load1(self, check_config): return (self._value_to_status_less(self.load[0], check_config), 'Load 1: {}'.format(self.load[0])) @my_plugin.check() def load5(self, check_config): return (self._value_to_status_less(self.load[1], check_config), 'Load 5: {}'.format(self.load[1])) @my_plugin.check() def load15(self, check_config): return (self._value_to_status_less(self.load[2], check_config), 'Load 15: {}'.format(self.load[2])) @property def load(self):
import os import glob from collections import namedtuple from functools import reduce from sauna.plugins import Plugin, PluginRegister Sensor = namedtuple('Sensor', ['device_name', 'label', 'value']) my_plugin = PluginRegister('Hwmon') @my_plugin.plugin() class Hwmon(Plugin): """Linux hardware monitoring plugin. This plugin crawls Linux's /sys/class/hwmon to find usable sensors. Be warned that this method is quite fragile since exotic hardware may present values that need offsets or conversions. A more solid approach could be to use lm-sensors, but: - it requires to install and configure lm-sensors - there is no proper python bindings to the library - parsing the output of 'sensors' is not fun nor efficient """ @my_plugin.check() def temperature(self, check_config): dummy_sensor = Sensor(device_name='Dummy', label='Dummy', value=-1000) sensors = self._get_temperatures() if check_config.get('sensors'): sensors = [
import socket from sauna.plugins import (Plugin, PluginRegister) my_plugin = PluginRegister('TCP') @my_plugin.plugin() class Tcp(Plugin): @my_plugin.check() def request(self, check_config): try: with socket.create_connection( (check_config['host'], check_config['port']), timeout=check_config['timeout']): pass except Exception as e: return Plugin.STATUS_CRIT, "{}".format(e) else: return Plugin.STATUS_OK, "OK" @staticmethod def config_sample(): return ''' # Tcp - type: TCP checks: - type: request host: localhost port: 11211 timeout: 5
from functools import lru_cache import time from sauna.plugins.base import PsutilPlugin from sauna.plugins import human_to_bytes, bytes_to_human, PluginRegister my_plugin = PluginRegister('Network') @my_plugin.plugin() class Network(PsutilPlugin): def __init__(self, config): super().__init__(config) @my_plugin.check() def upload_data_speed(self, check_config): ul, _, _, _ = self.get_network_data( interface=check_config['interface']) ul = round(ul, 2) return (self._value_to_status_less(ul, check_config, human_to_bytes), 'Upload speed: {}/s'.format(bytes_to_human(ul))) @my_plugin.check() def download_data_speed(self, check_config): _, dl, _, _ = self.get_network_data( interface=check_config['interface']) dl = round(dl, 2) return (self._value_to_status_less(dl, check_config, human_to_bytes), 'Download speed: {}/s'.format(bytes_to_human(dl)))