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 (e. contact_groups) into a parsable format.

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

Arguments:
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”

Arguments:

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.

Arguments:
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

Arguments:

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.

Arguments:
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()

Arguments:

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

Arguments:

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

Arguments:
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.

Arguments

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.

Arguments:

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

Arguments:
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 = ''

str CRITICAL threshold

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 = ''

str. Label section of the perfdata string

max = ''

str. Maximal value of control

min = ''

str. Minimal value of control

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 = ''

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

value = ''

str. Value section of the perfdata string

warn = ''

str. WARNING threshold

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 parsed and split

perfdata = None

str. Data returned by the plugin as a string

summary = None

str. Summary returned by the plugin check

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.

Arguments:
command (str): string containing the command line to run raise_error_on_fail (bool): Raise PynagError if returncode > 0
Returns:
string: 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

Arguments:

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)