def build_snap_ent(entry): basefields = [] if entry.tag in ['Package', 'Service']: basefields += ['type'] desired = dict([(key, u_str(entry.get(key))) for key in basefields]) state = dict([(key, u_str(entry.get(key))) for key in basefields]) desired.update([(key, u_str(entry.get(key))) for key in \ datafields[entry.tag]]) if entry.tag == 'ConfigFile' or \ ((entry.tag == 'Path') and (entry.get('type') == 'file')): if entry.text == None: desired['contents'] = None else: if entry.get('encoding', 'ascii') == 'ascii': desired['contents'] = u_str(entry.text) else: desired['contents'] = u_str(b64decode(entry.text)) if 'current_bfile' in entry.attrib: state['contents'] = u_str(b64decode(entry.get('current_bfile'))) elif 'current_bdiff' in entry.attrib: diff = b64decode(entry.get('current_bdiff')) state['contents'] = u_str( \ '\n'.join(difflib.restore(diff.split('\n'), 1))) state.update([(key, u_str(entry.get('current_' + key, entry.get(key)))) \ for key in datafields[entry.tag]]) if entry.tag in ['ConfigFile', 'Path'] and entry.get('exists', 'true') == 'false': state = None return [desired, state]
def GetCurrentEntry(self, client, e_type, e_name): try: c_inst = Client.objects.filter(name=client)[0] except IndexError: self.logger.error("Unknown client: %s" % client) raise Bcfg2.Server.Plugin.PluginExecutionError result = c_inst.current_interaction.bad().filter(entry__kind=e_type, entry__name=e_name) if not result: raise Bcfg2.Server.Plugin.PluginExecutionError entry = result[0] ret = [] data = ('owner', 'group', 'perms') for t in data: if getattr(entry.reason, "current_%s" % t) == '': ret.append(getattr(entry.reason, t)) else: ret.append(getattr(entry.reason, "current_%s" % t)) if entry.reason.is_sensitive: raise Bcfg2.Server.Plugin.PluginExecutionError elif len(entry.reason.unpruned) != 0: ret.append('\n'.join(entry.reason.unpruned)) elif entry.reason.current_diff != '': if entry.reason.is_binary: ret.append(b64decode(entry.reason.current_diff)) else: ret.append('\n'.join(difflib.restore(\ entry.reason.current_diff.split('\n'), 1))) elif entry.reason.is_binary: # If len is zero the object was too large to store raise Bcfg2.Server.Plugin.PluginExecutionError else: ret.append(None) return ret
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 = b64decode(entry.text) else: entrydata = entry.text if entrydata == contents: updated = True tries += 1
def GetCurrentEntry(self, client, e_type, e_name): curr = self.FindCurrent(client) entry = curr.xpath('.//Bad/%s[@name="%s"]' % (e_type, e_name)) if not entry: raise Bcfg2.Server.Plugin.PluginExecutionError cfentry = entry[-1] owner = cfentry.get("current_owner", cfentry.get("owner")) group = cfentry.get("current_group", cfentry.get("group")) perms = cfentry.get("current_perms", cfentry.get("perms")) if cfentry.get("sensitive") in ["true", "True"]: raise Bcfg2.Server.Plugin.PluginExecutionError elif "current_bfile" in cfentry.attrib: contents = b64decode(cfentry.get("current_bfile")) elif "current_bdiff" in cfentry.attrib: diff = b64decode(cfentry.get("current_bdiff")) contents = "\n".join(difflib.restore(diff.split("\n"), 1)) else: contents = None return (owner, group, perms, contents)
def write_data(self, data, metadata): """Write the probed file data to the bcfg2 specification.""" filename = data.get("name") contents = b64decode(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 = os.path.join(cfg.data, os.path.join(filename, specific).lstrip("/")) create = False try: cfg.entries[filename].bind_entry(entry, metadata) except (KeyError, Bcfg2.Server.Plugin.PluginExecutionError): create = True # get current entry data if entry.text and entry.get("encoding") == "base64": entrydata = b64decode(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(cfg.data, filename.lstrip("/"), "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 build_reason_kwargs(r_ent, encoding, logger): binary_file = False sensitive_file = False unpruned_entries = "" if r_ent.get("sensitive") in ["true", "True"]: sensitive_file = True rc_diff = "" elif r_ent.get("current_bfile", False): binary_file = True rc_diff = r_ent.get("current_bfile") if len(rc_diff) > 1024 * 1024: rc_diff = "" elif len(rc_diff) == 0: # No point in flagging binary if we have no data binary_file = False elif r_ent.get("current_bdiff", False): rc_diff = b64decode(r_ent.get("current_bdiff")) elif r_ent.get("current_diff", False): rc_diff = r_ent.get("current_diff") else: rc_diff = "" # detect unmanaged entries in pruned directories if r_ent.get("prune", "false") == "true" and r_ent.get("qtest"): unpruned_elist = [e.get("path") for e in r_ent.findall("Prune")] unpruned_entries = "\n".join(unpruned_elist) if not binary_file: try: rc_diff = rc_diff.decode(encoding) except: logger.error("Reason isn't %s encoded, cannot decode it" % encoding) rc_diff = "" return dict( owner=r_ent.get("owner", default=""), current_owner=r_ent.get("current_owner", default=""), group=r_ent.get("group", default=""), current_group=r_ent.get("current_group", default=""), perms=r_ent.get("perms", default=""), current_perms=r_ent.get("current_perms", default=""), status=r_ent.get("status", default=""), current_status=r_ent.get("current_status", default=""), to=r_ent.get("to", default=""), current_to=r_ent.get("current_to", default=""), version=r_ent.get("version", default=""), current_version=r_ent.get("current_version", default=""), current_exists=r_ent.get("current_exists", default="True").capitalize() == "True", current_diff=rc_diff, is_binary=binary_file, is_sensitive=sensitive_file, unpruned=unpruned_entries, )
def _get_data(self, entry): is_binary = False if entry.get('encoding', 'ascii') == 'base64': tempdata = b64decode(entry.text) is_binary = True elif entry.get('empty', 'false') == 'true': tempdata = '' else: tempdata = entry.text if isinstance(tempdata, unicode) and unicode != str: try: tempdata = tempdata.encode(self.setup['encoding']) except UnicodeEncodeError: err = sys.exc_info()[1] self.logger.error("POSIX: Error encoding file %s: %s" % (entry.get('name'), err)) return (tempdata, is_binary)