'''This module implements a Nagios configuration generator''' import os import re import sys import glob import socket import logging import lxml.etree import Bcfg2.Server import Bcfg2.Server.Plugin LOGGER = logging.getLogger('Bcfg2.Plugins.NagiosGen') line_fmt = '\t%-32s %s' class NagiosGenConfig(Bcfg2.Server.Plugin.StructFile): def __init__(self, filename, fam): # create config.xml if missing if not os.path.exists(filename): LOGGER.warning("NagiosGen: %s missing. " "Creating empty one for you." % filename) open(filename, "w").write("") Bcfg2.Server.Plugin.StructFile.__init__(self, filename, fam=fam, should_monitor=True) class NagiosGen(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Generator): """NagiosGen is a Bcfg2 plugin that dynamically generates Nagios configuration file based on Bcfg2 data. """ name = 'NagiosGen' __author__ = 'bcfg-dev@mcs.anl.gov' def __init__(self, core, datastore): Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Generator.__init__(self) self.config = NagiosGenConfig(os.path.join(self.data, 'config.xml'), core.fam) self.Entries = {'Path': {'/etc/nagiosgen.status': self.createhostconfig, '/etc/nagios/nagiosgen.cfg': self.createserverconfig}} self.client_attrib = {'encoding': 'ascii', 'owner': 'root', 'group': 'root', 'type': 'file', 'perms': '0400'} self.server_attrib = {'encoding': 'ascii', 'owner': 'nagios', 'group': 'nagios', 'type': 'file', 'perms': '0440'} def createhostconfig(self, entry, metadata): """Build host specific configuration file.""" try: host_address = socket.gethostbyname(metadata.hostname) except socket.gaierror: LOGGER.error("Failed to find IP address for %s" % metadata.hostname) raise Bcfg2.Server.Plugin.PluginExecutionError host_groups = [grp for grp in metadata.groups if os.path.isfile('%s/%s-group.cfg' % (self.data, grp))] host_config = ['define host {', line_fmt % ('host_name', metadata.hostname), line_fmt % ('alias', metadata.hostname), line_fmt % ('address', host_address)] if host_groups: host_config.append(line_fmt % ("hostgroups", ",".join(host_groups))) # read the old-style Properties config, but emit a warning. xtra = dict() props = None if (hasattr(metadata, 'Properties') and 'NagiosGen.xml' in metadata.Properties): props = metadata.Properties['NagiosGen.xml'].data if props is not None: LOGGER.warn("Parsing deprecated Properties/NagiosGen.xml. " "Update to the new-style config with " "nagiosgen-convert.py.") xtra = dict((el.tag, el.text) for el in props.find(metadata.hostname)) # hold off on parsing the defaults until we've checked for # a new-style config # read the old-style parents.xml, but emit a warning pfile = os.path.join(self.data, "parents.xml") if os.path.exists(pfile): LOGGER.warn("Parsing deprecated NagiosGen/parents.xml. " "Update to the new-style config with " "nagiosgen-convert.py.") parents = lxml.etree.parse(pfile, parser=Bcfg2.Server.XMLParser) for el in parents.xpath("//Depend[@name='%s']" % metadata.hostname): if 'parent' in xtra: xtra['parent'] += "," + el.get("on") else: xtra['parent'] = el.get("on") # read the new-style config and overwrite the old-style config for el in self.config.Match(metadata): if el.tag == 'Option': xtra[el.get("name")] = el.text # if we haven't found anything in the new- or old-style # configs, finally read defaults from old-style config if not xtra and props is not None: xtra = dict((el.tag, el.text) for el in props.find('default')) if xtra: host_config.extend([line_fmt % (opt, val) for opt, val in list(xtra.items())]) else: host_config.append(line_fmt % ('use', 'default')) host_config.append('}') entry.text = "%s\n" % "\n".join(host_config) [entry.attrib.__setitem__(key, value) for (key, value) in list(self.client_attrib.items())] try: fileh = open("%s/%s-host.cfg" % (self.data, metadata.hostname), 'w') fileh.write(entry.text) fileh.close() except OSError: ioerr = sys.exc_info()[1] LOGGER.error("Failed to write %s/%s-host.cfg" % (self.data, metadata.hostname)) LOGGER.error(ioerr) def createserverconfig(self, entry, _): """Build monolithic server configuration file.""" host_configs = glob.glob('%s/*-host.cfg' % self.data) group_configs = glob.glob('%s/*-group.cfg' % self.data) host_data = [] group_data = [] for host in host_configs: host_data.append(open(host, 'r').read()) for group in group_configs: group_name = re.sub("(-group.cfg|.*/(?=[^/]+))", "", group) if "\n".join(host_data).find(group_name) != -1: groupfile = open(group, 'r') group_data.append(groupfile.read()) groupfile.close() entry.text = "%s\n\n%s" % ("\n".join(group_data), "\n".join(host_data)) [entry.attrib.__setitem__(key, value) for (key, value) in list(self.server_attrib.items())] try: fileh = open("%s/nagiosgen.cfg" % self.data, 'w') fileh.write(entry.text) fileh.close() except OSError: ioerr = sys.exc_info()[1] LOGGER.error("Failed to write %s/nagiosgen.cfg" % self.data) LOGGER.error(ioerr)