diff --git a/nova/scheduler/client/report.py b/nova/scheduler/client/report.py index b444d8f249..e582642a9a 100644 --- a/nova/scheduler/client/report.py +++ b/nova/scheduler/client/report.py @@ -93,6 +93,25 @@ def _compute_node_to_inventory_dict(compute_node): } +def _instance_to_allocations_dict(instance): + """Given an `objects.Instance` object, return a dict, keyed by resource + class of the amount used by the instance. + + :param instance: `objects.Instance` object to translate + """ + # NOTE(danms): Boot-from-volume instances consume no local disk + is_bfv = compute_utils.is_volume_backed_instance(instance._context, + instance) + disk = ((0 if is_bfv else instance.flavor.root_gb) + + instance.flavor.swap + + instance.flavor.ephemeral_gb) + return { + MEMORY_MB: instance.flavor.memory_mb, + VCPU: instance.flavor.vcpus, + DISK_GB: disk, + } + + class SchedulerReportClient(object): """Client class for updating the scheduler.""" @@ -348,19 +367,6 @@ class SchedulerReportClient(object): compute_node.hypervisor_hostname) self._update_inventory(compute_node) - def _allocations(self, instance): - # NOTE(danms): Boot-from-volume instances consume no local disk - is_bfv = compute_utils.is_volume_backed_instance(instance._context, - instance) - disk = ((0 if is_bfv else instance.flavor.root_gb) + - instance.flavor.swap + - instance.flavor.ephemeral_gb) - return { - MEMORY_MB: instance.flavor.memory_mb, - VCPU: instance.flavor.vcpus, - DISK_GB: disk, - } - def _get_allocations_for_instance(self, compute_node, instance): url = '/allocations/%s' % instance.uuid resp = self.get(url) @@ -377,7 +383,7 @@ class SchedulerReportClient(object): def _allocate_for_instance(self, compute_node, instance): url = '/allocations/%s' % instance.uuid - my_allocations = self._allocations(instance) + my_allocations = _instance_to_allocations_dict(instance) current_allocations = self._get_allocations_for_instance(compute_node, instance) if current_allocations == my_allocations: diff --git a/nova/tests/unit/scheduler/client/test_report.py b/nova/tests/unit/scheduler/client/test_report.py index dcd136a77f..9ba31a30f2 100644 --- a/nova/tests/unit/scheduler/client/test_report.py +++ b/nova/tests/unit/scheduler/client/test_report.py @@ -676,7 +676,7 @@ class TestInventory(SchedulerReportClientTestCase): class TestAllocations(SchedulerReportClientTestCase): @mock.patch('nova.compute.utils.is_volume_backed_instance') - def test_allocations(self, mock_vbi): + def test_instance_to_allocations_dict(self, mock_vbi): mock_vbi.return_value = False inst = objects.Instance( uuid=uuids.inst, @@ -685,15 +685,16 @@ class TestAllocations(SchedulerReportClientTestCase): ephemeral_gb=100, memory_mb=1024, vcpus=2)) + result = report._instance_to_allocations_dict(inst) expected = { 'MEMORY_MB': 1024, 'VCPU': 2, 'DISK_GB': 111, } - self.assertEqual(expected, self.client._allocations(inst)) + self.assertEqual(expected, result) @mock.patch('nova.compute.utils.is_volume_backed_instance') - def test_allocations_boot_from_volume(self, mock_vbi): + def test_instance_to_allocations_dict_boot_from_volume(self, mock_vbi): mock_vbi.return_value = True inst = objects.Instance( uuid=uuids.inst, @@ -702,38 +703,44 @@ class TestAllocations(SchedulerReportClientTestCase): ephemeral_gb=100, memory_mb=1024, vcpus=2)) + result = report._instance_to_allocations_dict(inst) expected = { 'MEMORY_MB': 1024, 'VCPU': 2, 'DISK_GB': 101, } - self.assertEqual(expected, self.client._allocations(inst)) + self.assertEqual(expected, result) @mock.patch('nova.scheduler.client.report.SchedulerReportClient.' 'put') @mock.patch('nova.scheduler.client.report.SchedulerReportClient.' 'get') - def test_update_instance_allocation_new(self, mock_get, mock_put): + @mock.patch('nova.scheduler.client.report.' + '_instance_to_allocations_dict') + def test_update_instance_allocation_new(self, mock_a, mock_get, + mock_put): cn = objects.ComputeNode(uuid=uuids.cn) inst = objects.Instance(uuid=uuids.inst) mock_get.return_value.json.return_value = {'allocations': {}} - with mock.patch.object(self.client, '_allocations') as mock_a: - expected = { - 'allocations': [ - {'resource_provider': {'uuid': cn.uuid}, - 'resources': mock_a.return_value}] - } - self.client.update_instance_allocation(cn, inst, 1) - mock_put.assert_called_once_with( - '/allocations/%s' % inst.uuid, - expected) - self.assertTrue(mock_get.called) + expected = { + 'allocations': [ + {'resource_provider': {'uuid': cn.uuid}, + 'resources': mock_a.return_value}] + } + self.client.update_instance_allocation(cn, inst, 1) + mock_put.assert_called_once_with( + '/allocations/%s' % inst.uuid, + expected) + self.assertTrue(mock_get.called) @mock.patch('nova.scheduler.client.report.SchedulerReportClient.' 'put') @mock.patch('nova.scheduler.client.report.SchedulerReportClient.' 'get') - def test_update_instance_allocation_existing(self, mock_get, mock_put): + @mock.patch('nova.scheduler.client.report.' + '_instance_to_allocations_dict') + def test_update_instance_allocation_existing(self, mock_a, mock_get, + mock_put): cn = objects.ComputeNode(uuid=uuids.cn) inst = objects.Instance(uuid=uuids.inst) mock_get.return_value.json.return_value = {'allocations': { @@ -745,33 +752,33 @@ class TestAllocations(SchedulerReportClientTestCase): } }} } - with mock.patch.object(self.client, '_allocations') as mock_a: - mock_a.return_value = { - 'DISK_GB': 123, - 'MEMORY_MB': 456, - } - self.client.update_instance_allocation(cn, inst, 1) - self.assertFalse(mock_put.called) - mock_get.assert_called_once_with( - '/allocations/%s' % inst.uuid) + mock_a.return_value = { + 'DISK_GB': 123, + 'MEMORY_MB': 456, + } + self.client.update_instance_allocation(cn, inst, 1) + self.assertFalse(mock_put.called) + mock_get.assert_called_once_with( + '/allocations/%s' % inst.uuid) @mock.patch('nova.scheduler.client.report.SchedulerReportClient.' 'get') @mock.patch('nova.scheduler.client.report.SchedulerReportClient.' 'put') + @mock.patch('nova.scheduler.client.report.' + '_instance_to_allocations_dict') @mock.patch.object(report.LOG, 'warning') - def test_update_instance_allocation_new_failed(self, mock_warn, mock_put, - mock_get): + def test_update_instance_allocation_new_failed(self, mock_warn, mock_a, + mock_put, mock_get): cn = objects.ComputeNode(uuid=uuids.cn) inst = objects.Instance(uuid=uuids.inst) - with mock.patch.object(self.client, '_allocations'): - try: - mock_put.return_value.__nonzero__.return_value = False - except AttributeError: - # NOTE(danms): LOL @ py3 - mock_put.return_value.__bool__.return_value = False - self.client.update_instance_allocation(cn, inst, 1) - self.assertTrue(mock_warn.called) + try: + mock_put.return_value.__nonzero__.return_value = False + except AttributeError: + # NOTE(danms): LOL @ py3 + mock_put.return_value.__bool__.return_value = False + self.client.update_instance_allocation(cn, inst, 1) + self.assertTrue(mock_warn.called) @mock.patch('nova.scheduler.client.report.SchedulerReportClient.' 'delete') @@ -801,8 +808,10 @@ class TestAllocations(SchedulerReportClientTestCase): 'delete') @mock.patch('nova.scheduler.client.report.SchedulerReportClient.' 'get') - def test_remove_deleted_instances( - self, mock_get, mock_delete): + @mock.patch('nova.scheduler.client.report.' + '_instance_to_allocations_dict') + def test_remove_deleted_instances(self, mock_a, mock_get, + mock_delete): cn = objects.ComputeNode(uuid=uuids.cn) inst1 = objects.Instance(uuid=uuids.inst1) inst2 = objects.Instance(uuid=uuids.inst2) @@ -822,11 +831,10 @@ class TestAllocations(SchedulerReportClientTestCase): inst3 = {'uuid': 'foo'} mock_delete.return_value = True - with mock.patch.object(self.client, '_allocations'): - self.client.remove_deleted_instances(cn, [inst3]) - mock_get.assert_called_once_with( - '/resource_providers/%s/allocations' % cn.uuid) - expected_calls = [ - mock.call('/allocations/%s' % inst1.uuid), - mock.call('/allocations/%s' % inst2.uuid)] - mock_delete.assert_has_calls(expected_calls, any_order=True) + self.client.remove_deleted_instances(cn, [inst3]) + mock_get.assert_called_once_with( + '/resource_providers/%s/allocations' % cn.uuid) + expected_calls = [ + mock.call('/allocations/%s' % inst1.uuid), + mock.call('/allocations/%s' % inst2.uuid)] + mock_delete.assert_has_calls(expected_calls, any_order=True)