From: Aleš Mrázek Date: Fri, 28 Jul 2023 13:57:19 +0000 (+0200) Subject: manager: datamodel: prediction moved to cache X-Git-Tag: v6.0.2~24^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2410bcb6095f073a2f1790447cdcb9678d301860;p=thirdparty%2Fknot-resolver.git manager: datamodel: prediction moved to cache --- diff --git a/manager/knot_resolver_manager/datamodel/cache_schema.py b/manager/knot_resolver_manager/datamodel/cache_schema.py index ad0211f8f..7eeda1f46 100644 --- a/manager/knot_resolver_manager/datamodel/cache_schema.py +++ b/manager/knot_resolver_manager/datamodel/cache_schema.py @@ -1,4 +1,4 @@ -from typing import List, Optional, Union +from typing import Any, List, Optional, Union from typing_extensions import Literal @@ -64,27 +64,59 @@ class GarbageCollectorSchema(ConfigSchema): dry_run: bool = False -class CacheSchema(ConfigSchema): +class PredictionSchema(ConfigSchema): """ - DNS resolver cache configuration. + Helps keep the cache hot by prefetching expiring records and learning usage patterns and repetitive queries. --- - storage: Cache storage of the DNS resolver. - size_max: Maximum size of the cache. - garbage_collector: Use the garbage collector (kres-cache-gc) to periodically clear cache. - ttl_min: Minimum time-to-live for the cache entries. - ttl_max: Maximum time-to-live for the cache entries. - ns_timeout: Time interval for which a nameserver address will be ignored after determining that it does not return (useful) answers. - prefill: Prefill the cache periodically by importing zone data obtained over HTTP. + window: Sampling window length. + period: Number of windows that can be kept in memory. """ - storage: Dir = lazy_default(Dir, "/var/cache/knot-resolver") - size_max: SizeUnit = SizeUnit("100M") - garbage_collector: Union[GarbageCollectorSchema, Literal[False]] = GarbageCollectorSchema() - ttl_min: TimeUnit = TimeUnit("5s") - ttl_max: TimeUnit = TimeUnit("6d") - ns_timeout: TimeUnit = TimeUnit("1000ms") - prefill: Optional[List[PrefillSchema]] = None + window: TimeUnit = TimeUnit("15m") + period: IntNonNegative = IntNonNegative(24) + + +class CacheSchema(ConfigSchema): + class Raw(ConfigSchema): + """ + DNS resolver cache configuration. + + --- + storage: Cache storage of the DNS resolver. + size_max: Maximum size of the cache. + garbage_collector: Use the garbage collector (kres-cache-gc) to periodically clear cache. + ttl_min: Minimum time-to-live for the cache entries. + ttl_max: Maximum time-to-live for the cache entries. + ns_timeout: Time interval for which a nameserver address will be ignored after determining that it does not return (useful) answers. + prefill: Prefill the cache periodically by importing zone data obtained over HTTP. + prediction: Helps keep the cache hot by prefetching expiring records and learning usage patterns and repetitive queries. + """ + + storage: Dir = lazy_default(Dir, "/var/cache/knot-resolver") + size_max: SizeUnit = SizeUnit("100M") + garbage_collector: Union[GarbageCollectorSchema, Literal[False]] = GarbageCollectorSchema() + ttl_min: TimeUnit = TimeUnit("5s") + ttl_max: TimeUnit = TimeUnit("6d") + ns_timeout: TimeUnit = TimeUnit("1000ms") + prefill: Optional[List[PrefillSchema]] = None + prediction: Union[bool, PredictionSchema] = False + + _LAYER = Raw + + storage: Dir + size_max: SizeUnit + garbage_collector: Union[GarbageCollectorSchema, Literal[False]] + ttl_min: TimeUnit + ttl_max: TimeUnit + ns_timeout: TimeUnit + prefill: Optional[List[PrefillSchema]] + prediction: Union[Literal[False], PredictionSchema] + + def _prediction(self, obj: Raw) -> Any: + if obj.prediction is True: + return PredictionSchema() + return obj.prediction def _validate(self): if self.ttl_min.seconds() >= self.ttl_max.seconds(): diff --git a/manager/knot_resolver_manager/datamodel/options_schema.py b/manager/knot_resolver_manager/datamodel/options_schema.py index e95e5f88b..d0bb0399a 100644 --- a/manager/knot_resolver_manager/datamodel/options_schema.py +++ b/manager/knot_resolver_manager/datamodel/options_schema.py @@ -1,75 +1,36 @@ -from typing import Any, Union - from typing_extensions import Literal -from knot_resolver_manager.datamodel.types import IntNonNegative, TimeUnit from knot_resolver_manager.utils.modeling import ConfigSchema GlueCheckingEnum = Literal["normal", "strict", "permissive"] -class PredictionSchema(ConfigSchema): +class OptionsSchema(ConfigSchema): """ - Helps keep the cache hot by prefetching expiring records and learning usage patterns and repetitive queries. + Fine-tuning global parameters of DNS resolver operation. --- - window: Sampling window length. - period: Number of windows that can be kept in memory. + glue_checking: Glue records scrictness checking level. + minimize: Send minimum amount of information in recursive queries to enhance privacy. + query_loopback: Permits queries to loopback addresses. + reorder_rrset: Controls whether resource records within a RRSet are reordered each time it is served from the cache. + query_case_randomization: Randomize Query Character Case. + priming: Initializing DNS resolver cache with Priming Queries (RFC 8109) + rebinding_protection: Protection against DNS Rebinding attack. + refuse_no_rd: Queries without RD (recursion desired) bit set in query are answered with REFUSED. + time_jump_detection: Detection of difference between local system time and expiration time bounds in DNSSEC signatures for '. NS' records. + violators_workarounds: Workarounds for known DNS protocol violators. + serve_stale: Allows using timed-out records in case DNS resolver is unable to contact upstream servers. """ - window: TimeUnit = TimeUnit("15m") - period: IntNonNegative = IntNonNegative(24) - - -class OptionsSchema(ConfigSchema): - class Raw(ConfigSchema): - """ - Fine-tuning global parameters of DNS resolver operation. - - --- - glue_checking: Glue records scrictness checking level. - minimize: Send minimum amount of information in recursive queries to enhance privacy. - query_loopback: Permits queries to loopback addresses. - reorder_rrset: Controls whether resource records within a RRSet are reordered each time it is served from the cache. - query_case_randomization: Randomize Query Character Case. - priming: Initializing DNS resolver cache with Priming Queries (RFC 8109) - rebinding_protection: Protection against DNS Rebinding attack. - refuse_no_rd: Queries without RD (recursion desired) bit set in query are answered with REFUSED. - time_jump_detection: Detection of difference between local system time and expiration time bounds in DNSSEC signatures for '. NS' records. - violators_workarounds: Workarounds for known DNS protocol violators. - serve_stale: Allows using timed-out records in case DNS resolver is unable to contact upstream servers. - prediction: Helps keep the cache hot by prefetching expiring records and learning usage patterns and repetitive queries. - """ - - glue_checking: GlueCheckingEnum = "normal" - minimize: bool = True - query_loopback: bool = False - reorder_rrset: bool = True - query_case_randomization: bool = True - priming: bool = True - rebinding_protection: bool = False - refuse_no_rd: bool = True - time_jump_detection: bool = True - violators_workarounds: bool = False - serve_stale: bool = False - prediction: Union[bool, PredictionSchema] = False - - _LAYER = Raw - - glue_checking: GlueCheckingEnum - minimize: bool - query_loopback: bool - reorder_rrset: bool - query_case_randomization: bool - priming: bool - rebinding_protection: bool - refuse_no_rd: bool - time_jump_detection: bool - violators_workarounds: bool - serve_stale: bool - prediction: Union[Literal[False], PredictionSchema] - - def _prediction(self, obj: Raw) -> Any: - if obj.prediction is True: - return PredictionSchema() - return obj.prediction + glue_checking: GlueCheckingEnum = "normal" + minimize: bool = True + query_loopback: bool = False + reorder_rrset: bool = True + query_case_randomization: bool = True + priming: bool = True + rebinding_protection: bool = False + refuse_no_rd: bool = True + time_jump_detection: bool = True + violators_workarounds: bool = False + serve_stale: bool = False diff --git a/manager/knot_resolver_manager/datamodel/templates/cache.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/cache.lua.j2 index 357157718..0d942841c 100644 --- a/manager/knot_resolver_manager/datamodel/templates/cache.lua.j2 +++ b/manager/knot_resolver_manager/datamodel/templates/cache.lua.j2 @@ -15,4 +15,13 @@ prefill.config({ } {% endfor %} }) -{% endif %} \ No newline at end of file +{% endif %} + +{% if cfg.cache.prediction %} +-- cache.prediction +modules.load('predict') +predict.config({ + window = {{ cfg.cache.prediction.window.minutes() }} + period = {{ cfg.cache.prediction.period }} +}) +{% endif %} diff --git a/manager/knot_resolver_manager/datamodel/types/types.py b/manager/knot_resolver_manager/datamodel/types/types.py index c8b533215..f558da0de 100644 --- a/manager/knot_resolver_manager/datamodel/types/types.py +++ b/manager/knot_resolver_manager/datamodel/types/types.py @@ -60,6 +60,9 @@ class SizeUnit(UnitBase): class TimeUnit(UnitBase): _units = {"us": 1, "ms": 10**3, "s": 10**6, "m": 60 * 10**6, "h": 3600 * 10**6, "d": 24 * 3600 * 10**6} + def minutes(self) -> int: + return self._base_value // 1000**2 // 60 + def seconds(self) -> int: return self._base_value // 1000**2 diff --git a/manager/tests/unit/datamodel/test_options_schema.py b/manager/tests/unit/datamodel/test_cache_schema.py similarity index 51% rename from manager/tests/unit/datamodel/test_options_schema.py rename to manager/tests/unit/datamodel/test_cache_schema.py index f6bd5c3e0..f5c3030ac 100644 --- a/manager/tests/unit/datamodel/test_options_schema.py +++ b/manager/tests/unit/datamodel/test_cache_schema.py @@ -1,7 +1,7 @@ -from knot_resolver_manager.datamodel.options_schema import OptionsSchema +from knot_resolver_manager.datamodel.cache_schema import CacheSchema def test_prediction_true_defaults(): - o = OptionsSchema({"prediction": True}) + o = CacheSchema({"prediction": True}) assert str(o.prediction.window) == "15m" assert int(o.prediction.period) == 24