diff options
| author | Oleksandr Kuchmystyi <o.kuchmystyi@vyos.io> | 2026-05-01 16:51:32 +0300 |
|---|---|---|
| committer | Oleksandr Kuchmystyi <o.kuchmystyi@vyos.io> | 2026-05-25 15:39:27 +0300 |
| commit | 464fdf6da24c03ef725eeb6c52a9a1849a788ffd (patch) | |
| tree | 27f372a07927aa1bc44c6844286394b7020de513 /src | |
| parent | db23d7201c9df78c91aeeeade6963f2cc12b50b1 (diff) | |
| download | vyos-1x-464fdf6da24c03ef725eeb6c52a9a1849a788ffd.tar.gz vyos-1x-464fdf6da24c03ef725eeb6c52a9a1849a788ffd.zip | |
openvpn: T6478: Skip restart service when only client config changed
OpenVPN server reads per-client files from `--client-config-dir` at connect
time. When only `interfaces openvpn vtunN server client <client>`
entries are modified there is no need to send SIGHUP or restart
the service - the new CCD files written by `generate()` will
be picked up automatically on the next client connection.
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/interfaces_openvpn.py | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/src/conf_mode/interfaces_openvpn.py b/src/conf_mode/interfaces_openvpn.py index ab27fe66e..d6b63ae2a 100755 --- a/src/conf_mode/interfaces_openvpn.py +++ b/src/conf_mode/interfaces_openvpn.py @@ -78,6 +78,28 @@ otp_file = '/config/auth/openvpn/{ifname}-otp-secrets' secret_chars = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') service_file = '/run/systemd/system/openvpn@{ifname}.service.d/20-override.conf' +def _only_client_config_changed(conf, base, ifname): + """ + Return True when the sole diff under this interface is a change to + `server.client` entries (i.e. CCD files). + """ + + iface_path = base + [ifname] + diff = get_config_diff(conf) + + def _has_only_changes(path, node): + changes = diff.node_changed_children(path) + return len(changes) == 1 and changes[0] == node + + # Something outside of 'server' also changed - not a CCD-only change + if _has_only_changes(iface_path, 'server'): + # Something outside of 'server.client' also changed - not a CCD-only change + if _has_only_changes(iface_path + ['server'], 'client'): + return True + + return False + + def get_config(config=None): """ Retrieve CLI config as dictionary. Dictionary can never be empty, as at least the @@ -117,6 +139,12 @@ def get_config(config=None): if is_node_changed(conf, base + [ifname, 'enable-dco']): openvpn.update({'restart_required': {}}) + # Detect changes that are limited to per-client CCD entries (T6478). + # OpenVPN reads client-config-dir files at connect time, so adding or + # updating them requires neither a SIGHUP nor a service restart. + if 'restart_required' not in openvpn and openvpn['mode'] == 'server': + openvpn['client_only_changed'] = _only_client_config_changed(conf, base, ifname) + # We have to get the dict using 'get_config_dict' instead of 'get_interface_dict' # as 'get_interface_dict' merges the defaults in, so we can not check for defaults in there. tmp = conf.get_config_dict(base + [openvpn['ifname']], get_first_key=True) @@ -818,7 +846,7 @@ def apply(openvpn): # No matching OpenVPN process running - maybe it got killed or none # existed - nevertheless, spawn new OpenVPN process - if not openvpn.get('no_restart_crl'): + if not openvpn.get('no_restart_crl') and not openvpn.get('client_only_changed'): action = 'reload-or-restart' if 'restart_required' in openvpn: action = 'restart' |
