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