Refactoring: Changed all check parameters starting with an 'o' to the new rulespec...
[check_mk.git] / agents / plugins / apache_status
blob7b4c739912129f776e0310b03f48eb63f9571a92
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
10 # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # Check_MK-Agent-Plugin - Apache Server Status
29 # Fetches the server-status page from detected or configured apache
30 # processes to gather status information about this apache process.
32 # To make this agent plugin work you have to load the status_module
33 # into your apache process. It is also needed to enable the "server-status"
34 # handler below the URL "/server-status".
36 # By default this plugin tries to detect all locally running apache processes
37 # and to monitor them. If this is not good for your environment you might
38 # create an apache_status.cfg file in MK_CONFDIR and populate the servers
39 # list to prevent executing the detection mechanism.
41 # It is also possible to override or extend the ssl_ports variable to make the
42 # check contact other ports than 443 with HTTPS requests.
44 import os
45 import re
46 import socket
47 import sys
48 import urllib2
49 import ssl
51 config_dir = os.getenv("MK_CONFDIR", "/etc/check_mk")
52 config_file = config_dir + "/apache_status.conf"
54 if not os.path.exists(config_file):
55 config_file = config_dir + "/apache_status.cfg"
57 # We have to deal with socket timeouts. Python > 2.6
58 # supports timeout parameter for the urllib2.urlopen method
59 # but we are on a python 2.5 system here which seem to use the
60 # default socket timeout. We are local here so set it to 1 second.
61 socket.setdefaulttimeout(5.0)
63 # None or list of (proto, ipaddress, port) tuples.
64 # proto is 'http' or 'https'
65 servers = None
66 ssl_ports = [443]
68 if os.path.exists(config_file):
69 execfile(config_file)
72 def try_detect_servers():
73 results = []
75 for netstat_line in os.popen('netstat -tlnp 2>/dev/null').readlines():
76 parts = netstat_line.split()
77 # Skip lines with wrong format
78 if len(parts) < 7 or '/' not in parts[6]:
79 continue
81 pid, proc = parts[6].split('/', 1)
82 to_replace = re.compile('^.*/')
83 proc = to_replace.sub('', proc)
85 procs = ['apache2', 'httpd', 'httpd2-prefork', 'httpd2-worker', 'httpd.worker', 'fcgi-pm']
86 # the pid/proc field length is limited to 19 chars. Thus in case of
87 # long PIDs, the process names are stripped of by that length.
88 # Workaround this problem here
89 procs = [p[:19 - len(pid) - 1] for p in procs]
91 # Skip unwanted processes
92 if proc not in procs:
93 continue
95 server_address, server_port = parts[3].rsplit(':', 1)
96 server_port = int(server_port)
98 # Use localhost when listening globally
99 if server_address == '0.0.0.0':
100 server_address = '127.0.0.1'
101 elif server_address == '::':
102 server_address = '[::1]'
103 elif ':' in server_address:
104 server_address = '[%s]' % server_address
106 # Switch protocol if port is SSL port. In case you use SSL on another
107 # port you would have to change/extend the ssl_port list
108 if server_port in ssl_ports:
109 scheme = 'https'
110 else:
111 scheme = 'http'
113 results.append((scheme, server_address, server_port))
115 return results
118 if servers is None:
119 servers = try_detect_servers()
121 if not servers:
122 sys.exit(0)
124 sys.stdout.write('<<<apache_status>>>\n')
125 for server in servers:
126 if isinstance(server, tuple):
127 proto, address, port = server
128 page = 'server-status'
129 else:
130 proto = server['protocol']
131 address = server['address']
132 port = server['port']
133 page = server.get('page', 'server-status')
135 portspec = ':%d' % port if port else ''
137 try:
138 url = '%s://%s%s/%s?auto' % (proto, address, portspec, page)
139 # Try to fetch the status page for each server
140 try:
141 request = urllib2.Request(url, headers={"Accept": "text/plain"})
142 fd = urllib2.urlopen(request)
143 except urllib2.URLError, e:
144 if 'unknown protocol' in str(e):
145 # HACK: workaround misconfigurations where port 443 is used for
146 # serving non ssl secured http
147 url = 'http://%s%s/server-status?auto' % (address, portspec)
148 fd = urllib2.urlopen(url)
149 else:
150 raise
151 except Exception, e:
152 if 'doesn\'t match' in str(e) and address in ("127.0.0.1", "[::1]", "localhost"):
153 # HACK: workaround if SSL port is found and localhost is using
154 # SSL connections but certificate does not match
155 no_cert_context = ssl.create_default_context()
156 no_cert_context.check_hostname = False
157 no_cert_context.verify_mode = ssl.CERT_NONE
158 fd = urllib2.urlopen(url, context=no_cert_context)
159 else:
160 raise
162 for line in fd.read().split('\n'):
163 if not line.strip():
164 continue
165 if line.lstrip()[0] == '<':
166 # Seems to be html output. Skip this server.
167 break
169 sys.stdout.write("%s %s %s\n" % (address, port, line))
170 except urllib2.HTTPError, e:
171 sys.stderr.write('HTTP-Error (%s%s): %s %s\n' % (address, portspec, e.code, e))
173 except Exception, e:
174 sys.stderr.write('Exception (%s%s): %s\n' % (address, portspec, e))