Plugin module

Plugin

class naghelp.plugin.Plugin

Plugin base class

This is an abstract class used with ActivePlugin, it brings :

  • plugin search in a directory of python files
  • plugin instance generation
  • plugin logging management
  • plugin command line options management
  • plugin persistent data management

This abstract class should be used later with naghelp.PassivePlugin when developed.

add_cmd_options()

This method can be customized to add some OptionParser options for the current plugin

Example:

self._cmd_parser.add_option('-z', action='store_true', dest='super_debug',
                           default=False, help='Activate the super debug mode')
add_logger_console_handler()

Activate logging to the console

add_logger_file_handler()

Activate logging to the log file

classmethod debug(msg, *args, **kwargs)

log a debug message

Parameters:
  • msg (str) – the message to log
  • args (list) – if additional arguments are given, msg will be formatted with % (old-style python string formatting)

Examples

This logs a debug message in log file and/or console:

p = Plugin()
p.debug('my_variable = %s',my_variable)
classmethod error(msg, *args, **kwargs)

log an error message

Parameters:
  • msg (str) – the message to log
  • args (list) – if additional arguments are given, msg will be formatted with % (old-style python string formatting)

Examples

This logs an error message in log file and/or console:

p = Plugin()
p.error('Syntax error in line %s',36)
classmethod find_plugins()

Recursively find all plugin classes for all python files present in a directory.

It finds all python files inside YourPluginsBaseClass.plugins_basedir then look for all classes having the attribute plugin_type with the value YourPluginsBaseClass.plugin_type

It returns a dictionary where keys are plugin class name in lower case and the values are a dictionary containing :

Keys Values
name the class name (case sensitive)
module the plugin module name with a full dotted path
path the module file path
desc the plugin description (first docstring line)
classmethod find_plugins_import_errors()

Find all import errors all python files present in a directory.

It finds all python files inside YourPluginsBaseClass.plugins_basedir and try to import them. If an error occurs, the file path and linked exception is memorized.

It returns a list of tuples containing the file path and the exception.

found_plugins = {}

Plugins discovered during find_plugins() method

get_cmd_usage()

Returns the command line usage

classmethod get_instance(plugin_name, **extra_options)

Generate a plugin instance from its name string

This method is useful when you only know at execution time the name of the plugin to instantiate.

If you have an active plugin class called HpProliant in a file located at /home/me/myplugin_dir/hp/hp_proliant.py then you can get the plugin instance this way :

For all your plugins, you should first subclass the ActivePlugin to override plugins_basedir:

class MyProjectActivePlugin(ActivePlugin):
    plugins_basedir = '/home/me/myplugin_dir'
    plugin_type = 'myproject_plugin'  # you choose whatever you want but not 'plugin'

class HpProliant(MyProjectActivePlugin):
    ''' My code '''

Check that /home/me/myplugin_dir is in your python path.

Then you can get an instance by giving only the class name (case insensitive):

plugin = MyProjectActivePlugin.get_instance('hpproliant')

Or with the full doted path (case sensitive this time):

plugin = MyProjectActivePlugin.get_instance('hp.hp_proliant.HpProliant')

In first case, it is shorter but a recursive search will occur to find the class in all python files located in /home/me/myplugin_dir/. It is mainly useful in python interactive console.

In second case, as you specified the full path, the class is found at once : it is faster and should be used in production.

Once the class is found, an instance is created and returned.

Of course, if you do not need to get an instance from a string : it is more pythonic to do like this:

from hp.hp_proliant import HpProliant
plugin = HpProliant()
get_logger_console_level()

gets logger level specific for the console output.

Note : This is possible to set different logger level between log file and console

get_logger_file_level()

gets logger level specific for log file output.

Note : This is possible to set different logger level between log file and console

get_logger_file_logfile()

get log file path

get_logger_format()

gets logger format, by default the one defined in logger_format attribute

get_logger_level()

gets logger level. By default sets to logging.ERROR to get only errors

classmethod get_plugin(plugin_name)

find a plugin and return its module and its class name

To get the class itself, one have to get the corresponding module’s attribute:

