|
Server : Apache System : Linux server.mata-lashes.com 3.10.0-1160.90.1.el7.x86_64 #1 SMP Thu May 4 15:21:22 UTC 2023 x86_64 User : matalashes ( 1004) PHP Version : 8.1.29 Disable Function : NONE Directory : /usr/src/cloud-init/tests/unittests/distros/ |
Upload File : |
# See https://docs.pytest.org/en/stable/example
# /parametrize.html#parametrizing-conditional-raising
import textwrap
from unittest import mock
import pytest
from cloudinit import net
from cloudinit import safeyaml as yaml
from cloudinit.distros.networking import (
BSDNetworking,
LinuxNetworking,
Networking,
)
from tests.unittests.helpers import does_not_raise, readResource
@pytest.fixture
def generic_networking_cls():
"""Returns a direct Networking subclass which errors on /sys usage.
This enables the direct testing of functionality only present on the
``Networking`` super-class, and provides a check on accidentally using /sys
in that context.
"""
class TestNetworking(Networking):
def apply_network_config_names(self, *args, **kwargs):
raise NotImplementedError
def is_physical(self, *args, **kwargs):
raise NotImplementedError
def settle(self, *args, **kwargs):
raise NotImplementedError
def try_set_link_up(self, *args, **kwargs):
raise NotImplementedError
error = AssertionError("Unexpectedly used /sys in generic networking code")
with mock.patch(
"cloudinit.net.get_sys_class_path",
side_effect=error,
):
yield TestNetworking
@pytest.fixture
def bsd_networking_cls(asset="netinfo/freebsd-ifconfig-output"):
"""Returns a patched BSDNetworking class which already comes pre-loaded
with output for ``ifconfig -a``"""
ifs_txt = readResource(asset)
with mock.patch(
"cloudinit.distros.networking.subp.subp", return_value=(ifs_txt, None)
):
yield BSDNetworking
@pytest.fixture
def sys_class_net(tmpdir):
sys_class_net_path = tmpdir.join("sys/class/net")
sys_class_net_path.ensure_dir()
with mock.patch(
"cloudinit.net.get_sys_class_path",
return_value=sys_class_net_path.strpath + "/",
):
yield sys_class_net_path
class TestBSDNetworkingIsPhysical:
def test_is_physical(self, bsd_networking_cls):
networking = bsd_networking_cls()
assert networking.is_physical("vtnet0")
def test_is_not_physical(self, bsd_networking_cls):
networking = bsd_networking_cls()
assert not networking.is_physical("re0.33")
class TestBSDNetworkingIsVLAN:
def test_is_vlan(self, bsd_networking_cls):
networking = bsd_networking_cls()
assert networking.is_vlan("re0.33")
def test_is_not_physical(self, bsd_networking_cls):
networking = bsd_networking_cls()
assert not networking.is_vlan("vtnet0")
class TestBSDNetworkingIsBridge:
def test_is_vlan(self, bsd_networking_cls):
networking = bsd_networking_cls()
assert networking.is_bridge("bridge0")
def test_is_not_physical(self, bsd_networking_cls):
networking = bsd_networking_cls()
assert not networking.is_bridge("vtnet0")
class TestLinuxNetworkingIsPhysical:
def test_returns_false_by_default(self, sys_class_net):
assert not LinuxNetworking().is_physical("eth0")
def test_returns_false_if_devname_exists_but_not_physical(
self, sys_class_net
):
devname = "eth0"
sys_class_net.join(devname).mkdir()
assert not LinuxNetworking().is_physical(devname)
def test_returns_true_if_device_is_physical(self, sys_class_net):
devname = "eth0"
device_dir = sys_class_net.join(devname)
device_dir.mkdir()
device_dir.join("device").write("")
assert LinuxNetworking().is_physical(devname)
@mock.patch("cloudinit.distros.networking.BSDNetworking.is_up")
class TestBSDNetworkingTrySetLinkUp:
def test_calls_subp_return_true(self, m_is_up, bsd_networking_cls):
devname = "vtnet0"
networking = bsd_networking_cls()
m_is_up.return_value = True
with mock.patch("cloudinit.subp.subp") as m_subp:
is_success = networking.try_set_link_up(devname)
assert (
mock.call(["ifconfig", devname, "up"])
== m_subp.call_args_list[-1]
)
assert is_success
@mock.patch("cloudinit.net.is_up")
@mock.patch("cloudinit.distros.networking.subp.subp")
class TestLinuxNetworkingTrySetLinkUp:
def test_calls_subp_return_true(self, m_subp, m_is_up):
devname = "eth0"
m_is_up.return_value = True
is_success = LinuxNetworking().try_set_link_up(devname)
assert (
mock.call(["ip", "link", "set", devname, "up"])
== m_subp.call_args_list[-1]
)
assert is_success
def test_calls_subp_return_false(self, m_subp, m_is_up):
devname = "eth0"
m_is_up.return_value = False
is_success = LinuxNetworking().try_set_link_up(devname)
assert (
mock.call(["ip", "link", "set", devname, "up"])
== m_subp.call_args_list[-1]
)
assert not is_success
class TestBSDNetworkingSettle:
def test_settle_doesnt_error(self, bsd_networking_cls):
networking = bsd_networking_cls()
networking.settle()
@pytest.mark.usefixtures("sys_class_net")
@mock.patch("cloudinit.distros.networking.util.udevadm_settle", autospec=True)
class TestLinuxNetworkingSettle:
def test_no_arguments(self, m_udevadm_settle):
LinuxNetworking().settle()
assert [mock.call(exists=None)] == m_udevadm_settle.call_args_list
def test_exists_argument(self, m_udevadm_settle):
LinuxNetworking().settle(exists="ens3")
expected_path = net.sys_dev_path("ens3")
assert [
mock.call(exists=expected_path)
] == m_udevadm_settle.call_args_list
class TestNetworkingWaitForPhysDevs:
@pytest.fixture
def wait_for_physdevs_netcfg(self):
"""This config is shared across all the tests in this class."""
def ethernet(mac, name, driver=None, device_id=None):
v2_cfg = {"set-name": name, "match": {"macaddress": mac}}
if driver:
v2_cfg["match"].update({"driver": driver})
if device_id:
v2_cfg["match"].update({"device_id": device_id})
return v2_cfg
physdevs = [
["aa:bb:cc:dd:ee:ff", "eth0", "virtio", "0x1000"],
["00:11:22:33:44:55", "ens3", "e1000", "0x1643"],
]
netcfg = {
"version": 2,
"ethernets": {args[1]: ethernet(*args) for args in physdevs},
}
return netcfg
def test_skips_settle_if_all_present(
self,
generic_networking_cls,
wait_for_physdevs_netcfg,
):
networking = generic_networking_cls()
with mock.patch.object(
networking, "get_interfaces_by_mac"
) as m_get_interfaces_by_mac:
m_get_interfaces_by_mac.side_effect = iter(
[{"aa:bb:cc:dd:ee:ff": "eth0", "00:11:22:33:44:55": "ens3"}]
)
with mock.patch.object(
networking, "settle", autospec=True
) as m_settle:
networking.wait_for_physdevs(wait_for_physdevs_netcfg)
assert 0 == m_settle.call_count
def test_calls_udev_settle_on_missing(
self,
generic_networking_cls,
wait_for_physdevs_netcfg,
):
networking = generic_networking_cls()
with mock.patch.object(
networking, "get_interfaces_by_mac"
) as m_get_interfaces_by_mac:
m_get_interfaces_by_mac.side_effect = iter(
[
{
"aa:bb:cc:dd:ee:ff": "eth0"
}, # first call ens3 is missing
{
"aa:bb:cc:dd:ee:ff": "eth0",
"00:11:22:33:44:55": "ens3",
}, # second call has both
]
)
with mock.patch.object(
networking, "settle", autospec=True
) as m_settle:
networking.wait_for_physdevs(wait_for_physdevs_netcfg)
m_settle.assert_called_with(exists="ens3")
@pytest.mark.parametrize(
"strict,expectation",
[(True, pytest.raises(RuntimeError)), (False, does_not_raise())],
)
def test_retrying_and_strict_behaviour(
self,
strict,
expectation,
generic_networking_cls,
wait_for_physdevs_netcfg,
):
networking = generic_networking_cls()
with mock.patch.object(
networking, "get_interfaces_by_mac"
) as m_get_interfaces_by_mac:
m_get_interfaces_by_mac.return_value = {}
with mock.patch.object(
networking, "settle", autospec=True
) as m_settle:
with expectation:
networking.wait_for_physdevs(
wait_for_physdevs_netcfg, strict=strict
)
assert (
5 * len(wait_for_physdevs_netcfg["ethernets"])
== m_settle.call_count
)
class TestLinuxNetworkingApplyNetworkCfgNames:
V1_CONFIG = textwrap.dedent(
"""\
version: 1
config:
- type: physical
name: interface0
mac_address: "52:54:00:12:34:00"
subnets:
- type: static
address: 10.0.2.15
netmask: 255.255.255.0
gateway: 10.0.2.2
"""
)
V2_CONFIG = textwrap.dedent(
"""\
version: 2
ethernets:
interface0:
match:
macaddress: "52:54:00:12:34:00"
addresses:
- 10.0.2.15/24
gateway4: 10.0.2.2
set-name: interface0
"""
)
V2_CONFIG_NO_SETNAME = textwrap.dedent(
"""\
version: 2
ethernets:
interface0:
match:
macaddress: "52:54:00:12:34:00"
addresses:
- 10.0.2.15/24
gateway4: 10.0.2.2
"""
)
V2_CONFIG_NO_MAC = textwrap.dedent(
"""\
version: 2
ethernets:
interface0:
match:
driver: virtio-net
addresses:
- 10.0.2.15/24
gateway4: 10.0.2.2
set-name: interface0
"""
)
@pytest.mark.parametrize(
["config_attr"],
[
pytest.param("V1_CONFIG", id="v1"),
pytest.param("V2_CONFIG", id="v2"),
],
)
@mock.patch("cloudinit.net.device_devid")
@mock.patch("cloudinit.net.device_driver")
def test_apply_renames(
self,
m_device_driver,
m_device_devid,
config_attr: str,
):
networking = LinuxNetworking()
m_device_driver.return_value = "virtio_net"
m_device_devid.return_value = "0x15d8"
netcfg = yaml.load(getattr(self, config_attr))
with mock.patch.object(
networking, "_rename_interfaces"
) as m_rename_interfaces:
networking.apply_network_config_names(netcfg)
assert (
mock.call(
[["52:54:00:12:34:00", "interface0", "virtio_net", "0x15d8"]]
)
== m_rename_interfaces.call_args_list[-1]
)
@pytest.mark.parametrize(
["config_attr"],
[
pytest.param("V2_CONFIG_NO_SETNAME", id="without_setname"),
pytest.param("V2_CONFIG_NO_MAC", id="without_mac"),
],
)
def test_apply_v2_renames_skips_without_setname_or_mac(
self, config_attr: str
):
networking = LinuxNetworking()
netcfg = yaml.load(getattr(self, config_attr))
with mock.patch.object(
networking, "_rename_interfaces"
) as m_rename_interfaces:
networking.apply_network_config_names(netcfg)
m_rename_interfaces.assert_called_with([])
def test_apply_v2_renames_raises_runtime_error_on_unknown_version(self):
networking = LinuxNetworking()
with pytest.raises(RuntimeError):
networking.apply_network_config_names(yaml.load("version: 3"))