From: Štěpán Balážik Date: Thu, 30 Oct 2025 12:41:23 +0000 (+0100) Subject: Refactor ControllableAsyncDnsServer setup X-Git-Tag: v9.21.17~25^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a0970f3d0410afd35799306c24f8ed43955ad027;p=thirdparty%2Fbind9.git Refactor ControllableAsyncDnsServer setup When this class was introduced, the constructor of its base class had no parameters. This was changed in the meantime and these parameters were not accessible by users of the subclass. Don't override the constructor. Move command setup to methods. Move subclass-specific storage to cached properties. Take instances of Command instead of the classes themselves for symmetry with install_response_handler. --- diff --git a/bin/tests/system/chain/ans4/ans.py b/bin/tests/system/chain/ans4/ans.py index 3e042ea58ce..249da49b9aa 100755 --- a/bin/tests/system/chain/ans4/ans.py +++ b/bin/tests/system/chain/ans4/ans.py @@ -473,7 +473,8 @@ class ChainResponseHandler(DomainHandler): def main() -> None: - server = ControllableAsyncDnsServer(commands=[ChainSetupCommand]) + server = ControllableAsyncDnsServer() + server.install_control_command(ChainSetupCommand()) server.run() diff --git a/bin/tests/system/fetchlimit/ans4/ans.py b/bin/tests/system/fetchlimit/ans4/ans.py index 34891fa310c..52be94125ca 100644 --- a/bin/tests/system/fetchlimit/ans4/ans.py +++ b/bin/tests/system/fetchlimit/ans4/ans.py @@ -39,7 +39,8 @@ class MaybeDelayedAddressAnswerHandler(ResponseHandler): def main() -> None: - server = ControllableAsyncDnsServer([ToggleResponsesCommand]) + server = ControllableAsyncDnsServer() + server.install_control_command(ToggleResponsesCommand()) server.install_response_handler(MaybeDelayedAddressAnswerHandler()) server.run() diff --git a/bin/tests/system/forward/ans11/ans.py b/bin/tests/system/forward/ans11/ans.py index 8d0b3e9b33e..0b4ec5682e1 100644 --- a/bin/tests/system/forward/ans11/ans.py +++ b/bin/tests/system/forward/ans11/ans.py @@ -49,7 +49,8 @@ class ExtraAnswersHandler(DomainHandler): def main() -> None: - server = ControllableAsyncDnsServer(commands=[ToggleResponsesCommand]) + server = ControllableAsyncDnsServer() + server.install_control_command(ToggleResponsesCommand()) server.install_response_handler(ExtraAnswersHandler()) server.run() diff --git a/bin/tests/system/forward/ans6/ans.py b/bin/tests/system/forward/ans6/ans.py index f63cdcd4d54..a9fd0b8ac65 100644 --- a/bin/tests/system/forward/ans6/ans.py +++ b/bin/tests/system/forward/ans6/ans.py @@ -72,7 +72,8 @@ class ChaseDsHandler(ResponseHandler): def main() -> None: - server = ControllableAsyncDnsServer([ToggleResponsesCommand]) + server = ControllableAsyncDnsServer() + server.install_control_command(ToggleResponsesCommand()) server.install_response_handler(ChaseDsHandler()) server.run() diff --git a/bin/tests/system/isctest/asyncserver.py b/bin/tests/system/isctest/asyncserver.py index c91f63a1230..27a981446b9 100644 --- a/bin/tests/system/isctest/asyncserver.py +++ b/bin/tests/system/isctest/asyncserver.py @@ -21,7 +21,6 @@ from typing import ( List, Optional, Tuple, - Type, Union, cast, ) @@ -1281,22 +1280,29 @@ class ControllableAsyncDnsServer(AsyncDnsServer): _CONTROL_DOMAIN = "_control." - def __init__(self, commands: List[Type["ControlCommand"]]): - super().__init__() - self._control_domain = dns.name.from_text(self._CONTROL_DOMAIN) - self._commands: Dict[dns.name.Name, "ControlCommand"] = {} - for command_class in commands: - command = command_class() - command_subdomain = dns.name.Name([command.control_subdomain]) - control_subdomain = command_subdomain.concatenate(self._control_domain) - try: - existing_command = self._commands[control_subdomain] - except KeyError: - self._commands[control_subdomain] = command - else: - raise RuntimeError( - f"{control_subdomain} already handled by {existing_command}" - ) + @functools.cached_property + def _control_domain(self) -> dns.name.Name: + return dns.name.from_text(self._CONTROL_DOMAIN) + + @functools.cached_property + def _commands(self) -> Dict[dns.name.Name, "ControlCommand"]: + return {} + + def install_control_commands(self, commands: List["ControlCommand"]) -> None: + for command in commands: + self.install_control_command(command) + + def install_control_command(self, command: "ControlCommand") -> None: + command_subdomain = dns.name.Name([command.control_subdomain]) + control_subdomain = command_subdomain.concatenate(self._control_domain) + try: + existing_command = self._commands[control_subdomain] + except KeyError: + self._commands[control_subdomain] = command + else: + raise RuntimeError( + f"{control_subdomain} already handled by {existing_command}" + ) async def _prepare_responses( self, qctx: QueryContext diff --git a/bin/tests/system/xfer/ans9/ans.py b/bin/tests/system/xfer/ans9/ans.py index 56c80becb9b..f1a4bf54372 100644 --- a/bin/tests/system/xfer/ans9/ans.py +++ b/bin/tests/system/xfer/ans9/ans.py @@ -106,6 +106,7 @@ class AXFRServer(DomainHandler): if __name__ == "__main__": - server = ControllableAsyncDnsServer([ToggleResponsesCommand]) + server = ControllableAsyncDnsServer() + server.install_control_command(ToggleResponsesCommand()) server.install_response_handler(AXFRServer()) server.run()