Example #1
0
class TestXMLMatchesUnorderedExtraChildren(testtools.TestCase,
                                           helpers.TestMatchersInterface):

    matches_matcher = matchers.XMLMatches("""<?xml version="1.0"?>
<root>
  <children>
    <child1 />
    <child2 />
  </children>
</root>""",
                                          allow_mixed_nodes=True)

    matches_matches = []

    matches_mismatches = []

    describe_examples = [
        ("/root/children[0]/child2[1]: XML unexpected child element <foo> "
         "present at index 0", """<?xml version="1.0"?>
<root>
  <children>
    <child1 />
    <child2>
      <foo>subchild</foo>
    </child2>
  </children>
</root>""", matches_matcher),
    ]

    str_examples = []
Example #2
0
    def test_update_memory_backing_discard_keep(self):
        data = objects.LibvirtLiveMigrateData(
            dst_wants_file_backed_memory=True, file_backed_memory_discard=True)

        xml = """<domain>
  <memoryBacking>
    <source type="file"/>
    <access mode="shared"/>
    <allocation mode="immediate"/>
    <discard />
  </memoryBacking>
</domain>"""
        doc = etree.fromstring(xml)
        res = etree.tostring(migration._update_memory_backing_xml(doc, data),
                             encoding='unicode')

        self.assertThat(
            res,
            matchers.XMLMatches("""<domain>
  <memoryBacking>
    <source type="file"/>
    <access mode="shared"/>
    <allocation mode="immediate"/>
    <discard />
  </memoryBacking>
</domain>"""))
Example #3
0
    def _test_update_vif_xml(self, conf, original_xml, expected_xml):
        """Simulates updating the guest xml for live migrating from a host
        using OVS to a host using vhostuser as the networking backend.
        """
        vif_ovs = network_model.VIF(id=uuids.vif,
                                    address='DE:AD:BE:EF:CA:FE',
                                    details={'port_filter': False},
                                    devname='tap-xxx-yyy-zzz',
                                    ovs_interfaceid=uuids.ovs)
        source_vif = vif_ovs
        migrate_vifs = [
            objects.VIFMigrateData(
                port_id=uuids.port_id,
                vnic_type=network_model.VNIC_TYPE_NORMAL,
                vif_type=network_model.VIF_TYPE_VHOSTUSER,
                vif_details={'vhostuser_socket': '/vhost-user/test.sock'},
                profile={},
                host='dest.host',
                source_vif=source_vif)
        ]
        data = objects.LibvirtLiveMigrateData(vifs=migrate_vifs)

        get_vif_config = mock.MagicMock(return_value=conf)
        doc = etree.fromstring(original_xml)
        updated_xml = etree.tostring(migration._update_vif_xml(
            doc, data, get_vif_config),
                                     encoding='unicode')
        self.assertThat(updated_xml, matchers.XMLMatches(expected_xml))
Example #4
0
class TestXMLMatchesUnorderedNodes(testtools.TestCase,
                                   helpers.TestMatchersInterface):

    matches_matcher = matchers.XMLMatches("""<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="DONTCARE"/>
  <children>
    <child3>DONTCARE</child3>
    <!--This is a comment-->
    <child2>child 2</child2>
    <child1>child 1</child1>
    <?spam processing instruction?>
  </children>
</root>""", allow_mixed_nodes=True)

    matches_matches = ["""<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <attrs key2="spam" key1="spam"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
  <text>some other text here</text>
</root>""",
    ]

    matches_mismatches = ["""<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>mismatch text</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""",
    ]

    describe_examples = [
        ("/root: XML expected child element <text> not present at index 4",
         """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>mismatch text</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""", matches_matcher),
    ]

    str_examples = []
