Example #1
0
    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 #2
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 #3
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 #4
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 #5
0
 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 #6
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_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 #7
0
 def bind_entry(self, entry, _):
     entry.set("encoding", "base64")
     entry.text = b64encode(self.data)
Example #8
0
    def bind_entry(self, entry, metadata):
        info_handlers = []
        generators = []
        filters = []
        verifiers = []
        for ent in self.entries.values():
            if ent.__specific__ and not ent.specific.matches(metadata):
                continue
            if isinstance(ent, CfgInfo):
                info_handlers.append(ent)
            elif isinstance(ent, CfgGenerator):
                generators.append(ent)
            elif isinstance(ent, CfgFilter):
                filters.append(ent)
            elif isinstance(ent, CfgVerifier):
                verifiers.append(ent)

        DEFAULT_INFO.bind_info_to_entry(entry, metadata)
        if len(info_handlers) > 1:
            logger.error("More than one info supplier found for %s: %s" %
                         (self.name, info_handlers))
        if len(info_handlers):
            info_handlers[0].bind_info_to_entry(entry, metadata)
        if entry.tag == 'Path':
            entry.set('type', 'file')

        generator = self.best_matching(metadata, generators)
        if entry.get('perms').lower() == 'inherit':
            # use on-disk permissions
            fname = os.path.join(self.path, generator.name)
            entry.set('perms',
                      str(oct(stat.S_IMODE(os.stat(fname).st_mode))))
        try:
            data = generator.get_data(entry, metadata)
        except:
            msg = "Cfg: exception rendering %s with %s: %s" % \
                (entry.get("name"), generator, sys.exc_info()[1])
            logger.error(msg)
            raise Bcfg2.Server.Plugin.PluginExecutionError(msg)

        for fltr in filters:
            data = fltr.modify_data(entry, metadata, data)

        if SETUP['validate']:
            # we can have multiple verifiers, but we only want to use the
            # best matching verifier of each class
            verifiers_by_class = dict()
            for verifier in verifiers:
                cls = verifier.__class__.__name__
                if cls not in verifiers_by_class:
                    verifiers_by_class[cls] = [verifier]
                else:
                    verifiers_by_class[cls].append(verifier)
            for verifiers in verifiers_by_class.values():
                verifier = self.best_matching(metadata, verifiers)
                try:
                    verifier.verify_entry(entry, metadata, data)
                except CfgVerificationError:
                    msg = "Data for %s for %s failed to verify: %s" % \
                        (entry.get('name'), metadata.hostname,
                         sys.exc_info()[1])
                    logger.error(msg)
                    raise Bcfg2.Server.Plugin.PluginExecutionError(msg)
                
        if entry.get('encoding') == 'base64':
            data = b64encode(data)
        else:
            try:
                if not isinstance(data, unicode):
                    data = u_str(data, self.encoding)
            except UnicodeDecodeError:
                msg = "Failed to decode %s: %s" % (entry.get('name'),
                                                   sys.exc_info()[1])
                logger.error(msg)
                logger.error("Please verify you are using the proper encoding.")
                raise Bcfg2.Server.Plugin.PluginExecutionError(msg)
            except ValueError:
                msg = "Error in specification for %s: %s" % (entry.get('name'),
                                                             sys.exc_info()[1])
                logger.error(msg)
                logger.error("You need to specify base64 encoding for %s." %
                             entry.get('name'))
                raise Bcfg2.Server.Plugin.PluginExecutionError(msg)
            except TypeError:
                # data is already unicode; newer versions of Cheetah
                # seem to return unicode
                pass

        if data:
            entry.text = data
        else:
            entry.set('empty', 'true')