summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/integration_tests/modules/test_user_events.py5
-rw-r--r--tests/integration_tests/test_networking.py93
-rw-r--r--tests/unittests/net/test_netplan.py41
-rw-r--r--tests/unittests/test_net.py4
-rw-r--r--tests/unittests/test_util.py21
5 files changed, 159 insertions, 5 deletions
diff --git a/tests/integration_tests/modules/test_user_events.py b/tests/integration_tests/modules/test_user_events.py
index 79d88022..810f8727 100644
--- a/tests/integration_tests/modules/test_user_events.py
+++ b/tests/integration_tests/modules/test_user_events.py
@@ -28,8 +28,7 @@ def _add_dummy_bridge_to_netplan(client: IntegrationInstance):
@pytest.mark.skipif(
- PLATFORM
- not in ["lxd_container", "lxd_vm", "ec2", "gce", "oci", "openstack"],
+ PLATFORM not in ["lxd_container", "lxd_vm", "ec2", "oci", "openstack"],
reason="Default boot events testing is datasource specific",
)
def test_boot_event_disabled_by_default(client: IntegrationInstance):
@@ -93,7 +92,7 @@ def _test_network_config_applied_on_reboot(client: IntegrationInstance):
@pytest.mark.skipif(
- PLATFORM != "azure",
+ PLATFORM not in ("azure", "gce"),
reason=(
f"{PLATFORM} doesn't support updates every boot event by default "
"(or hasn't been testing for it)."
diff --git a/tests/integration_tests/test_networking.py b/tests/integration_tests/test_networking.py
new file mode 100644
index 00000000..cde69afc
--- /dev/null
+++ b/tests/integration_tests/test_networking.py
@@ -0,0 +1,93 @@
+"""Networking-related tests."""
+import pytest
+import yaml
+
+from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+
+
+def _add_dummy_bridge_to_netplan(client: IntegrationInstance):
+ # Update netplan configuration to ensure it doesn't change on reboot
+ netplan = yaml.safe_load(
+ client.execute("cat /etc/netplan/50-cloud-init.yaml")
+ )
+ # Just a dummy bridge to do nothing
+ try:
+ netplan["network"]["bridges"]["dummy0"] = {"dhcp4": False}
+ except KeyError:
+ netplan["network"]["bridges"] = {"dummy0": {"dhcp4": False}}
+
+ dumped_netplan = yaml.dump(netplan)
+ client.write_to_file("/etc/netplan/50-cloud-init.yaml", dumped_netplan)
+
+
+USER_DATA = """\
+#cloud-config
+updates:
+ network:
+ when: [boot]
+"""
+
+
+@pytest.mark.skipif(
+ PLATFORM not in ("lxd_container", "lxd_vm"),
+ reason=(
+ f"{PLATFORM} could make nic changes in a reboot event invalidating"
+ f" these tests."
+ ),
+)
+@pytest.mark.user_data(USER_DATA)
+class TestNetplanGenerateBehaviorOnReboot:
+ def test_skip(self, client: IntegrationInstance):
+ log = client.read_from_file("/var/log/cloud-init.log")
+ assert "Applying network configuration" in log
+ assert "Selected renderer 'netplan'" in log
+ client.execute(
+ "mv /var/log/cloud-init.log /var/log/cloud-init.log.bak"
+ )
+ netplan = yaml.safe_load(
+ client.execute("cat /etc/netplan/50-cloud-init.yaml")
+ )
+
+ client.restart()
+
+ log = client.read_from_file("/var/log/cloud-init.log")
+ assert "Event Allowed: scope=network EventType=boot" in log
+ assert "Applying network configuration" in log
+ assert "Running command ['netplan', 'generate']" not in log
+ assert (
+ "skipping call to `netplan generate`."
+ " reason: identical netplan config"
+ ) in log
+ netplan_new = yaml.safe_load(
+ client.execute("cat /etc/netplan/50-cloud-init.yaml")
+ )
+ assert netplan == netplan_new, "no changes expected in netplan config"
+
+ def test_applied(self, client: IntegrationInstance):
+ log = client.read_from_file("/var/log/cloud-init.log")
+ assert "Applying network configuration" in log
+ assert "Selected renderer 'netplan'" in log
+ client.execute(
+ "mv /var/log/cloud-init.log /var/log/cloud-init.log.bak"
+ )
+ # fake a change in the rendered network config file
+ _add_dummy_bridge_to_netplan(client)
+ netplan = yaml.safe_load(
+ client.execute("cat /etc/netplan/50-cloud-init.yaml")
+ )
+
+ client.restart()
+
+ log = client.read_from_file("/var/log/cloud-init.log")
+ assert "Event Allowed: scope=network EventType=boot" in log
+ assert "Applying network configuration" in log
+ assert (
+ "skipping call to `netplan generate`."
+ " reason: identical netplan config"
+ ) not in log
+ assert "Running command ['netplan', 'generate']" in log
+ netplan_new = yaml.safe_load(
+ client.execute("cat /etc/netplan/50-cloud-init.yaml")
+ )
+ assert netplan != netplan_new, "changes expected in netplan config"
diff --git a/tests/unittests/net/test_netplan.py b/tests/unittests/net/test_netplan.py
new file mode 100644
index 00000000..28b0891d
--- /dev/null
+++ b/tests/unittests/net/test_netplan.py
@@ -0,0 +1,41 @@
+import os
+from unittest import mock
+
+import pytest
+
+from cloudinit import util
+from cloudinit.net import netplan
+
+
+@pytest.fixture
+def renderer(tmp_path):
+ config = {
+ "netplan_path": str(tmp_path / "netplan/50-cloud-init.yaml"),
+ "postcmds": True,
+ }
+ yield netplan.Renderer(config)
+
+
+class TestNetplanRenderer:
+ @pytest.mark.parametrize("write_config", [True, False])
+ def test_skip_netplan_generate(self, renderer, write_config, mocker):
+ """Check `netplan generate` is called if netplan config has changed."""
+ header = "\n"
+ content = "foo"
+ renderer_mocks = mocker.patch.multiple(
+ renderer,
+ _render_content=mocker.Mock(return_value=content),
+ _netplan_generate=mocker.DEFAULT,
+ _net_setup_link=mocker.DEFAULT,
+ )
+ if write_config:
+ util.ensure_dir(os.path.dirname(renderer.netplan_path))
+ with open(renderer.netplan_path, "w") as f:
+ f.write(header)
+ f.write(content)
+
+ renderer.render_network_state(mocker.Mock())
+
+ assert renderer_mocks["_netplan_generate"].call_args_list == [
+ mock.call(run=True, same_content=write_config)
+ ]
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index d7640d70..a8b18ee2 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -6470,7 +6470,7 @@ class TestNetplanPostcommands(CiTestCase):
@mock.patch.object(netplan.Renderer, "_net_setup_link")
@mock.patch("cloudinit.subp.subp")
def test_netplan_render_calls_postcmds(
- self, mock_subp, mock_netplan_generate, mock_net_setup_link
+ self, mock_subp, mock_net_setup_link, mock_netplan_generate
):
tmp_dir = self.tmp_dir()
ns = network_state.parse_net_config_data(self.mycfg, skip_broken=False)
@@ -6485,7 +6485,7 @@ class TestNetplanPostcommands(CiTestCase):
mock_subp.side_effect = iter([subp.ProcessExecutionError])
renderer.render_network_state(ns, target=render_dir)
- mock_netplan_generate.assert_called_with(run=True)
+ mock_netplan_generate.assert_called_with(run=True, same_content=False)
mock_net_setup_link.assert_called_with(run=True)
@mock.patch("cloudinit.util.SeLinuxGuard")
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index e5243ef3..c23f6399 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -3043,3 +3043,24 @@ class TestResolvable:
assert util.is_resolvable("http://169.254.169.254/") is True
assert util.is_resolvable("http://[fd00:ec2::254]/") is True
assert not m_getaddr.called
+
+
+class TestHashBuffer:
+ def test_in_memory(self):
+ buf = io.BytesIO(b"hola")
+ assert (
+ util.hash_buffer(buf)
+ == b"\x99\x80\x0b\x85\xd38>:/\xb4^\xb7\xd0\x06jHy\xa9\xda\xd0"
+ )
+
+ def test_file(self, tmp_path):
+ content = b"hola"
+ file = tmp_path / "file.txt"
+ with file.open("wb") as f:
+ f.write(content)
+
+ with file.open("rb") as f:
+ assert (
+ util.hash_buffer(f)
+ == b"\x99\x80\x0b\x85\xd38>:/\xb4^\xb7\xd0\x06jHy\xa9\xda\xd0"
+ )