# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # 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.fixture import uuidsentinel as uuids from nova import conf from nova import objects from nova.objects import numa from nova.scheduler import host_manager from nova.tests.unit.objects import test_objects CONF = conf.CONF fake_numa_limit1 = numa.NUMATopologyLimits(cpu_allocation_ratio=1.0, ram_allocation_ratio=1.0) fake_limit1 = {"memory_mb": 1024, "disk_gb": 100, "vcpus": 2, "numa_topology": fake_numa_limit1} fake_limit_obj1 = objects.SchedulerLimits.from_dict(fake_limit1) fake_host1 = { "uuid": uuids.host1, "host": "host1", "nodename": "node1", "cell_uuid": uuids.cell, "limits": fake_limit1, } fake_host_state1 = host_manager.HostState("host1", "node1", uuids.cell) fake_host_state1.uuid = uuids.host1 fake_host_state1.limits = fake_limit1.copy() fake_alloc1 = {"allocations": [ {"resource_provider": {"uuid": uuids.host1}, "resources": {"VCPU": 1, "MEMORY_MB": 1024, "DISK_GB": 100} }]} fake_alloc_version = "1.23" class _TestSelectionObject(object): def test_create_with_values(self): json_alloc = jsonutils.dumps(fake_alloc1) dest = objects.Selection(service_host="host", nodename="node", compute_node_uuid=uuids.host1, cell_uuid=uuids.cell, limits=fake_limit_obj1, allocation_request=json_alloc, allocation_request_version=fake_alloc_version) self.assertEqual("host", dest.service_host) self.assertEqual(uuids.host1, dest.compute_node_uuid) self.assertEqual("node", dest.nodename) self.assertEqual(uuids.cell, dest.cell_uuid) self.assertEqual(fake_limit_obj1, dest.limits) self.assertEqual(json_alloc, dest.allocation_request) self.assertEqual(fake_alloc_version, dest.allocation_request_version) def test_passing_dict_allocation_fails(self): self.assertRaises(ValueError, objects.Selection, service_host="host", compute_node_uuid=uuids.host, nodename="node", cell_uuid=uuids.cell, allocation_request=fake_alloc1, allocation_request_version=fake_alloc_version) def test_passing_numeric_allocation_version_converts(self): json_alloc = jsonutils.dumps(fake_alloc1) dest = objects.Selection(service_host="host", compute_node_uuid=uuids.host, nodename="node", cell_uuid=uuids.cell, allocation_request=json_alloc, allocation_request_version=1.23) self.assertEqual("1.23", dest.allocation_request_version) def test_from_host_state(self): dest = objects.Selection.from_host_state(fake_host_state1, fake_alloc1, fake_alloc_version) self.assertEqual(dest.service_host, fake_host_state1.host) expected_alloc = jsonutils.dumps(fake_alloc1) self.assertEqual(dest.allocation_request, expected_alloc) self.assertEqual(dest.allocation_request_version, fake_alloc_version) def test_from_host_state_no_alloc_info(self): dest = objects.Selection.from_host_state(fake_host_state1) self.assertEqual(dest.service_host, fake_host_state1.host) expected_alloc = jsonutils.dumps(None) self.assertEqual(expected_alloc, dest.allocation_request) self.assertIsNone(dest.allocation_request_version) def test_selection_obj_to_dict(self): """Tests that to_dict() method properly converts a Selection object to the corresponding dict. """ fake_network_metadata = objects.NetworkMetadata( physnets=set(['foo', 'bar']), tunneled=True) fake_numa_limit = objects.numa.NUMATopologyLimits( cpu_allocation_ratio=1.0, ram_allocation_ratio=1.0, network_metadata=fake_network_metadata) fake_limit = {"memory_mb": 1024, "disk_gb": 100, "vcpus": 2, "numa_topology": fake_numa_limit} fake_limit_obj = objects.SchedulerLimits.from_dict(fake_limit) sel_obj = objects.Selection(service_host="fakehost", nodename="fakenode", compute_node_uuid=uuids.host, cell_uuid=uuids.cell, limits=fake_limit_obj, allocation_request="fake", allocation_request_version="99.9") result = sel_obj.to_dict() self.assertEqual(['host', 'limits', 'nodename'], sorted(result.keys())) self.assertEqual('fakehost', result['host']) self.assertEqual('fakenode', result['nodename']) limits = result['limits'] self.assertEqual(['disk_gb', 'memory_mb', 'numa_topology'], sorted(limits.keys())) self.assertEqual(100, limits['disk_gb']) self.assertEqual(1024, limits['memory_mb']) numa_topology = limits['numa_topology']['nova_object.data'] self.assertEqual(1.0, numa_topology['cpu_allocation_ratio']) self.assertEqual(1.0, numa_topology['ram_allocation_ratio']) network_meta = numa_topology['network_metadata']['nova_object.data'] # sets are unordered so we need to convert to a list self.assertEqual(['bar', 'foo'], sorted(network_meta['physnets'])) self.assertTrue(network_meta['tunneled']) def test_selection_obj_to_dict_no_numa(self): """Tests that to_dict() method properly converts a Selection object to the corresponding dict when the numa_topology field is None. """ fake_limit = {"memory_mb": 1024, "disk_gb": 100, "vcpus": 2, "numa_topology": None} fake_limit_obj = objects.SchedulerLimits.from_dict(fake_limit) sel_obj = objects.Selection(service_host="fakehost", nodename="fakenode", compute_node_uuid=uuids.host, cell_uuid=uuids.cell, limits=fake_limit_obj, allocation_request="fake", allocation_request_version="99.9") expected = {"host": "fakehost", "nodename": "fakenode", "limits": { "disk_gb": 100, "memory_mb": 1024}} result = sel_obj.to_dict() self.assertDictEqual(expected, result) class TestSelectionObject(test_objects._LocalTest, _TestSelectionObject): # NOTE(mriedem): The tests below are for methods which are not remotable # so they can go in the local-only test class rather than the mixin above. def test_obj_make_compatible(self): selection = objects.Selection(service_host='host1', availability_zone='zone1') primitive = selection.obj_to_primitive( target_version='1.1')['nova_object.data'] self.assertIn('availability_zone', primitive) primitive = selection.obj_to_primitive( target_version='1.0')['nova_object.data'] self.assertNotIn('availability_zone', primitive) self.assertIn('service_host', primitive) def test_from_host_state_az_via_aggregate_metadata(self): """Tests the scenario that the host is in multiple aggregates and one has the availability_zone aggregate metadata key which is used on the selection object. """ host_state = host_manager.HostState('host', 'node', uuids.cell_uuid) host_state.uuid = uuids.compute_node_uuid host_state.limits = {} host_state.aggregates = [ objects.Aggregate(metadata={'foo': 'bar'}), objects.Aggregate(metadata={'availability_zone': 'zone1'}) ] selection = objects.Selection.from_host_state(host_state) self.assertEqual('zone1', selection.availability_zone) def test_from_host_state_az_via_config(self): """Tests the scenario that the host is not in an aggregate with the availability_zone metadata key so the AZ comes from config. """ host_state = host_manager.HostState('host', 'node', uuids.cell_uuid) host_state.uuid = uuids.compute_node_uuid host_state.limits = {} host_state.aggregates = [] selection = objects.Selection.from_host_state(host_state) self.assertEqual(CONF.default_availability_zone, selection.availability_zone) class TestRemoteSelectionObject(test_objects._RemoteTest, _TestSelectionObject): pass