Add 'auto_gateway' option

If enabled, a default route will be configured using the default gateway. If disabled,
the default route will be removed.

If this variable is not specified, the role will use the default behavior of the
`network_provider` selected.

Setting this option to `no` is equivalent to:
- `DEFROUTE = no` in initscripts, or
- `ipv4.never-default/ipv6.never-default yes` in nmcli

Signed-off-by: Jack Adolph <jack.adolph@gmail.com>
This commit is contained in:
Jack Adolph 2020-10-29 12:46:18 +11:00 committed by Gris Ge
parent 6fdac168a9
commit b368bce8aa
7 changed files with 409 additions and 0 deletions

View file

@ -341,6 +341,18 @@ The IP configuration supports the following options:
Manual addressing can be specified via a list of addresses under the `address` option.
- `auto_gateway`
If enabled, a default route will be configured using the default gateway. If disabled,
the default route will be removed.
If this variable is not specified, the role will use the default behavior of the
`network_provider` selected.
Setting this option to `no` is equivalent to:
- `DEFROUTE = no` in initscripts, or
- `ipv4.never-default/ipv6.never-default yes` in nmcli
- `dhcp4`, `auto6`, and `ipv6_disabled`
Also, manual addressing can be specified by setting either `dhcp4` or `auto6`.

View file

@ -510,6 +510,12 @@ class IfcfgUtil:
if ip["gateway6"] is not None:
ifcfg["IPV6_DEFAULTGW"] = ip["gateway6"]
if ip["auto_gateway"] is not None:
if ip["auto_gateway"]:
ifcfg["DEFROUTE"] = "yes"
else:
ifcfg["DEFROUTE"] = "no"
route4 = []
route6 = []
for r in ip["route"]:
@ -1056,6 +1062,15 @@ class NMUtil:
s_ip6.set_property(
NM.SETTING_IP_CONFIG_ROUTE_METRIC, ip["route_metric6"]
)
if ip["auto_gateway"] is not None:
if ip["auto_gateway"]:
s_ip6.set_property(NM.SETTING_IP_CONFIG_NEVER_DEFAULT, False)
s_ip4.set_property(NM.SETTING_IP_CONFIG_NEVER_DEFAULT, False)
else:
s_ip6.set_property(NM.SETTING_IP_CONFIG_NEVER_DEFAULT, True)
s_ip4.set_property(NM.SETTING_IP_CONFIG_NEVER_DEFAULT, True)
for nameserver in ip["dns"]:
if nameserver["family"] == socket.AF_INET6:
s_ip6.add_dns(nameserver["address"])

View file

@ -578,6 +578,7 @@ class ArgValidator_DictIP(ArgValidatorDict):
nested=ArgValidatorIPAddr("address[?]"),
default_value=list,
),
ArgValidatorBool("auto_gateway", default_value=None),
ArgValidatorList(
"route", nested=ArgValidatorIPRoute("route[?]"), default_value=list
),
@ -611,6 +612,7 @@ class ArgValidator_DictIP(ArgValidatorDict):
"gateway6": None,
"route_metric6": None,
"address": [],
"auto_gateway": None,
"route": [],
"route_append_only": False,
"rule_append_only": False,
@ -665,6 +667,20 @@ class ArgValidator_DictIP(ArgValidatorDict):
raise ValidationError(
name, "'dhcp4_send_hostname' is only valid if 'dhcp4' is enabled"
)
ipv4_gw_defined = result["gateway4"] is not None
ipv6_gw_defined = result["gateway6"] is not None
dhcp_enabled = result["dhcp4"] or result["auto6"]
if result["auto_gateway"] and not (
ipv4_gw_defined or ipv6_gw_defined or dhcp_enabled
):
raise ValidationError(
name,
"must define 'gateway4', 'gateway6', or use dhcp "
"if 'auto_gateway' is enabled",
)
return result

View file

