--- /dev/null
+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="""<a href='javascript:addToFavorites("%s","%s")'>
+# <font color='#0000FF' face="Verdana">%s</font></a>"""
+# # 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="""<script language="JavaScript" type="Text/Javascript">
+#<!-- // Hide script from older browsers
+# // script by http://www.hypergurl.com
+# function addToFavorites(url,title) {
+# if (window.sidebar) { // Mozilla Firefox Bookmark
+# window.sidebar.addPanel(title, url,"");
+# } else if (window.external) { // IE Favorite
+# window.external.AddFavorite(url,title)
+# } else {
+# alert("Sorry! Your browser doesn't support this function.");
+# }
+# }
+#// -->
+#</script>""" ### ' 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 '<a name="%s">%s</a>' % (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()