diff --git a/certbot-apache/certbot_apache/apacheparser.py b/certbot-apache/certbot_apache/apacheparser.py new file mode 100644 index 000000000..6625735b4 --- /dev/null +++ b/certbot-apache/certbot_apache/apacheparser.py @@ -0,0 +1,157 @@ +""" apacheconfig implementation of the ParserNode interfaces """ + +from certbot_apache import assertions +from certbot_apache import interfaces +from certbot_apache import parsernode_util as util + + +class ApacheParserNode(interfaces.ParserNode): + """ apacheconfig implementation of ParserNode interface. + + Expects metadata `ac_ast` to be passed in, where `ac_ast` is the AST provided + by parsing the equivalent configuration text using the apacheconfig library. + """ + + def __init__(self, **kwargs): + ancestor, dirty, filepath, metadata = util.parsernode_kwargs(kwargs) # pylint: disable=unused-variable + super(ApacheParserNode, self).__init__(**kwargs) + self.ancestor = ancestor + self.filepath = filepath + self.dirty = dirty + self.metadata = metadata + self._raw = self.metadata["ac_ast"] + + def save(self, msg): # pragma: no cover + pass + + +class ApacheCommentNode(ApacheParserNode): + """ apacheconfig implementation of CommentNode interface """ + + def __init__(self, **kwargs): + comment, kwargs = util.commentnode_kwargs(kwargs) # pylint: disable=unused-variable + super(ApacheCommentNode, self).__init__(**kwargs) + self.comment = comment + + def __eq__(self, other): # pragma: no cover + if isinstance(other, self.__class__): + return (self.comment == other.comment and + self.dirty == other.dirty and + self.ancestor == other.ancestor and + self.metadata == other.metadata and + self.filepath == other.filepath) + return False + + +class ApacheDirectiveNode(ApacheParserNode): + """ apacheconfig implementation of DirectiveNode interface """ + + def __init__(self, **kwargs): + name, parameters, enabled, kwargs = util.directivenode_kwargs(kwargs) + super(ApacheDirectiveNode, self).__init__(**kwargs) + self.name = name + self.parameters = parameters + self.enabled = enabled + self.include = None + + def __eq__(self, other): # pragma: no cover + if isinstance(other, self.__class__): + return (self.name == other.name and + self.filepath == other.filepath and + self.parameters == other.parameters and + self.enabled == other.enabled and + self.dirty == other.dirty and + self.ancestor == other.ancestor and + self.metadata == other.metadata) + return False + + def set_parameters(self, parameters): + """Sets the parameters for DirectiveNode""" + pass + + +class ApacheBlockNode(ApacheDirectiveNode): + """ apacheconfig implementation of BlockNode interface """ + + def __init__(self, **kwargs): + super(ApacheBlockNode, self).__init__(**kwargs) + self.children = () + + def __eq__(self, other): # pragma: no cover + if isinstance(other, self.__class__): + return (self.name == other.name and + self.filepath == other.filepath and + self.parameters == other.parameters and + self.children == other.children and + self.enabled == other.enabled and + self.dirty == other.dirty and + self.ancestor == other.ancestor and + self.metadata == other.metadata) + return False + + def add_child_block(self, name, parameters=None, position=None): # pylint: disable=unused-argument + """Adds a new BlockNode to the sequence of children""" + new_block = ApacheBlockNode(name=assertions.PASS, + parameters=assertions.PASS, + ancestor=self, + filepath=assertions.PASS, + metadata=self.metadata) + self.children += (new_block,) + return new_block + + def add_child_directive(self, name, parameters=None, position=None): # pylint: disable=unused-argument + """Adds a new DirectiveNode to the sequence of children""" + new_dir = ApacheDirectiveNode(name=assertions.PASS, + parameters=assertions.PASS, + ancestor=self, + filepath=assertions.PASS, + metadata=self.metadata) + self.children += (new_dir,) + return new_dir + + # pylint: disable=unused-argument + def add_child_comment(self, comment="", position=None): # pragma: no cover + + """Adds a new CommentNode to the sequence of children""" + new_comment = ApacheCommentNode(comment=assertions.PASS, + ancestor=self, + filepath=assertions.PASS, + metadata=self.metadata) + self.children += (new_comment,) + return new_comment + + def find_blocks(self, name, exclude=True): # pylint: disable=unused-argument + """Recursive search of BlockNodes from the sequence of children""" + return [ApacheBlockNode(name=assertions.PASS, + parameters=assertions.PASS, + ancestor=self, + filepath=assertions.PASS, + metadata=self.metadata)] + + def find_directives(self, name, exclude=True): # pylint: disable=unused-argument + """Recursive search of DirectiveNodes from the sequence of children""" + return [ApacheDirectiveNode(name=assertions.PASS, + parameters=assertions.PASS, + ancestor=self, + filepath=assertions.PASS, + metadata=self.metadata)] + + def find_comments(self, comment, exact=False): # pylint: disable=unused-argument + """Recursive search of DirectiveNodes from the sequence of children""" + return [ApacheCommentNode(comment=assertions.PASS, + ancestor=self, + filepath=assertions.PASS, + metadata=self.metadata)] + + def delete_child(self, child): # pragma: no cover + """Deletes a ParserNode from the sequence of children""" + pass + + def unsaved_files(self): # pragma: no cover + """Returns a list of unsaved filepaths""" + return [assertions.PASS] + + +interfaces.CommentNode.register(ApacheCommentNode) +interfaces.DirectiveNode.register(ApacheDirectiveNode) +interfaces.BlockNode.register(ApacheBlockNode) diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index 808748006..2b20ebb7c 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -258,7 +258,8 @@ class ApacheConfigurator(common.Installer): # Set up ParserNode root pn_meta = {"augeasparser": self.parser, - "augeaspath": self.parser.get_root_augpath()} + "augeaspath": self.parser.get_root_augpath(), + "ac_ast": None} self.parser_root = self.get_parsernode_root(pn_meta) # Check for errors in parsing files with Augeas diff --git a/certbot-apache/certbot_apache/dualparser.py b/certbot-apache/certbot_apache/dualparser.py index 769933ae0..5899aaca6 100644 --- a/certbot-apache/certbot_apache/dualparser.py +++ b/certbot-apache/certbot_apache/dualparser.py @@ -1,6 +1,7 @@ """ Dual ParserNode implementation """ from certbot_apache import assertions from certbot_apache import augeasparser +from certbot_apache import apacheparser class DualNodeBase(object): @@ -57,7 +58,7 @@ class DualCommentNode(DualNodeBase): self.secondary = secondary else: self.primary = augeasparser.AugeasCommentNode(**kwargs) - self.secondary = augeasparser.AugeasCommentNode(**kwargs) + self.secondary = apacheparser.ApacheCommentNode(**kwargs) assertions.assertEqual(self.primary, self.secondary) @@ -91,7 +92,7 @@ class DualDirectiveNode(DualNodeBase): self.secondary = secondary else: self.primary = augeasparser.AugeasDirectiveNode(**kwargs) - self.secondary = augeasparser.AugeasDirectiveNode(**kwargs) + self.secondary = apacheparser.ApacheDirectiveNode(**kwargs) assertions.assertEqual(self.primary, self.secondary) @@ -131,7 +132,7 @@ class DualBlockNode(DualNodeBase): self.secondary = secondary else: self.primary = augeasparser.AugeasBlockNode(**kwargs) - self.secondary = augeasparser.AugeasBlockNode(**kwargs) + self.secondary = apacheparser.ApacheBlockNode(**kwargs) assertions.assertEqual(self.primary, self.secondary) diff --git a/certbot-apache/certbot_apache/tests/augeasnode_test.py b/certbot-apache/certbot_apache/tests/augeasnode_test.py index 5012eb133..c97cec497 100644 --- a/certbot-apache/certbot_apache/tests/augeasnode_test.py +++ b/certbot-apache/certbot_apache/tests/augeasnode_test.py @@ -110,7 +110,7 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- name=servernames[0].name, parameters=["test", "setting", "these"], ancestor=assertions.PASS, - metadata=servernames[0].metadata + metadata=servernames[0].primary.metadata ) self.assertTrue(mock_set.called) self.assertEqual( @@ -145,11 +145,11 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- self.assertTrue(found) def test_delete_child(self): - listens = self.config.parser_root.find_directives("Listen") + listens = self.config.parser_root.primary.find_directives("Listen") self.assertEqual(len(listens), 1) self.config.parser_root.primary.delete_child(listens[0]) - listens = self.config.parser_root.find_directives("Listen") + listens = self.config.parser_root.primary.find_directives("Listen") self.assertEqual(len(listens), 0) def test_delete_child_not_found(self): @@ -163,11 +163,11 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- ) def test_add_child_block(self): - nb = self.config.parser_root.primary.add_child_block( + nb = self.config.parser_root.add_child_block( "NewBlock", ["first", "second"] ) - rpath, _, directive = nb.metadata["augeaspath"].rpartition("/") + rpath, _, directive = nb.primary.metadata["augeaspath"].rpartition("/") self.assertEqual( rpath, self.config.parser_root.primary.metadata["augeaspath"] @@ -175,7 +175,7 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- self.assertTrue(directive.startswith("NewBlock")) def test_add_child_block_beginning(self): - self.config.parser_root.primary.add_child_block( + self.config.parser_root.add_child_block( "Beginning", position=0 ) @@ -186,7 +186,7 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- self.assertTrue(first[0].endswith("Beginning")) def test_add_child_block_append(self): - self.config.parser_root.primary.add_child_block( + self.config.parser_root.add_child_block( "VeryLast", ) parser = self.config.parser_root.primary.parser @@ -196,7 +196,7 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- self.assertTrue(last[0].endswith("VeryLast")) def test_add_child_block_append_alt(self): - self.config.parser_root.primary.add_child_block( + self.config.parser_root.add_child_block( "VeryLastAlt", position=99999 ) @@ -207,7 +207,7 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- self.assertTrue(last[0].endswith("VeryLastAlt")) def test_add_child_block_middle(self): - self.config.parser_root.primary.add_child_block( + self.config.parser_root.add_child_block( "Middle", position=5 ) @@ -223,12 +223,12 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- # There already exists a single VirtualHost in the base config new_block = parser.aug.match("{}/VirtualHost[2]".format(root_path)) self.assertEqual(len(new_block), 0) - vh = self.config.parser_root.primary.add_child_block( + vh = self.config.parser_root.add_child_block( "VirtualHost", ) new_block = parser.aug.match("{}/VirtualHost[2]".format(root_path)) self.assertEqual(len(new_block), 1) - self.assertTrue(vh.metadata["augeaspath"].endswith("VirtualHost[2]")) + self.assertTrue(vh.primary.metadata["augeaspath"].endswith("VirtualHost[2]")) def test_node_init_error_bad_augeaspath(self): from certbot_apache.augeasparser import AugeasBlockNode @@ -264,7 +264,7 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- ) def test_add_child_directive(self): - self.config.parser_root.primary.add_child_directive( + self.config.parser_root.add_child_directive( "ThisWasAdded", ["with", "parameters"], position=0 @@ -273,12 +273,12 @@ class AugeasParserNodeTest(util.ApacheTest): # pylint: disable=too-many-public- self.assertEqual(len(dirs), 1) self.assertEqual(dirs[0].parameters, ("with", "parameters")) # The new directive was added to the very first line of the config - self.assertTrue(dirs[0].metadata["augeaspath"].endswith("[1]")) + self.assertTrue(dirs[0].primary.metadata["augeaspath"].endswith("[1]")) def test_add_child_directive_exception(self): self.assertRaises( errors.PluginError, - self.config.parser_root.primary.add_child_directive, + self.config.parser_root.add_child_directive, "ThisRaisesErrorBecauseMissingParameters" ) diff --git a/certbot-apache/certbot_apache/tests/dualnode_test.py b/certbot-apache/certbot_apache/tests/dualnode_test.py index f0fa818a7..1ed4a43ad 100644 --- a/certbot-apache/certbot_apache/tests/dualnode_test.py +++ b/certbot-apache/certbot_apache/tests/dualnode_test.py @@ -16,7 +16,7 @@ class DualParserNodeTest(unittest.TestCase): # pylint: disable=too-many-public- parser_mock = mock.MagicMock() parser_mock.aug.match.return_value = [] parser_mock.get_arg.return_value = [] - self.metadata = {"augeasparser": parser_mock, "augeaspath": "/invalid"} + self.metadata = {"augeasparser": parser_mock, "augeaspath": "/invalid", "ac_ast": None} self.block = dualparser.DualBlockNode(name="block", ancestor=None, filepath="/tmp/something",