summaryrefslogtreecommitdiffstats
path: root/src/lib/Server/Plugins/FileProbes.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Server/Plugins/FileProbes.py')
-rw-r--r--src/lib/Server/Plugins/FileProbes.py230
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