Example #5
0
    def test_update_volume_xml(self):
        connection_info = {
            'driver_volume_type': 'iscsi',
            'serial': '58a84f6d-3f0c-4e19-a0af-eb657b790657',
            'data': {
                'access_mode':
                'rw',
                'target_discovered':
                False,
                'target_iqn':
                'ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z',
                'volume_id':
                '58a84f6d-3f0c-4e19-a0af-eb657b790657',
                'device_path':
                '/dev/disk/by-path/ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z'
            }
        }
        bdm = objects.LibvirtLiveMigrateBDMInfo(
            serial='58a84f6d-3f0c-4e19-a0af-eb657b790657',
            bus='virtio',
            type='disk',
            dev='vdb',
            connection_info=connection_info)
        data = objects.LibvirtLiveMigrateData(target_connect_addr='127.0.0.1',
                                              bdms=[bdm],
                                              block_migration=False)
        xml = """<domain>
 <devices>
   <disk type='block' device='disk'>
     <driver name='qemu' type='raw' cache='none'/>
     <source dev='/dev/disk/by-path/ip-1.2.3.4:3260-iqn.abc.12345.opst-lun-X'/>
     <target bus='virtio' dev='vdb'/>
     <serial>58a84f6d-3f0c-4e19-a0af-eb657b790657</serial>
     <address type='pci' domain='0x0' bus='0x0' slot='0x04' function='0x0'/>
   </disk>
 </devices>
</domain>"""
        conf = vconfig.LibvirtConfigGuestDisk()
        conf.source_device = bdm.type
        conf.driver_name = "qemu"
        conf.driver_format = "raw"
        conf.driver_cache = "none"
        conf.target_dev = bdm.dev
        conf.target_bus = bdm.bus
        conf.serial = bdm.connection_info.get('serial')
        conf.source_type = "block"
        conf.source_path = bdm.connection_info['data'].get('device_path')

        get_volume_config = mock.MagicMock(return_value=conf)
        doc = etree.fromstring(xml)
        res = etree.tostring(migration._update_volume_xml(
            doc, data, get_volume_config),
                             encoding='unicode')
        new_xml = xml.replace('ip-1.2.3.4:3260-iqn.abc.12345.opst-lun-X',
                              'ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z')
        self.assertThat(res, matchers.XMLMatches(new_xml))
Example #6
0
    def test_update_perf_events_xml_add_new_events(self):
        data = objects.LibvirtLiveMigrateData(
            supported_perf_events=['cmt'])
        xml = """<domain>
</domain>"""
        doc = etree.fromstring(xml)
        res = etree.tostring(migration._update_perf_events_xml(doc, data))

        self.assertThat(res, matchers.XMLMatches("""<domain>
<perf><event enabled="yes" name="cmt"/></perf></domain>"""))
Example #7
0
    def test_update_serial_xml_serial(self):
        data = objects.LibvirtLiveMigrateData(serial_listen_addr='127.0.0.100')
        xml = """<domain>
  <devices>
    <serial type="tcp">
      <source host="127.0.0.1"/>
    </serial>
  </devices>
</domain>"""
        doc = etree.fromstring(xml)
        res = etree.tostring(migration._update_serial_xml(doc, data))
        new_xml = xml.replace("127.0.0.1", "127.0.0.100")
        self.assertThat(res, matchers.XMLMatches(new_xml))
Example #8
0
    def test_update_serial_xml_serial(self):
        data = objects.LibvirtLiveMigrateData(serial_listen_addr='127.0.0.100',
                                              serial_listen_ports=[2001])
        xml = """<domain>
  <devices>
    <serial type="tcp">
      <source host="127.0.0.1" service="2000"/>
      <target type="serial" port="0"/>
    </serial>
  </devices>
</domain>"""
        doc = etree.fromstring(xml)
        res = etree.tostring(migration._update_serial_xml(doc, data),
                             encoding='unicode')
        new_xml = xml.replace("127.0.0.1",
                              "127.0.0.100").replace("2000", "2001")
        self.assertThat(res, matchers.XMLMatches(new_xml))
