# # Copyright (C) 2019 Marko Myllynen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # """PCP netcheck PMDA packet loss module""" # pylint: disable=too-many-arguments,too-many-positional-arguments # pylint: disable=invalid-name import sys from re import search from subprocess import Popen, PIPE from pcp.pmapi import pmUnits from cpmapi import PM_TYPE_32, PM_SEM_INSTANT from modules.pcpnetcheck import PCPNetcheckModuleBase # Module constants MODULE = 'ping_loss' BASENS = 'ping.' units_none = pmUnits(0, 0, 0, 0, 0, 0) class PCPNetcheckModule(PCPNetcheckModuleBase): # pylint: disable=too-many-arguments """PCP netcheck packet loss module""" def __init__(self, config, dbg, log, err, params): """Constructor""" PCPNetcheckModuleBase.__init__(self, MODULE, config, dbg, log, err, params) self.command = 'ping' self.cmdargs = '' self.count = 5 self.timeout = 2.0 self.prereq_check(self.command) for opt in self.config.options(MODULE): if opt == 'command': self.command = self.config.get(MODULE, opt) elif opt == 'cmdargs': self.cmdargs = self.config.get(MODULE, opt) elif opt == 'count': self.count = int(self.config.get(MODULE, opt)) self.assert_positive(opt, self.count) elif opt not in self.common_opts: self.err("Invalid directive '%s' in %s, aborting." % (opt, MODULE)) sys.exit(1) self.log("Module parameters: command: %s, cmdargs: %s, count: %s, timeout: %s." % (self.command, self.cmdargs, self.count, self.timeout)) self.log("Initialized.") @staticmethod def prereq_check(command): """Check module prerequisities""" try: cmd = [command, '-c', '1', '-W', '1', 'localhost'] proc = Popen(cmd, stdout=PIPE, stderr=PIPE) proc.communicate() if proc.returncode: raise RuntimeError("Can't ping the loopback interface!") except OSError: # pylint: disable=broad-except raise RuntimeError("Can't run the " + command + "(1) command!") def metrics(self): """Get metric definitions""" self.items = ( # Name - reserved - type - semantics - units - help (BASENS + 'loss', None, PM_TYPE_32, PM_SEM_INSTANT, units_none, 'ping packet loss percent'), ) return True, self.items def do_check(self): """Do net check""" cmd_template = [self.command, '-c', str(self.count), '-W', str(self.timeout)] if self.cmdargs != '': cmd_template.append(self.cmdargs) cmd_template.append(self.HOST_TMPL_STR) self.log_command_once(cmd_template) outputs = self._run_check_commands(cmd_template)[0] for host in self.hosts: try: self.hosts[host] = \ int(search(r'\d+% ', outputs[host][0].decode('UTF-8')).group(0)[:-2]) except Exception: # pylint: disable=broad-except self.hosts[host] = -2