]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
manager: datamodel: local-data schema added
authorAleš Mrázek <ales.mrazek@nic.cz>
Mon, 20 Feb 2023 18:55:47 +0000 (19:55 +0100)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 9 Jun 2023 11:54:07 +0000 (11:54 +0000)
manager/knot_resolver_manager/datamodel/config_schema.py
manager/knot_resolver_manager/datamodel/local_data_schema.py [new file with mode: 0644]
manager/knot_resolver_manager/datamodel/templates/config.lua.j2
manager/knot_resolver_manager/datamodel/templates/local_data.lua.j2 [new file with mode: 0644]
manager/tests/unit/datamodel/test_local_data.py [new file with mode: 0644]

index 1fc612e88a1b434e537088b7a9c98765029d36c7..fed9b2c48291abbdd775f47fa0e958f261712686 100644 (file)
@@ -12,6 +12,7 @@ from knot_resolver_manager.datamodel.cache_schema import CacheSchema
 from knot_resolver_manager.datamodel.dns64_schema import Dns64Schema
 from knot_resolver_manager.datamodel.dnssec_schema import DnssecSchema
 from knot_resolver_manager.datamodel.forward_schema import ForwardSchema
+from knot_resolver_manager.datamodel.local_data_schema import LocalDataSchema
 from knot_resolver_manager.datamodel.logging_schema import LoggingSchema
 from knot_resolver_manager.datamodel.lua_schema import LuaSchema
 from knot_resolver_manager.datamodel.management_schema import ManagementSchema
@@ -21,7 +22,6 @@ from knot_resolver_manager.datamodel.options_schema import OptionsSchema
 from knot_resolver_manager.datamodel.policy_schema import PolicySchema
 from knot_resolver_manager.datamodel.rpz_schema import RPZSchema
 from knot_resolver_manager.datamodel.slice_schema import SliceSchema
-from knot_resolver_manager.datamodel.static_hints_schema import StaticHintsSchema
 from knot_resolver_manager.datamodel.stub_zone_schema import StubZoneSchema
 from knot_resolver_manager.datamodel.types import IntPositive
 from knot_resolver_manager.datamodel.types.files import UncheckedPath
@@ -96,8 +96,8 @@ class KresConfig(ConfigSchema):
         webmgmt: Configuration of legacy web management endpoint.
         options: Fine-tuning global parameters of DNS resolver operation.
         network: Network connections and protocols configuration.
-        static_hints: Static hints for forward records (A/AAAA) and reverse records (PTR)
         views: List of views and its configuration.
+        local_data: Local data for forward records (A/AAAA) and reverse records (PTR).
         slices: Split the entire DNS namespace into distinct slices.
         policy: List of policy rules and its configuration.
         rpz: List of Response Policy Zones and its configuration.
@@ -121,8 +121,8 @@ class KresConfig(ConfigSchema):
         webmgmt: Optional[WebmgmtSchema] = None
         options: OptionsSchema = OptionsSchema()
         network: NetworkSchema = NetworkSchema()
-        static_hints: StaticHintsSchema = StaticHintsSchema()
         views: Optional[List[ViewSchema]] = None
+        local_data: LocalDataSchema = LocalDataSchema()
         slices: Optional[List[SliceSchema]] = None
         policy: Optional[List[PolicySchema]] = None
         rpz: Optional[List[RPZSchema]] = None
@@ -146,8 +146,8 @@ class KresConfig(ConfigSchema):
     webmgmt: Optional[WebmgmtSchema]
     options: OptionsSchema
     network: NetworkSchema
-    static_hints: StaticHintsSchema
     views: Optional[List[ViewSchema]]
+    local_data: LocalDataSchema
     slices: Optional[List[SliceSchema]]
     policy: Optional[List[PolicySchema]]
     rpz: Optional[List[RPZSchema]]
