def _get_diffs(self, entry, interactive=False, sensitive=False, is_binary=False, content=None): if not interactive and sensitive: return prompt = [entry.get('qtext', '')] attrs = dict() if content is None: # it's possible that we figured out the files are # different without reading in the local file. if the # supplied version of the file is not binary, we now have # to read in the local file to figure out if _it_ is # binary, and either include that fact or the diff in our # prompts for -I and the reports try: content = open(entry.get('name')).read() except IOError: self.logger.error("POSIX: Failed to read %s: %s" % (entry.get("name"), sys.exc_info()[1])) return False if not is_binary: is_binary |= not self._is_string(content, self.setup['encoding']) if is_binary: # don't compute diffs if the file is binary prompt.append('Binary file, no printable diff') attrs['current_bfile'] = b64encode(content) else: if interactive: diff = self._diff(content, self._get_data(entry)[0], difflib.unified_diff, filename=entry.get("name")) if diff: udiff = ''.join(diff) if hasattr(udiff, "decode"): udiff = udiff.decode(self.setup['encoding']) try: prompt.append(udiff) except UnicodeEncodeError: prompt.append("Could not encode diff") else: prompt.append("Diff took too long to compute, no " "printable diff") if not sensitive: diff = self._diff(content, self._get_data(entry)[0], difflib.ndiff, filename=entry.get("name")) if diff: attrs["current_bdiff"] = b64encode("\n".join(diff)) else: attrs['current_bfile'] = b64encode(content) if interactive: entry.set("qtext", "\n".join(prompt)) if not sensitive: for attr, val in attrs.items(): entry.set(attr, val)
def bind_entry(self, entry, metadata): """Build literal file information.""" self.template.metadata = metadata self.searchlist['metadata'] = metadata self.template.path = entry.get('realname', entry.get('name')) self.searchlist['path'] = entry.get('realname', entry.get('name')) self.template.source_path = self.name self.searchlist['source_path'] = self.name if entry.tag == 'Path': entry.set('type', 'file') try: if type(self.template) == unicode: entry.text = self.template else: if entry.get('encoding') == 'base64': # take care of case where file needs base64 encoding entry.text = b64encode(self.template) else: entry.text = unicode(str(self.template), self.encoding) except: (a, b, c) = sys.exc_info() msg = traceback.format_exception(a, b, c, limit=2)[-1][:-1] logger.error(msg) logger.error("TCheetah template error for %s" % self.searchlist['path']) del a, b, c raise Bcfg2.Server.Plugin.PluginExecutionError
def test_get_data(self): orig_entry = lxml.etree.Element("Path", name="/test", type="file") setup = dict(encoding="ascii", ppath='/', max_copies=5) ptool = self.get_obj(posix=get_posix_object(setup=setup)) entry = copy.deepcopy(orig_entry) entry.text = b64encode("test") entry.set("encoding", "base64") self.assertEqual(ptool._get_data(entry), ("test", True)) entry = copy.deepcopy(orig_entry) entry.set("empty", "true") self.assertEqual(ptool._get_data(entry), ("", False)) entry = copy.deepcopy(orig_entry) entry.text = "test" self.assertEqual(ptool._get_data(entry), ("test", False)) if inPy3k: ustr = 'é' else: ustr = u_str('é', 'UTF-8') entry = copy.deepcopy(orig_entry) entry.text = ustr self.assertEqual(ptool._get_data(entry), (ustr, False))
def bind_entry(self, entry, metadata): """Build literal file information.""" fname = entry.get('realname', entry.get('name')) if entry.tag == 'Path': entry.set('type', 'file') try: stream = self.template.generate( \ name=fname, metadata=metadata, path=self.name).filter(removecomment) if have_ntt: ttypes = [TextTemplate, NewTextTemplate] else: ttypes = [TextTemplate] if True in [isinstance(self.template, t) for t in ttypes]: try: textdata = stream.render('text', strip_whitespace=False) except TypeError: textdata = stream.render('text') if type(textdata) == unicode: entry.text = textdata else: if entry.get('encoding') == 'base64': # take care of case where file needs base64 encoding entry.text = b64encode(textdata) else: entry.text = unicode(textdata, self.encoding) else: try: xmldata = stream.render('xml', strip_whitespace=False) except TypeError: xmldata = stream.render('xml') if type(xmldata) == unicode: entry.text = xmldata else: entry.text = unicode(xmldata, self.encoding) if entry.text == '': entry.set('empty', 'true') except TemplateError: err = sys.exc_info()[1] logger.exception('Genshi template error') raise Bcfg2.Server.Plugin.PluginExecutionError('Genshi template error: %s' % err) except AttributeError: err = sys.exc_info()[1] logger.exception('Genshi template loading error') raise Bcfg2.Server.Plugin.PluginExecutionError('Genshi template loading error: %s' % err)
def bind_entry(self, entry, metadata): entry.set('type', 'file') if entry.get('encoding') == 'base64': entry.text = b64encode(self.data) else: try: entry.text = u_str(self.data, self.encoding) except UnicodeDecodeError: e = sys.exc_info()[1] logger.error("Failed to decode %s: %s" % (entry.get('name'), e)) logger.error("Please verify you are using the proper encoding.") raise Bcfg2.Server.Plugin.PluginExecutionError except ValueError: e = sys.exc_info()[1] logger.error("Error in specification for %s" % entry.get('name')) logger.error(str(e)) logger.error("You need to specify base64 encoding for %s." % entry.get('name')) raise Bcfg2.Server.Plugin.PluginExecutionError if entry.text in ['', None]: entry.set('empty', 'true')
def test__get_diffs(self, mock_is_string, mock_get_data, mock_diff, mock_open): orig_entry = lxml.etree.Element("Path", name="/test", type="file", perms='0644', owner='root', group='root') orig_entry.text = "test" ondisk = "test2" setup = dict(encoding="utf-8", ppath='/', max_copies=5) ptool = self.get_obj(posix=get_posix_object(setup=setup)) def reset(): mock_is_string.reset_mock() mock_get_data.reset_mock() mock_diff.reset_mock() mock_open.reset_mock() return copy.deepcopy(orig_entry) mock_is_string.return_value = True mock_get_data.return_value = (orig_entry.text, False) mock_open.return_value.read.return_value = ondisk mock_diff.return_value = ["-test2", "+test"] # binary data in the entry entry = reset() ptool._get_diffs(entry, is_binary=True) mock_open.assert_called_with(entry.get("name")) mock_open.return_value.read.assert_any_call() self.assertFalse(mock_diff.called) self.assertEqual(entry.get("current_bfile"), b64encode(ondisk)) # binary data on disk entry = reset() mock_is_string.return_value = False ptool._get_diffs(entry, content=ondisk) self.assertFalse(mock_open.called) self.assertFalse(mock_diff.called) self.assertEqual(entry.get("current_bfile"), b64encode(ondisk)) # sensitive, non-interactive -- do nothing entry = reset() mock_is_string.return_value = True ptool._get_diffs(entry, sensitive=True, interactive=False) self.assertFalse(mock_open.called) self.assertFalse(mock_diff.called) self.assertXMLEqual(entry, orig_entry) # sensitive, interactive entry = reset() ptool._get_diffs(entry, sensitive=True, interactive=True) mock_open.assert_called_with(entry.get("name")) mock_open.return_value.read.assert_any_call() mock_diff.assert_called_with(ondisk, entry.text, difflib.unified_diff, filename=entry.get("name")) self.assertIsNotNone(entry.get("qtext")) del entry.attrib['qtext'] self.assertItemsEqual(orig_entry.attrib, entry.attrib) # non-sensitive, non-interactive entry = reset() ptool._get_diffs(entry, content=ondisk) self.assertFalse(mock_open.called) mock_diff.assert_called_with(ondisk, entry.text, difflib.ndiff, filename=entry.get("name")) self.assertIsNone(entry.get("qtext")) self.assertEqual(entry.get("current_bdiff"), b64encode("\n".join(mock_diff.return_value))) del entry.attrib["current_bdiff"] self.assertItemsEqual(orig_entry.attrib, entry.attrib) # non-sensitive, interactive -- do everything. also test # appending to qtext entry = reset() entry.set("qtext", "test") ptool._get_diffs(entry, interactive=True) mock_open.assert_called_with(entry.get("name")) mock_open.return_value.read.assert_any_call() self.assertItemsEqual(mock_diff.call_args_list, [call(ondisk, entry.text, difflib.unified_diff, filename=entry.get("name")), call(ondisk, entry.text, difflib.ndiff, filename=entry.get("name"))]) self.assertIsNotNone(entry.get("qtext")) self.assertTrue(entry.get("qtext").startswith("test\n")) self.assertEqual(entry.get("current_bdiff"), b64encode("\n".join(mock_diff.return_value))) del entry.attrib['qtext'] del entry.attrib["current_bdiff"] self.assertItemsEqual(orig_entry.attrib, entry.attrib) # non-sensitive, interactive with unicode data entry = reset() entry.text = u("tëst") encoded = entry.text.encode(setup['encoding']) mock_get_data.return_value = (encoded, False) ptool._get_diffs(entry, interactive=True) mock_open.assert_called_with(entry.get("name")) mock_open.return_value.read.assert_any_call() self.assertItemsEqual(mock_diff.call_args_list, [call(ondisk, encoded, difflib.unified_diff, filename=entry.get("name")), call(ondisk, encoded, difflib.ndiff, filename=entry.get("name"))]) self.assertIsNotNone(entry.get("qtext")) self.assertEqual(entry.get("current_bdiff"), b64encode("\n".join(mock_diff.return_value))) del entry.attrib['qtext'] del entry.attrib["current_bdiff"] self.assertItemsEqual(orig_entry.attrib, entry.attrib)
def bind_entry(self, entry, _): entry.set("encoding", "base64") entry.text = b64encode(self.data)
def bind_entry(self, entry, metadata): info_handlers = [] generators = [] filters = [] verifiers = [] for ent in self.entries.values(): if ent.__specific__ and not ent.specific.matches(metadata): continue if isinstance(ent, CfgInfo): info_handlers.append(ent) elif isinstance(ent, CfgGenerator): generators.append(ent) elif isinstance(ent, CfgFilter): filters.append(ent) elif isinstance(ent, CfgVerifier): verifiers.append(ent) DEFAULT_INFO.bind_info_to_entry(entry, metadata) if len(info_handlers) > 1: logger.error("More than one info supplier found for %s: %s" % (self.name, info_handlers)) if len(info_handlers): info_handlers[0].bind_info_to_entry(entry, metadata) if entry.tag == 'Path': entry.set('type', 'file') generator = self.best_matching(metadata, generators) if entry.get('perms').lower() == 'inherit': # use on-disk permissions fname = os.path.join(self.path, generator.name) entry.set('perms', str(oct(stat.S_IMODE(os.stat(fname).st_mode)))) try: data = generator.get_data(entry, metadata) except: msg = "Cfg: exception rendering %s with %s: %s" % \ (entry.get("name"), generator, sys.exc_info()[1]) logger.error(msg) raise Bcfg2.Server.Plugin.PluginExecutionError(msg) for fltr in filters: data = fltr.modify_data(entry, metadata, data) if SETUP['validate']: # we can have multiple verifiers, but we only want to use the # best matching verifier of each class verifiers_by_class = dict() for verifier in verifiers: cls = verifier.__class__.__name__ if cls not in verifiers_by_class: verifiers_by_class[cls] = [verifier] else: verifiers_by_class[cls].append(verifier) for verifiers in verifiers_by_class.values(): verifier = self.best_matching(metadata, verifiers) try: verifier.verify_entry(entry, metadata, data) except CfgVerificationError: msg = "Data for %s for %s failed to verify: %s" % \ (entry.get('name'), metadata.hostname, sys.exc_info()[1]) logger.error(msg) raise Bcfg2.Server.Plugin.PluginExecutionError(msg) if entry.get('encoding') == 'base64': data = b64encode(data) else: try: if not isinstance(data, unicode): data = u_str(data, self.encoding) except UnicodeDecodeError: msg = "Failed to decode %s: %s" % (entry.get('name'), sys.exc_info()[1]) logger.error(msg) logger.error("Please verify you are using the proper encoding.") raise Bcfg2.Server.Plugin.PluginExecutionError(msg) except ValueError: msg = "Error in specification for %s: %s" % (entry.get('name'), sys.exc_info()[1]) logger.error(msg) logger.error("You need to specify base64 encoding for %s." % entry.get('name')) raise Bcfg2.Server.Plugin.PluginExecutionError(msg) except TypeError: # data is already unicode; newer versions of Cheetah # seem to return unicode pass if data: entry.text = data else: entry.set('empty', 'true')