def test_check_can_migrate_pci(self): """Tests that _check_can_migrate_pci() allows live-migration if instance does not contain non-network related PCI requests and raises MigrationPreCheckError otherwise """ @mock.patch.object(self.task.network_api, 'supports_port_binding_extension') @mock.patch.object(live_migrate, 'supports_vif_related_pci_allocations') def _test(instance_pci_reqs, supp_binding_ext_retval, supp_vif_related_pci_alloc_retval, mock_supp_vif_related_pci_alloc, mock_supp_port_binding_ext): mock_supp_vif_related_pci_alloc.return_value = \ supp_vif_related_pci_alloc_retval mock_supp_port_binding_ext.return_value = \ supp_binding_ext_retval self.task.instance.pci_requests = instance_pci_reqs self.task._check_can_migrate_pci("Src", "Dst") # in case we managed to get away without rasing, check mocks if instance_pci_reqs: mock_supp_port_binding_ext.assert_called_once_with( self.context) self.assertTrue(mock_supp_vif_related_pci_alloc.called) # instance has no PCI requests _test(None, False, False) # No support in Neutron and Computes _test(None, True, False) # No support in Computes _test(None, False, True) # No support in Neutron _test(None, True, True) # Support in both Neutron and Computes # instance contains network related PCI requests (alias_name=None) pci_requests = objects.InstancePCIRequests( requests=[objects.InstancePCIRequest(alias_name=None)]) self.assertRaises(exception.MigrationPreCheckError, _test, pci_requests, False, False) self.assertRaises(exception.MigrationPreCheckError, _test, pci_requests, True, False) self.assertRaises(exception.MigrationPreCheckError, _test, pci_requests, False, True) _test(pci_requests, True, True) # instance contains Non network related PCI requests (alias_name!=None) pci_requests.requests.append( objects.InstancePCIRequest(alias_name="non-network-related-pci")) self.assertRaises(exception.MigrationPreCheckError, _test, pci_requests, False, False) self.assertRaises(exception.MigrationPreCheckError, _test, pci_requests, True, False) self.assertRaises(exception.MigrationPreCheckError, _test, pci_requests, False, True) self.assertRaises(exception.MigrationPreCheckError, _test, pci_requests, True, True)
def test_get_instance_pci_request_from_vif(self, cn_get_by_host_and_node): self.mock_inst_cn.id = 1 cn_get_by_host_and_node.return_value = self.mock_inst_cn # Create a fake instance with PCI request and allocated PCI devices pci_req1 = objects.InstancePCIRequest( request_id=uuidsentinel.pci_req_id1) pci_dev1 = objects.PciDevice(request_id=uuidsentinel.pci_req_id1, address='0000:04:00.0', compute_node_id=1) pci_req2 = objects.InstancePCIRequest( request_id=uuidsentinel.pci_req_id2) pci_dev2 = objects.PciDevice(request_id=uuidsentinel.pci_req_id2, address='0000:05:00.0', compute_node_id=1) pci_request_list = [pci_req1, pci_req2] pci_device_list = [pci_dev1, pci_dev2] inst = PciRequestTestCase._create_fake_inst_with_pci_devs( pci_request_list, pci_device_list) # Create a vif with normal port and make sure no PCI request returned normal_vif = model.VIF(vnic_type=model.VNIC_TYPE_NORMAL) self.assertIsNone( request.get_instance_pci_request_from_vif(self.context, inst, normal_vif)) # Create a vif with PCI address under profile, make sure the correct # PCI request is returned pci_vif = model.VIF(vnic_type=model.VNIC_TYPE_DIRECT, profile={'pci_slot': '0000:05:00.0'}) self.assertEqual( uuidsentinel.pci_req_id2, request.get_instance_pci_request_from_vif(self.context, inst, pci_vif).request_id) # Create a vif with PCI under profile which is not claimed # for the instance, i.e no matching pci device in instance.pci_devices nonclaimed_pci_vif = model.VIF(vnic_type=model.VNIC_TYPE_DIRECT, profile={'pci_slot': '0000:08:00.0'}) self.assertIsNone( request.get_instance_pci_request_from_vif(self.context, inst, nonclaimed_pci_vif)) # "Move" the instance to another compute node, make sure that no # matching PCI request against the new compute. self.mock_inst_cn.id = 2 self.assertIsNone( request.get_instance_pci_request_from_vif(self.context, inst, pci_vif))
def test_consume_reqeusts(self, mock_get_dev_filter): mock_get_dev_filter.return_value = self.pci_wlist self._create_pci_devices() pci_requests = [objects.InstancePCIRequest(count=1, spec=[{'physical_network': 'physnet1'}]), objects.InstancePCIRequest(count=1, spec=[{'vendor_id': '1137', 'product_id': '0072'}])] devs = self.pci_stats.consume_requests(pci_requests) self.assertEqual(2, len(devs)) self.assertEqual(set(['0071', '0072']), set([dev['product_id'] for dev in devs])) self._assertPoolContent(self.pci_stats.pools[0], '1137', '0072', 2) self._assertPoolContent(self.pci_stats.pools[1], '1137', '0071', 3, physical_network='physnet1')
def test_numa_topology_with_pci_no_numa_info(self, mock_get_by_instance): dev_dict = { 'compute_node_id': 1, 'address': 'a', 'product_id': 'p', 'vendor_id': 'v', 'numa_node': None, 'dev_type': 'type-PCI', 'parent_addr': 'a1', 'status': 'available' } self.tracker.new_pci_tracker() self.tracker.pci_tracker._set_hvdevs([dev_dict]) request = objects.InstancePCIRequest(count=1, spec=[{ 'vendor_id': 'v', 'product_id': 'p' }]) requests = objects.InstancePCIRequests(requests=[request]) mock_get_by_instance.return_value = requests huge_instance = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=1, cpuset=set([1, 2]), memory=512) ]) self._claim(requests=requests, numa_topology=huge_instance)
def test_multiplier_none(self): """Test weigher with a PCI device instance and a 0.0 multiplier. Ensure that the 0.0 multiplier disables the weigher entirely. """ self.flags(pci_weight_multiplier=0.0, group='filter_scheduler') hosts = [ ('host1', 'node1', [4, 1]), # 5 devs ('host2', 'node2', [10]), # 10 devs ('host3', 'node3', [1, 1, 1, 1]), # 4 devs ] hostinfo_list = self._get_all_hosts(hosts) request = objects.InstancePCIRequest(count=1, spec=[{ 'vendor_id': '8086' }]) requests = objects.InstancePCIRequests(requests=[request]) spec_obj = objects.RequestSpec(pci_requests=requests) # we do not know the host as all have same weight weighed_hosts = self._get_weighed_hosts(hostinfo_list, spec_obj) for weighed_host in weighed_hosts: # the weigher normalizes all weights to 0 if they're all equal self.assertEqual(0.0, weighed_host.weight)
def test_multiplier_with_pci(self): """Test weigher with a PCI device instance and a multiplier. Ensure that the host with the smallest number of free PCI devices capable of meeting the requirements of the instance is chosen, enforcing a stacking (rather than spreading) behavior. """ # none of the hosts will have less than the number of devices required # by the instance: the NUMATopologyFilter takes care of this for us hosts = [ ('host1', 'node1', [4, 1]), # 5 devs ('host2', 'node2', [10]), # 10 devs ('host3', 'node3', [1, 1, 1, 1]), # 4 devs ] hostinfo_list = self._get_all_hosts(hosts) # we request PCI devices request = objects.InstancePCIRequest(count=4, spec=[{ 'vendor_id': '8086' }]) requests = objects.InstancePCIRequests(requests=[request]) spec_obj = objects.RequestSpec(pci_requests=requests) # host3, which has the least free PCI devices, should win weighed_host = self._get_weighed_hosts(hostinfo_list, spec_obj)[0] self.assertEqual(1.0, weighed_host.weight) self.assertEqual('host3', weighed_host.obj.host)
def test_multiplier_with_many_pci(self): """Test weigher with a PCI device instance and huge hosts. Ensure that the weigher gracefully degrades when the number of PCI devices on the host exceeeds MAX_DEVS. """ hosts = [ ('host1', 'node1', [500]), # 500 devs ('host2', 'node2', [2000]), # 2000 devs ] hostinfo_list = self._get_all_hosts(hosts) # we request PCI devices request = objects.InstancePCIRequest(count=4, spec=[{ 'vendor_id': '8086' }]) requests = objects.InstancePCIRequests(requests=[request]) spec_obj = objects.RequestSpec(pci_requests=requests) # we do not know the host as all have same weight weighed_hosts = self._get_weighed_hosts(hostinfo_list, spec_obj) for weighed_host in weighed_hosts: # the weigher normalizes all weights to 0 if they're all equal self.assertEqual(0.0, weighed_host.weight)
def test_consume_VF_and_PF_requests(self): self._create_pci_devices() pci_requests = [ objects.InstancePCIRequest(count=2, spec=[{ 'product_id': '1515' }]), objects.InstancePCIRequest(count=1, spec=[{ 'product_id': '1528', 'dev_type': 'type-PF' }]) ] devs = self.pci_stats.consume_requests(pci_requests) self.assertEqual(3, len(devs)) self.assertEqual(set(['1528', '1515']), set([dev.product_id for dev in devs]))
def test_numa_topology_with_pci_fail(self, mock_get_by_instance, mock_get): dev_dict = { 'compute_node_id': 1, 'address': 'a', 'product_id': 'p', 'vendor_id': 'v', 'numa_node': 1, 'status': 'available'} dev_dict2 = { 'compute_node_id': 1, 'address': 'a', 'product_id': 'p', 'vendor_id': 'v', 'numa_node': 2, 'status': 'available'} self.tracker.new_pci_tracker() self.tracker.pci_tracker._set_hvdevs([dev_dict, dev_dict2]) request = objects.InstancePCIRequest(count=2, spec=[{'vendor_id': 'v', 'product_id': 'p'}]) requests = objects.InstancePCIRequests(requests=[request]) mock_get.return_value = requests mock_get_by_instance.return_value = requests huge_instance = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell( id=1, cpuset=set([1, 2]), memory=512)]) self.assertRaises(exception.ComputeResourcesUnavailable, self._claim, numa_topology=huge_instance)
def test_stat_consumption_from_instance_with_pci_exception(self): fake_requests = [{'request_id': 'fake_request1', 'count': 3, 'spec': [{'vendor_id': '8086'}]}] fake_requests_obj = objects.InstancePCIRequests( requests=[objects.InstancePCIRequest(**r) for r in fake_requests], instance_uuid='fake-uuid') req_spec = objects.RequestSpec( instance_uuid='fake-uuid', project_id='12345', numa_topology=None, pci_requests=fake_requests_obj, flavor=objects.Flavor(root_gb=0, ephemeral_gb=0, memory_mb=1024, vcpus=1)) host = host_manager.HostState("fakehost", "fakenode") self.assertIsNone(host.updated) fake_updated = mock.sentinel.fake_updated host.updated = fake_updated host.pci_stats = pci_stats.PciDeviceStats() with mock.patch.object(host.pci_stats, 'apply_requests', side_effect=exception.PciDeviceRequestFailed): host.consume_from_request(req_spec) self.assertEqual(fake_updated, host.updated)
def test_save_and_reload(self, mock_get, mock_update): database = {} def _save(context, uuid, values): database.setdefault(uuid, {'instance_uuid': uuid}) database[uuid].update(values) def _get(context, uuid, columns): return database.get(uuid, {}) mock_update.side_effect = _save mock_get.side_effect = _get requests = objects.InstancePCIRequests(context=self.context, instance_uuid=FAKE_UUID, requests=[ objects.InstancePCIRequest( count=1, is_new=False, alias_name='alias_1', spec=[{ 'foo': 'bar' }]) ]) requests.save() _requests = objects.InstancePCIRequests.get_by_instance_uuid( self.context, FAKE_UUID) self.assertEqual(requests.instance_uuid, _requests.instance_uuid) self.assertEqual(len(requests.requests), len(_requests.requests)) self.assertEqual(requests.requests[0].alias_name, _requests.requests[0].alias_name)
def test_stat_consumption_from_instance_with_pci_exception(self): fake_requests = [{'request_id': 'fake_request1', 'count': 3, 'spec': [{'vendor_id': '8086'}]}] fake_requests_obj = objects.InstancePCIRequests( requests=[objects.InstancePCIRequest(**r) for r in fake_requests], instance_uuid='fake-uuid') instance = objects.Instance(root_gb=0, ephemeral_gb=0, memory_mb=512, vcpus=1, project_id='12345', vm_state=vm_states.BUILDING, task_state=task_states.SCHEDULING, os_type='Linux', uuid='fake-uuid', pci_requests=fake_requests_obj, id=1243) req_spec = sched_utils.build_request_spec(None, None, [instance], objects.Flavor( root_gb=0, ephemeral_gb=0, memory_mb=1024, vcpus=1)) host = host_manager.HostState("fakehost", "fakenode") self.assertIsNone(host.updated) fake_updated = mock.sentinel.fake_updated host.updated = fake_updated host.pci_stats = pci_stats.PciDeviceStats() with mock.patch.object(host.pci_stats, 'apply_requests', side_effect=exception.PciDeviceRequestFailed): host.consume_from_instance(req_spec['instance_properties']) self.assertEqual(fake_updated, host.updated)
def _create_pci_requests_object(self, mock_get, requests): pci_reqs = [] for request in requests: pci_req_obj = objects.InstancePCIRequest(count=request['count'], spec=request['spec']) pci_reqs.append(pci_req_obj) mock_get.return_value = objects.InstancePCIRequests(requests=pci_reqs)
def create_pci_requests_for_sriov_ports(self, context, pci_requests, requested_networks): """Check requested networks for any SR-IOV port request. Create a PCI request object for each SR-IOV port, and add it to the pci_requests object that contains a list of PCI request object. """ if not requested_networks: return for request_net in requested_networks: phynet_name = None vnic_type = network_model.VNIC_TYPE_NORMAL if request_net.port_id: vnic_type, connection_ident = self._get_port_vnic_info( request_net.port_id) pci_request_id = None if vnic_type != network_model.VNIC_TYPE_NORMAL: # all types other than 'normal' are PCI types?! TODO phynet_name = connection_iden['physical_network'] request = objects.InstancePCIRequest( count=1, spec=[{ pci_request.PCI_NET_TAG: phynet_name }], request_id=str(uuid.uuid4())) pci_requests.requests.append(request) pci_request_id = request.request_id # Add pci_request_id into the requested network request_net.pci_request_id = pci_request_id
def test_get_instance_pci_request_from_vif_invalid( self, cn_get_by_host_and_node): # Basically make sure we raise an exception if an instance # has an allocated PCI device without having the its corresponding # PCIRequest object in instance.pci_requests mock_inst_cn = mock.Mock() mock_inst_cn.id = 1 cn_get_by_host_and_node.return_value = mock_inst_cn # Create a fake instance with PCI request and allocated PCI devices pci_dev1 = objects.PciDevice(request_id=uuidsentinel.pci_req_id1, address='0000:04:00.0', compute_node_id=1) pci_req2 = objects.InstancePCIRequest( request_id=uuidsentinel.pci_req_id2) pci_dev2 = objects.PciDevice(request_id=uuidsentinel.pci_req_id2, address='0000:05:00.0', compute_node_id=1) pci_request_list = [pci_req2] pci_device_list = [pci_dev1, pci_dev2] inst = PciRequestTestCase._create_fake_inst_with_pci_devs( pci_request_list, pci_device_list) # Create a VIF with pci_dev1 that has no corresponding PCI request pci_vif = model.VIF(vnic_type=model.VNIC_TYPE_DIRECT, profile={'pci_slot': '0000:04:00.0'}) self.assertRaises(exception.PciRequestFromVIFNotFound, request.get_instance_pci_request_from_vif, self.context, inst, pci_vif)
def test_save(self, mock_update): requests = objects.InstancePCIRequests( context=self.context, instance_uuid=FAKE_UUID, requests=[ objects.InstancePCIRequest(count=1, spec=[{ 'foo': 'bar' }, { 'baz': 'bat' }], alias_name='alias_1', is_new=False, request_id=FAKE_REQUEST_UUID) ]) requests.save() self.assertEqual(FAKE_UUID, mock_update.call_args_list[0][0][1]) self.assertEqual([{ 'count': 1, 'is_new': False, 'alias_name': 'alias_1', 'spec': [{ 'foo': 'bar' }, { 'baz': 'bat' }], 'request_id': FAKE_REQUEST_UUID }], jsonutils.loads( mock_update.call_args_list[0][0][2]['pci_requests']))
def test_consume_requests_no_numa_info(self): cells = [objects.NUMACell(id=0, cpuset=set(), memory=0)] pci_request = [objects.InstancePCIRequest(count=1, spec=[{'vendor_id': 'v3'}])] devs = self.pci_stats.consume_requests(pci_request, cells) self.assertEqual(1, len(devs)) self.assertEqual(set(['v3']), set([dev['vendor_id'] for dev in devs]))
def test_consume_requests_no_numa_info(self): cells = [hardware.VirtNUMATopologyCell(0, None, None)] pci_request = [objects.InstancePCIRequest(count=1, spec=[{'vendor_id': 'v3'}])] devs = self.pci_stats.consume_requests(pci_request, cells) self.assertEqual(1, len(devs)) self.assertEqual(set(['v3']), set([dev['vendor_id'] for dev in devs]))
def test_consume_VF_and_PF_same_prodict_id_failed(self): self._create_pci_devices(pf_product_id=1515) pci_requests = [ objects.InstancePCIRequest(count=9, spec=[{ 'product_id': '1515' }]) ] self.assertIsNone(self.pci_stats.consume_requests(pci_requests))
def test_support_requests_no_numa_info(self): cells = [objects.InstanceNUMACell(id=0, cpuset=set(), memory=0)] pci_request = [ objects.InstancePCIRequest(count=1, spec=[{ 'vendor_id': 'v3' }]) ] self.assertTrue(self.pci_stats.support_requests(pci_request, cells))
def _get_fake_requests(vendor_ids=None, numa_policy=None, count=1): if not vendor_ids: vendor_ids = ['v1', 'v2'] specs = [{'vendor_id': vendor_id} for vendor_id in vendor_ids] return [objects.InstancePCIRequest(count=count, spec=[spec], numa_policy=numa_policy) for spec in specs]
def test_pci_fail(self, mock_supports): request = objects.InstancePCIRequest(count=1, spec=[{'vendor_id': 'v', 'product_id': 'p'}]) requests = objects.InstancePCIRequests(requests=[request]) self.assertRaises(exception.ComputeResourcesUnavailable, self._claim, requests=requests) mock_supports.assert_called_once_with(requests.requests)
def test_source_property(self): neutron_port_pci_req = objects.InstancePCIRequest( count=1, spec=[{'vendor_id': '15b3', 'device_id': '1018'}], request_id=uuids.pci_request_id1, requester_id=uuids.requester_id1, alias_name = None) flavor_alias_pci_req = objects.InstancePCIRequest( count=1, spec=[{'vendor_id': '15b3', 'device_id': '1810'}], request_id=uuids.pci_request_id2, requester_id=uuids.requester_id2, alias_name = 'alias_1') self.assertEqual(neutron_port_pci_req.source, objects.InstancePCIRequest.NEUTRON_PORT) self.assertEqual(flavor_alias_pci_req.source, objects.InstancePCIRequest.FLAVOR_ALIAS)
def test_consume_VF_requests_remote_managed_filtered(self): self._create_pci_devices() pci_requests = [ objects.InstancePCIRequest(count=1, spec=[{ 'product_id': '101e', PCI_REMOTE_MANAGED_TAG: 'false' }]), objects.InstancePCIRequest(count=1, spec=[{ 'product_id': '101e' }]) ] free_devs_before = self.pci_stats.get_free_devs() devs = self.pci_stats.consume_requests(pci_requests) self.assertIsNone(devs) free_devs_after = self.pci_stats.get_free_devs() self.assertEqual(free_devs_before, free_devs_after)
def test_get_by_instance_uuid_and_newness(self, mock_get): pcir = objects.InstancePCIRequests mock_get.return_value = objects.InstancePCIRequests( instance_uuid=uuids.instance, requests=[objects.InstancePCIRequest(count=1, is_new=False), objects.InstancePCIRequest(count=2, is_new=True)]) old_req = pcir.get_by_instance_uuid_and_newness(self.context, uuids.instance, False) mock_get.return_value = objects.InstancePCIRequests( instance_uuid=uuids.instance, requests=[objects.InstancePCIRequest(count=1, is_new=False), objects.InstancePCIRequest(count=2, is_new=True)]) new_req = pcir.get_by_instance_uuid_and_newness(self.context, uuids.instance, True) self.assertEqual(1, old_req.requests[0].count) self.assertEqual(2, new_req.requests[0].count)
def test_consume_VF_and_PF_same_prodict_id_failed(self): self._create_pci_devices(pf_product_id=1515) pci_requests = [ objects.InstancePCIRequest(count=9, spec=[{ 'product_id': '1515' }]) ] self.assertRaises(exception.PciDeviceRequestFailed, self.pci_stats.consume_requests, pci_requests)
def _create_pci_requests_object(self, requests, instance_uuid=None): instance_uuid = instance_uuid or uuidsentinel.instance1 pci_reqs = [] for request in requests: pci_req_obj = objects.InstancePCIRequest(count=request['count'], spec=request['spec']) pci_reqs.append(pci_req_obj) return objects.InstancePCIRequests(instance_uuid=instance_uuid, requests=pci_reqs)
def test_pci_pass(self, mock_pci_supports_requests): request = objects.InstancePCIRequest(count=1, spec=[{ 'vendor_id': 'v', 'product_id': 'p' }]) requests = objects.InstancePCIRequests(requests=[request]) self._claim(requests=requests) mock_pci_supports_requests.assert_called_once_with([request])
def test_support_requests_no_numa_info(self): cells = [hardware.VirtNUMATopologyCell(0, None, None)] pci_request = [ objects.InstancePCIRequest(count=1, spec=[{ 'vendor_id': 'v3' }]) ] self.assertEqual(True, self.pci_stats.support_requests(pci_request, cells))
def test_pci_pass(self, mock_supports): request = objects.InstancePCIRequest(count=1, spec=[{'vendor_id': 'v', 'product_id': 'p'}]) requests = objects.InstancePCIRequests(requests=[request]) # Claim.__init__() would raise ComputeResourcesUnavailable # if Claim._test_pci() did not return None. self._claim(requests=requests) mock_supports.assert_called_once_with(requests.requests)