177 lines
7.9 KiB
Python
177 lines
7.9 KiB
Python
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development Company LP
|
|
|
|
import logging
|
|
import os
|
|
import urllib2
|
|
|
|
import monasca_setup.agent_config
|
|
import monasca_setup.detection
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
# Process name is apache2 on Debian derivatives, on RHEL derivatives it's httpd,
|
|
# on openSUSE/SLES it might be httpd-prefork
|
|
APACHE_PROCESS_NAMES = ('apache2', 'httpd', 'httpd-prefork')
|
|
DEFAULT_APACHE_CONFIG = '/root/.apache.cnf'
|
|
CONFIG_ARG_KEYS = set(["url", "user", "password", "use_server_status_metrics"])
|
|
|
|
|
|
class Apache(monasca_setup.detection.Plugin):
|
|
|
|
"""Detect Apache web server daemons and setup configuration to monitor apache.
|
|
|
|
This plugin will by default setup process check metrics for the apache process,
|
|
and setup server-status metrics using the input url. If only process check
|
|
metrics are desired, the use_server_status_metrics argument can be passed in
|
|
with a value of false.
|
|
This plugin needs user/password for apache if using the server-status metrics
|
|
when security is setup on the web server.
|
|
This plugin accepts arguments and if none are provided it will attempt to read
|
|
the default configuration file (/root/.apache.cnf) in a format such as:
|
|
[client]
|
|
url=http://localhost/server-status?auto
|
|
user=guest
|
|
password=guest
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self._apache_process_name = 'apache2'
|
|
super(Apache, self).__init__(*args, **kwargs)
|
|
|
|
def _detect(self):
|
|
"""Run detection, set self.available True if the service is detected.
|
|
|
|
"""
|
|
process_exists = False
|
|
for proc_name in APACHE_PROCESS_NAMES:
|
|
if monasca_setup.detection.find_process_name(proc_name) is not None:
|
|
self._apache_process_name = proc_name
|
|
process_exists = True
|
|
has_args_or_config_file = (self.args is not None or
|
|
os.path.isfile(DEFAULT_APACHE_CONFIG))
|
|
self.available = process_exists and has_args_or_config_file
|
|
if not self.available:
|
|
if not process_exists:
|
|
log.error('Apache process does not exist.')
|
|
elif not has_args_or_config_file:
|
|
log.error(('Apache process exists but '
|
|
'configuration file was not found and '
|
|
'no arguments were given.'))
|
|
|
|
def _read_apache_config(self, config_location):
|
|
# Read the apache config file to extract the needed variables.
|
|
client_section = False
|
|
apache_url = None
|
|
apache_user = None
|
|
apache_pass = None
|
|
use_server_status_metrics = True
|
|
try:
|
|
with open(config_location, "r") as config_file:
|
|
for row in config_file:
|
|
if "[client]" in row:
|
|
client_section = True
|
|
continue
|
|
if client_section:
|
|
if "url=" in row:
|
|
apache_url = row.split("=")[1].strip()
|
|
if "user=" in row:
|
|
apache_user = row.split("=")[1].strip()
|
|
if "password=" in row:
|
|
apache_pass = row.split("=")[1].strip()
|
|
if "use_server_status_metrics" in row:
|
|
use_server_status_metrics = row.split("=")[1].strip()
|
|
except IOError:
|
|
log.warn("\tUnable to read {:s}".format(config_location))
|
|
|
|
return apache_url, apache_user, apache_pass, use_server_status_metrics
|
|
|
|
def build_config(self):
|
|
"""Build the config as a Plugins object and return.
|
|
|
|
"""
|
|
config = monasca_setup.agent_config.Plugins()
|
|
# First watch the process
|
|
config.merge(monasca_setup.detection.watch_process(
|
|
[self._apache_process_name], 'apache'))
|
|
log.info("\tWatching the apache webserver process.")
|
|
|
|
error_msg = '\n\t*** The Apache plugin is not configured ***\n\tPlease correct and re-run monasca-setup.'
|
|
# Attempt login, requires either an empty root password from localhost
|
|
# or relying on a configured /root/.apache.cnf
|
|
if self.dependencies_installed():
|
|
# If any of the exact keys are present, use them.
|
|
if self.args and self.args.viewkeys() & CONFIG_ARG_KEYS:
|
|
log.info("Attempting to use command args")
|
|
apache_url = self.args.get("url", None)
|
|
apache_user = self.args.get("user", None)
|
|
apache_pass = self.args.get("password", None)
|
|
use_server_status_metrics = self.args.get('use_server_status_metrics', True)
|
|
elif self.args and self.args.get("apache_config_file"):
|
|
config_file = self.args.get("apache_config_file")
|
|
apache_url, apache_user, apache_pass, use_server_status_metrics = \
|
|
self._read_apache_config(config_file)
|
|
else:
|
|
apache_url, apache_user, apache_pass, use_server_status_metrics = \
|
|
self._read_apache_config(DEFAULT_APACHE_CONFIG)
|
|
if type(use_server_status_metrics) is str:
|
|
use_server_status_metrics = (use_server_status_metrics.lower() == 'true')
|
|
|
|
if use_server_status_metrics:
|
|
if not apache_url:
|
|
missing_url_msg = ('\tNo server-status url specified.' + error_msg)
|
|
log.error(missing_url_msg)
|
|
raise Exception(missing_url_msg)
|
|
else:
|
|
log.info("\tWatching the apache process only.")
|
|
return config
|
|
|
|
if apache_user and apache_pass:
|
|
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
|
|
password_mgr.add_password(None,
|
|
apache_url,
|
|
apache_user,
|
|
apache_pass)
|
|
handler = urllib2.HTTPBasicAuthHandler(password_mgr)
|
|
else:
|
|
if 'https' in apache_url:
|
|
handler = urllib2.HTTPSHandler()
|
|
else:
|
|
handler = urllib2.HTTPHandler()
|
|
|
|
opener = urllib2.build_opener(handler)
|
|
|
|
try:
|
|
request = opener.open(apache_url)
|
|
response = request.read()
|
|
request.close()
|
|
if 'Total Accesses:' in response:
|
|
instance_vars = {'name': apache_url, 'apache_status_url': apache_url}
|
|
if apache_user and apache_pass:
|
|
instance_vars.update({'apache_user': apache_user,
|
|
'apache_password': apache_pass})
|
|
config['apache'] = {'init_config': None, 'instances': [instance_vars]}
|
|
log.info("\tSuccessfully setup Apache plugin.")
|
|
else:
|
|
log.warn('Unable to access the Apache server-status URL;' + error_msg)
|
|
except urllib2.URLError as e:
|
|
exception_msg = (
|
|
'\tError {0} received when accessing url {1}.'.format(e.reason, apache_url) +
|
|
'\n\tPlease ensure the Apache web server is running and your configuration ' +
|
|
'information is correct.' + error_msg)
|
|
log.error(exception_msg)
|
|
raise Exception(exception_msg)
|
|
except Exception as e:
|
|
exception_msg = (
|
|
'Error received when accessing url {0} exception {1}'.format(apache_url, e) +
|
|
error_msg)
|
|
log.error(exception_msg)
|
|
raise Exception(exception_msg)
|
|
else:
|
|
log.error('\tThe dependencies for Apache Web Server are not installed or unavailable.' + error_msg)
|
|
|
|
return config
|
|
|
|
def dependencies_installed(self):
|
|
# No real dependencies to check
|
|
return True
|