Utils Package

Utils Package

Misc utility classes and helper functions for pynag

This module contains misc classes and conveninence functions that are used throughout the pynag library.

class pynag.Utils.AttributeList(value=None)

Bases: object

Parse a list of nagios attributes into a parsable format. (e. contact_groups)

This makes it handy to mangle with nagios attribute values that are in a comma seperated format.

Typical comma-seperated format in nagios configuration files looks something like this:

contact_groups     +group1,group2,group3

Example:

>>> i = AttributeList('+group1,group2,group3')
>>> i.operator
'+'
>>> i.fields
['group1', 'group2', 'group3']

# if your data is already in a list format you can use it directly:
>>> i = AttributeList(['group1', 'group2', 'group3'])
>>> i.fields
['group1', 'group2', 'group3']

# white spaces will be stripped from all fields
>>> i = AttributeList('+group1, group2')
>>> i
+group1,group2
>>> i.fields
['group1', 'group2']
append(object)

Same as list.append():

Args:

object: Item to append into self.fields (typically a string)

Example:

>>> i = AttributeList('group1,group2,group3')
>>> i.append('group5')
>>> i.fields
['group1', 'group2', 'group3', 'group5']
count(value)

Same as list.count()

Args:
value: Any object that might exist in self.fields (string)
Returns:
The number of occurances that ‘value’ has in self.fields
Example:
>>> i = AttributeList('group1,group2,group3')
>>> i.count('group3')
1
extend(iterable)

Same as list.extend()

Args:
iterable: Any iterable that list.extend() supports
Example:
>>> i = AttributeList('group1,group2,group3')
>>> i.extend(['group4', 'group5'])
>>> i.fields
['group1', 'group2', 'group3', 'group4', 'group5']
index(value, start=0, stop=None)

Same as list.index()

Args:

value: object to look for in self.fields

start: start at this index point

stop: stop at this index point

Returns:
The index of ‘value’ (integer)
Examples:
>>> i = AttributeList('group1,group2,group3')
>>> i.index('group2')
1
>>> i.index('group3', 2, 5)
2
insert(index, object)

Same as list.insert()

Args:

object: Any object that will be inserted into self.fields (usually a string)

Example:

>>> i = AttributeList('group1,group2,group3')
>>> i.insert(1, 'group4')
>>> i.fields
['group1', 'group4', 'group2', 'group3']
remove(value)

Same as list.remove()

Args:
value: The object that is to be removed
Examples:
>>> i = AttributeList('group1,group2,group3')
>>> i.remove('group3')
>>> i.fields
['group1', 'group2']
reverse()

Same as list.reverse()

Examples:
>>> i = AttributeList('group1,group2,group3')
>>> i.reverse()
>>> i.fields
['group3', 'group2', 'group1']
sort()

Same as list.sort()

Examples:
>>> i = AttributeList('group3,group1,group2')
>>> i.sort()
>>> print(i.fields)
['group1', 'group2', 'group3']
class pynag.Utils.GitRepo(directory, auto_init=True, author_name='Pynag User', author_email=None)

Bases: object

add(filename)

Run git add on filename

Args:
filename (str): name of one file to add,
Returns:
str. The stdout from “git add” shell command.
commit(message='commited by pynag', filelist=None, author=None)

Commit files with “git commit”

Args:

message (str): Message used for the git commit

filelist (list of strings): List of filenames to commit (if None, then commit all files in the repo)

author (str): Author to use for git commit. If any is specified, overwrite self.author_name and self.author_email

Returns:
stdout from the “git commit” shell command.
diff(commit_id_or_filename=None)

Returns diff (as outputted by “git diff”) for filename or commit id.

If commit_id_or_filename is not specified. show diff against all uncommited files.

Args:
commit_id_or_filename (str): git commit id or file to diff with
Returns:
str. git diff for filename or commit id
Raises:
PynagError: Invalid commit id or filename was given
get_uncommited_files()

Returns a list of files that are have unstaged changes

Returns:
List. All files that have unstaged changes.
get_valid_commits()

Returns a list of all commit ids from git log

Returns:
List of all valid commit hashes
init()

Initilizes a new git repo (i.e. run “git init”)

is_dirty(filename)

Returns True if filename needs to be committed to git

Args:

filename (str): file to check
is_up_to_date()

Returns True if all files in git repo are fully commited

Returns:
bool. Git repo is up-to-date

True – All files are commited

False – At least one file is not commited

