2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
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.
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'
68 if os
.path
.exists(config_file
):
72 def try_detect_servers():
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]:
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
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
:
113 results
.append((scheme
, server_address
, server_port
))
119 servers
= try_detect_servers()
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'
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 ''
138 url
= '%s://%s%s/%s?auto' % (proto
, address
, portspec
, page
)
139 # Try to fetch the status page for each server
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
)
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
)
162 for line
in fd
.read().split('\n'):
165 if line
.lstrip()[0] == '<':
166 # Seems to be html output. Skip this server.
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
))
174 sys
.stderr
.write('Exception (%s%s): %s\n' % (address
, portspec
, e
))