Example #9
0
    def test_update_graphics(self):
        data = objects.LibvirtLiveMigrateData(
            graphics_listen_addr_vnc='127.0.0.100',
            graphics_listen_addr_spice='127.0.0.200')
        xml = """<domain>
  <devices>
    <graphics type="vnc">
      <listen type="address" address="127.0.0.1"/>
    </graphics>
    <graphics type="spice">
      <listen type="address" address="127.0.0.2"/>
    </graphics>
  </devices>
</domain>"""
        doc = etree.fromstring(xml)
        res = etree.tostring(migration._update_graphics_xml(doc, data))
        new_xml = xml.replace("127.0.0.1", "127.0.0.100")
        new_xml = new_xml.replace("127.0.0.2", "127.0.0.200")
        self.assertThat(res, matchers.XMLMatches(new_xml))
    def test_update_serial_xml_without_ports(self):
        # This test is for backwards compatibility when we don't
        # get the serial ports from the target node.
        data = objects.LibvirtLiveMigrateData(serial_listen_addr='127.0.0.100',
                                              serial_listen_ports=[])
        xml = """<domain>
  <devices>
    <console type="tcp">
      <source host="127.0.0.1" service="2001"/>
      <target type="serial" port="0"/>
    </console>
    <console type="tcp">
      <source host="127.0.0.1" service="2002"/>
      <target type="serial" port="1"/>
    </console>
  </devices>
</domain>"""
        doc = etree.fromstring(xml)
        res = etree.tostring(migration._update_serial_xml(doc, data))
        new_xml = xml.replace("127.0.0.1", "127.0.0.100")
        self.assertThat(res, matchers.XMLMatches(new_xml))
    def test_update_serial_xml_console(self):
        data = objects.LibvirtLiveMigrateData(serial_listen_addr='127.0.0.100',
                                              serial_listen_ports=[299, 300])
        xml = """<domain>
  <devices>
    <console type="tcp">
      <source host="127.0.0.1" service="2001"/>
      <target type="serial" port="0"/>
    </console>
    <console type="tcp">
      <source host="127.0.0.1" service="2002"/>
      <target type="serial" port="1"/>
    </console>
  </devices>
</domain>"""
        doc = etree.fromstring(xml)
        res = etree.tostring(migration._update_serial_xml(doc, data))
        new_xml = xml.replace("127.0.0.1", "127.0.0.100").replace(
            "2001", "299").replace("2002", "300")

        self.assertThat(res, matchers.XMLMatches(new_xml))
Example #12
0
 def assertXmlEqual(self, expected, observed, **options):
     self.assertThat(observed, matchers.XMLMatches(expected, **options))
