Example #1
0
    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)
Example #2
0
    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)
Example #3
0
File: File.py Project: ab/bcfg2
    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)
Example #4
0
    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')
Example #5
0
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"
Example #6
0
    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')
Example #7
0
File: TestFile.py Project: ab/bcfg2
    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))
Example #8
0
    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))
Example #9
0
    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))
Example #10
0
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"
Example #11
0
    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))
Example #12
0
    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
Example #13
0
    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
Example #14
0
    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")
Example #15
0
 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))
Example #16
0
 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))
Example #17
0
    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
Example #18
0
    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))
Example #19
0
    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
Example #20
0
    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
Example #21
0
    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
Example #22
0
    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
Example #23
0
    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
Example #24
0
 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)
Example #25
0
 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)
Example #26
0
File: SSHbase.py Project: ab/bcfg2
 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')
Example #27
0
File: __init__.py Project: ab/bcfg2
    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')
Example #28
0
    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)
Example #29
0
    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)
Example #30
0
File: TestFile.py Project: ab/bcfg2
    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)
Example #31
0
    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)
Example #32
0
 def bind_entry(self, entry, _):
     entry.set('encoding', 'base64')
     entry.text = b64encode(self.data)