Read current domain state from XML on filesystem
Use the XML file as a source of truth when getting current state of each domain. Reading current state from the running VM's requires that we do a reboot every time we change something. Change-Id: Ifcc9afc46562a5df5dd73010b8d274452c1aefc1 Story: #2007735 Task: #39901
This commit is contained in:
parent
6baebba032
commit
13a0b5920c
11
releasenotes/notes/no-boot-1709a77ecc140034.yaml
Normal file
11
releasenotes/notes/no-boot-1709a77ecc140034.yaml
Normal file
@ -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.
|
@ -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]/.."):
|
||||
|
@ -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/'
|
||||
|
Loading…
Reference in New Issue
Block a user