diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/Options.py | 19 | ||||
-rw-r--r-- | src/lib/Server/Plugin.py | 6 | ||||
-rw-r--r-- | src/lib/Server/Plugins/Cfg.py | 20 | ||||
-rw-r--r-- | src/lib/Server/Plugins/FileProbes.py | 148 | ||||
-rw-r--r-- | src/lib/Server/Plugins/Packages/Source.py | 10 | ||||
-rw-r--r-- | src/lib/Server/Plugins/Packages/Yum.py | 6 | ||||
-rw-r--r-- | src/lib/Server/Plugins/SSHbase.py | 4 | ||||
-rw-r--r-- | src/lib/Server/Plugins/Trigger.py | 13 | ||||
-rw-r--r-- | src/lib/Server/Reports/reports/templates/base.html | 2 |
9 files changed, 129 insertions, 99 deletions
diff --git a/src/lib/Options.py b/src/lib/Options.py index dc9818c78..2f535397f 100644 --- a/src/lib/Options.py +++ b/src/lib/Options.py @@ -27,12 +27,7 @@ class Option(object): def getCFP(self): if not self.__cfp: self.__cfp = ConfigParser.ConfigParser() - # FIXME: Remove this hack when except: pass below is fixed - try: - self.__cfp.readfp(open(self.cfpath)) - except IOError: - e = sys.exc_info()[1] - print("Unable to read bcfg2.conf: %s" % e) + self.__cfp.readfp(open(self.cfpath)) return self.__cfp cfp = property(getCFP) @@ -116,11 +111,7 @@ class Option(object): self.value = self.get_cooked_value(os.environ[self.env]) return if self.cf: - """ - FIXME: This is masking any sort of error present in getCFP, we - need to remove this catchall exception and figure out something - better - """ + # FIXME: This is potentially masking a lot of errors try: self.value = self.get_cooked_value(self.cfp.get(*self.cf)) return @@ -383,3 +374,9 @@ class OptionParser(OptionSet): Option.cfpath = self.Bootstrap['configfile'] Option.__cfp = False OptionSet.__init__(self, args) + try: + f = open(Option.cfpath, 'r') + f.close() + except IOError: + e = sys.exc_info()[1] + print("Warning! Unable to read specified configuration file: %s" % e) diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py index 6a4020b12..1ceed702d 100644 --- a/src/lib/Server/Plugin.py +++ b/src/lib/Server/Plugin.py @@ -992,6 +992,12 @@ class EntrySet: self.entry_init(event) else: if event.filename not in self.entries: + logger.warning("Got %s event for unknown file %s" % + (action, event.filename)) + if action == 'changed': + # received a bogus changed event; warn, but treat + # it like a created event + self.entry_init(event) return if action == 'changed': self.entries[event.filename].handle_event(event) diff --git a/src/lib/Server/Plugins/Cfg.py b/src/lib/Server/Plugins/Cfg.py index d2e6e8a1d..1ea8e4e75 100644 --- a/src/lib/Server/Plugins/Cfg.py +++ b/src/lib/Server/Plugins/Cfg.py @@ -221,32 +221,32 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet): return "%s.H_%s" % (bfname, specific.hostname) def write_update(self, specific, new_entry, log): - # FIXME: need to redo print with python's logging module if 'text' in new_entry: name = self.build_filename(specific) if os.path.exists("%s.genshi" % name): - print("Cfg: Unable to pull data for genshi types") + self.logger.error("Cfg: Unable to pull data for genshi types") raise Bcfg2.Server.Plugin.PluginExecutionError elif os.path.exists("%s.cheetah" % name): - print("Cfg: Unable to pull data for cheetah types") + self.logger.error("Cfg: Unable to pull data for cheetah types") raise Bcfg2.Server.Plugin.PluginExecutionError try: etext = new_entry['text'].encode(self.encoding) except: - print("Cfg: Cannot encode content of %s as %s" % (name, self.encoding)) + self.logger.error("Cfg: Cannot encode content of %s as %s" % (name, self.encoding)) raise Bcfg2.Server.Plugin.PluginExecutionError open(name, 'w').write(etext) - if log: - print("Wrote file %s" % name) + self.debug_log("Wrote file %s" % name, flag=log) badattr = [attr for attr in ['owner', 'group', 'perms'] if attr in new_entry] if badattr: # check for info files and inform user of their removal if os.path.exists(self.path + "/:info"): - print("Removing :info file and replacing with info.xml") + self.logger.info("Removing :info file and replacing with " + "info.xml") os.remove(self.path + "/:info") if os.path.exists(self.path + "/info"): - print("Removing info file and replacing with info.xml") + self.logger.info("Removing info file and replacing with " + "info.xml") os.remove(self.path + "/info") metadata_updates = {} metadata_updates.update(self.metadata) @@ -259,8 +259,8 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet): ofile = open(self.path + "/info.xml", "w") ofile.write(lxml.etree.tostring(infoxml, pretty_print=True)) ofile.close() - if log: - print("Wrote file %s" % (self.path + "/info.xml")) + self.debug_log("Wrote file %s" % (self.path + "/info.xml"), + flag=log) class Cfg(Bcfg2.Server.Plugin.GroupSpool, diff --git a/src/lib/Server/Plugins/FileProbes.py b/src/lib/Server/Plugins/FileProbes.py index 269664ef4..c58040b65 100644 --- a/src/lib/Server/Plugins/FileProbes.py +++ b/src/lib/Server/Plugins/FileProbes.py @@ -6,6 +6,7 @@ the client """ __revision__ = '$Revision: 1465 $' import os +import sys import errno import binascii import lxml.etree @@ -89,33 +90,27 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin, interpreter="/usr/bin/env python") probe.text = probecode % path self.probes[metadata.hostname].append(probe) - self.logger.debug("Adding file probe for %s to %s" % - (path, metadata.hostname)) + 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.logger.debug("Receiving file probe data from %s" % - metadata.hostname) + 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: - self.logger.debug("%s:fileprobe:%s:%s" % - (metadata.hostname, - data.get("name"), - data.text)) try: - filedata = lxml.etree.XML(data.text) - self.write_file(filedata, metadata) + 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_file(self, data, metadata): + 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) @@ -139,74 +134,80 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin, entrydata = entry.text if create: - self.logger.info("Writing new probed file %s" % fileloc) - try: - os.makedirs(os.path.dirname(fileloc)) - except OSError, err: - if err.errno == errno.EEXIST: - pass - else: - raise - open(fileloc, 'wb').write(contents) - - infoxml = os.path.join("%s%s" % (cfg.data, filename), - "info.xml") - if not os.path.exists(infoxml): - self.write_infoxml(infoxml, entry, data) - - # 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". - tries = 0 - is_bound = False - while not is_bound: - if tries >= 10: - self.logger.error("%s still not registered" % filename) - raise Bcfg2.Server.Plugin.PluginExecutionError - self.core.fam.handle_events_in_interval(1) - try: - cfg.entries[filename].bind_entry(entry, metadata) - is_bound = True - except Bcfg2.Server.Plugin.PluginExecutionError: - pass - tries += 1 + 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.logger.debug("Existing %s contents match probed contents" % - filename) + 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) - open(fileloc, 'wb').write(contents) - - # service FAM events - tries = 0 - updated = False - while not updated: - if tries >= 10: - self.logger.error("%s still not registered" % filename) - raise Bcfg2.Server.Plugin.PluginExecutionError - self.core.fam.handle_events_in_interval(1) - cfg.entries[filename].bind_entry(entry, metadata) - # 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 + 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 = \ @@ -222,5 +223,10 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin, root = lxml.etree.Element("FileInfo") root.append(info) - open(infoxml, "w").write(lxml.etree.tostring(root, - pretty_print=True)) + 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 diff --git a/src/lib/Server/Plugins/Packages/Source.py b/src/lib/Server/Plugins/Packages/Source.py index 910a90cac..1dfeecc40 100644 --- a/src/lib/Server/Plugins/Packages/Source.py +++ b/src/lib/Server/Plugins/Packages/Source.py @@ -136,7 +136,7 @@ class Source(Bcfg2.Server.Plugin.Debuggable): def get_repo_name(self, url_map): # try to find a sensible name for a repo if url_map['component']: - return url_map['component'] + rname = url_map['component'] else: name = None for repo_re in (self.mrepo_re, @@ -144,14 +144,18 @@ class Source(Bcfg2.Server.Plugin.Debuggable): self.genericrepo_re): match = repo_re.search(url_map['url']) if match: - name = match.group(1).replace('/', '-') break if name is None: # couldn't figure out the name from the URL or URL map # (which probably means its a screwy URL), so we just # generate a random one name = base64.b64encode(os.urandom(16))[:-2] - return "%s-%s" % (self.groups[0], name) + rname = "%s-%s" % (self.groups[0], name) + # see yum/__init__.py in the yum source, lines 441-449, for + # the source of this regex. yum doesn't like anything but + # string.ascii_letters, string.digits, and [-_.:]. There + # doesn't seem to be a reason for this, because yum. + return re.sub(r'[^A-Za-z0-9-_.:]', '-', rname) def __str__(self): if self.rawurl: diff --git a/src/lib/Server/Plugins/Packages/Yum.py b/src/lib/Server/Plugins/Packages/Yum.py index a5fe706cd..416602b27 100644 --- a/src/lib/Server/Plugins/Packages/Yum.py +++ b/src/lib/Server/Plugins/Packages/Yum.py @@ -124,6 +124,7 @@ class YumCollection(Collection): mainopts = dict(cachedir=self.cachefile, keepcache="0", sslverify="0", + debuglevel="0", reposdir="/dev/null") try: for opt in self.config.options("yum"): @@ -394,6 +395,11 @@ class YumCollection(Collection): if rv: self.logger.error("Packages: error running bcfg2-yum-helper " "(returned %d): %s" % (rv, stderr)) + elif self.debug_flag: + self.logger.debug("Packages: debug info from bcfg2-yum-helper: %s" % + stderr) + self.logger.debug("Packages: output from bcfg2-yum-helper: %s" % + stderr) try: return json.loads(stdout) except ValueError: diff --git a/src/lib/Server/Plugins/SSHbase.py b/src/lib/Server/Plugins/SSHbase.py index 724d169f5..eb91bea39 100644 --- a/src/lib/Server/Plugins/SSHbase.py +++ b/src/lib/Server/Plugins/SSHbase.py @@ -235,6 +235,8 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, if entry.specific.match(event.filename): entry.handle_event(event) if event.filename.endswith(".pub"): + self.logger.info("New public key %s; invalidating " + "ssh_known_hosts cache" % event.filename) self.skn = False return @@ -244,6 +246,8 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, return if event.filename.endswith('.static'): + self.logger.info("Static key %s %s; invalidating ssh_known_hosts " + "cache" % (event.filename, action)) if action == "deleted" and event.filename in self.static: del self.static[event.filename] self.skn = False diff --git a/src/lib/Server/Plugins/Trigger.py b/src/lib/Server/Plugins/Trigger.py index f6dd47e12..eb3310a4e 100644 --- a/src/lib/Server/Plugins/Trigger.py +++ b/src/lib/Server/Plugins/Trigger.py @@ -26,12 +26,19 @@ class Trigger(Bcfg2.Server.Plugin.Plugin, try: os.stat(self.data) except: - self.logger.error("Trigger: spool directory %s does not exist; unloading" % self.data) + self.logger.error("Trigger: spool directory %s does not exist; " + "unloading" % self.data) raise Bcfg2.Server.Plugin.PluginInitError def process_statistics(self, metadata, _): args = [metadata.hostname, '-p', metadata.profile, '-g', ':'.join([g for g in metadata.groups])] for notifier in os.listdir(self.data): - n = self.data + '/' + notifier - async_run(n, args) + if ((notifier[-1] == '~') or + (notifier[:2] == '.#') or + (notifier[-4:] == '.swp') or + (notifier in ['SCCS', '.svn', '4913'])): + continue + npath = self.data + '/' + notifier + self.logger.debug("Running %s %s" % (npath, " ".join(args))) + async_run(npath, args) diff --git a/src/lib/Server/Reports/reports/templates/base.html b/src/lib/Server/Reports/reports/templates/base.html index a12bf66ba..f541c0d2b 100644 --- a/src/lib/Server/Reports/reports/templates/base.html +++ b/src/lib/Server/Reports/reports/templates/base.html @@ -87,7 +87,7 @@ <div style='clear:both'></div> </div><!-- document --> <div id="footer"> - <span>Bcfg2 Version 1.2.1</span> + <span>Bcfg2 Version 1.2.2</span> </div> <div id="calendar_div" style='position:absolute; visibility:hidden; background-color:white; layer-background-color:white;'></div> |