module,class_name = MyProjectActivePlugin.get_plugin('hpproliant')
plugin_class = getattr(module,class_name,None)
Parameters:plugin_name (str) – the plugin name to find (case insensitive)
Returns:A tuple containing the plugin’s module and plugin’s class name
Return type:module, str
classmethod get_plugin_class(plugin_name)

get the plugin class from its name

If the dotted notation is used, the string is case sensitive and the corresponding module is loaded at once, otherwise the plugin name is case insensitive and a recursive file search is done from the directory plugin_class.plugins_basedir

Parameters:plugin_name (str) – the plugin name to find.
Returns:plugin’s class object or None if not found.
Return type:class object or None

You can get plugin class object by giving only the class name (case insensitive):

plugin_class = MyProjectActivePlugin.get_plugin_class('hpproliant')

Or with the full dotted path (case sensitive this time):

plugin_class = MyProjectActivePlugin.get_plugin_class('hp.hp_proliant.HpProliant')

If you need a plugin instance, prefer using get_instance()

classmethod get_plugin_desc()

Returns the plugin description. By default return the class docstring.

handle_cmd_options()

Parse command line options

The parsed options are stored in self.options and arguments in self.args

classmethod info(msg, *args, **kwargs)

log an informational message

Parameters:
  • msg (str) – the message to log
  • args (list) – if additional arguments are given, msg will be formatted with % (old-style python string formatting)

Examples

This logs an informational message in log file and/or console:

p = Plugin()
p.info('Date : %s',datetime.now())
init_cmd_options()

Create OptionParser instance and add some basic options

This is automatically called when the plugin is run. Avoid to override this method, prefer to customize add_cmd_options()

init_logger()

Initialize logging

classmethod load_data(filename)

Load and de-serialize data from a file

The input file must be a json file.

Parameters:filename (str) – The file path to load.
Returns:The restored data or NoAttr on error.
Return type:textops.DictExt

Examples

>>> open('/tmp/mydata','w').write('''{
...   "powers": {
...     "1": "OK",
...     "2": "Degraded",
...     "3": "OK",
...     "4": "Failed"
...   },
...   "nb_disks": 36
... }''')
>>> data = ActivePlugin.load_data('/tmp/mydata')
>>> print data
{u'powers': {u'1': u'OK', u'3': u'OK', u'2': u'Degraded', u'4': u'Failed'}, u'nb_disks': 36}
>>> print type(data)
<class 'textops.base.DictExt'>

See save_data() to know how /tmp/mydata has been generated.

logger_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

The logging format to use

logger_logbackup = 5

Log file backup file number

logger_logsize = 1000000

Log file max size

manage_cmd_options()

Manage commande line options

OptionParser instance is created, options are added, then command line is parsed.

plugin_type = 'plugin'

For plugin search, it will search for classes having this attribute in all python files

plugins_basedir = '/path/to/your/plugins/python/modules'

For plugin search, it will search recursively from this directory

plugins_basemodule = 'plugins.python.'

For plugin search, the module prefix to add to have the module accessible from python path. Do not forget the ending dot. You can set empty if your plugin modules are in python path.

Note

Do not forget to put empty __init__.py file in each directory leading to your plugins.

classmethod save_data(filename, data, ignore_error=True)

Serialize and save data into a file

The data must be a dictionary where values must be simple types : str, int, float, date, list and/or dict. The data are serialized into json format.

Parameters:
  • filename (str) – The file path to store the data. The directories are created if not present.
  • data (dict) – The dictionary to save.
  • ignore_error (bool) – ignore errors if True (Default: True)

Notes

The data dictionary keys must be strings. If you specify integers, they will be replaced by a string.

Examples

>>> data={'powers': {1:'OK', 2:'Degraded',3:'OK', 4:'Failed'}, 'nb_disks': 36 }
>>> ActivePlugin.save_data('/tmp/mydata',data)
>>> print open('/tmp/mydata').read()  
{
    "powers": {
        "1": "OK",
        "2": "Degraded",
        "3": "OK",
        "4": "Failed"
    },
    "nb_disks": 36
}
classmethod warning(msg, *args, **kwargs)

