Support dns-options in network role

Signed-off-by: Wen Liang <liangwen12year@gmail.com>
This commit is contained in:
Wen Liang 2021-01-07 15:09:53 -05:00 committed by Gris Ge
parent 675c7e8073
commit 880b7ab0cc
8 changed files with 357 additions and 4 deletions

View file

@ -327,11 +327,12 @@ The IP configuration supports the following options:
[`ipv4.dhcp-send-hostname`](https://developer.gnome.org/NetworkManager/stable/nm-settings.html#nm-settings.property.ipv4.dhcp-send-hostname)
property.
* `dns` and `dns_search`
* `dns`, `dns_search` and `dns_options`
Manual DNS configuration can be specified via a list of addresses
given in the `dns` option and a list of domains to search given in the
`dns_search` option.
given in the `dns` option, a list of domains to search given in the
`dns_search` option and a list of dns options to set given in the
`dns_options`.
* `route_metric4` and `route_metric6`
@ -717,6 +718,9 @@ network_connections:
dns_search:
- example.com
- subdomain.example.com
dns_options:
- rotate
- timeout:1
route_metric6: -1
auto6: no

View file

@ -0,0 +1,44 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- hosts: all
vars:
network_connections:
- name: eth0
type: ethernet
ip:
route_metric4: 100
dhcp4: no
gateway4: 192.0.2.1
dns:
- 192.0.2.2
- 198.51.100.5
dns_search:
- example.com
- subdomain.example.com
dns_options:
- rotate
- timeout:1
route_metric6: -1
auto6: no
gateway6: 2001:db8::1
address:
- 192.0.2.3/24
- 198.51.100.3/26
- 2001:db8::80/7
route:
- network: 198.51.100.128
prefix: 26
gateway: 198.51.100.1
metric: 2
- network: 198.51.100.64
prefix: 26
gateway: 198.51.100.6
metric: 4
route_append_only: no
rule_append_only: yes
roles:
- linux-system-roles.network
...

View file

@ -993,7 +993,9 @@ class NMUtil:
s_ip4.add_dns(d["address"])
for s in ip["dns_search"]:
s_ip4.add_dns_search(s)
s_ip4.clear_dns_options(True)
for s in ip["dns_options"]:
s_ip4.add_dns_option(s)
if ip["auto6"]:
s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto")
elif addrs6:

View file

@ -4,6 +4,7 @@
import posixpath
import socket
import re
# pylint: disable=import-error, no-name-in-module
from ansible.module_utils.network_lsr import MyError # noqa:E501
@ -171,10 +172,12 @@ class ArgValidatorStr(ArgValidator):
allow_empty=False,
min_length=None,
max_length=None,
regex=None,
):
ArgValidator.__init__(self, name, required, default_value)
self.enum_values = enum_values
self.allow_empty = allow_empty
self.regex = regex
if max_length is not None:
if not isinstance(max_length, int):
@ -200,6 +203,12 @@ class ArgValidatorStr(ArgValidator):
"is '%s' but must be one of '%s'"
% (value, "' '".join(sorted(self.enum_values))),
)
if self.regex is not None and not any(re.match(x, value) for x in self.regex):
raise ValidationError(
name,
"is '%s' which does not match the regex '%s'"
% (value, "' '".join(sorted(self.regex))),
)
if not self.allow_empty and not value:
raise ValidationError(name, "cannot be empty")
if not self._validate_string_max_length(value):
@ -517,6 +526,22 @@ class ArgValidatorIPRoute(ArgValidatorDict):
class ArgValidator_DictIP(ArgValidatorDict):
REGEX_DNS_OPTIONS = [
r"^attempts:([1-9]\d*|0)$",
r"^debug$",
r"^edns0$",
r"^ndots:([1-9]\d*|0)$",
r"^no-check-names$",
r"^no-reload$",
r"^no-tld-query$",
r"^rotate$",
r"^single-request$",
r"^single-request-reopen$",
r"^timeout:([1-9]\d*|0)$",
r"^trust-ad$",
r"^use-vc$",
]
def __init__(self):
ArgValidatorDict.__init__(
self,
@ -553,6 +578,13 @@ class ArgValidator_DictIP(ArgValidatorDict):
nested=ArgValidatorStr("dns_search[?]"),
default_value=list,
),
ArgValidatorList(
"dns_options",
nested=ArgValidatorStr(
"dns_options[?]", regex=ArgValidator_DictIP.REGEX_DNS_OPTIONS
),
default_value=list,
),
],
default_value=lambda: {
"dhcp4": True,
@ -568,6 +600,7 @@ class ArgValidator_DictIP(ArgValidatorDict):
"rule_append_only": False,
"dns": [],
"dns_search": [],
"dns_options": [],
},
)
@ -1707,3 +1740,12 @@ class ArgValidator_ListConnections(ArgValidatorList):
"Configure wireless connection in /etc/wpa_supplicant.conf "
"if you need to use initscripts.",
)
# initscripts does not support ip.dns_options, so raise errors when network
# provider is initscripts
if connection["ip"]["dns_options"]:
if mode == self.VALIDATE_ONE_MODE_INITSCRIPTS:
raise ValidationError.from_connection(
idx,
"ip.dns_options is not supported by initscripts.",
)

