X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=nagios%2Fconfigurator%2FNagiosConfig.py;fp=nagios%2Fconfigurator%2FNagiosConfig.py;h=d1592796317e8888b9c1f63098343a7d9b216bb5;hb=80f8e07e75431f360ffbd0f3daee305cd87363c6;hp=0000000000000000000000000000000000000000;hpb=7bcbd9d4532b7745e0c56850459feecccdaf03dd;p=infrastructure.git diff --git a/nagios/configurator/NagiosConfig.py b/nagios/configurator/NagiosConfig.py new file mode 100644 index 0000000..d159279 --- /dev/null +++ b/nagios/configurator/NagiosConfig.py @@ -0,0 +1,450 @@ +import os +import sys +import xmlrpclib + +### downloaded makeHTML from: +### article +### http://www.hoboes.com/Mimsy/?ART=128 +### download \ +### http://www.hoboes.com/Mimsy/library/downloads/makeHTML.py.gz +import makeHTML + +# utilities for building comon queries +import comon_query + + +class NagiosConfig: + + # static + _admin_role=10 + _pi_role=20 + # person emails to exclude + _exclude_admins={'maint@localhost.localdomain':True} + + # set of services to check on each node + # these refer to generic services you must have in generic.cfg + _full_node_services = ['ssh', + 'ssh-root', + 'ssh-pl_conf', + ] + _restricted_node_services = ['ssh', + 'planetlab', + ] + + _verbose = False +# WARNING : some site names come with wierd unicode chars +# in this case verbose mode might fail +# _verbose = True + + plchost=None + xmlrpcserver = None + auth=None + + dest_email = None + + # a tree of sites, for access to nodes and contacts + siteTree = None + # list of admin people + allAdmins = {} + + ### record arguments + def __init__ (self, plchost, plcid, plcpasswd, plcrole): + self.plchost = plchost + + self.auth={} + self.auth['Username'] = plcid + self.auth['AuthMethod'] = "password" + self.auth['AuthString'] = plcpasswd + self.auth['Role']=plcrole + + def Auth (self): + return self.auth + + ### connect to xml rpc server + def Connect (self): + + try: + self.xmlrpcserver = xmlrpclib.Server("https://%s/PLCAPI/" + % (self.plchost)) + except: + self.xmlrpcserver = None + + return self.xmlrpcserver + + def set_verbose (self): + self._verbose = True + + def verbose (self,arg): + if (self._verbose): + print str(arg) + + def GatherData (self, email, sitefile): + + # if email is None, we NEED to have admin role + # otherwise let's dont wait 10 minutes before we fail + AdminRoleRequired = "admin role required, or provide -o/-O" + if not email: + if self.auth['Role'] != 'admin': + raise AdminRoleRequired + + self.dest_email = email + + self.verbose ("Gathering") + server = self.Connect() + auth = self.Auth () + + if sitefile: + # open and parse the file, let's gather site_ids in the process + self.verbose("Opening site file %s"%sitefile) + siteF=open(sitefile,'r') + selected_ids=[] + while 1: + siteline=siteF.readline() + if not siteline: + break + selected_ids += [int(siteline.split(' ')[0])] + siteF.close() + sitesList = server.GetSites(auth,selected_ids) + else: + # get list of all sites + sitesList = server.GetSites(auth) + self.verbose("Working on a total of %d sites"%len(sitesList)) + + selectedNodeIds = []; + for site in sitesList: + selectedNodeIds += site['node_ids'] + + # get all nodenetworks + allNodeNetworks = server.GetNodeNetworks (auth) + allNodeNetworksIndex = dict ( [ ( nn['nodenetwork_id'],nn) for nn in allNodeNetworks ] ) + + # get list of nodes + # might wish to restrict the returned attributes + selectedNodes = server.GetNodes(auth,selectedNodeIds,['node_id','hostname','nodenetwork_ids']) + self.verbose("Got a total of %d nodes"%len(selectedNodes)) + + for node in selectedNodes: + if not node['nodenetwork_ids']: + print 'WARNING : Node %s has no nodenetwork thus no IP'%node['hostname'] + nn = allNodeNetworksIndex[node['nodenetwork_ids'][0]] + node['ip'] = nn['ip'] + + + # index it by node_id + selectedNodesIndex = dict( [ (node['node_id'],node) for node in selectedNodes ] ) + + self.siteTree = {} + for site in sitesList : + self.verbose( "SITE = %s" % site['name']) + site_id=site['site_id'] + siteHash = {} + self.siteTree[site_id] = siteHash + node_ids = site['node_ids'] + self.verbose( "NODES IDS = " + str(node_ids)) + siteNodes=[ selectedNodesIndex[node_id] for node_id in node_ids ] + nodesHash = dict ( [ (node['node_id'],node) for node in siteNodes ] ) + personsHash = {} + siteHash['site'] = site + siteHash['nodes'] = nodesHash + siteHash['persons'] = personsHash + + # We are provided a hard-wired e-mail : + # dont scan all people (maybe we cannot) + if not email: + + # get list of people + allPersons = server.GetPersons (auth, [],['person_id','email', + 'first_name','last_name']) + for person in allPersons: + person_id = person['person_id'] + # keep only PIs + roles = server.AdmGetPersonRoles (auth,person_id) + is_admin = roles.has_key(str(self._admin_role)) + is_pi = roles.has_key(str(self._pi_role)) + if is_admin: + ### handle exclude list + if not self._exclude_admins.has_key(person['email']): + self.allAdmins[person_id]=person + elif is_pi: + person_sites=server.AdmGetPersonSites(auth,person_id) + for site_id in person_sites: + personsHash = self.siteTree[site_id]['persons'] + personsHash[person_id]=person + person['full_name']=person['first_name']+person['last_name'] + self.verbose("Added PI %s" % person['full_name']) + + _define_host="""define host{ + use generic-host + host_name %s + alias %s + address %s + contact_groups %s_pis + }\n""" + _define_hostgroup="""define hostgroup{ + hostgroup_name %s + alias %s + members %s + }\n""" + # as of nagios-2.5-2.fc4 - apparently cannot use genericity in contacts + _define_contact="""define contact{ + contact_name %s + alias %s %s + email %s + service_notification_period 24x7 + host_notification_period 24x7 + service_notification_options w,u,c,r + host_notification_options d,r + service_notification_commands notify-by-email + host_notification_commands host-notify-by-email + }\n""" + _define_contactgroup="""define contactgroup{ + contactgroup_name %s_pis + alias %s + members %s + }\n""" + _define_service="""define service{ + use generic-%s + host_name %s + contact_groups %s_pis + servicegroups %s + }\n""" + _define_servicegroup="""define servicegroup{ + servicegroup_name %s + alias all %s + }\n""" + + def WriteNagiosConfig (self, dirname): + + site_ids=self.siteTree.keys() + site_ids.sort() + + + # by default use all avail services + node_services = self._full_node_services + # but in restricted mode some wont work out + if self.dest_email: + node_services = self._restricted_node_services + + # generate contact file + # with people with admin roles, and also + # centraladmin if email was provided + # located in main dir so we can have control on load order + filename = "%s/%s.cfg"%(dirname,"planetlab") + print ( "Opening %s for writing" % filename) + file = open (filename,'w') + for admin_id in self.allAdmins.keys(): + admin=self.allAdmins[admin_id] + file.write(self._define_contact% + ('rootadmin','root','admin',admin['email'])) + if self.dest_email: + file.write(self._define_contact% + (self.dest_email,'central','admin',self.dest_email)) + + for service in node_services: + file.write(self._define_servicegroup + %(service,service)) + + file.close() + + ### manage planetlab subdir + planetlabdir="%s/planetlab/"%dirname + import os.path + if not os.path.isdir (planetlabdir): + try: + print "Trying to create subdir %s"%planetlabdir + os.mkdir (planetlabdir) + except Exception,e: + print "Failed -- exiting" + sys.exit(1) + + import dircache + ls = dircache.listdir(planetlabdir) + import re + m=re.compile('^.*\.cfg$') + cfgs=filter(lambda x: m.match(x),ls) + if len(cfgs) != 0: + print "Warning : you have %d nagios configs left in %s"%( + len(cfgs),planetlabdir) + print "It's OK to keep them, if that's what you're trying to do" + + ### scan over sites + for site_id in site_ids: + + siteHash=self.siteTree[site_id] + site = siteHash['site'] + sitename = site['name'] + sitebase = site['login_base'] + + nodes = siteHash['nodes'] + node_ids = nodes.keys() + node_ids.sort() + if len(node_ids) != 0: + + filename = "%s/%s.cfg"%(planetlabdir,sitebase) + print ( "Opening %s for writing" % filename) + file = open (filename,'w') + + ### without email / use real people + if not self.dest_email: + persons = siteHash ['persons'] + + self.verbose("retrieved PIs = %s"%str(persons)) + + if len(persons) != 0: + personnames='' + for person_id in persons.keys(): + person=persons[person_id] + personname=person['full_name'] + if len(personnames) == 0: + personnames = personname + else: + personnames = "%s,%s"%(personnames,personname) + file.write(self._define_contact + %(personname, + person['first_name'], + person['last_name'], + person['email'])) + + file.write(self._define_contactgroup + %(sitebase,sitename,personnames)) + else: + file.write(self._define_contactgroup + %(sitebase,sitename,self.dest_email)) + + + nodenames="" + for node_id in node_ids: + node = nodes[node_id] + if len(nodenames) == 0: + nodenames = node['hostname'] + else: + nodenames = "%s,%s"%(nodenames,node['hostname']) + file.write(self._define_host + %(node['hostname'],node['hostname'], + node['ip'],sitebase)) + + for service in node_services: + file.write(self._define_service + %(service,node['hostname'],sitebase,service)) + + + file.write(self._define_hostgroup + %(sitebase,sitename,nodenames)) + + file.close() + +#################### static html file with bookmarks to comon site-centric queries +# a first draft tried to create a column for easying the bookmarking process +# I did not completely succeed, because +# the javascript interface for firefox seems to only allow +# the creation of bookmarks in the sidebar +# in fact you can bookmark the link, but when you use that bookmark +# the target url is opened in the sidebar +# you can easily fix this by editing the bookmark and uncheck +# a dialob box, but that's not what we want +# it's much easier to directly use the 'Bookmark this link' +# from the firefox menu +# so let's forget about this altogether + +# ### bookmarks +# def ManualBookmark (self, url, text, bookmark_name): +# bookmark_link=""" +# %s""" +# # the single quotes in the URL need to be html-encoded +# cleanurl = url.replace ("'","%27") +# return bookmark_link%(makeHTML.encode(cleanurl),bookmark_name,text) +# +# bookmark_code="""""" ### ' for fooling emacs + + def ComonNodesSelect (self,nodes): + names = map(lambda node: node['hostname'],nodes) + filters = map (comon_query.filter_node,names) + server = comon_query.SERVER + return comon_query.full_url(server,'||'.join(filters)) + + ### could not find the makeHTML tool for that + def ManualAnchor (self,name,value): + return '%s' % (name,value) + + def SiteRow (self,site_id): + ### returns a (makeHTML) row for the given site + + siteHash = self.siteTree[site_id] + site = siteHash['site'] + sitename = site['name'] + sitebase = site['login_base'] + + nodes = siteHash['nodes'].values() + if len(nodes) == 0 : + return None + else: + row = makeHTML.tableRow() + query=self.ComonNodesSelect(nodes) + row.addCells([makeHTML.link(content=sitename, url=query), + self.ManualAnchor(sitebase,sitebase), +# self.ManualBookmark(query, +# "Bookmark it", +# "Comon on %s"%sitename), + ]) + return row + + def MakeSiteTable (self, sites): + ### create table / sitename + table = makeHTML.table () + ### first row + head_row = makeHTML.tableRow() + head_row.addCells ( ['Site name', + 'Site login', +# 'Comon query', + ]) + table.addRow(rowList=[head_row]) + + for site in sites: + table.addRow ( rowList=[self.SiteRow(site['site_id'])]) + return table + + ### Write a single index page that contains one bookmark per site + def WriteComonLinks (self, indexname): + + pageHead = makeHTML.part('head') + pageHead.addPart('title',content='Comon links for all sites') +# pageHead.addPiece(bookmark_code) + + pageBody = makeHTML.part('body') + pageBody.addPart('h1',content='Comon links, per site') + + sites = map(lambda s: s['site'],self.siteTree.values()) + + pageBody.addPart('h2',content='By site name') + + sites.sort (lambda s1,s2: cmp(s1['name'],s2['name'])) + pageBody.addPart('p',self.MakeSiteTable(sites)) + + pageBody.addPart('h2',content='By site login') + + sites.sort (lambda s1,s2: cmp(s1['login_base'],s2['login_base'])) + pageBody.addPart('p',self.MakeSiteTable(sites)) + + fullPage = makeHTML.part('html') + fullPage.addPiece(pageHead) + fullPage.addPiece(pageBody) + + text=fullPage.make() + + print ( "Opening %s for writing" % indexname) + index=open (indexname,"w") + index.write(text+"\n") + index.close()