]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
manager: datamodel: policy: schema extended by new policy actions
authorAleš Mrázek <ales.mrazek@nic.cz>
Fri, 10 Jun 2022 14:33:04 +0000 (16:33 +0200)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 10 Jun 2022 14:33:04 +0000 (16:33 +0200)
- policy schema tests improved

manager/knot_resolver_manager/datamodel/policy_schema.py
manager/knot_resolver_manager/datamodel/types/enums.py
manager/tests/unit/datamodel/test_policy_schema.py

index a934ac7c2bbbc69ececb05a0666989a121a71049..83379128e1897ed5ede6fdca6580a2e4dbe194b3 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Optional
+from typing import List, Optional, Union
 
 from knot_resolver_manager.datamodel.network_schema import AddressRenumberingSchema
 from knot_resolver_manager.datamodel.types import (
@@ -43,6 +43,10 @@ class AnswerSchema(SchemaNode):
     nodata: bool = False
 
 
+class ForwardServerSchema(SchemaNode):
+    pass
+
+
 class PolicySchema(SchemaNode):
     """
     Configuration of policy rule.
@@ -56,7 +60,7 @@ class PolicySchema(SchemaNode):
     message: Deny message for 'deny' action.
     reroute: Configuration for 'reroute' action.
     answer: Answer definition for 'answer' action.
-    mirror: Mirroring parameters for 'mirror' action.
+    servers: Servers configuration for 'mirror', 'forward', 'forward-tls' and 'stub' action.
     """
 
     action: PolicyActionEnum
@@ -67,16 +71,25 @@ class PolicySchema(SchemaNode):
     message: Optional[str] = None
     reroute: Optional[List[AddressRenumberingSchema]] = None
     answer: Optional[AnswerSchema] = None
-    mirror: Optional[List[IPAddressOptionalPort]] = None
+    servers: Optional[Union[List[IPAddressOptionalPort], List[ForwardServerSchema]]] = None
 
     def _validate(self) -> None:
+        servers = ["mirror", "forward", "forward-tls", "stub"]
+
+        def _field(action: str) -> str:
+            if action in servers:
+                return "servers"
+            return {"deny": "message"}.get(action, action)
+
+        configurable_actions = ["deny", "reroute", "answer"] + servers
+
         # checking for missing mandatory fields for actions
-        mandatory_fields = ["reroute", "answer", "mirror"]
-        if self.action in mandatory_fields and not getattr(self, self.action):
-            raise ValueError(f"missing mandatory field '{self.action}' for '{self.action}' action")
+        field = _field(self.action)
+        if self.action in configurable_actions and not getattr(self, field):
+            raise ValueError(f"missing mandatory field '{field}' for '{self.action}' action")
 
         # checking for unnecessary fields
-        for action in ["deny"] + mandatory_fields:
-            field = {"deny": "message"}.get(action, action)
-            if getattr(self, field) and not self.action == action:
-                raise ValueError(f"'{field}' field can only be defined for '{self.action}' action")
+        for action in configurable_actions + ["deny"]:
+            field = _field(action)
+            if getattr(self, field) and _field(self.action) != field:
+                raise ValueError(f"'{field}' field can only be defined for '{action}' action")
index 6918f8b1a6db109af88ed92105f6e3c0994ccced..292be734a84f2d56426c420233b943bcf3fbe5f3 100644 (file)
@@ -12,6 +12,9 @@ PolicyActionEnum = Literal[
     "answer",
     # Chain actions
     "mirror",
+    "forward",
+    "forward-tls",
+    "stub",
     "debug-always",
     "debug-cache-miss",
     "qtrace",
index cb0dd4a1503a27314b3e2c110a2189662ad64ab2..e2acd529c2351847aaeaff94f5ff1f94a2d14038 100644 (file)
@@ -4,31 +4,55 @@ import pytest
 from pytest import raises
 
 from knot_resolver_manager.datamodel.policy_schema import PolicySchema
+from knot_resolver_manager.datamodel.types import PolicyActionEnum
 from knot_resolver_manager.exceptions import KresManagerException
+from knot_resolver_manager.utils.types import get_generic_type_arguments
+
+noconfig_actions = [
+    "pass",
+    "drop",
+    "refuse",
+    "tc",
+    "debug-always",
+    "debug-cache-miss",
+    "qtrace",
+    "reqtrace",
+]
+configurable_actions = ["deny", "reroute", "answer", "mirror", "forward", "forward-tls", "stub"]
+policy_actions = get_generic_type_arguments(PolicyActionEnum)
+
+
+@pytest.mark.parametrize("val", [item for item in policy_actions if item not in configurable_actions])
+def test_policy_action_valid(val: Any):
+    PolicySchema({"action": val})
 
 
 @pytest.mark.parametrize("val", [{"action": "invalid-action"}])
-def test_simple_actions_invalid(val: Dict[str, Any]):
+def test_action_invalid(val: Dict[str, Any]):
     with raises(KresManagerException):
-        PolicySchema({"action": "invalid-action"})
+        PolicySchema(val)
 
 
 @pytest.mark.parametrize(
     "val",
     [
-        "pass",
-        "drop",
-        "refuse",
-        "tc",
-        "debug-always",
-        "debug-cache-miss",
-        "qtrace",
-        "reqtrace",
+        {"action": "deny", "message": "this is deny message"},
+        {
+            "action": "reroute",
+            "reroute": [
+                {"source": "192.0.2.0/24", "destination": "127.0.0.0"},
+                {"source": "10.10.10.0/24", "destination": "192.168.1.0"},
+            ],
+        },
+        {"action": "answer", "answer": {"rtype": "AAAA", "rdata": "192.0.2.7"}},
+        {"action": "mirror", "servers": ["192.0.2.1@5353", "2001:148f:ffff::1"]},
+        {"action": "forward", "servers": ["192.0.2.1@5353", "2001:148f:ffff::1"]},
+        {"action": "forward-tls", "servers": ["192.0.2.1@5353", "2001:148f:ffff::1"]},
+        {"action": "stub", "servers": ["192.0.2.1@5353", "2001:148f:ffff::1"]},
     ],
 )
-def test_message_invalid(val: str):
-    with raises(KresManagerException):
-        PolicySchema({"action": f"{val}", "message": "this is deny message"})
+def test_policy_valid(val: Dict[str, Any]):
+    PolicySchema(val)
 
 
 @pytest.mark.parametrize(
@@ -39,9 +63,18 @@ def test_message_invalid(val: str):
         {"action": "mirror"},
         {"action": "pass", "reroute": [{"source": "192.0.2.0/24", "destination": "127.0.0.0"}]},
         {"action": "pass", "answer": {"rtype": "AAAA", "rdata": "::1"}},
-        {"action": "pass", "mirror": ["127.0.0.1@5353"]},
+        {"action": "pass", "servers": ["127.0.0.1@5353"]},
     ],
 )
-def test_invalid(val: Dict[str, Any]):
+def test_policy_invalid(val: Dict[str, Any]):
     with raises(KresManagerException):
         PolicySchema(val)
+
+
+@pytest.mark.parametrize(
+    "val",
+    noconfig_actions,
+)
+def test_policy_message_invalid(val: str):
+    with raises(KresManagerException):
+        PolicySchema({"action": f"{val}", "message": "this is deny message"})