diff --git a/manager/knot_resolver_manager/datamodel/local_data_schema.py b/manager/knot_resolver_manager/datamodel/local_data_schema.py
new file mode 100644 (file)
index 0000000..e10f6c3
--- /dev/null
@@ -0,0 +1,59 @@
+from typing import Dict, List, Optional, Union
+
+from typing_extensions import Literal
+
+from knot_resolver_manager.datamodel.types import DomainName, IDPattern, IPAddress, TimeUnit, UncheckedPath
+from knot_resolver_manager.utils.modeling import BaseSchema
+
+
+class SubtreeSchema(BaseSchema):
+    """
+    Local data and configuration of subtree.
+
+    ---
+    type: Type of the subtree.
+    tags: Tags to link with other policy rules.
+    addresses: Subtree addresses.
+    roots: Subtree roots.
+    roots_file: Subtree roots from given file.
+    roots_url: Subtree roots form given URL.
+    refresh: Refresh time to update data from 'roots-file' or 'roots-url'.
+    """
+
+    type: Literal["empty", "nxdomain", "redirect"]
+    tags: Optional[List[IDPattern]] = None
+    addresses: Optional[Union[List[IPAddress], IPAddress]] = None
+    roots: Optional[Union[List[DomainName], DomainName]] = None
+    roots_file: Optional[UncheckedPath] = None
+    roots_url: Optional[str] = None
+    refresh: Optional[TimeUnit] = None
+
+    def _validate(self) -> None:
+        options_sum = sum([bool(self.roots), bool(self.roots_file), bool(self.roots_url)])
+        if options_sum > 1:
+            raise ValueError("only one of, 'roots', 'roots-file' or 'roots-url' can be configured")
+        elif options_sum < 1:
+            raise ValueError("one of, 'roots', 'roots-file' or 'roots-url' must be configured")
+        if self.refresh and not (self.roots_file or self.roots_url):
+            raise ValueError("'refresh' can be only configured with 'roots-file' or 'roots-url'")
+
+
+class LocalDataSchema(BaseSchema):
+    """
+    Local data for forward records (A/AAAA) and reverse records (PTR).
+
+    ---
+    ttl: Default TTL value used for added local data/records.
+    nodata: Use NODATA synthesis. NODATA will be synthesised for matching name, but mismatching type(e.g. AAAA query when only A exists).
+    addresses: Direct addition of hostname and IP addresses pairs.
+    addresses_files: Direct addition of hostname and IP addresses pairs from files in '/etc/hosts' like format.
+    records: Direct addition of records in DNS zone file format.
+    subtrees: Direct addition of subtrees.
+    """
+
+    ttl: Optional[TimeUnit] = None
+    nodata: bool = True
+    addresses: Optional[Dict[DomainName, Union[List[IPAddress], IPAddress]]] = None
+    addresses_files: Optional[Union[List[UncheckedPath], UncheckedPath]] = None
+    records: Optional[str] = None
+    subtrees: Optional[List[SubtreeSchema]] = None
index 52bef389369f44f6f5fa1725f41d956e118266f7..9dc7ef21445329dc324ce9d200e52d71b39e982e 100644 (file)
@@ -21,12 +21,12 @@ nsid.name('{{ cfg.nsid }}_' .. worker.id)
 -- NETWORK section ----------------------------------
 {% include "network.lua.j2" %}
 
--- STATIC-HINTS section -----------------------------
-{% include "static_hints.lua.j2" %}
-
 -- VIEWS section ------------------------------------
 {% include "views.lua.j2" %}
 
+-- LOCAL-DATA section -----------------------------
+{% include "local_data.lua.j2" %}
+
 -- SLICES section -----------------------------------
 {% include "slices.lua.j2" %}
 
diff --git a/manager/knot_resolver_manager/datamodel/templates/local_data.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/local_data.lua.j2
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/manager/tests/unit/datamodel/test_local_data.py b/manager/tests/unit/datamodel/test_local_data.py
new file mode 100644 (file)
index 0000000..198bccd
--- /dev/null
@@ -0,0 +1,33 @@
+from typing import Any
+
+import pytest
+from pytest import raises
+
+from knot_resolver_manager.datamodel.local_data_schema import LocalDataSchema, SubtreeSchema
+from knot_resolver_manager.utils.modeling.exceptions import DataValidationError
+
+
+@pytest.mark.parametrize(
+    "val",
+    [
+        {"type": "empty", "roots": ["sub2.example.org"]},
+        {"type": "empty", "roots-url": "https://example.org/blocklist.txt", "refresh": "1d"},
+        {"type": "nxdomain", "roots-file": "/path/to/file.txt"},
+        {"type": "redirect", "roots": ["sub4.example.org"], "addresses": ["127.0.0.1", "::1"]},
+    ],
+)
+def test_subtree_valid(val: Any):
+    SubtreeSchema(val)
+
+
+@pytest.mark.parametrize(
+    "val",
+    [
+        {"type": "empty"},
+        {"type": "empty", "roots": ["sub2.example.org"], "roots-url": "https://example.org/blocklist.txt"},
+        {"type": "redirect", "roots": ["sub4.example.org"], "refresh": "1d"},
+    ],
+)
+def test_subtree_invalid(val: Any):
+    with raises(DataValidationError):
+        SubtreeSchema(val)