diff --git a/nagixsc/__init__.py b/nagixsc/__init__.py
index 56c4cf3ead117ca047a818085912232a5ad514d4..644c9ab624b78cc35b748f5a46637cd3d67e5e31 100644 (file)
--- a/nagixsc/__init__.py
+++ b/nagixsc/__init__.py
import os
import random
import shlex
+import signal
import socket
import string
import subprocess
##############################################################################
+class ExecTimeoutError(Exception):
+ pass
+
+##############################################################################
+
def available_encodings():
return ['base64', 'plain',]
##############################################################################
-def exec_check(host_name, service_descr, cmdline):
+def exec_timeout_handler(signum, frame):
+ raise ExecTimeoutError
+
+def exec_check(host_name, service_descr, cmdline, timeout=None, timeout_returncode=2):
+ cmdarray = shlex.split(cmdline)
+
+ check = {}
+ check['host_name'] = host_name
+ check['service_description'] = service_descr
+
+ if len(cmdarray) == 0:
+ check['output'] = 'No command line specified!'
+ check['returncode'] = 127
+ return check
+
+ if timeout:
+ signal.signal(signal.SIGALRM, exec_timeout_handler)
+ signal.alarm(timeout)
+
try:
- cmd = subprocess.Popen(shlex.split(cmdline), stdout=subprocess.PIPE)
- output = cmd.communicate()[0].rstrip()
- retcode = cmd.returncode
+ cmd = subprocess.Popen(cmdarray, stdout=subprocess.PIPE)
+ check['output'] = cmd.communicate()[0].rstrip()
+ check['returncode'] = cmd.returncode
except OSError:
- output = 'Could not execute "%s"' % cmdline
- retcode = 127
+ check['output'] = 'Could not execute "%s"' % cmdline
+ check['returncode'] = 127
+ except ExecTimeoutError:
+ check['output'] = 'Plugin timed out after %s seconds' % timeout
+ check['returncode'] = timeout_returncode
+
+ if timeout:
+ signal.alarm(0)
+ try:
+ cmd.terminate()
+ except OSError:
+ pass
- return {'host_name':host_name, 'service_description':service_descr, 'returncode':retcode, 'output':output, 'timestamp':datetime.datetime.now().strftime('%s')}
+ check['timestamp'] = datetime.datetime.now().strftime('%s')
+ return check
##############################################################################
def conf2dict(config, opt_host=None, opt_service=None):
checks = []
+ # Read "plugin_timeout" from "[nagixsc]", default "None" (no timeout)
+ try:
+ timeout = config.getint('nagixsc','plugin_timeout')
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ timeout = None
+
+ # Read "plugin_timeout_returncode" from "[nagixsc]", default "2" (CRITICAL)
+ try:
+ timeout_returncode = config.getint('nagixsc','plugin_timeout_returncode')
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ timeout_returncode = 2
+
# Sections are Hosts (not 'nagixsc'), options in sections are Services
hosts = config.sections()
if 'nagixsc' in hosts:
# Look for host check
if '_host_check' in services and not opt_service:
cmdline = config.get(host, '_host_check')
- check = exec_check(host_name, None, cmdline)
+ check = exec_check(host_name, None, cmdline, timeout, timeout_returncode)
checks.append(check)
if service[0] != '_':
cmdline = config.get(host, service)
- check = exec_check(host_name, service, cmdline)
+ check = exec_check(host_name, service, cmdline, timeout, timeout_returncode)
checks.append(check)
return checks
else:
timestamp = filetimestamp
- if retcode and output:
+ # Append only if no service filter
+ if not servicefilter and retcode and output:
checks.append({'host_name':hostname, 'service_description':None, 'returncode':retcode, 'output':output, 'timestamp':timestamp})
return xmldoc
+def xml_merge(xmldocs):
+ checks = []
+ for xmldoc in xmldocs:
+ checks.extend(xml_to_dict(xmldoc))
+ newxmldoc = xml_from_dict(checks)
+ return newxmldoc
+
+
def check_mark_outdated(check, now, maxtimediff, markold):
timedelta = now - check['timestamp']
if timedelta > maxtimediff:
##############################################################################
-class MyHTTPServer(BaseHTTPServer.HTTPServer):
+def daemonize(pidfile=None, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
+ # 1st fork
+ try:
+ pid = os.fork()
+ if pid > 0:
+ sys.exit(0)
+ except OSError, e:
+ sys.stderr.write("1st fork failed: (%d) %s\n" % (e.errno, e.strerror))
+ sys.exit(1)
+ # Prepare 2nd fork
+ os.chdir("/")
+ os.umask(0)
+ os.setsid( )
+ # 2nd fork
+ try:
+ pid = os.fork()
+ if pid > 0:
+ sys.exit(0)
+ except OSError, e:
+ sys.stderr.write("2nd fork failed: (%d) %s\n" % (e.errno, e.strerror))
+ sys.exit(1)
+
+ # Try to write PID file
+ if pidfile:
+ pid = str(os.getpid())
+ try:
+ file(pidfile, 'w+').write('%s\n' % pid)
+ except IOError:
+ sys.stderr.write("Could not write PID file, exiting...\n")
+ sys.exit(1)
+
+ # Redirect stdin, stdout, stderr
+ sys.stdout.flush()
+ sys.stderr.flush()
+ si = file(stdin, 'r')
+ so = file(stdout, 'a+')
+ se = file(stderr, 'a+', 0)
+ os.dup2(si.fileno(), sys.stdin.fileno())
+ os.dup2(so.fileno(), sys.stdout.fileno())
+ os.dup2(se.fileno(), sys.stderr.fileno())
+
+ return
+
+##############################################################################
+
+class MyHTTPServer(SocketServer.ForkingMixIn, BaseHTTPServer.HTTPServer):
def __init__(self, server_address, HandlerClass, ssl=False, sslpemfile=None):
if ssl:
# FIXME: SSL is in Py2.6