171 lines
6.3 KiB
Python
Executable File
171 lines
6.3 KiB
Python
Executable File
#!/usr/bin/python
|
|
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
|
# +------------------------------------------------------------------+
|
|
# | ____ _ _ __ __ _ __ |
|
|
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
|
|
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
|
|
# | | |___| | | | __/ (__| < | | | | . \ |
|
|
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
|
|
# | |
|
|
# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
|
|
# +------------------------------------------------------------------+
|
|
#
|
|
# This file is part of Check_MK.
|
|
# The official homepage is at http://mathias-kettner.de/check_mk.
|
|
#
|
|
# check_mk is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation in version 2. check_mk is distributed
|
|
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
|
|
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
|
|
# tails. You should have received a copy of the GNU General Public
|
|
# License along with GNU Make; see the file COPYING. If not, write
|
|
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
# Boston, MA 02110-1301 USA.
|
|
|
|
# Check_MK-Agent-Plugin - Apache Server Status
|
|
#
|
|
# Fetches the server-status page from detected or configured apache
|
|
# processes to gather status information about this apache process.
|
|
#
|
|
# To make this agent plugin work you have to load the status_module
|
|
# into your apache process. It is also needed to enable the "server-status"
|
|
# handler below the URL "/server-status".
|
|
#
|
|
# By default this plugin tries to detect all locally running apache processes
|
|
# and to monitor them. If this is not good for your environment you might
|
|
# create an apache_status.cfg file in MK_CONFDIR and populate the servers
|
|
# list to prevent executing the detection mechanism.
|
|
#
|
|
# It is also possible to override or extend the ssl_ports variable to make the
|
|
# check contact other ports than 443 with HTTPS requests.
|
|
|
|
import os, sys, urllib2, re, socket
|
|
|
|
config_dir = os.getenv("MK_CONFDIR", "/etc/check_mk")
|
|
config_file = config_dir + "/apache_status.conf"
|
|
|
|
if not os.path.exists(config_file):
|
|
config_file = config_dir + "/apache_status.cfg"
|
|
|
|
# We have to deal with socket timeouts. Python > 2.6
|
|
# supports timeout parameter for the urllib2.urlopen method
|
|
# but we are on a python 2.5 system here which seem to use the
|
|
# default socket timeout. We are local here so set it to 1 second.
|
|
socket.setdefaulttimeout(5.0)
|
|
|
|
# None or list of (proto, ipaddress, port) tuples.
|
|
# proto is 'http' or 'https'
|
|
servers = None
|
|
ssl_ports = [ 443, ]
|
|
|
|
if os.path.exists(config_file):
|
|
execfile(config_file)
|
|
|
|
|
|
def try_detect_servers():
|
|
results = []
|
|
|
|
for line in os.popen('netstat -tlnp 2>/dev/null').readlines():
|
|
parts = line.split()
|
|
# Skip lines with wrong format
|
|
if len(parts) < 7 or '/' not in parts[6]:
|
|
continue
|
|
|
|
pid, proc = parts[6].split('/', 1)
|
|
to_replace = re.compile('^.*/')
|
|
proc = to_replace.sub('', proc)
|
|
|
|
procs = [ 'apache2', 'httpd', 'httpd2-prefork', 'httpd2-worker', 'httpd.worker', 'fcgi-pm' ]
|
|
# the pid/proc field length is limited to 19 chars. Thus in case of
|
|
# long PIDs, the process names are stripped of by that length.
|
|
# Workaround this problem here
|
|
procs = [ p[:19 - len(pid) - 1] for p in procs ]
|
|
|
|
# Skip unwanted processes
|
|
if proc not in procs:
|
|
continue
|
|
|
|
address, port = parts[3].rsplit(':', 1)
|
|
port = int(port)
|
|
|
|
# Use localhost when listening globally
|
|
if address == '0.0.0.0':
|
|
address = '127.0.0.1'
|
|
elif address == '::':
|
|
address = '[::1]'
|
|
elif ':' in address:
|
|
address = '[%s]' % address
|
|
|
|
# Switch protocol if port is SSL port. In case you use SSL on another
|
|
# port you would have to change/extend the ssl_port list
|
|
if port in ssl_ports:
|
|
proto = 'https'
|
|
else:
|
|
proto = 'http'
|
|
|
|
results.append((proto, address, port))
|
|
|
|
return results
|
|
|
|
|
|
if servers is None:
|
|
servers = try_detect_servers()
|
|
|
|
|
|
if not servers:
|
|
sys.exit(0)
|
|
|
|
|
|
sys.stdout.write('<<<apache_status>>>\n')
|
|
for server in servers:
|
|
if isinstance(server, tuple):
|
|
proto, address, port = server
|
|
page = 'server-status'
|
|
else:
|
|
proto = server['protocol']
|
|
address = server['address']
|
|
port = server['port']
|
|
page = server.get('page', 'server-status')
|
|
|
|
portspec = port and ":%d" % port or ""
|
|
|
|
try:
|
|
url = '%s://%s%s/%s?auto' % (proto, address, portspec, page)
|
|
# Try to fetch the status page for each server
|
|
try:
|
|
request = urllib2.Request(url, headers={"Accept" : "text/plain"})
|
|
fd = urllib2.urlopen(request)
|
|
except urllib2.URLError, e:
|
|
if 'unknown protocol' in str(e):
|
|
# HACK: workaround misconfigurations where port 443 is used for
|
|
# serving non ssl secured http
|
|
url = 'http://%s%s/server-status?auto' % (address, portspec)
|
|
fd = urllib2.urlopen(url)
|
|
else:
|
|
raise
|
|
except Exception, e:
|
|
if 'doesn\'t match' in str(e):
|
|
# HACK: workaround if SSL port is found and localhost is using
|
|
# SSL connections but certificate does not match
|
|
portspec = ':80'
|
|
url = 'http://%s%s/server-status?auto' % (address, portspec)
|
|
fd = urllib2.urlopen(url)
|
|
else:
|
|
raise
|
|
|
|
for line in fd.read().split('\n'):
|
|
if not line.strip():
|
|
continue
|
|
if line.lstrip()[0] == '<':
|
|
# Seems to be html output. Skip this server.
|
|
break
|
|
|
|
sys.stdout.write("%s %s %s\n" % (address, port, line))
|
|
except urllib2.HTTPError, e:
|
|
sys.stderr.write('HTTP-Error (%s%s): %s %s\n' % (address, portspec, e.code, e))
|
|
|
|
except Exception, e:
|
|
sys.stderr.write('Exception (%s%s): %s\n' % (address, portspec, e))
|