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'