1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
"""Home of the tests for end-to-end net rendering
Tests defined here should take a v1 or v2 yaml config as input, and verify
that the rendered network config is as expected. Input files are defined
under `tests/unittests/net/artifacts` with the format of
<test_name><format>.yaml
For example, if my test name is "test_all_the_things" and I'm testing a
v2 format, I should have a file named test_all_the_things_v2.yaml.
If a renderer outputs multiple files, the expected files should live in
the artifacts directory under the given test name. For example, if I'm
expecting NetworkManager to output a file named eth0.nmconnection as
part of my "test_all_the_things" test, then in the artifacts directory
there should be a
`test_all_the_things/etc/NetworkManager/system-connections/eth0.nmconnection`
file.
To add a new nominal test, create the input and output files, then add the test
name to the `test_convert` test along with it's supported renderers.
Before adding a test here, check that it is not already represented
in `unittests/test_net.py`. While that file contains similar tests, it has
become too large to be maintainable.
"""
import glob
from enum import Flag, auto
from pathlib import Path
import pytest
import yaml
from cloudinit.net.netplan import Renderer as NetplanRenderer
from cloudinit.net.network_manager import Renderer as NetworkManagerRenderer
from cloudinit.net.network_state import NetworkState, parse_net_config_data
from cloudinit.net.networkd import Renderer as NetworkdRenderer
from tests.unittests.helpers import mock
ARTIFACT_DIR = Path(__file__).parent.absolute() / "artifacts"
class Renderer(Flag):
Netplan = auto()
NetworkManager = auto()
Networkd = auto()
@pytest.fixture(autouse=True)
def setup(mocker):
mocker.patch("cloudinit.net.network_state.get_interfaces_by_mac")
def _check_file_diff(expected_paths: list, tmp_path: Path):
for expected_path in expected_paths:
expected_contents = Path(expected_path).read_text()
actual_path = tmp_path / expected_path.split(
str(ARTIFACT_DIR), maxsplit=1
)[1].lstrip("/")
assert (
actual_path.exists()
), f"Expected {actual_path} to exist, but it does not"
actual_contents = actual_path.read_text()
assert expected_contents.strip() == actual_contents.strip()
def _check_netplan(
network_state: NetworkState, netplan_path: Path, expected_config
):
if network_state.version == 2:
renderer = NetplanRenderer(config={"netplan_path": netplan_path})
renderer.render_network_state(network_state)
assert yaml.safe_load(netplan_path.read_text()) == expected_config, (
f"Netplan config generated at {netplan_path} does not match v2 "
"config defined for this test."
)
else:
raise NotImplementedError
def _check_network_manager(network_state: NetworkState, tmp_path: Path):
renderer = NetworkManagerRenderer()
renderer.render_network_state(
network_state, target=str(tmp_path / "no_matching_mac")
)
expected_paths = glob.glob(
str(ARTIFACT_DIR / "no_matching_mac" / "**/*.nmconnection"),
recursive=True,
)
_check_file_diff(expected_paths, tmp_path)
@mock.patch("cloudinit.net.util.chownbyname", return_value=True)
def _check_networkd_renderer(
network_state: NetworkState, tmp_path: Path, m_chown
):
renderer = NetworkdRenderer()
renderer.render_network_state(
network_state, target=str(tmp_path / "photon_net_config")
)
expected_paths = glob.glob(
str(ARTIFACT_DIR / "photon_net_config" / "**/*.net*"),
recursive=True,
)
_check_file_diff(expected_paths, tmp_path)
@pytest.mark.parametrize(
"test_name, renderers",
[
("no_matching_mac_v2", Renderer.Netplan | Renderer.NetworkManager),
("photon_net_config_v2", Renderer.Networkd),
],
)
def test_convert(test_name, renderers, tmp_path):
network_config = yaml.safe_load(
Path(ARTIFACT_DIR, f"{test_name}.yaml").read_text()
)
network_state = parse_net_config_data(network_config["network"])
if Renderer.Netplan in renderers:
_check_netplan(
network_state, tmp_path / "netplan.yaml", network_config
)
if Renderer.NetworkManager in renderers:
_check_network_manager(network_state, tmp_path)
if Renderer.Networkd in renderers:
_check_networkd_renderer( # pylint: disable=E1120
network_state, tmp_path
)
|