def set_hvdevs(self, devices): """Sync the pci device tracker with hypervisor information. To support pci device hot plug, we sync with the hypervisor periodically, fetching all devices information from hypervisor, update the tracker and sync the DB information. Devices should not be hot-plugged when assigned to a guest, but possibly the hypervisor has no such guarantee. The best we can do is to give a warning if a device is changed or removed while assigned. """ exist_addrs = set([dev['address'] for dev in self.pci_devs]) new_addrs = set([dev['address'] for dev in devices]) for existed in self.pci_devs: if existed['address'] in exist_addrs - new_addrs: try: pci_device.remove(existed) except exception.PciDeviceInvalidStatus as e: LOG.warn(_("Trying to remove device with %(status)s " "ownership %(instance_uuid)s because of " "%(pci_exception)s"), {'status': existed.status, 'instance_uuid': existed.instance_uuid, 'pci_exception': e.format_message()}) # Note(yjiang5): remove the device by force so that # db entry is cleaned in next sync. existed.status = 'removed' else: # Note(yjiang5): no need to update stats if an assigned # device is hot removed. self.stats.consume_device(existed) else: new_value = next((dev for dev in devices if dev['address'] == existed['address'])) new_value['compute_node_id'] = self.node_id if existed['status'] in ('claimed', 'allocated'): # Pci properties may change while assigned because of # hotplug or config changes. Although normally this should # not happen. # As the devices have been assigned to a instance, we defer # the change till the instance is destroyed. We will # not sync the new properties with database before that. # TODO(yjiang5): Not sure if this is a right policy, but # at least it avoids some confusion and, if needed, # we can add more action like killing the instance # by force in future. self.stale[dev['address']] = dev else: pci_device.update_device(existed, new_value) for dev in [dev for dev in devices if dev['address'] in new_addrs - exist_addrs]: dev['compute_node_id'] = self.node_id dev_obj = pci_device_obj.PciDevice.create(dev) self.pci_devs.append(dev_obj) self.stats.add_device(dev_obj)
def set_hvdevs(self, devices): """Sync the pci device tracker with hypervisor information. To support pci device hot plug, we sync with the hypervisor periodically, fetching all devices information from hypervisor, update the tracker and sync the DB information. Devices should not be hot-plugged when assigned to a guest, but possibly the hypervisor has no such guarantee. The best we can do is to give a warning if a device is changed or removed while assigned. """ exist_addrs = set([dev['address'] for dev in self.pci_devs]) new_addrs = set([dev['address'] for dev in devices]) for existed in self.pci_devs: if existed['address'] in exist_addrs - new_addrs: try: pci_device.remove(existed) except exception.PciDeviceInvalidStatus as e: LOG.warn(_("Trying to remove device with %(status)s " "ownership %(instance_uuid)s because of " "%(pci_exception)s"), {'status': existed.status, 'instance_uuid': existed.instance_uuid, 'pci_exception': e.format_message()}) # Note(yjiang5): remove the device by force so that # db entry is cleaned in next sync. existed.status = 'removed' else: # Note(yjiang5): no need to update stats if an assigned # device is hot removed. self.stats.remove_device(existed) else: new_value = next((dev for dev in devices if dev['address'] == existed['address'])) new_value['compute_node_id'] = self.node_id if existed['status'] in ('claimed', 'allocated'): # Pci properties may change while assigned because of # hotplug or config changes. Although normally this should # not happen. # As the devices have been assigned to a instance, we defer # the change till the instance is destroyed. We will # not sync the new properties with database before that. # TODO(yjiang5): Not sure if this is a right policy, but # at least it avoids some confusion and, if needed, # we can add more action like killing the instance # by force in future. self.stale[dev['address']] = dev else: pci_device.update_device(existed, new_value) for dev in [dev for dev in devices if dev['address'] in new_addrs - exist_addrs]: dev['compute_node_id'] = self.node_id dev_obj = objects.PciDevice.create(dev) self.pci_devs.append(dev_obj) self.stats.add_device(dev_obj)
def test_save_removed(self): self.stubs.Set(db, "pci_device_update", self._fake_pci_device_update) self.stubs.Set(db, "pci_device_destroy", self._fake_pci_device_destroy) self.destroy_called = 0 self.assertEqual(len(self.tracker.pci_devs), 3) dev = self.tracker.pci_devs[0] self.update_called = 0 pci_device.remove(dev) self.tracker.save(self.fake_context) self.assertEqual(len(self.tracker.pci_devs), 2) self.assertEqual(self.destroy_called, 1)
def test_remove_device(self): pci_device.remove(self.devobj) self.assertEqual(self.devobj.status, 'removed') self.assertIsNone(self.devobj.instance_uuid)