Example #13
0
class TestXMLMatches(testtools.TestCase, helpers.TestMatchersInterface):

    matches_matcher = matchers.XMLMatches("""<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="DONTCARE"/>
  <children>
    <!--This is a comment-->
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>DONTCARE</child3>
    <?spam processing instruction?>
  </children>
</root>""",
                                          allow_mixed_nodes=False)

    matches_matches = [
        """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key2="spam" key1="spam"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""",
        """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="quux"/>
  <children><child1>child 1</child1>
<child2>child 2</child2>
<child3>blah</child3>
  </children>
</root>""",
    ]

    matches_mismatches = [
        """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>mismatch text</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""",
        """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key3="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""",
        """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="quux" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""",
        """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child4>child 4</child4>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""",
        """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
  </children>
</root>""",
        """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
    <child4>child 4</child4>
  </children>
</root>""",
        """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="DONTCARE"/>
  <children>
    <!--This is a comment-->
    <child2>child 2</child2>
    <child1>child 1</child1>
    <child3>DONTCARE</child3>
    <?spam processing instruction?>
  </children>
</root>""",
        """<?xml version="1.1"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="DONTCARE"/>
  <children>
    <!--This is a comment-->
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>DONTCARE</child3>
    <?spam processing instruction?>
  </children>
</root>""",
    ]

    str_examples = [
        ("XMLMatches('<?xml version=\"1.0\"?>\\n"
         "<root>\\n"
         "  <text>some text here</text>\\n"
         "  <text>some other text here</text>\\n"
         "  <attrs key1=\"spam\" key2=\"DONTCARE\"/>\\n"
         "  <children>\\n"
         "    <!--This is a comment-->\\n"
         "    <child1>child 1</child1>\\n"
         "    <child2>child 2</child2>\\n"
         "    <child3>DONTCARE</child3>\\n"
         "    <?spam processing instruction?>\\n"
         "  </children>\\n"
         "</root>')", matches_matcher),
    ]

    describe_examples = [
        ("/root/text[1]: XML text value mismatch: expected text value: "
         "['some other text here']; actual value: ['mismatch text']",
         """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>mismatch text</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""", matches_matcher),
        ("/root/attrs[2]: XML attributes mismatch: keys only in expected: "
         "key2; keys only in actual: key3", """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key3="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""", matches_matcher),
        ("/root/attrs[2]: XML attribute value mismatch: expected value of "
         "attribute key1: 'spam'; actual value: 'quux'",
         """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="quux" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""", matches_matcher),
        ("/root/children[3]: XML tag mismatch at index 1: expected tag "
         "<child2>; actual tag <child4>", """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child4>child 4</child4>
    <child2>child 2</child2>
    <child3>child 3</child3>
  </children>
</root>""", matches_matcher),
        ("/root/children[3]: XML expected child element <child3> not "
         "present at index 2", """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
  </children>
</root>""", matches_matcher),
        ("/root/children[3]: XML unexpected child element <child4> "
         "present at index 3", """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>child 3</child3>
    <child4>child 4</child4>
  </children>
</root>""", matches_matcher),
        ("/root/children[3]: XML tag mismatch at index 0: "
         "expected tag <child1>; actual tag <child2>", """<?xml version="1.0"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="quux"/>
  <children>
    <child2>child 2</child2>
    <child1>child 1</child1>
    <child3>child 3</child3>
  </children>
</root>""", matches_matcher),
        ("/: XML information mismatch(version, encoding) "
         "expected version 1.0, expected encoding UTF-8; "
         "actual version 1.1, actual encoding UTF-8", """<?xml version="1.1"?>
<root>
  <text>some text here</text>
  <text>some other text here</text>
  <attrs key1="spam" key2="DONTCARE"/>
  <children>
    <!--This is a comment-->
    <child1>child 1</child1>
    <child2>child 2</child2>
    <child3>DONTCARE</child3>
    <?spam processing instruction?>
  </children>
</root>""", matches_matcher),
    ]
Example #14
0
    def test_update_vif_xml(self):
        """Simulates updating the guest xml for live migrating from a host
        using OVS to a host using vhostuser as the networking backend.
        """
        vif_ovs = network_model.VIF(id=uuids.vif,
                                    address='DE:AD:BE:EF:CA:FE',
                                    details={'port_filter': False},
                                    devname='tap-xxx-yyy-zzz',
                                    ovs_interfaceid=uuids.ovs)
        source_vif = vif_ovs
        migrate_vifs = [
            objects.VIFMigrateData(
                port_id=uuids.port_id,
                vnic_type=network_model.VNIC_TYPE_NORMAL,
                vif_type=network_model.VIF_TYPE_VHOSTUSER,
                vif_details={'vhostuser_socket': '/vhost-user/test.sock'},
                profile={},
                host='dest.host',
                source_vif=source_vif)
        ]
        data = objects.LibvirtLiveMigrateData(vifs=migrate_vifs)

        original_xml = """<domain>
 <uuid>3de6550a-8596-4937-8046-9d862036bca5</uuid>
 <devices>
    <interface type="bridge">
        <mac address="DE:AD:BE:EF:CA:FE"/>
        <model type="virtio"/>
        <source bridge="qbra188171c-ea"/>
        <target dev="tapa188171c-ea"/>
        <virtualport type="openvswitch">
            <parameters interfaceid="%s"/>
        </virtualport>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x04'
                 function='0x0'/>
    </interface>
 </devices>
</domain>""" % uuids.ovs

        conf = vconfig.LibvirtConfigGuestInterface()
        conf.net_type = "vhostuser"
        conf.vhostuser_type = "unix"
        conf.vhostuser_mode = "server"
        conf.mac_addr = "DE:AD:BE:EF:CA:FE"
        conf.vhostuser_path = "/vhost-user/test.sock"
        conf.model = "virtio"

        get_vif_config = mock.MagicMock(return_value=conf)
        doc = etree.fromstring(original_xml)
        updated_xml = etree.tostring(migration._update_vif_xml(
            doc, data, get_vif_config),
                                     encoding='unicode')

        # Note that <target> and <virtualport> are dropped from the ovs source
        # interface xml since they aren't applicable to the vhostuser
        # destination interface xml. The type attribute value changes and the
        # hardware address element is retained.
        expected_xml = """<domain>
 <uuid>3de6550a-8596-4937-8046-9d862036bca5</uuid>
 <devices>
    <interface type="vhostuser">
        <mac address="DE:AD:BE:EF:CA:FE"/>
        <model type="virtio"/>
        <source mode="server" path="/vhost-user/test.sock" type="unix"/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x04'
                 function='0x0'/>
    </interface>
 </devices>
</domain>"""
        self.assertThat(updated_xml, matchers.XMLMatches(expected_xml))