View file

@ -59,6 +59,7 @@ EXTRA_RUN_CONDITION = "extra_run_condition"
NM_ONLY_TESTS = {
"playbooks/tests_802_1x_updated.yml": {},
"playbooks/tests_802_1x.yml": {},
"playbooks/tests_eth_dns_support.yml": {},
"playbooks/tests_dummy.yml": {},
"playbooks/tests_ethtool_features.yml": {
MINIMUM_VERSION: "'1.20.0'",

View file

@ -0,0 +1,79 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- hosts: all
tasks:
- name: Connection 'eth0' was not exists yet
shell: nmcli connection show eth0
register: eth0_exists
ignore_errors: yes
- debug:
var: eth0_exists.stderr
- import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: eth0
type: ethernet
ip:
route_metric4: 100
dhcp4: no
gateway4: 192.0.2.1
dns:
- 192.0.2.2
- 198.51.100.5
dns_search:
- example.com
- example.org
dns_options:
- rotate
- timeout:1
route_metric6: -1
auto6: no
gateway6: 2001:db8::1
address:
- 192.0.2.3/24
- 198.51.100.3/26
- 2001:db8::80/7
route:
- network: 198.51.100.128
prefix: 26
gateway: 198.51.100.1
metric: 2
- network: 198.51.100.64
prefix: 26
gateway: 198.51.100.6
metric: 4
route_append_only: no
rule_append_only: yes
- name: Verify nmcli connection DNS entry
shell: nmcli connection show eth0 | grep ipv4.dns
register: ipv4_dns
ignore_errors: yes
- name: "Assert that DNS addresses are configured correctly"
assert:
that:
- "'192.0.2.2' in ipv4_dns.stdout"
- "'198.51.100.5' in ipv4_dns.stdout"
msg: "DNS addresses are configured incorrectly"
- name: "Assert that DNS search domains are configured correctly"
assert:
that:
- "'example.com' in ipv4_dns.stdout"
- "'example.org' in ipv4_dns.stdout"
msg: "DNS search domains are configured incorrectly"
- name: "Assert that DNS options are configured correctly"
assert:
that:
- "'rotate' in ipv4_dns.stdout"
- "'timeout:1' in ipv4_dns.stdout"
msg: "DNS options are configured incorrectly"
...

View file

@ -0,0 +1,19 @@
# 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_eth_dns_support.yml' with nm as provider
tasks:
- 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_eth_dns_support.yml
when:
- ansible_distribution_major_version != '6'

View file

@ -170,6 +170,7 @@ class TestValidator(unittest.TestCase):
"route_metric6": None,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
},
"mac": None,
@ -461,6 +462,7 @@ class TestValidator(unittest.TestCase):
"route_metric6": None,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
},
"mac": None,
@ -511,6 +513,7 @@ class TestValidator(unittest.TestCase):
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -557,6 +560,7 @@ class TestValidator(unittest.TestCase):
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -633,6 +637,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -696,6 +701,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -772,6 +778,7 @@ class TestValidator(unittest.TestCase):
"route": [],
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -805,6 +812,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -913,6 +921,7 @@ class TestValidator(unittest.TestCase):
"route": [],
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -946,6 +955,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -1049,6 +1059,7 @@ class TestValidator(unittest.TestCase):
"route": [],
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -1081,6 +1092,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -1133,6 +1145,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -1237,6 +1250,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": False,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
@ -1275,6 +1289,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": True,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
@ -1335,6 +1350,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": True,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -1382,6 +1398,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": True,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
@ -1448,6 +1465,7 @@ class TestValidator(unittest.TestCase):
"route_metric4": None,
"route_metric6": None,
"dns": [],
"dns_options": [],
"dns_search": [],
},
"mac": "aa:bb:cc:dd:ee:ff",
@ -1491,6 +1509,7 @@ class TestValidator(unittest.TestCase):
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -1559,6 +1578,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": True,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
@ -1597,6 +1617,7 @@ class TestValidator(unittest.TestCase):
"dhcp4_send_hostname": None,
"dhcp4": True,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
@ -1651,6 +1672,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": True,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
@ -1722,6 +1744,7 @@ class TestValidator(unittest.TestCase):
"dhcp4": True,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
@ -1820,6 +1843,7 @@ class TestValidator(unittest.TestCase):
},
],
"dns": [],
"dns_options": [],
"dns_search": ["aa", "bb"],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -1920,6 +1944,7 @@ class TestValidator(unittest.TestCase):
},
],
"dns": [],
"dns_options": [],
"dns_search": ["aa", "bb"],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -2033,6 +2058,7 @@ class TestValidator(unittest.TestCase):
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -2108,6 +2134,7 @@ class TestValidator(unittest.TestCase):
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -2183,6 +2210,7 @@ class TestValidator(unittest.TestCase):
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -2256,6 +2284,7 @@ class TestValidator(unittest.TestCase):
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -2319,6 +2348,7 @@ class TestValidator(unittest.TestCase):
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
@ -3019,6 +3049,138 @@ class TestValidator(unittest.TestCase):
input_connection.update({"state": "absent"})
self.assertValidationError(validator, input_connection)
def test_dns_options_argvalidator(self):
"""
Test that argvalidator for validating dns_options value is correctly defined.
"""
validator = network_lsr.argument_validator.ArgValidator_DictIP()
false_testcase_1 = {
"dns_options": ["attempts:01"],
}
false_testcase_2 = {
"dns_options": ["debug$"],
}
false_testcase_3 = {
"dns_options": ["edns00"],
}
false_testcase_4 = {
"dns_options": ["ndots:"],
}
false_testcase_5 = {
"dns_options": ["no-check-name"],
}
false_testcase_6 = {
"dns_options": ["no-rel0ad"],
}
false_testcase_7 = {
"dns_options": ["bugno-tld-query"],
}
false_testcase_8 = {
"dns_options": ["etator"],
}
false_testcase_9 = {
"dns_options": ["singlerequest"],
}
false_testcase_10 = {
"dns_options": ["single-request-reopen:2"],
}
false_testcase_11 = {
"dns_options": ["timeout"],
}
false_testcase_12 = {
"dns_options": ["*trust-ad*"],
}
false_testcase_13 = {
"dns_options": ["use1-vc2-use-vc"],
}
self.assertValidationError(validator, false_testcase_1)
self.assertValidationError(validator, false_testcase_2)
self.assertValidationError(validator, false_testcase_3)
self.assertValidationError(validator, false_testcase_4)
self.assertValidationError(validator, false_testcase_5)
self.assertValidationError(validator, false_testcase_6)
self.assertValidationError(validator, false_testcase_7)
self.assertValidationError(validator, false_testcase_8)
self.assertValidationError(validator, false_testcase_9)
self.assertValidationError(validator, false_testcase_10)
self.assertValidationError(validator, false_testcase_11)
self.assertValidationError(validator, false_testcase_12)
self.assertValidationError(validator, false_testcase_13)
true_testcase_1 = {
"dns_options": ["attempts:3"],
}
true_testcase_2 = {
"dns_options": ["debug"],
}
true_testcase_3 = {
"dns_options": ["ndots:3", "single-request-reopen"],
}
true_testcase_4 = {
"dns_options": ["ndots:2", "timeout:3"],
}
true_testcase_5 = {
"dns_options": ["no-check-names"],
}
true_testcase_6 = {
"dns_options": ["no-reload"],
}
true_testcase_7 = {
"dns_options": ["no-tld-query"],
}
true_testcase_8 = {
"dns_options": ["rotate"],
}
true_testcase_9 = {
"dns_options": ["single-request"],
}
true_testcase_10 = {
"dns_options": ["single-request-reopen"],
}
true_testcase_11 = {
"dns_options": ["trust-ad"],
}
true_testcase_12 = {
"dns_options": ["use-vc"],
}
self.assertEqual(
validator.validate(true_testcase_1)["dns_options"], ["attempts:3"]
)
self.assertEqual(validator.validate(true_testcase_2)["dns_options"], ["debug"])
self.assertEqual(
validator.validate(true_testcase_3)["dns_options"],
["ndots:3", "single-request-reopen"],
)
self.assertEqual(
validator.validate(true_testcase_4)["dns_options"], ["ndots:2", "timeout:3"]
)
self.assertEqual(
validator.validate(true_testcase_5)["dns_options"], ["no-check-names"]
)
self.assertEqual(
validator.validate(true_testcase_6)["dns_options"], ["no-reload"]
)
self.assertEqual(
validator.validate(true_testcase_7)["dns_options"], ["no-tld-query"]
)
self.assertEqual(validator.validate(true_testcase_8)["dns_options"], ["rotate"])
self.assertEqual(
validator.validate(true_testcase_9)["dns_options"], ["single-request"]
)
self.assertEqual(
validator.validate(true_testcase_10)["dns_options"],
["single-request-reopen"],
)
self.assertEqual(
validator.validate(true_testcase_11)["dns_options"], ["trust-ad"]
)
self.assertEqual(
validator.validate(true_testcase_12)["dns_options"], ["use-vc"]
)
@my_test_skipIf(nmutil is None, "no support for NM (libnm via pygobject)")
class TestNM(unittest.TestCase):