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()