log a warning message

Parameters:
  • msg (str) – the message to log
  • args (list) – if additional arguments are given, msg will be formatted with % (old-style python string formatting)

Examples

This logs an warning message in log file and/or console:

p = Plugin()
p.warning('This variable is not used in line %s',36)

ActivePlugin

class naghelp.ActivePlugin(**extra_options)

Python base class for active nagios plugins

This is the base class for developping Active Nagios plugin with the naghelp module

build_response(data)

Build a response

This method should be overridden when developing a new plugin. You must use data dictionary to decide what alerts and/or informations to send to Nagios. To do so, a PluginResponse object has already been initialized by the framework and is available at self.response : you just have to use add* methods. It is highly recommended to call the super/parent build_response() at the end to easily take advantage of optional mixins like naghelp.GaugeMixin.

Parameters:data (textops.DictExt) – the data dictionary where are collected and parsed data

Example

After getting a raw syslog output, we extract warnings and critical errors:

def build_response(self,data):
    self.response.add_list(WARNING,data.warnings)
    self.response.add_list(CRITICAL,data.criticals)
    ...
    super(MyPluginClass,self).build_response(data)

See parse_data() and collect_data() examples to see how data has been updated.

check_host_required_fields()

Checks host required fields

This checks the presence of values for host parameters specified in attribute required_params. If this attribute is empty, all parameters specified in attribute cmd_params will be considerated as required. The method will also check that either name or ip parameter value is present.

check_ports()

Checks port

This method is called when an error occurs while collecting data from host : It will check whether the tcp ports are reachable or not. If not, the plugin exits with a fast response.

cmd_params = ''

Attribute that must contain a list of all possible Host parameters for the current plugin

This will automatically add options to the optparse.OptionParser object. This means that the given parameters can be set at command line (use ‘-h’ for plugin help to see them appear). This also ask naghelp to get parameters from environment variable or an optional database if available. Once the parameters value found, naghelp will store them into the host object at the same index. For example, if plugin.cmd_params = 'user,passwd' then parameters values will be available at self.host.user and self.host.passwd inside the definition of collect_data().

It is highly recommended to use the following parameters name as their description has been already defined by the method get_plugin_host_params_tab() :

NAME DESCRIPTION
name Hostname
ip Host IP address
subtype Plugin subtype (usually host model)
user User
passwd Password
console_ip Console or controller IP address
snmpversion SNMP protocal version (1,2 or 3)
community SNMP community
community_alt SNMP community for other device
authpp SNMP authentification passphrase
authproto SNMP authentification protocal (md5 or sha)
privpp SNMP privacy passphrase
privproto SNMP privacy protocal (des or aes)
protocol ssh or telnet
port Port number
collect_cmd_timeout Maximum time allowed for one collect command
collect_all_timeout Maximum time allowed for the whole collect process
maxwarn Gauge max value for a warning status
maxcrit Gauge max value for a critical status
minwarn Gauge min value for a warning status
mincrit Gauge min value for a critical status
options Additionnal options

Note that name and ip are hard coded : you must use them for Nagios hostname and hostaddress. The same for subtype, protocol and port that are hard coded for port testing.

The parameter list can be a python list or a coma separated string.

You can force all your plugin to have some default parameters (like ‘name’ and ‘ip’) : to do so, use the plugin attribute forced_params.

Note

Do not include the parameters that are not Host related (like plugin debug mode flag, verbose mode flag, plugin description flag etc…). These parameters are already checked by optparse.OptionParser and do not need to get their value from environment variables or a database.

collect_data(data)

Collect data from monitored host

This method should be overridden when developing a new plugin. One should use naghelp.collect module to retrieve raw data from monitored equipment. Do not parse raw data in this method : see parse_data(). Note that no data is returned : one just have to modify data with a dotted notation.

Parameters:data (textops.DictExt) – the data dictionary to write collected raw data to.

Example

Here we execute the command dmesg on a remote host via SSH to get last logs:

def collect_data(self,data):
    data.syslog = Ssh(self.host.ip,self.host.user,self.host.passwd).run('dmesg')

