def _get_diffs(self, entry, interactive=False, # pylint: disable=R0912 sensitive=False, is_binary=False, content=None): """ generate the necessary diffs for entry """ 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 UnicodeDecodeError: content = open(entry.get('name'), encoding='utf-8').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, Bcfg2.Options.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: diff = self._diff(content, self._get_data(entry)[0], filename=entry.get("name")) if interactive: if diff: udiff = '\n'.join(diff) if hasattr(udiff, "decode"): udiff = udiff.decode(Bcfg2.Options.setup.encoding) try: prompt.append(udiff) except UnicodeEncodeError: prompt.append("Could not encode diff") elif entry.get("empty", "true"): # the file doesn't exist on disk, but there's no # expected content prompt.append("%s does not exist" % entry.get("name")) else: prompt.append("Diff took too long to compute, no " "printable diff") if not sensitive: 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 _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, _): """ Bind the entry with the data of this key :param entry: The abstract entry to bind. This will be modified in place. :type entry: lxml.etree._Element :returns: None """ entry.set('type', 'file') if entry.get('encoding') == 'base64': entry.text = b64encode(self.data) else: try: entry.text = u_str(self.data, Bcfg2.Options.setup.encoding) except UnicodeDecodeError: msg = "Failed to decode %s: %s" % (entry.get('name'), sys.exc_info()[1]) self.logger.error(msg) self.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]) self.logger.error(msg) self.logger.error("You need to specify base64 encoding for %s" % entry.get('name')) raise Bcfg2.Server.Plugin.PluginExecutionError(msg) if entry.text in ['', None]: entry.set('empty', 'true')
def ssl_encrypt(plaintext, passwd, algorithm=None, salt=None): """ Encrypt data in a format that is openssl compatible. :param plaintext: The plaintext data to encrypt :type plaintext: string :param passwd: The password to use to encrypt the data :type passwd: string :param algorithm: The cipher algorithm to use :type algorithm: string :param salt: The salt to use. If none is provided, one will be randomly generated. :type salt: bytes :returns: string - The base64-encoded, salted, encrypted string. The string includes a trailing newline to make it fully compatible with openssl command-line tools. """ if salt is None: salt = Rand.rand_bytes(8) # pylint: disable=E1101,E1121 hashes = [md5(passwd + salt).digest()] for i in range(1, 3): hashes.append(md5(hashes[i - 1] + passwd + salt).digest()) # pylint: enable=E1101,E1121 key = hashes[0] + hashes[1] iv = hashes[2] crypted = str_encrypt(plaintext, key=key, salt=salt, iv=iv, algorithm=algorithm) return b64encode("Salted__" + salt + crypted) + "\n"
def bind_entry(self, entry, _): """ Bind the entry with the data of this key :param entry: The abstract entry to bind. This will be modified in place. :type entry: lxml.etree._Element :returns: None """ 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: 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) if entry.text in ['', None]: entry.set('empty', 'true')
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 test_get_data(self): orig_entry = lxml.etree.Element("Path", name="/test", type="file") Bcfg2.Options.setup.encoding = "ascii" ptool = self.get_obj() 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("encoding", "base64") entry.set("empty", "true") self.assertEqual(ptool._get_data(entry), ("", True)) entry = copy.deepcopy(orig_entry) entry.set("empty", "true") self.assertEqual(ptool._get_data(entry), ("", False)) entry = copy.deepcopy(orig_entry) 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.""" 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 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 bind_entry(self, entry, _): """ Bind the entry with the data of this key :param entry: The abstract entry to bind. This will be modified in place. :type entry: lxml.etree._Element :returns: None """ 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: 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) if entry.text in ["", None]: entry.set("empty", "true")
def test_bind_entry(self): data = self.get_obj() data.data = "test" entry = lxml.etree.Element("test", name=self.path) data.bind_entry(entry, Mock()) self.assertEqual(entry.get("name"), self.path) self.assertEqual(entry.get("encoding"), "base64") self.assertEqual(entry.text, b64encode(data.data))
def bind_entry(self, entry, metadata): self.bind_info_to_entry(entry, metadata) data, generator = self._generate_data(entry, metadata) if generator is not None: # apply no filters if the data was created by a CfgCreator for fltr in self.get_handlers(metadata, CfgFilter): if fltr.specific <= generator.specific: # only apply filters that are as specific or more # specific than the generator used for this entry. # Note that specificity comparison is backwards in # this sense, since it's designed to sort from # most specific to least specific. data = fltr.modify_data(entry, metadata, data) if Bcfg2.Options.setup.cfg_validation: try: self._validate_data(entry, metadata, data) except CfgVerificationError: raise PluginExecutionError("Failed to verify %s for %s: %s" % (entry.get('name'), metadata.hostname, sys.exc_info()[1])) if entry.get('encoding') == 'base64': data = b64encode(data) else: try: if not isinstance(data, unicode): if not isinstance(data, str): data = data.decode('utf-8') data = u_str(data, Bcfg2.Options.setup.encoding) except UnicodeDecodeError: msg = "Failed to decode %s: %s" % (entry.get('name'), sys.exc_info()[1]) self.logger.error(msg) self.logger.error("Please verify you are using the proper " "encoding") raise PluginExecutionError(msg) except ValueError: msg = "Error in specification for %s: %s" % (entry.get('name'), sys.exc_info()[1]) self.logger.error(msg) self.logger.error("You need to specify base64 encoding for %s" % entry.get('name')) raise 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') return entry
def test_bruteforce_decrypt(self): passwd = "a simple passphrase" crypted = ssl_encrypt(self.plaintext, passwd) # test with no passphrases given nor in config Bcfg2.Options.setup.passphrases = dict() self.assertRaises(EVPError, bruteforce_decrypt, crypted) # test with good passphrase given in function call self.assertEqual(self.plaintext, bruteforce_decrypt(crypted, passphrases=["bogus pass", passwd, "also bogus"])) # test with no good passphrase given nor in config. we use # something that isn't a valid ciphertext here since a # ciphertext encrypted with one key may be technically # decryptable with a different key, although it will decrypt # to gibberish. nonetheless, it doesn't raise the requisite # EVPError, so the test fails. self.assertRaises(EVPError, bruteforce_decrypt, b64encode("not an actual ciphertext!"), passphrases=["bogus", "also bogus"]) # test with no good passphrase given nor in config. this # version of the test uses a valid ciphertext, and looks for # *either* EVPError or a failed decrypt. try: plaintext = bruteforce_decrypt(crypted, passphrases=["bogus", "also bogus"]) if plaintext == passwd: self.fail("Successfully decrypted ciphertext with wrong key") except EVPError: # success! pass # test with good passphrase in config file Bcfg2.Options.setup.passphrases = dict(bogus="bogus", real=passwd, bogus2="also bogus") self.assertEqual(self.plaintext, bruteforce_decrypt(crypted)) # test that passphrases given in function call take # precedence over config self.assertRaises(EVPError, bruteforce_decrypt, crypted, passphrases=["bogus", "also bogus"]) # test that different algorithms are used crypted = ssl_encrypt(self.plaintext, passwd, algorithm=self.algo) self.assertEqual(self.plaintext, bruteforce_decrypt(crypted, algorithm=self.algo))
def bind_entry(self, entry, metadata): self.bind_info_to_entry(entry, metadata) data, generator = self._generate_data(entry, metadata) if generator is not None: # apply no filters if the data was created by a CfgCreator for fltr in self.get_handlers(metadata, CfgFilter): if fltr.specific <= generator.specific: # only apply filters that are as specific or more # specific than the generator used for this entry. # Note that specificity comparison is backwards in # this sense, since it's designed to sort from # most specific to least specific. data = fltr.modify_data(entry, metadata, data) if SETUP['validate']: try: self._validate_data(entry, metadata, data) except CfgVerificationError: raise PluginExecutionError( "Failed to verify %s for %s: %s" % (entry.get('name'), metadata.hostname, sys.exc_info()[1])) if entry.get('encoding') == 'base64': data = b64encode(data) else: try: if not isinstance(data, unicode): if not isinstance(data, str): data = data.decode('utf-8') data = u_str(data, self.encoding) except UnicodeDecodeError: msg = "Failed to decode %s: %s" % (entry.get('name'), sys.exc_info()[1]) self.logger.error(msg) self.logger.error("Please verify you are using the proper " "encoding") raise PluginExecutionError(msg) except ValueError: msg = "Error in specification for %s: %s" % (entry.get('name'), sys.exc_info()[1]) self.logger.error(msg) self.logger.error( "You need to specify base64 encoding for %s" % entry.get('name')) raise 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') return entry
def bind_entry(self, entry, _): """ Return a fully-bound entry. The module data is automatically encoded with base64. :param entry: The abstract entry to bind the module for :type entry: lxml.etree._Element :returns: lxml.etree._Element - the fully bound entry """ entry.set('encoding', 'base64') entry.text = b64encode(self.data) return entry
def bind_entry(self, entry, metadata): self.bind_info_to_entry(entry, metadata) data = self._generate_data(entry, metadata) for fltr in self.get_handlers(metadata, CfgFilter): data = fltr.modify_data(entry, metadata, data) if self.setup['validate']: try: self._validate_data(entry, metadata, data) except CfgVerificationError: raise PluginExecutionError("Failed to verify %s for %s: %s" % (entry.get('name'), metadata.hostname, sys.exc_info()[1])) if entry.get('encoding') == 'base64': data = b64encode(data) else: try: if not isinstance(data, unicode): if not isinstance(data, str): data = data.decode('utf-8') data = u_str(data, self.encoding) except UnicodeDecodeError: msg = "Failed to decode %s: %s" % (entry.get('name'), sys.exc_info()[1]) self.logger.error(msg) self.logger.error("Please verify you are using the proper " "encoding") raise PluginExecutionError(msg) except ValueError: msg = "Error in specification for %s: %s" % (entry.get('name'), sys.exc_info()[1]) self.logger.error(msg) self.logger.error("You need to specify base64 encoding for %s" % entry.get('name')) raise 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') return entry
def bind_entry(self, entry, metadata): self.bind_info_to_entry(entry, metadata) data = self._generate_data(entry, metadata) for fltr in self.get_handlers(metadata, CfgFilter): data = fltr.modify_data(entry, metadata, data) if self.setup['validate']: try: self._validate_data(entry, metadata, data) except CfgVerificationError: raise PluginExecutionError( "Failed to verify %s for %s: %s" % (entry.get('name'), metadata.hostname, sys.exc_info()[1])) if entry.get('encoding') == 'base64': data = b64encode(data) else: try: if not isinstance(data, unicode): if not isinstance(data, str): data = data.decode('utf-8') data = u_str(data, self.encoding) except UnicodeDecodeError: msg = "Failed to decode %s: %s" % (entry.get('name'), sys.exc_info()[1]) self.logger.error(msg) self.logger.error("Please verify you are using the proper " "encoding") raise PluginExecutionError(msg) except ValueError: msg = "Error in specification for %s: %s" % (entry.get('name'), sys.exc_info()[1]) self.logger.error(msg) self.logger.error( "You need to specify base64 encoding for %s" % entry.get('name')) raise 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') return entry
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): """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 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) if ent.deprecated: if ent.__basenames__: fdesc = "/".join(ent.__basenames__) elif ent.__extensions__: fdesc = "." + "/.".join(ent.__extensions__) logger.warning("Cfg: %s: Use of %s files is deprecated" % (ent.name, fdesc)) DEFAULT_INFO.bind_info_to_entry(entry, metadata) if len(info_handlers) > 1: logger.error("More than one info supplier found for %s: %s" % (entry.get("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')
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_diff.return_value = ["-test2", "+tëst"] 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 test__get_diffs(self, mock_utils, mock_open): orig_entry = lxml.etree.Element("Path", name="/test", type="file", mode='0644', owner='root', group='root') orig_entry.text = "test" ondisk = "test2" Bcfg2.Options.setup.encoding = "utf-8" ptool = self.get_obj() ptool._get_data = Mock() ptool._diff = Mock() def reset(): mock_utils.is_string.reset_mock() ptool._get_data.reset_mock() ptool._diff.reset_mock() mock_open.reset_mock() return copy.deepcopy(orig_entry) mock_utils.is_string.return_value = True ptool._get_data.return_value = (orig_entry.text, False) mock_open.return_value.read.return_value = ondisk ptool._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(ptool._diff.called) self.assertEqual(entry.get("current_bfile"), b64encode(ondisk)) # binary data on disk entry = reset() mock_utils.is_string.return_value = False ptool._get_diffs(entry, content=ondisk) self.assertFalse(mock_open.called) self.assertFalse(ptool._diff.called) self.assertEqual(entry.get("current_bfile"), b64encode(ondisk)) # sensitive, non-interactive -- do nothing entry = reset() mock_utils.is_string.return_value = True ptool._get_diffs(entry, sensitive=True, interactive=False) self.assertFalse(mock_open.called) self.assertFalse(ptool._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() ptool._diff.assert_called_with(ondisk, entry.text, 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) ptool._diff.assert_called_with(ondisk, entry.text, filename=entry.get("name")) self.assertIsNone(entry.get("qtext")) self.assertEqual(entry.get("current_bdiff"), b64encode("\n".join(ptool._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( ptool._diff.call_args_list, [call(ondisk, entry.text, 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(ptool._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(Bcfg2.Options.setup.encoding) ptool._diff.return_value = ["-test2", "+tëst"] ptool._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( ptool._diff.call_args_list, [call(ondisk, encoded, filename=entry.get("name"))]) self.assertIsNotNone(entry.get("qtext")) self.assertEqual(entry.get("current_bdiff"), b64encode("\n".join(ptool._diff.return_value))) del entry.attrib['qtext'] del entry.attrib["current_bdiff"] self.assertItemsEqual(orig_entry.attrib, entry.attrib)
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_diff.return_value = ["-test2", "+tëst"] 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 test__get_diffs(self, mock_utils, mock_open): orig_entry = lxml.etree.Element("Path", name="/test", type="file", mode='0644', owner='root', group='root') orig_entry.text = "test" ondisk = "test2" Bcfg2.Options.setup.encoding = "utf-8" ptool = self.get_obj() ptool._get_data = Mock() ptool._diff = Mock() def reset(): mock_utils.is_string.reset_mock() ptool._get_data.reset_mock() ptool._diff.reset_mock() mock_open.reset_mock() return copy.deepcopy(orig_entry) mock_utils.is_string.return_value = True ptool._get_data.return_value = (orig_entry.text, False) mock_open.return_value.read.return_value = ondisk ptool._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(ptool._diff.called) self.assertEqual(entry.get("current_bfile"), b64encode(ondisk)) # binary data on disk entry = reset() mock_utils.is_string.return_value = False ptool._get_diffs(entry, content=ondisk) self.assertFalse(mock_open.called) self.assertFalse(ptool._diff.called) self.assertEqual(entry.get("current_bfile"), b64encode(ondisk)) # sensitive, non-interactive -- do nothing entry = reset() mock_utils.is_string.return_value = True ptool._get_diffs(entry, sensitive=True, interactive=False) self.assertFalse(mock_open.called) self.assertFalse(ptool._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() ptool._diff.assert_called_with(ondisk, entry.text, 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) ptool._diff.assert_called_with(ondisk, entry.text, filename=entry.get("name")) self.assertIsNone(entry.get("qtext")) self.assertEqual(entry.get("current_bdiff"), b64encode("\n".join(ptool._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(ptool._diff.call_args_list, [call(ondisk, entry.text, 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(ptool._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(Bcfg2.Options.setup.encoding) ptool._diff.return_value = ["-test2", "+tëst"] ptool._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(ptool._diff.call_args_list, [call(ondisk, encoded, filename=entry.get("name"))]) self.assertIsNotNone(entry.get("qtext")) self.assertEqual(entry.get("current_bdiff"), b64encode("\n".join(ptool._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)