log(**kwargs)

Returns a log of previous commits. Log is is a list of dict objects.

Any arguments provided will be passed directly to pynag.Utils.grep() to filter the results.

Args:
kwargs: Arguments passed to pynag.Utils.grep()
Returns:
List of dicts. Log of previous commits.
Examples:

self.log(author_name=’nagiosadmin’)

self.log(comment__contains=’localhost’)

pre_save(object_definition, message)

Commits object_definition.get_filename() if it has any changes.

This function is called by pynag.Model.EventHandlers before calling pynag.Utils.GitRepo.save()

Args:

object_definition (pynag.Model.ObjectDefinition): object to commit changes

message (str): git commit message as specified in git commit -m

A message from the authors:
“Since this is still here, either i forgot to remove it, or because it is here for backwards compatibility, palli”
revert(commit)

Revert some existing commits works like “git revert”

save(object_definition, message)

Commits object_definition.get_filename() if it has any changes. This function is called by pynag.Model.EventHandlers

Args:

object_definition (pynag.Model.ObjectDefinition): object to commit changes

message (str): git commit message as specified in git commit -m

show(commit_id)

Returns output from “git show” for a specified commit_id

Args:
commit_id (str): Commit id of the commit to display (git show)
Returns:
str. Output of git show commit_id
Raises:
PynagError: Invalid commit_id was given
write(object_definition, message)

This method is called whenever pynag.Model.EventHandlers is called.

Args:

object_definition (pynag.Model.ObjectDefinition): Object to write to file.

message (str): git commit message as specified in git commit -m

class pynag.Utils.PerfData(perfdatastring='')

Bases: object

Data Structure for a nagios perfdata string with multiple perfdata metric

Example string:

>>> perf = PerfData("load1=10 load2=10 load3=20 'label with spaces'=5")
>>> perf.metrics
['load1'=10;;;;, 'load2'=10;;;;, 'load3'=20;;;;, 'label with spaces'=5;;;;]
>>> for i in perf.metrics: print("%s %s" % (i.label, i.value))
load1 10
load2 10
load3 20
label with spaces 5
add_perfdatametric(perfdatastring='', label='', value='', warn='', crit='', min='', max='', uom='')

Add a new perfdatametric to existing list of metrics.

Args:

perfdatastring (str): Complete perfdata string

label (str): Label section of the perfdata string

value (str): Value section of the perfdata string

warn (str): WARNING threshold

crit (str): CRITICAL threshold

min (str): Minimal value of control

max (str): Maximal value of control

uom (str): Measure unit (octets, bits/s, volts, ...)

Example:

>>> s = PerfData()
>>> s.add_perfdatametric("a=1")
>>> s.add_perfdatametric(label="utilization",value="10",uom="%")
get_perfdatametric(metric_name)

Get one specific perfdatametric

Args:
metric_name (str): Name of the metric to return

Example:

>>> s = PerfData("cpu=90% memory=50% disk_usage=20%")
>>> my_metric = s.get_perfdatametric('cpu')
>>> my_metric.label, my_metric.value
('cpu', '90')
is_valid()

Returns True if the every metric in the string is valid

Example usage:

>>> PerfData("load1=10 load2=10 load3=20").is_valid()
True
>>> PerfData("10b").is_valid()
False
>>> PerfData("load1=").is_valid()
False
>>> PerfData("load1=10 10").is_valid()
False
reconsile_thresholds()

Convert all thresholds in new_threshold_syntax to the standard one

class pynag.Utils.PerfDataMetric(perfdatastring='', label='', value='', warn='', crit='', min='', max='', uom='')

Bases: object

Data structure for one single Nagios Perfdata Metric

Attributes:

perfdatastring (str): Complete perfdata string

label (str): Label section of the perfdata string

value (str): Value section of the perfdata string

warn (str): WARNING threshold

crit (str): CRITICAL threshold

min (str): Minimal value of control

max (str): Maximal value of control

uom (str): Measure unit (octets, bits/s, volts, ...)

crit = ''
get_dict()

Returns a dictionary which contains this class’ attributes.

Returned dict example:

{
    'label': self.label,
    'value': self.value,
    'uom': self.uom,
    'warn': self.warn,
    'crit': self.crit,
    'min': self.min,
    'max': self.max,
}
get_status()

Return nagios-style exit code (int 0-3) by comparing

Example:

self.value with self.warn and self.crit

