diff options
author | Ramesh Nachimuthu <rnachimu@redhat.com> | 2014-04-27 19:03:45 +0530 |
---|---|---|
committer | Bala.FA <barumuga@redhat.com> | 2014-04-29 10:21:37 +0530 |
commit | 0bb9c00a64b981d4b793f618c5dbda8337b99ce0 (patch) | |
tree | a08460e82155dfa2ce9a0b2c66c3aab1d2156780 /plugins/discovery.py | |
parent | 6e01d10fbc862478485168a83f3542bb249e341b (diff) |
auto config : Enhance the auto config to preserve user changes
Enhace the auto configuration in nagios to preserve the user
changes. pynag apis are used to read/write/update the nagios config
files.
Change-Id: I6820928fb2b0baff5d6e65c811a48b5ff718f9e3
Signed-off-by: Ramesh Nachimuthu <rnachimu@redhat.com>
Diffstat (limited to 'plugins/discovery.py')
-rwxr-xr-x | plugins/discovery.py | 291 |
1 files changed, 258 insertions, 33 deletions
diff --git a/plugins/discovery.py b/plugins/discovery.py index b2cc21a..3ee102b 100755 --- a/plugins/discovery.py +++ b/plugins/discovery.py @@ -18,24 +18,27 @@ # import argparse import json -import datetime + +import os +import shutil import sys from glusternagios import utils from config_generator import GlusterNagiosConfManager +import server_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 -import submit_external_command -serviceCmdPath = utils.CommandPath("service", "/sbin/service", ) +from config_generator import CHANGE_MODE_ADD +from config_generator import CHANGE_MODE_REMOVE +from config_generator import CHANGE_MODE_UPDATE + + nrpeCmdPath = utils.CommandPath("nrpe", NRPE_PATH, ) def excecNRPECommand(host, command): - output = {} (returncode, outputStr, err) = utils.execCmd([nrpeCmdPath.cmd, "-H", host, "-c", command]) #convert to dictionary @@ -48,13 +51,36 @@ def excecNRPECommand(host, command): def discoverCluster(hostip, cluster): + """ + This method helps to discover the nodes, volumes and bricks in the given + gluster. It uses NRPE commands to contact the gluster nodes. + + Assumptions: + First node returned by the "discoverpeers" NRPE command should be the same + node where "discoverpeers" is executed. + + Parameters + ---------- + hostip: Address of a node in the gluster cluster. + cluster: Cluster Name + + Returns + --------- + Returns cluster details in the following dictinary format + { + 'name': cluster-name, + 'volumes': [list-volumes], + 'host': [list-hosts] + } + each host in the list will a have list of bricks from the host. + """ + clusterdata = {} #Discover the logical components componentlist = excecNRPECommand(hostip, "discoverlogicalcomponents") #Discover the peers hostlist = excecNRPECommand(hostip, "discoverpeers") - #Add the ip address of the root node to the peer list - #to generate the configuration + #Add the ip address of the root node given by the user to the peer list hostlist[0]['hostip'] = hostip for host in hostlist: #Get host names @@ -70,16 +96,22 @@ def discoverCluster(hostip, cluster): clusterdata['hosts'] = hostlist clusterdata['volumes'] = componentlist['volumes'] clusterdata['name'] = cluster + #Host names returned by "discoverhostparams" supposed to be unique. So host + #name can be used to configure the host_name in nagios host. + #But if host names are not unique then we have to use IP address to + #configure host_name in nagios. if not isHostsNamesUnique(clusterdata): setHostNameWithIP(clusterdata) return clusterdata +# Set host address as the hostname def setHostNameWithIP(clusterdata): for host in clusterdata['hosts']: host['hostname'] = host['hostip'] +# Check host names are unique def isHostsNamesUnique(clusterdata): hostnames = {} for host in clusterdata['hosts']: @@ -90,51 +122,244 @@ def isHostsNamesUnique(clusterdata): return True +def getConfigManager(args): + configDir = DEFAULT_AUTO_CONFIG_DIR + if args.configDir is not None: + configDir = args.configDir + clusterConfigDir = configDir + "/" + args.cluster + configManager = GlusterNagiosConfManager(clusterConfigDir) + return configManager + + +#Find the given service in service list. +def findServiceInList(serviceList, serviceDescription): + for service in serviceList: + if service['service_description'] == serviceDescription: + return service + return None + + +#Find the given host in host list +def findHostInList(hostList, hostName): + for host in hostList: + if host['host_name'] == hostName: + return host + return None + + +#Find all deleted services in the host. +def findDeletedServices(host): + deletedService = [] + serviceConfigs = server_utils.getServiceConfigByHost(host['host_name']) + for serviceConfig in serviceConfigs: + service = findServiceInList(host['host_services'], + serviceConfig['service_description']) + if service is None: + deletedService.append( + {'service_description': serviceConfig['service_description'], + 'changeMode': CHANGE_MODE_REMOVE}) + return deletedService + + +#Check if auto config is changed. IP address in the check command will change +#when user runs the auto config using different host. +def findChangeInAutoConfig(newService, oldService): + if newService['check_command'] != oldService['check_command']: + changes = {} + changes['check_command'] = newService['check_command'] + changes['service_description'] = newService['service_description'] + changes['host_name'] = newService['host_name'] + changes['changeMode'] = CHANGE_MODE_UPDATE + return changes + return None + + +#Find all Added/Deleted services in the given host. +#Note: 'Cluster Auto Config' is a special service. When user runs the +#auto-config using different host instead what is used previously then we +#have to update the host ip in existing auto-config service. +def findServiceDelta(host): + serviceDelta = [] + for service in host['host_services']: + serviceConfig = server_utils.getServiceConfig( + service['service_description'], service['host_name']) + if serviceConfig is None: + service['changeMode'] = CHANGE_MODE_ADD + serviceDelta.append(service) + elif serviceConfig['service_description'] == "Cluster Auto Config": + changes = findChangeInAutoConfig(service, serviceConfig) + if changes: + serviceDelta.append(changes) + serviceDelta.extend(findDeletedServices(host)) + return serviceDelta + + +#Find newly added hosts and newly added services to the existing hosts +def findAddUpdateHosts(hosts): + delta = [] + for host in hosts: + hostConfing = server_utils.getHostConfigByName(host['host_name']) + if hostConfing is None: + host['changeMode'] = CHANGE_MODE_ADD + delta.append(host) + else: + serviceDelta = findServiceDelta(host) + if serviceDelta: + host['changeMode'] = CHANGE_MODE_UPDATE + host['host_services'] = serviceDelta + delta.append(host) + return delta + + +#Find deleted hosts in the given cluster. +def findDeletedHosts(hostgroup, hosts): + deletedHosts = [] + hostConfigs = server_utils.getHostConfigsForCluster(hostgroup) + for hostConfig in hostConfigs: + host = findHostInList(hosts, hostConfig['host_name']) + if host is None: + deletedHosts.append({'host_name': hostConfig['host_name'], + 'changeMode': CHANGE_MODE_REMOVE}) + return deletedHosts + + +#Find Added/Deleted/Updated hosts in cluster +def findHostDelta(clusterConfig): + hostDelta = [] + updated = findAddUpdateHosts(clusterConfig['_hosts']) + hostDelta.extend(updated) + hostDelta.extend(findDeletedHosts(clusterConfig['hostgroup_name'], + clusterConfig['_hosts'])) + return hostDelta + + +#Find changes to the cluster +def findDelta(clusterConfig): + delta = {} + delta['hostgroup_name'] = clusterConfig['hostgroup_name'] + delta['alias'] = clusterConfig['alias'] + + hostgroup = server_utils.getHostGroup(clusterConfig['hostgroup_name']) + if hostgroup is None: + delta['changeMode'] = CHANGE_MODE_ADD + delta['_hosts'] = clusterConfig['_hosts'] + return delta + + hostDelta = findHostDelta(clusterConfig) + delta['_hosts'] = hostDelta + if hostDelta: + delta['changeMode'] = CHANGE_MODE_UPDATE + return delta + + 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('-m', '--mode', action='store', dest='mode', + choices=['auto', 'manual'], required=False, + default='manual', help='Mode') parser.add_argument('-d', '--configdir', action='store', dest='configDir', type=str, required=False, - help='Configuration directory ' - 'where output files will be written') + default=DEFAULT_AUTO_CONFIG_DIR, + help='Configuration directory where' + ' output files will be written') + parser.add_argument('-f', '--force', action='store_true', dest='force', + help="Force sync the Cluster configuration") 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 +#Clean the config directory +def cleanConfigDir(dir): + if os.path.exists(dir): + # Deleting the config dir to write new configs + shutil.rmtree(dir) + os.mkdir(dir) -def _restartNagios(): - now = datetime.datetime.now() - cmdStr = "[%s] RESTART_PROGRAM\n" % (now) - submit_external_command.submitExternalCommand(cmdStr) +#Preview the changes to cluster config +def previewChanges(clusterDelta): + print "Changes :" + clusterChangeMode = clusterDelta['changeMode'] + print "Hostgroup %s - %s" % (clusterDelta['hostgroup_name'], + clusterChangeMode) + for host in clusterDelta['_hosts']: + if host.get('changeMode'): + changeMode = host.get('changeMode') + else: + changeMode = clusterChangeMode + print "Host %s - %s" % (host['host_name'], changeMode) + for service in host.get('host_services'): + if service.get('changeMode'): + changeMode = service.get('changeMode') + print "\t Service - %s -%s " % (service['service_description'], + changeMode) -def _isNagiosRunning(): - (rc, out, err) = utils.execCmd([serviceCmdPath.cmd, 'nagios', 'status']) - if rc == 0: - return True - else: - return False +#Write the cluster configurations. If force mode is used then it will clean +#the config directory before writing the changes. +def writeDelta(clusterDelta, configManager, force): + if force: + cleanConfigDir(configManager.configDir) + configManager.generateConfigFiles(clusterDelta) + +def getConfirmation(message, default): + while True: + ans = raw_input("%s (Yes, No) [%s]: " % (message, default)) + if not ans: + ans = default + ans = ans.upper() + if ans not in ['YES', 'NO']: + print 'please enter Yes or No' + if ans == 'YES': + return True + if ans == 'NO': + return False if __name__ == '__main__': args = parse_input() clusterdata = discoverCluster(args.hostip, args.cluster) configManager = getConfigManager(args) - clusterConfing = configManager.generateNagiosConfigFromGlusterCluster( - clusterdata) - print " Cluster configurations re-synced successfully from host %s" % \ - (args.hostip) - if _isNagiosRunning(): - _restartNagios() + clusterDelta = configManager.generateNagiosConfig(clusterdata) + if args.force: + clusterDelta['changeMode'] = CHANGE_MODE_ADD + else: + clusterDelta = findDelta(clusterDelta) + + if clusterDelta.get('changeMode') is None: + print "Cluster configurations are in sync" + sys.exit(utils.PluginStatusCode.OK) + #When auto config is run in manual mode, we will ask confirmation + #before writing the config file and before restarting the Nagios + if args.mode == "manual": + print "Cluster configurations changed" + previewChanges(clusterDelta) + confirmation = getConfirmation( + "Are you sure, you want to commit the changes?", "Yes") + if confirmation: + writeDelta(clusterDelta, configManager, args.force) + print "Cluster configurations synced successfully from host %s" % \ + (args.hostip) + #If Nagios is running then try to restart. Otherwise don't do + #anything. + if server_utils.isNagiosRunning(): + confirmation = getConfirmation( + "Do you want to restart Nagios to start monitoring newly " + "discovered entities?", "Yes") + if confirmation: + server_utils.restartNagios() + print "Nagios re-started successfully" + else: + print "Start the Nagios service to monitor" + #auto mode means write the configurations without asking confirmation + elif args.mode == "auto": + writeDelta(clusterDelta, configManager, args.force) + print "Cluster configurations synced successfully from host %s" % \ + (args.hostip) + if server_utils.isNagiosRunning(): + server_utils.restartNagios() sys.exit(utils.PluginStatusCode.OK) |