summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIndrajit Raychaudhuri <irc@indrajit.com>2023-09-13 01:02:12 -0500
committerIndrajit Raychaudhuri <irc@indrajit.com>2023-11-30 21:42:23 -0600
commitc3ba4527824c9f4d2e53e7fbd0bff4b84c3012f4 (patch)
treeb09750a0bfad77def691baee1ce8139e04194cdd
parent6b30a92eaff48ae5dd4968e30f3464e04c69d4fd (diff)
downloadvyos-1x-c3ba4527824c9f4d2e53e7fbd0bff4b84c3012f4.tar.gz
vyos-1x-c3ba4527824c9f4d2e53e7fbd0bff4b84c3012f4.zip
ddclient: T5574: Support per-service cache management for services
Add support for per-service cache management for ddclient providers via `wait-time` and `expiry-time` options. This allows for finer-grained control over how often a service is updated and how long the hostname will be cached before being marked expired in ddclient's cache. More specifically, `wait-time` controls how often ddclient will attempt to check for a change in the hostname's IP address, and `expiry-time` controls how often ddclient to a forced update of the hostname's IP address. These options intentionally don't have any default values because they are provider-specific. They get treated similar to the other provider- specific options in that they are only used if defined.
-rw-r--r--data/templates/dns-dynamic/ddclient.conf.j211
-rw-r--r--interface-definitions/dns-dynamic.xml.in2
-rw-r--r--interface-definitions/include/dns/dynamic-service-wait-expiry-time.xml.i28
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_dynamic.py12
-rwxr-xr-xsrc/conf_mode/dns_dynamic.py3
5 files changed, 49 insertions, 7 deletions
diff --git a/data/templates/dns-dynamic/ddclient.conf.j2 b/data/templates/dns-dynamic/ddclient.conf.j2
index 5905b19ea..6e77abdb5 100644
--- a/data/templates/dns-dynamic/ddclient.conf.j2
+++ b/data/templates/dns-dynamic/ddclient.conf.j2
@@ -14,10 +14,8 @@ if{{ ipv }}={{ address }}, \
{% endif %}
{% endfor %}
{# Other service options #}
-{% for k,v in kwargs.items() %}
-{% if v is vyos_defined %}
-{{ k }}={{ v }}{{ ',' if not loop.last }} \
-{% endif %}
+{% for k,v in kwargs.items() if v is vyos_defined %}
+{{ k | replace('_', '-') }}={{ v }}{{ ',' if not loop.last }} \
{% endfor %}
{# Actual hostname for the service #}
{{ host }}
@@ -49,7 +47,6 @@ use=no
{{ render_config(host, address, service_cfg.web_options,
protocol='nsupdate', server=config.server, zone=config.zone,
password=config.key, ttl=config.ttl) }}
-
{% endfor %}
{% endfor %}
{% endif %}
@@ -66,8 +63,8 @@ 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, ttl=config.ttl) }}
-
+ login=config.username, password=config.password, ttl=config.ttl,
+ min_interval=config.wait_time, max_interval=config.expiry_time) }}
{% endfor %}
{% endfor %}
{% endif %}
diff --git a/interface-definitions/dns-dynamic.xml.in b/interface-definitions/dns-dynamic.xml.in
index ba7f426c1..723223f1c 100644
--- a/interface-definitions/dns-dynamic.xml.in
+++ b/interface-definitions/dns-dynamic.xml.in
@@ -61,6 +61,7 @@
<children>
#include <include/generic-description.xml.i>
#include <include/dns/dynamic-service-host-name-server.xml.i>
+ #include <include/dns/dynamic-service-wait-expiry-time.xml.i>
<leafNode name="key">
<properties>
<help>File containing the TSIG secret key shared with remote DNS server</help>
@@ -88,6 +89,7 @@
<children>
#include <include/generic-description.xml.i>
#include <include/dns/dynamic-service-host-name-server.xml.i>
+ #include <include/dns/dynamic-service-wait-expiry-time.xml.i>
#include <include/generic-username.xml.i>
#include <include/generic-password.xml.i>
#include <include/dns/time-to-live.xml.i>
diff --git a/interface-definitions/include/dns/dynamic-service-wait-expiry-time.xml.i b/interface-definitions/include/dns/dynamic-service-wait-expiry-time.xml.i
new file mode 100644
index 000000000..866690cbe
--- /dev/null
+++ b/interface-definitions/include/dns/dynamic-service-wait-expiry-time.xml.i
@@ -0,0 +1,28 @@
+<!-- include start from dns/dynamic-service-wait-expiry-time.xml.i -->
+<leafNode name="wait-time">
+ <properties>
+ <help>Time in seconds to wait between update attempts</help>
+ <valueHelp>
+ <format>u32:60-86400</format>
+ <description>Time in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 60-86400"/>
+ </constraint>
+ <constraintErrorMessage>Wait time must be between 60 and 86400 seconds</constraintErrorMessage>
+ </properties>
+</leafNode>
+<leafNode name="expiry-time">
+ <properties>
+ <help>Time in seconds for the hostname to be marked expired in cache</help>
+ <valueHelp>
+ <format>u32:300-2160000</format>
+ <description>Time in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 300-2160000"/>
+ </constraint>
+ <constraintErrorMessage>Expiry time must be between 300 and 2160000 seconds</constraintErrorMessage>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py
index 66dcde434..acabc0070 100755
--- a/smoketest/scripts/cli/test_service_dns_dynamic.py
+++ b/smoketest/scripts/cli/test_service_dns_dynamic.py
@@ -116,6 +116,9 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
svc_path = ['address', interface, 'service', 'dynv6']
proto = 'dyndns2'
ip_version = 'ipv6'
+ wait_time = '600'
+ expiry_time_good = '3600'
+ expiry_time_bad = '360'
self.cli_set(base_path + ['timeout', timeout])
self.cli_set(base_path + svc_path + ['ip-version', ip_version])
@@ -124,6 +127,13 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
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])
+ self.cli_set(base_path + svc_path + ['wait-time', wait_time])
+
+ # expiry-time must be greater than wait-time, exception is raised otherwise
+ self.cli_set(base_path + svc_path + ['expiry-time', expiry_time_bad])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(base_path + svc_path + ['expiry-time', expiry_time_good])
# commit changes
self.cli_commit()
@@ -137,6 +147,8 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'server={server}', ddclient_conf)
self.assertIn(f'login={username}', ddclient_conf)
self.assertIn(f'password={password}', ddclient_conf)
+ self.assertIn(f'min-interval={wait_time}', ddclient_conf)
+ self.assertIn(f'max-interval={expiry_time_good}', ddclient_conf)
# IPv4+IPv6 dual DDNS service configuration
def test_03_dyndns_service_dual_stack(self):
diff --git a/src/conf_mode/dns_dynamic.py b/src/conf_mode/dns_dynamic.py
index 8a438cf6f..874c4b689 100755
--- a/src/conf_mode/dns_dynamic.py
+++ b/src/conf_mode/dns_dynamic.py
@@ -111,6 +111,9 @@ def verify(dyndns):
raise ConfigError(f'"{config["protocol"]}" does not support '
f'both IPv4 and IPv6 at the same time for "{config["server"]}"')
+ if {'wait_time', 'expiry_time'} <= config.keys() and int(config['expiry_time']) < int(config['wait_time']):
+ raise ConfigError(f'"expiry-time" must be greater than "wait-time"')
+
return None
def generate(dyndns):