def test_numa_topology_with_pci_fail(self, mock_get_by_instance): dev_dict = { 'compute_node_id': 1, 'address': 'a', 'product_id': 'p', 'vendor_id': 'v', 'numa_node': 1, 'dev_type': 'type-PCI', 'parent_addr': 'a1', 'status': 'available' } dev_dict2 = { 'compute_node_id': 1, 'address': 'a', 'product_id': 'p', 'vendor_id': 'v', 'numa_node': 2, 'dev_type': 'type-PCI', 'parent_addr': 'a1', '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_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, requests=requests, numa_topology=huge_instance)
def test_obj_make_compatible(self): topo_obj = objects.InstanceNUMACell( cpuset=set(), pcpuset=set([0, 1]), cpuset_reserved=set([1, 2]), cpu_policy=fields.CPUAllocationPolicy.MIXED, ) versions = ovo_base.obj_tree_get_versions('InstanceNUMACell') data = lambda x: x['nova_object.data'] primitive = data( topo_obj.obj_to_primitive(target_version='1.6', version_manifest=versions)) self.assertEqual(fields.CPUAllocationPolicy.MIXED, primitive['cpu_policy']) self.assertRaises(exception.ObjectActionError, topo_obj.obj_to_primitive, target_version='1.5', version_manifest=versions) # set this to something compatible with < 1.6 so we can keep testing topo_obj.cpu_policy = fields.CPUAllocationPolicy.DEDICATED primitive = data( topo_obj.obj_to_primitive(target_version='1.5', version_manifest=versions)) self.assertIn('pcpuset', primitive) primitive = data( topo_obj.obj_to_primitive(target_version='1.4', version_manifest=versions)) self.assertNotIn('pcpuset', primitive) self.assertEqual(set([0, 1]), set(primitive['cpuset'])) self.assertIn('cpuset_reserved', primitive) primitive = data( topo_obj.obj_to_primitive(target_version='1.3', version_manifest=versions)) self.assertNotIn('cpuset_reserved', primitive)
def test_claim_fails_page_size_not_called(self): instance_type = self._fake_instance_type() instance = self._fake_instance() # This topology cannot fit in self.compute_node # (see _fake_compute_node()) numa_topology = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell( id=1, cpuset=set([1, 2, 3]), pcpuset=set(), memory=1024) ]) with test.nested( mock.patch('nova.virt.hardware.numa_get_constraints', return_value=numa_topology), mock.patch( 'nova.compute.claims.MoveClaim._test_live_migration_page_size' )) as (mock_test_numa, mock_test_page_size): self.assertRaisesRegex( exception.ComputeResourcesUnavailable, 'Requested instance NUMA topology', claims.MoveClaim, self.context, instance, _NODENAME, instance_type, {}, self.tracker, self.compute_node, self.empty_requests, objects.Migration(migration_type='live-migration'), None) mock_test_page_size.assert_not_called()
def _test_core_bind(self, context, instance, resource_tracker): LOG.debug("get instance cpu bind info in _test_core_bind") filter_properties = {} inst_extra = objects.HuaweiInstanceExtra.get_by_instance_uuid( context, instance.uuid) if inst_extra: scheduler_hints = jsonutils.loads(inst_extra.scheduler_hints or '{}') stats = jsonutils.loads(inst_extra.stats or '{}') else: scheduler_hints = {} stats = {} filter_properties['scheduler_hints'] = scheduler_hints filter_properties['stats'] = stats pci_requests = objects.InstancePCIRequests.get_by_instance_uuid( context, instance['uuid']) if pci_requests: filter_properties['pci_requests'] = pci_requests bind_info, instance_numa, enable_ht = sched_utils.get_inst_cpu_bind_info( instance, resource_tracker.host, filter_properties=filter_properties) sched_utils.update_cpu_bind_info_to_db(bind_info, instance.uuid, instance_numa) if instance_numa and instance_numa['cells'][0].get('is_huawei'): cells = [] for cell in instance_numa['cells']: cells.append( objects.InstanceNUMACell(id=cell['id'], cpuset=set(cell['cpuset']), memory=cell['mem']['total'], pagesize=cell.get('pagesize'))) format_inst_numa = objects.InstanceNUMATopology(cells=cells) self.claimed_numa_topology = format_inst_numa self.instance['numa_topology'] = format_inst_numa
def test_stat_consumption_from_instance_pci(self): inst_topology = objects.InstanceNUMATopology( cells = [objects.InstanceNUMACell( cpuset=set([0]), memory=512, id=0)]) fake_requests = [{'request_id': 'fake_request1', 'count': 1, '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=inst_topology, pci_requests=fake_requests_obj, flavor=objects.Flavor(root_gb=0, ephemeral_gb=0, memory_mb=512, vcpus=1)) host = host_manager.HostState("fakehost", "fakenode") self.assertIsNone(host.updated) host.pci_stats = pci_stats.PciDeviceStats( [objects.PciDevicePool(vendor_id='8086', product_id='15ed', numa_node=1, count=1)]) host.numa_topology = fakes.NUMA_TOPOLOGY host.consume_from_request(req_spec) self.assertIsInstance(req_spec.numa_topology, objects.InstanceNUMATopology) self.assertEqual(512, host.numa_topology.cells[1].memory_usage) self.assertEqual(1, host.numa_topology.cells[1].cpu_usage) self.assertEqual(0, len(host.pci_stats.pools)) self.assertIsNotNone(host.updated)
def test_create_migration_context(self): numa_topology = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell( id=1, cpuset=set([1, 2]), memory=512)]) claim = self._claim(numa_topology=numa_topology) migration = objects.Migration(context=self.context, id=42) claim.migration = migration fake_mig_context = mock.Mock(spec=objects.MigrationContext) @mock.patch('nova.db.instance_extra_get_by_instance_uuid', return_value=None) @mock.patch('nova.objects.MigrationContext', return_value=fake_mig_context) def _test(ctxt_mock, mock_get_extra): claim.create_migration_context() ctxt_mock.assert_called_once_with( context=self.context, instance_uuid=self.instance.uuid, migration_id=42, old_numa_topology=None, new_numa_topology=mock.ANY) self.assertIsInstance(ctxt_mock.call_args[1]['new_numa_topology'], objects.InstanceNUMATopology) self.assertEqual(migration, claim.migration) _test()
def test_numa_topology_with_pci(self, mock_get): dev_dict = { 'compute_node_id': 1, 'address': 'a', 'product_id': 'p', 'vendor_id': 'v', 'numa_node': 1, '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' }]) mock_get.return_value = objects.InstancePCIRequests(requests=[request]) huge_instance = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=1, cpuset=set([1, 2]), memory=512) ]) self._claim(numa_topology=huge_instance)
def _numa_fit_instance_cell(host_cell, instance_cell, limit_cell=None): """Check if a instance cell can fit and set it's cell id :param host_cell: host cell to fit the instance cell onto :param instance_cell: instance cell we want to fit :param limit_cell: cell with limits of the host_cell if any Make sure we can fit the instance cell onto a host cell and if so, return a new objects.InstanceNUMACell with the id set to that of the host, or None if the cell exceeds the limits of the host :returns: a new instance cell or None """ # NOTE (ndipanov): do not allow an instance to overcommit against # itself on any NUMA cell if (instance_cell.memory > host_cell.memory or len(instance_cell.cpuset) > len(host_cell.cpuset)): return None if limit_cell: memory_usage = host_cell.memory_usage + instance_cell.memory cpu_usage = host_cell.cpu_usage + len(instance_cell.cpuset) if (memory_usage > limit_cell.memory_limit or cpu_usage > limit_cell.cpu_limit): return None pagesize = None if instance_cell.pagesize: pagesize = _numa_cell_supports_pagesize_request( host_cell, instance_cell) if not pagesize: return return objects.InstanceNUMACell(id=host_cell.id, cpuset=instance_cell.cpuset, memory=instance_cell.memory, pagesize=pagesize)
def test_cpu_pinning_requested_cell(self): inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), cpu_pinning=None) self.assertFalse(inst_cell.cpu_pinning_requested) inst_cell.cpu_pinning = {} self.assertTrue(inst_cell.cpu_pinning_requested)
def _schedule(self, context, request_spec, filter_properties): """Returns a list of hosts that meet the required specs, ordered by their fitness. """ elevated = context.elevated() instance_properties = request_spec['instance_properties'] instance_type = request_spec.get("instance_type", None) instance_uuids = request_spec.get("instance_uuids", None) LOG.debug("[HINTS] filter_properties=%s" % filter_properties) # query scheduler_hints from database, and skip what in the parameters. if instance_uuids: inst_extra = objects.HuaweiInstanceExtra.get_by_instance_uuid( context, instance_uuids[0]) if inst_extra: scheduler_hints = jsonutils.loads(inst_extra.scheduler_hints or '{}') stats = jsonutils.loads(inst_extra.stats or '{}') else: scheduler_hints = {} stats = {} LOG.debug("[HINTS] Got scheduler_hints via db. " "scheduler_hints=%s" % scheduler_hints) filter_properties['scheduler_hints'] = scheduler_hints filter_properties['stats'] = stats instance_properties['stats'] = stats try: update_group_hosts = self._setup_instance_group( context, filter_properties) except exception.InstanceGroupNotFound as e: # InstanceGroup has already checked in API, # might has been deleted when migrate/ha LOG.warning("ServerGroup %s doesn't exist" % scheduler_hints.get('group', "None")) update_group_hosts = False config_options = self._get_configuration_options() filter_properties.update({ 'context': context, 'request_spec': request_spec, 'config_options': config_options, 'instance_type': instance_type }) self.populate_filter_properties(request_spec, filter_properties) # Find our local list of acceptable hosts by repeatedly # filtering and weighing our options. Each time we choose a # host, we virtually consume resources on it so subsequent # selections can adjust accordingly. # Note: remember, we are using an iterator here. So only # traverse this list once. This can bite you if the hosts # are being scanned in a filter or weighing function. hosts = self._get_all_host_states(elevated) selected_hosts = [] if instance_uuids: num_instances = len(instance_uuids) else: num_instances = request_spec.get('num_instances', 1) for num in xrange(num_instances): #NOTE: add a tracker of filter tracker = HuaweiFilterTracker() filter_properties['__tracker'] = tracker # Filter local hosts based on requirements ... hosts = self.host_manager.get_filtered_hosts(hosts, filter_properties, index=num) if not hosts: # Can't get any more locally. break LOG.debug("Filtered %(hosts)s", {'hosts': hosts}) weighed_hosts = self.host_manager.get_weighed_hosts( hosts, filter_properties) LOG.debug("Weighed %(hosts)s", {'hosts': weighed_hosts}) scheduler_host_subset_size = CONF.scheduler_host_subset_size if scheduler_host_subset_size > len(weighed_hosts): scheduler_host_subset_size = len(weighed_hosts) if scheduler_host_subset_size < 1: scheduler_host_subset_size = 1 chosen_host = random.choice( weighed_hosts[0:scheduler_host_subset_size]) host_mapper = dict() for host in weighed_hosts: host_mapper[host.obj.host] = host if 'resize_prefer_to_same_host' in filter_properties: origin_host = filter_properties['resize_prefer_to_same_host'] chosen_host = host_mapper.get(origin_host, chosen_host) migrate_host = filter_properties.get('migrate_host') if migrate_host: if migrate_host in host_mapper: chosen_host = host_mapper.get(migrate_host) else: # migrate_host not in filter hosts list # raise NoVaildHost break selected_hosts.append(chosen_host) # Now consume the resources so the filter/weights # will change for the next instance. # NOTE () adding and deleting pci_requests is a temporary # fix to avoid DB access in consume_from_instance() while getting # pci_requests. The change can be removed once pci_requests is # part of the instance object that is passed into the scheduler # APIs pci_requests = filter_properties.get('pci_requests') if pci_requests: instance_properties['pci_requests'] = pci_requests if request_spec.get('instance_type'): instance_properties['numa_topology'] = \ hardware.numa_get_constraints(instance_type, {}) self._update_instance_topology(instance_properties, chosen_host) try: bind_info, instance_numa, __ = utils.get_inst_cpu_bind_info( instance_properties, chosen_host.obj, filter_properties=filter_properties) except exception.NovaException as ex: msg = ("Get cpu binding info on host %(host)s failed, the" " host_numa_top is %(host_numa_top)s, " "instance_properties is %(instance_properties)s") params = { 'host': chosen_host.obj.host, 'host_numa_top': chosen_host.obj.numa_topology, 'instance_properties': instance_properties } # set bind_info and instance_numa is None bind_info = None instance_numa = None LOG.debug(_LE(msg), params) LOG.debug(_LE(ex.format_message())) scheduler_hints = filter_properties.get('scheduler_hints', None) if instance_numa and instance_numa['cells'][0].get('is_huawei'): cells = [] for cell in instance_numa['cells']: cells.append( objects.InstanceNUMACell( id=cell['id'], cpuset=set(cell['cpuset']), memory=cell['mem']['total'], pagesize=cell.get('pagesize'))) format_inst_numa = objects.InstanceNUMATopology(cells=cells) instance_properties['numa_topology'] = format_inst_numa try: if isinstance(chosen_host.obj, ironic_host_manager.IronicNodeState): chosen_host.obj.consume_from_instance(instance_properties) else: chosen_host.obj.consume_from_instance( instance_properties, filter_properties) except exception.PciDeviceRequestFailed as e: # pop the select chosen host in order to rollback resource in # memory LOG.warning("consume get exception: %s", e.format_message()) rollback_hosts = [chosen_host] self.host_manager.force_update_host_states( context, rollback_hosts) if pci_requests: del instance_properties['pci_requests'] if update_group_hosts is True: # NOTE(): Group details are serialized into a list now # that they are populated by the conductor, we need to # deserialize them if isinstance(filter_properties['group_hosts'], list): filter_properties['group_hosts'] = set( filter_properties['group_hosts']) self._check_fulfill_for_multiple_create(context, num_instances, selected_hosts) return selected_hosts
def test_siblings(self): # default thread number of VirtualCPUTopology is one, one thread means # no thread and no sibling inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2]), pcpuset=set()) self.assertEqual([], inst_cell.siblings) inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2]), pcpuset=set([4, 5, 6])) self.assertEqual([], inst_cell.siblings) # 'threads=0' means no sibling topo = objects.VirtCPUTopology(sockets=1, cores=3, threads=0) inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2]), pcpuset=set(), cpu_topology=topo) self.assertEqual([], inst_cell.siblings) inst_cell = objects.InstanceNUMACell(cpuset=set(), pcpuset=set([0, 1, 2]), cpu_topology=topo) self.assertEqual([], inst_cell.siblings) # One thread actually means no threads topo = objects.VirtCPUTopology(sockets=1, cores=3, threads=1) inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2]), pcpuset=set(), cpu_topology=topo) self.assertEqual([], inst_cell.siblings) inst_cell = objects.InstanceNUMACell(cpuset=set(), pcpuset=set([0, 1, 2]), cpu_topology=topo) self.assertEqual([], inst_cell.siblings) # 2 threads per virtual core, and numa node has only one type CPU # pinned and un-pinned. topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=2) inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), pcpuset=set(), cpu_topology=topo) self.assertEqual([set([0, 1]), set([2, 3])], inst_cell.siblings) inst_cell = objects.InstanceNUMACell(cpuset=set(), pcpuset=set([0, 1, 2, 3]), cpu_topology=topo) self.assertEqual([set([0, 1]), set([2, 3])], inst_cell.siblings) # 4 threads per virtual core, numa node has only one type CPU topo = objects.VirtCPUTopology(sockets=1, cores=1, threads=4) inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), pcpuset=set(), cpu_topology=topo) self.assertEqual([set([0, 1, 2, 3])], inst_cell.siblings) inst_cell = objects.InstanceNUMACell(cpuset=set(), pcpuset=set([0, 1, 2, 3]), cpu_topology=topo) self.assertEqual([set([0, 1, 2, 3])], inst_cell.siblings) # 2 threads per virtual core, numa node with two type CPUs, the pinned # and un-pinned topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=2) inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1]), pcpuset=set([2, 3]), cpu_topology=topo) self.assertEqual([set([0, 1]), set([2, 3])], inst_cell.siblings)
def test_numa_pinning_requested_cell(self): inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), physnode=None) self.assertFalse(inst_cell.numa_pinning_requested) inst_cell.physnode = 0 self.assertTrue(inst_cell.numa_pinning_requested)
def test_obj_make_compatible_numa_cell_pre_1_4(self): topo_obj = objects.InstanceNUMACell(cpuset_reserved=set([1, 2])) versions = ovo_base.obj_tree_get_versions('InstanceNUMACell') primitive = topo_obj.obj_to_primitive(target_version='1.3', version_manifest=versions) self.assertNotIn('cpuset_reserved', primitive)
def test_cpu_pinning_requested_cell(self): inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), cpu_pinning=None) self.assertFalse(inst_cell.cpu_pinning_requested) inst_cell.cpu_policy = fields.CPUAllocationPolicy.DEDICATED self.assertTrue(inst_cell.cpu_pinning_requested)
def test_pin_vcpus(self): inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), cpu_pinning=None) inst_cell.pin_vcpus((0, 14), (1, 15), (2, 16), (3, 17)) self.assertEqual({0: 14, 1: 15, 2: 16, 3: 17}, inst_cell.cpu_pinning)
# Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from oslo_serialization import jsonutils from oslo_utils import uuidutils from nova import context from nova import objects from nova.tests.unit import fake_flavor from nova.tests import uuidsentinel as uuids INSTANCE_NUMA_TOPOLOGY = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([1, 2]), memory=512), objects.InstanceNUMACell(id=1, cpuset=set([3, 4]), memory=512) ]) INSTANCE_NUMA_TOPOLOGY.obj_reset_changes(recursive=True) IMAGE_META = objects.ImageMeta.from_dict({ 'status': 'active', 'container_format': 'bare', 'min_ram': 0, 'updated_at': '2014-12-12T11:16:36.000000', 'min_disk': 0,
def test_pci_claim_instance_with_numa_fail(self, mock_get): self._create_pci_requests_object(mock_get, fake_pci_requests) self.inst.numa_topology = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=1, cpuset=set([1, 2]), memory=512) ]) self.assertIsNone(self.tracker.claim_instance(None, self.inst))
class CellsSchedulerTestCase(test.TestCase): """Test case for CellsScheduler class.""" def setUp(self): super(CellsSchedulerTestCase, self).setUp() self.flags(scheduler_filter_classes=[], scheduler_weight_classes=[], group='cells') self._init_cells_scheduler() def _init_cells_scheduler(self): fakes.init(self) self.msg_runner = fakes.get_message_runner('api-cell') self.scheduler = self.msg_runner.scheduler self.state_manager = self.msg_runner.state_manager self.my_cell_state = self.state_manager.get_my_state() self.ctxt = context.RequestContext('fake', 'fake') instance_uuids = [] for x in range(3): instance_uuids.append(uuidutils.generate_uuid()) self.instance_uuids = instance_uuids self.instances = [objects.Instance(uuid=uuid, id=id) for id, uuid in enumerate(instance_uuids)] self.request_spec = { 'num_instances': len(instance_uuids), 'instance_properties': self.instances[0], 'instance_type': 'fake_type', 'image': 'fake_image'} self.build_inst_kwargs = { 'instances': self.instances, 'image': 'fake_image', 'filter_properties': {'instance_type': 'fake_type'}, 'security_groups': 'fake_sec_groups', 'block_device_mapping': 'fake_bdm'} def test_create_instances_here(self): # Just grab the first instance type inst_type = objects.Flavor.get_by_id(self.ctxt, 1) image = {'properties': {}} instance_uuids = self.instance_uuids instance_props = {'id': 'removed', 'security_groups': 'removed', 'info_cache': 'removed', 'name': 'instance-00000001', 'hostname': 'meow', 'display_name': 'moo', 'image_ref': 'fake_image_ref', 'user_id': self.ctxt.user_id, # Test these as lists 'metadata': {'moo': 'cow'}, 'system_metadata': {'meow': 'cat'}, 'flavor': inst_type, 'project_id': self.ctxt.project_id, 'numa_topology': None} call_info = {'uuids': []} block_device_mapping = [ objects.BlockDeviceMapping(context=self.ctxt, **fake_block_device.FakeDbBlockDeviceDict( block_device.create_image_bdm('fake_image_ref'), anon=True)) ] def _fake_instance_update_at_top(_ctxt, instance): call_info['uuids'].append(instance['uuid']) self.stubs.Set(self.msg_runner, 'instance_update_at_top', _fake_instance_update_at_top) self.scheduler._create_instances_here(self.ctxt, instance_uuids, instance_props, inst_type, image, ['default'], block_device_mapping) self.assertEqual(instance_uuids, call_info['uuids']) for count, instance_uuid in enumerate(instance_uuids): instance = db.instance_get_by_uuid(self.ctxt, instance_uuid) meta = utils.instance_meta(instance) self.assertEqual('cow', meta['moo']) sys_meta = utils.instance_sys_meta(instance) self.assertEqual('cat', sys_meta['meow']) self.assertEqual('meow', instance['hostname']) self.assertEqual('moo-%d' % (count + 1), instance['display_name']) self.assertEqual('fake_image_ref', instance['image_ref']) def test_build_instances_selects_child_cell(self): # Make sure there's no capacity info so we're sure to # select a child cell our_cell_info = self.state_manager.get_my_state() our_cell_info.capacities = {} call_info = {'times': 0} orig_fn = self.msg_runner.build_instances def msg_runner_build_instances(ctxt, target_cell, build_inst_kwargs): # This gets called twice. Once for our running it # in this cell.. and then it'll get called when the # child cell is picked. So, first time.. just run it # like normal. if not call_info['times']: call_info['times'] += 1 return orig_fn(ctxt, target_cell, build_inst_kwargs) call_info['ctxt'] = ctxt call_info['target_cell'] = target_cell call_info['build_inst_kwargs'] = build_inst_kwargs def fake_build_request_spec(ctxt, image, instances): request_spec = { 'num_instances': len(instances), 'image': image} return request_spec self.stubs.Set(self.msg_runner, 'build_instances', msg_runner_build_instances) self.stubs.Set(scheduler_utils, 'build_request_spec', fake_build_request_spec) self.msg_runner.build_instances(self.ctxt, self.my_cell_state, self.build_inst_kwargs) self.assertEqual(self.ctxt, call_info['ctxt']) self.assertEqual(self.build_inst_kwargs, call_info['build_inst_kwargs']) child_cells = self.state_manager.get_child_cells() self.assertIn(call_info['target_cell'], child_cells) def test_build_instances_selects_current_cell(self): # Make sure there's no child cells so that we will be # selected self.state_manager.child_cells = {} call_info = {} build_inst_kwargs = copy.deepcopy(self.build_inst_kwargs) def fake_create_instances_here(ctxt, instance_uuids, instance_properties, instance_type, image, security_groups, block_device_mapping): call_info['ctxt'] = ctxt call_info['instance_uuids'] = instance_uuids call_info['instance_properties'] = instance_properties call_info['instance_type'] = instance_type call_info['image'] = image call_info['security_groups'] = security_groups call_info['block_device_mapping'] = block_device_mapping return self.instances def fake_rpc_build_instances(ctxt, **build_inst_kwargs): call_info['build_inst_kwargs'] = build_inst_kwargs def fake_build_request_spec(ctxt, image, instances): request_spec = { 'num_instances': len(instances), 'image': image} return request_spec self.stubs.Set(self.scheduler, '_create_instances_here', fake_create_instances_here) self.stubs.Set(self.scheduler.compute_task_api, 'build_instances', fake_rpc_build_instances) self.stubs.Set(scheduler_utils, 'build_request_spec', fake_build_request_spec) self.msg_runner.build_instances(self.ctxt, self.my_cell_state, build_inst_kwargs) self.assertEqual(self.ctxt, call_info['ctxt']) self.assertEqual(self.instance_uuids, call_info['instance_uuids']) self.assertEqual(self.build_inst_kwargs['instances'][0]['id'], call_info['instance_properties']['id']) self.assertEqual( self.build_inst_kwargs['filter_properties']['instance_type'], call_info['instance_type']) self.assertEqual(self.build_inst_kwargs['image'], call_info['image']) self.assertEqual(self.build_inst_kwargs['security_groups'], call_info['security_groups']) self.assertEqual(self.build_inst_kwargs['block_device_mapping'], call_info['block_device_mapping']) self.assertEqual(build_inst_kwargs, call_info['build_inst_kwargs']) self.assertEqual(self.instance_uuids, call_info['instance_uuids']) def test_build_instances_retries_when_no_cells_avail(self): self.flags(scheduler_retries=7, group='cells') call_info = {'num_tries': 0, 'errored_uuids': []} def fake_grab_target_cells(filter_properties): call_info['num_tries'] += 1 raise exception.NoCellsAvailable() def fake_sleep(_secs): return def fake_instance_save(inst): self.assertEqual(vm_states.ERROR, inst.vm_state) call_info['errored_uuids'].append(inst.uuid) def fake_build_request_spec(ctxt, image, instances): request_spec = { 'num_instances': len(instances), 'image': image} return request_spec self.stubs.Set(self.scheduler, '_grab_target_cells', fake_grab_target_cells) self.stubs.Set(time, 'sleep', fake_sleep) self.stubs.Set(objects.Instance, 'save', fake_instance_save) self.stubs.Set(scheduler_utils, 'build_request_spec', fake_build_request_spec) self.msg_runner.build_instances(self.ctxt, self.my_cell_state, self.build_inst_kwargs) self.assertEqual(8, call_info['num_tries']) self.assertEqual(self.instance_uuids, call_info['errored_uuids']) def test_build_instances_numa_topology_not_none(self): self.build_inst_kwargs['instances'][0].numa_topology = objects.InstanceNUMATopology() self.build_inst_kwargs['instances'][0].numa_topology.cells = [objects.InstanceNUMACell(cpu_pinning_raw=None,cpu_topology=None, cpuset=set([0]),id=0,memory=64,pagesize=None)]
fake_build_request_spec) self.msg_runner.build_instances(self.ctxt, self.my_cell_state, self.build_inst_kwargs) self.assertEqual(8, call_info['num_tries']) self.assertEqual(self.instance_uuids, call_info['errored_uuids']) def test_build_instances_numa_topology_not_none(self): self.build_inst_kwargs['instances'][0].numa_topology = objects.InstanceNUMATopology() self.build_inst_kwargs['instances'][0].numa_topology.cells = [objects.InstanceNUMACell(cpu_pinning_raw=None,cpu_topology=None, cpuset=set([0]),id=0,memory=64,pagesize=None)] instance_topology = objects.InstanceNUMATopology() instance_topology.cells = [objects.InstanceNUMACell(cpu_pinning_raw=None, cpu_topology=None,cpuset=set([0]),id=0,memory=64,pagesize=None)] self.msg_runner.build_instances(self.ctxt, self.my_cell_state, self.build_inst_kwargs) self.assertEqual(instance_topology.cells[0]['cpu_pinning_raw'], self.build_inst_kwargs['instances'][0].numa_topology.cells[0]['cpu_pinning_raw']) self.assertEqual(instance_topology.cells[0]['cpu_topology'], self.build_inst_kwargs['instances'][0].numa_topology.cells[0]['cpu_topology']) self.assertEqual(instance_topology.cells[0]['cpuset'], self.build_inst_kwargs['instances'][0].numa_topology.cells[0]['cpuset']) self.assertEqual(instance_topology.cells[0]['id'], self.build_inst_kwargs['instances'][0].numa_topology.cells[0]['id']) self.assertEqual(instance_topology.cells[0]['memory'], self.build_inst_kwargs['instances'][0].numa_topology.cells[0]['memory']) self.assertEqual(instance_topology.cells[0]['pagesize'],
def _instance_topology(self, mem): mem = mem * 1024 return objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([1]), memory=mem), objects.InstanceNUMACell(id=1, cpuset=set([3]), memory=mem) ])
def test_consume_requests_numa_failed(self): cells = [ objects.InstanceNUMACell( id=0, cpuset=set(), pcpuset=set(), memory=0), ] self.assertIsNone(self.pci_stats.consume_requests(pci_requests, cells))
import mock from oslo_serialization import jsonutils from nova import exception from nova import objects from nova.objects import fields from nova.tests.unit.objects import test_objects fake_instance_uuid = str(uuid.uuid4()) fake_obj_numa_topology = objects.InstanceNUMATopology( instance_uuid=fake_instance_uuid, cells=[ objects.InstanceNUMACell(id=0, cpuset=set([1, 2]), memory=512, pagesize=2048), objects.InstanceNUMACell(id=1, cpuset=set([3, 4]), memory=512, pagesize=2048) ]) fake_numa_topology = fake_obj_numa_topology._to_dict() fake_db_topology = { 'created_at': None, 'updated_at': None, 'deleted_at': None, 'deleted': 0, 'id': 1,
1: flavors.save_flavor_info({}, _INSTANCE_TYPE_FIXTURES[1]), 2: flavors.save_flavor_info({}, _INSTANCE_TYPE_FIXTURES[2]), } _MIGRATION_SYS_META = flavors.save_flavor_info({}, _INSTANCE_TYPE_FIXTURES[1], 'old_') _MIGRATION_SYS_META = flavors.save_flavor_info(_MIGRATION_SYS_META, _INSTANCE_TYPE_FIXTURES[2], 'new_') _2MB = 2 * units.Mi / units.Ki _INSTANCE_NUMA_TOPOLOGIES = { '2mb': objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell( id=0, cpuset=set([1]), memory=_2MB, pagesize=0), objects.InstanceNUMACell( id=1, cpuset=set([3]), memory=_2MB, pagesize=0) ]), } _NUMA_LIMIT_TOPOLOGIES = { '2mb': objects.NUMATopologyLimits(id=0, cpu_allocation_ratio=1.0, ram_allocation_ratio=1.0), } _NUMA_PAGE_TOPOLOGIES = { '2kb*8': objects.NUMAPagesTopology(size_kb=2, total=8, used=0) }
def test_default_behavior(self): inst_cell = objects.InstanceNUMACell() self.assertEqual(0, len(inst_cell.obj_get_changes()))
def test_support_requests_numa_failed(self): cells = [objects.InstanceNUMACell(id=0, cpuset=set(), memory=0)] self.assertFalse(self.pci_stats.support_requests(pci_requests, cells))
def test_numa_topology_no_limit(self): huge_instance = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=1, cpuset=set([1, 2]), memory=512) ]) self._claim(numa_topology=huge_instance)
def test_consume_requests_numa_failed(self): cells = [objects.InstanceNUMACell(id=0, cpuset=set(), memory=0)] self.assertRaises(exception.PciDeviceRequestFailed, self.pci_stats.consume_requests, pci_requests, cells)