>>> PerfDataMetric("label1=10;20;30").get_status()
0
>>> PerfDataMetric("label2=25;20;30").get_status()
1
>>> PerfDataMetric("label3=35;20;30").get_status()
2

Invalid metrics always return unknown

>>> PerfDataMetric("label3=35;invalid_metric").get_status()
3
is_valid()

Returns True if all Performance data is valid. Otherwise False

Example Usage:

>>> PerfDataMetric("load1=2").is_valid()
True
>>> PerfDataMetric("load1").is_valid()
False
>>> PerfDataMetric('').is_valid()
False
>>> PerfDataMetric('invalid_value=invalid').is_valid()
False
>>> PerfDataMetric('invalid_min=0;0;0;min;0').is_valid()
False
>>> PerfDataMetric('invalid_min=0;0;0;0;max').is_valid()
False
>>> PerfDataMetric('label with spaces=0').is_valid()
False
>>> PerfDataMetric("'label with spaces=0'").is_valid()
False
label = ''
max = ''
min = ''
reconsile_thresholds()

Convert threshold from new threshold syntax to current one.

For backwards compatibility

split_value_and_uom(value)

Example:

get value=”10M” and return (10,”M”)

>>> p = PerfDataMetric()
>>> p.split_value_and_uom( "10" )
('10', '')
>>> p.split_value_and_uom( "10c" )
('10', 'c')
>>> p.split_value_and_uom( "10B" )
('10', 'B')
>>> p.split_value_and_uom( "10MB" )
('10', 'MB')
>>> p.split_value_and_uom( "10KB" )
('10', 'KB')
>>> p.split_value_and_uom( "10TB" )
('10', 'TB')
>>> p.split_value_and_uom( "10%" )
('10', '%')
>>> p.split_value_and_uom( "10s" )
('10', 's')
>>> p.split_value_and_uom( "10us" )
('10', 'us')
>>> p.split_value_and_uom( "10ms" )
('10', 'ms')
uom = ''
value = ''
warn = ''
class pynag.Utils.PluginOutput(stdout)

This class parses a typical stdout from a nagios plugin

It splits the output into the following fields:

  • Summary
  • Long Output
  • Perfdata

Attributes:

summary (str): Summary returned by the plugin check

long_output (str)

perfdata (str): Data returned by the plugin as a string

parsed_perfdata: perfdata parsed and split

Example Usage:

>>> p = PluginOutput("Everything is ok | load1=15 load2=10")
>>> p.summary
'Everything is ok '
>>> p.long_output
''
>>> p.perfdata
'load1=15 load2=10'
>>> p.parsed_perfdata.metrics
['load1'=15;;;;, 'load2'=10;;;;]
long_output = None
parsed_perfdata = None
perfdata = None
summary = None
exception pynag.Utils.PynagError(message, errorcode=None, errorstring=None, *args, **kwargs)

Bases: exceptions.Exception

The default pynag exception.

Exceptions raised within the pynag library should aim to inherit this one.

pynag.Utils.cache_only(func)
class pynag.Utils.defaultdict(default_factory=None, *a, **kw)

Bases: dict

This is an alternative implementation of collections.defaultdict.

Used as a fallback if using python 2.4 or older.

Usage:

try:
    from collections import defaultdict
except ImportError:
    from pynag.Utils import defaultdict
copy()
pynag.Utils.grep(objects, **kwargs)

Returns all the elements from array that match the keywords in **kwargs

See documentation for pynag.Model.ObjectDefinition.objects.filter() for example how to use this.

Arguments:

objects (list of dict): list to be searched

kwargs (str): Any search argument provided will be checked against every dict

Examples:

array = [
{'host_name': 'examplehost', 'state':0},
{'host_name': 'example2', 'state':1},
]
grep_dict(array, state=0)
# should return [{'host_name': 'examplehost', 'state':0},]
pynag.Utils.grep_to_livestatus(*args, **kwargs)

Converts from pynag style grep syntax to livestatus filter syntax.

Example:

>>> grep_to_livestatus(host_name='test')
['Filter: host_name = test']
>>> grep_to_livestatus(service_description__contains='serv')
['Filter: service_description ~ serv']
>>> grep_to_livestatus(service_description__isnot='serv')
['Filter: service_description != serv']
>>> grep_to_livestatus(service_description__contains=['serv','check'])
['Filter: service_description ~ serv']
>>> grep_to_livestatus(service_description__contains='foo', contacts__has_field='admin')
['Filter: contacts >= admin', 'Filter: service_description ~ foo']
>>> grep_to_livestatus(service_description__has_field='foo')
['Filter: service_description >= foo']
>>> grep_to_livestatus(service_description__startswith='foo')
['Filter: service_description ~ ^foo']
>>> grep_to_livestatus(service_description__endswith='foo')
['Filter: service_description ~ foo$']
pynag.Utils.reconsile_threshold(threshold_range)

