##################### # # # NagLib # Functions for handling nagios config files # # ##################### def parse_config(file) : """ accepts a filehandle and returns the object definitions """ definitions=[] config = file.readlines() config = ''.join(config) # dump comments try: config = config[config.index('define'):] except ValueError: return() # cut into chunks config = config.split('define') # config now has one definition per element x=0 # Clean lines up for definition in config : config[x]=definition.strip() # dump everything after the } config[x]=config[x][:config[x].find('}')+1] x=x+1 for entry in config: try: config.remove('') except ValueError: break return (config) def hash_objects(obj_list): """accept a list of object definitions and return them as a dictionary""" object_base=[] for entry in obj_list: # remove pesky trailing } #explode the object definition for easy pickin's exp_obj = entry.split('\n') object = {} object['type'] = exp_obj[0][:exp_obj[0].index('{')] # pop off the type field soas not to interfere with loop exp_obj.pop(0) for attrib in exp_obj: attrib = attrib.lstrip() attribname = attrib.split()[0] # some values have spaces in them # so we just grab the rest of the line attribvalue = attrib[len(attribname):] # remove comments attribvalue = attribvalue.split(';')[0] attribvalue = attribvalue.strip() # in case closing brace is on the line with values attribvalue = attribvalue.split('}')[0] if attribname == '}' : continue if attribname == '#' : continue #poke values into hash object[attribname] = attribvalue # add complete object to list of objects object_base.append(object) return(object_base) def validate_objects(obj_base): """ validate objects """ # TODO: dig through /include/objects.h and validate the attribute # against the actual struct for each object type invalid=False for entry in obj_base: if entry.has_key('use'): valid = False # print 'found dependency: need:', entry['use'],'|' for obj in obj_base: if obj.has_key('name'): if obj['name'] == entry['use']: valid = True if not valid : invalid = True # members are dependencies # they appear in hostgroups and contact groups if entry.has_key('members'): members = entry['members'].split(',') # print members for member in members: member = member.strip() if member == '': continue valid = False for obj in obj_base: if obj['type'] == 'contact': if obj['contact_name'] == member: # print '|',obj['contact_name'],'|' # print '|',member,'|' valid = True break if obj['type'] == 'host' and obj.has_key('host_name') : if obj['host_name'] == member: # print '|',obj['host_name'],'|' # print '|',member,'|' valid = True break # Contact_groups are deps these appear in hosts and services if entry.has_key('contact_groups'): contact_groups = entry['contact_groups'].split(',') # print contact_groups for contact_group in contact_groups: contact_group = contact_group.strip() # print 'SEEKING : | ',contact_group,' |' if contact_group == '': # print 'FOUND : | ',obj['contactgroup_name'],' |' continue valid = False for obj in obj_base: if obj['type'] == 'contactgroup': if obj['contactgroup_name'] == contact_group: # print 'FOUND : | ',obj['contactgroup_name'],' |' valid = True break if not valid: print 'cross references failed' invalid = True return(not invalid) def format_object(object): """format the hash object into the output format expected by Nagios """ output='define '+object['type']+'{\n' for key in object.keys(): if key == 'type': continue output = output+'\t'+key+'\t'+object[key]+'\n' output = output+'\t}\n\n\n' return(output) def dump_objects(obj_base,minimal,config_dir): """write objects to config file(s) obj_base a list of hashed config entitties minimal indicates if using minimal.cfg config_dir you figure it out""" if minimal: print else: hosts_cfg = open(config_dir+"/hosts.cfg",mode='w') hostgroups_cfg = open(config_dir+"/hostgroups.cfg",mode='w') services_cfg = open(config_dir+"/services.cfg",mode='w') servicegroups_cfg = open(config_dir+"/servicegroups.cfg",mode='w') contacts_cfg = open(config_dir+"/contacts.cfg",mode='w') contactgroups_cfg = open(config_dir+"/contactgroups.cfg",mode='w') timeperiods_cfg = open(config_dir+"/timeperiods.cfg" ,mode='w') for object in obj_base: if object['type']=='host': entry = format_object(object) hosts_cfg.writelines(entry) continue if object['type']=='hostgroup': entry = format_object(object) hostgroups_cfg.writelines(entry) continue if object['type']=='service': entry = format_object(object) services_cfg.writelines(entry) continue if object['type']=='servicegroup': entry = format_object(object) servicegroups_cfg.writelines(entry) continue if object['type']=='contact': entry = format_object(object) contacts_cfg.writelines(entry) continue if object['type']=='contactgroup': entry = format_object(object) contactgroups_cfg.writelines(entry) continue if object['type']=='timeperiod': entry = format_object(object) timeperiods_cfg.writelines(entry) continue hosts_cfg.truncate() hosts_cfg.close() hostgroups_cfg.truncate() hostgroups_cfg.close() services_cfg.truncate() services_cfg.close() servicegroups_cfg.truncate() servicegroups_cfg.close() contacts_cfg.truncate() contacts_cfg.close() contactgroups_cfg.truncate() contactgroups_cfg.close() timeperiods_cfg.truncate() timeperiods_cfg.close() return(0) def parse_status(status_file_handle): """ Parse status file returns List of Dictionaries""" definitions = [] status = status_file_handle.readlines() # print status x=0 obj_list = [] # remove comments and blank lines for element in status: element = element.strip() if element == '': continue if element[0] == '#' : continue obj_list.append(element) status = '\n'.join(obj_list) # cut into chunks status = status.split('}') status = status[:-1] # config now has one definition per element return (status) def hash_status(status): """accept a list of object definitions and return them as a dictionary""" object_base=[] for entry in status: #explode the object definition for easy pickin's entry=entry.lstrip() exp_obj = entry.split('\n') object = {} object['type'] = exp_obj[0][:exp_obj[0].index('{')] object['type'] =object['type'].strip() # pop off the type field soas not to interfere with loop exp_obj.pop(0) for attrib in exp_obj: if attrib =='': continue attrib=attrib.lstrip() attrib=attrib.split('=',1) attribname=attrib[0] # some values have spaces in them # so we just grab the rest of the line attribvalue=attrib[1] attribvalue=attribvalue.strip() attribname=attribname.strip() # put values into hash object[attribname]=attribvalue # add complete object to list of objects object_base.append(object) return(object_base) if __name__=='__main__': from time import time as now start =now() nagios_cfg="/usr/local/nagios/etc/nagios.cfg" hosts_cfg="/usr/local/nagios/etc/hosts.cfg" hostgroups_cfg="/usr/local/nagios/etc/hostgroups.cfg" services_cfg="/usr/local/nagios/etc/services.cfg" servicegroups_cfg="/usr/local/nagios/etc/servicegroups.cfg" contacts_cfg="/usr/local/nagios/etc/contacts.cfg" contactgroups_cfg="/usr/local/nagios/etc/contactgroups.cfg" timeperiods_cfg="/usr/local/nagios/etc/timeperiods.cfg" config_files=[hosts_cfg,\ hostgroups_cfg,\ services_cfg,\ servicegroups_cfg,\ contacts_cfg,\ contactgroups_cfg,\ timeperiods_cfg] print '\n'*124 objects=[] for file in config_files: try: input=open(file,mode='r') input.close() parsed=parse_config(file) except IOError: print "couldn't open: ", file sys.exit if parsed: objects.extend(parsed) # print objects print '++ sucessfully added',len(parsed),'object(s) from:\t', file else : print '-- no objects found in: \t\t', file print '\n' hashed=hash_objects(objects) validity=validate_objects(hashed) print '============== Hashed objects loaded: ====================' totals={} for obj in hashed: type = obj['type'] if not totals.has_key(type): totals[type] = 1 else: totals[type] = totals[type]+1 for obj_type in totals: print totals[obj_type],'\t',obj_type if validity ==True: print 'all cross references resolved successfully' else : print '* WARNING: objects contain invalid cross references *' print '============== End Hashed objects ====================' end=now() print '\n\n\n','='*80 print len(hashed), 'objects processed in ', end-start, 'seconds'