Example #15
0
    def test_update_volume_xml_update_encryption(self):
        connection_info = {
            'driver_volume_type': 'rbd',
            'serial': 'd299a078-f0db-4993-bf03-f10fe44fd192',
            'data': {
                'access_mode': 'rw',
                'secret_type': 'ceph',
                'name': 'cinder-volumes/volume-d299a078',
                'encrypted': False,
                'discard': True,
                'cluster_name': 'ceph',
                'secret_uuid': '1a790a26-dd49-4825-8d16-3dd627cf05a9',
                'qos_specs': None,
                'auth_enabled': True,
                'volume_id': 'd299a078-f0db-4993-bf03-f10fe44fd192',
                'hosts': ['172.16.128.101', '172.16.128.121'],
                'auth_username': '******',
                'ports': ['6789', '6789', '6789']
            }
        }
        bdm = objects.LibvirtLiveMigrateBDMInfo(
            serial='d299a078-f0db-4993-bf03-f10fe44fd192',
            bus='scsi',
            type='disk',
            dev='sdb',
            connection_info=connection_info,
            encryption_secret_uuid=uuids.encryption_secret_uuid_new)
        data = objects.LibvirtLiveMigrateData(target_connect_addr=None,
                                              bdms=[bdm],
                                              block_migration=False)
        xml = """<domain>
 <devices>
    <disk type='network' device='disk'>
      <driver name='qemu' type='raw' cache='writeback' discard='unmap'/>
      <auth username='******'>
        <secret type='ceph' uuid='1a790a26-dd49-4825-8d16-3dd627cf05a9'/>
      </auth>
      <source protocol='rbd' name='cinder-volumes/volume-d299a078'>
        <host name='172.16.128.101' port='6789'/>
        <host name='172.16.128.121' port='6789'/>
      </source>
      <backingStore/>
      <target dev='sdb' bus='scsi'/>
      <serial>d299a078-f0db-4993-bf03-f10fe44fd192</serial>
      <alias name='scsi0-0-0-1'/>
      <encryption format='luks'>
        <secret type='passphrase' uuid='%(encryption_secret_uuid)s'/>
      </encryption>
      <address type='drive' controller='0' bus='0' target='0' unit='1'/>
    </disk>
 </devices>
</domain>""" % {
            'encryption_secret_uuid': uuids.encryption_secret_uuid_old
        }
        conf = vconfig.LibvirtConfigGuestDisk()
        conf.source_device = bdm.type
        conf.driver_name = "qemu"
        conf.driver_format = "raw"
        conf.driver_cache = "writeback"
        conf.target_dev = bdm.dev
        conf.target_bus = bdm.bus
        conf.serial = bdm.connection_info.get('serial')
        conf.source_type = "network"
        conf.driver_discard = 'unmap'
        conf.device_addr = vconfig.LibvirtConfigGuestDeviceAddressDrive()
        conf.device_addr.controller = 0

        get_volume_config = mock.MagicMock(return_value=conf)
        doc = etree.fromstring(xml)
        res = etree.tostring(migration._update_volume_xml(
            doc, data, get_volume_config),
                             encoding='unicode')
        new_xml = xml.replace(uuids.encryption_secret_uuid_old,
                              uuids.encryption_secret_uuid_new)
        self.assertThat(res, matchers.XMLMatches(new_xml))