Take threshold string as and normalize it to the format supported by plugin development team

The input (usually a string in the form of ‘the new threshold syntax’) is a string in the form of x..y

The output will be a compatible string in the older nagios plugin format @x:y

Examples:

>>> reconsile_threshold("0..5")
'@0:5'
>>> reconsile_threshold("inf..5")
'5:'
>>> reconsile_threshold("5..inf")
'~:5'
>>> reconsile_threshold("inf..inf")
'@~:'
>>> reconsile_threshold("^0..5")
'0:5'
>>> reconsile_threshold("10..20")
'@10:20'
>>> reconsile_threshold("10..inf")
'~:10'
pynag.Utils.runCommand(command, raise_error_on_fail=False, shell=True, env=None)

Run command from the shell prompt. Wrapper around subprocess.

Args:

command (str): string containing the command line to run

raise_error_on_fail (bool): Raise PynagError if returncode > 0

Returns:

str: stdout/stderr of the command run

Raises:

PynagError if returncode > 0
pynag.Utils.send_nsca(code, message, nscahost, hostname=None, service=None, nscabin='send_nsca', nscaconf=None)

Send data via send_nsca for passive service checks

Args:

code (int): Return code of plugin.

message (str): Message to pass back.

nscahost (str): Hostname or IP address of NSCA server.

hostname (str): Hostname the check results apply to.

service (str): Service the check results apply to.

nscabin (str): Location of send_nsca binary. If none specified whatever is in the path will be used.

nscaconf (str): Location of the NSCA configuration to use if any.

Returns:

[result,stdout,stderr] of the command being run
pynag.Utils.synchronized(lock)

Synchronization decorator

Use this to make a multi-threaded method synchronized and thread-safe.

Use the decorator like so:

@pynag.Utils.synchronized(pynag.Utils.rlock)
class pynag.Utils.CheckResult(nagios_result_dir, file_time=1406146567.120654)

Bases: object

Methods for creating host and service checkresults for nagios processing

host_result(host_name, **kwargs)

Create a service checkresult

Any kwarg will be added to the checkresult

Args:
host_name (str) service_descritpion (str)
Kwargs:
check_type (int): active(0) or passive(1) check_options (int) scheduled_check (int) reschedule_check (int) latency (float) start_time (float) finish_time (float) early_timeout (int) exited_ok (int) return_code (int) output (str): plugin output
service_result(host_name, service_description, **kwargs)

Create a service checkresult

Any kwarg will be added to the checkresult

Args:
host_name (str) service_descritpion (str)
Kwargs:
check_type (int): active(0) or passive(1) check_options (int) scheduled_check (int) reschedule_check (int) latency (float) start_time (float) finish_time (float) early_timeout (int) exited_ok (int) return_code (int) output (str): plugin output
submit()

Submits the results to nagios

The importer

General Utilities from importing nagios objects. Currently .csv files are supported

Either execute this script standalone from the command line or use it as a python library like so:

>>> from pynag.Utils import importer
>>> pynag_objects = importer.import_from_csv_file(filename='foo', seperator=',') 
>>> for i in pynag_objects: 
...     i.save() 
pynag.Utils.importer.dict_to_pynag_objects(dict_list, object_type=None)

Take a list of dictionaries, return a list of pynag.Model objects.

Args:
dict_list: List of dictionaries that represent pynag objects object_type: Use this object type as default, if it is not specified in dict_list
Returns:
List of pynag objects
pynag.Utils.importer.import_from_csv_file(filename, seperator=', ', object_type=None)

Parses filename and returns a list of pynag objects.

Args:
filename: Path to a file seperator: use this symbol to seperate columns in the file object_type: Assume this object_type if there is no object_type column
pynag.Utils.importer.parse_arguments()

Parse command line arguments

pynag.Utils.importer.parse_csv_file(filename, seperator=', ')

Parse filename and return a dict representing its contents

pynag.Utils.importer.parse_csv_string(csv_string, seperator=', ')

Parse csv string and return a dict representing its contents