Added Compass CLI and health check modules

1. Added comments, removed typos.
2. Updated github urls to stackforge
3. Added setting.py
Amend: Run pep8 and fix styling issues.
Change-Id: Ice0ba0964207827f683c27734f78b43b6a522392
This commit is contained in:
Xicheng Chang 2014-01-21 22:36:28 -08:00
parent d2fec0205f
commit ccefdc1b6f
17 changed files with 1494 additions and 0 deletions

6
bin/compass Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/python
import sys
import compass.actions.cli as cli
sys.exit(cli.main())

146
compass/actions/cli.py Normal file
View File

@ -0,0 +1,146 @@
"""Compass Command Line Interface"""
import sys
import os
from subprocess import Popen
from compass.actions.health_check import check
from compass.utils.util import pretty_print
ACTION_MAP = {"check": "apache celery dhcp dns hds misc os_installer "
"package_installer squid tftp".split(" "),
"refresh": "db sync".split(" "),
}
class BootCLI:
def __init__(self):
return
def run(self, args):
"""
cli takes the commands and calls respective modules
"""
action = self.get_action(args)
if action is None:
self.print_help()
else:
module = self.get_module(action, args)
if module == "invalid":
self.print_help(action)
else:
method = "self.run_" + action + "(module)"
eval(method)
def get_action(self, args):
"""
This method returns an action type.
For 'compass check dhcp' command, it will return 'check'.
"""
if len(args) == 1:
return None
elif args[1] in ACTION_MAP.keys():
return args[1]
return None
def get_module(self, action, args):
"""
This method returns a module.
For 'compass check dhcp' command, it will return 'dhcp'.
"""
if len(args) <= 2:
return None
elif args[2] in ACTION_MAP[action]:
return args[2]
return "invalid"
def run_check(self, module=None):
"""
param module default set to None.
This provides a flexible sanity check,
if parameter module is none. Compass checks all modules.
If module specified, Compass will only check such module.
"""
if module is None:
pretty_print("Starting: Compass Health Check",
"==============================")
c = check.BootCheck()
res = c.run()
self.output_check_result(res)
else:
pretty_print("Checking Module: %s" % module,
"============================")
c = check.BootCheck()
method = "c.check_" + module + "()"
res = eval(method)
print "\n".join(msg for msg in res[1])
def output_check_result(self, result):
if result == {}:
return
pretty_print("\n",
"===============================",
"* Compass Health Check Report *",
"===============================")
successful = True
num = 1
for key in result.keys():
if result[key][0] == 0:
successful = False
print "%s" % "\n".join(item for item in result[key][1])
print "===================="
if successful is True:
print "Compass Check completes. No problems found, all systems go"
else:
print "Compass has ERRORS shown above. Please fix them before " \
"deploying!"
def run_refresh(self, action=None):
## TODO: replace refresh.sh with refresh.py
if action is None:
pretty_print("Refreshing Compass...",
"=================")
Popen(['/opt/compass/bin/refresh.sh'], shell=True)
elif action == "db":
pretty_print("Refreshing Compass Database...",
"===================")
Popen(['/opt/compass/bin/manage_db.py createdb'], shell=True)
else:
pretty_print("Syncing with Installers...",
"================")
Popen(['/opt/compass/bin/manage_db.py sync_from_installers'],
shell=True)
def print_help(self, module_help=""):
if module_help == "":
pretty_print("usage\n=====",
"compass <refresh|check>",
"type 'compass {action} --help' for detailed "
"command list")
elif module_help == "refresh":
pretty_print("usage\n=====",
"compass refresh [%s]" %
"|".join(action for action in ACTION_MAP['refresh']))
else:
pretty_print("usage\n=====",
"compass check [%s]" %
"|".join(action for action in ACTION_MAP['check']))
sys.exit(2)
def main():
"""
Compass cli entry point
"""
cli = BootCLI()
output = cli.run(sys.argv)
return sys.exit(output)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,22 @@
"""Base class for Compass Health Check"""
import compass.utils.setting_wrapper as setting
import utils as health_check_utils
from compass.utils.util import pretty_print
class BaseCheck:
def __init__(self):
self.config = setting
self.code = 1
self.messages = []
self.dist, self.version, self.release = health_check_utils.get_dist()
def _set_status(self, code, message):
self.code = code
self.messages.append(message)
def get_status(self):
return (self.code, self.messages)

View File

