From af123707c2aec179b01e664c545df6440c7093f1 Mon Sep 17 00:00:00 2001 From: Wen Liang Date: Wed, 15 Sep 2021 21:35:27 -0400 Subject: [PATCH] Set DNS search setting only for enabled IP families NetworkManager requires to configure DNS options (such as the search setting) for each IP family even though it does not matter in the system's DNS configuration. Also, NetworkManager only allows to configure the DNS options for each IP family, when they are enabled. In the network_connections dictionary, the DNS options are configured without considering the IP family. Therefore, configure ipv4.dns-search or ipv6.dns-search only if the IP family is enabled. Signed-off-by: Wen Liang --- library/network_connections.py | 20 ++- tests/ensure_provider_tests.py | 1 + tests/playbooks/tests_ipv6_dns_search.yml | 156 ++++++++++++++++++++++ tests/tests_ipv6_dns_search_nm.yml | 20 +++ 4 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 tests/playbooks/tests_ipv6_dns_search.yml create mode 100644 tests/tests_ipv6_dns_search_nm.yml diff --git a/library/network_connections.py b/library/network_connections.py index 4185a13..d615edb 100644 --- a/library/network_connections.py +++ b/library/network_connections.py @@ -1029,14 +1029,17 @@ class NMUtil: addrs4 = [a for a in ip["address"] if a["family"] == socket.AF_INET] addrs6 = [a for a in ip["address"] if a["family"] == socket.AF_INET6] + is_ipv4_configured = False if ip["dhcp4"]: s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto") s_ip4.set_property( NM.SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, ip["dhcp4_send_hostname"] is not False, ) + is_ipv4_configured = True elif addrs4: s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "manual") + is_ipv4_configured = True else: s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "disabled") for a in addrs4: @@ -1052,8 +1055,11 @@ class NMUtil: for nameserver in ip["dns"]: if nameserver["family"] == socket.AF_INET: s_ip4.add_dns(nameserver["address"]) - for search_domain in ip["dns_search"]: - s_ip4.add_dns_search(search_domain) + # NetworkManager only allows to configure `ipv4.dns-search` setting when + # IPv4 is enabled + if is_ipv4_configured: + for search_domain in ip["dns_search"]: + s_ip4.add_dns_search(search_domain) # NetworkManager ifcfg plguin will discard empty dns option which # cause follow up NM.Connection.compare() raise false alarm # Use False here to ask NetworkManager remove dns option completely instead @@ -1062,12 +1068,15 @@ class NMUtil: for option in ip["dns_options"]: s_ip4.add_dns_option(option) + is_ipv6_configured = False if ip["ipv6_disabled"]: s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "disabled") elif ip["auto6"]: s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto") + is_ipv6_configured = True elif addrs6: s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "manual") + is_ipv6_configured = True else: # we should not set "ipv6.method=ignore". "ignore" is a legacy mode # and not really useful. Instead, we should set "link-local" here. @@ -1098,8 +1107,11 @@ class NMUtil: for nameserver in ip["dns"]: if nameserver["family"] == socket.AF_INET6: s_ip6.add_dns(nameserver["address"]) - for search_domain in ip["dns_search"]: - s_ip6.add_dns_search(search_domain) + # NetworkManager only allows to configure `ipv6.dns-search` setting when + # IPv6 is enabled + if is_ipv6_configured: + for search_domain in ip["dns_search"]: + s_ip6.add_dns_search(search_domain) # NetworkManager ifcfg plguin will discard empty dns option which # cause follow up NM.Connection.compare() raise false alarm # Use False here to ask NetworkManager remove dns option completely instead diff --git a/tests/ensure_provider_tests.py b/tests/ensure_provider_tests.py index c060de5..ab8f4d7 100755 --- a/tests/ensure_provider_tests.py +++ b/tests/ensure_provider_tests.py @@ -72,6 +72,7 @@ ibution_major_version | int < 9", "playbooks/tests_ipv6_disabled.yml": { EXTRA_RUN_CONDITION: "ansible_distribution_major_version == '8'", }, + "playbooks/tests_ipv6_dns_search.yml": {}, "playbooks/tests_provider.yml": { MINIMUM_VERSION: "'1.20.0'", "comment": "# NetworKmanager 1.20.0 added support for forgetting profiles", diff --git a/tests/playbooks/tests_ipv6_dns_search.yml b/tests/playbooks/tests_ipv6_dns_search.yml new file mode 100644 index 0000000..d95eee5 --- /dev/null +++ b/tests/playbooks/tests_ipv6_dns_search.yml @@ -0,0 +1,156 @@ +--- +- hosts: all + tasks: + - block: + - name: Configure the static IPv4 address and not configure the IPv6 + address + import_role: + name: linux-system-roles.network + vars: + network_connections: + - name: br-example + type: bridge + ip: + dhcp4: false + auto6: false + dns: 203.0.113.113 + dns_search: example.com + address: + - 192.0.2.1/24 + state: up + - name: Get DNS search entry for IPv4 + command: nmcli -f ipv4.dns-search connection show br-example + register: ipv4_dns_search + ignore_errors: yes + changed_when: false + + - name: Get DNS search entry for IPv6 + command: nmcli -f ipv6.dns-search connection show br-example + register: ipv6_dns_search + ignore_errors: yes + changed_when: false + + - name: Assert that IPv4 DNS search entry is configured correctly + assert: + that: + - "'example.com' in ipv4_dns_search.stdout" + msg: "IPv4 DNS search entry is missing" + + - name: Assert that DNS search setting for IPv6 is not configured when + IPv6 address is not configured + assert: + that: + - "'example.com' not in ipv6_dns_search.stdout" + msg: DNS search setting for IPv6 is configured when IPv6 address is + not configured + + - name: Reconfigure the static IPv4 and IPv6 address, reconfigure DNS + and DNS search setting for IPv4 and IPv6 + import_role: + name: linux-system-roles.network + vars: + network_connections: + - name: br-example + type: bridge + ip: + dhcp4: false + auto6: false + dns: + - 203.0.113.113 + - 2001:db8::20 + dns_search: example.com + address: + - 192.0.2.1/24 + - 2001:db8::2/32 + state: up + + - name: Get DNS search entry for IPv6 + command: nmcli -f ipv6.dns-search connection show br-example + register: ipv6_dns_search_static + ignore_errors: yes + changed_when: false + + - name: Assert that DNS search setting for IPv6 is configured when + the static IPv6 address is configured + assert: + that: + - "'example.com' in ipv6_dns_search_static.stdout" + msg: DNS search setting for IPv6 is not configured when the static + IPv6 address is configured + + - name: Reconfigure connection profile and only configure the static + IPv6 address + import_role: + name: linux-system-roles.network + vars: + network_connections: + - name: br-example + type: bridge + ip: + dhcp4: false + auto6: false + dns: + - 2001:db8::20 + dns_search: example.com + address: + - 2001:db8::2/32 + state: up + + - name: Get DNS search entry for IPv6 + command: nmcli -f ipv6.dns-search connection show br-example + register: ipv6_dns_search_static_only + ignore_errors: yes + changed_when: false + + - name: Assert that DNS search setting for IPv6 is configured when only + the static IPv6 address is configured + assert: + that: + - "'example.com' in ipv6_dns_search_static_only.stdout" + msg: DNS search setting for IPv6 is not configured when only the + static IPv6 address is configured + + - name: Reconfigure connection profile, disable both IPv4 and IPv6 + import_role: + name: linux-system-roles.network + vars: + network_connections: + - name: br-example + type: bridge + ip: + dhcp4: false + ipv6_disabled: true + dns_search: example.com + state: up + ignore_errors: true # noqa ignore-errors + changed_when: false + + - name: Assert that reconfiguring network connection is failed + assert: + that: + - __network_connections_result.failed + msg: reconfiguring network connection is not failed + + - name: Assert that configuring DNS search setting is not allowed when + both IPv4 and IPv6 are disabled + assert: + that: + - __network_connections_result.stderr is search("Setting + 'dns_search' or 'dns_options' is not allowed when both IPv4 and + IPv6 are disabled.") + msg: Reconfiguring network connection is not failed with the error + "Setting 'dns_search' or 'dns_options' is not allowed when both + IPv4 and IPv6 are disabled." + + always: + - block: + - import_role: + name: linux-system-roles.network + vars: + network_connections: + - name: br-example + persistent_state: absent + state: down + ignore_errors: true + tags: + - "tests::cleanup" diff --git a/tests/tests_ipv6_dns_search_nm.yml b/tests/tests_ipv6_dns_search_nm.yml new file mode 100644 index 0000000..7ba96b1 --- /dev/null +++ b/tests/tests_ipv6_dns_search_nm.yml @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: BSD-3-Clause +# This file was generated by ensure_provider_tests.py +--- +# set network provider and gather facts +- hosts: all + name: Run playbook 'playbooks/tests_ipv6_dns_search.yml' with nm as provider + tasks: + - include_tasks: tasks/el_repo_setup.yml + - name: Set network provider to 'nm' + set_fact: + network_provider: nm + tags: + - always + + +# The test requires or should run with NetworkManager, therefore it cannot run +# on RHEL/CentOS 6 +- import_playbook: playbooks/tests_ipv6_dns_search.yml + when: + - ansible_distribution_major_version != '6'