diff options
author | Ramesh Nachimuthu <rnachimu@redhat.com> | 2014-03-28 17:48:54 +0530 |
---|---|---|
committer | Bala.FA <barumuga@redhat.com> | 2014-04-29 10:21:37 +0530 |
commit | 05278f31d54d89ef0a68e94af389d66a3c3b6f74 (patch) | |
tree | 933d5ece03e544b190a5fac9a97d5b647b41d748 /plugins | |
parent | b0f3cfc18011f149e1ce4b885fd47a6828a3c2ca (diff) |
AutoDiscovery: Auto discovery for gluster entities
Basic plugin which will discover all the basic gluster entities
and creates nagios configuration.
Change-Id: I71f05dec9bcce74969db300393f7f7c178161dba
Signed-off-by: Ramesh Nachimuthu <rnachimu@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/22100
Reviewed-by: Sahina Bose <sabose@redhat.com>
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/Makefile.am | 2 | ||||
-rw-r--r-- | plugins/config_generator.py | 186 | ||||
-rw-r--r-- | plugins/constants.py.in | 5 | ||||
-rwxr-xr-x | plugins/discovery.py | 138 |
4 files changed, 331 insertions, 0 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 3787e9a..5606fb3 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -6,6 +6,8 @@ dist_glusternagiosplugins_PYTHON = \ gluster_host_service_handler.py \ livestatus.py \ notify_ovirt_engine_handler.py \ + discovery.py \ + config_generator.py \ $(NULL) EXTRA_DIST = \ diff --git a/plugins/config_generator.py b/plugins/config_generator.py new file mode 100644 index 0000000..041ee8b --- /dev/null +++ b/plugins/config_generator.py @@ -0,0 +1,186 @@ +#!/usr/bin/python +# +# config_generator.py - Nagios configuration generator for gluster +# entities. Copyright (C) 2014 Red Hat Inc +# +# This program 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; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# + +from jinja2 import Environment, FileSystemLoader +import os +import shutil + + +class GlusterNagiosConfManager: + + def __init__(self, configDir, configTemplateDir, hostTemplateName): + self.configDir = configDir + self.configTemplateDir = configTemplateDir + self.hostTemplateName = hostTemplateName + self.__loadJinja() + + def __loadJinja(self): + self.jinjaEnv = Environment( + loader=FileSystemLoader(self.configTemplateDir)) + self.hostTemplate = self.jinjaEnv.get_template(self.hostTemplateName) + + def __createHostConfig(self, host): + hostConfigStr = self.hostTemplate.render(host=host) + hostConfig = {'name': host['host_name'], 'config': hostConfigStr} + return hostConfig + + def createHost(self, hostName, alias, template, + address, hostGroups, checkCommand, services): + host = {} + host['host_name'] = hostName + host['alias'] = alias + host['use'] = template + host['address'] = address + if checkCommand is not None: + host['check_command'] = checkCommand + if hostGroups is not None: + host['hostgroups'] = hostGroups + + if services is not None: + host['host_services'] = services + return host + + def __createVolumeUtilizationService(self, volume, clusterName): + volumeService = {} + volumeService['host_name'] = clusterName + volumeService['use'] = 'gluster-service-with-graph' + serviceDesc = 'Volume Utilization - %s' % (volume['name']) + volumeService['service_description'] = serviceDesc + volumeService['_VOL_NAME'] = volume['name'] + checkCommand = 'check_vol_utilization!%s!%s!70!90' % \ + (clusterName, volume['name']) + volumeService['check_command'] = checkCommand + volumeService['notes'] = "Volume type : %s" % (volume['typeStr']) + return volumeService + + def __createVolumeStatusService(self, volume, clusterName): + volumeService = {} + volumeService['host_name'] = clusterName + volumeService['use'] = 'gluster-service-with-graph' + serviceDesc = 'Volume Status - %s' % (volume['name']) + volumeService['service_description'] = serviceDesc + volumeService['_VOL_NAME'] = volume['name'] + checkCommand = 'check_vol_utilization!%s!%s!70!90' % \ + (clusterName, volume['name']) + volumeService['check_command'] = checkCommand + volumeService['notes'] = "Volume type : %s" % (volume['typeStr']) + return volumeService + + def createClusterUtilizationService(self, clusterName): + service = {} + service['host_name'] = clusterName + service['use'] = 'gluster-service-with-graph' + service['service_description'] = 'Cluster Utilization' + service['check_command'] = 'check_cluster_vol_usage!80!90' + return service + + def createClusterAutoConfigService(self, clusterName, hostIp): + service = {} + service['host_name'] = clusterName + service['use'] = 'generic-service' + service['service_description'] = 'Cluster Auto Config' + service['check_command'] = "gluster_auto_discovery!%s!%s" % ( + hostIp, clusterName) + service['check_interval'] = '1440' + return service + + def createrVolumeServices(self, volumes, clusterName): + volumeServices = [] + for volume in volumes: + volumeService = self.__createVolumeUtilizationService(volume, + clusterName) + volumeServices.append(volumeService) + return volumeServices + + def __createBrickUtilizationService(self, brick, hostName): + brickService = {} + brickService['use'] = 'brick-service' + brickService['host_name'] = hostName + serviceDesc = "Brick-%s:%s" % (hostName, brick['brickpath']) + brickService['service_description'] = serviceDesc + brickService['display_name'] = serviceDesc + brickService['_BRICK_DIR'] = brick['brickpath'] + return brickService + + def __createBrickStatusService(self, brick, hostName): + brickService = {} + brickService['use'] = 'brick-service' + brickService['host_name'] = hostName + serviceDesc = "Brick-%s:%s-Status" % (hostName, brick['brickpath']) + brickService['service_description'] = serviceDesc + brickService['display_name'] = serviceDesc + brickService['_BRICK_DIR'] = brick['brickpath'] + return brickService + + def createBrickServices(self, host): + brickServices = [] + for brick in host['bricks']: + brickService = self.__createBrickUtilizationService( + brick, host['hostip']) + brickServices.append(brickService) + return brickServices + + def generateNagiosConfigFromGlusterCluster(self, cluster): + hostsConfigs = [] + clusterServices = self.createrVolumeServices( + cluster.get('volumes'), cluster['name']) + clusterServices.append(self.createClusterUtilizationService( + cluster['name'])) + clusterServices.append(self.createClusterAutoConfigService( + cluster['name'], cluster['hosts'][0]['hostip'])) + clusterHostConfig = self.createHost( + cluster['name'], cluster['name'], "gluster-cluster", + cluster['name'], "", "check_dummy", clusterServices) + hostsConfigs.append(clusterHostConfig) + for host in cluster['hosts']: + brickServices = self.createBrickServices(host) + hostGroups = "gluster_hosts,%s" % (cluster['name']) + hostConfig = self.createHost( + host['hostip'], host['hostip'], "gluster-host", + host['hostip'], hostGroups, "", brickServices) + hostsConfigs.append(hostConfig) + self.generateConfigFiles(hostsConfigs) + return hostsConfigs + + def generateConfigFiles(self, hosts): + clusterConfig = {'name': None, 'hostConfigs': []} + clusterConfigDir = None + for host in hosts: + if host['use'] == 'gluster-cluster': + clusterConfigDir = self.configDir + "/" + host['host_name'] + self.__prepareConfDir(clusterConfigDir) + clusterConfig['name'] = host['host_name'] + hostConfig = self.__createHostConfig(host) + clusterConfig['hostConfigs'].append(hostConfig) + for hostConfig in clusterConfig['hostConfigs']: + self.__writeHostConfig(clusterConfigDir, hostConfig) + + def __prepareConfDir(self, confDir): + if os.path.exists(confDir): + # Deleting the config dir to write new configs + shutil.rmtree(confDir) + os.mkdir(confDir) + + def __writeHostConfig(self, clusterConfigDir, hostConfig): + if clusterConfigDir is None: + raise Exception("Cluster configuration directory can't None") + configFilePath = clusterConfigDir + "/" + hostConfig['name'] + ".cfg" + with open(configFilePath, 'w') as configFile: + configFile.write(hostConfig['config']) diff --git a/plugins/constants.py.in b/plugins/constants.py.in index 40dd304..bf649de 100644 --- a/plugins/constants.py.in +++ b/plugins/constants.py.in @@ -1 +1,6 @@ LIVESTATUS_SOCKETPATH = "@nagioslivestatussocketpath@" +DEFAULT_AUTO_CONFIG_DIR = "@glusterautoconfdir@" +HOST_TEMPLATE_DIR = "@glusterhostconfigtemplatedir@" +HOST_TEMPLATE_NAME = "gluster-host.cfg.template" +NRPE_PATH = "@nrpepath@" +NAGIOS_COMMAND_FILE_PATH = "@nagioscommandfilepath@" diff --git a/plugins/discovery.py b/plugins/discovery.py new file mode 100755 index 0000000..3fd5573 --- /dev/null +++ b/plugins/discovery.py @@ -0,0 +1,138 @@ +#!/usr/bin/python +# discovery.py Nagios plugin to discover Gluster entities using NRPE +# Copyright (C) 2014 Red Hat Inc +# +# This program 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; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# +import argparse +import commands +import json +import datetime +import re +from config_generator import GlusterNagiosConfManager + +#from glusternagios import utils +from constants import DEFAULT_AUTO_CONFIG_DIR +from constants import HOST_TEMPLATE_DIR +from constants import HOST_TEMPLATE_NAME +from constants import NRPE_PATH +from constants import NAGIOS_COMMAND_FILE_PATH + + +def excecNRPECommand(command): + """ + This function executes NRPE command and return the result + """ + status = commands.getoutput(command) + return status + + +def discoverhostdetails(host, args): + hostparamsdict = {} + command = NRPE_PATH + " -H " + host + " -c discoverhostparams" + hostparams = excecNRPECommand(command) + #convert to dictionary + try: + hostparamsdict = json.loads(hostparams) + except Exception, e: + e.args += (hostparams,) + raise + return hostparamsdict + + +def discoverlogicalcomponents(host): + componentlist = [] + command = NRPE_PATH + " -H " + host + " -c discoverlogicalcomponents" + components = excecNRPECommand(command) + try: + componentlist = json.loads(components) + except Exception, e: + e.args += (components,) + #print e.args + raise + return componentlist + + +def discovercluster(args): + """ + + :rtype : None + """ + ipPat = re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$") + clusterdata = {} + #Discover the logical components + componentlist = discoverlogicalcomponents(args.hostip) + #Discover the peers + command = NRPE_PATH + " -H " + args.hostip + " -c discoverpeers" + hosts = excecNRPECommand(command) + hostlist = json.loads(hosts) + + #Add the ip address of the root node to the peer list + #to generate the configuration + hostlist.append({"hostip": args.hostip}) + for host in hostlist: + if(ipPat.match(host['hostip'])): + host.update(discoverhostdetails(host['hostip'], args)) + #Get the list of bricks for this host and add to dictionary + host['bricks'] = \ + [brick for brick in componentlist + if brick["hostip"] == host['hostip']] + clusterdata['hosts'] = hostlist + clusterdata['volumes'] =\ + [volume for volume in componentlist + if volume["srvctype"] == "volume"] + clusterdata['name'] = args.cluster + return clusterdata + + +def parse_input(): + parser = argparse.ArgumentParser(description="Gluster Auto Discover Tool") + parser.add_argument('-c', '--cluster', action='store', dest='cluster', + type=str, required=True, help='Cluster name') + parser.add_argument('-H', '--hostip', action='store', dest='hostip', + type=str, required=True, help='Host IP') + parser.add_argument('-d', '--configdir', action='store', dest='configDir', + type=str, required=False, + help='Configuration directory ' + 'where output files will be written') + args = parser.parse_args() + return args + + +def getConfigManager(args): + configDir = DEFAULT_AUTO_CONFIG_DIR + if args.configDir is not None: + configDir = args.configDir + configManager = GlusterNagiosConfManager( + configDir, HOST_TEMPLATE_DIR, HOST_TEMPLATE_NAME) + return configManager + + +def __restartNagios(): + now = datetime.datetime.now() + cmdStr = "[%s] RESTART_PROGRAM\n" % (now) + with open(NAGIOS_COMMAND_FILE_PATH, "w") as f: + f.write(cmdStr) + + +if __name__ == '__main__': + args = parse_input() + clusterdata = discovercluster(args) + configManager = getConfigManager(args) + clusterConfing = configManager.generateNagiosConfigFromGlusterCluster( + clusterdata) + print " Cluster configurations re-synced successfully from host %s" % \ + (args.hostip) + __restartNagios() |