"Fossies" - the Fresh Open Source Software Archive

Member "nova-22.0.1/nova/tests/unit/virt/libvirt/fakelibvirt.py" (19 Nov 2020, 64443 Bytes) of package /linux/misc/openstack/nova-22.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "fakelibvirt.py": 22.0.0_vs_22.0.1.

    1 #    Copyright 2010 OpenStack Foundation
    2 #
    3 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    4 #    not use this file except in compliance with the License. You may obtain
    5 #    a copy of the License at
    6 #
    7 #         http://www.apache.org/licenses/LICENSE-2.0
    8 #
    9 #    Unless required by applicable law or agreed to in writing, software
   10 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   11 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   12 #    License for the specific language governing permissions and limitations
   13 #    under the License.
   14 
   15 import sys
   16 import textwrap
   17 import time
   18 import typing as ty
   19 
   20 import fixtures
   21 from lxml import etree
   22 from oslo_log import log as logging
   23 from oslo_utils.fixture import uuidsentinel as uuids
   24 from oslo_utils import versionutils
   25 
   26 from nova import conf
   27 from nova.objects import fields as obj_fields
   28 from nova.tests.unit.virt.libvirt import fake_libvirt_data
   29 from nova.virt.libvirt import config as vconfig
   30 from nova.virt.libvirt import driver as libvirt_driver
   31 
   32 
   33 # Allow passing None to the various connect methods
   34 # (i.e. allow the client to rely on default URLs)
   35 allow_default_uri_connection = True
   36 
   37 # Has libvirt connection been used at least once
   38 connection_used = False
   39 
   40 
   41 def _reset():
   42     global allow_default_uri_connection
   43     allow_default_uri_connection = True
   44 
   45 
   46 LOG = logging.getLogger(__name__)
   47 CONF = conf.CONF
   48 
   49 # virDomainState
   50 VIR_DOMAIN_NOSTATE = 0
   51 VIR_DOMAIN_RUNNING = 1
   52 VIR_DOMAIN_BLOCKED = 2
   53 VIR_DOMAIN_PAUSED = 3
   54 VIR_DOMAIN_SHUTDOWN = 4
   55 VIR_DOMAIN_SHUTOFF = 5
   56 VIR_DOMAIN_CRASHED = 6
   57 
   58 # NOTE(mriedem): These values come from include/libvirt/libvirt-domain.h
   59 VIR_DOMAIN_XML_SECURE = 1
   60 VIR_DOMAIN_XML_INACTIVE = 2
   61 VIR_DOMAIN_XML_UPDATE_CPU = 4
   62 VIR_DOMAIN_XML_MIGRATABLE = 8
   63 
   64 VIR_DOMAIN_BLOCK_REBASE_SHALLOW = 1
   65 VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT = 2
   66 VIR_DOMAIN_BLOCK_REBASE_COPY = 8
   67 VIR_DOMAIN_BLOCK_REBASE_RELATIVE = 16
   68 VIR_DOMAIN_BLOCK_REBASE_COPY_DEV = 32
   69 
   70 # virDomainBlockResize
   71 VIR_DOMAIN_BLOCK_RESIZE_BYTES = 1
   72 
   73 VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC = 1
   74 VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT = 2
   75 
   76 VIR_DOMAIN_EVENT_ID_LIFECYCLE = 0
   77 
   78 VIR_DOMAIN_EVENT_DEFINED = 0
   79 VIR_DOMAIN_EVENT_UNDEFINED = 1
   80 VIR_DOMAIN_EVENT_STARTED = 2
   81 VIR_DOMAIN_EVENT_SUSPENDED = 3
   82 VIR_DOMAIN_EVENT_RESUMED = 4
   83 VIR_DOMAIN_EVENT_STOPPED = 5
   84 VIR_DOMAIN_EVENT_SHUTDOWN = 6
   85 VIR_DOMAIN_EVENT_PMSUSPENDED = 7
   86 
   87 VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED = 1
   88 VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY = 7
   89 
   90 VIR_DOMAIN_UNDEFINE_MANAGED_SAVE = 1
   91 VIR_DOMAIN_UNDEFINE_NVRAM = 4
   92 
   93 VIR_DOMAIN_AFFECT_CURRENT = 0
   94 VIR_DOMAIN_AFFECT_LIVE = 1
   95 VIR_DOMAIN_AFFECT_CONFIG = 2
   96 
   97 VIR_CPU_COMPARE_ERROR = -1
   98 VIR_CPU_COMPARE_INCOMPATIBLE = 0
   99 VIR_CPU_COMPARE_IDENTICAL = 1
  100 VIR_CPU_COMPARE_SUPERSET = 2
  101 
  102 VIR_CRED_USERNAME = 1
  103 VIR_CRED_AUTHNAME = 2
  104 VIR_CRED_LANGUAGE = 3
  105 VIR_CRED_CNONCE = 4
  106 VIR_CRED_PASSPHRASE = 5
  107 VIR_CRED_ECHOPROMPT = 6
  108 VIR_CRED_NOECHOPROMPT = 7
  109 VIR_CRED_REALM = 8
  110 VIR_CRED_EXTERNAL = 9
  111 
  112 VIR_MIGRATE_LIVE = 1
  113 VIR_MIGRATE_PEER2PEER = 2
  114 VIR_MIGRATE_TUNNELLED = 4
  115 VIR_MIGRATE_PERSIST_DEST = 8
  116 VIR_MIGRATE_UNDEFINE_SOURCE = 16
  117 VIR_MIGRATE_NON_SHARED_INC = 128
  118 VIR_MIGRATE_AUTO_CONVERGE = 8192
  119 VIR_MIGRATE_POSTCOPY = 32768
  120 VIR_MIGRATE_TLS = 65536
  121 
  122 VIR_NODE_CPU_STATS_ALL_CPUS = -1
  123 
  124 VIR_DOMAIN_START_PAUSED = 1
  125 
  126 # libvirtError enums
  127 # (Intentionally different from what's in libvirt. We do this to check,
  128 #  that consumers of the library are using the symbolic names rather than
  129 #  hardcoding the numerical values)
  130 VIR_FROM_QEMU = 100
  131 VIR_FROM_DOMAIN = 200
  132 VIR_FROM_SECRET = 300
  133 VIR_FROM_NWFILTER = 330
  134 VIR_FROM_REMOTE = 340
  135 VIR_FROM_RPC = 345
  136 VIR_FROM_NODEDEV = 666
  137 
  138 VIR_ERR_INVALID_ARG = 8
  139 VIR_ERR_NO_SUPPORT = 3
  140 VIR_ERR_XML_ERROR = 27
  141 VIR_ERR_XML_DETAIL = 350
  142 VIR_ERR_NO_DOMAIN = 420
  143 VIR_ERR_OPERATION_FAILED = 510
  144 VIR_ERR_OPERATION_INVALID = 55
  145 VIR_ERR_OPERATION_TIMEOUT = 68
  146 VIR_ERR_NO_NWFILTER = 620
  147 VIR_ERR_SYSTEM_ERROR = 900
  148 VIR_ERR_INTERNAL_ERROR = 950
  149 VIR_ERR_CONFIG_UNSUPPORTED = 951
  150 VIR_ERR_NO_NODE_DEVICE = 667
  151 VIR_ERR_INVALID_SECRET = 65
  152 VIR_ERR_NO_SECRET = 66
  153 VIR_ERR_AGENT_UNRESPONSIVE = 86
  154 VIR_ERR_ARGUMENT_UNSUPPORTED = 74
  155 VIR_ERR_OPERATION_UNSUPPORTED = 84
  156 VIR_ERR_DEVICE_MISSING = 99
  157 # Readonly
  158 VIR_CONNECT_RO = 1
  159 
  160 # virConnectBaselineCPU flags
  161 VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES = 1
  162 
  163 # snapshotCreateXML flags
  164 VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA = 4
  165 VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY = 16
  166 VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT = 32
  167 VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE = 64
  168 
  169 # blockCommit flags
  170 VIR_DOMAIN_BLOCK_COMMIT_RELATIVE = 4
  171 
  172 
  173 VIR_CONNECT_LIST_DOMAINS_ACTIVE = 1
  174 VIR_CONNECT_LIST_DOMAINS_INACTIVE = 2
  175 
  176 # virConnectListAllNodeDevices flags
  177 VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV = 2
  178 VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET = 16
  179 
  180 # secret type
  181 VIR_SECRET_USAGE_TYPE_NONE = 0
  182 VIR_SECRET_USAGE_TYPE_VOLUME = 1
  183 VIR_SECRET_USAGE_TYPE_CEPH = 2
  184 VIR_SECRET_USAGE_TYPE_ISCSI = 3
  185 
  186 # Libvirt version to match MIN_LIBVIRT_VERSION in driver.py
  187 FAKE_LIBVIRT_VERSION = versionutils.convert_version_to_int(
  188     libvirt_driver.MIN_LIBVIRT_VERSION)
  189 # Libvirt version to match MIN_QEMU_VERSION in driver.py
  190 FAKE_QEMU_VERSION = versionutils.convert_version_to_int(
  191     libvirt_driver.MIN_QEMU_VERSION)
  192 
  193 PCI_VEND_ID = '8086'
  194 PCI_VEND_NAME = 'Intel Corporation'
  195 
  196 PCI_PROD_ID = '1533'
  197 PCI_PROD_NAME = 'I210 Gigabit Network Connection'
  198 PCI_DRIVER_NAME = 'igb'
  199 
  200 PF_PROD_ID = '1528'
  201 PF_PROD_NAME = 'Ethernet Controller 10-Gigabit X540-AT2'
  202 PF_DRIVER_NAME = 'ixgbe'
  203 PF_CAP_TYPE = 'virt_functions'
  204 
  205 VF_PROD_ID = '1515'
  206 VF_PROD_NAME = 'X540 Ethernet Controller Virtual Function'
  207 VF_DRIVER_NAME = 'ixgbevf'
  208 VF_CAP_TYPE = 'phys_function'
  209 
  210 MDEV_CAPABLE_VEND_ID = '10DE'
  211 MDEV_CAPABLE_VEND_NAME = 'Nvidia'
  212 MDEV_CAPABLE_PROD_ID = '0FFE'
  213 MDEV_CAPABLE_PROD_NAME = 'GRID M60-0B'
  214 MDEV_CAPABLE_DRIVER_NAME = 'nvidia'
  215 MDEV_CAPABLE_CAP_TYPE = 'mdev_types'
  216 
  217 NVIDIA_11_VGPU_TYPE = 'nvidia-11'
  218 NVIDIA_12_VGPU_TYPE = 'nvidia-12'
  219 PGPU1_PCI_ADDR = 'pci_0000_81_00_0'
  220 PGPU2_PCI_ADDR = 'pci_0000_81_01_0'
  221 PGPU3_PCI_ADDR = 'pci_0000_81_02_0'
  222 
  223 
  224 class FakePCIDevice(object):
  225     """Generate a fake PCI device.
  226 
  227     Generate a fake PCI devices corresponding to one of the following
  228     real-world PCI devices.
  229 
  230     - I210 Gigabit Network Connection (8086:1533)
  231     - Ethernet Controller 10-Gigabit X540-AT2 (8086:1528)
  232     - X540 Ethernet Controller Virtual Function (8086:1515)
  233     """
  234 
  235     pci_default_parent = "pci_0000_80_01_0"
  236     pci_device_template = textwrap.dedent("""
  237         <device>
  238           <name>pci_0000_81_%(slot)02x_%(function)d</name>
  239           <path>/sys/devices/pci0000:80/0000:80:01.0/0000:81:%(slot)02x.%(function)d</path>
  240           <parent>%(parent)s</parent>
  241           <driver>
  242             <name>%(driver)s</name>
  243           </driver>
  244           <capability type='pci'>
  245             <domain>0</domain>
  246             <bus>129</bus>
  247             <slot>%(slot)d</slot>
  248             <function>%(function)d</function>
  249             <product id='0x%(prod_id)s'>%(prod_name)s</product>
  250             <vendor id='0x%(vend_id)s'>%(vend_name)s</vendor>
  251         %(capability)s
  252             <iommuGroup number='%(iommu_group)d'>
  253               <address domain='0x0000' bus='0x81' slot='%(slot)#02x' function='0x%(function)d'/>
  254             </iommuGroup>
  255             <numa node='%(numa_node)s'/>
  256             <pci-express>
  257               <link validity='cap' port='0' speed='5' width='8'/>
  258               <link validity='sta' speed='5' width='8'/>
  259             </pci-express>
  260           </capability>
  261         </device>""".strip())  # noqa
  262     cap_templ = "<capability type='%(cap_type)s'>%(addresses)s</capability>"
  263     addr_templ = "<address domain='0x0000' bus='0x81' slot='%(slot)#02x' function='%(function)#02x'/>"  # noqa
  264     mdevtypes_templ = textwrap.dedent("""
  265         <type id='%(type_id)s'>
  266         <name>GRID M60-0B</name><deviceAPI>vfio-pci</deviceAPI>
  267         <availableInstances>%(instances)s</availableInstances>
  268         </type>""".strip())  # noqa
  269 
  270     is_capable_of_mdevs = False
  271 
  272     def __init__(self, dev_type, slot, function, iommu_group, numa_node,
  273                  vf_ratio=None, multiple_gpu_types=False, parent=None):
  274         """Populate pci devices
  275 
  276         :param dev_type: (string) Indicates the type of the device (PCI, PF,
  277             VF).
  278         :param slot: (int) Slot number of the device.
  279         :param function: (int) Function number of the device.
  280         :param iommu_group: (int) IOMMU group ID.
  281         :param numa_node: (int) NUMA node of the device.
  282         :param vf_ratio: (int) Ratio of Virtual Functions on Physical. Only
  283             applicable if ``dev_type`` is one of: ``PF``, ``VF``.
  284         :param multiple_gpu_types: (bool) Supports different vGPU types
  285         """
  286 
  287         self.dev_type = dev_type
  288         self.slot = slot
  289         self.function = function
  290         self.iommu_group = iommu_group
  291         self.numa_node = numa_node
  292         self.vf_ratio = vf_ratio
  293         self.multiple_gpu_types = multiple_gpu_types
  294         self.parent = parent
  295         self.generate_xml()
  296 
  297     def generate_xml(self, skip_capability=False):
  298         vend_id = PCI_VEND_ID
  299         vend_name = PCI_VEND_NAME
  300         capability = ''
  301         if self.dev_type == 'PCI':
  302             if self.vf_ratio:
  303                 raise ValueError('vf_ratio does not apply for PCI devices')
  304 
  305             prod_id = PCI_PROD_ID
  306             prod_name = PCI_PROD_NAME
  307             driver = PCI_DRIVER_NAME
  308         elif self.dev_type == 'PF':
  309             prod_id = PF_PROD_ID
  310             prod_name = PF_PROD_NAME
  311             driver = PF_DRIVER_NAME
  312             if not skip_capability:
  313                 capability = self.cap_templ % {
  314                     'cap_type': PF_CAP_TYPE,
  315                     'addresses': '\n'.join([
  316                         self.addr_templ % {
  317                             # these are the slot, function values of the child
  318                             # VFs, we can only assign 8 functions to a slot
  319                             # (0-7) so bump the slot each time we exceed this
  320                             'slot': self.slot + (x // 8),
  321                             # ...and wrap the function value
  322                             'function': x % 8,
  323                         # the offset is because the PF is occupying function 0
  324                         } for x in range(1, self.vf_ratio + 1)])
  325                 }
  326         elif self.dev_type == 'VF':
  327             prod_id = VF_PROD_ID
  328             prod_name = VF_PROD_NAME
  329             driver = VF_DRIVER_NAME
  330             if not skip_capability:
  331                 capability = self.cap_templ % {
  332                     'cap_type': VF_CAP_TYPE,
  333                     'addresses': self.addr_templ % {
  334                         # this is the slot, function value of the parent PF
  335                         # if we're e.g. device 8, we'll have a different slot
  336                         # to our parent so reverse this
  337                         'slot': self.slot - ((self.vf_ratio + 1) // 8),
  338                         # the parent PF is always function 0
  339                         'function': 0,
  340                     }
  341                 }
  342         elif self.dev_type == 'MDEV_TYPES':
  343             prod_id = MDEV_CAPABLE_PROD_ID
  344             prod_name = MDEV_CAPABLE_PROD_NAME
  345             driver = MDEV_CAPABLE_DRIVER_NAME
  346             vend_id = MDEV_CAPABLE_VEND_ID
  347             vend_name = MDEV_CAPABLE_VEND_NAME
  348             types = [self.mdevtypes_templ % {
  349                 'type_id': NVIDIA_11_VGPU_TYPE,
  350                 'instances': 16,
  351             }]
  352             if self.multiple_gpu_types:
  353                 types.append(self.mdevtypes_templ % {
  354                     'type_id': NVIDIA_12_VGPU_TYPE,
  355                     'instances': 8,
  356                 })
  357             if not skip_capability:
  358                 capability = self.cap_templ % {
  359                     'cap_type': MDEV_CAPABLE_CAP_TYPE,
  360                     'addresses': '\n'.join(types)
  361                 }
  362             self.is_capable_of_mdevs = True
  363         else:
  364             raise ValueError('Expected one of: PCI, VF, PCI')
  365 
  366         self.pci_device = self.pci_device_template % {
  367             'slot': self.slot,
  368             'function': self.function,
  369             'vend_id': vend_id,
  370             'vend_name': vend_name,
  371             'prod_id': prod_id,
  372             'prod_name': prod_name,
  373             'driver': driver,
  374             'capability': capability,
  375             'iommu_group': self.iommu_group,
  376             'numa_node': self.numa_node,
  377             'parent': self.parent or self.pci_default_parent
  378         }
  379         # -1 is the sentinel set in /sys/bus/pci/devices/*/numa_node
  380         # for no NUMA affinity. When the numa_node is set to -1 on a device
  381         # Libvirt omits the NUMA element so we remove it.
  382         if self.numa_node == -1:
  383             self.pci_device = self.pci_device.replace("<numa node='-1'/>", "")
  384 
  385     def XMLDesc(self, flags):
  386         return self.pci_device
  387 
  388 
  389 class HostPCIDevicesInfo(object):
  390     """Represent a pool of host PCI devices."""
  391 
  392     TOTAL_NUMA_NODES = 2
  393     pci_devname_template = 'pci_0000_81_%(slot)02x_%(function)d'
  394 
  395     def __init__(self, num_pci=0, num_pfs=2, num_vfs=8, num_mdevcap=0,
  396                  numa_node=None, multiple_gpu_types=False):
  397         """Create a new HostPCIDevicesInfo object.
  398 
  399         :param num_pci: (int) The number of (non-SR-IOV) and (non-MDEV capable)
  400             PCI devices.
  401         :param num_pfs: (int) The number of PCI SR-IOV Physical Functions.
  402         :param num_vfs: (int) The number of PCI SR-IOV Virtual Functions.
  403         :param num_mdevcap: (int) The number of PCI devices capable of creating
  404             mediated devices.
  405         :param iommu_group: (int) Initial IOMMU group ID.
  406         :param numa_node: (int) NUMA node of the device; if set all of the
  407             devices will be assigned to the specified node else they will be
  408             split between ``$TOTAL_NUMA_NODES`` nodes.
  409         :param multiple_gpu_types: (bool) Supports different vGPU types
  410         """
  411         self.devices = {}
  412 
  413         if not (num_vfs or num_pfs) and not num_mdevcap:
  414             return
  415 
  416         if num_vfs and not num_pfs:
  417             raise ValueError('Cannot create VFs without PFs')
  418 
  419         if num_pfs and num_vfs % num_pfs:
  420             raise ValueError('num_vfs must be a factor of num_pfs')
  421 
  422         slot = 0
  423         function = 0
  424         iommu_group = 40  # totally arbitrary number
  425 
  426         # Generate PCI devs
  427         for dev in range(num_pci):
  428             pci_dev_name = self.pci_devname_template % {
  429                 'slot': slot, 'function': function}
  430 
  431             LOG.info('Generating PCI device %r', pci_dev_name)
  432 
  433             self.devices[pci_dev_name] = FakePCIDevice(
  434                 dev_type='PCI',
  435                 slot=slot,
  436                 function=function,
  437                 iommu_group=iommu_group,
  438                 numa_node=self._calc_numa_node(dev, numa_node))
  439 
  440             slot += 1
  441             iommu_group += 1
  442 
  443         # Generate MDEV capable devs
  444         for dev in range(num_mdevcap):
  445             pci_dev_name = self.pci_devname_template % {
  446                 'slot': slot, 'function': function}
  447 
  448             LOG.info('Generating MDEV capable device %r', pci_dev_name)
  449 
  450             self.devices[pci_dev_name] = FakePCIDevice(
  451                 dev_type='MDEV_TYPES',
  452                 slot=slot,
  453                 function=function,
  454                 iommu_group=iommu_group,
  455                 numa_node=self._calc_numa_node(dev, numa_node),
  456                 multiple_gpu_types=multiple_gpu_types)
  457 
  458             slot += 1
  459             iommu_group += 1
  460 
  461         vf_ratio = num_vfs // num_pfs if num_pfs else 0
  462 
  463         # Generate PFs
  464         for dev in range(num_pfs):
  465             function = 0
  466             numa_node_pf = self._calc_numa_node(dev, numa_node)
  467 
  468             pci_dev_name = self.pci_devname_template % {
  469                 'slot': slot, 'function': function}
  470 
  471             LOG.info('Generating PF device %r', pci_dev_name)
  472 
  473             self.devices[pci_dev_name] = FakePCIDevice(
  474                 dev_type='PF',
  475                 slot=slot,
  476                 function=function,
  477                 iommu_group=iommu_group,
  478                 numa_node=numa_node_pf,
  479                 vf_ratio=vf_ratio)
  480             pf_dev_name = pci_dev_name
  481             # Generate VFs
  482             for _ in range(vf_ratio):
  483                 function += 1
  484                 iommu_group += 1
  485 
  486                 if function % 8 == 0:
  487                     # functions must be 0-7
  488                     slot += 1
  489                     function = 0
  490 
  491                 pci_dev_name = self.pci_devname_template % {
  492                     'slot': slot, 'function': function}
  493 
  494                 LOG.info('Generating VF device %r', pci_dev_name)
  495 
  496                 self.devices[pci_dev_name] = FakePCIDevice(
  497                     dev_type='VF',
  498                     slot=slot,
  499                     function=function,
  500                     iommu_group=iommu_group,
  501                     numa_node=numa_node_pf,
  502                     vf_ratio=vf_ratio,
  503                     parent=pf_dev_name)
  504 
  505             slot += 1
  506 
  507     @classmethod
  508     def _calc_numa_node(cls, dev, numa_node):
  509         return dev % cls.TOTAL_NUMA_NODES if numa_node is None else numa_node
  510 
  511     def get_all_devices(self):
  512         return self.devices.keys()
  513 
  514     def get_device_by_name(self, device_name):
  515         pci_dev = self.devices.get(device_name)
  516         return pci_dev
  517 
  518     def get_all_mdev_capable_devices(self):
  519         return [dev for dev in self.devices
  520                 if self.devices[dev].is_capable_of_mdevs]
  521 
  522 
  523 class FakeMdevDevice(object):
  524     template = """
  525     <device>
  526       <name>%(dev_name)s</name>
  527       <path>/sys/devices/pci0000:00/0000:00:02.0/%(path)s</path>
  528       <parent>%(parent)s</parent>
  529       <driver>
  530         <name>vfio_mdev</name>
  531       </driver>
  532       <capability type='mdev'>
  533         <type id='%(type_id)s'/>
  534         <iommuGroup number='12'/>
  535       </capability>
  536     </device>
  537     """
  538 
  539     def __init__(self, dev_name, type_id, parent):
  540         self.xml = self.template % {
  541             'dev_name': dev_name, 'type_id': type_id,
  542             'path': dev_name[len('mdev_'):],
  543             'parent': parent}
  544 
  545     def XMLDesc(self, flags):
  546         return self.xml
  547 
  548 
  549 class HostMdevDevicesInfo(object):
  550     def __init__(self, devices=None):
  551         if devices is not None:
  552             self.devices = devices
  553         else:
  554             self.devices = {}
  555 
  556     def get_all_devices(self):
  557         return self.devices.keys()
  558 
  559     def get_device_by_name(self, device_name):
  560         dev = self.devices[device_name]
  561         return dev
  562 
  563 
  564 class HostInfo(object):
  565 
  566     def __init__(self, cpu_nodes=1, cpu_sockets=1, cpu_cores=2, cpu_threads=1,
  567                  kB_mem=4096, mempages=None):
  568         """Create a new Host Info object
  569 
  570         :param cpu_nodes: (int) the number of NUMA cell, 1 for unusual
  571                           NUMA topologies or uniform
  572         :param cpu_sockets: (int) number of CPU sockets per node if nodes > 1,
  573                             total number of CPU sockets otherwise
  574         :param cpu_cores: (int) number of cores per socket
  575         :param cpu_threads: (int) number of threads per core
  576         :param kB_mem: (int) memory size in KBytes
  577         """
  578 
  579         self.arch = obj_fields.Architecture.X86_64
  580         self.kB_mem = kB_mem
  581         self.cpus = cpu_nodes * cpu_sockets * cpu_cores * cpu_threads
  582         self.cpu_mhz = 800
  583         self.cpu_nodes = cpu_nodes
  584         self.cpu_cores = cpu_cores
  585         self.cpu_threads = cpu_threads
  586         self.cpu_sockets = cpu_sockets
  587         self.cpu_model = "Penryn"
  588         self.cpu_vendor = "Intel"
  589         self.numa_topology = NUMATopology(self.cpu_nodes, self.cpu_sockets,
  590                                           self.cpu_cores, self.cpu_threads,
  591                                           self.kB_mem, mempages)
  592 
  593 
  594 class NUMATopology(vconfig.LibvirtConfigCapsNUMATopology):
  595     """A batteries-included variant of LibvirtConfigCapsNUMATopology.
  596 
  597     Provides sane defaults for LibvirtConfigCapsNUMATopology that can be used
  598     in tests as is, or overridden where necessary.
  599     """
  600 
  601     def __init__(self, cpu_nodes=4, cpu_sockets=1, cpu_cores=1, cpu_threads=2,
  602                  kb_mem=1048576, mempages=None, **kwargs):
  603 
  604         super(NUMATopology, self).__init__(**kwargs)
  605 
  606         cpu_count = 0
  607         for cell_count in range(cpu_nodes):
  608             cell = vconfig.LibvirtConfigCapsNUMACell()
  609             cell.id = cell_count
  610             cell.memory = kb_mem // cpu_nodes
  611             for socket_count in range(cpu_sockets):
  612                 for cpu_num in range(cpu_cores * cpu_threads):
  613                     cpu = vconfig.LibvirtConfigCapsNUMACPU()
  614                     cpu.id = cpu_count
  615                     cpu.socket_id = cell_count
  616                     cpu.core_id = cpu_num // cpu_threads
  617                     cpu.siblings = set([cpu_threads *
  618                                        (cpu_count // cpu_threads) + thread
  619                                         for thread in range(cpu_threads)])
  620                     cell.cpus.append(cpu)
  621 
  622                     cpu_count += 1
  623 
  624             # If no mempages are provided, use only the default 4K pages
  625             if mempages:
  626                 cell.mempages = mempages[cell_count]
  627             else:
  628                 cell.mempages = create_mempages([(4, cell.memory // 4)])
  629 
  630             self.cells.append(cell)
  631 
  632 
  633 def create_mempages(mappings):
  634     """Generate a list of LibvirtConfigCapsNUMAPages objects.
  635 
  636     :param mappings: (dict) A mapping of page size to quantity of
  637         said pages.
  638     :returns: [LibvirtConfigCapsNUMAPages, ...]
  639     """
  640     mempages = []
  641 
  642     for page_size, page_qty in mappings:
  643         mempage = vconfig.LibvirtConfigCapsNUMAPages()
  644         mempage.size = page_size
  645         mempage.total = page_qty
  646         mempages.append(mempage)
  647 
  648     return mempages
  649 
  650 
  651 VIR_DOMAIN_JOB_NONE = 0
  652 VIR_DOMAIN_JOB_BOUNDED = 1
  653 VIR_DOMAIN_JOB_UNBOUNDED = 2
  654 VIR_DOMAIN_JOB_COMPLETED = 3
  655 VIR_DOMAIN_JOB_FAILED = 4
  656 VIR_DOMAIN_JOB_CANCELLED = 5
  657 
  658 
  659 def _parse_disk_info(element):
  660     disk_info = {}
  661     disk_info['type'] = element.get('type', 'file')
  662     disk_info['device'] = element.get('device', 'disk')
  663 
  664     driver = element.find('./driver')
  665     if driver is not None:
  666         disk_info['driver_name'] = driver.get('name')
  667         disk_info['driver_type'] = driver.get('type')
  668 
  669     source = element.find('./source')
  670     if source is not None:
  671         disk_info['source'] = source.get('file')
  672         if not disk_info['source']:
  673             disk_info['source'] = source.get('dev')
  674 
  675         if not disk_info['source']:
  676             disk_info['source'] = source.get('path')
  677 
  678     target = element.find('./target')
  679     if target is not None:
  680         disk_info['target_dev'] = target.get('dev')
  681         disk_info['target_bus'] = target.get('bus')
  682 
  683     return disk_info
  684 
  685 
  686 def _parse_nic_info(element):
  687     nic_info = {}
  688     nic_info['type'] = element.get('type', 'bridge')
  689 
  690     driver = element.find('./mac')
  691     if driver is not None:
  692         nic_info['mac'] = driver.get('address')
  693 
  694     source = element.find('./source')
  695     if source is not None:
  696         nic_info['source'] = source.get('bridge')
  697 
  698     target = element.find('./target')
  699     if target is not None:
  700         nic_info['target_dev'] = target.get('dev')
  701 
  702     return nic_info
  703 
  704 
  705 def disable_event_thread(self):
  706     """Disable nova libvirt driver event thread.
  707 
  708     The Nova libvirt driver includes a native thread which monitors
  709     the libvirt event channel. In a testing environment this becomes
  710     problematic because it means we've got a floating thread calling
  711     sleep(1) over the life of the unit test. Seems harmless? It's not,
  712     because we sometimes want to test things like retry loops that
  713     should have specific sleep paterns. An unlucky firing of the
  714     libvirt thread will cause a test failure.
  715 
  716     """
  717     # because we are patching a method in a class MonkeyPatch doesn't
  718     # auto import correctly. Import explicitly otherwise the patching
  719     # may silently fail.
  720     import nova.virt.libvirt.host  # noqa
  721 
  722     def evloop(*args, **kwargs):
  723         pass
  724 
  725     self.useFixture(fixtures.MockPatch(
  726         'nova.virt.libvirt.host.Host._init_events',
  727         side_effect=evloop))
  728 
  729 
  730 class libvirtError(Exception):
  731     """This class was copied and slightly modified from
  732     `libvirt-python:libvirt-override.py`.
  733 
  734     Since a test environment will use the real `libvirt-python` version of
  735     `libvirtError` if it's installed and not this fake, we need to maintain
  736     strict compatibility with the original class, including `__init__` args
  737     and instance-attributes.
  738 
  739     To create a libvirtError instance you should:
  740 
  741         # Create an unsupported error exception
  742         exc = libvirtError('my message')
  743         exc.err = (libvirt.VIR_ERR_NO_SUPPORT,)
  744 
  745     self.err is a tuple of form:
  746         (error_code, error_domain, error_message, error_level, str1, str2,
  747          str3, int1, int2)
  748 
  749     Alternatively, you can use the `make_libvirtError` convenience function to
  750     allow you to specify these attributes in one shot.
  751     """
  752     def __init__(self, defmsg, conn=None, dom=None, net=None, pool=None,
  753                  vol=None):
  754         Exception.__init__(self, defmsg)
  755         self.err = None
  756 
  757     def get_error_code(self):
  758         if self.err is None:
  759             return None
  760         return self.err[0]
  761 
  762     def get_error_domain(self):
  763         if self.err is None:
  764             return None
  765         return self.err[1]
  766 
  767     def get_error_message(self):
  768         if self.err is None:
  769             return None
  770         return self.err[2]
  771 
  772     def get_error_level(self):
  773         if self.err is None:
  774             return None
  775         return self.err[3]
  776 
  777     def get_str1(self):
  778         if self.err is None:
  779             return None
  780         return self.err[4]
  781 
  782     def get_str2(self):
  783         if self.err is None:
  784             return None
  785         return self.err[5]
  786 
  787     def get_str3(self):
  788         if self.err is None:
  789             return None
  790         return self.err[6]
  791 
  792     def get_int1(self):
  793         if self.err is None:
  794             return None
  795         return self.err[7]
  796 
  797     def get_int2(self):
  798         if self.err is None:
  799             return None
  800         return self.err[8]
  801 
  802 
  803 class NodeDevice(object):
  804 
  805     def __init__(self, connection, xml=None):
  806         self._connection = connection
  807 
  808         self._xml = xml
  809         if xml is not None:
  810             self._parse_xml(xml)
  811 
  812     def _parse_xml(self, xml):
  813         tree = etree.fromstring(xml)
  814         root = tree.find('.')
  815         self._name = root.find('name').text
  816         self._parent = root.find('parent').text
  817 
  818     def attach(self):
  819         pass
  820 
  821     def dettach(self):
  822         pass
  823 
  824     def reset(self):
  825         pass
  826 
  827     def XMLDesc(self, flags: int) -> str:
  828         return self._xml
  829 
  830     def parent(self) -> str:
  831         return self._parent
  832 
  833     def name(self) -> str:
  834         return self._name
  835 
  836     def listCaps(self) -> ty.List[str]:
  837         return [self.name().split('_')[0]]
  838 
  839 
  840 class Domain(object):
  841     def __init__(self, connection, xml, running=False, transient=False):
  842         self._connection = connection
  843         if running:
  844             connection._mark_running(self)
  845 
  846         self._state = running and VIR_DOMAIN_RUNNING or VIR_DOMAIN_SHUTOFF
  847         self._transient = transient
  848         self._def = self._parse_definition(xml)
  849         self._has_saved_state = False
  850         self._snapshots = {}
  851         self._id = self._connection._id_counter
  852         self._job_type = VIR_DOMAIN_JOB_UNBOUNDED
  853 
  854     def _parse_definition(self, xml):
  855         try:
  856             tree = etree.fromstring(xml)
  857         except etree.ParseError:
  858             raise make_libvirtError(
  859                     libvirtError, "Invalid XML.",
  860                     error_code=VIR_ERR_XML_DETAIL,
  861                     error_domain=VIR_FROM_DOMAIN)
  862 
  863         definition = {}
  864 
  865         name = tree.find('./name')
  866         if name is not None:
  867             definition['name'] = name.text
  868 
  869         uuid_elem = tree.find('./uuid')
  870         if uuid_elem is not None:
  871             definition['uuid'] = uuid_elem.text
  872         else:
  873             definition['uuid'] = uuids.fake
  874 
  875         vcpu = tree.find('./vcpu')
  876         if vcpu is not None:
  877             definition['vcpu'] = int(vcpu.text)
  878 
  879         memory = tree.find('./memory')
  880         if memory is not None:
  881             definition['memory'] = int(memory.text)
  882 
  883         os = {}
  884         os_type = tree.find('./os/type')
  885         if os_type is not None:
  886             os['type'] = os_type.text
  887             os['arch'] = os_type.get('arch', self._connection.host_info.arch)
  888 
  889         os_kernel = tree.find('./os/kernel')
  890         if os_kernel is not None:
  891             os['kernel'] = os_kernel.text
  892 
  893         os_initrd = tree.find('./os/initrd')
  894         if os_initrd is not None:
  895             os['initrd'] = os_initrd.text
  896 
  897         os_cmdline = tree.find('./os/cmdline')
  898         if os_cmdline is not None:
  899             os['cmdline'] = os_cmdline.text
  900 
  901         os_boot = tree.find('./os/boot')
  902         if os_boot is not None:
  903             os['boot_dev'] = os_boot.get('dev')
  904 
  905         definition['os'] = os
  906 
  907         features = {}
  908 
  909         acpi = tree.find('./features/acpi')
  910         if acpi is not None:
  911             features['acpi'] = True
  912 
  913         definition['features'] = features
  914 
  915         cpu_pins = {}
  916 
  917         pins = tree.findall('./cputune/vcpupin')
  918         for pin in pins:
  919             cpu_pins[pin.get('vcpu')] = pin.get('cpuset')
  920 
  921         definition['cpu_pins'] = cpu_pins
  922 
  923         emulator_pin = tree.find('./cputune/emulatorpin')
  924         if emulator_pin is not None:
  925             definition['emulator_pin'] = emulator_pin.get('cpuset')
  926 
  927         memnodes = {}
  928 
  929         for node in tree.findall('./numatune/memnode'):
  930             memnodes[node.get('cellid')] = node.get('nodeset')
  931 
  932         definition['memnodes'] = memnodes
  933 
  934         devices = {}
  935 
  936         device_nodes = tree.find('./devices')
  937         if device_nodes is not None:
  938             disks_info = []
  939             disks = device_nodes.findall('./disk')
  940             for disk in disks:
  941                 disks_info += [_parse_disk_info(disk)]
  942             devices['disks'] = disks_info
  943 
  944             nics_info = []
  945             nics = device_nodes.findall('./interface')
  946             for nic in nics:
  947                 nic_info = {}
  948                 nic_info['type'] = nic.get('type')
  949 
  950                 mac = nic.find('./mac')
  951                 if mac is not None:
  952                     nic_info['mac'] = mac.get('address')
  953 
  954                 source = nic.find('./source')
  955                 if source is not None:
  956                     if nic_info['type'] == 'network':
  957                         nic_info['source'] = source.get('network')
  958                     elif nic_info['type'] == 'bridge':
  959                         nic_info['source'] = source.get('bridge')
  960                     elif nic_info['type'] == 'hostdev':
  961                         # <interface type='hostdev'> is for VF when vnic_type
  962                         # is direct. Add sriov vf pci information in nic_info
  963                         address = source.find('./address')
  964                         pci_type = address.get('type')
  965                         pci_domain = address.get('domain').replace('0x', '')
  966                         pci_bus = address.get('bus').replace('0x', '')
  967                         pci_slot = address.get('slot').replace('0x', '')
  968                         pci_function = address.get('function').replace(
  969                             '0x', '')
  970                         pci_device = "%s_%s_%s_%s_%s" % (pci_type, pci_domain,
  971                                                          pci_bus, pci_slot,
  972                                                          pci_function)
  973                         nic_info['source'] = pci_device
  974 
  975                 nics_info += [nic_info]
  976 
  977             devices['nics'] = nics_info
  978 
  979             hostdev_info = []
  980             hostdevs = device_nodes.findall('./hostdev')
  981             for hostdev in hostdevs:
  982                 address = hostdev.find('./source/address')
  983                 # NOTE(gibi): only handle mdevs as pci is complicated
  984                 dev_type = hostdev.get('type')
  985                 if dev_type == 'mdev':
  986                     hostdev_info.append({
  987                         'type': dev_type,
  988                         'model': hostdev.get('model'),
  989                         'address_uuid': address.get('uuid')
  990                     })
  991             devices['hostdevs'] = hostdev_info
  992 
  993             vpmem_info = []
  994             vpmems = device_nodes.findall('./memory')
  995             for vpmem in vpmems:
  996                 model = vpmem.get('model')
  997                 if model == 'nvdimm':
  998                     source = vpmem.find('./source')
  999                     target = vpmem.find('./target')
 1000                     path = source.find('./path').text
 1001                     alignsize = source.find('./alignsize').text
 1002                     size = target.find('./size').text
 1003                     node = target.find('./node').text
 1004                     vpmem_info.append({
 1005                         'path': path,
 1006                         'size': size,
 1007                         'alignsize': alignsize,
 1008                         'node': node})
 1009             devices['vpmems'] = vpmem_info
 1010 
 1011         definition['devices'] = devices
 1012 
 1013         return definition
 1014 
 1015     def verify_hostdevs_interface_are_vfs(self):
 1016         """Verify for interface type hostdev if the pci device is VF or not.
 1017         """
 1018 
 1019         error_message = ("Interface type hostdev is currently supported on "
 1020                          "SR-IOV Virtual Functions only")
 1021 
 1022         nics = self._def['devices'].get('nics', [])
 1023         for nic in nics:
 1024             if nic['type'] == 'hostdev':
 1025                 pci_device = nic['source']
 1026                 pci_info_from_connection = self._connection.pci_info.devices[
 1027                     pci_device]
 1028                 if 'phys_function' not in pci_info_from_connection.pci_device:
 1029                     raise make_libvirtError(
 1030                         libvirtError,
 1031                         error_message,
 1032                         error_code=VIR_ERR_CONFIG_UNSUPPORTED,
 1033                         error_domain=VIR_FROM_DOMAIN)
 1034 
 1035     def create(self):
 1036         self.createWithFlags(0)
 1037 
 1038     def createWithFlags(self, flags):
 1039         # FIXME: Not handling flags at the moment
 1040         self.verify_hostdevs_interface_are_vfs()
 1041         self._state = VIR_DOMAIN_RUNNING
 1042         self._connection._mark_running(self)
 1043         self._has_saved_state = False
 1044 
 1045     def isActive(self):
 1046         return int(self._state == VIR_DOMAIN_RUNNING)
 1047 
 1048     def undefine(self):
 1049         self._connection._undefine(self)
 1050 
 1051     def isPersistent(self):
 1052         return True
 1053 
 1054     def undefineFlags(self, flags):
 1055         self.undefine()
 1056         if flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE:
 1057             if self.hasManagedSaveImage(0):
 1058                 self.managedSaveRemove()
 1059 
 1060     def destroy(self):
 1061         self._state = VIR_DOMAIN_SHUTOFF
 1062         self._connection._mark_not_running(self)
 1063 
 1064     def ID(self):
 1065         return self._id
 1066 
 1067     def name(self):
 1068         return self._def['name']
 1069 
 1070     def UUIDString(self):
 1071         return self._def['uuid']
 1072 
 1073     def interfaceStats(self, device):
 1074         return [10000242400, 1234, 0, 2, 213412343233, 34214234, 23, 3]
 1075 
 1076     def blockStats(self, device):
 1077         return [2, 10000242400, 234, 2343424234, 34]
 1078 
 1079     def setTime(self, time=None, flags=0):
 1080         pass
 1081 
 1082     def suspend(self):
 1083         self._state = VIR_DOMAIN_PAUSED
 1084 
 1085     def shutdown(self):
 1086         self._state = VIR_DOMAIN_SHUTDOWN
 1087         self._connection._mark_not_running(self)
 1088 
 1089     def reset(self, flags):
 1090         # FIXME: Not handling flags at the moment
 1091         self._state = VIR_DOMAIN_RUNNING
 1092         self._connection._mark_running(self)
 1093 
 1094     def info(self):
 1095         return [self._state,
 1096                 int(self._def['memory']),
 1097                 int(self._def['memory']),
 1098                 self._def['vcpu'],
 1099                 123456789]
 1100 
 1101     def migrateToURI3(self, dconnuri, params, flags):
 1102         raise make_libvirtError(
 1103                 libvirtError,
 1104                 "Migration always fails for fake libvirt!",
 1105                 error_code=VIR_ERR_INTERNAL_ERROR,
 1106                 error_domain=VIR_FROM_QEMU)
 1107 
 1108     def migrateSetMaxDowntime(self, downtime):
 1109         pass
 1110 
 1111     def attachDevice(self, xml):
 1112         result = False
 1113         if xml.startswith("<disk"):
 1114             disk_info = _parse_disk_info(etree.fromstring(xml))
 1115             disk_info['_attached'] = True
 1116             self._def['devices']['disks'] += [disk_info]
 1117             result = True
 1118         elif xml.startswith("<interface"):
 1119             nic_info = _parse_nic_info(etree.fromstring(xml))
 1120             nic_info['_attached'] = True
 1121             self._def['devices']['nics'] += [nic_info]
 1122             result = True
 1123 
 1124         return result
 1125 
 1126     def attachDeviceFlags(self, xml, flags):
 1127         if (flags & VIR_DOMAIN_AFFECT_LIVE and
 1128                 self._state != VIR_DOMAIN_RUNNING):
 1129             raise make_libvirtError(
 1130                 libvirtError,
 1131                 "AFFECT_LIVE only allowed for running domains!",
 1132                 error_code=VIR_ERR_INTERNAL_ERROR,
 1133                 error_domain=VIR_FROM_QEMU)
 1134         self.attachDevice(xml)
 1135 
 1136     def detachDevice(self, xml):
 1137         disk_info = _parse_disk_info(etree.fromstring(xml))
 1138         disk_info['_attached'] = True
 1139         return disk_info in self._def['devices']['disks']
 1140 
 1141     def detachDeviceFlags(self, xml, flags):
 1142         self.detachDevice(xml)
 1143 
 1144     def setUserPassword(self, user, password, flags=0):
 1145         pass
 1146 
 1147     def XMLDesc(self, flags):
 1148         disks = ''
 1149         for disk in self._def['devices']['disks']:
 1150             if disk['type'] == 'file':
 1151                 source_attr = 'file'
 1152             else:
 1153                 source_attr = 'dev'
 1154 
 1155             disks += '''<disk type='%(type)s' device='%(device)s'>
 1156       <driver name='%(driver_name)s' type='%(driver_type)s'/>
 1157       <source %(source_attr)s='%(source)s'/>
 1158       <target dev='%(target_dev)s' bus='%(target_bus)s'/>
 1159       <address type='drive' controller='0' bus='0' unit='0'/>
 1160     </disk>''' % dict(source_attr=source_attr, **disk)
 1161 
 1162         nics = ''
 1163         for nic in self._def['devices']['nics']:
 1164             if 'source' in nic and nic['type'] != 'hostdev':
 1165                 nics += '''<interface type='%(type)s'>
 1166           <mac address='%(mac)s'/>
 1167           <source %(type)s='%(source)s'/>
 1168           <target dev='tap274487d1-60'/>
 1169           <address type='pci' domain='0x0000' bus='0x00' slot='0x03'
 1170                    function='0x0'/>
 1171         </interface>''' % nic
 1172             # this covers for direct nic type
 1173             else:
 1174                 nics += '''<interface type='%(type)s'>
 1175           <mac address='%(mac)s'/>
 1176           <source>
 1177               <address type='pci' domain='0x0000' bus='0x81' slot='0x00'
 1178                    function='0x01'/>
 1179           </source>
 1180         </interface>''' % nic
 1181 
 1182         hostdevs = ''
 1183         for hostdev in self._def['devices']['hostdevs']:
 1184             hostdevs += '''<hostdev mode='subsystem' type='%(type)s' model='%(model)s'>
 1185     <source>
 1186       <address uuid='%(address_uuid)s'/>
 1187     </source>
 1188     </hostdev>
 1189             ''' % hostdev  # noqa
 1190 
 1191         vpmems = ''
 1192         for vpmem in self._def['devices']['vpmems']:
 1193             vpmems += '''
 1194     <memory model='nvdimm' access='shared'>
 1195       <source>
 1196         <path>%(path)s</path>
 1197         <alignsize>%(alignsize)s</alignsize>
 1198         <pmem/>
 1199       </source>
 1200       <target>
 1201         <size>%(size)s</size>
 1202         <node>%(node)s</node>
 1203         <label>
 1204           <size>2097152</size>
 1205         </label>
 1206       </target>
 1207     </memory>
 1208             ''' % vpmem
 1209         cputune = ''
 1210         for vcpu, cpuset in self._def['cpu_pins'].items():
 1211             cputune += '<vcpupin vcpu="%d" cpuset="%s"/>' % (int(vcpu), cpuset)
 1212         emulatorpin = None
 1213         if 'emulator_pin' in self._def:
 1214             emulatorpin = ('<emulatorpin cpuset="%s"/>' %
 1215                            self._def['emulator_pin'])
 1216         if cputune or emulatorpin:
 1217             cputune = '<cputune>%s%s</cputune>' % (emulatorpin, cputune)
 1218 
 1219         numatune = ''
 1220         for cellid, nodeset in self._def['memnodes'].items():
 1221             numatune += '<memnode cellid="%d" nodeset="%s"/>' % (int(cellid),
 1222                                                                  nodeset)
 1223             numatune += '<memory nodeset="%s"/>' % ','.join(
 1224                 self._def['memnodes'].values())
 1225         if numatune:
 1226             numatune = '<numatune>%s</numatune>' % numatune
 1227 
 1228         serial_console = ''
 1229         if CONF.serial_console.enabled:
 1230             serial_console = """<serial type="tcp">
 1231                 <source host="-1" service="-1" mode="bind"/>
 1232                 </serial>"""
 1233 
 1234         return '''<domain type='kvm'>
 1235   <name>%(name)s</name>
 1236   <uuid>%(uuid)s</uuid>
 1237   <memory>%(memory)s</memory>
 1238   <currentMemory>%(memory)s</currentMemory>
 1239   <vcpu>%(vcpu)s</vcpu>
 1240   <os>
 1241     <type arch='%(arch)s' machine='pc-0.12'>hvm</type>
 1242     <boot dev='hd'/>
 1243   </os>
 1244   <features>
 1245     <acpi/>
 1246     <apic/>
 1247     <pae/>
 1248   </features>
 1249   <clock offset='localtime'/>
 1250   <on_poweroff>destroy</on_poweroff>
 1251   <on_reboot>restart</on_reboot>
 1252   <on_crash>restart</on_crash>
 1253   %(cputune)s
 1254   %(numatune)s
 1255   <devices>
 1256     <emulator>/usr/bin/kvm</emulator>
 1257     %(disks)s
 1258     <controller type='ide' index='0'>
 1259       <address type='pci' domain='0x0000' bus='0x00' slot='0x01'
 1260                function='0x1'/>
 1261     </controller>
 1262     %(nics)s
 1263     %(serial_console)s
 1264     <console type='file'>
 1265       <source path='dummy.log'/>
 1266       <target port='0'/>
 1267     </console>
 1268     <input type='tablet' bus='usb'/>
 1269     <input type='mouse' bus='ps2'/>
 1270     <graphics type='vnc' port='-1' autoport='yes'/>
 1271     <graphics type='spice' port='-1' autoport='yes'/>
 1272     <video>
 1273       <model type='cirrus' vram='9216' heads='1'/>
 1274       <address type='pci' domain='0x0000' bus='0x00' slot='0x02'
 1275                function='0x0'/>
 1276     </video>
 1277     <memballoon model='virtio'>
 1278       <address type='pci' domain='0x0000' bus='0x00' slot='0x04'
 1279                function='0x0'/>
 1280     </memballoon>
 1281     %(hostdevs)s
 1282     %(vpmems)s
 1283   </devices>
 1284 </domain>''' % {'name': self._def['name'],
 1285                 'uuid': self._def['uuid'],
 1286                 'memory': self._def['memory'],
 1287                 'vcpu': self._def['vcpu'],
 1288                 'arch': self._def['os']['arch'],
 1289                 'disks': disks,
 1290                 'nics': nics,
 1291                 'hostdevs': hostdevs,
 1292                 'vpmems': vpmems,
 1293                 'serial_console': serial_console,
 1294                 'cputune': cputune,
 1295                 'numatune': numatune}
 1296 
 1297     def managedSave(self, flags):
 1298         self._connection._mark_not_running(self)
 1299         self._has_saved_state = True
 1300 
 1301     def managedSaveRemove(self, flags):
 1302         self._has_saved_state = False
 1303 
 1304     def hasManagedSaveImage(self, flags):
 1305         return int(self._has_saved_state)
 1306 
 1307     def resume(self):
 1308         self._state = VIR_DOMAIN_RUNNING
 1309 
 1310     def snapshotCreateXML(self, xml, flags):
 1311         tree = etree.fromstring(xml)
 1312         name = tree.find('./name').text
 1313         snapshot = DomainSnapshot(name, self)
 1314         self._snapshots[name] = snapshot
 1315         return snapshot
 1316 
 1317     def vcpus(self):
 1318         vcpus = ([], [])
 1319         for i in range(0, self._def['vcpu']):
 1320             vcpus[0].append((i, 1, 120405, i))
 1321             vcpus[1].append((True, True, True, True))
 1322         return vcpus
 1323 
 1324     def memoryStats(self):
 1325         return {}
 1326 
 1327     def maxMemory(self):
 1328         return self._def['memory']
 1329 
 1330     def blockJobInfo(self, disk, flags):
 1331         return {}
 1332 
 1333     def blockJobAbort(self, disk, flags):
 1334         pass
 1335 
 1336     def blockResize(self, disk, size, flags):
 1337         pass
 1338 
 1339     def blockRebase(self, disk, base, bandwidth=0, flags=0):
 1340         if (not base) and (flags and VIR_DOMAIN_BLOCK_REBASE_RELATIVE):
 1341             raise make_libvirtError(
 1342                     libvirtError,
 1343                     'flag VIR_DOMAIN_BLOCK_REBASE_RELATIVE is '
 1344                     'valid only with non-null base',
 1345                     error_code=VIR_ERR_INVALID_ARG,
 1346                     error_domain=VIR_FROM_QEMU)
 1347         return 0
 1348 
 1349     def blockCommit(self, disk, base, top, flags):
 1350         return 0
 1351 
 1352     def jobInfo(self):
 1353         # NOTE(danms): This is an array of 12 integers, so just report
 1354         # something to avoid an IndexError if we look at this
 1355         return [0] * 12
 1356 
 1357     def jobStats(self, flags=0):
 1358         # NOTE(artom) By returning VIR_DOMAIN_JOB_UNBOUNDED, we're pretending a
 1359         # job is constantly running. Tests are expected to call the
 1360         # complete_job or fail_job methods when they're ready for jobs (read:
 1361         # live migrations) to "complete".
 1362         return {'type': self._job_type}
 1363 
 1364     def complete_job(self):
 1365         self._job_type = VIR_DOMAIN_JOB_COMPLETED
 1366 
 1367     def fail_job(self):
 1368         self._job_type = VIR_DOMAIN_JOB_FAILED
 1369 
 1370     def injectNMI(self, flags=0):
 1371         return 0
 1372 
 1373     def abortJob(self):
 1374         pass
 1375 
 1376     def fsFreeze(self):
 1377         pass
 1378 
 1379     def fsThaw(self):
 1380         pass
 1381 
 1382 
 1383 class DomainSnapshot(object):
 1384     def __init__(self, name, domain):
 1385         self._name = name
 1386         self._domain = domain
 1387 
 1388     def delete(self, flags):
 1389         del self._domain._snapshots[self._name]
 1390 
 1391 
 1392 class Secret(object):
 1393     def __init__(self, connection, xml):
 1394         self._connection = connection
 1395         self._xml = xml
 1396         self._parse_xml(xml)
 1397         self._value = None
 1398 
 1399     def _parse_xml(self, xml):
 1400         tree = etree.fromstring(xml)
 1401         self._uuid = tree.find('./uuid').text
 1402         self._private = tree.get('private') == 'yes'
 1403 
 1404     def setValue(self, value, flags=0):
 1405         self._value = value
 1406         return 0
 1407 
 1408     def value(self, flags=0):
 1409         if self._value is None:
 1410             raise make_libvirtError(
 1411                 libvirtError,
 1412                 "secret '%s' does not have a value" % self._uuid,
 1413                 error_code=VIR_ERR_NO_SECRET,
 1414                 error_domain=VIR_FROM_SECRET)
 1415             pass
 1416 
 1417         if self._private:
 1418             raise make_libvirtError(
 1419                 libvirtError,
 1420                 'secret is private',
 1421                 error_code=VIR_ERR_INVALID_SECRET,
 1422                 error_domain=VIR_FROM_SECRET)
 1423 
 1424         return self._value
 1425 
 1426     def undefine(self):
 1427         self._connection._remove_secret(self)
 1428 
 1429 
 1430 class Connection(object):
 1431     def __init__(self, uri=None, readonly=False, version=FAKE_LIBVIRT_VERSION,
 1432                  hv_version=FAKE_QEMU_VERSION, host_info=None, pci_info=None,
 1433                  mdev_info=None, hostname=None):
 1434         if not uri or uri == '':
 1435             if allow_default_uri_connection:
 1436                 uri = 'qemu:///session'
 1437             else:
 1438                 raise ValueError("URI was None, but fake libvirt is "
 1439                                  "configured to not accept this.")
 1440 
 1441         uri_whitelist = ['qemu:///system',
 1442                          'qemu:///session',
 1443                          'lxc:///',     # from LibvirtDriver._uri()
 1444                          'xen:///',     # from LibvirtDriver._uri()
 1445                          'uml:///system',
 1446                          'test:///default',
 1447                          'parallels:///system']
 1448 
 1449         if uri not in uri_whitelist:
 1450             raise make_libvirtError(
 1451                     libvirtError,
 1452                    "libvirt error: no connection driver "
 1453                    "available for No connection for URI %s" % uri,
 1454                    error_code=5, error_domain=0)
 1455 
 1456         self.readonly = readonly
 1457         self._uri = uri
 1458         self._vms = {}
 1459         self._running_vms = {}
 1460         self._id_counter = 1  # libvirt reserves 0 for the hypervisor.
 1461         self._nodedevs = {}
 1462         self._secrets = {}
 1463         self._event_callbacks = {}
 1464         self.fakeLibVersion = version
 1465         self.fakeVersion = hv_version
 1466         self.host_info = host_info or HostInfo()
 1467         self.pci_info = pci_info or HostPCIDevicesInfo(num_pci=0,
 1468                                                        num_pfs=0,
 1469                                                        num_vfs=0)
 1470         self.mdev_info = mdev_info or HostMdevDevicesInfo(devices={})
 1471         self.hostname = hostname or 'compute1'
 1472 
 1473     def _add_nodedev(self, nodedev):
 1474         self._nodedevs[nodedev._name] = nodedev
 1475 
 1476     def _remove_nodedev(self, nodedev):
 1477         del self._nodedevs[nodedev._name]
 1478 
 1479     def _add_secret(self, secret):
 1480         self._secrets[secret._uuid] = secret
 1481 
 1482     def _remove_secret(self, secret):
 1483         del self._secrets[secret._uuid]
 1484 
 1485     def _mark_running(self, dom):
 1486         self._running_vms[self._id_counter] = dom
 1487         self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_STARTED, 0)
 1488         self._id_counter += 1
 1489 
 1490     def _mark_not_running(self, dom):
 1491         if dom._transient:
 1492             self._undefine(dom)
 1493 
 1494         dom._id = -1
 1495 
 1496         for (k, v) in self._running_vms.items():
 1497             if v == dom:
 1498                 del self._running_vms[k]
 1499                 self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_STOPPED, 0)
 1500                 return
 1501 
 1502     def _undefine(self, dom):
 1503         del self._vms[dom.name()]
 1504         if not dom._transient:
 1505             self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_UNDEFINED, 0)
 1506 
 1507     def getInfo(self):
 1508         return [self.host_info.arch,
 1509                 self.host_info.kB_mem,
 1510                 self.host_info.cpus,
 1511                 self.host_info.cpu_mhz,
 1512                 self.host_info.cpu_nodes,
 1513                 self.host_info.cpu_sockets,
 1514                 self.host_info.cpu_cores,
 1515                 self.host_info.cpu_threads]
 1516 
 1517     def lookupByUUIDString(self, uuid):
 1518         for vm in self._vms.values():
 1519             if vm.UUIDString() == uuid:
 1520                 return vm
 1521         raise make_libvirtError(
 1522                 libvirtError,
 1523                 'Domain not found: no domain with matching uuid "%s"' % uuid,
 1524                 error_code=VIR_ERR_NO_DOMAIN,
 1525                 error_domain=VIR_FROM_QEMU)
 1526 
 1527     def listAllDomains(self, flags=None):
 1528         vms = []
 1529         for vm in self._vms.values():
 1530             if flags & VIR_CONNECT_LIST_DOMAINS_ACTIVE:
 1531                 if vm._state != VIR_DOMAIN_SHUTOFF:
 1532                     vms.append(vm)
 1533             if flags & VIR_CONNECT_LIST_DOMAINS_INACTIVE:
 1534                 if vm._state == VIR_DOMAIN_SHUTOFF:
 1535                     vms.append(vm)
 1536         return vms
 1537 
 1538     def _emit_lifecycle(self, dom, event, detail):
 1539         if VIR_DOMAIN_EVENT_ID_LIFECYCLE not in self._event_callbacks:
 1540             return
 1541 
 1542         cbinfo = self._event_callbacks[VIR_DOMAIN_EVENT_ID_LIFECYCLE]
 1543         callback = cbinfo[0]
 1544         opaque = cbinfo[1]
 1545         callback(self, dom, event, detail, opaque)
 1546 
 1547     def defineXML(self, xml):
 1548         dom = Domain(connection=self, running=False, transient=False, xml=xml)
 1549         self._vms[dom.name()] = dom
 1550         self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_DEFINED, 0)
 1551         return dom
 1552 
 1553     def createXML(self, xml, flags):
 1554         dom = Domain(connection=self, running=True, transient=True, xml=xml)
 1555         self._vms[dom.name()] = dom
 1556         self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_STARTED, 0)
 1557         return dom
 1558 
 1559     def getType(self):
 1560         if self._uri == 'qemu:///system':
 1561             return 'QEMU'
 1562 
 1563     def getLibVersion(self):
 1564         return self.fakeLibVersion
 1565 
 1566     def getVersion(self):
 1567         return self.fakeVersion
 1568 
 1569     def getHostname(self):
 1570         return self.hostname
 1571 
 1572     def domainEventRegisterAny(self, dom, eventid, callback, opaque):
 1573         self._event_callbacks[eventid] = [callback, opaque]
 1574 
 1575     def registerCloseCallback(self, cb, opaque):
 1576         pass
 1577 
 1578     def getCPUMap(self):
 1579         """Return calculated CPU map from HostInfo, by default showing 2
 1580            online CPUs.
 1581         """
 1582         total_cpus = self.host_info.cpus
 1583         cpu_map = [True for cpu_num in range(total_cpus)]
 1584         return (total_cpus, cpu_map, total_cpus)
 1585 
 1586     def getDomainCapabilities(self, emulatorbin, arch, machine_type,
 1587                               virt_type, flags):
 1588         """Return spoofed domain capabilities."""
 1589         if arch in fake_libvirt_data.STATIC_DOMCAPABILITIES:
 1590             return fake_libvirt_data.STATIC_DOMCAPABILITIES[arch]
 1591 
 1592         if arch == 'x86_64':
 1593             aliases = {'pc': 'pc-i440fx-2.11', 'q35': 'pc-q35-2.11'}
 1594             return fake_libvirt_data.DOMCAPABILITIES_X86_64_TEMPLATE % \
 1595                 {'features': self._domain_capability_features,
 1596                  'mtype': aliases.get(machine_type, machine_type)}
 1597 
 1598         raise Exception("fakelibvirt doesn't support getDomainCapabilities "
 1599                         "for %s architecture" % arch)
 1600 
 1601     def getCPUModelNames(self, arch):
 1602         mapping = {
 1603             'x86_64': [
 1604                 '486',
 1605                 'pentium',
 1606                 'pentium2',
 1607                 'pentium3',
 1608                 'pentiumpro',
 1609                 'coreduo',
 1610                 'n270',
 1611                 'core2duo',
 1612                 'qemu32',
 1613                 'kvm32',
 1614                 'cpu64-rhel5',
 1615                 'cpu64-rhel6',
 1616                 'qemu64',
 1617                 'kvm64',
 1618                 'Conroe',
 1619                 'Penryn',
 1620                 'Nehalem',
 1621                 'Nehalem-IBRS',
 1622                 'Westmere',
 1623                 'Westmere-IBRS',
 1624                 'SandyBridge',
 1625                 'SandyBridge-IBRS',
 1626                 'IvyBridge',
 1627                 'IvyBridge-IBRS',
 1628                 'Haswell-noTSX',
 1629                 'Haswell-noTSX-IBRS',
 1630                 'Haswell',
 1631                 'Haswell-IBRS',
 1632                 'Broadwell-noTSX',
 1633                 'Broadwell-noTSX-IBRS',
 1634                 'Broadwell',
 1635                 'Broadwell-IBRS',
 1636                 'Skylake-Client',
 1637                 'Skylake-Client-IBRS',
 1638                 'Skylake-Server',
 1639                 'Skylake-Server-IBRS',
 1640                 'Cascadelake-Server',
 1641                 'Icelake-Client',
 1642                 'Icelake-Server',
 1643                 'athlon',
 1644                 'phenom',
 1645                 'Opteron_G1',
 1646                 'Opteron_G2',
 1647                 'Opteron_G3',
 1648                 'Opteron_G4',
 1649                 'Opteron_G5',
 1650                 'EPYC',
 1651                 'EPYC-IBPB'],
 1652             'ppc64': [
 1653                 'POWER6',
 1654                 'POWER7',
 1655                 'POWER8',
 1656                 'POWER9',
 1657                 'POWERPC_e5500',
 1658                 'POWERPC_e6500']
 1659         }
 1660         return mapping.get(arch, [])
 1661 
 1662     # Features are kept separately so that the tests can patch this
 1663     # class variable with alternate values.
 1664     _domain_capability_features = '''  <features>
 1665     <gic supported='no'/>
 1666   </features>'''
 1667 
 1668     _domain_capability_features_with_SEV = '''  <features>
 1669     <gic supported='no'/>
 1670     <sev supported='yes'>
 1671       <cbitpos>47</cbitpos>
 1672       <reducedPhysBits>1</reducedPhysBits>
 1673     </sev>
 1674   </features>'''
 1675 
 1676     _domain_capability_features_with_SEV_unsupported = \
 1677         _domain_capability_features_with_SEV.replace('yes', 'no')
 1678 
 1679     def getCapabilities(self):
 1680         """Return spoofed capabilities."""
 1681         numa_topology = self.host_info.numa_topology
 1682         if isinstance(numa_topology, vconfig.LibvirtConfigCapsNUMATopology):
 1683             numa_topology = numa_topology.to_xml()
 1684 
 1685         return (fake_libvirt_data.CAPABILITIES_TEMPLATE
 1686                 % {'sockets': self.host_info.cpu_sockets,
 1687                    'cores': self.host_info.cpu_cores,
 1688                    'threads': self.host_info.cpu_threads,
 1689                    'topology': numa_topology})
 1690 
 1691     def compareCPU(self, xml, flags):
 1692         tree = etree.fromstring(xml)
 1693 
 1694         arch_node = tree.find('./arch')
 1695         if arch_node is not None:
 1696             if arch_node.text not in [obj_fields.Architecture.X86_64,
 1697                                       obj_fields.Architecture.I686]:
 1698                 return VIR_CPU_COMPARE_INCOMPATIBLE
 1699 
 1700         model_node = tree.find('./model')
 1701         if model_node is not None:
 1702             # arch_node may not present, therefore query all cpu models.
 1703             if model_node.text not in self.getCPUModelNames('x86_64') and \
 1704                 model_node.text not in self.getCPUModelNames('ppc64'):
 1705                 raise make_libvirtError(
 1706                     libvirtError,
 1707                     "internal error: Unknown CPU model %s" % model_node.text,
 1708                     error_code = VIR_ERR_INTERNAL_ERROR,
 1709                     error_domain=VIR_FROM_QEMU)
 1710             if model_node.text != self.host_info.cpu_model:
 1711                 return VIR_CPU_COMPARE_INCOMPATIBLE
 1712 
 1713         vendor_node = tree.find('./vendor')
 1714         if vendor_node is not None:
 1715             if vendor_node.text != self.host_info.cpu_vendor:
 1716                 return VIR_CPU_COMPARE_INCOMPATIBLE
 1717 
 1718         # The rest of the stuff libvirt implements is rather complicated
 1719         # and I don't think it adds much value to replicate it here.
 1720 
 1721         return VIR_CPU_COMPARE_IDENTICAL
 1722 
 1723     def getCPUStats(self, cpuNum, flag):
 1724         if cpuNum < 2:
 1725             return {'kernel': 5664160000000,
 1726                     'idle': 1592705190000000,
 1727                     'user': 26728850000000,
 1728                     'iowait': 6121490000000}
 1729         else:
 1730             raise make_libvirtError(
 1731                     libvirtError,
 1732                     "invalid argument: Invalid cpu number",
 1733                     error_code=VIR_ERR_INTERNAL_ERROR,
 1734                     error_domain=VIR_FROM_QEMU)
 1735 
 1736     def device_lookup_by_name(self, dev_name):
 1737         return self.pci_info.get_device_by_name(dev_name)
 1738 
 1739     def nodeDeviceLookupByName(self, name):
 1740         if name.startswith('mdev'):
 1741             return self.mdev_info.get_device_by_name(name)
 1742 
 1743         pci_dev = self.pci_info.get_device_by_name(name)
 1744         if pci_dev:
 1745             return pci_dev
 1746         try:
 1747             return self._nodedevs[name]
 1748         except KeyError:
 1749             raise make_libvirtError(
 1750                     libvirtError,
 1751                     "no nodedev with matching name %s" % name,
 1752                     error_code=VIR_ERR_NO_NODE_DEVICE,
 1753                     error_domain=VIR_FROM_NODEDEV)
 1754 
 1755     def listDevices(self, cap, flags):
 1756         if cap == 'pci':
 1757             return self.pci_info.get_all_devices()
 1758         if cap == 'mdev':
 1759             return self.mdev_info.get_all_devices()
 1760         if cap == 'mdev_types':
 1761             return self.pci_info.get_all_mdev_capable_devices()
 1762         else:
 1763             raise ValueError('Capability "%s" is not supported' % cap)
 1764 
 1765     def baselineCPU(self, cpu, flag):
 1766         """Add new libvirt API."""
 1767         return """<cpu mode='custom' match='exact'>
 1768                     <model>Penryn</model>
 1769                     <vendor>Intel</vendor>
 1770                     <feature name='xtpr'/>
 1771                     <feature name='tm2'/>
 1772                     <feature name='est'/>
 1773                     <feature name='vmx'/>
 1774                     <feature name='ds_cpl'/>
 1775                     <feature name='monitor'/>
 1776                     <feature name='pbe'/>
 1777                     <feature name='tm'/>
 1778                     <feature name='ht'/>
 1779                     <feature name='ss'/>
 1780                     <feature name='acpi'/>
 1781                     <feature name='ds'/>
 1782                     <feature name='vme'/>
 1783                     <feature policy='require' name='aes'/>
 1784                   </cpu>"""
 1785 
 1786     def secretLookupByUsage(self, usage_type_obj, usage_id):
 1787         pass
 1788 
 1789     def secretDefineXML(self, xml):
 1790         secret = Secret(self, xml)
 1791         self._add_secret(secret)
 1792         return secret
 1793 
 1794     def listAllDevices(self, flags):
 1795         # Note this is incomplete as we do not filter
 1796         # based on the flags however it is enough for our
 1797         # current testing.
 1798         return [NodeDevice(self, xml=dev.XMLDesc(0))
 1799                 for dev in self.pci_info.devices.values()]
 1800 
 1801 
 1802 def openAuth(uri, auth, flags=0):
 1803 
 1804     if type(auth) != list:
 1805         raise Exception("Expected a list for 'auth' parameter")
 1806 
 1807     if type(auth[0]) != list:
 1808         raise Exception("Expected a function in 'auth[0]' parameter")
 1809 
 1810     if not callable(auth[1]):
 1811         raise Exception("Expected a function in 'auth[1]' parameter")
 1812 
 1813     return Connection(uri, (flags == VIR_CONNECT_RO))
 1814 
 1815 
 1816 def virEventRunDefaultImpl():
 1817     time.sleep(1)
 1818 
 1819 
 1820 def virEventRegisterDefaultImpl():
 1821     if connection_used:
 1822         raise Exception("virEventRegisterDefaultImpl() must be "
 1823                         "called before connection is used.")
 1824 
 1825 
 1826 def registerErrorHandler(handler, ctxt):
 1827     pass
 1828 
 1829 
 1830 def make_libvirtError(error_class, msg, error_code=None,
 1831                        error_domain=None, error_message=None,
 1832                        error_level=None, str1=None, str2=None, str3=None,
 1833                        int1=None, int2=None):
 1834     """Convenience function for creating `libvirtError` exceptions which
 1835     allow you to specify arguments in constructor without having to manipulate
 1836     the `err` tuple directly.
 1837 
 1838     We need to pass in `error_class` to this function because it may be
 1839     `libvirt.libvirtError` or `fakelibvirt.libvirtError` depending on whether
 1840     `libvirt-python` is installed.
 1841     """
 1842     exc = error_class(msg)
 1843     exc.err = (error_code, error_domain, error_message, error_level,
 1844                str1, str2, str3, int1, int2)
 1845     return exc
 1846 
 1847 
 1848 virDomain = Domain
 1849 virNodeDevice = NodeDevice
 1850 
 1851 virConnect = Connection
 1852 virSecret = Secret
 1853 
 1854 
 1855 # A private libvirt-python class and global only provided here for testing to
 1856 # ensure it's not returned by libvirt.host.Host.get_libvirt_proxy_classes.
 1857 class FakeHandler(object):
 1858     def __init__(self):
 1859         pass
 1860 
 1861 
 1862 _EventAddHandleFunc = FakeHandler
 1863 
 1864 
 1865 class FakeLibvirtFixture(fixtures.Fixture):
 1866     """Performs global setup/stubbing for all libvirt tests.
 1867     """
 1868     def __init__(self, stub_os_vif=True):
 1869         self.stub_os_vif = stub_os_vif
 1870 
 1871     def setUp(self):
 1872         super(FakeLibvirtFixture, self).setUp()
 1873 
 1874         # Some modules load the libvirt library in a strange way
 1875         for module in ('driver', 'host', 'guest', 'migration'):
 1876             i = 'nova.virt.libvirt.{module}.libvirt'.format(module=module)
 1877             # NOTE(mdbooth): The strange incantation below means 'this module'
 1878             self.useFixture(fixtures.MonkeyPatch(i, sys.modules[__name__]))
 1879 
 1880         self.useFixture(
 1881             fixtures.MockPatch('nova.virt.libvirt.utils.get_fs_info'))
 1882         self.useFixture(
 1883             fixtures.MockPatch('nova.compute.utils.get_machine_ips'))
 1884 
 1885         # libvirt driver needs to call out to the filesystem to get the
 1886         # parent_ifname for the SRIOV VFs.
 1887         self.useFixture(fixtures.MockPatch(
 1888             'nova.pci.utils.get_ifname_by_pci_address',
 1889             return_value='fake_pf_interface_name'))
 1890 
 1891         # libvirt calls out to sysfs to get the vfs ID during macvtap plug
 1892         self.useFixture(fixtures.MockPatch(
 1893             'nova.pci.utils.get_vf_num_by_pci_address', return_value=1))
 1894 
 1895         # libvirt calls out to privsep to set the mac and vlan of a macvtap
 1896         self.useFixture(fixtures.MockPatch(
 1897             'nova.privsep.linux_net.set_device_macaddr_and_vlan'))
 1898 
 1899         # libvirt calls out to privsep to set the port state during macvtap
 1900         # plug
 1901         self.useFixture(fixtures.MockPatch(
 1902             'nova.privsep.linux_net.set_device_macaddr'))
 1903 
 1904         # Don't assume that the system running tests has a valid machine-id
 1905         self.useFixture(fixtures.MockPatch(
 1906             'nova.virt.libvirt.driver.LibvirtDriver'
 1907             '._get_host_sysinfo_serial_os', return_value=uuids.machine_id))
 1908 
 1909         # Stub out _log_host_capabilities since it logs a giant string at INFO
 1910         # and we don't want that to blow up the subunit parser in test runs.
 1911         self.useFixture(fixtures.MockPatch(
 1912             'nova.virt.libvirt.host.Host._log_host_capabilities'))
 1913 
 1914         disable_event_thread(self)
 1915 
 1916         if self.stub_os_vif:
 1917             # Make sure to never try and actually plug/unplug VIFs in os-vif
 1918             # unless we're explicitly testing that code and the test itself
 1919             # will handle the appropriate mocking.
 1920             self.useFixture(fixtures.MonkeyPatch(
 1921                 'nova.virt.libvirt.vif.LibvirtGenericVIFDriver._plug_os_vif',
 1922                 lambda *a, **kw: None))
 1923             self.useFixture(fixtures.MonkeyPatch(
 1924                 'nova.virt.libvirt.vif.LibvirtGenericVIFDriver._unplug_os_vif',
 1925                 lambda *a, **kw: None))
 1926 
 1927         # os_vif.initialize is typically done in nova-compute startup
 1928         # even if we are not planning to plug anything with os_vif in the test
 1929         # we still need the object model initialized to be able to generate
 1930         # guest config xml properly
 1931         import os_vif
 1932         os_vif.initialize()