summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorRamesh Nachimuthu <rnachimu@redhat.com>2014-03-28 17:48:54 +0530
committerBala.FA <barumuga@redhat.com>2014-04-29 10:21:37 +0530
commit05278f31d54d89ef0a68e94af389d66a3c3b6f74 (patch)
tree933d5ece03e544b190a5fac9a97d5b647b41d748 /plugins
parentb0f3cfc18011f149e1ce4b885fd47a6828a3c2ca (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.am2
-rw-r--r--plugins/config_generator.py186
-rw-r--r--plugins/constants.py.in5
-rwxr-xr-xplugins/discovery.py138
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()