diff --git a/releasenotes/notes/no-boot-1709a77ecc140034.yaml b/releasenotes/notes/no-boot-1709a77ecc140034.yaml new file mode 100644 index 00000000..54b0f26f --- /dev/null +++ b/releasenotes/notes/no-boot-1709a77ecc140034.yaml @@ -0,0 +1,11 @@ +--- +issues: + - | + Reads hardware state from libvirt domain XML + + Now reads boot device/mode/image from domain XML on + filesystem rather then the running VM, thus avoiding + the need for a reboot after setting soemthing. The client + should now power cycle the instance if the changes are + required in the running VM. + note: not simply a soft reboot. diff --git a/sushy_tools/emulator/resources/systems/libvirtdriver.py b/sushy_tools/emulator/resources/systems/libvirtdriver.py index 144941c0..36016c39 100644 --- a/sushy_tools/emulator/resources/systems/libvirtdriver.py +++ b/sushy_tools/emulator/resources/systems/libvirtdriver.py @@ -62,23 +62,6 @@ class libvirt_open(object): self._conn.close() -def power_cycle(wrapped): - def wrapper(self, identity, *args, **kwargs): - power_state = self.get_power_state(identity) - - if power_state == 'On': - self.set_power_state(identity, 'ForceOff') - - try: - return wrapped(self, identity, *args, **kwargs) - - finally: - if power_state == 'On': - self.set_power_state(identity, power_state) - - return wrapper - - class LibvirtDriver(AbstractSystemsDriver): """Libvirt driver""" @@ -301,7 +284,7 @@ class LibvirtDriver(AbstractSystemsDriver): """ domain = self._get_domain(identity, readonly=True) - tree = ET.fromstring(domain.XMLDesc()) + tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) # Try boot configuration in the bootloader @@ -364,7 +347,6 @@ class LibvirtDriver(AbstractSystemsDriver): return boot_source_target - @power_cycle def set_boot_device(self, identity, boot_source): """Get/Set computer system boot device name @@ -382,7 +364,7 @@ class LibvirtDriver(AbstractSystemsDriver): domain = self._get_domain(identity) # XML schema: https://libvirt.org/formatdomain.html#elementsOSBIOS - tree = ET.fromstring(domain.XMLDesc()) + tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) # Remove bootloader configuration @@ -463,7 +445,7 @@ class LibvirtDriver(AbstractSystemsDriver): domain = self._get_domain(identity, readonly=True) # XML schema: https://libvirt.org/formatdomain.html#elementsOSBIOS - tree = ET.fromstring(domain.XMLDesc()) + tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) loader_element = tree.find('.//loader') @@ -474,7 +456,6 @@ class LibvirtDriver(AbstractSystemsDriver): return boot_mode - @power_cycle def set_boot_mode(self, identity, boot_mode): """Set computer system boot mode. @@ -486,7 +467,7 @@ class LibvirtDriver(AbstractSystemsDriver): domain = self._get_domain(identity, readonly=True) # XML schema: https://libvirt.org/formatdomain.html#elementsOSBIOS - tree = ET.fromstring(domain.XMLDesc()) + tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) try: loader_type = self.BOOT_MODE_MAP[boot_mode] @@ -593,7 +574,7 @@ class LibvirtDriver(AbstractSystemsDriver): """ domain = self._get_domain(identity, readonly=True) - tree = ET.fromstring(domain.XMLDesc()) + tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) total_cpus = 0 @@ -692,9 +673,10 @@ class LibvirtDriver(AbstractSystemsDriver): """ domain = self._get_domain(identity) - result = self._process_bios_attributes(domain.XMLDesc(), - bios_attributes, - update_existing_attributes) + result = self._process_bios_attributes( + domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE), + bios_attributes, + update_existing_attributes) if result.attributes_written: @@ -720,7 +702,6 @@ class LibvirtDriver(AbstractSystemsDriver): """ return self._process_bios(identity) - @power_cycle def set_bios(self, identity, attributes): """Update BIOS attributes @@ -743,7 +724,6 @@ class LibvirtDriver(AbstractSystemsDriver): self._process_bios(identity, bios_attributes, update_existing_attributes=True) - @power_cycle def reset_bios(self, identity): """Reset BIOS attributes to default @@ -762,7 +742,7 @@ class LibvirtDriver(AbstractSystemsDriver): :returns: list of network interfaces dict with their attributes """ domain = self._get_domain(identity, readonly=True) - tree = ET.fromstring(domain.XMLDesc()) + tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) return [{'id': iface.get('address'), 'mac': iface.get('address')} for iface in tree.findall( ".//devices/interface[@type='network']/mac")] @@ -778,7 +758,7 @@ class LibvirtDriver(AbstractSystemsDriver): """ domain = self._get_domain(identity, readonly=True) - tree = ET.fromstring(domain.XMLDesc()) + tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) device_element = tree.find('devices') if device_element is None: @@ -970,7 +950,6 @@ class LibvirtDriver(AbstractSystemsDriver): if dev_type == lv_device: device_element.remove(disk_element) - @power_cycle def set_boot_image(self, identity, device, boot_image=None, write_protected=True): """Set backend VM boot image @@ -986,7 +965,8 @@ class LibvirtDriver(AbstractSystemsDriver): """ domain = self._get_domain(identity) - domain_tree = ET.fromstring(domain.XMLDesc()) + domain_tree = ET.fromstring( + domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) self._remove_boot_images(domain, domain_tree, device) @@ -1082,7 +1062,7 @@ class LibvirtDriver(AbstractSystemsDriver): :returns: dict of simple storage controller dict with their attributes """ domain = self._get_domain(identity, readonly=True) - tree = ET.fromstring(domain.XMLDesc()) + tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) simple_storage = defaultdict(lambda: defaultdict(DeviceList=list())) for disk_element in tree.findall(".//disk/target[@bus]/.."): diff --git a/sushy_tools/tests/unit/emulator/resources/systems/test_libvirt.py b/sushy_tools/tests/unit/emulator/resources/systems/test_libvirt.py index 9caead88..beb94a32 100644 --- a/sushy_tools/tests/unit/emulator/resources/systems/test_libvirt.py +++ b/sushy_tools/tests/unit/emulator/resources/systems/test_libvirt.py @@ -165,7 +165,7 @@ class LibvirtDriverTestCase(base.BaseTestCase): domain_mock.injectNMI.assert_called_once_with() @mock.patch('libvirt.open', autospec=True) - def test_power_cycle_when_off(self, libvirt_mock): + def test_power_cycle(self, libvirt_mock): with open('sushy_tools/tests/unit/emulator/' 'domain_boot_os.xml', 'r') as f: data = f.read() @@ -181,29 +181,9 @@ class LibvirtDriverTestCase(base.BaseTestCase): gps_mock.return_value = 'Off' self.test_driver.set_boot_device(self.uuid, 'Cd') - self.assertTrue(gps_mock.called) + self.assertFalse(gps_mock.called) self.assertFalse(sps_mock.called) - @mock.patch('libvirt.open', autospec=True) - def test_power_cycle_when_on(self, libvirt_mock): - with open('sushy_tools/tests/unit/emulator/' - 'domain_boot_os.xml', 'r') as f: - data = f.read() - - conn_mock = libvirt_mock.return_value - domain_mock = conn_mock.lookupByUUID.return_value - domain_mock.XMLDesc.return_value = data - - with mock.patch.object( - self.test_driver, 'get_power_state') as gps_mock: - with mock.patch.object( - self.test_driver, 'set_power_state') as sps_mock: - gps_mock.return_value = 'On' - self.test_driver.set_boot_device(self.uuid, 'Cd') - - self.assertTrue(gps_mock.called) - self.assertTrue(sps_mock.called) - @mock.patch('libvirt.openReadOnly', autospec=True) def test_get_boot_device_os(self, libvirt_mock): with open('sushy_tools/tests/unit/emulator/'