@ -0,0 +1,71 @@
"""Main Entry Point of Compass Health Check"""
import check_apache as apache
import check_celery as celery
import check_dhcp as dhcp
import check_dns as dns
import check_hds as hds
import check_os_installer as os_installer
import check_package_installer as package_installer
import check_squid as squid
import check_tftp as tftp
import check_misc as misc
import base
class BootCheck(base.BaseCheck):
def run(self):
status = {}
status['apache'] = self.check_apache()
status['celery'] = self.check_celery()
status['dhcp'] = self.check_dhcp()
status['dns'] = self.check_dns()
status['hds'] = self.check_hds()
status['os_installer'] = self.check_os_installer()
status['package_installer'] = self.check_package_installer()
status['squid'] = self.check_squid()
status['tftp'] = self.check_tftp()
status['other'] = self.check_misc()
return status
def check_apache(self):
checker = apache.ApacheCheck()
return checker.run()
def check_celery(self):
checker = celery.CeleryCheck()
return checker.run()
def check_dhcp(self):
checker = dhcp.DhcpCheck()
return checker.run()
def check_dns(self):
checker = dns.DnsCheck()
return checker.run()
def check_hds(self):
checker = hds.HdsCheck()
return checker.run()
def check_os_installer(self):
checker = os_installer.OsInstallerCheck()
return checker.run()
def check_package_installer(self):
checker = package_installer.PackageInstallerCheck()
return checker.run()
def check_squid(self):
checker = squid.SquidCheck()
return checker.run()
def check_tftp(self):
checker = tftp.TftpCheck()
return checker.run()
def check_misc(self):
checker = misc.MiscCheck()
return checker.run()

View File

@ -0,0 +1,84 @@
"""Health Check module for Apache service"""
import os
import re
import commands
import urllib2
from socket import *
import utils as health_check_utils
import base
import logging
class ApacheCheck(base.BaseCheck):
NAME = "Apache Check"
def run(self):
if self.dist in ("centos", "redhat", "fedora", "scientific linux"):
apache_service = 'httpd'
else:
apache_service = 'apache2'
self.check_apache_conf(apache_service)
print "[Done]"
self.check_apache_running(apache_service)
print "[Done]"
if self.code == 1:
self.messages.append(
"[%s]Info: Apache health check has completed. "
"No problems found, all systems go." % self.NAME)
return (self.code, self.messages)
def check_apache_conf(self, apache_service):
"""
Validates if Apache settings.
:param apache_service : service type of apache, os dependent.
e.g. httpd or apache2
:type apache_service : string
"""
print "Checking Apache Config......",
conf_err_msg = health_check_utils.check_path(
self.NAME,
"/etc/%s/conf.d/ods-server.conf" % apache_service)
if not conf_err_msg == "":
self._set_status(0, conf_err_msg)
wsgi_err_msg = health_check_utils.check_path(
self.NAME,
'/var/www/compass/compass.wsgi')
if not wsgi_err_msg == "":
self._set_status(0, wsgi_err_msg)
return True
def check_apache_running(self, apache_service):
"""Checks if Apache service is running on port 80"""
print "Checking Apache service......",
serv_err_msg = health_check_utils.check_service_running(self.NAME,
apache_service)
if not serv_err_msg == "":
self._set_status(0, serv_err_msg)
if 'http' != getservbyport(80):
self._set_status(
0,
"[%s]Error: Apache is not listening on port 80."
% self.NAME)
try:
html = urllib2.urlopen('http://localhost')
content = html.geturl()
if "http://localhost/ods/ods.html" != content:
self._set_status(
0,
"[%s]Error: Compass web is not redirected by Apache.")
except:
self._set_status(
0,
"[%s]Error: Apache is not running on Port 80."
% self.NAME)
return True

View File

@ -0,0 +1,107 @@
"""Health Check module for Celery"""
import os
import re
import commands
import base
import utils as health_check_utils
from celery.task.control import inspect
class CeleryCheck(base.BaseCheck):
NAME = "Celery Check"
def run(self):
self.check_compass_celery_setting()
print "[Done]"
self.check_celery_backend()
print "[Done]"
if self.code == 1:
self.messages.append("[%s]Info: Celery health check "
"has completed. No problems found, "
"all systems go." % self.NAME)
return (self.code, self.messages)
def check_compass_celery_setting(self):
"""Validates Celery settings"""
print "Checking Celery setting......",
SETTING_MAP = {'logfile': 'CELERY_LOGFILE',
'configdir': 'CELERYCONFIG_DIR',
'configfile': 'CELERYCONFIG_FILE',
}
res = health_check_utils.validate_setting('Celery',
self.config,
'CELERY_LOGFILE')
if res is True:
logfile = self.config.CELERY_LOGFILE
else:
logfile = ""
self._set_status(0, res)
res = health_check_utils.validate_setting('Celery',
self.config,
'CELERYCONFIG_DIR')
if res is True:
configdir = self.config.CELERYCONFIG_DIR
else:
configdir = ""
self._set_status(0, res)
res = health_check_utils.validate_setting('Celery',
self.config,
'CELERYCONFIG_FILE')
if res is True:
configfile = self.config.CELERYCONFIG_FILE
else:
configfile = ""
self._set_status(0, res)
unset = []
for item in ['logfile', 'configdir', 'configfile']:
if eval(item) == "":
unset.append(SETTING_MAP[item])
if len(unset) != 0:
self._set_status(0,
"[%s]Error: Unset celery settings: %s"
" in /etc/compass/setting"
% (self.NAME, ', '.join(item for item in unset)))
return True
def check_celery_backend(self):
"""Checks if Celery backend is running and configured properly"""
print "Checking Celery Backend......",
if not 'celeryd' in commands.getoutput('ps -ef'):
self._set_status(0, "[%s]Error: celery is not running" % self.NAME)
return True
if not os.path.exists('/etc/compass/celeryconfig'):
self._set_status(
0,
"[%s]Error: No celery config file found for Compass"
% self.NAME)
return True
try:
insp = inspect()
celery_stats = inspect.stats(insp)
if not celery_stats:
self._set_status(
0,
"[%s]Error: No running Celery workers were found."
% self.NAME)
except IOError as e:
self._set_status(
0,
"[%s]Error: Failed to connect to the backend: %s"
% (self.NAME, str(e)))
from errno import errorcode
if len(e.args) > 0 and errorcode.get(e.args[0]) == 'ECONNREFUSED':
self.messages.append(
"[%s]Error: RabbitMQ server isn't running"
% self.NAME)
return True