See parse_data() example to see how data has been parsed. See build_response() example to see how data will be used.

collected_data_filename_pattern = '/tmp/naghelp/%s_collected_data.json'

Attribute giving the pattern for the persistent data file path. %s will be replaced by the monitored host name (or IP if host name not specified)

data

The place to put collected and parsed data

As data is a textops.DictExt object, one can use the dotted notation for reading and for writing.

default_level = OK

Attribute giving the response level to return if no level has been set.

By default, naghelp consider that if no level message has been added to the response, there is no errors and return the OK level to Nagios.

In some situation, one may prefer to send an UKNOWN state by default.

do_feature()

Run the appropriate feature depending on the options given

do_monitoring()

Run the monitoring feature of the plugin

It will take care of everything in that order :

  1. Collect monitoring informations with collect_data()
  2. Check ports if an error occured while collecting data
  3. Parse collected data with parse_data()
  4. Build a response with build_response()
  5. Save persistent data (save the host object to a json file)
  6. Add plugin information at the response ending
  7. Send the response (render the response to stdout and exit the plugin with appropriate exit code)
doctest_begin()

For doctest usage only

doctest_end()

For doctest usage only

error(msg, sublevel=3, exception=None, *args, **kwargs)

Log an error and exit the plugin

Not only it logs an error to console and/or log file, it also send a fast response that will exit the plugin. If the exception that has generated the error is not derived from CollectError, A stack and available data are also dumped.

Parameters:
  • msg (str) – Message body. Note that it adds a begin message (not a message level).
  • sublevel (int) – The message sublevel (displayed into plugin information section)
  • exception (Exception) – The exception that is the error’s origin (Optional).
fast_response(level, synopsis, msg='', sublevel=1)

Exit the plugin at once by sending a basic message level to Nagios

This is used mainly on errors : the goal is to avoid the plugin to go any further.

Parameters:
  • level (ResponseLevel) – Response level to give to Nagios
  • synopsis (str) – Response title
  • msg (str) – Message body. Note that it adds a begin message (not a message level).
  • sublevel (int) – The message sublevel (displayed into plugin information section)
fast_response_if(test, level, synopsis, msg='', sublevel=1)

If test is True, exit the plugin at once by sending a basic message level to Nagios

This works like fast_response() except that it exits only if test is True.

Parameters:
  • test (bool) – Must be True to send response and exit plugin.
  • level (ResponseLevel) – Response level to give to Nagios
  • synopsis (str) – Response title
  • msg (str) – Message body. Note that it adds a begin message (not a message level).
  • sublevel (int) – The message sublevel (displayed into plugin information section)
forced_params = 'name,ip,collect_cmd_timeout,collect_all_timeout'

Attribute you can set to force all your plugins to have some default Host parameters. These parameters are automatically added to the plugin attribute cmd_params.

Default is 'name,ip' because all the monitored equipments must have a Nagios name and an IP.

get_plugin_host_params_desc()

Builds a dictionary giving description of plugin host parameters

This merges cmd_params and forced_params paramters and returns their description

get_plugin_host_params_tab()

Returns a dictionary of Host parameters description

This dictionary helps naghelp to build the plugin help (-h option in command line).

It is highly recommended to use, in the attribute cmd_params, only keys from this dictionary. If it is not the case, a pseudo-description will be calculated when needed.

If you want to create specific parameters, add them in the dictionary with their description by overriding this method in a subclass.

get_plugin_informations()

Get plugin informations

This method builds a text giving some informations about the plugin, it will be placed at the end of the plugin response.

Example

Here an output:

>>> p = ActivePlugin()
>>> print p.get_plugin_informations() 

============================[ Plugin Informations ]=============================
Plugin name : naghelp.plugin.ActivePlugin
Description : Python base class for active nagios plugins
Execution date : ...
Execution time : ...
Ports used : tcp = none, udp = none
Exit code : 0 (OK), __sublevel__=0
get_tcp_ports()

Returns tcp ports

Manages port and protocol host parameters if defined

get_udp_ports()

Returns udp ports

