From 1bc78d73410a367cdc5b511ef746dd1be148b1b6 Mon Sep 17 00:00:00 2001 From: Indrajit Raychaudhuri Date: Tue, 12 Sep 2023 23:31:43 -0500 Subject: ddclient: T5612: Fix VRF support for ddclient service Fix VRF support interface definition and configuration mode for ddclient to actually capture the VRF name and pass it to the template. --- src/conf_mode/dns_dynamic.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/conf_mode/dns_dynamic.py b/src/conf_mode/dns_dynamic.py index 4b1aed742..712889f68 100755 --- a/src/conf_mode/dns_dynamic.py +++ b/src/conf_mode/dns_dynamic.py @@ -19,6 +19,7 @@ import os from sys import exit from vyos.config import Config +from vyos.configverify import verify_interface_exists from vyos.template import render from vyos.utils.process import call from vyos import ConfigError @@ -61,6 +62,10 @@ def verify(dyndns): return None for address in dyndns['address']: + # If dyndns address is an interface, ensure it exists + if address != 'web': + verify_interface_exists(address) + # RFC2136 - configuration validation if 'rfc2136' in dyndns['address'][address]: for config in dyndns['address'][address]['rfc2136'].values(): -- cgit v1.2.3 From 98694f5717f282e10caeded3e4e07891fd5bea18 Mon Sep 17 00:00:00 2001 From: Indrajit Raychaudhuri Date: Sat, 16 Sep 2023 13:33:02 -0500 Subject: ddclient: T5612: Improve dual stack support for dyndns2 protocol dyndns2 protocol in ddclient honors dual stack for selective servers because of the way it is implemented in ddclient. We formalize the well known servers that support dual stack in a list and check against it when validating the configuration. --- src/conf_mode/dns_dynamic.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/conf_mode/dns_dynamic.py b/src/conf_mode/dns_dynamic.py index 712889f68..84c983ee3 100755 --- a/src/conf_mode/dns_dynamic.py +++ b/src/conf_mode/dns_dynamic.py @@ -30,7 +30,7 @@ config_file = r'/run/ddclient/ddclient.conf' systemd_override = r'/run/systemd/system/ddclient.service.d/override.conf' # Protocols that require zone -zone_allowed = ['cloudflare', 'godaddy', 'hetzner', 'gandi', 'nfsn'] +zone_required = ['cloudflare', 'godaddy', 'hetzner', 'gandi', 'nfsn'] # Protocols that do not require username username_unnecessary = ['1984', 'cloudflare', 'cloudns', 'duckdns', 'freemyip', 'hetzner', 'keysystems', 'njalla'] @@ -38,6 +38,10 @@ username_unnecessary = ['1984', 'cloudflare', 'cloudns', 'duckdns', 'freemyip', # Protocols that support both IPv4 and IPv6 dualstack_supported = ['cloudflare', 'dyndns2', 'freedns', 'njalla'] +# dyndns2 protocol in ddclient honors dual stack for selective servers +# because of the way it is implemented in ddclient +dyndns_dualstack_servers = ['members.dyndns.org', 'dynv6.com'] + def get_config(config=None): if config: conf = config @@ -83,10 +87,10 @@ def verify(dyndns): if field not in config: raise ConfigError(f'"{field.replace("_", "-")}" {error_msg}') - if config['protocol'] in zone_allowed and 'zone' not in config: + if config['protocol'] in zone_required and 'zone' not in config: raise ConfigError(f'"zone" {error_msg}') - if config['protocol'] not in zone_allowed and 'zone' in config: + if config['protocol'] not in zone_required and 'zone' in config: raise ConfigError(f'"{config["protocol"]}" does not support "zone"') if config['protocol'] not in username_unnecessary: @@ -98,7 +102,7 @@ def verify(dyndns): raise ConfigError(f'"{config["protocol"]}" does not support ' f'both IPv4 and IPv6 at the same time') # dyndns2 protocol in ddclient honors dual stack only for dyn.com (dyndns.org) - if config['protocol'] == 'dyndns2' and 'server' in config and config['server'] != 'members.dyndns.org': + if config['protocol'] == 'dyndns2' and 'server' in config and config['server'] not in dyndns_dualstack_servers: raise ConfigError(f'"{config["protocol"]}" does not support ' f'both IPv4 and IPv6 at the same time for "{config["server"]}"') -- cgit v1.2.3 From 8088cb8b6aacf9b7003845e4c9081b7f569b6fac Mon Sep 17 00:00:00 2001 From: Indrajit Raychaudhuri Date: Thu, 21 Sep 2023 21:35:18 -0500 Subject: ddclient: T5612: Enable TTL support for web-service based protocols Enable TTL support for web-service based protocols in addition to RFC2136 based (nsupdate) protocol. Since TTL is not supported by all protocols, and thus cannot have a configuration default, the existing XML snippet `include/dns/time-to-live.xml.i` does not have common `300` anymore and is instead added explicitly whenever necessary. --- data/templates/dns-dynamic/ddclient.conf.j2 | 2 +- interface-definitions/dns-dynamic.xml.in | 1 + interface-definitions/dns-forwarding.xml.in | 30 ++++++++++++++++++++++ .../include/dns/time-to-live.xml.i | 1 - smoketest/scripts/cli/test_service_dns_dynamic.py | 19 +++++++++++--- src/conf_mode/dns_dynamic.py | 6 +++++ 6 files changed, 53 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/data/templates/dns-dynamic/ddclient.conf.j2 b/data/templates/dns-dynamic/ddclient.conf.j2 index f2a20d4b8..5905b19ea 100644 --- a/data/templates/dns-dynamic/ddclient.conf.j2 +++ b/data/templates/dns-dynamic/ddclient.conf.j2 @@ -66,7 +66,7 @@ use=no # Web service dynamic DNS configuration for {{ name }}: [{{ config.protocol }}, {{ host }}] {{ render_config(host, address, service_cfg.web_options, ip_suffixes, protocol=config.protocol, server=config.server, zone=config.zone, - login=config.username, password=config.password) }} + login=config.username, password=config.password, ttl=config.ttl) }} {% endfor %} {% endfor %} diff --git a/interface-definitions/dns-dynamic.xml.in b/interface-definitions/dns-dynamic.xml.in index 8d08bf37d..ba7f426c1 100644 --- a/interface-definitions/dns-dynamic.xml.in +++ b/interface-definitions/dns-dynamic.xml.in @@ -90,6 +90,7 @@ #include #include #include + #include ddclient protocol used for Dynamic DNS service diff --git a/interface-definitions/dns-forwarding.xml.in b/interface-definitions/dns-forwarding.xml.in index 86dc47a47..c4295317a 100644 --- a/interface-definitions/dns-forwarding.xml.in +++ b/interface-definitions/dns-forwarding.xml.in @@ -158,6 +158,9 @@ #include + + 300 + #include @@ -195,6 +198,9 @@ #include + + 300 + #include @@ -227,6 +233,9 @@ #include + + 300 + #include @@ -274,6 +283,9 @@ #include + + 300 + #include @@ -302,6 +314,9 @@ #include + + 300 + #include @@ -334,6 +349,9 @@ #include + + 300 + #include @@ -364,6 +382,9 @@ #include + + 300 + #include @@ -393,6 +414,9 @@ #include + + 300 + #include @@ -477,6 +501,9 @@ #include + + 300 + #include @@ -585,6 +612,9 @@ #include + + 300 + #include diff --git a/interface-definitions/include/dns/time-to-live.xml.i b/interface-definitions/include/dns/time-to-live.xml.i index 5c1a1472d..000eea108 100644 --- a/interface-definitions/include/dns/time-to-live.xml.i +++ b/interface-definitions/include/dns/time-to-live.xml.i @@ -10,6 +10,5 @@ - 300 diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py index 366b063c7..aa4891829 100755 --- a/smoketest/scripts/cli/test_service_dns_dynamic.py +++ b/smoketest/scripts/cli/test_service_dns_dynamic.py @@ -63,18 +63,29 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ddns + [svc, 'host-name', hostname]) self.cli_set(base_path + ddns + [svc, 'password', password]) self.cli_set(base_path + ddns + [svc, 'zone', zone]) + self.cli_set(base_path + ddns + [svc, 'ttl', ttl]) for opt, value in details.items(): self.cli_set(base_path + ddns + [svc, opt, value]) - # commit changes + # 'zone' option is supported and required by 'cloudfare', but not 'freedns' and 'zoneedit' + self.cli_set(base_path + ddns + [svc, 'zone', zone]) + if details['protocol'] == 'cloudflare': + pass + else: + # exception is raised for unsupported ones + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(base_path + ddns + [svc, 'zone']) + + # 'ttl' option is supported by 'cloudfare', but not 'freedns' and 'zoneedit' + self.cli_set(base_path + ddns + [svc, 'ttl', ttl]) if details['protocol'] == 'cloudflare': pass else: - # zone option does not work on all protocols, an exception is - # raised for all others + # exception is raised for unsupported ones with self.assertRaises(ConfigSessionError): self.cli_commit() - self.cli_delete(base_path + ddns + [svc, 'zone', zone]) + self.cli_delete(base_path + ddns + [svc, 'ttl']) # commit changes self.cli_commit() diff --git a/src/conf_mode/dns_dynamic.py b/src/conf_mode/dns_dynamic.py index 84c983ee3..5150574a8 100755 --- a/src/conf_mode/dns_dynamic.py +++ b/src/conf_mode/dns_dynamic.py @@ -35,6 +35,9 @@ zone_required = ['cloudflare', 'godaddy', 'hetzner', 'gandi', 'nfsn'] # Protocols that do not require username username_unnecessary = ['1984', 'cloudflare', 'cloudns', 'duckdns', 'freemyip', 'hetzner', 'keysystems', 'njalla'] +# Protocols that support TTL +ttl_supported = ['cloudflare', 'gandi', 'hetzner', 'dnsexit', 'godaddy', 'nfsn'] + # Protocols that support both IPv4 and IPv6 dualstack_supported = ['cloudflare', 'dyndns2', 'freedns', 'njalla'] @@ -97,6 +100,9 @@ def verify(dyndns): if 'username' not in config: raise ConfigError(f'"username" {error_msg}') + if config['protocol'] not in ttl_supported and 'ttl' in config: + raise ConfigError(f'"{config["protocol"]}" does not support "ttl"') + if config['ip_version'] == 'both': if config['protocol'] not in dualstack_supported: raise ConfigError(f'"{config["protocol"]}" does not support ' -- cgit v1.2.3 From d9f8ff7e277105e34afaa9164517b03ff7675d76 Mon Sep 17 00:00:00 2001 From: Indrajit Raychaudhuri Date: Fri, 22 Sep 2023 12:29:22 -0500 Subject: ddclient: T5612: Adjust validator and completion for ddclient Adjust the validator and completion for ddclient to remove unsupported or superfluous protocols. Specifically, - remove 'nsupdate' protocol from the list because there is a separate config path for that protocol (rfc2136) - remove 'cloudns' protocol from the list because it has non standard configuration and is not supported by our configurator at this time --- src/completion/list_ddclient_protocols.sh | 2 +- src/validators/ddclient-protocol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/completion/list_ddclient_protocols.sh b/src/completion/list_ddclient_protocols.sh index 75fb0cf44..3b4eff4d6 100755 --- a/src/completion/list_ddclient_protocols.sh +++ b/src/completion/list_ddclient_protocols.sh @@ -14,4 +14,4 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -echo -n $(ddclient -list-protocols) +echo -n $(ddclient -list-protocols | grep -vE 'nsupdate|cloudns') diff --git a/src/validators/ddclient-protocol b/src/validators/ddclient-protocol index 6f927927b..bc6826120 100755 --- a/src/validators/ddclient-protocol +++ b/src/validators/ddclient-protocol @@ -14,7 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -ddclient -list-protocols | grep -qw $1 +ddclient -list-protocols | grep -vE 'nsupdate|cloudns' | grep -qw $1 if [ $? -gt 0 ]; then echo "Error: $1 is not a valid protocol, please choose from the supported list of protocols" -- cgit v1.2.3 From 6c2a2aa4e93d40c9575a83791daf2d141f387976 Mon Sep 17 00:00:00 2001 From: Indrajit Raychaudhuri Date: Thu, 21 Sep 2023 21:11:40 -0500 Subject: ddclient: T5612: Additional refactoring for scripts and smoketests Additional cleanup and refactoring for ddclient scripts including the smotektests. --- smoketest/scripts/cli/test_service_dns_dynamic.py | 115 +++++++++++----------- src/conf_mode/dns_dynamic.py | 21 ++-- 2 files changed, 69 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py index f1870320e..66dcde434 100755 --- a/smoketest/scripts/cli/test_service_dns_dynamic.py +++ b/smoketest/scripts/cli/test_service_dns_dynamic.py @@ -32,12 +32,19 @@ DDCLIENT_PID = '/run/ddclient/ddclient.pid' DDCLIENT_PNAME = 'ddclient' base_path = ['service', 'dns', 'dynamic'] +server = 'ddns.vyos.io' hostname = 'test.ddns.vyos.io' zone = 'vyos.io' +username = 'vyos_user' password = 'paSS_@4ord' +ttl = '300' interface = 'eth0' class TestServiceDDNS(VyOSUnitTestSHIM.TestCase): + def setUp(self): + # Always start with a clean CLI instance + self.cli_delete(base_path) + def tearDown(self): # Check for running process self.assertTrue(process_running(DDCLIENT_PID)) @@ -51,41 +58,38 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase): # IPv4 standard DDNS service configuration def test_01_dyndns_service_standard(self): - ddns = ['address', interface, 'service'] + svc_path = ['address', interface, 'service'] services = {'cloudflare': {'protocol': 'cloudflare'}, - 'freedns': {'protocol': 'freedns', 'username': 'vyos_user'}, - 'zoneedit': {'protocol': 'zoneedit1', 'username': 'vyos_user'}} + 'freedns': {'protocol': 'freedns', 'username': username}, + 'zoneedit': {'protocol': 'zoneedit1', 'username': username}} for svc, details in services.items(): - # Always start with a clean CLI instance - self.cli_delete(base_path) - - self.cli_set(base_path + ddns + [svc, 'host-name', hostname]) - self.cli_set(base_path + ddns + [svc, 'password', password]) - self.cli_set(base_path + ddns + [svc, 'zone', zone]) - self.cli_set(base_path + ddns + [svc, 'ttl', ttl]) + self.cli_set(base_path + svc_path + [svc, 'host-name', hostname]) + self.cli_set(base_path + svc_path + [svc, 'password', password]) + self.cli_set(base_path + svc_path + [svc, 'zone', zone]) + self.cli_set(base_path + svc_path + [svc, 'ttl', ttl]) for opt, value in details.items(): - self.cli_set(base_path + ddns + [svc, opt, value]) + self.cli_set(base_path + svc_path + [svc, opt, value]) # 'zone' option is supported and required by 'cloudfare', but not 'freedns' and 'zoneedit' - self.cli_set(base_path + ddns + [svc, 'zone', zone]) + self.cli_set(base_path + svc_path + [svc, 'zone', zone]) if details['protocol'] == 'cloudflare': pass else: # exception is raised for unsupported ones with self.assertRaises(ConfigSessionError): self.cli_commit() - self.cli_delete(base_path + ddns + [svc, 'zone']) + self.cli_delete(base_path + svc_path + [svc, 'zone']) # 'ttl' option is supported by 'cloudfare', but not 'freedns' and 'zoneedit' - self.cli_set(base_path + ddns + [svc, 'ttl', ttl]) + self.cli_set(base_path + svc_path + [svc, 'ttl', ttl]) if details['protocol'] == 'cloudflare': pass else: # exception is raised for unsupported ones with self.assertRaises(ConfigSessionError): self.cli_commit() - self.cli_delete(base_path + ddns + [svc, 'ttl']) + self.cli_delete(base_path + svc_path + [svc, 'ttl']) # commit changes self.cli_commit() @@ -109,20 +113,17 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase): # IPv6 only DDNS service configuration def test_02_dyndns_service_ipv6(self): timeout = '60' - ddns = ['address', interface, 'service', 'dynv6'] + svc_path = ['address', interface, 'service', 'dynv6'] proto = 'dyndns2' - user = 'none' - password = 'paSS_4ord' - srv = 'ddns.vyos.io' ip_version = 'ipv6' self.cli_set(base_path + ['timeout', timeout]) - self.cli_set(base_path + ddns + ['ip-version', ip_version]) - self.cli_set(base_path + ddns + ['protocol', proto]) - self.cli_set(base_path + ddns + ['server', srv]) - self.cli_set(base_path + ddns + ['username', user]) - self.cli_set(base_path + ddns + ['password', password]) - self.cli_set(base_path + ddns + ['host-name', hostname]) + self.cli_set(base_path + svc_path + ['ip-version', ip_version]) + self.cli_set(base_path + svc_path + ['protocol', proto]) + self.cli_set(base_path + svc_path + ['server', server]) + self.cli_set(base_path + svc_path + ['username', username]) + self.cli_set(base_path + svc_path + ['password', password]) + self.cli_set(base_path + svc_path + ['host-name', hostname]) # commit changes self.cli_commit() @@ -133,37 +134,45 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase): self.assertIn(f'usev6=ifv6', ddclient_conf) self.assertIn(f'ifv6={interface}', ddclient_conf) self.assertIn(f'protocol={proto}', ddclient_conf) - self.assertIn(f'server={srv}', ddclient_conf) - self.assertIn(f'login={user}', ddclient_conf) + self.assertIn(f'server={server}', ddclient_conf) + self.assertIn(f'login={username}', ddclient_conf) self.assertIn(f'password={password}', ddclient_conf) # IPv4+IPv6 dual DDNS service configuration def test_03_dyndns_service_dual_stack(self): - ddns = ['address', interface, 'service'] - services = {'cloudflare': {'protocol': 'cloudflare', 'zone': 'vyos.io'}, - 'freedns': {'protocol': 'freedns', 'username': 'vyos_user'}} - password = 'vyos_pass' + svc_path = ['address', interface, 'service'] + services = {'cloudflare': {'protocol': 'cloudflare', 'zone': zone}, + 'freedns': {'protocol': 'freedns', 'username': username}, + 'google': {'protocol': 'googledomains', 'username': username}} ip_version = 'both' - for svc, details in services.items(): - # Always start with a clean CLI instance - self.cli_delete(base_path) - - self.cli_set(base_path + ddns + [svc, 'host-name', hostname]) - self.cli_set(base_path + ddns + [svc, 'password', password]) - self.cli_set(base_path + ddns + [svc, 'ip-version', ip_version]) + for name, details in services.items(): + self.cli_set(base_path + svc_path + [name, 'host-name', hostname]) + self.cli_set(base_path + svc_path + [name, 'password', password]) for opt, value in details.items(): - self.cli_set(base_path + ddns + [svc, opt, value]) + self.cli_set(base_path + svc_path + [name, opt, value]) + + # Dual stack is supported by 'cloudfare' and 'freedns' but not 'googledomains' + # exception is raised for unsupported ones + self.cli_set(base_path + svc_path + [name, 'ip-version', ip_version]) + if details['protocol'] not in ['cloudflare', 'freedns']: + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(base_path + svc_path + [name, 'ip-version']) # commit changes self.cli_commit() # Check the generating config parameters ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}') - self.assertIn(f'usev4=ifv4', ddclient_conf) - self.assertIn(f'usev6=ifv6', ddclient_conf) - self.assertIn(f'ifv4={interface}', ddclient_conf) - self.assertIn(f'ifv6={interface}', ddclient_conf) + if details['protocol'] not in ['cloudflare', 'freedns']: + self.assertIn(f'usev4=ifv4', ddclient_conf) + self.assertIn(f'ifv4={interface}', ddclient_conf) + else: + self.assertIn(f'usev4=ifv4', ddclient_conf) + self.assertIn(f'usev6=ifv6', ddclient_conf) + self.assertIn(f'ifv4={interface}', ddclient_conf) + self.assertIn(f'ifv6={interface}', ddclient_conf) self.assertIn(f'password={password}', ddclient_conf) for opt in details.keys(): @@ -176,19 +185,16 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase): def test_04_dyndns_rfc2136(self): # Check if DDNS service can be configured and runs - ddns = ['address', interface, 'rfc2136', 'vyos'] - srv = 'ns1.vyos.io' - zone = 'vyos.io' - ttl = '300' + svc_path = ['address', interface, 'rfc2136', 'vyos'] with tempfile.NamedTemporaryFile(prefix='/config/auth/') as key_file: key_file.write(b'S3cretKey') - self.cli_set(base_path + ddns + ['server', srv]) - self.cli_set(base_path + ddns + ['zone', zone]) - self.cli_set(base_path + ddns + ['key', key_file.name]) - self.cli_set(base_path + ddns + ['ttl', ttl]) - self.cli_set(base_path + ddns + ['host-name', hostname]) + self.cli_set(base_path + svc_path + ['server', server]) + self.cli_set(base_path + svc_path + ['zone', zone]) + self.cli_set(base_path + svc_path + ['key', key_file.name]) + self.cli_set(base_path + svc_path + ['ttl', ttl]) + self.cli_set(base_path + svc_path + ['host-name', hostname]) # commit changes self.cli_commit() @@ -198,7 +204,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase): self.assertIn(f'use=if', ddclient_conf) self.assertIn(f'if={interface}', ddclient_conf) self.assertIn(f'protocol=nsupdate', ddclient_conf) - self.assertIn(f'server={srv}', ddclient_conf) + self.assertIn(f'server={server}', ddclient_conf) self.assertIn(f'zone={zone}', ddclient_conf) self.assertIn(f'password={key_file.name}', ddclient_conf) self.assertIn(f'ttl={ttl}', ddclient_conf) @@ -231,9 +237,6 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase): vrf_name = f'vyos-test-{"".join(random.choices(string.ascii_letters + string.digits, k=5))}' svc_path = ['address', interface, 'service', 'cloudflare'] - # Always start with a clean CLI instance - self.cli_delete(base_path) - self.cli_set(['vrf', 'name', vrf_name, 'table', '12345']) self.cli_set(base_path + ['vrf', vrf_name]) diff --git a/src/conf_mode/dns_dynamic.py b/src/conf_mode/dns_dynamic.py index 5150574a8..8a438cf6f 100755 --- a/src/conf_mode/dns_dynamic.py +++ b/src/conf_mode/dns_dynamic.py @@ -30,7 +30,7 @@ config_file = r'/run/ddclient/ddclient.conf' systemd_override = r'/run/systemd/system/ddclient.service.d/override.conf' # Protocols that require zone -zone_required = ['cloudflare', 'godaddy', 'hetzner', 'gandi', 'nfsn'] +zone_necessary = ['cloudflare', 'godaddy', 'hetzner', 'gandi', 'nfsn'] # Protocols that do not require username username_unnecessary = ['1984', 'cloudflare', 'cloudns', 'duckdns', 'freemyip', 'hetzner', 'keysystems', 'njalla'] @@ -51,11 +51,11 @@ def get_config(config=None): else: conf = Config() - base_level = ['service', 'dns', 'dynamic'] - if not conf.exists(base_level): + base = ['service', 'dns', 'dynamic'] + if not conf.exists(base): return None - dyndns = conf.get_config_dict(base_level, key_mangling=('-', '_'), + dyndns = conf.get_config_dict(base, key_mangling=('-', '_'), no_tag_node_value_mangle=True, get_first_key=True, with_recursive_defaults=True) @@ -90,15 +90,14 @@ def verify(dyndns): if field not in config: raise ConfigError(f'"{field.replace("_", "-")}" {error_msg}') - if config['protocol'] in zone_required and 'zone' not in config: - raise ConfigError(f'"zone" {error_msg}') + if config['protocol'] in zone_necessary and 'zone' not in config: + raise ConfigError(f'"zone" {error_msg}') - if config['protocol'] not in zone_required and 'zone' in config: - raise ConfigError(f'"{config["protocol"]}" does not support "zone"') + if config['protocol'] not in zone_necessary and 'zone' in config: + raise ConfigError(f'"{config["protocol"]}" does not support "zone"') - if config['protocol'] not in username_unnecessary: - if 'username' not in config: - raise ConfigError(f'"username" {error_msg}') + if config['protocol'] not in username_unnecessary and 'username' not in config: + raise ConfigError(f'"username" {error_msg}') if config['protocol'] not in ttl_supported and 'ttl' in config: raise ConfigError(f'"{config["protocol"]}" does not support "ttl"') -- cgit v1.2.3