network/tests/unit/test_network_connections.py
Jack Adolph 001f81b823 Fix static IPv6 support for initscripts provider
Use the correct parameter names for declaring static IPV6 connections
for the initscripts provider. Also, add integration and unit tests to
cover this.

Signed-off-by: Jack Adolph <jack.adolph@gmail.com>
Signed-off-by: Till Maas <opensource@till.name>
2021-04-08 16:49:20 +02:00

3425 lines
124 KiB
Python

#!/usr/bin/env python
""" Tests for network_connections Ansible module """
# SPDX-License-Identifier: BSD-3-Clause
import copy
import itertools
import pprint as pprint_
import socket
import sys
import unittest
try:
from unittest import mock
except ImportError: # py2
import mock
sys.modules["ansible.module_utils.basic"] = mock.Mock()
# pylint: disable=import-error, wrong-import-position
import network_lsr
import network_lsr.argument_validator
from network_connections import IfcfgUtil, NMUtil, SysUtil, Util
from network_lsr.argument_validator import ValidationError
try:
my_test_skipIf = unittest.skipIf
except AttributeError:
# python 2.6 workaround
def my_test_skipIf(condition, reason):
if condition:
return lambda x: None
else:
return lambda x: x
try:
nmutil = NMUtil()
assert nmutil
except Exception:
# NMUtil is not supported, for example on RHEL 6 or without
# pygobject.
nmutil = None
if nmutil:
NM = Util.NM()
GObject = Util.GObject()
def pprint(msg, obj):
print("PRINT: %s\n" % (msg))
p = pprint_.PrettyPrinter(indent=4)
p.pprint(obj)
if nmutil is not None and isinstance(obj, NM.Connection):
obj.dump()
ARGS_CONNECTIONS = network_lsr.argument_validator.ArgValidator_ListConnections()
VALIDATE_ONE_MODE_INITSCRIPTS = ARGS_CONNECTIONS.VALIDATE_ONE_MODE_INITSCRIPTS
VALIDATE_ONE_MODE_NM = ARGS_CONNECTIONS.VALIDATE_ONE_MODE_NM
ETHTOOL_FEATURES_DEFAULTS = {
"esp_hw_offload": None,
"esp_tx_csum_hw_offload": None,
"fcoe_mtu": None,
"gro": None,
"gso": None,
"highdma": None,
"hw_tc_offload": None,
"l2_fwd_offload": None,
"loopback": None,
"lro": None,
"ntuple": None,
"rx": None,
"rx_all": None,
"rx_fcs": None,
"rx_gro_hw": None,
"rx_udp_tunnel_port_offload": None,
"rx_vlan_filter": None,
"rx_vlan_stag_filter": None,
"rx_vlan_stag_hw_parse": None,
"rxhash": None,
"rxvlan": None,
"sg": None,
"tls_hw_record": None,
"tls_hw_tx_offload": None,
"tso": None,
"tx": None,
"tx_checksum_fcoe_crc": None,
"tx_checksum_ip_generic": None,
"tx_checksum_ipv4": None,
"tx_checksum_ipv6": None,
"tx_checksum_sctp": None,
"tx_esp_segmentation": None,
"tx_fcoe_segmentation": None,
"tx_gre_csum_segmentation": None,
"tx_gre_segmentation": None,
"tx_gso_partial": None,
"tx_gso_robust": None,
"tx_ipxip4_segmentation": None,
"tx_ipxip6_segmentation": None,
"tx_nocache_copy": None,
"tx_scatter_gather": None,
"tx_scatter_gather_fraglist": None,
"tx_sctp_segmentation": None,
"tx_tcp_ecn_segmentation": None,
"tx_tcp_mangleid_segmentation": None,
"tx_tcp_segmentation": None,
"tx_tcp6_segmentation": None,
"tx_udp_segmentation": None,
"tx_udp_tnl_csum_segmentation": None,
"tx_udp_tnl_segmentation": None,
"tx_vlan_stag_hw_insert": None,
"txvlan": None,
}
ETHTOOL_COALESCE_DEFAULTS = {
"adaptive_rx": None,
"adaptive_tx": None,
"pkt_rate_high": None,
"pkt_rate_low": None,
"rx_frames": None,
"rx_frames_high": None,
"rx_frames_irq": None,
"rx_frames_low": None,
"rx_usecs": None,
"rx_usecs_high": None,
"rx_usecs_irq": None,
"rx_usecs_low": None,
"sample_interval": None,
"stats_block_usecs": None,
"tx_frames": None,
"tx_frames_high": None,
"tx_frames_irq": None,
"tx_frames_low": None,
"tx_usecs": None,
"tx_usecs_high": None,
"tx_usecs_irq": None,
"tx_usecs_low": None,
}
ETHTOOL_DEFAULTS = {
"features": ETHTOOL_FEATURES_DEFAULTS,
"coalesce": ETHTOOL_COALESCE_DEFAULTS,
}
ETHERNET_DEFAULTS = {"autoneg": None, "duplex": None, "speed": 0}
class TestValidator(unittest.TestCase):
def setUp(self):
# default values when "type" is specified and state is not
self.default_connection_settings = {
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"ignore_errors": None,
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "5",
"parent": None,
"port_type": None,
"zone": None,
}
def assertValidationError(self, v, value):
self.assertRaises(ValidationError, v.validate, value)
def assert_nm_connection_routes_expected(self, connection, route_list_expected):
parser = network_lsr.argument_validator.ArgValidatorIPRoute("route[?]")
route_list_exp = [parser.validate(r) for r in route_list_expected]
route_list_new = itertools.chain(
nmutil.setting_ip_config_get_routes(
connection.get_setting(NM.SettingIP4Config)
),
nmutil.setting_ip_config_get_routes(
connection.get_setting(NM.SettingIP6Config)
),
)
route_list_new = [
{
"family": r.get_family(),
"network": r.get_dest(),
"prefix": int(r.get_prefix()),
"gateway": r.get_next_hop(),
"metric": int(r.get_metric()),
}
for r in route_list_new
]
self.assertEqual(route_list_exp, route_list_new)
def do_connections_check_invalid(self, input_connections):
self.assertValidationError(ARGS_CONNECTIONS, input_connections)
def do_connections_validate_nm(self, input_connections, **kwargs):
if not nmutil:
return
connections = ARGS_CONNECTIONS.validate(input_connections)
for connection in connections:
if "type" in connection:
connection["nm.exists"] = False
connection["nm.uuid"] = Util.create_uuid()
mode = VALIDATE_ONE_MODE_NM
for idx, connection in enumerate(connections):
try:
ARGS_CONNECTIONS.validate_connection_one(mode, connections, idx)
except ValidationError:
continue
if "type" in connection:
con_new = nmutil.connection_create(connections, idx)
self.assertTrue(con_new)
self.assertTrue(con_new.verify())
if "nm_route_list_current" in kwargs:
parser = network_lsr.argument_validator.ArgValidatorIPRoute(
"route[?]"
)
s4 = con_new.get_setting(NM.SettingIP4Config)
s6 = con_new.get_setting(NM.SettingIP6Config)
s4.clear_routes()
s6.clear_routes()
for r in kwargs["nm_route_list_current"][idx]:
r = parser.validate(r)
r = NM.IPRoute.new(
r["family"],
r["network"],
r["prefix"],
r["gateway"],
r["metric"],
)
if r.get_family() == socket.AF_INET:
s4.add_route(r)
else:
s6.add_route(r)
con_new = nmutil.connection_create(
connections, idx, connection_current=con_new
)
self.assertTrue(con_new)
self.assertTrue(con_new.verify())
if "nm_route_list_expected" in kwargs:
self.assert_nm_connection_routes_expected(
con_new, kwargs["nm_route_list_expected"][idx]
)
def do_connections_validate_ifcfg(self, input_connections, **kwargs):
mode = VALIDATE_ONE_MODE_INITSCRIPTS
connections = ARGS_CONNECTIONS.validate(input_connections)
for idx, connection in enumerate(connections):
try:
ARGS_CONNECTIONS.validate_connection_one(mode, connections, idx)
except ValidationError:
continue
if "type" not in connection:
continue
if (
connection["type"] in ["macvlan", "wireless"]
or connection["ieee802_1x"]
):
# initscripts do not support this type. Skip the test.
continue
content_current = kwargs.get("initscripts_content_current", None)
if content_current:
content_current = content_current[idx]
c = IfcfgUtil.ifcfg_create(
connections, idx, content_current=content_current
)
# pprint("con[%s] = \"%s\"" % (idx, connections[idx]['name']), c)
exp = kwargs.get("initscripts_dict_expected", None)
if exp is not None:
self.assertEqual(exp[idx], c)
def do_connections_validate(
self, expected_connections, input_connections, **kwargs
):
connections = ARGS_CONNECTIONS.validate(input_connections)
self.assertEqual(expected_connections, connections)
self.do_connections_validate_nm(input_connections, **kwargs)
self.do_connections_validate_ifcfg(input_connections, **kwargs)
def test_validate_str(self):
v = network_lsr.argument_validator.ArgValidatorStr("state")
self.assertEqual("a", v.validate("a"))
self.assertValidationError(v, 1)
self.assertValidationError(v, None)
v = network_lsr.argument_validator.ArgValidatorStr("state", required=True)
self.assertValidationError(v, None)
v = network_lsr.argument_validator.ArgValidatorStr(
"test_max_length", max_length=13
)
self.assertEqual("less_than_13", v.validate("less_than_13"))
self.assertValidationError(v, "longer_than_13")
v = network_lsr.argument_validator.ArgValidatorStr(
"test_min_length", min_length=13
)
self.assertEqual("longer_than_13", v.validate("longer_than_13"))
self.assertValidationError(v, "less_than_13")
v = network_lsr.argument_validator.ArgValidatorStr(
"test_min_max_length", min_length=10, max_length=15
)
self.assertEqual("13_characters", v.validate("13_characters"))
self.assertValidationError(v, "too_short")
self.assertValidationError(v, "string_is_too_long")
self.assertRaises(
ValueError,
network_lsr.argument_validator.ArgValidatorStr,
"non_int",
min_length="string",
)
self.assertRaises(
ValueError,
network_lsr.argument_validator.ArgValidatorStr,
"non_int",
max_length="string",
)
self.assertRaises(
ValueError,
network_lsr.argument_validator.ArgValidatorStr,
"negative_int",
min_length=-5,
)
self.assertRaises(
ValueError,
network_lsr.argument_validator.ArgValidatorStr,
"negative_int",
max_length=-5,
)
def test_validate_int(self):
v = network_lsr.argument_validator.ArgValidatorNum(
"state", default_value=None, numeric_type=float
)
self.assertEqual(1, v.validate(1))
self.assertEqual(1.5, v.validate(1.5))
self.assertEqual(1.5, v.validate("1.5"))
self.assertValidationError(v, None)
self.assertValidationError(v, "1a")
v = network_lsr.argument_validator.ArgValidatorNum("state", default_value=None)
self.assertEqual(1, v.validate(1))
self.assertEqual(1, v.validate(1.0))
self.assertEqual(1, v.validate("1"))
self.assertValidationError(v, None)
self.assertValidationError(v, None)
self.assertValidationError(v, 1.5)
self.assertValidationError(v, "1.5")
v = network_lsr.argument_validator.ArgValidatorNum("state", required=True)
self.assertValidationError(v, None)
def test_validate_bool(self):
v = network_lsr.argument_validator.ArgValidatorBool("state")
self.assertEqual(True, v.validate("yes"))
self.assertEqual(True, v.validate("yeS"))
self.assertEqual(True, v.validate("Y"))
self.assertEqual(True, v.validate(True))
self.assertEqual(True, v.validate("True"))
self.assertEqual(True, v.validate("1"))
self.assertEqual(True, v.validate(1))
self.assertEqual(False, v.validate("no"))
self.assertEqual(False, v.validate("nO"))
self.assertEqual(False, v.validate("N"))
self.assertEqual(False, v.validate(False))
self.assertEqual(False, v.validate("False"))
self.assertEqual(False, v.validate("0"))
self.assertEqual(False, v.validate(0))
self.assertValidationError(v, 2)
self.assertValidationError(v, -1)
self.assertValidationError(v, "Ye")
self.assertValidationError(v, "")
self.assertValidationError(v, None)
v = network_lsr.argument_validator.ArgValidatorBool("state", required=True)
self.assertValidationError(v, None)
def test_validate_dict(self):
v = network_lsr.argument_validator.ArgValidatorDict(
"dict",
nested=[
network_lsr.argument_validator.ArgValidatorNum("i", required=True),
network_lsr.argument_validator.ArgValidatorStr(
"s", required=False, default_value="s_default"
),
network_lsr.argument_validator.ArgValidatorStr(
"l",
required=False,
default_value=network_lsr.argument_validator.ArgValidator.MISSING,
),
],
)
self.assertEqual({"i": 5, "s": "s_default"}, v.validate({"i": "5"}))
self.assertEqual(
{"i": 5, "s": "s_default", "l": "6"}, v.validate({"i": "5", "l": "6"})
)
self.assertValidationError(v, {"k": 1})
def test_validate_list(self):
v = network_lsr.argument_validator.ArgValidatorList(
"list", nested=network_lsr.argument_validator.ArgValidatorNum("i")
)
self.assertEqual([1, 5], v.validate(["1", 5]))
self.assertValidationError(v, [1, "s"])
def test_empty(self):
self.maxDiff = None
self.do_connections_validate([], [])
def test_ethernet_two_defaults(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present"],
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"ignore_errors": None,
"interface_name": "5",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "5",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": None,
"type": "ethernet",
"zone": None,
},
{
"actions": ["present"],
"ignore_errors": None,
"name": "5",
"persistent_state": "present",
"state": None,
},
],
[{"name": "5", "type": "ethernet"}, {"name": "5"}],
)
def test_up_ethernet(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": "5",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "5",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[{"name": "5", "state": "up", "type": "ethernet"}],
)
def test_up_ethernet_no_autoconnect(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": False,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "5",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "5",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[{"name": "5", "state": "up", "type": "ethernet", "autoconnect": "no"}],
initscripts_dict_expected=[
{
"ifcfg": {
"BOOTPROTO": "dhcp",
"IPV6INIT": "yes",
"IPV6_AUTOCONF": "yes",
"NM_CONTROLLED": "no",
"ONBOOT": "no",
"TYPE": "Ethernet",
"DEVICE": "5",
},
"keys": None,
"route": None,
"route6": None,
"rule": None,
"rule6": None,
}
],
)
def test_invalid_autoconnect(self):
self.maxDiff = None
self.do_connections_check_invalid([{"name": "a", "autoconnect": True}])
def test_absent(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["absent"],
"ignore_errors": None,
"name": "5",
"persistent_state": "absent",
"state": None,
}
],
[{"name": "5", "persistent_state": "absent"}],
)
def test_up_ethernet_mac_mtu_static_ip(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": None,
"ip": {
"dhcp4": False,
"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": [
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.174.5",
}
],
"route_append_only": False,
"rule_append_only": False,
"route": [],
},
"mac": "52:54:00:44:9f:ba",
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": 1450,
"name": "prod1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[
{
"name": "prod1",
"state": "up",
"type": "ethernet",
"autoconnect": "yes",
"mac": "52:54:00:44:9f:ba",
"mtu": 1450,
"ip": {"address": "192.168.174.5/24"},
}
],
)
def test_up_single_v4_dns(self):
self.maxDiff = None
# set single IPv4 DNS server
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": False,
"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": "192.168.174.1", "family": socket.AF_INET}],
"address": [
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.174.5",
}
],
"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",
"autoconnect": "yes",
"ip": {"address": "192.168.174.5/24", "dns": "192.168.174.1"},
}
],
)
def test_ipv6_static(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": {
"gateway6": "2001:db8::1",
"gateway4": None,
"route_metric4": None,
"auto6": False,
"ipv6_disabled": False,
"dhcp4": False,
"address": [
{
"address": "2001:db8::2",
"family": socket.AF_INET6,
"prefix": 32,
},
{
"address": "2001:db8::3",
"family": socket.AF_INET6,
"prefix": 32,
},
{
"address": "2001:db8::4",
"family": socket.AF_INET6,
"prefix": 32,
},
],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"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": {
"dhcp4": "no",
"auto6": "no",
"address": [
"2001:db8::2/32",
"2001:db8::3/32",
"2001:db8::4/32",
],
"gateway6": "2001:db8::1",
},
}
],
initscripts_dict_expected=[
{
"ifcfg": {
"BOOTPROTO": "none",
"IPV6INIT": "yes",
"IPV6_AUTOCONF": "no",
"IPV6ADDR": "2001:db8::2/32",
"IPV6ADDR_SECONDARIES": "2001:db8::3/32 2001:db8::4/32",
"IPV6_DEFAULTGW": "2001:db8::1",
"NM_CONTROLLED": "no",
"ONBOOT": "yes",
"TYPE": "Ethernet",
"DEVICE": "prod1",
},
"keys": None,
"route": None,
"route6": None,
"rule": None,
"rule6": None,
}
],
)
def test_routes(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": None,
"ip": {
"dhcp4": False,
"auto6": True,
"ipv6_disabled": False,
"address": [
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.176.5",
},
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.177.5",
},
],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
"gateway4": None,
"dns": [],
},
"mac": "52:54:00:44:9f:ba",
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": 1450,
"name": "prod1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
},
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "prod.100",
"ip": {
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
"gateway4": None,
"auto6": False,
"ipv6_disabled": False,
"dns": [],
"address": [
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.174.5",
},
{
"prefix": 65,
"family": socket.AF_INET6,
"address": "a:b:c::6",
},
],
"route_append_only": False,
"rule_append_only": False,
"route": [
{
"family": socket.AF_INET,
"network": "192.168.5.0",
"prefix": 24,
"gateway": None,
"metric": -1,
}
],
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "prod.100",
"parent": "prod1",
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "vlan",
"vlan": {"id": 100},
"wait": None,
"zone": None,
},
],
[
{
"name": "prod1",
"state": "up",
"type": "ethernet",
"autoconnect": "yes",
"mac": "52:54:00:44:9f:ba",
"mtu": 1450,
"ip": {"address": "192.168.176.5/24 192.168.177.5/24"},
},
{
"name": "prod.100",
"state": "up",
"type": "vlan",
"parent": "prod1",
"vlan": {"id": "100"},
"ip": {
"address": [
"192.168.174.5/24",
{"address": "a:b:c::6", "prefix": 65},
],
"route_append_only": False,
"rule_append_only": False,
"route": [{"network": "192.168.5.0"}],
},
},
],
)
def test_vlan(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": None,
"ip": {
"dhcp4": False,
"auto6": True,
"address": [
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.176.5",
},
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.177.5",
},
],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
"gateway4": None,
"ipv6_disabled": False,
"dns": [],
},
"mac": "52:54:00:44:9f:ba",
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": 1450,
"name": "prod1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
},
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "prod.100",
"ip": {
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
"gateway4": None,
"ipv6_disabled": False,
"auto6": False,
"dns": [],
"address": [
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.174.5",
},
{
"prefix": 65,
"family": socket.AF_INET6,
"address": "a:b:c::6",
},
],
"route_append_only": False,
"rule_append_only": False,
"route": [
{
"family": socket.AF_INET,
"network": "192.168.5.0",
"prefix": 24,
"gateway": None,
"metric": -1,
}
],
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "prod.100",
"parent": "prod1",
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "vlan",
"vlan": {"id": 101},
"wait": None,
"zone": None,
},
],
[
{
"name": "prod1",
"state": "up",
"type": "ethernet",
"autoconnect": "yes",
"mac": "52:54:00:44:9f:ba",
"mtu": 1450,
"ip": {"address": "192.168.176.5/24 192.168.177.5/24"},
},
{
"name": "prod.100",
"state": "up",
"type": "vlan",
"parent": "prod1",
"vlan_id": 101,
"ip": {
"address": [
"192.168.174.5/24",
{"address": "a:b:c::6", "prefix": 65},
],
"route_append_only": False,
"rule_append_only": False,
"route": [{"network": "192.168.5.0"}],
},
},
],
)
def test_macvlan(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": "eth0",
"ip": {
"dhcp4": False,
"auto6": False,
"address": [
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.122.3",
}
],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"ipv6_disabled": False,
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
"gateway4": None,
"dns": [],
},
"mac": "33:24:10:24:2f:b9",
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": 1450,
"name": "eth0-parent",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
},
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "veth0",
"ip": {
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"ipv6_disabled": False,
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
"gateway4": None,
"auto6": False,
"dns": [],
"address": [
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.244.1",
}
],
"route_append_only": False,
"rule_append_only": False,
"route": [
{
"family": socket.AF_INET,
"network": "192.168.244.0",
"prefix": 24,
"gateway": None,
"metric": -1,
}
],
},
"mac": None,
"macvlan": {"mode": "bridge", "promiscuous": True, "tap": False},
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "veth0.0",
"parent": "eth0-parent",
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "macvlan",
"wait": None,
"zone": None,
},
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "veth1",
"ip": {
"dhcp4": False,
"route_metric6": None,
"route_metric4": None,
"dns_options": [],
"dns_search": [],
"dhcp4_send_hostname": None,
"gateway6": None,
"gateway4": None,
"ipv6_disabled": False,
"auto6": False,
"dns": [],
"address": [
{
"prefix": 24,
"family": socket.AF_INET,
"address": "192.168.245.7",
}
],
"route_append_only": False,
"rule_append_only": False,
"route": [
{
"family": socket.AF_INET,
"network": "192.168.245.0",
"prefix": 24,
"gateway": None,
"metric": -1,
}
],
},
"mac": None,
"macvlan": {"mode": "passthru", "promiscuous": False, "tap": True},
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "veth0.1",
"parent": "eth0-parent",
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "macvlan",
"wait": None,
"zone": None,
},
],
[
{
"name": "eth0-parent",
"state": "up",
"type": "ethernet",
"autoconnect": "yes",
"interface_name": "eth0",
"mac": "33:24:10:24:2f:b9",
"mtu": 1450,
"ip": {"address": "192.168.122.3/24", "auto6": False},
},
{
"name": "veth0.0",
"state": "up",
"type": "macvlan",
"parent": "eth0-parent",
"interface_name": "veth0",
"macvlan": {"mode": "bridge", "promiscuous": True, "tap": False},
"ip": {
"address": "192.168.244.1/24",
"auto6": False,
"route_append_only": False,
"rule_append_only": False,
"route": [{"network": "192.168.244.0"}],
},
},
{
"name": "veth0.1",
"state": "up",
"type": "macvlan",
"parent": "eth0-parent",
"interface_name": "veth1",
"macvlan": {"mode": "passthru", "promiscuous": False, "tap": True},
"ip": {
"address": "192.168.245.7/24",
"auto6": False,
"route_append_only": False,
"rule_append_only": False,
"route": [{"network": "192.168.245.0"}],
},
},
],
)
def test_bridge_no_dhcp4_auto6(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": "bridge2",
"ip": {
"address": [],
"auto6": False,
"dhcp4": False,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
"ipv6_disabled": False,
"route": [],
"route_append_only": False,
"route_metric4": None,
"route_metric6": None,
"rule_append_only": False,
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "prod2",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "bridge",
"wait": None,
"zone": None,
},
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "eth1",
"ip": {
"address": [],
"auto6": True,
"dhcp4": True,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
"ipv6_disabled": False,
"route": [],
"route_append_only": False,
"route_metric4": None,
"route_metric6": None,
"rule_append_only": False,
},
"mac": None,
"controller": "prod2",
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "prod2-port1",
"parent": None,
"persistent_state": "present",
"port_type": "bridge",
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
},
],
[
{
"name": "prod2",
"state": "up",
"type": "bridge",
"interface_name": "bridge2",
"ip": {"dhcp4": False, "auto6": False},
},
{
"name": "prod2-port1",
"state": "up",
"type": "ethernet",
"interface_name": "eth1",
"controller": "prod2",
},
],
)
def test_bond(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": True,
"bond": {"mode": "balance-rr", "miimon": None},
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "bond1",
"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": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "bond1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "bond",
"wait": None,
"zone": None,
}
],
[{"name": "bond1", "state": "up", "type": "bond"}],
)
def test_bond_active_backup(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": True,
"bond": {"mode": "active-backup", "miimon": None},
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "bond1",
"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": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "bond1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "bond",
"wait": None,
"zone": None,
}
],
[
{
"name": "bond1",
"state": "up",
"type": "bond",
"bond": {"mode": "active-backup"},
}
],
)
def test_invalid_values(self):
self.maxDiff = None
self.do_connections_check_invalid([{}])
self.do_connections_check_invalid([{"name": "b", "xxx": 5}])
def test_ethernet_mac_address(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present"],
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"ignore_errors": None,
"interface_name": None,
"ip": {
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"dhcp4_send_hostname": None,
"gateway4": None,
"gateway6": None,
"route_metric4": None,
"route_metric6": None,
"dns": [],
"dns_options": [],
"dns_search": [],
},
"mac": "aa:bb:cc:dd:ee:ff",
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "5",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": None,
"type": "ethernet",
"zone": None,
}
],
[{"name": "5", "type": "ethernet", "mac": "AA:bb:cC:DD:ee:FF"}],
)
def test_ethernet_speed_settings(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethernet": {"autoneg": False, "duplex": "half", "speed": 400},
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "5",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "5",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[
{
"name": "5",
"state": "up",
"type": "ethernet",
"ip": {},
"ethernet": {"duplex": "half", "speed": 400},
}
],
initscripts_dict_expected=[
{
"ifcfg": {
"BOOTPROTO": "dhcp",
"ETHTOOL_OPTS": "autoneg off speed 400 duplex half",
"IPV6INIT": "yes",
"IPV6_AUTOCONF": "yes",
"NM_CONTROLLED": "no",
"ONBOOT": "yes",
"TYPE": "Ethernet",
"DEVICE": "5",
},
"keys": None,
"route": None,
"route6": None,
"rule": None,
"rule6": None,
}
],
)
def test_bridge2(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": "6643-controller",
"ip": {
"address": [],
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
"route": [],
"route_append_only": False,
"route_metric4": None,
"route_metric6": None,
"rule_append_only": False,
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "6643-controller",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "bridge",
"wait": None,
"zone": None,
},
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethernet": ETHERNET_DEFAULTS,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "6643",
"ip": {
"address": [],
"auto6": True,
"dhcp4_send_hostname": None,
"dhcp4": True,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
"ipv6_disabled": False,
"route": [],
"route_append_only": False,
"route_metric4": None,
"route_metric6": None,
"rule_append_only": False,
},
"mac": None,
"controller": "6643-controller",
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "6643",
"parent": None,
"persistent_state": "present",
"port_type": "bridge",
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
},
],
[
{"name": "6643-controller", "state": "up", "type": "bridge"},
{
"name": "6643",
"state": "up",
"type": "ethernet",
"controller": "6643-controller",
},
],
)
def test_infiniband(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"infiniband": {"p_key": -1, "transport_mode": "datagram"},
"interface_name": None,
"ip": {
"address": [],
"auto6": True,
"dhcp4": True,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
"ipv6_disabled": False,
"route": [],
"route_append_only": False,
"route_metric4": None,
"route_metric6": None,
"rule_append_only": False,
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "infiniband.1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "infiniband",
"wait": None,
"zone": None,
}
],
[
{
"name": "infiniband.1",
"interface_name": "",
"state": "up",
"type": "infiniband",
}
],
initscripts_dict_expected=[
{
"ifcfg": {
"BOOTPROTO": "dhcp",
"CONNECTED_MODE": "no",
"IPV6INIT": "yes",
"IPV6_AUTOCONF": "yes",
"NM_CONTROLLED": "no",
"ONBOOT": "yes",
"TYPE": "InfiniBand",
},
"keys": None,
"route": None,
"route6": None,
"rule": None,
"rule6": None,
}
],
)
def test_infiniband2(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"infiniband": {"p_key": 5, "transport_mode": "datagram"},
"interface_name": None,
"ip": {
"address": [],
"auto6": True,
"dhcp4": True,
"dhcp4_send_hostname": None,
"dns": [],
"dns_options": [],
"dns_search": [],
"gateway4": None,
"gateway6": None,
"ipv6_disabled": False,
"route": [],
"route_append_only": False,
"route_metric4": None,
"route_metric6": None,
"rule_append_only": False,
},
"mac": "11:22:33:44:55:66:77:88:99:00:"
"11:22:33:44:55:66:77:88:99:00",
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "infiniband.2",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "infiniband",
"wait": None,
"zone": None,
}
],
[
{
"name": "infiniband.2",
"state": "up",
"type": "infiniband",
"mac": "11:22:33:44:55:66:77:88:99:00:"
"11:22:33:44:55:66:77:88:99:00",
"infiniband_p_key": 5,
}
],
initscripts_dict_expected=[
{
"ifcfg": {
"BOOTPROTO": "dhcp",
"CONNECTED_MODE": "no",
"HWADDR": "11:22:33:44:55:66:77:88:99:00:"
"11:22:33:44:55:66:77:88:99:00",
"IPV6INIT": "yes",
"IPV6_AUTOCONF": "yes",
"NM_CONTROLLED": "no",
"ONBOOT": "yes",
"PKEY": "yes",
"PKEY_ID": "5",
"TYPE": "InfiniBand",
},
"keys": None,
"route": None,
"route6": None,
"rule": None,
"rule6": None,
}
],
)
def test_route_metric_prefix(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": "555",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [
{
"family": socket.AF_INET,
"network": "192.168.45.0",
"prefix": 24,
"gateway": None,
"metric": 545,
},
{
"family": socket.AF_INET,
"network": "192.168.46.0",
"prefix": 30,
"gateway": None,
"metric": -1,
},
],
"dns": [],
"dns_options": [],
"dns_search": ["aa", "bb"],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "555",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[
{
"name": "555",
"state": "up",
"type": "ethernet",
"ip": {
"dns_search": ["aa", "bb"],
"route": [
{"network": "192.168.45.0", "metric": 545},
{"network": "192.168.46.0", "prefix": 30},
],
},
}
],
initscripts_dict_expected=[
{
"ifcfg": {
"BOOTPROTO": "dhcp",
"DOMAIN": "aa bb",
"IPV6INIT": "yes",
"IPV6_AUTOCONF": "yes",
"NM_CONTROLLED": "no",
"ONBOOT": "yes",
"TYPE": "Ethernet",
"DEVICE": "555",
},
"keys": None,
"route": "192.168.45.0/24 metric 545\n192.168.46.0/30\n",
"route6": None,
"rule": None,
"rule6": None,
}
],
)
def test_route_v6(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": "e556",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": True,
"rule_append_only": False,
"route": [
{
"family": socket.AF_INET,
"network": "192.168.45.0",
"prefix": 24,
"gateway": None,
"metric": 545,
},
{
"family": socket.AF_INET,
"network": "192.168.46.0",
"prefix": 30,
"gateway": None,
"metric": -1,
},
{
"family": socket.AF_INET6,
"network": "a:b:c:d::",
"prefix": 64,
"gateway": None,
"metric": -1,
},
],
"dns": [],
"dns_options": [],
"dns_search": ["aa", "bb"],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": None,
"mtu": None,
"name": "e556",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": "external",
}
],
[
{
"name": "e556",
"state": "up",
"type": "ethernet",
"zone": "external",
"ip": {
"dns_search": ["aa", "bb"],
"route_append_only": True,
"rule_append_only": False,
"route": [
{"network": "192.168.45.0", "metric": 545},
{"network": "192.168.46.0", "prefix": 30},
{"network": "a:b:c:d::"},
],
},
}
],
nm_route_list_current=[
[
{"network": "192.168.40.0", "prefix": 24, "metric": 545},
{"network": "192.168.46.0", "prefix": 30},
{"network": "a:b:c:f::"},
]
],
nm_route_list_expected=[
[
{"network": "192.168.40.0", "prefix": 24, "metric": 545},
{"network": "192.168.46.0", "prefix": 30},
{"network": "192.168.45.0", "prefix": 24, "metric": 545},
{"network": "a:b:c:f::"},
{"network": "a:b:c:d::"},
]
],
initscripts_content_current=[
{
"ifcfg": "",
"keys": None,
"route": "192.168.40.0/24 metric 545\n192.168.46.0/30",
"route6": "a:b:c:f::/64",
"rule": None,
"rule6": None,
}
],
initscripts_dict_expected=[
{
"ifcfg": {
"BOOTPROTO": "dhcp",
"DOMAIN": "aa bb",
"IPV6INIT": "yes",
"IPV6_AUTOCONF": "yes",
"NM_CONTROLLED": "no",
"ONBOOT": "yes",
"TYPE": "Ethernet",
"ZONE": "external",
"DEVICE": "e556",
},
"keys": None,
"route": "192.168.40.0/24 metric 545\n192.168.46.0/30\n"
"192.168.45.0/24 metric 545\n",
"route6": "a:b:c:f::/64\na:b:c:d::/64\n",
"rule": None,
"rule6": None,
}
],
)
def test_802_1x_1(self):
"""
Test private key with password
"""
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": "eth0",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"private_key_password": "p@55w0rD",
"private_key_password_flags": None,
"client_cert": "/etc/pki/tls/client.pem",
"ca_cert": "/etc/pki/tls/cacert.pem",
"ca_path": None,
"system_ca_certs": False,
"domain_suffix_match": None,
},
"wireless": None,
"mtu": None,
"name": "eth0",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[
{
"name": "eth0",
"state": "up",
"type": "ethernet",
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"private_key_password": "p@55w0rD",
"client_cert": "/etc/pki/tls/client.pem",
"ca_cert": "/etc/pki/tls/cacert.pem",
},
}
],
)
def test_802_1x_2(self):
"""
Test 802.1x profile with unencrypted private key,
domain suffix match, and system ca certs
"""
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": "eth0",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"private_key_password": None,
"private_key_password_flags": ["not-required"],
"client_cert": "/etc/pki/tls/client.pem",
"ca_cert": None,
"ca_path": None,
"system_ca_certs": True,
"domain_suffix_match": "example.com",
},
"wireless": None,
"mtu": None,
"name": "eth0",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[
{
"name": "eth0",
"state": "up",
"type": "ethernet",
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"client_cert": "/etc/pki/tls/client.pem",
"private_key_password_flags": ["not-required"],
"system_ca_certs": True,
"domain_suffix_match": "example.com",
},
}
],
)
def test_802_1x_3(self):
"""
Test 802.1x profile with unencrypted private key and ca_path
"""
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": "eth0",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"private_key_password": None,
"private_key_password_flags": ["not-required"],
"client_cert": "/etc/pki/tls/client.pem",
"ca_cert": None,
"ca_path": "/etc/pki/tls/my_ca_certs",
"system_ca_certs": False,
"domain_suffix_match": None,
},
"wireless": None,
"mtu": None,
"name": "eth0",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "ethernet",
"wait": None,
"zone": None,
}
],
[
{
"name": "eth0",
"state": "up",
"type": "ethernet",
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"client_cert": "/etc/pki/tls/client.pem",
"private_key_password_flags": ["not-required"],
"ca_path": "/etc/pki/tls/my_ca_certs",
},
}
],
)
def test_wireless_psk(self):
"""
Test wireless connection with wpa-psk auth
"""
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "wireless1",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": None,
"wireless": {
"ssid": "test wireless network",
"key_mgmt": "wpa-psk",
"password": "p@55w0rD",
},
"mtu": None,
"name": "wireless1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "wireless",
"wait": None,
"zone": None,
}
],
[
{
"name": "wireless1",
"state": "up",
"type": "wireless",
"wireless": {
"ssid": "test wireless network",
"key_mgmt": "wpa-psk",
"password": "p@55w0rD",
},
}
],
)
def test_wireless_eap(self):
"""
Test wireless connection with wpa-eap
"""
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present", "up"],
"autoconnect": True,
"check_iface_exists": True,
"ethtool": ETHTOOL_DEFAULTS,
"force_state_change": None,
"ignore_errors": None,
"interface_name": "wireless1",
"ip": {
"gateway6": None,
"gateway4": None,
"route_metric4": None,
"auto6": True,
"ipv6_disabled": False,
"dhcp4": True,
"address": [],
"route_append_only": False,
"rule_append_only": False,
"route": [],
"dns": [],
"dns_options": [],
"dns_search": [],
"route_metric6": None,
"dhcp4_send_hostname": None,
},
"mac": None,
"controller": None,
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"private_key_password": "p@55w0rD",
"private_key_password_flags": None,
"client_cert": "/etc/pki/tls/client.pem",
"ca_cert": "/etc/pki/tls/cacert.pem",
"ca_path": None,
"system_ca_certs": False,
"domain_suffix_match": None,
},
"wireless": {
"ssid": "test wireless network",
"password": None,
"key_mgmt": "wpa-eap",
},
"mtu": None,
"name": "wireless1",
"parent": None,
"persistent_state": "present",
"port_type": None,
"state": "up",
"type": "wireless",
"wait": None,
"zone": None,
}
],
[
{
"name": "wireless1",
"state": "up",
"type": "wireless",
"wireless": {
"ssid": "test wireless network",
"key_mgmt": "wpa-eap",
},
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"private_key_password": "p@55w0rD",
"client_cert": "/etc/pki/tls/client.pem",
"ca_cert": "/etc/pki/tls/cacert.pem",
},
}
],
)
def test_invalid_cert_path(self):
"""
should fail if a relative path is used for 802.1x certs/keys
"""
self.maxDiff = None
self.do_connections_check_invalid(
[
{
"name": "eth0",
"state": "up",
"type": "ethernet",
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "client.key",
"client_cert": "client.pem",
"private_key_password_flags": ["not-required"],
"system_ca_certs": True,
},
}
]
)
def test_invalid_password_flag(self):
"""
should fail if an invalid private key password flag is set
"""
self.maxDiff = None
self.do_connections_check_invalid(
[
{
"name": "eth0",
"state": "up",
"type": "ethernet",
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"client_cert": "/etc/pki/tls/client.pem",
"private_key_password_flags": ["bad-flag"],
"system_ca_certs": True,
},
}
]
)
def test_802_1x_ca_path_and_system_ca_certs(self):
"""
should fail if ca_path and system_ca_certs are used together
"""
self.maxDiff = None
self.do_connections_check_invalid(
[
{
"name": "eth0",
"state": "up",
"type": "ethernet",
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"client_cert": "/etc/pki/tls/client.pem",
"private_key_password_flags": ["not-required"],
"ca_path": "/etc/pki/my_ca_certs",
"system_ca_certs": True,
},
}
]
)
def test_802_1x_initscripts(self):
"""
should fail to create ieee802_1x connection with initscripts
"""
input_connections = [
{
"name": "eth0",
"state": "up",
"type": "ethernet",
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"client_cert": "/etc/pki/tls/client.pem",
"private_key_password_flags": ["not-required"],
"system_ca_certs": True,
},
}
]
connections = ARGS_CONNECTIONS.validate(input_connections)
self.assertRaises(
ValidationError,
ARGS_CONNECTIONS.validate_connection_one,
VALIDATE_ONE_MODE_INITSCRIPTS,
connections,
0,
)
def test_802_1x_unsupported_type(self):
"""
should fail if a non ethernet/wireless connection has 802.1x settings defined
"""
self.do_connections_check_invalid(
[
{
"name": "bond0",
"state": "up",
"type": "bond",
"ieee802_1x": {
"identity": "myhost",
"eap": "tls",
"private_key": "/etc/pki/tls/client.key",
"client_cert": "/etc/pki/tls/client.pem",
"private_key_password_flags": ["not-required"],
"system_ca_certs": True,
},
}
]
)
def test_wireless_initscripts(self):
"""
should fail to create wireless connection with initscripts
"""
input_connections = [
{
"name": "wireless1",
"state": "up",
"type": "wireless",
"wireless": {
"ssid": "test wireless network",
"key_mgmt": "wpa-psk",
"password": "p@55w0rD",
},
}
]
connections = ARGS_CONNECTIONS.validate(input_connections)
self.assertRaises(
ValidationError,
ARGS_CONNECTIONS.validate_connection_one,
VALIDATE_ONE_MODE_INITSCRIPTS,
connections,
0,
)
def test_wireless_unsupported_type(self):
"""
should fail if a non wireless connection has wireless settings defined
"""
self.do_connections_check_invalid(
[
{
"name": "wireless-bond",
"state": "up",
"type": "bond",
"wireless": {
"ssid": "test wireless network",
"key_mgmt": "wpa-psk",
"password": "p@55w0rD",
},
}
]
)
def test_wireless_ssid_too_long(self):
"""
should fail if ssid longer than 32 bytes
"""
self.do_connections_check_invalid(
[
{
"name": "wireless1",
"state": "up",
"type": "wireless",
"wireless": {
"ssid": "test wireless network with ssid too long",
"key_mgmt": "wpa-psk",
"password": "p@55w0rD",
},
}
]
)
def test_wireless_no_password(self):
"""
should fail if wpa-psk is selected and no password provided
"""
self.do_connections_check_invalid(
[
{
"name": "wireless1",
"state": "up",
"type": "wireless",
"wireless": {
"ssid": "test wireless network",
"key_mgmt": "wpa-psk",
},
}
]
)
def test_wireless_password_too_long(self):
"""
should fail if wpa-psk is selected and no password provided
"""
self.do_connections_check_invalid(
[
{
"name": "wireless1",
"state": "up",
"type": "wireless",
"wireless": {
"ssid": "test wireless network",
"key_mgmt": "wpa-psk",
"password": "This password is too long and should "
"not be able to validate properly",
},
}
]
)
def test_wireless_no_802_1x_for_wpa_eap(self):
"""
should fail if no 802.1x parameters are defined for a wireless
connection with key_mgmt=wpa-eap
"""
self.do_connections_check_invalid(
[
{
"name": "wireless1",
"state": "up",
"type": "wireless",
"wireless": {
"ssid": "test wireless network",
"key_mgmt": "wpa-eap",
},
}
]
)
def test_wireless_no_options_defined(self):
"""
should fail if a connection of type='wireless' does not
have any 'wireless' settings defined
"""
self.do_connections_check_invalid(
[{"name": "wireless1", "state": "up", "type": "wireless"}]
)
def test_invalid_mac(self):
self.maxDiff = None
self.do_connections_check_invalid(
[{"name": "b", "type": "ethernet", "mac": "aa:b"}]
)
def test_interface_name_ethernet_default(self):
""" Use the profile name as interface_name for ethernet profiles """
cons_without_interface_name = [{"name": "eth0", "type": "ethernet"}]
connections = ARGS_CONNECTIONS.validate(cons_without_interface_name)
self.assertTrue(connections[0]["interface_name"] == "eth0")
def test_interface_name_ethernet_mac(self):
""" Do not set interface_name when mac is specified """
cons_without_interface_name = [
{"name": "eth0", "type": "ethernet", "mac": "3b:0b:88:16:6d:1a"}
]
connections = ARGS_CONNECTIONS.validate(cons_without_interface_name)
self.assertTrue(connections[0]["interface_name"] is None)
def test_interface_name_ethernet_empty(self):
""" Allow not to restrict the profile to an interface """
network_connections = [
{"name": "internal_network", "type": "ethernet", "interface_name": ""}
]
connections = ARGS_CONNECTIONS.validate(network_connections)
self.assertTrue(connections[0]["interface_name"] is None)
def test_interface_name_ethernet_None(self):
""" Check that interface_name cannot be None """
network_connections = [
{"name": "internal_network", "type": "ethernet", "interface_name": None}
]
self.assertRaises(
ValidationError, ARGS_CONNECTIONS.validate, network_connections
)
def test_interface_name_ethernet_explicit(self):
""" Use the explicitly provided interface name """
network_connections = [
{"name": "internal", "type": "ethernet", "interface_name": "eth0"}
]
connections = ARGS_CONNECTIONS.validate(network_connections)
self.assertEqual(connections[0]["interface_name"], "eth0")
def test_interface_name_ethernet_invalid_profile(self):
"""Require explicit interface_name when the profile name is not a
valid interface_name"""
network_connections = [{"name": "internal:main", "type": "ethernet"}]
self.assertRaises(
ValidationError, ARGS_CONNECTIONS.validate, network_connections
)
network_connections = [
{"name": "internal:main", "type": "ethernet", "interface_name": "eth0"}
]
connections = ARGS_CONNECTIONS.validate(network_connections)
self.assertTrue(connections[0]["interface_name"] == "eth0")
def test_interface_name_ethernet_invalid_interface_name(self):
network_connections = [
{"name": "internal", "type": "ethernet", "interface_name": "invalid:name"}
]
self.assertRaises(
ValidationError, ARGS_CONNECTIONS.validate, network_connections
)
def test_interface_name_bond_empty_interface_name(self):
network_connections = [
{"name": "internal", "type": "bond", "interface_name": "invalid:name"}
]
self.assertRaises(
ValidationError, ARGS_CONNECTIONS.validate, network_connections
)
def test_interface_name_bond_profile_as_interface_name(self):
network_connections = [{"name": "internal", "type": "bond"}]
connections = ARGS_CONNECTIONS.validate(network_connections)
self.assertEqual(connections[0]["interface_name"], "internal")
def check_connection(self, connection, expected):
reduced_connection = {}
for setting in expected:
reduced_connection[setting] = connection[setting]
self.assertEqual(reduced_connection, expected)
def check_partial_connection_zero(self, network_config, expected):
connections = ARGS_CONNECTIONS.validate([network_config])
self.check_connection(connections[0], expected)
def check_one_connection_with_defaults(
self, network_config, expected_changed_settings
):
self.maxDiff = None
expected = self.default_connection_settings
expected.update(expected_changed_settings)
self.do_connections_validate([expected], [network_config])
def test_default_states(self):
self.check_partial_connection_zero(
{"name": "eth0"},
{"actions": ["present"], "persistent_state": "present", "state": None},
)
def test_invalid_persistent_state_up(self):
network_connections = [{"name": "internal", "persistent_state": "up"}]
self.assertRaises(
ValidationError, ARGS_CONNECTIONS.validate, network_connections
)
def test_invalid_persistent_state_down(self):
network_connections = [{"name": "internal", "persistent_state": "down"}]
self.assertRaises(
ValidationError, ARGS_CONNECTIONS.validate, network_connections
)
def test_invalid_state_test(self):
network_connections = [{"name": "internal", "state": "test"}]
self.assertRaises(
ValidationError, ARGS_CONNECTIONS.validate, network_connections
)
def test_default_states_type(self):
self.check_partial_connection_zero(
{"name": "eth0", "type": "ethernet"},
{"actions": ["present"], "persistent_state": "present", "state": None},
)
def test_persistent_state_present(self):
self.check_partial_connection_zero(
{"name": "eth0", "persistent_state": "present", "type": "ethernet"},
{"actions": ["present"], "persistent_state": "present", "state": None},
)
def test_state_present(self):
self.check_partial_connection_zero(
{"name": "eth0", "state": "present", "type": "ethernet"},
{"actions": ["present"], "persistent_state": "present", "state": None},
)
def test_state_absent(self):
self.check_partial_connection_zero(
{"name": "eth0", "state": "absent"},
{"actions": ["absent"], "persistent_state": "absent", "state": None},
)
def test_persistent_state_absent(self):
self.check_partial_connection_zero(
{"name": "eth0", "persistent_state": "absent"},
{"actions": ["absent"], "persistent_state": "absent", "state": None},
)
def test_state_present_up(self):
self.check_partial_connection_zero(
{
"name": "eth0",
"persistent_state": "present",
"state": "up",
"type": "ethernet",
},
{
"actions": ["present", "up"],
"persistent_state": "present",
"state": "up",
},
)
def test_state_present_down(self):
self.check_partial_connection_zero(
{
"name": "eth0",
"persistent_state": "present",
"state": "down",
"type": "ethernet",
},
{
"actions": ["present", "down"],
"persistent_state": "present",
"state": "down",
},
)
def test_state_absent_up_no_type(self):
self.check_partial_connection_zero(
{"name": "eth0", "persistent_state": "absent", "state": "up"},
{"actions": ["absent", "up"], "persistent_state": "absent", "state": "up"},
)
def test_state_absent_up_type(self):
# if type is specified, present should happen, too
self.check_partial_connection_zero(
{
"name": "eth0",
"persistent_state": "absent",
"state": "up",
"type": "ethernet",
},
{
"actions": ["present", "absent", "up"],
"persistent_state": "absent",
"state": "up",
},
)
def test_state_absent_down(self):
# if type is specified, present should happen, too
self.check_partial_connection_zero(
{"name": "eth0", "persistent_state": "absent", "state": "down"},
{
"actions": ["absent", "down"],
"persistent_state": "absent",
"state": "down",
},
)
def test_state_up_no_type(self):
self.check_partial_connection_zero(
{"name": "eth0", "state": "up"},
{
"actions": ["present", "up"],
"persistent_state": "present",
"state": "up",
},
)
def test_state_up_type(self):
self.check_partial_connection_zero(
{"name": "eth0", "state": "up", "type": "ethernet"},
{
"actions": ["present", "up"],
"persistent_state": "present",
"state": "up",
},
)
def test_state_down_no_type(self):
self.check_partial_connection_zero(
{"name": "eth0", "state": "down"},
{
"actions": ["present", "down"],
"persistent_state": "present",
"state": "down",
},
)
def test_full_state_present_no_type(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["present"],
"ignore_errors": None,
"name": "eth0",
"state": None,
"persistent_state": "present",
}
],
[{"name": "eth0", "persistent_state": "present"}],
)
def test_full_state_present_type_defaults(self):
self.check_one_connection_with_defaults(
{"name": "eth0", "type": "ethernet", "persistent_state": "present"},
{
"actions": ["present"],
"interface_name": "eth0",
"name": "eth0",
"persistent_state": "present",
"state": None,
"type": "ethernet",
},
)
def test_full_state_absent_no_type(self):
self.maxDiff = None
self.do_connections_validate(
[
{
"actions": ["absent"],
"ignore_errors": None,
"name": "eth0",
"state": None,
"persistent_state": "absent",
}
],
[{"name": "eth0", "persistent_state": "absent"}],
)
def test_full_state_absent_defaults(self):
self.maxDiff = None
self.check_one_connection_with_defaults(
{"name": "eth0", "persistent_state": "absent", "type": "ethernet"},
{
"actions": ["absent"],
"ignore_errors": None,
"name": "eth0",
"state": None,
"persistent_state": "absent",
"type": "ethernet",
"interface_name": "eth0",
},
)
def _test_ethtool_changes(self, input_ethtool, expected_ethtool):
"""
When passing a dictionary 'input_features' with each feature and their
value to change, and a dictionary 'expected_features' with the expected
result in the configuration, the expected and resulting connection are
created and validated.
"""
expected_ethtool_full = copy.deepcopy(ETHTOOL_DEFAULTS)
for key in list(expected_ethtool_full):
if key in expected_ethtool:
expected_ethtool_full[key].update(expected_ethtool[key])
input_connection = {
"ethtool": input_ethtool,
"name": "5",
"persistent_state": "present",
"type": "ethernet",
}
expected_connection = {
"actions": ["present"],
"ethtool": expected_ethtool_full,
"interface_name": "5",
"persistent_state": "present",
"state": None,
"type": "ethernet",
}
self.check_one_connection_with_defaults(input_connection, expected_connection)
def test_set_ethtool_feature(self):
"""
When passing the name of an non-deprecated ethtool feature, their
current version is updated.
"""
input_ethtool = {"features": {"tx_tcp_segmentation": "yes"}}
expected_ethtool = {"features": {"tx_tcp_segmentation": True}}
self._test_ethtool_changes(input_ethtool, expected_ethtool)
def test_set_deprecated_ethtool_feature(self):
"""
When passing a deprecated name, their current version is updated.
"""
input_ethtool = {"features": {"esp-hw-offload": "yes"}}
expected_ethtool = {"features": {"esp_hw_offload": True}}
self._test_ethtool_changes(input_ethtool, expected_ethtool)
def test_invalid_ethtool_settings(self):
"""
When both the deprecated and current version of a feature are stated,
a Validation Error is raised.
"""
input_features = {"tx-tcp-segmentation": "yes", "tx_tcp_segmentation": "yes"}
features_validator = (
network_lsr.argument_validator.ArgValidator_DictEthtoolFeatures()
)
self.assertValidationError(features_validator, input_features)
def test_deprecated_ethtool_names(self):
"""
Test that for each validator in
ArgValidator_DictEthtoolFeatures.nested there is another non-deprecated
validator that has the name from the deprecated_by attribute"
"""
validators = (
network_lsr.argument_validator.ArgValidator_DictEthtoolFeatures().nested
)
for name, validator in validators.items():
if isinstance(
validator, network_lsr.argument_validator.ArgValidatorDeprecated
):
assert validator.deprecated_by in validators.keys()
def test_valid_persistent_state(self):
"""
Test that when persistent_state is present and state is set to present
or absent, a ValidationError raises.
"""
validator = network_lsr.argument_validator.ArgValidator_DictConnection()
input_connection = {
"name": "test",
"persistent_state": "present",
"state": "present",
"type": "ethernet",
}
self.assertValidationError(validator, input_connection)
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"]
)
def test_set_deprecated_master(self):
"""
When passing the deprecated "master" it is updated to "controller".
"""
input_connections = [
{
"name": "prod2",
"state": "up",
"type": "bridge",
},
{
"name": "prod2-port1",
"state": "up",
"type": "ethernet",
"interface_name": "eth1",
"master": "prod2",
},
]
connections = ARGS_CONNECTIONS.validate(input_connections)
self.assertTrue(len(connections) == 2)
for connection in connections:
self.assertTrue("controller" in connection)
self.assertTrue("master" not in connection)
def test_set_deprecated_slave_type(self):
"""
When passing the deprecated "slave_type" it is updated to "port_type".
"""
input_connections = [
{
"name": "prod2",
"state": "up",
"type": "bridge",
},
{
"name": "prod2-port1",
"state": "up",
"type": "ethernet",
"interface_name": "eth1",
"controller": "prod2",
"slave_type": "bridge",
},
]
connections = ARGS_CONNECTIONS.validate(input_connections)
self.assertTrue(len(connections) == 2)
for connection in connections:
self.assertTrue("port_type" in connection)
self.assertTrue("slave_type" not in connection)
@my_test_skipIf(nmutil is None, "no support for NM (libnm via pygobject)")
class TestNM(unittest.TestCase):
def test_connection_ensure_setting(self):
con = NM.SimpleConnection.new()
self.assertIsNotNone(con)
self.assertTrue(GObject.type_is_a(con, NM.Connection))
s = nmutil.connection_ensure_setting(con, NM.SettingWired)
self.assertIsNotNone(s)
self.assertTrue(GObject.type_is_a(s, NM.SettingWired))
s2 = nmutil.connection_ensure_setting(con, NM.SettingWired)
self.assertIsNotNone(s2)
self.assertIs(s, s2)
self.assertTrue(GObject.type_is_a(s, NM.SettingWired))
def test_connection_list(self):
connections = nmutil.connection_list()
self.assertIsNotNone(connections)
def test_path_to_glib_bytes(self):
result = Util.path_to_glib_bytes("/my/test/path")
self.assertIsInstance(result, Util.GLib().Bytes)
self.assertEqual(result.get_data(), b"file:///my/test/path\x00")
class TestUtils(unittest.TestCase):
def test_mac_ntoa(self):
mac_bytes = b"\xaa\xbb\xcc\xdd\xee\xff"
self.assertEqual(Util.mac_ntoa(mac_bytes), "aa:bb:cc:dd:ee:ff")
def test_convert_passwd_flags_nm(self):
test_cases = [
([], 0),
(["none"], 0),
(["agent-owned"], 1),
(["not-saved"], 2),
(["agent-owned", "not-saved"], 3),
(
["not-required"],
4,
),
(["agent-owned", "not-required"], 5),
(["not-saved", "not-required"], 6),
(["agent-owned", "not-saved", "not-required"], 7),
]
for test_case in test_cases:
result = Util.convert_passwd_flags_nm(test_case[0])
self.assertEqual(result, test_case[1])
class TestSysUtils(unittest.TestCase):
def test_link_read_permaddress(self):
self.assertEqual(SysUtil._link_read_permaddress("lo"), "00:00:00:00:00:00")
self.assertEqual(SysUtil._link_read_permaddress("fakeiface"), None)
self.assertEqual(SysUtil._link_read_permaddress("morethansixteenchars"), None)
if __name__ == "__main__":
unittest.main()