Manages port host parameter if defined

handle_cmd_options()

Parse command line options

The parsed options are stored in plugin.options and arguments in plugin.args

If the user requests plugin description, it is displayed and the plugin exited with UNKOWN response level.

You should customize this method if you want to check some options before running the plugin main part.

host

This will contain the Host object. not that it is devrived from a dict.

host_class

alias of naghelp.host.Host

init_cmd_options()

Initialize command line options

This create optparse.OptionParser instance and add some basic options

It also add options corresponding to Host parameters. The host parameters will be stored first into OptionParse’s options object (plugin.options), later it is set to host object.

This method is automatically called when the plugin is run. Avoid to override this method, prefer to customize add_cmd_options()

nagios_status_on_error = CRITICAL

Attribute giving the ResponseLevel to return to Nagios on error.

options

Attribute that contains the command line options as parsed by optparse.OptionParser

parse_data(data)

Parse data

This method should be overridden when developing a new plugin. When raw data are not usable at once, one should parse them to structure the informations. parse_data() will get the data dictionary updated by collect_data(). One should then use python-textops to parse the data. There is no data to return : one just have to modify data with a dotted notation.

Parameters:data (textops.DictExt) – the data dictionary to read collected raw data and write parsed data.

Example

After getting a raw syslog output, we extract warnings and critical errors:

def parse_data(self,data):
    data.warnings  = data.syslog.grepi('EMS Event Notification').grep('MAJORWARNING|SERIOUS')
    data.criticals = data.syslog.grepi('EMS Event Notification').grep('CRITICAL')

See collect_data() example to see how data has been updated. See build_response() example to see how data will be used.

Note

The data dictionary is the same for collected data and parsed data, so do not use already existing keys for collected data to store new parsed data.

plugin_type = 'active'

Attribute for the plugin type

This is used during plugin recursive search : should be the same string accross all your plugins

required_params = None

Attribute that contains the list of parameters required for the Host object

For example, if your plugin need to connect to a host that requires a password, you must add ‘passwd’ in the list. The list of possible Host parameters you can add should be keys of the dictionary returned by the method get_plugin_host_params_tab().

At execution time, naghelp will automatically check the required parameters presence : they could come from command line option, environment variable or a database (see naghelp.Host).

The parameter list can be a python list or a coma separated string. If the list is None (by default), this means that all parameters from attribute cmd_params are required.

response_class

alias of naghelp.response.PluginResponse

restore_collected_data()

Restore collected data

During development and testing, it may boring to wait the data to be collected : The idea is to save them once, and then use them many times : This is useful when developing parse_data() and build_response()

This method is called when using -r option on command line.

run()

Run the plugin with options given in command line, database or plugin initial extra_options

It will take care of everything in that order :

  1. Manage command line options (uses cmd_params)
  2. Create the Host object (store it in attribute host)
  3. Activate logging (if asked in command line options with -v or -d)
  4. Load persistent data into host
  5. call do_feature() method
  6. save host persistent data
save_collected_data()

Save collected data

During development and testing, it may boring to wait the data to be collected : The idea is to save them once, and then use them many times : This is useful when developing parse_data() and build_response()

This method is called when using -s option on command line.

save_host_data()

Save data before sending the built response

tcp_ports = ''

Attribute that lists the tcp_ports used by the plugin

naghelp will check specified ports if a problem is detected while collecting data from host. naghelp also use this attribute in plugin summary to help administrator to configure their firewall.

The attribute is ignored if the plugin uses the protocol or port parameters.

The ports list can be a python list or a coma separated string.

udp_ports = ''

Attribute that lists the udp_ports used by the plugin

naghelp uses this attribute in plugin summary to help administrator to configure their firewall.

The attribute is ignored if the plugin uses the protocol or port parameters.

The ports list can be a python list or a coma separated string.

usage = 'usage: \n%prog [options]'

Attribute for the command line usage

warning(msg, *args, **kwargs)

Log a warning and add a warning message level

Not only it logs a warning to console and/or log file, it also add a warning in response’s message level section

Parameters:msg (str) – The message to log and add.