mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
When the guest agent failed, the Guest Info section stayed empty with no word: the request's error answer was not handled. An agent without the time zone or host name command lost the OS details it had answered too. The section now shows the agent's error, and a missing command leaves out only its own details.
89 lines
4.2 KiB
Python
89 lines
4.2 KiB
Python
"""A running VM's addresses come from the guest agent when it answers and
|
|
from the host's ARP table, so a VM without an agent shows its IPv4 address.
|
|
The agent is asked with a timeout: interfaceAddresses() would wait for a
|
|
hung agent indefinitely, and the VM page with it."""
|
|
|
|
import json
|
|
import unittest
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from django.conf import settings
|
|
|
|
if not settings.configured:
|
|
settings.configure(MAC_OUI="52:54:10")
|
|
|
|
from libvirt import VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP, libvirtError
|
|
from vrtManager import instance as module
|
|
from vrtManager.instance import wvmInstance
|
|
|
|
MAC = "52:54:00:00:00:01"
|
|
ARP = {"vnet0": {"hwaddr": MAC, "addrs": [{"type": 0, "addr": "192.0.2.10", "prefix": 0}]}}
|
|
# guest-network-get-interfaces: the loopback has no hardware address
|
|
AGENT = [{"name": "lo", "ip-addresses": [{"ip-address-type": "ipv4", "ip-address": "127.0.0.1", "prefix": 8}]},
|
|
{"name": "eth0", "hardware-address": MAC, "ip-addresses": [
|
|
{"ip-address-type": "ipv4", "ip-address": "192.0.2.20", "prefix": 24},
|
|
{"ip-address-type": "ipv6", "ip-address": "2001:db8::20", "prefix": 64}]}]
|
|
|
|
|
|
def vm(agent):
|
|
inst = wvmInstance.__new__(wvmInstance)
|
|
inst._ip_cache = None
|
|
inst.instance = MagicMock()
|
|
inst.instance.interfaceAddresses.side_effect = lambda source: {VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP: ARP}[source]
|
|
patch.object(inst, "get_status", return_value=1).start()
|
|
patch.object(inst, "is_agent_ready", return_value=agent).start()
|
|
return inst
|
|
|
|
|
|
class InterfaceAddressesTestCase(unittest.TestCase):
|
|
def setUp(self):
|
|
self.agent = patch.object(module, "qemuAgentCommand", return_value=json.dumps({"return": AGENT})).start()
|
|
|
|
def tearDown(self):
|
|
patch.stopall()
|
|
|
|
def test_a_vm_without_an_agent_shows_its_arp_address(self):
|
|
inst = vm(agent=False)
|
|
self.assertEqual(inst.get_interface_addresses(MAC), (["192.0.2.10"], []))
|
|
self.agent.assert_not_called()
|
|
|
|
def test_the_agents_address_comes_first_and_is_asked_with_a_timeout(self):
|
|
inst = vm(agent=True)
|
|
self.assertEqual(inst.get_interface_addresses(MAC), (["192.0.2.20"], ["2001:db8::20/64"]))
|
|
self.agent.assert_called_once_with(inst.instance, '{"execute": "guest-network-get-interfaces"}', 10, 0)
|
|
self.assertEqual([c.args for c in inst.instance.interfaceAddresses.call_args_list],
|
|
[(VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP,)])
|
|
|
|
def test_an_agent_that_does_not_answer_leaves_the_arp_address(self):
|
|
self.agent.side_effect = libvirtError("guest agent didn't respond to command within '10' seconds")
|
|
self.assertEqual(vm(agent=True).get_interface_addresses(MAC), (["192.0.2.10"], []))
|
|
|
|
|
|
class OsInfoTestCase(unittest.TestCase):
|
|
def test_the_os_details_are_asked_with_a_timeout(self):
|
|
answers = {"guest-get-osinfo": {"kernel-release": "6.12"}, "guest-get-timezone": {"zone": "UTC"},
|
|
"guest-get-host-name": {"host-name": "web"}}
|
|
inst = wvmInstance.__new__(wvmInstance)
|
|
inst.instance = MagicMock()
|
|
with patch.object(module, "qemuAgentCommand",
|
|
side_effect=lambda dom, cmd, timeout, flags: json.dumps(
|
|
{"return": answers[json.loads(cmd)["execute"]]})) as agent:
|
|
self.assertEqual(inst.osinfo(), {"kernel-release": "6.12", "zone": "UTC", "host-name": "web"})
|
|
self.assertEqual({c.args[2] for c in agent.call_args_list}, {10})
|
|
|
|
def test_a_command_the_agent_lacks_leaves_out_only_its_details(self):
|
|
inst = wvmInstance.__new__(wvmInstance)
|
|
inst.instance = MagicMock()
|
|
|
|
def agent(dom, cmd, timeout, flags):
|
|
if json.loads(cmd)["execute"] == "guest-get-timezone":
|
|
raise libvirtError("The command guest-get-timezone has not been found")
|
|
return json.dumps({"return": {"guest-get-osinfo": {"id": "alma"}, "guest-get-host-name": {"host-name": "web"}}[
|
|
json.loads(cmd)["execute"]]})
|
|
|
|
with patch.object(module, "qemuAgentCommand", side_effect=agent):
|
|
self.assertEqual(inst.osinfo(), {"id": "alma", "host-name": "web"})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|