diff options
Diffstat (limited to 'src/lib/Server/Plugins/FileProbes.py')
-rw-r--r-- | src/lib/Server/Plugins/FileProbes.py | 230 |
1 files changed, 0 insertions, 230 deletions
diff --git a/src/lib/Server/Plugins/FileProbes.py b/src/lib/Server/Plugins/FileProbes.py deleted file mode 100644 index a76d7cac4..000000000 --- a/src/lib/Server/Plugins/FileProbes.py +++ /dev/null @@ -1,230 +0,0 @@ -""" This module allows you to probe a client for a file, which is then -added to the specification. On subsequent runs, the file will be -replaced on the client if it is missing; if it has changed on the -client, it can either be updated in the specification or replaced on -the client """ - -import os -import sys -import errno -import binascii -import lxml.etree -import Bcfg2.Options -import Bcfg2.Server.Plugin - -probecode = """#!/usr/bin/env python - -import os -import pwd -import grp -import binascii -import lxml.etree - -path = "%s" - -if not os.path.exists(path): - print "%%s does not exist" %% path - raise SystemExit(1) - -stat = os.stat(path) -data = lxml.etree.Element("ProbedFileData", - name=path, - owner=pwd.getpwuid(stat[4])[0], - group=grp.getgrgid(stat[5])[0], - perms=oct(stat[0] & 07777)) -data.text = binascii.b2a_base64(open(path).read()) -print lxml.etree.tostring(data) -""" - -class FileProbesConfig(Bcfg2.Server.Plugin.SingleXMLFileBacked, - Bcfg2.Server.Plugin.StructFile): - """ Config file handler for FileProbes """ - def __init__(self, filename, fam): - Bcfg2.Server.Plugin.SingleXMLFileBacked.__init__(self, filename, fam) - Bcfg2.Server.Plugin.StructFile.__init__(self, filename) - - -class FileProbes(Bcfg2.Server.Plugin.Plugin, - Bcfg2.Server.Plugin.Probing): - """ This module allows you to probe a client for a file, which is then - added to the specification. On subsequent runs, the file will be - replaced on the client if it is missing; if it has changed on the - client, it can either be updated in the specification or replaced on - the client """ - - name = 'FileProbes' - experimental = True - __author__ = 'chris.a.st.pierre@gmail.com' - - def __init__(self, core, datastore): - Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) - Bcfg2.Server.Plugin.Probing.__init__(self) - self.config = FileProbesConfig(os.path.join(self.data, 'config.xml'), - core.fam) - self.entries = dict() - self.probes = dict() - - def GetProbes(self, metadata): - """Return a set of probes for execution on client.""" - if metadata.hostname not in self.probes: - cfg = self.core.plugins['Cfg'] - self.entries[metadata.hostname] = dict() - self.probes[metadata.hostname] = [] - for entry in self.config.Match(metadata): - path = entry.get("name") - # do not probe for files that are already in Cfg and - # for which update is false; we can't possibly do - # anything with the data we get from such a probe - try: - if (entry.get('update', 'false').lower() == "false" and - cfg.entries[path].get_pertinent_entries(entry, - metadata)): - continue - except (KeyError, Bcfg2.Server.Plugin.PluginExecutionError): - pass - self.entries[metadata.hostname][path] = entry - probe = lxml.etree.Element('probe', name=path, - source=self.name, - interpreter="/usr/bin/env python") - probe.text = probecode % path - self.probes[metadata.hostname].append(probe) - self.debug_log("Adding file probe for %s to %s" % - (path, metadata.hostname)) - return self.probes[metadata.hostname] - - def ReceiveData(self, metadata, datalist): - """Receive data from probe.""" - self.debug_log("Receiving file probe data from %s" % metadata.hostname) - - for data in datalist: - if data.text is None: - self.logger.error("Got null response to %s file probe from %s" % - (data.get('name'), metadata.hostname)) - else: - try: - self.write_data(lxml.etree.XML(data.text), metadata) - except lxml.etree.XMLSyntaxError: - # if we didn't get XML back from the probe, assume - # it's an error message - self.logger.error(data.text) - - def write_data(self, data, metadata): - """Write the probed file data to the bcfg2 specification.""" - filename = data.get("name") - contents = binascii.a2b_base64(data.text) - entry = self.entries[metadata.hostname][filename] - cfg = self.core.plugins['Cfg'] - specific = "%s.H_%s" % (os.path.basename(filename), metadata.hostname) - # we can't use os.path.join() for this because specific - # already has a leading /, which confuses os.path.join() - fileloc = "%s%s" % (cfg.data, os.path.join(filename, specific)) - - create = False - try: - cfg.entries[filename].bind_entry(entry, metadata) - except Bcfg2.Server.Plugin.PluginExecutionError: - create = True - - # get current entry data - if entry.text and entry.get("encoding") == "base64": - entrydata = binascii.a2b_base64(entry.text) - else: - entrydata = entry.text - - if create: - self.logger.info("Writing new probed file %s" % fileloc) - self.write_file(fileloc, contents) - self.verify_file(filename, contents, metadata) - infoxml = os.path.join("%s%s" % (cfg.data, filename), "info.xml") - self.write_infoxml(infoxml, entry, data) - elif entrydata == contents: - self.debug_log("Existing %s contents match probed contents" % - filename) - return - elif (entry.get('update', 'false').lower() == "true"): - self.logger.info("Writing updated probed file %s" % fileloc) - self.write_file(fileloc, contents) - self.verify_file(filename, contents, metadata) - else: - self.logger.info("Skipping updated probed file %s" % fileloc) - return - - def write_file(self, fileloc, contents): - try: - os.makedirs(os.path.dirname(fileloc)) - except OSError: - err = sys.exc_info()[1] - if err.errno == errno.EEXIST: - pass - else: - self.logger.error("Could not create parent directories for %s: " - "%s" % (fileloc, err)) - return - - try: - open(fileloc, 'wb').write(contents) - except IOError: - err = sys.exc_info()[1] - self.logger.error("Could not write %s: %s" % (fileloc, err)) - return - - def verify_file(self, filename, contents, metadata): - # Service the FAM events queued up by the key generation so - # the data structure entries will be available for binding. - # - # NOTE: We wait for up to ten seconds. There is some potential - # for race condition, because if the file monitor doesn't get - # notified about the new key files in time, those entries - # won't be available for binding. In practice, this seems - # "good enough". - entry = self.entries[metadata.hostname][filename] - cfg = self.core.plugins['Cfg'] - tries = 0 - updated = False - while not updated: - if tries >= 10: - self.logger.error("%s still not registered" % filename) - return - self.core.fam.handle_events_in_interval(1) - try: - cfg.entries[filename].bind_entry(entry, metadata) - except Bcfg2.Server.Plugin.PluginExecutionError: - tries += 1 - continue - - # get current entry data - if entry.get("encoding") == "base64": - entrydata = binascii.a2b_base64(entry.text) - else: - entrydata = entry.text - if entrydata == contents: - updated = True - tries += 1 - - def write_infoxml(self, infoxml, entry, data): - """ write an info.xml for the file """ - if os.path.exists(infoxml): - return - - self.logger.info("Writing info.xml at %s for %s" % - (infoxml, data.get("name"))) - info = \ - lxml.etree.Element("Info", - owner=data.get("owner", - Bcfg2.Options.MDATA_OWNER.value), - group=data.get("group", - Bcfg2.Options.MDATA_GROUP.value), - perms=data.get("perms", - Bcfg2.Options.MDATA_PERMS.value), - encoding=entry.get("encoding", - Bcfg2.Options.ENCODING.value)) - - root = lxml.etree.Element("FileInfo") - root.append(info) - try: - open(infoxml, "w").write(lxml.etree.tostring(root, - pretty_print=True)) - except IOError: - err = sys.exc_info()[1] - self.logger.error("Could not write %s: %s" % (fileloc, err)) - return |