@ -0,0 +1,133 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- hosts: all
vars:
type: veth
interface: veth0
tasks:
- include_tasks: tasks/show_interfaces.yml
- include_tasks: tasks/manage_test_interface.yml
vars:
state: present
- include_tasks: tasks/assert_device_present.yml
- name: >-
TEST: I can configure an interface with auto_gateway enabled
debug:
msg: "##################################################"
- import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
auto_gateway: yes
dhcp4: no
auto6: no
address:
- "2001:db8::2/64"
- "203.0.113.2/24"
gateway6: "2001:db8::1"
gateway4: "203.0.113.1"
- include_tasks: tasks/assert_device_present.yml
- include_tasks: tasks/assert_profile_present.yml
vars:
profile: "{{ interface }}"
- name: "Show ipv4 routes"
command: "ip route"
register: ipv4_routes
changed_when: false
- name: "Assert default ipv4 route is present"
assert:
that:
- >-
"default via 203.0.113.1 dev {{ interface }}"
in ipv4_routes.stdout
- name: "Get ipv6 routes"
command: "ip -6 route"
register: ipv6_route
changed_when: false
- name: "Assert default ipv6 route is present"
assert:
that:
- >-
"default via 2001:db8::1 dev {{ interface }}"
in ipv6_route.stdout
when: network_provider == "nm"
- name: "TEARDOWN: remove profiles."
debug:
msg: "##################################################"
- import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
persistent_state: absent
state: down
ignore_errors: true
- include_tasks: tasks/manage_test_interface.yml
vars:
state: absent
- name: >-
TEST: I can configure an interface with auto_gateway disabled
debug:
msg: "##################################################"
- include_tasks: tasks/manage_test_interface.yml
vars:
state: present
- import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
auto_gateway: no
dhcp4: no
auto6: no
address:
- "2001:db8::2/64"
- "203.0.113.2/24"
gateway6: "2001:db8::1"
gateway4: "203.0.113.1"
- include_tasks: tasks/assert_device_present.yml
- include_tasks: tasks/assert_profile_present.yml
vars:
profile: "{{ interface }}"
- name: "Show ipv4 routes"
command: "ip route"
register: ipv4_routes
changed_when: false
- name: "Assert default ipv4 route is absent"
assert:
that:
- >-
"default via 203.0.113.1 dev {{ interface }}"
not in ipv4_routes.stdout
- name: "Get ipv6 routes"
command: "ip -6 route"
register: ipv6_route
changed_when: false
- name: "Assert default ipv6 route is absent"
assert:
that:
- >-
"default via 2001:db8::1 dev {{ interface }}"
not in ipv6_route.stdout
when: network_provider == "nm"
- name: "TEARDOWN: remove profiles."
debug:
msg: "##################################################"
- import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
persistent_state: absent
state: down
ignore_errors: true
- include_tasks: tasks/manage_test_interface.yml
vars:
state: absent

View file

@ -0,0 +1,15 @@
# SPDX-License-Identifier: BSD-3-Clause
# This file was generated by ensure_provider_tests.py
---
- hosts: all
name: >
Run playbook 'playbooks/tests_auto_gateway.yml' with
initscripts as provider
tasks:
- name: Set network provider to 'initscripts'
set_fact:
network_provider: initscripts
tags:
- always
- import_playbook: playbooks/tests_auto_gateway.yml

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_auto_gateway.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_auto_gateway.yml
when:
- ansible_distribution_major_version != '6'

View file

