External snapshots with host-passthrough cpu mode
Domain/cpu node in XML description of external snapshots now being updated with an appropriate information from domain XML description when 'host-passthrough' cpu mode is selected. This is implemented in Snapshot class from libvirt-driver module. The reason why it was done is libvirt rejects calls for restoring VMs to the states from external snapshots and redefining external snapshots without specifying cpu model and vendor. Currently libvirt does neither return cpu model and vendor when calling getXMLDesc for snapshot object for domains with 'host-passthrough' cpu mode selected nor accept additional flags for the mentioned method to get such information. Fortunately, this can be done using XMLDesc domain method by passing VIR_DOMAIN_XML_UPDATE_CPU flag. Change-Id: I06c574c16f3a39d22a773bf306527293882a015a Closes-Bug: #1535259
This commit is contained in:
@@ -33,9 +33,31 @@ class Snapshot(object):
|
||||
|
||||
def __init__(self, snapshot):
|
||||
self._snapshot = snapshot
|
||||
self._domain = snapshot.getDomain()
|
||||
self._xml_content = ''
|
||||
self._xml = snapshot.getXMLDesc(0)
|
||||
self._repr = ""
|
||||
|
||||
@property
|
||||
def _xml(self):
|
||||
return self._xml_content
|
||||
|
||||
@_xml.setter
|
||||
def _xml(self, xml_content):
|
||||
snapshot_xmltree = ET.fromstring(xml_content)
|
||||
cpu_mode = snapshot_xmltree.findall('./domain/cpu')[0].get('mode')
|
||||
# Get cpu model from domain definition as it is not available
|
||||
# in snapshot XML for host-passthrough cpu mode
|
||||
if cpu_mode == 'host-passthrough':
|
||||
domain_xml = self._domain.XMLDesc(
|
||||
libvirt.VIR_DOMAIN_XML_UPDATE_CPU)
|
||||
domain_xmltree = ET.fromstring(domain_xml)
|
||||
cpu_element = domain_xmltree.find('./cpu')
|
||||
domain_element = snapshot_xmltree.findall('./domain')[0]
|
||||
domain_element.remove(domain_element.findall('./cpu')[0])
|
||||
domain_element.append(cpu_element)
|
||||
self._xml_content = ET.tostring(snapshot_xmltree)
|
||||
|
||||
@property
|
||||
def _xml_tree(self):
|
||||
return ET.fromstring(self._xml)
|
||||
@@ -448,7 +470,7 @@ class DevopsDriver(object):
|
||||
def node_set_snapshot_current(self, node, name):
|
||||
domain = self.conn.lookupByUUIDString(node.uuid)
|
||||
snapshot = self._get_snapshot(domain, name)
|
||||
snapshot_xml = snapshot.getXMLDesc()
|
||||
snapshot_xml = Snapshot(snapshot)._xml
|
||||
domain.snapshotCreateXML(
|
||||
snapshot_xml,
|
||||
libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
|
||||
|
||||
@@ -184,7 +184,12 @@ class TestDevopsDriver(TestCase):
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.libvirt.open')
|
||||
def test_node_set_snapshot_current(self, mock_conn):
|
||||
xml_fuzzy = factories.fuzzy_string()
|
||||
xml = '<{0}/>'.format(xml_fuzzy)
|
||||
xml = '''<domainsnapshot>
|
||||
<name>{0}</name>
|
||||
<domain>
|
||||
<cpu mode="host-model" />
|
||||
</domain>
|
||||
</domainsnapshot>'''.format(xml_fuzzy)
|
||||
snapshot = mock.Mock()
|
||||
snapshot.getXMLDesc.return_value = xml
|
||||
domain = mock.Mock()
|
||||
@@ -203,15 +208,58 @@ class TestDevopsDriver(TestCase):
|
||||
xml, libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
|
||||
libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)
|
||||
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.libvirt.open')
|
||||
def test_node_set_snapshot_current_host_passthrough(self, mock_conn):
|
||||
xml_fuzzy = factories.fuzzy_string()
|
||||
cpu_model = factories.fuzzy_string()
|
||||
domain_cpu = '''<cpu mode="host-passthrough">
|
||||
<model>{0}</model>
|
||||
<vendor>Intel</vendor>
|
||||
</cpu>'''.format(cpu_model)
|
||||
domain_xml = '''<domain>
|
||||
{0}
|
||||
</domain>'''.format(domain_cpu)
|
||||
snapshot_cpu = '<cpu mode="host-passthrough" />'
|
||||
snapshot_xml_tmpl = '''<domainsnapshot>
|
||||
<name>{0}</name>
|
||||
<domain>
|
||||
{1}
|
||||
</domain>
|
||||
</domainsnapshot>'''
|
||||
snapshot_xml = snapshot_xml_tmpl.format(xml_fuzzy, snapshot_cpu)
|
||||
snapshot = mock.Mock()
|
||||
snapshot.getXMLDesc.return_value = snapshot_xml
|
||||
domain = mock.Mock()
|
||||
domain.isActive.return_value = False
|
||||
domain.snapshotCreateXML.return_value = True
|
||||
domain.snapshotCurrent.return_value = snapshot
|
||||
domain.snapshotLookupByName.return_value = snapshot
|
||||
domain.XMLDesc.return_value = domain_xml
|
||||
mock_conn.return_value.lookupByUUIDString.return_value = domain
|
||||
snapshot.getDomain.return_value = domain
|
||||
node = mock.Mock(uuid='test_node')
|
||||
snapshot_name = factories.fuzzy_string()
|
||||
|
||||
dd = DevopsDriver()
|
||||
dd.node_set_snapshot_current(node, snapshot_name)
|
||||
|
||||
domain.snapshotCreateXML.assert_called_with(
|
||||
snapshot_xml_tmpl.format(xml_fuzzy, domain_cpu),
|
||||
libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
|
||||
libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)
|
||||
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.libvirt.open')
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.os')
|
||||
def test_delete_snaphost_files(self, mock_os, mock_conn):
|
||||
def test_delete_snapshot_files(self, mock_os, mock_conn):
|
||||
mock_os.path.isfile.return_value = True
|
||||
mock_os.remove.return_value = True
|
||||
|
||||
memory_file = factories.fuzzy_string('/path/to/')
|
||||
snapshot_xml = '''<domainsnapshot>
|
||||
<memory file="{0}" snapshot="external"/>
|
||||
<domain>
|
||||
<cpu mode='host-model'/>
|
||||
</domain>
|
||||
</domainsnapshot>'''.format(memory_file)
|
||||
snapshot = mock.Mock()
|
||||
snapshot.getXMLDesc.return_value = snapshot_xml
|
||||
@@ -223,12 +271,15 @@ class TestDevopsDriver(TestCase):
|
||||
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.libvirt.open')
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.os')
|
||||
def test_delete_snaphost_files_internal(self, mock_os, mock_conn):
|
||||
def test_delete_snapshot_files_internal(self, mock_os, mock_conn):
|
||||
mock_os.path.isfile.return_value = True
|
||||
mock_os.remove.return_value = True
|
||||
|
||||
snapshot_xml = '''<domainsnapshot>
|
||||
<memory snapshot="internal"/>
|
||||
<domain>
|
||||
<cpu mode='host-model'/>
|
||||
</domain>
|
||||
</domainsnapshot>'''
|
||||
snapshot = mock.Mock()
|
||||
snapshot.getXMLDesc.return_value = snapshot_xml
|
||||
@@ -239,9 +290,12 @@ class TestDevopsDriver(TestCase):
|
||||
self.assertEqual(mock_os.remove.called, False)
|
||||
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.libvirt.open')
|
||||
def test_node_delete_snaphost_internal(self, mock_conn):
|
||||
def test_node_delete_snapshot_internal(self, mock_conn):
|
||||
snapshot_xml = '''<domainsnapshot>
|
||||
<memory snapshot="internal"/>
|
||||
<domain>
|
||||
<cpu mode='host-model'/>
|
||||
</domain>
|
||||
</domainsnapshot>'''
|
||||
snapshot = mock.Mock()
|
||||
snapshot.numChildren.return_value = 0
|
||||
@@ -265,10 +319,13 @@ class TestDevopsDriver(TestCase):
|
||||
'devops.driver.libvirt.libvirt_driver.DevopsDriver.'
|
||||
'_delete_snapshot_files')
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.libvirt.open')
|
||||
def test_node_delete_snaphost_external_has_children(
|
||||
def test_node_delete_snapshot_external_has_children(
|
||||
self, mock_conn, mock_delete_snapshot_files):
|
||||
snapshot_xml = '''<domainsnapshot>
|
||||
<memory snapshot="external"/>
|
||||
<domain>
|
||||
<cpu mode='host-model'/>
|
||||
</domain>
|
||||
</domainsnapshot>'''
|
||||
snapshot = mock.Mock()
|
||||
snapshot.numChildren.return_value = 1
|
||||
@@ -293,10 +350,11 @@ class TestDevopsDriver(TestCase):
|
||||
'devops.driver.libvirt.libvirt_driver.DevopsDriver.'
|
||||
'_delete_snapshot_files')
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.libvirt.open')
|
||||
def test_node_delete_snaphost_external(self, mock_conn,
|
||||
def test_node_delete_snapshot_external(self, mock_conn,
|
||||
mock_delete_snapshot_files):
|
||||
domain_xml = '''<domain>
|
||||
<name>{0}</name>
|
||||
<cpu mode='host-model'/>
|
||||
<devices>
|
||||
<disk type='file' device='disk' snapshot='external'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
@@ -341,8 +399,15 @@ class TestDevopsDriver(TestCase):
|
||||
|
||||
@mock.patch('devops.driver.libvirt.libvirt_driver.libvirt.open')
|
||||
def test_node_revert_snapshot_recreate_disks_has_children(self, mock_conn):
|
||||
snapshot_xml = '''<domainsnapshot>
|
||||
<memory snapshot="external"/>
|
||||
<domain>
|
||||
<cpu mode='host-model'/>
|
||||
</domain>
|
||||
</domainsnapshot>'''
|
||||
snapshot = mock.Mock()
|
||||
snapshot.children_num = 1
|
||||
snapshot.getXMLDesc.return_value = snapshot_xml
|
||||
domain = mock.Mock()
|
||||
domain.isActive.return_value = True
|
||||
domain.snapshotCreateXML.return_value = True
|
||||
@@ -371,6 +436,9 @@ class TestDevopsDriver(TestCase):
|
||||
<source file='{1}'/>
|
||||
</disk>
|
||||
</disks>
|
||||
<domain>
|
||||
<cpu mode='host-model'/>
|
||||
</domain>
|
||||
</domainsnapshot>'''.format(disk1_file, disk2_file)
|
||||
snapshot = mock.Mock()
|
||||
snapshot.getXMLDesc.return_value = snapshot_xml
|
||||
@@ -440,6 +508,7 @@ class TestDevopsDriver(TestCase):
|
||||
snapshot2_path = factories.fuzzy_string('/path/to/')
|
||||
domain_xml_tmpl = ''' <domain>
|
||||
<name>{0}</name>
|
||||
<cpu mode='host-model'/>
|
||||
<devices>
|
||||
<disk type='file' device='disk' snapshot='external'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
@@ -509,6 +578,9 @@ class TestDevopsDriver(TestCase):
|
||||
<state>running</state>
|
||||
<memory snapshot="internal"/>
|
||||
<disks/>
|
||||
<domain>
|
||||
<cpu mode='host-model'/>
|
||||
</domain>
|
||||
</domainsnapshot>'''
|
||||
snapshot = mock.Mock()
|
||||
snapshot.getXMLDesc.return_value = snapshot_xml
|
||||
@@ -542,6 +614,7 @@ class TestDevopsDriver(TestCase):
|
||||
snapshot1_path = factories.fuzzy_string('/path/to/')
|
||||
domain_xml_tmpl = ''' <domain>
|
||||
<name>{0}</name>
|
||||
<cpu mode='host-model'/>
|
||||
<devices>
|
||||
<disk type='file' device='disk' snapshot='external'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
@@ -605,6 +678,7 @@ class TestDevopsDriver(TestCase):
|
||||
snapshot2_path = factories.fuzzy_string('/path/to/')
|
||||
domain_xml_tmpl = ''' <domain>
|
||||
<name>{0}</name>
|
||||
<cpu mode='host-model'/>
|
||||
<devices>
|
||||
<disk type='file' device='disk' snapshot='external'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
|
||||
Reference in New Issue
Block a user