Skip to content

Commit

Permalink
Merge pull request #1 from bithon/master
Browse files Browse the repository at this point in the history
Implemented perfdata metrics and lots of code improvements. Thanks, @bithon !
  • Loading branch information
mpibpc-mroose authored Jun 13, 2019
2 parents e0bff4c + c939fd4 commit 25fa01c
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 166 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Change Log

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to
[Semantic Versioning](http://semver.org/).

## 0.2.0
### Added
- parsed arguments: `label`
- parfdata to output (https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/perfdata.html)
- exception for UnicodeDecodeError in `CheckPcMeasure.check()`
### Changes
- code is now more generic for NAGIOS and ICINGA
- restructuring the class

# 0.1.0 Initial release
52 changes: 41 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Nagios Plugin for MessPC.de Ethernet Boxes
![GitHub release](https://img.shields.io/github/release/mpibpc-mroose/nagios_plugin_pcmeasure.svg)
![GitHub](https://img.shields.io/github/license/mpibpc-mroose/nagios_plugin_pcmeasure.svg?color=blue)
![code coverage 100%](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)

[![Build Status](https://travis-ci.org/mpibpc-mroose/nagios_plugin_pcmeasure.svg?branch=master)](https://travis-ci.org/mpibpc-mroose/nagios_plugin_pcmeasure)
# check_pcmeasure.py
Nagios/Icinga2 Plugin for https://messpc.de/ and https://pcmeasure.com Ethernet Boxes written in Python 3

An implementation for Perl already exists:
https://exchange.nagios.org/directory/Plugins/Hardware/Environmental/MessPC--2F-pcmeasure/details
Expand All @@ -9,25 +12,52 @@ https://exchange.nagios.org/directory/Plugins/Hardware/Environmental/MessPC--2F-

So I decided to implement it's functionality in Python.

There is no warranty for a 100% compatibilty to the old plugin, but
There is no warranty for a 100% compatibility to the old plugin, but
requests for adaptions and error reports are always welcome.

# How to use it
## Example commandline
```
root@icinga-agent01:/usr/lib/nagios/plugins# ./check_pcmeasure.py -H 10.10.200.250 -S com1.1 -w 45 -c 55 -l 'celsius'
OK: 27.8 celsius | celsius=27.8
```

1. copy `check_pcmeasure.py' to your Nagios plugin folder
1. define a nagios command:
## Config files:
- copy `check_pcmeasure.py' to your Nagios/Icinga plugin folder
- define a command:
```
define command{
command_name check_messpc
command_line $USER1$/check_pcmeasure.py -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ -S $ARG3
command_name check_pcmeasure
command_line $USER1$/check_pcmeasure.py -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ -S $ARG3 -l $ARG4
}
```
1. define a service
- define a service
```
define service{
use generic-service
host_name messpc.example.com
host_name pcmeasure.example.com
service_description temperature sensor
check_command check_messpc!28!30!com1.1
check_command check_pcmeasure!28!30!com1.1!celsius
}
```
```
## Director:
- Icinga Director -> Define Data Fields:

|Label|Field name|
|-----|----------|
|Critical|critical|
|Warning|warning|
|Etherbox address|etherbox_address|
|Etherbox sensor label|etherbox_sensor_label|
|Etherbox sensor name|etherbox_sensor_name|
- Icinga Director -> Commands -> Templates -> Add:
![screenshot](https://s3.gifyu.com/images/check_pcmeasure_command_template.png)
- Click on "Fields":
![screenshot](https://s3.gifyu.com/images/check_pcmeasure_command_template_fields.png)
- Icinga Director -> Commands -> Commands -> Add:
![screenshot](https://s3.gifyu.com/images/check_pcmeasure_command.png)
- Click on "Arguments"
![screenshot](https://s3.gifyu.com/images/check_pcmeasure_command_arguments.png)
- Create a service as usual ...
- Enjoy :)
![screenshot](https://s3.gifyu.com/images/perfdata_icinga.png)
3 changes: 3 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# TODO
- Create a release
- Upload to NAGIOS and ICINGA exchange ...
210 changes: 111 additions & 99 deletions check_pcmeasure.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,127 +1,139 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import argparse
import os
import re
import socket
import sys
import textwrap
import time


STATUS_OK = 0
STATUS_WARNING = 1
STATUS_CRITICAL = 2
STATUS_UNKNOWN = 3


class CheckPcMeasure(object):
def __init__(self, host="127.0.0.1", port=4000):
version = "0.2.0"
if __name__ == '__main__':
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
description=textwrap.dedent(os.path.basename(__file__) + " " + version +
" (GPLv3) 2018 - " + time.strftime("%Y")),
epilog=textwrap.dedent("GitHub: https://github.com/mpibpc-mroose/"
"nagios_plugin_pcmeasure"))
parser.add_argument("-H", dest="host", type=str, required=True, help="hostname of the etherbox")
parser.add_argument("-p", type=int, dest="port", default=4000, required=False, help="port to use")
parser.add_argument("-S", dest="sensor_name", type=str, required=True, help="sensor name, e.g. com1.1")
parser.add_argument("-w", dest="warning_threshold", type=float, required=True, help="warning threshold")
parser.add_argument("-c", dest="critical_threshold", type=float, required=True, help="critical threshold")
parser.add_argument("-l", dest="label", type=str, required=False, help="label for perfdata, e.g. 'celsius'")

NAGIOS_OK = 0
NAGIOS_WARNING = 1
NAGIOS_CRITICAL = 2
NAGIOS_UNKNOWN = 3
self.arguments = parser.parse_args()
self.critical_threshold = self.arguments.critical_threshold
self.warning_threshold = self.arguments.warning_threshold
self.host = self.arguments.host
self.port = self.arguments.port
self.sensor_name = self.arguments.sensor_name

if self.arguments.label:
self.label_name = " " + self.arguments.label
self.label_perfdata = self.arguments.label
else:
self.label_name = ""
self.label_perfdata = "sensor_output"

class MessPCCheck(object):
def __init__(self, host, port=4000):
self.host = host
self.port = port
self.socket = self.connect()
if self.warning_threshold > self.critical_threshold:
print("UNKNOWN: warning threshold should be lower than critical threshold")
sys.exit(STATUS_UNKNOWN)
else:
self.label_name = ""
self.label_perfdata = "sensor_output"
self.critical_threshold = False
self.warning_threshold = False
self.host = host
self.port = port
self.sensor_name = False
self.socket = self._connect()

def connect(self):
def _connect(self):
_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_socket.settimeout(0.5)
_socket.connect((self.host, self.port))
try:
_socket.connect((self.host, self.port))
except socket.timeout:
print("UNKNOWN: timeout on connect to {host}:{port}".format(host=self.host,
port=self.port))
sys.exit(STATUS_UNKNOWN)
except ConnectionRefusedError as error:
print("UNKNOWN: {error} by {host}:{port}".format(error=str(error),
host=self.host,
port=self.port))
sys.exit(STATUS_UNKNOWN)
return _socket

def close(self):
self.socket.close()

def __delete__(self, instance):
self.socket.close()

def _get_value(self, sensor_name: bytes) -> float:
self.socket.send(
b'pcmeasure.' + sensor_name + b'\n'
)
def _get_value(self, sensor_name) -> float:
self.socket.send(b'pcmeasure.' + bytes(sensor_name, 'utf-8') + b'\n')
raw_data = self.socket.recv(2096).decode()
sensor_reply_pattern = re.compile(r"value=\s(?P<value>.+);")
return float(sensor_reply_pattern.findall(raw_data)[0])

def check(self, sensor_name: bytes, warning_threshold: float, critical_threshold: float) -> int:
def check(self, sensor_name=False, warning_threshold=False, critical_threshold=False, label=False) -> int:
if sensor_name:
self.sensor_name = sensor_name
if warning_threshold:
self.warning_threshold = warning_threshold
if critical_threshold:
self.critical_threshold = critical_threshold
if label:
self.label_name = " " + label
self.label_perfdata = label
try:
value = self._get_value(sensor_name=sensor_name)
if value > critical_threshold:
print("CRITICAL: {value} exceeds {threshold}".format(
value=value,
threshold=critical_threshold
))
return NAGIOS_CRITICAL
elif value > warning_threshold:
print("WARNING: {value} exceeds {threshold}".format(
value=value,
threshold=warning_threshold
))
return NAGIOS_WARNING
value = self._get_value(sensor_name=self.sensor_name)
if value > self.critical_threshold:
print("CRITICAL: {value} exceeds {threshold} | "
"{label_perfdata}={value};;;0".format(value=value,
label=self.label_name,
label_perfdata=self.label_perfdata,
threshold=self.critical_threshold))
return STATUS_CRITICAL
elif value > self.warning_threshold:
print("WARNING: {value} exceeds {threshold} | "
"{label_perfdata}={value};;;0".format(value=value,
label=self.label_name,
label_perfdata=self.label_perfdata,
threshold=self.warning_threshold))
return STATUS_WARNING
else:
print("OK: {value}".format(
value=value
))
return NAGIOS_OK
print("OK: {value}{label} | {label_perfdata}={value};;;0".format(value=value,
label_perfdata=self.label_perfdata,
label=self.label_name))
return STATUS_OK
except UnicodeDecodeError:
print("UNKNOWN: can not read from sensor '{sensor_name}'! "
"use {app_name} -h for further information!".format(sensor_name=self.sensor_name,
app_name=os.path.basename(__file__)))
return STATUS_UNKNOWN
except Exception as error:
print("UNKNOWN: " + str(error))
return NAGIOS_UNKNOWN
return STATUS_UNKNOWN

def check_command(self):
return_code = self.check(sensor_name=self.sensor_name,
warning_threshold=self.warning_threshold,
critical_threshold=self.critical_threshold)
sys.exit(return_code)


if __name__ == '__main__':
parser = argparse.ArgumentParser()
"""
check_pcmeasure2.pl -H <host> -S <sensor>[,<sensor] [-p <port>]
[-w <threshold>] [-c <threshold>]
"""
parser.add_argument(
"-H",
dest="host",
type=str,
required=True,
help="hostname of the MessPC unit"
)
parser.add_argument(
"-p",
type=int,
dest="port",
default=4000,
required=False,
help="port to use for communication"
)
parser.add_argument(
"-S",
dest="sensor_name",
type=str,
required=True,
help="sensor name, e.g. com1.1"
)
parser.add_argument(
"-w",
dest="warning_threshold",
type=float,
required=True,
help="warning threshold"
)
parser.add_argument(
"-c",
dest="critical_threshold",
type=float,
required=True,
help="critical threshold"
)
arguments = parser.parse_args()

if arguments.warning_threshold > arguments.critical_threshold:
print("UNKNOWN: warning threshold should be lower than critical threshold")
sys.exit(NAGIOS_UNKNOWN)

try:
mess_pc = MessPCCheck(
host=arguments.host, port=arguments.port
)
except TimeoutError:
print(
"CRITICAL: timeout on connect to {host}:{port}".format(
host=arguments.host,
port=arguments.port
))
sys.exit(NAGIOS_CRITICAL)

return_code = mess_pc.check(
sensor_name=arguments.sensor_name.encode(),
warning_threshold=arguments.warning_threshold,
critical_threshold=arguments.critical_threshold
)
sys.exit(return_code)
check_pcmeasure = CheckPcMeasure()
check_pcmeasure.check_command()
37 changes: 28 additions & 9 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,43 @@
import sys
import os
from setuptools import setup
#!/usr/bin/env python3

version = '0.1.0'
import setuptools

setup(
name='nagios_plugin_pcmeasure',

version = '0.2.0'

with open("README.md", "r") as fh:
long_description = fh.read()

setuptools.setup(
name='check__pcmeasure.py',
version=version,
author='Dr. Marco Roose',
author_email='[email protected]',
url='https://github.com/mpibpc-mroose/nagios_plugin_pcmeasure/',
license='GPL-3.0',
description='Nagios Plugin for ethernet sensor boxes from http://messpc.de',
long_description='Please see our GitHub README',
description='Nagios/Icinga2 Plugin for ethernet sensor boxes from http://messpc.de and http://pcmeasure.com',
long_description=long_description,
long_description_content_type="text/markdown",
install_requires=[],
python_requires='>=3.5',
packages=setuptools.find_packages(),
project_urls={
'Source': 'https://github.com/mpibpc-mroose/nagios_plugin_pcmeasure/',
'Nagios Exchange': 'https://exchange.nagios.org/',
'Icinga Exchange': 'https://exchange.icinga.com',
},
keywords=[
'Nagios',
'Icinga2',
'pcmeasure',
'messpc',
'etherbox'
],
classifiers=[
"Development Status :: 5 - Production/Stable",
"Operating System :: OS Independent",
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6'
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7'
]
)
Loading

0 comments on commit 25fa01c

Please sign in to comment.