@ -174,6 +174,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -469,6 +470,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -523,6 +525,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -571,6 +574,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -667,6 +671,7 @@ class TestValidator(unittest.TestCase):
"address": "192.168.174.5",
}
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -732,6 +737,7 @@ class TestValidator(unittest.TestCase):
"address": "192.168.174.5",
}
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -799,6 +805,7 @@ class TestValidator(unittest.TestCase):
"prefix": 32,
},
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -892,6 +899,7 @@ class TestValidator(unittest.TestCase):
"address": "192.168.177.5",
},
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -951,6 +959,7 @@ class TestValidator(unittest.TestCase):
"address": "a:b:c::6",
},
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [
@ -1008,6 +1017,174 @@ class TestValidator(unittest.TestCase):
],
)
def test_auto_gateway_true(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "prod1",
"ip": {
"dhcp4": True,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
"gateway4": None,
"auto6": True,
"ipv6_disabled": False,
"dns": [],
"address": [],
"auto_gateway": True,
"route_append_only": False,
"rule_append_only": False,
"route": [],
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "prod1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[
{
"name": "prod1",
"state": "up",
"type": "ethernet",
"ip": {"auto_gateway": True},
}
],
initscripts_dict_expected=[
{
"ifcfg": {
"BOOTPROTO": "dhcp",
"DEFROUTE": "yes",
"IPV6INIT": "yes",
"IPV6_AUTOCONF": "yes",
"NM_CONTROLLED": "no",
"ONBOOT": "yes",
"DEVICE": "prod1",
"TYPE": "Ethernet",
},
"keys": None,
"route": None,
"route6": None,
"rule": None,
"rule6": None,
}
],
)
def test_auto_gateway_false(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "prod1",
"ip": {
"dhcp4": True,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
"gateway4": None,
"auto6": True,
"ipv6_disabled": False,
"dns": [],
"address": [],
"auto_gateway": False,
"route_append_only": False,
"rule_append_only": False,
"route": [],
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "prod1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[
{
"name": "prod1",
"state": "up",
"type": "ethernet",
"ip": {"auto_gateway": False},
}
],
initscripts_dict_expected=[
{
"ifcfg": {
"BOOTPROTO": "dhcp",
"DEFROUTE": "no",
"IPV6INIT": "yes",
"IPV6_AUTOCONF": "yes",
"NM_CONTROLLED": "no",
"ONBOOT": "yes",
"DEVICE": "prod1",
"TYPE": "Ethernet",
},
"keys": None,
"route": None,
"route6": None,
"rule": None,
"rule6": None,
}
],
)
def test_auto_gateway_no_gateway(self):
self.maxDiff = None
self.do_connections_check_invalid(
[
{
"name": "eth0",
"state": "up",
"type": "ethernet",
"ip": {
"dhcp4": "no",
"auto6": "no",
"auto_gateway": "true",
"address": "192.168.176.5/24",
},
}
]
)
def test_vlan(self):
self.maxDiff = None
self.do_connections_validate(
@ -1036,6 +1213,7 @@ class TestValidator(unittest.TestCase):
"address": "192.168.177.5",
},
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -1096,6 +1274,7 @@ class TestValidator(unittest.TestCase):
"address": "a:b:c::6",
},
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [
@ -1176,6 +1355,7 @@ class TestValidator(unittest.TestCase):
"address": "192.168.122.3",
}
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -1230,6 +1410,7 @@ class TestValidator(unittest.TestCase):
"address": "192.168.244.1",
}
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [
@ -1284,6 +1465,7 @@ class TestValidator(unittest.TestCase):
"address": "192.168.245.7",
}
],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [
@ -1371,6 +1553,7 @@ class TestValidator(unittest.TestCase):
"interface_name": "bridge2",
"ip": {
"address": [],
"auto_gateway": None,
"auto6": False,
"dhcp4": False,
"dhcp4_send_hostname": None,
@ -1411,6 +1594,7 @@ class TestValidator(unittest.TestCase):
"interface_name": "eth1",
"ip": {
"address": [],
"auto_gateway": None,
"auto6": True,
"dhcp4": True,
"dhcp4_send_hostname": None,
@ -1486,6 +1670,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dns": [],
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -1535,6 +1720,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dns": [],
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -1583,6 +1769,7 @@ class TestValidator(unittest.TestCase):
"interface_name": None,
"ip": {
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -1636,6 +1823,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -1705,6 +1893,7 @@ class TestValidator(unittest.TestCase):
"interface_name": "6643-controller",
"ip": {
"address": [],
"auto_gateway": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
@ -1745,6 +1934,7 @@ class TestValidator(unittest.TestCase):
"interface_name": "6643",
"ip": {
"address": [],
"auto_gateway": None,
"auto6": True,
"dhcp4_send_hostname": None,
"dhcp4": True,
@ -1801,6 +1991,7 @@ class TestValidator(unittest.TestCase):
"interface_name": None,
"ip": {
"address": [],
"auto_gateway": None,
"auto6": True,
"dhcp4": True,
"dhcp4_send_hostname": None,
@ -1874,6 +2065,7 @@ class TestValidator(unittest.TestCase):
"interface_name": None,
"ip": {
"address": [],
"auto_gateway": None,
"auto6": True,
"dhcp4": True,
"dhcp4_send_hostname": None,
@ -1960,6 +2152,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [
@ -2055,6 +2248,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": True,
"rule_append_only": False,
"route": [
@ -2192,6 +2386,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -2269,6 +2464,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -2346,6 +2542,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -2421,6 +2618,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],
@ -2486,6 +2684,7 @@ class TestValidator(unittest.TestCase):
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"auto_gateway": None,
"route_append_only": False,
"rule_append_only": False,
"route": [],