View File

@ -0,0 +1,137 @@
"""Health Check module for DHCP service"""
import os
import re
import commands
import xmlrpclib
import sys
from socket import *
import base
class DhcpCheck(base.BaseCheck):
NAME = "DHCP Check"
def run(self):
installer = self.config.OS_INSTALLER
method_name = "self.check_" + installer + "_dhcp()"
return eval(method_name)
def check_cobbler_dhcp(self):
"""Checks if Cobbler has taken over DHCP service"""
try:
self.remote = xmlrpclib.Server(
self.config.COBBLER_INSTALLER_URL,
allow_none=True)
self.token = self.remote.login(
*self.config.COBBLER_INSTALLER_TOKEN)
except:
self._set_status(
0,
"[%s]Error: Cannot login to Cobbler with "
"the tokens provided in the config file" % self.NAME)
return (self.code, self.messages)
cobbler_settings = self.remote.get_settings()
if cobbler_settings['manage_dhcp'] == 0:
self.messages.append(
"[DHCP]Info: DHCP service is not managed by Compass")
return (self.code, self.messages)
self.check_cobbler_dhcp_template()
print "[Done]"
self.check_dhcp_service()
print "[Done]"
if self.code == 1:
self.messages.append(
"[%s]Info: DHCP health check has completed. "
"No problems found, all systems go." % self.NAME)
return (self.code, self.messages)
def check_cobbler_dhcp_template(self):
"""Validates Cobbler's DHCP template file"""
print "Checking DHCP template......",
if os.path.exists("/etc/cobbler/dhcp.template"):
VAR_MAP = {"match_next_server": False,
"match_subnet": False,
"match_filename": False,
"match_range": False,
}
ip_regex = re.compile('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
f = open("/etc/cobbler/dhcp.template")
for line in f.readlines():
if line.find("next_server") != -1:
elmlist = line.split(" ")
for elm in elmlist:
if ";" in elm:
elm = elm[:-2]
if "$next_server" in elm or ip_regex.match(elm):
VAR_MAP["match_next_server"] = True
elif line.find("subnet") != -1 and line.find("{") != -1:
elmlist = line.split(" ")
for elm in elmlist:
if ip_regex.match(elm):
if elm[-1] == "0" and "255" not in elm:
VAR_MAP["match_subnet"] = True
elif elm[-1] != "0":
self.messages.append(
"[%s]Error: Subnet should be set "
"in the form of 192.168.0.0 in"
"/etc/cobbler/dhcp.template"
% self.NAME)
elif line.find("filename") != -1:
VAR_MAP["match_filename"] = True
elif line.find("range dynamic-bootp") != -1:
elmlist = line.split(" ")
ip_count = 0
for elm in elmlist:
if ";" in elm and "\n" in elm:
elm = elm[:-2]
if ip_regex.match(elm):
ip_count += 1
if ip_count != 2:
self.messages.append(
"[%s]Error: DHCP range should be set "
"between two IP addresses in "
"/etc/cobbler/dhcp.template" % self.NAME)
else:
VAR_MAP["match_range"] = True
f.close()
failed = []
for var in VAR_MAP.keys():
if VAR_MAP[var] is False:
failed.append(var)
if len(failed) != 0:
self._set_status(0,
"[%s]Info: DHCP template file "
"failed components: %s"
% (self.NAME, ' '.join(f for f in failed)))
else:
self._set_status(0,
"[%s]Error: DHCP template file doesn't exist, "
"health check failed." % self.NAME)
return True
def check_dhcp_service(self):
"""Checks if DHCP is running on port 67"""
print "Checking DHCP service......",
if not 'dhcp' in commands.getoutput('ps -ef'):
self._set_status(
0,
"[%s]Error: dhcp service does not seem to be running"
% self.NAME)
if getservbyport(67) != 'bootps':
self._set_status(
0,
"[%s]Error: bootps is not listening on port 67"
% self.NAME)
return True

View File

@ -0,0 +1,120 @@
"""Health Check module for DNS service"""
import os
import re
import xmlrpclib
import commands
from socket import *
import base
class DnsCheck(base.BaseCheck):
NAME = "DNS Check"
def run(self):
installer = self.config.OS_INSTALLER
method_name = "self.check_" + installer + "_dns()"
return eval(method_name)
def check_cobbler_dns(self):
"""Checks if Cobbler has taken over DNS service"""
try:
self.remote = xmlrpclib.Server(
self.config.COBBLER_INSTALLER_URL,
allow_none=True)
self.token = self.remote.login(
*self.config.COBBLER_INSTALLER_TOKEN)
except:
self._set_status(0,
"[%s]Error: Cannot login to Cobbler "
"with the tokens provided in the config file"
% self.NAME)
return (self.code, self.messages)
cobbler_settings = self.remote.get_settings()
if cobbler_settings['manage_dns'] == 0:
self.messages.append('[DNS]Info: DNS is not managed by Compass')
return (self.code, self.messages)
self.check_cobbler_dns_template()
print "[Done]"
self.check_dns_service()
print "[Done]"
if self.code == 1:
self.messages.append(
"[%s]Info: DNS health check has complated. "
"No problems found, all systems go." % self.NAME)
return (self.code, self.messages)
def check_cobbler_dns_template(self):
"""Validates Cobbler's DNS template file"""
print "Checking DNS template......",
if os.path.exists("/etc/cobbler/named.template"):
VAR_MAP = {"match_port": False,
"match_allow_query": False,
}
f = open("/etc/cobbler/named.template")
host_ip = gethostbyname(gethostname())
missing_query = []
for line in f.readlines():
if "listen-on port 53" in line and host_ip in line:
VAR_MAP["match_port"] = True
if "allow-query" in line:
for subnet in ["127.0.0.0/8",
"10.0.0.0/8",
"192.168.0.0/16",
"172.16.0.0/12"]:
if not subnet in line:
missing_query.append(subnet)
f.close()
if VAR_MAP["match_port"] is False:
self.messages.append(
"[%s]Error: named service port and/or IP is "
"misconfigured in /etc/cobbler/named.template"
% self.NAME)
if len(missing_query) != 0:
self.messages.append(
"[%s]Error: Missing allow_query values in "
"/etc/cobbler/named.template:%s"
% (self.Name,
', '.join(subnet for subnet in missing_query)))
else:
VAR_MAP["match_allow_query"] = True
failed = []
for var in VAR_MAP.keys():
if VAR_MAP[var] is False:
failed.append(var)
if len(failed) != 0:
self._set_status(
0,
"[%s]Info: DNS template failed components: %s"
% (self.NAME, ' '.join(f for f in failed)))
else:
self._set_status(
0,
"[%s]Error: named template file doesn't exist, "
"health check failed." % self.NAME)
return True
def check_dns_service(self):
"""Checks if DNS is running on port 53"""
print "Checking DNS service......",
if not 'named' in commands.getoutput('ps -ef'):
self._set_status(
0,
"[%s]Error: named service does not seem to be running"
% self.NAME)
if getservbyport(53) != 'domain':
self._set_status(
0,
"[%s]Error: domain service is not listening on port 53"
% self.NAME)
return None

View File

@ -0,0 +1,74 @@
"""Health Check module for Hardware Discovery"""
import os
import re
import base
import utils as health_check_utils
class HdsCheck(base.BaseCheck):
NAME = "HDS Check"
def run(self):
if self.dist in ("centos", "redhat", "fedora", "scientific linux"):
pkg_type = "yum"
else:
pkg_type = "apt"
try:
pkg_module = __import__(pkg_type)
except:
self.messages.append("[HDS]Error: No module named %s, "
"please install it first." % pkg_module)
method_name = 'self.check_' + pkg_type + '_snmp(pkg_module)'
eval(method_name)
print "[Done]"
self.check_snmp_mibs()
print "[Done]"
if self.code == 1:
self.messages.append("[HDS]Info: hds health check has complated. "
"No problems found, all systems go.")
return (self.code, self.messages)
def check_yum_snmp(self, pkg_module):
"""
Check if SNMP yum dependencies are installed
:param pkg_module : python yum library
:type pkg_module : python module
"""
print "Checking SNMP Packages......",
yum_base = pkg_module.YumBase()
uninstalled = []
for package in ['net-snmp-utils', 'net-snmp', 'net-snmp-python']:
if not yum_base.rpmdb.searchNevra(name=package):
self.messages.append("[HDS]Error: %s package is required "
"for HDS" % package)
uninstalled.append(package)
if len(uninstalled) != 0:
self._set_status(0, "[%s]Info: Uninstalled packages: %s"
% (self.NAME,
', '.join(item for item in uninstalled)))
return True
def check_apt_snmp(self, pkg_module):
## TODO: add ubuntu package check here
return None
def check_snmp_mibs(self):
"""Checks if SNMP MIB files are properly placed"""
print "Checking SNMP MIBs......",
conf_err_msg = health_check_utils.check_path(self.NAME,
'/etc/snmp/snmp.conf')
if not conf_err_msg == "":
self._set_status(0, conf_err_msg)
mibs_err_msg = health_check_utils.check_path(
self.NAME,
'/usr/local/share/snmp/mibs')
if not mibs_err_msg == "":
self._set_status(0, mibs_err_msg)
return True

View File

@ -0,0 +1,206 @@
"""Miscellaneous Health Check for Compass"""
import os
import re
import commands
import base
import utils as health_check_utils
class MiscCheck(base.BaseCheck):
NAME = "Miscellaneous Check"
MISC_MAPPING = {
"yum": "rsyslog ntp iproute openssh-clients python git wget "
"python-setuptools python-netaddr python-flask "
"python-flask-sqlalchemy python-amqplib amqp "
"python-paramiko python-mock mod_wsgi httpd squid "
"dhcp bind rsync yum-utils xinetd tftp-server gcc "
"net-snmp-utils net-snmp python-daemon".split(" "),
"pip": "flask-script flask-restful celery six discover "
"unittest2 chef".replace("-", "_").split(" "),
"disable": "iptables ip6tables".split(" "),
"enable": "httpd squid xinetd dhcpd named sshd rsyslog cobblerd "
"ntpd compassd".split(" "),
}
def run(self):
self.check_linux_dependencies()
print "[Done]"
self.check_pip_dependencies()
print "[Done]"
self.check_ntp()
print "[Done]"
self.check_rsyslogd()
print "[Done]"
self.check_chkconfig()
print "[Done]"
self.check_selinux()
print "[Done]"
if self.code == 1:
self.messages.append(
"[%s]Info: Miscellaneous check has completed "
"No problems found, all systems go." % self.NAME)
return (self.code, self.messages)
def check_linux_dependencies(self):
"""Checks if dependencies are installed"""
print "Checking Linux dependencies....",
if self.dist in ("centos", "redhat", "fedora", "scientific linux"):
pkg_type = "yum"
else:
pkg_type = "apt"
try:
pkg_module = __import__(pkg_type)
except:
self._set_status(
0,
"[%s]Error: No module named %s, "
"please install it first." % (self.NAME, pkg_module))
method_name = 'self.check_' + pkg_type + '_dependencies(pkg_module)'
eval(method_name)
def check_yum_dependencies(self, pkg_module):
"""
Checks if yum dependencies are installed.
:param pkg_module : python yum library
:type pkg_module : python module
"""
print "Checking Yum dependencies......",
yum_base = pkg_module.YumBase()
uninstalled = []
for package in self.MISC_MAPPING["yum"]:
if not yum_base.rpmdb.searchNevra(name=package):
self._set_status(
0,
"[%s]Error: %s package is required"
% (self.NAME, package))
uninstalled.append(package)
if len(uninstalled) != 0:
self._set_status(
0,
"[%s]Info: Uninstalled yum packages: %s"
% (self.NAME, ', '.join(item for item in uninstalled)))
return True
def check_pip_dependencies(self):
"""Checks if required pip packages are installed"""
print "Checking pip dependencies......",
uninstalled = []
for module in self.MISC_MAPPING['pip']:
try:
__import__(module)
except:
self._set_status(
0,
"[%s]Error: pip package %s is requred"
% (self.NAME, module))
uninstalled.append(module)
if len(uninstalled) != 0:
self._set_status(
0,
"[%s]Info: Uninstalled pip packages: %s"
% (self.NAME, ', '.join(item for item in uninstalled)))
return True
def check_ntp(self):
"""Validates ntp configuration and service"""
print "Checking NTP......",
conf_err_msg = health_check_utils.check_path(self.NAME,
'/etc/ntp.conf')
if not conf_err_msg == "":
self._set_status(0, conf_err_msg)
serv_err_msg = health_check_utils.check_service_running(self.NAME,
'ntpd')
if not serv_err_msg == "":
self._set_status(0, serv_err_msg)
return True
def check_rsyslogd(self):
"""Validates rsyslogd configuration and service"""
print "Checking rsyslog......",
conf_err_msg = health_check_utils.check_path(self.NAME,
'/etc/rsyslog.conf')
if not conf_err_msg == "":
self._set_status(0, conf_err_msg)
dir_err_msg = health_check_utils.check_path(self.NAME,
'/etc/rsyslog.d/')
if not dir_err_msg == "":
self._set_status(0, dir_err_msg)
serv_err_msg = health_check_utils.check_service_running(self.NAME,
'rsyslogd')
if not serv_err_msg == "":
self._set_status(0, serv_err_msg)
return True
def check_chkconfig(self):
"""Check if required services are enabled on the start up"""
print "Checking chkconfig......",
serv_to_disable = []
for serv in self.MISC_MAPPING["disable"]:
if health_check_utils.check_chkconfig(serv) is True:
self._set_status(
0,
"[Miscellaenous Check]Error: %s is not disabled"
% serv)
serv_to_disable.append(serv)
if len(serv_to_disable) != 0:
self._set_status(
0,
"[%s]Info: You need to disable these services "
"on system start-up: %s"
% (self.NAME,
", ".join(item for item in serv_to_disable)))
serv_to_enable = []
for serv in self.MISC_MAPPING["enable"]:
if health_check_utils.check_chkconfig(serv) is False:
self._set_status(
0, "[%s]Error: %s is disabled" % (self.NAME, serv))
serv_to_enable.append(serv)
if len(serv_to_enable) != 0:
self._set_status(0, "[%s]Info: You need to enable these "
"services on system start-up: %s"
% (self.NAME,
", ".join(item for item in serv_to_enable)))
return True
def check_selinux(self):
"""Check if SELinux is disabled"""
print "Checking Selinux......",
f = open("/etc/selinux/config")
disabled = False
for line in f.readlines():
if "SELINUX=disabled" in line:
disabled = True
break
if disabled is False:
self._set_status(
0,
"[%s]Selinux is not disabled, "
"please disable it in /etc/selinux/config." % self.NAME)
return True

View File

@ -0,0 +1,113 @@
"""Compass Health Check module for OS Installer"""
import os
import re
import xmlrpclib
import base
class OsInstallerCheck(base.BaseCheck):
NAME = "OS Installer Check"
def run(self):
installer = self.config.OS_INSTALLER
method_name = 'self.' + installer + '_check()'
return eval(method_name)
def cobbler_check(self):
"""Runs cobbler check from xmlrpc client"""
try:
self.remote = xmlrpclib.Server(
self.config.COBBLER_INSTALLER_URL,
allow_none=True)
self.token = self.remote.login(
*self.config.COBBLER_INSTALLER_TOKEN)
except:
self.code = 0
self.messages.append(
"[OS Installer]Error: Cannot login to Cobbler with "
"the tokens provided in the config file")
self.messages.append(
"[OS Installer]Error: Failed to connect to Cobbler "
"API, please check if /etc/cobbler/setting "
"is properly configured")
return (self.code, self.messages)
check_result = self.remote.check(self.token)
if len(check_result) != 0:
self.code = 0
for error_msg in check_result:
self.messages.append("[OS Installer]Error: " + error_msg)
if len(self.remote.get_distros()) == 0:
self._set_status(0,
"[%s]Error: No Cobbler distros found" % self.NAME)
if len(self.remote.get_profiles()) == 0:
self._set_status(0,
"[%s]Error: No Cobbler profiles found"
% self.NAME)
found_ppa = False
if len(self.remote.get_repos()) != 0:
for repo in self.remote.get_repos():
if 'ppa_repo' in repo['mirror']:
found_ppa = True
break
if found_ppa is False:
self._set_status(0,
"[%s]Error: No repository ppa_repo found"
% self.NAME)
PATH_MAP = {'match_kickstart': ('/var/lib/cobbler/kickstarts/',
['default.ks', ]
),
'match_snippets': ('/var/lib/cobbler/snippets/',
[
'chef',
'chef-validator.pem',
'client.rb',
'first-boot.json',
'kickstart_done',
'kickstart_start',
'network_config',
'ntp.conf',
'partition_disks',
'partition_select',
'post_anamon',
'post_install_network_config',
'pre_anamon',
'pre_install_network_config',
'rsyslogchef',
'rsyslogconf',
'yum.conf',
]
),
'match_ks_mirror': ('/var/www/cobbler/',
['ks_mirror']
),
'match_repo_mirror': ('/var/www/cobbler/',
['repo_mirror/ppa_repo']
),
'match_iso': ('/var/lib/cobbler/', ['iso']),
}
not_exists = []
for key in PATH_MAP.keys():
for path in PATH_MAP[key][1]:
if not os.path.exists(PATH_MAP[key][0] + path):
not_exists.append(PATH_MAP[key][0] + path)
if len(not_exists) != 0:
self._set_status(
0,
"[%s]Error: These locations do not exist: %s"
% (self.NAME, ', '.join(item for item in not_exists)))
if self.code == 1:
self.messages.append(
"[OS Installer]Info: OS Installer health check "
"has completed. No problems found, all systems go.")
return (self.code, self.messages)

View File

@ -0,0 +1,120 @@
"""Health Check module for Package Installer"""
import os
import re
import requests
import base
import utils as health_check_utils
import setting as health_check_setting
class PackageInstallerCheck(base.BaseCheck):
NAME = "Package Installer Check"
def run(self):
installer = self.config.PACKAGE_INSTALLER
method_name = "self." + installer + "_check()"
return eval(method_name)
def chef_check(self):
"""Checks chef setting, cookbooks, databags and roles"""
CHEFDATA_MAP = {'CookBook': health_check_setting.COOKBOOKS,
'DataBag': health_check_setting.DATABAGS,
'Role': health_check_setting.ROLES,
}
total_missing = []
for data_type in CHEFDATA_MAP.keys():
total_missing.append(self.check_chef_data(data_type,
CHEFDATA_MAP[data_type]))
print "[Done]"
missing = False
for item in total_missing:
if item[1] != []:
missing = True
break
if missing is True:
messages = []
for item in total_missing:
messages.append("[%s]:%s"
% (item[0],
', '.join(missed for missed in item[1])))
self._set_status(
0,
"[%s]Error: Missing modules on chef server: %s. "
% (self.NAME, ' ;'.join(message for message in messages)))
self.check_chef_config_dir()
print "[Done]"
if self.code == 1:
self.messages.append(
"[%s]Info: Package installer health check "
"has completed. No problems found, all systems go."
% self.NAME)
return (self.code, self.messages)
def check_chef_data(self, data_type, github_url):
"""
Checks if chef cookbooks/roles/databags are correct.
:param data_type : chef data type
should be one of ['CookBook','DataBag','Role']
:type data_type : string
:param github_url : Latest chef data on stackforge/compass-adapters
:type github_url : string
"""
print "Checking Chef %s......" % (data_type.lower().strip() + 's'),
try:
import chef
except:
self._set_status(
0,
"[%s]Error: pychef is not installed." % self.NAME)
return self.get_status()
self.api_ = chef.autoconfigure()
github = set([item['name']
for item in
requests.get(github_url).json()])
if data_type == 'CookBook':
local = set(os.listdir('/var/chef/cookbooks'))
elif data_type == 'Role':
local = set([name
for
name, item
in
chef.Role.list(api=self.api_).iteritems()])
github = set([item['name'].replace(".rb", "")
for item in
requests.get(github_url).json()])
else:
local = set([item
for item in
eval('chef.' + data_type + '.list(api = self.api_)')])
diff = github - local
if len(diff) <= 0:
return (data_type, [])
else:
return (data_type, list(diff))
def check_chef_config_dir(self):
"""Validates chef configuration directories"""
print "Checking Chef configurations......",
message = health_check_utils.check_path(self.NAME, '/etc/chef-server/')
if not message == "":
self._set_status(0, message)
message = health_check_utils.check_path(self.NAME, '/opt/chef-server/')
if not message == "":
self._set_status(0, message)
return None

View File

@ -0,0 +1,106 @@
"""Health Check module for Squid service"""
import os
import re
import commands
import pwd
from socket import *
import base
import utils as health_check_utils
class SquidCheck(base.BaseCheck):
NAME = "Squid Check"
def run(self):
self.check_squid_files()
print "[Done]"
self.check_squid_service()
print "[Done]"
if self.code == 1:
self.messages.append(
"[%s]Info: Squid health check has completed. "
"No problems found, all systems go." % self.NAME)
return (self.code, self.messages)
def check_squid_files(self):
"""Validates squid config, cache directory and ownership"""
print "Checking Squid Files......",
VAR_MAP = {'match_squid_conf': False,
'match_squid_cache': False,
'match_squid_ownership': False,
}
conf_err_msg = health_check_utils.check_path(
self.NAME,
"/etc/squid/squid.conf")
if not conf_err_msg == "":
self._set_status(0, conf_err_msg)
elif int(oct(os.stat('/etc/squid/squid.conf').st_mode)) < 644:
self._set_status(
0,
"[%s]Error: squid.conf has incorrect "
"file permissions" % self.NAME)
else:
VAR_MAP['match_squid_conf'] = True
squid_path_err_msg = health_check_utils.check_path(
self.NAME,
'/var/squid/')
if not squid_path_err_msg == "":
self.set_stauts(0, squid_path_err_msg)
elif health_check_utils.check_path(self.NAME,
'/var/squid/cache') != "":
self._set_status(
0,
health_check_utils.check_path(
self.NAME,
'/var/squid/cache'))
else:
VAR_MAP['match_squid_cache'] = True
uid = os.stat('/var/squid/').st_uid
gid = os.stat('/var/squid/').st_gid
if uid != gid or pwd.getpwuid(23).pw_name != 'squid':
self._set_status(
0,
"[%s]Error: /var/squid directory ownership "
"misconfigured" % self.NAME)
else:
VAR_MAP['match_squid_ownership'] = True
failed = []
for key in VAR_MAP.keys():
if VAR_MAP[key] is False:
failed.append(key)
if len(failed) != 0:
self.messages.append(
"[%s]Info: Failed components for squid config: %s"
% (self.NAME, ', '.join(item for item in failed)))
return True
def check_squid_service(self):
"""Checks if squid is running on port 3128"""
print "Checking Squid service......",
if not 'squid' in commands.getoutput('ps -ef'):
self._set_status(
0,
"[%s]Error: squid service does not seem running"
% self.NAME)
try:
if 'squid' != getservbyport(3128):
self._set_status(
0,
"[%s]Error: squid is not listening on 3128"
% self.NAME)
except:
self._set_status(
0,
"[%s]Error: No service is listening on 3128, "
"squid failed" % self.NAME)
return True

View File

@ -0,0 +1,88 @@
"""Health Check module for TFTP service"""
import os
import re
import sys
import xmlrpclib
import commands
from socket import *
import base
import utils as health_check_utils
class TftpCheck(base.BaseCheck):
NAME = "TFTP Check"
def run(self):
installer = self.config.OS_INSTALLER
method_name = "self.check_" + installer + "_tftp()"
return eval(method_name)
def check_cobbler_tftp(self):
"""
Checks if Cobbler manages TFTP service
:note: we assume TFTP service is running at the
same machine where this health check runs at
"""
try:
self.remote = xmlrpclib.Server(
self.config.COBBLER_INSTALLER_URL,
allow_none=True)
self.token = self.remote.login(
*self.config.COBBLER_INSTALLER_TOKEN)
except:
self._set_status(
0,
"[%s]Error: Cannot login to Cobbler with the tokens "
" provided in the config file" % self.NAME)
return (self.code, self.messages)
cobbler_settings = self.remote.get_settings()
if cobbler_settings['manage_tftp'] == 0:
self.messages.append(
'[TFTP]Info: tftp service is not managed by Compass')
return (self.code, self.messages)
self.check_tftp_dir()
print "[Done]"
self.check_tftp_service()
print "[Done]"
if self.code == 1:
self.messages.append(
"[%s]Info: tftp service health check has completed. "
"No problems found, all systems go." % self.NAME)
return (self.code, self.messages)
def check_tftp_dir(self):
"""Validates TFTP directories and configurations"""
print "Checking TFTP directories......",
if not os.path.exists('/var/lib/tftpboot/'):
self._set_status(
0,
"[%s]Error: No tftp-boot libraries found, "
"please check if tftp server is properly "
"installed/managed" % self.NAME)
return True
def check_tftp_service(self):
"""Checks if TFTP is running on port 69"""
print "Checking TFTP services......",
serv_err_msg = health_check_utils.check_service_running(self.NAME,
'xinetd')
if not serv_err_msg == "":
self._set_status(0, serv_err_msg)
if 'tftp' != getservbyport(69):
self._set_status(
0,
"[%s]Error: tftp doesn't seem to be listening "
"on Port 60." % self.NAME)
return True

View File

@ -0,0 +1,6 @@
"""Health Check Settings"""
# Chef data on github
COOKBOOKS="https://api.github.com/repos/stackforge/compass-adapters/contents/chef/cookbooks"
ROLES="https://api.github.com/repos/stackforge/compass-adapters/contents/chef/roles"
DATABAGS="https://api.github.com/repos/stackforge/compass-adapters/contents/chef/databags"

View File

@ -0,0 +1,81 @@
"""Compass Health Check heavy-lifting utilities"""
import os
import platform
import commands
def validate_setting(module, setting, param):
"""
Checks if a Compass setting exists in the config file.
:param module : module name to be checked
:type module : string
:param setting : compass setting wrapper
:type setting : python module
:param param : settings defined in compass config file
:type param : string
"""
if hasattr(setting, param):
return True
else:
err_msg = "[%s]Error: no %s defined" % (module, param)
return err_msg
def get_dist():
"""Returns the operating system related information"""
os, version, release = platform.linux_distribution()
return (os.lower().strip(), version, release.lower().strip())
def check_path(module_name, path):
"""
Checks if a directory or file exisits.
:param module_name : module name to be checked
:type module_name : string
:param path : path of the directory of file
:type path : string
"""
err_msg = ""
if not os.path.exists(path):
err_msg = "[%s]Error: %s does not exsit, "
"please check your configurations." % (module_name, path)
return err_msg
def check_service_running(module_name, service_name):
"""
Checks if a certain service is running.
:param module_name : module name to be checked
:type module_name : string
:param service_name : service name to be checked
:type service_name : string
"""
err_msg = ""
if not service_name in commands.getoutput('ps -ef'):
err_msg = "[%s]Error: %s is not running." \
% (module_name, service_name)
return err_msg
def check_chkconfig(service_name):
"""
Checks if a service is enabled at the start up.
:param service_name : service name to be checked
:type service_name : string
"""
on = False
for service in os.listdir('/etc/rc3.d/'):
if service_name in service and 'S' in service:
on = True
break
return on

View File

@ -129,3 +129,10 @@ def flat_lists_with_possibility(lists):
max_index = list_possibility.index(max(list_possibility))
return output
def pretty_print(*contents):
if len(contents) == 0:
print ""
else:
print "\n".join(content for content in contents)