Example #16
0
    def test_pci_devices_generation(self):
        def _cmp_pci_dev_addr(dev_xml, cmp_addr):
            cfgdev = vconfig.LibvirtConfigNodeDevice()
            cfgdev.parse_str(dev_xml)

            address = "%04x:%02x:%02x.%1x" % (
                cfgdev.pci_capability.domain, cfgdev.pci_capability.bus,
                cfgdev.pci_capability.slot, cfgdev.pci_capability.function)
            self.assertEqual(cmp_addr, address)

        pf_xml = """<device>
  <name>pci_0000_81_00_0</name>
  <path>/sys/devices/pci0000:80/0000:80:01.0/0000:81:00.0</path>
  <parent>pci_0000_80_01_0</parent>
  <driver>
    <name>ixgbe</name>
  </driver>
  <capability type='pci'>
    <domain>0</domain>
    <bus>129</bus>
    <slot>0</slot>
    <function>0</function>
    <product id='0x1528'>Ethernet Controller 10-Gigabit X540-AT2</product>
    <vendor id='0x8086'>Intel Corporation</vendor>
    <capability type='virt_functions'>
      <address domain='0x0000' bus='0x81' slot='0x0' function='0x1'/>
    </capability>
    <iommuGroup number='40'>
      <address domain='0x0000' bus='0x81' slot='0x0' function='0x0'/>
    </iommuGroup>
    <numa node='0'/>
    <pci-express>
      <link validity='cap' port='0' speed='5' width='8'/>
      <link validity='sta' speed='5' width='8'/>
    </pci-express>
  </capability>
</device>"""
        vf_xml = """<device>
  <name>pci_0000_81_00_1</name>
  <path>/sys/devices/pci0000:80/0000:80:01.0/0000:81:00.1</path>
  <parent>pci_0000_80_01_0</parent>
  <driver>
    <name>ixgbevf</name>
  </driver>
  <capability type='pci'>
    <domain>0</domain>
    <bus>129</bus>
    <slot>0</slot>
    <function>1</function>
    <product id='0x1515'>X540 Ethernet Controller Virtual Function</product>
    <vendor id='0x8086'>Intel Corporation</vendor>
    <capability type='phys_function'>
      <address domain='0x0000' bus='0x81' slot='0x0' function='0x0'/>
    </capability>
    <iommuGroup number='41'>
      <address domain='0x0000' bus='0x81' slot='0x0' function='0x1'/>
    </iommuGroup>
    <numa node='0'/>
    <pci-express>
      <link validity='cap' port='0' speed='5' width='8'/>
      <link validity='sta' speed='5' width='8'/>
    </pci-express>
  </capability>
</device>"""

        # create fake pci devices
        pci_info = libvirt.HostPCIDevicesInfo(num_pfs=1, num_vfs=1)

        # generate xml for the created pci devices
        gen_pf = pci_info.get_device_by_name('pci_0000_81_00_0')
        gen_vf = pci_info.get_device_by_name('pci_0000_81_00_1')

        self.assertThat(gen_pf.XMLDesc(0), matchers.XMLMatches(pf_xml))
        self.assertThat(gen_vf.XMLDesc(0), matchers.XMLMatches(vf_xml))

        # parse the generated xml with a libvirt config class and compare
        # device address
        _cmp_pci_dev_addr(pf_xml, '0000:81:00.0')
        _cmp_pci_dev_addr(vf_xml, '0000:81:00.1')