def test_disk_ignore_volumeinfo_from_metadata_xml(self): xml_snippet = u'''<volumeInfo> <path>/rhev/data-center/omitted/for/brevity</path> <volType>path</volType> </volumeInfo>''' root = vmxml.parse_xml(_DISK_DATA.metadata_xml) dev = vmxml.find_first(root, 'device') vmxml.append_child(dev, etree_child=vmxml.parse_xml(xml_snippet)) data = _TestData(copy.deepcopy(_DISK_DATA.conf), vmxml.format_xml(root)) self._check_drive_from_metadata_xml(data)
def test_console_pty_properties(self, console_type, is_serial): console_xml = u'''<console type="pty"> <target port="0" type="%s" /> </console>''' % console_type dev = vmdevices.core.Console.from_xml_tree( self.log, vmxml.parse_xml(console_xml), meta={'vmid': 'VMID'}) self.assertEqual(dev.isSerial, is_serial)
def test_load_ns(self): test_xml = u'''<ovirt-vm:vm xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <ovirt-vm:version type="float">4.2</ovirt-vm:version> </ovirt-vm:vm>''' metadata_obj = metadata.Metadata('ovirt-vm', 'http://ovirt.org/vm/1.0') self.assertEqual(metadata_obj.load(vmxml.parse_xml(test_xml)), {'version': 4.2})
def load(self, dom): """ Reads the content of the metadata section from the given libvirt domain. This will fully overwrite any existing content stored in the Descriptor. The data in the libvirt domain is not changed at all. :param dom: domain to access :type dom: libvirt.Domain """ md_xml = "<{tag}/>".format(tag=self._name) try: md_xml = dom.metadata( libvirt.VIR_DOMAIN_METADATA_ELEMENT, self._namespace_uri, 0 ) except libvirt.libvirtError as e: if e.get_error_code() != libvirt.VIR_ERR_NO_DOMAIN_METADATA: raise # else `md_xml` not reassigned, so we will parse empty section # and that's exactly what we want. self._log.debug( 'loading metadata for %s: %s', dom.UUIDString(), md_xml) self._load(vmxml.parse_xml(md_xml))
def test_load_empty_not_string(self, elem_type): test_xml = u'''<ovirt-vm:vm xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <ovirt-vm:param type="{elem_type}" /> </ovirt-vm:vm>'''.format(elem_type=elem_type) metadata_obj = metadata.Metadata('ovirt-vm', 'http://ovirt.org/vm/1.0') self.assertRaises(ValueError, metadata_obj.load, vmxml.parse_xml(test_xml))
def test_missing_address_alias(self): XML = u"<device type='fake' />" dev = vmxml.parse_xml(XML) found_addr = vmdevices.core.find_device_guest_address(dev) found_alias = vmdevices.core.find_device_alias(dev) self.assertIs(found_addr, None) self.assertEqual(found_alias, '')
def test_skip_nested(self, test_xml): metadata_obj = metadata.Metadata( 'ovirt-vm', 'http://ovirt.org/vm/1.0' ) self.assertEqual( metadata_obj.load(vmxml.parse_xml(test_xml)), {} )
def test_missing_address(self): XML = u"""<device type='fake'> <alias name='{alias}'/> </device>""".format(alias=self.ALIAS) found_addr, found_alias = vmdevices.core.parse_device_ident( vmxml.parse_xml(XML)) self.assertIs(found_addr, None) self.assertEqual(found_alias, self.ALIAS)
def from_xml(xml_str): """ Helper function to parse the libvirt domain metadata used by oVirt form one domain XML. Useful in the VM creation flow, when the libvirt Domain is not yet started. Example: given this XML: test_xml -> <?xml version="1.0" encoding="utf-8"?> <domain type="kvm" xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <metadata> <ovirt-vm:vm> <ovirt-vm:version type="float">4.2</ovirt-vm:version> <ovirt-vm:custom> <ovirt-vm:foo>bar</ovirt-vm:foo> </ovirt-vm:custom> </ovirt-vm:vm> </metadata.> </domain> metadata.from_xml(test_xml) -> { 'version': 4.2, 'custom': { 'foo': 'bar' }, } :param xml_str: domain XML to parse :type name: text string :return: the parsed metadata :rtype: Python dict, whose keys are always strings. No nested objects are allowed, with the only exception of the special 'custom' key, whose value will be another Python dictionary whose keys are strings, with no further nesting allowed. """ metadata_obj = Metadata(xmlconstants.METADATA_VM_VDSM_PREFIX, xmlconstants.METADATA_VM_VDSM_URI) root = vmxml.parse_xml(xml_str) md_elem = root.find('./metadata/{%s}%s' % (xmlconstants.METADATA_VM_VDSM_URI, xmlconstants.METADATA_VM_VDSM_ELEMENT)) if md_elem is None: return {} md_data = metadata_obj.load(md_elem) custom_elem = root.find('./metadata/{%s}%s/{%s}custom' % ( xmlconstants.METADATA_VM_VDSM_URI, xmlconstants.METADATA_VM_VDSM_ELEMENT, xmlconstants.METADATA_VM_VDSM_URI, )) if custom_elem is not None: md_data['custom'] = metadata_obj.load(custom_elem) return md_data
def _parse_xml(self, xml_str): root = vmxml.parse_xml(xml_str) md_elem = root.find('./metadata/{%s}%s' % (self._namespace_uri, self._name)) if md_elem is not None: md_uuid = root.find('./uuid') self._log.debug('parsing metadata for %s: %s', md_uuid.text, vmxml.format_xml(md_elem, pretty=True)) self._load(md_elem, self._namespace, self._namespace_uri)
def test_load_empty(self, elem_type): elem_spec = ('' if elem_type is None else 'type="{elem_type}"'.format( elem_type=elem_type)) test_xml = u'''<ovirt-vm:vm xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <ovirt-vm:param {elem_spec}/> </ovirt-vm:vm>'''.format(elem_spec=elem_spec) metadata_obj = metadata.Metadata('ovirt-vm', 'http://ovirt.org/vm/1.0') self.assertEqual(metadata_obj.load(vmxml.parse_xml(test_xml)), {'param': ''})
def test_missing_address(self): XML = u"""<device type='fake'> <alias name='{alias}'/> </device>""".format(alias=self.ALIAS) dev = vmxml.parse_xml(XML) found_addr = vmdevices.core.find_device_guest_address(dev) found_alias = vmdevices.core.find_device_alias(dev) self.assertIs(found_addr, None) self.assertEqual(found_alias, self.ALIAS)
def test_missing_alias(self): params = self.ADDR.copy() XML = u"""<device type='fake'> <address domain='{domain}' bus='{bus}' slot='{slot}' function='{function}'/> </device>""".format(**params) found_addr, found_alias = vmdevices.core.parse_device_ident( vmxml.parse_xml(XML)) self.assertEqual(found_addr, self.ADDR) self.assertEqual(found_alias, '')
def test_console_pty_properties(self, console_type, is_serial): console_xml = u'''<console type="pty"> <target port="0" type="%s" /> </console>''' % console_type dev = vmdevices.core.Console.from_xml_tree( self.log, vmxml.parse_xml(console_xml), meta={'vmid': 'VMID'} ) self.assertEqual(dev.isSerial, is_serial)
def test_pretty_format_safety(self): # Check that dom is not modified in format_xml; we check that by # comparing the exported forms of `dom' created before and after # format_xml call. xml = re.sub(' *\n *', '', self._XML) dom = vmxml.parse_xml(xml) exported_1 = etree.tostring(dom) vmxml.format_xml(dom, pretty=True) exported_2 = etree.tostring(dom) self.assertEqual(exported_1, exported_2)
def test_load_ns(self): test_xml = u'''<ovirt-vm:vm xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <ovirt-vm:version type="float">4.2</ovirt-vm:version> </ovirt-vm:vm>''' metadata_obj = metadata.Metadata( 'ovirt-vm', 'http://ovirt.org/vm/1.0' ) self.assertEqual( metadata_obj.load(vmxml.parse_xml(test_xml)), {'version': 4.2} )
def test_missing_alias(self): params = self.ADDR.copy() XML = u"""<device type='fake'> <address domain='{domain}' bus='{bus}' slot='{slot}' function='{function}'/> </device>""".format(**params) dev = vmxml.parse_xml(XML) found_addr = vmdevices.core.find_device_guest_address(dev) found_alias = vmdevices.core.find_device_alias(dev) self.assertEqual(found_addr, self.ADDR) self.assertEqual(found_alias, '')
def test_address_alias(self): params = {'alias': self.ALIAS} params.update(self.ADDR) XML = u"""<device type='fake'> <address domain='{domain}' bus='{bus}' slot='{slot}' function='{function}'/> <alias name='{alias}'/> </device>""".format(**params) found_addr, found_alias = vmdevices.core.parse_device_ident( vmxml.parse_xml(XML)) self.assertEqual(found_addr, self.ADDR) self.assertEqual(found_alias, self.ALIAS)
def dev_from_xml(vm, xml): """ Create and return device instance from provided XML. The XML must contain <devices> element with a single device subelement, the one to create the instance for. Depending on the device kind <metadata> element may be required to provide device metadata; the element may and needn't contain unrelated metadata. This function is used in device hot(un)plugs. Example `xml` value (top element tag may be arbitrary): <?xml version='1.0' encoding='UTF-8'?> <hotplug> <devices> <interface type="bridge"> <mac address="66:55:44:33:22:11"/> <model type="virtio" /> <source bridge="ovirtmgmt" /> <filterref filter="vdsm-no-mac-spoofing" /> <link state="up" /> <bandwidth /> </interface> </devices> <metadata xmlns:ns0="http://ovirt.org/vm/tune/1.0" xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <ovirt-vm:vm xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <ovirt-vm:device mac_address='66:55:44:33:22:11'> <ovirt-vm:network>test</ovirt-vm:network> <ovirt-vm:portMirroring> <ovirt-vm:network>network1</ovirt-vm:network> <ovirt-vm:network>network2</ovirt-vm:network> </ovirt-vm:portMirroring> </ovirt-vm:device> </ovirt-vm:vm> </metadata> </hotplug> :param xml: XML specifying the device as described above. :type xml: basestring :returns: Device instance created from the provided XML. """ dom = vmxml.parse_xml(xml) devices = vmxml.find_first(dom, 'devices') dev_elem = next(vmxml.children(devices)) _dev_type, dev_class = identify_from_xml_elem(dev_elem) meta = vmxml.find_first(dom, 'metadata', None) if meta is None: md_desc = metadata.Descriptor() else: md_desc = metadata.Descriptor.from_xml(vmxml.format_xml(meta)) dev_meta = _get_metadata_from_elem_xml(vm.id, md_desc, dev_class, dev_elem) return dev_class.from_xml_tree(vm.log, dev_elem, dev_meta)
def _check_roundtrip(self, klass, dev_xml, meta=None, expected_xml=None): dev = klass.from_xml_tree(self.log, vmxml.parse_xml(dev_xml), {} if meta is None else meta) dev.setup() try: rebuilt_xml = vmxml.format_xml(dev.getXML(), pretty=True) # make troubleshooting easier print(rebuilt_xml) result_xml = dev_xml if expected_xml is None else expected_xml self.assertXMLEqual(rebuilt_xml, result_xml) finally: dev.teardown()
def test_find_first_nested(self): XML = u'''<?xml version="1.0" ?> <topelement> <subelement id="1"> <subelement id="2"/> </subelement> </topelement> ''' dom = vmxml.parse_xml(XML) sub1 = vmxml.find_first(dom, 'subelement') # outermost sub2 = vmxml.find_first(sub1, 'subelement') # innermost last = vmxml.find_first(sub2, 'subelement') self.assertIsNot(sub2, last)
def test_address_alias(self): params = {'alias': self.ALIAS} params.update(self.ADDR) XML = u"""<device type='fake'> <address domain='{domain}' bus='{bus}' slot='{slot}' function='{function}'/> <alias name='{alias}'/> </device>""".format(**params) dev = vmxml.parse_xml(XML) found_addr = vmdevices.core.find_device_guest_address(dev) found_alias = vmdevices.core.find_device_alias(dev) self.assertEqual(found_addr, self.ADDR) self.assertEqual(found_alias, self.ALIAS)
def test_console_unix_socket_properties(self, console_type, is_serial): vmid = 'VMID' console_xml = u'''<console type='unix'> <source mode='bind' path='{sockpath}.sock' /> <target type='{console_type}' port='0' /> </console>'''.format(sockpath=os.path.join( constants.P_OVIRT_VMCONSOLES, vmid), console_type=console_type) dev = vmdevices.core.Console.from_xml_tree( self.log, vmxml.parse_xml(console_xml), meta={'vmid': vmid}) self.assertEqual(dev.isSerial, is_serial) self.assertEqual(dev.vmid, vmid) self.assertTrue(dev.specParams['enableSocket'])
def test_base_not_implemented(self): # simplified version of channel XML, only for test purposes. # this should never be seen in the wild generic_xml = '<channel type="spicevmc" />' try: vmdevices.core.Base.from_xml_tree(self.log, vmxml.parse_xml(generic_xml), meta={'vmid': 'VMID'}) except NotImplementedError as exc: self.assertEqual(vmdevices.core.Base.__name__, str(exc)) except Exception as ex: raise AssertionError('from_xml_tree raise unexpected %s', ex) else: raise AssertionError('from_xml_tree implemented')
def test_roundtrip_empty(self, elem_type): elem_spec = ('' if elem_type is None else 'type="{elem_type}"'.format( elem_type=elem_type)) test_xml = u'''<ovirt-vm:vm xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <ovirt-vm:param {elem_spec}/> </ovirt-vm:vm>'''.format(elem_spec=elem_spec) expected_xml = u'''<ovirt-vm:vm xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <ovirt-vm:param /> </ovirt-vm:vm>''' metadata_src = metadata.Metadata('ovirt-vm', 'http://ovirt.org/vm/1.0') metadata_dst = metadata.Metadata('ovirt-vm', 'http://ovirt.org/vm/1.0') data = metadata_src.load(vmxml.parse_xml(test_xml)) out_xml = vmxml.format_xml(metadata_dst.dump('vm', **data)) self.assertXMLEqual(out_xml, expected_xml)
def _parse_xml(self, xml_str): root = vmxml.parse_xml(xml_str) selector = '{%s}%s' % (self._namespace_uri, self._name) if root.tag == 'metadata': md_elem = root.find('./' + selector) else: md_elem = root.find('./metadata/' + selector) if md_elem is not None: md_uuid = root.find('./uuid') # UUID may not be present in hotplug/hotunplug metadata snippets uuid_text = '?' if md_uuid is None else md_uuid.text self._log.debug( 'parsing metadata for %s: %s', uuid_text, vmxml.format_xml(md_elem, pretty=True)) self._load(md_elem, self._namespace, self._namespace_uri)
def _check_roundtrip(self, klass, dev_xml, meta=None, expected_xml=None): dev = klass.from_xml_tree( self.log, vmxml.parse_xml(dev_xml), {} if meta is None else meta ) dev.setup() try: rebuilt_xml = vmxml.format_xml(dev.getXML(), pretty=True) # make troubleshooting easier print(rebuilt_xml) result_xml = dev_xml if expected_xml is None else expected_xml self.assertXMLEqual(rebuilt_xml, result_xml) finally: dev.teardown()
def _metadata_xml(dom, tag, namespace, namespace_uri): md_xml = "<{tag}/>".format(tag=tag) try: md_xml = dom.metadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, namespace_uri, 0) except libvirt.libvirtError as e: if e.get_error_code() != libvirt.VIR_ERR_NO_DOMAIN_METADATA: raise md_elem = [vmxml.parse_xml(md_xml)] # we do this because we need to receive back the updated element yield md_elem dom.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, vmxml.format_xml(md_elem[0]), namespace, namespace_uri, 0)
def test_unknown_device_from_xml_tree(self): test_xml = u'''<?xml version="1.0" encoding="utf-8"?> <domain type="kvm" xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <metadata> <ovirt-vm:vm> <ovirt-vm:version type="float">4.2</ovirt-vm:version> </ovirt-vm:vm> </metadata> </domain>''' dom = vmxml.parse_xml(test_xml) md_elem = vmxml.find_first(dom, 'metadata') self.assertIsNot(md_elem, None) self.assertEqual( metadata.device_from_xml_tree(md_elem, id='mydev'), {} )
def test_console_unix_socket_properties(self, console_type, is_serial): vmid = 'VMID' console_xml = u'''<console type='unix'> <source mode='bind' path='{sockpath}.sock' /> <target type='{console_type}' port='0' /> </console>'''.format( sockpath=os.path.join(constants.P_OVIRT_VMCONSOLES, vmid), console_type=console_type ) dev = vmdevices.core.Console.from_xml_tree( self.log, vmxml.parse_xml(console_xml), meta={'vmid': vmid} ) self.assertEqual(dev.isSerial, is_serial) self.assertEqual(dev.vmid, vmid) self.assertTrue(dev.specParams['enableSocket'])
def test_pretty_format_formatting(self): xml = re.sub(' *\n *', '', self._XML) dom = vmxml.parse_xml(xml) pretty = vmxml.format_xml(dom, pretty=True) self.assertEqual(pretty, '''<?xml version='1.0' encoding='UTF-8'?> <topelement> <hello lang="english">hello</hello> <hello cyrillic="yes" lang="русский">здра́вствуйте</hello> <bye>good bye<hello lang="čeština">dobrý den</hello> </bye> <container> <subelement /> </container> <container> <subelement>some content</subelement> </container> <empty /> </topelement> ''')
def test_pretty_format_formatting(self): xml = re.sub(' *\n *', '', self._XML) dom = vmxml.parse_xml(xml) pretty = vmxml.format_xml(dom, pretty=True) self.assertEqual( pretty, '''<?xml version='1.0' encoding='UTF-8'?> <topelement> <hello lang="english">hello</hello> <hello cyrillic="yes" lang="русский">здра́вствуйте</hello> <bye>good bye<hello lang="čeština">dobrý den</hello> </bye> <container> <subelement /> </container> <container> <subelement>some content</subelement> </container> <empty /> </topelement> ''')
def test_multiple_device_from_xml_tree(self): test_xml = u'''<?xml version="1.0" encoding="utf-8"?> <domain type="kvm" xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <metadata> <ovirt-vm:vm> <ovirt-vm:version type="float">4.2</ovirt-vm:version> <ovirt-vm:device id="dev0"> <ovirt-vm:foo>bar</ovirt-vm:foo> </ovirt-vm:device> <ovirt-vm:device id="dev1"> <ovirt-vm:number type="int">42</ovirt-vm:number> </ovirt-vm:device> </ovirt-vm:vm> </metadata> </domain>''' dom = vmxml.parse_xml(test_xml) md_elem = vmxml.find_first(dom, 'metadata') self.assertIsNot(md_elem, None) self.assertEqual( [metadata.device_from_xml_tree(md_elem, id=dev_id) for dev_id in ('dev0', 'dev1')], [{'foo': 'bar'}, {'number': 42}] )
def test_find_device_alias(self, xml_data, alias): self.assertEqual( alias, vmdevices.core.find_device_alias(vmxml.parse_xml(xml_data)))
def test_append_child_too_many_args(self): empty = vmxml.find_first(self._dom, 'empty') self.assertRaises(RuntimeError, vmxml.append_child, empty, vmxml.Element('new'), vmxml.parse_xml('<new/>'))
def test_find_device_alias(self, xml_data, alias): self.assertEqual( alias, vmdevices.core.find_device_alias(vmxml.parse_xml(xml_data)) )
def test_parse_device_type(self, xml_data, dev_type): self.assertEqual( dev_type, vmdevices.core.parse_device_type(vmxml.parse_xml(xml_data)) )
def test_attrs_partial(self): XML = u"<device foo='bar' ans='42' fizz='buzz' />" attrs = vmdevices.core.parse_device_attrs( vmxml.parse_xml(XML), ('foo', 'fizz') ) self.assertEqual(attrs, {'foo': 'bar', 'fizz': 'buzz'})
def test_attrs_missing(self): XML = u"<device type='fake' />" attrs = vmdevices.core.parse_device_attrs( vmxml.parse_xml(XML), ('type', 'foo') ) self.assertEqual(attrs, {'type': 'fake'})
def test_missing_address_alias(self): XML = u"<device type='fake' />" found_addr, found_alias = vmdevices.core.parse_device_ident( vmxml.parse_xml(XML)) self.assertIs(found_addr, None) self.assertEqual(found_alias, '')
def test_find_device_guest_address(self, xml_data, address): self.assertEqual( address, vmdevices.core.find_device_guest_address( vmxml.parse_xml(xml_data)))
def from_xml(xml_str): """ Helper function to parse the libvirt domain metadata used by oVirt form one domain XML. Useful in the VM creation flow, when the libvirt Domain is not yet started. Example: given this XML: test_xml -> <?xml version="1.0" encoding="utf-8"?> <domain type="kvm" xmlns:ovirt-vm="http://ovirt.org/vm/1.0"> <metadata> <ovirt-vm:vm> <ovirt-vm:version type="float">4.2</ovirt-vm:version> <ovirt-vm:custom> <ovirt-vm:foo>bar</ovirt-vm:foo> </ovirt-vm:custom> </ovirt-vm:vm> </metadata.> </domain> metadata.from_xml(test_xml) -> { 'version': 4.2, 'custom': { 'foo': 'bar' }, } :param xml_str: domain XML to parse :type name: text string :return: the parsed metadata :rtype: Python dict, whose keys are always strings. No nested objects are allowed, with the only exception of the special 'custom' key, whose value will be another Python dictionary whose keys are strings, with no further nesting allowed. """ metadata_obj = Metadata( xmlconstants.METADATA_VM_VDSM_PREFIX, xmlconstants.METADATA_VM_VDSM_URI ) root = vmxml.parse_xml(xml_str) md_elem = root.find( './metadata/{%s}%s' % ( xmlconstants.METADATA_VM_VDSM_URI, xmlconstants.METADATA_VM_VDSM_ELEMENT ) ) if md_elem is None: return {} md_data = metadata_obj.load(md_elem) custom_elem = root.find( './metadata/{%s}%s/{%s}custom' % ( xmlconstants.METADATA_VM_VDSM_URI, xmlconstants.METADATA_VM_VDSM_ELEMENT, xmlconstants.METADATA_VM_VDSM_URI, ) ) if custom_elem is not None: md_data['custom'] = metadata_obj.load(custom_elem) return md_data
def appendDeviceXML(self, deviceXML): self._devices.appendChild(etree_element=vmxml.parse_xml(deviceXML))
def test_append_child_etree(self): empty = vmxml.find_first(self._dom, 'empty') vmxml.append_child(empty, etree_child=vmxml.parse_xml('<new/>')) self.assertIsNotNone(vmxml.find_first(self._dom, 'new', None)) empty = vmxml.find_first(self._dom, 'empty') self.assertIsNotNone(vmxml.find_first(empty, 'new', None))
def test_parse_device_type(self, xml_data, dev_type): self.assertEqual( dev_type, vmdevices.core.parse_device_type(vmxml.parse_xml(xml_data)))
def __init__(self, xmlStr): self._dom = vmxml.parse_xml(xmlStr) self._id = self._dom.findtext('uuid') self._name = self._dom.findtext('name')
def setUp(self): self._dom = vmxml.parse_xml(self._XML)