Mechanical: ruff format, and ruff check --fix with the rule set every NAPALM driver uses (E, F, I, UP, B at line length 100). typing.List/Dict/Optional become builtin generics and X | None, imports are sorted, the coding cookies are gone. Two tests that read the source text follow the new spelling. What ruff cannot fix comes in the next commit.
104 lines
3.8 KiB
Python
104 lines
3.8 KiB
Python
"""What provisioning a VM from a cloud image needs to know about the guest,
|
|
the same for every hypervisor (NetOrk/netork#794)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from napalm_device_types import HypervisorDriver
|
|
from napalm_device_types.provisioning import (
|
|
QEMU_GUEST_AGENTS,
|
|
network_config,
|
|
split_compression,
|
|
)
|
|
|
|
|
|
class TestGuestAgentDeclaration:
|
|
"""netOrk's cloud-init installs the agent through which the hypervisor
|
|
reads the new VM's IP. Which agent depends on the hypervisor and on the
|
|
guest; the guests a driver lists are the ones it can provision."""
|
|
|
|
def test_the_base_provisions_linux_with_qemu_guest_agent(self):
|
|
assert HypervisorDriver.GUEST_AGENTS == {
|
|
"linux": (("qemu-guest-agent",), ("systemctl enable --now qemu-guest-agent",)),
|
|
}
|
|
|
|
def test_the_declaration_is_data_netork_reads_off_the_class(self):
|
|
assert not callable(vars(HypervisorDriver)["GUEST_AGENTS"])
|
|
|
|
def test_the_per_hypervisor_attributes_are_gone(self):
|
|
assert not hasattr(HypervisorDriver, "GUEST_AGENT_PACKAGES")
|
|
assert not hasattr(HypervisorDriver, "GUEST_AGENT_RUNCMD")
|
|
|
|
|
|
class TestQemuGuestAgents:
|
|
"""Verified on FreeBSD 15.1 and OpenBSD 7.9 cloud images (#793)."""
|
|
|
|
def test_linux_is_the_base_default(self):
|
|
assert QEMU_GUEST_AGENTS["linux"] == HypervisorDriver.GUEST_AGENTS["linux"]
|
|
|
|
def test_freebsd(self):
|
|
assert QEMU_GUEST_AGENTS["freebsd"] == (
|
|
("qemu-guest-agent",),
|
|
("sysrc qemu_guest_agent_enable=YES", "service qemu-guest-agent start"),
|
|
)
|
|
|
|
def test_openbsd(self):
|
|
assert QEMU_GUEST_AGENTS["openbsd"] == (
|
|
("qemu-ga",),
|
|
("rcctl enable qemu_ga", "rcctl start qemu_ga"),
|
|
)
|
|
|
|
@pytest.mark.parametrize("guest_os", ["freebsd", "openbsd"])
|
|
def test_no_bsd_guest_is_told_to_use_systemd(self, guest_os):
|
|
_, runcmd = QEMU_GUEST_AGENTS[guest_os]
|
|
assert not any("systemctl" in command for command in runcmd)
|
|
|
|
|
|
class TestNetworkConfig:
|
|
"""cloud-init's network-config v2. FreeBSD's nuageinit reads only this
|
|
version; the v1 Proxmox generates makes it skip runcmd (#793)."""
|
|
|
|
def test_dhcp_nics_matched_by_mac(self):
|
|
cfg = network_config([("00:50:56:aa:bb:cc", True), ("00:50:56:aa:bb:dd", False)])
|
|
assert cfg == {
|
|
"version": 2,
|
|
"ethernets": {
|
|
"nic0": {"match": {"macaddress": "00:50:56:aa:bb:cc"}, "dhcp4": True},
|
|
},
|
|
}
|
|
|
|
def test_no_dhcp_nic_means_no_network_config(self):
|
|
assert network_config([("00:50:56:aa:bb:cc", False)]) is None
|
|
|
|
def test_macs_are_written_in_lower_case(self):
|
|
"""Proxmox reports them upper-case; nuageinit compares them as given."""
|
|
cfg = network_config([("BC:24:11:AA:BB:02", True)])
|
|
assert cfg["ethernets"]["nic0"]["match"]["macaddress"] == "bc:24:11:aa:bb:02"
|
|
|
|
|
|
class TestSplitCompression:
|
|
"""Official FreeBSD images come packed; hypervisors import unpacked ones."""
|
|
|
|
def test_xz(self):
|
|
assert split_compression("FreeBSD-15.1-RELEASE-amd64-BASIC-CLOUDINIT-ufs.qcow2.xz") == (
|
|
"FreeBSD-15.1-RELEASE-amd64-BASIC-CLOUDINIT-ufs.qcow2",
|
|
"xz -dc",
|
|
)
|
|
|
|
@pytest.mark.parametrize(
|
|
("name", "command"),
|
|
[("a.raw.gz", "gzip -dc"), ("a.raw.bz2", "bzip2 -dc"), ("a.qcow2.zst", "zstd -dc")],
|
|
)
|
|
def test_other_packers(self, name, command):
|
|
assert split_compression(name) == (name.rsplit(".", 1)[0], command)
|
|
|
|
@pytest.mark.parametrize(
|
|
"name", ["debian-13-genericcloud-amd64.qcow2", "ubuntu-24.04-server-cloudimg-amd64.img"]
|
|
)
|
|
def test_an_unpacked_image_is_left_as_it_is(self, name):
|
|
assert split_compression(name) == (name, None)
|
|
|
|
def test_the_suffix_is_matched_case_insensitively(self):
|
|
assert split_compression("IMAGE.QCOW2.XZ") == ("IMAGE.QCOW2", "xz -dc")
|