Intro
Python is by default installed on an OP5 Monitor system and is an easy to use programming language, therefore it's very good for writing plugins for OP5 Monitor, Naemon or Nagios.
This how-to introduces some key concepts and shall be seen as an introduction to plugin/extension development in Python.
Installation
Python comes pre-installed on most Linux distributions and on Mac OS X, so most of the time you don't have to do any extra configuration on these platforms.
For Windows users, it's recommended that you download the latest release of Python 2.7 from http://www.python.org and then it's just a matter of a simple application install.
If you're unable to install Python, there are also online interpreters for testing. repl.it has an excellent one.
First-steps
After the installation, launch the Python interpreter to test that everything works. On Linux or Mac OS X, it's just a matter of opening a terminal and running the command "python". On Windows you will have to find the python.exe binary in your installation path.
Once you have the Python interpreter up and running, try the following piece of code:
print "Hello World"
Python has all kinds of common logic built in and there's a lot to talk about here, but Python has some excellent documentation for almost everything.
I can also recommend CodeAcademys Python course which is done in an online interpreter with intuitive examples and assignments.
Continue to the next step once you feel that you have basic knowledge in Python.
Developing for OP5 Monitor with Python
Developing plugins for OP5 Monitor, Naemon or Nagios is straight forward. The different states (Ok, Warning, Critical, Unknown) are set depending on the exit codes (0,1,2,3) of the program and the output to stdout is used for displaying a status message and performance statistics.
Development guidelines
At ITRS Group, we really appreciate when developers follow the developer guidelines, the developer guidelines can be found over at monitoring-plugins.com. In short, having the following options makes the plugin easier to use:
- -H for hostname
- -h for short help
- --help for long help output
- -v for verbose mode and -vv for very verbose mode
Exit codes, what you need to know
Exit codes are the backbone of the check plugins and are required to be used with OP5 Monitor.
One thing to know, though, is that the exit codes translate to different things if the object that is using the plugins is a host or service, for instance:
Exit Code | Service status | Host status | Description |
---|---|---|---|
0 | OK | UP | Everything is working as it should |
1 | WARNING | - | Things are kind of working, might be some problems. |
2 | CRITICAL | DOWN | Things are not working. |
3 | UNKNOWN | - | Something went wrong with the supplied commands or the plugin isn't working as it should. |
Output, what you need to know
Output from OP5 Monitor, Naemon or Nagios plugins are used for displaying a status message and/or performance data, which is used for performance or health statistics. See the following example of output:
OK: I'm plugin output and I found one cat | cats=1;5;10;0;11
In the above example, the pipe (|) char separates the status message from the performance data. The string "OK: I'm plugin output and I found one cat" will be the status message and the "cats=1;5;10;0;11" will generate the graphs,
where 1 = current number of cats, 5 = number of cats for warning threshold, 10 = number of cats for critical threshold, 0 & 11 is for min and max in the graph.
For more info, see the Development Guidelines (performance data, status message sections) over at Monitoring Plugins.
Examples
First Example: Dead Simple Plugin
Read through this code, try to understand what it does. There are explanations below for reference. (Download)
#!/usr/bin/env python
state = "OK"
if state == "OK":
print "We are OK."
exit(0)
elif state == "WARNING":
print "We are WARNING."
exit(1)
elif state == "CRITICAL":
print "We are CRITICAL."
exit(2)
elif state == "UNKNOWN":
print "We are UNKNOWN."
exit(3)
else:
print "Shouldn't be here."
exit(127)
Lets go through the key concepts of this code:
state = "OK"
This is just a simple variable assignment. In this example, the variable is assigned statically, but this could and will in most cases be assigned with some logic.
if state == "OK":
print "We are OK."
exit(0)
elif state == "WARNING":
print "We are WARNING."
exit(1)
elif state == "CRITICAL":
print "We are CRITICAL."
exit(2)
elif state == "UNKNOWN":
print "We are UNKNOWN."
exit(3)
else:
print "Shouldn't be here."
exit(127)
This is where the "magic" happens. We are now checking our state and depending on what state is we are exiting with the correct exit code. At the bottom of the if statement we have an else where we shouldn't end up, instead of 127 as an exit code we could probably use 3 here also, because it's really an unknown state.
Second Example: Dead Simple Plugin with Arguments
Here's a bit more advanced example with argument parsing, it looks kind of like the first example but with some user input. Go through the code and see if you understand what it does, explanation is found below the code. (Download)
#!/usr/bin/env python
import argparse
parser = argparse.ArgumentParser(description="Dead Simple Plugin with arguments.")
parser.add_argument(
"-s",
help="State type, can be OK, WARNING, CRITICAL or UNKNOWN",
required=True,
choices=["OK", "WARNING", "CRITICAL", "UNKNOWN"])
parser.add_argument(
"-w",
help="Warning threshold",
required=True,
type=int)
parser.add_argument(
"-c",
help="Critical threshold",
required=True,
type=int)
args = parser.parse_args()
if args.s == "OK":
print "We are OK. | somegraph=1;%s;%s;;" % (args.w, args.c)
exit(0)
elif args.s == "WARNING":
print "We are WARNING. | somegraph=1;%s;%s;;" % (args.w, args.c)
exit(1)
elif args.s == "CRITICAL":
print "We are CRITICAL. | somegraph=1;%s;%s;;" % (args.w, args.c)
exit(2)
elif args.s == "UNKNOWN":
print "We are UNKNOWN. | somegraph=1;%s;%s;;" % (args.w, args.c)
exit(3)
else:
print "Shouldn't be here."
exit(127)
Let's go through the key concepts of this code:
import argparse
Python has a great system that allows you to import different modules to extend the applications functionality. argparse is one of those outstanding modules which is used for parsing command line arguments. For more info on argparse, check out the manuals.
parser = argparse.ArgumentParser(description="Dead Simple Plugin with arguments.")
Here we create a new argument parser instance, which we will add logic to later on.
parser.add_argument(
"-s",
help="State type, can be OK, WARNING, CRITICAL or UNKNOWN",
required=True,
choices=["OK", "WARNING", "CRITICAL", "UNKNOWN"])
parser.add_argument(
"-w",
help="Warning threshold",
required=True,
type=int)
parser.add_argument(
"-c",
help="Critical threshold",
required=True,
type=int)
This piece of code will add arguments to our parser, the add_argument function takes a lot of arguments. Look at the docs mentioned above for more information.
args = parser.parse_args()
To use our arguments, we need to parse them. This nice function will do it for us. Afterwards, arguments can be found using the variable args.option. So in other words, args.s will be the string that we submit to the -s switch.
if args.s == "OK":
print "We are OK. | somegraph=1;%s;%s;;" % (args.w, args.c)
exit(0)
elif args.s == "WARNING":
print "We are WARNING. | somegraph=1;%s;%s;;" % (args.w, args.c)
exit(1)
elif args.s == "CRITICAL":
print "We are CRITICAL. | somegraph=1;%s;%s;;" % (args.w, args.c)
exit(2)
elif args.s == "UNKNOWN":
print "We are UNKNOWN. | somegraph=1;%s;%s;;" % (args.w, args.c)
exit(3)
else:
print "Shouldn't be here."
exit(127)
As in the first example, we will need some logic to determinate what to do with the input, this if handles the logic like a beast and we are also including performance data in the output. Yay!
Third example, using pynag to make development easier
Once you understand the basic principles of plugin development, moving on to using a class/lib to make the development process easier is preferred. There are a lot of different libraries for this out there, but here's an example using pynag. (Download)
#!/usr/bin/env python
# Built on boilerplate form pynag:
# https://github.com/pynag/pynag/wiki/Writing-Plugins-with-pynag.Plugins.PluginHelper
# Example usage:
# python pynag2.py -s WARNING --th metric=some-metrics,ok=0..5,warning=5..10,critical=10..inf
#Modules
from pynag.Plugins import PluginHelper, ok, warning, critical, unknown
helper = PluginHelper()
# Arguments
helper.parser.add_option("-s", help="Exit State", dest="state", default='OK')
helper.parse_arguments()
if helper.options.state == "OK":
helper.status(ok)
elif helper.options.state == "WARNING":
helper.status(warning)
elif helper.options.state == "CRITICAL":
helper.status(critical)
elif helper.options.state == "UNKNOWN":
helper.status(unknown)
else:
print "No state specified, calculating from input metrics."
helper.add_metric(label='some-metrics',value=5)
helper.add_summary("Some status message.")
helper.check_all_metrics()
helper.exit()
Let's go through this code and what it does.
helper = PluginHelper()
After importing the different modules in this library, start with creating an instance of our pluginhelper. This will be the core functionality we will work around.
helper.parser.add_option("-s", help="Exit State", dest="state", default='OK')
helper.parse_arguments()
Pretty straight forward here. Add some arguments for your plugin. This example will take an argument that defines the exit status of the plugin. Most of the arguments are already defined when using the PluginHelper().
if helper.options.state == "OK":
helper.status(ok)
elif helper.options.state == "WARNING":
helper.status(warning)
elif helper.options.state == "CRITICAL":
helper.status(critical)
elif helper.options.state == "UNKNOWN":
helper.status(unknown)
else:
print "No state specified, calculating from input metrics."
Again, here's the "logic" for this plugin, but instead of running exit directly in the if, we are setting the exit state that will be used when helper.exit() runs.
helper.add_metric(label='some-metrics',value=5)
helper.add_summary("Some status message.")
Pynag has some very nice functions for adding status messages and different metrics. Using add_metric() you can add different metrics and assign values to these. Also, there's no need to specify extra arguments for thresholds per metric because of the nifty functions of --th switch that's implemented in pynag.
helper.check_all_metrics()
helper.exit()
Before exiting, validate metrics.
Roundup
That's about it for the plugin examples. As you can see, mostly it's about using the correct arguments, printing the correct stuff to stdout and exiting in a correct way. Not that hard once you understand the concepts.
Now what?
After going through the above, you should be set up to start working with plugins. From now on, there's only one way to learn, and that's to develop, rethink and refine. Don't forget to use the numerous tools and libraries that Python has for managing data.
We would also like to mention that there are a lot of different libraries for developing plugins and working with configuration in OP5 Monitor, Naemon or Nagios. Check out the following sites for more info:
Comments
0 comments
Please sign in to leave a comment.