From f061579f001d288d3a51d0db3662454d20b0993a Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Fri, 3 Mar 2017 10:50:41 -0800 Subject: [PATCH] Teach simple_tenant_usage about cells Related to blueprint cells-aware-api Change-Id: Icd5e46e0276df6cf7ffbbb57abb1dddc46678e11 --- .../openstack/compute/simple_tenant_usage.py | 39 ++++++++++++++++-- .../compute/test_simple_tenant_usage.py | 41 +++++++++++++++---- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/nova/api/openstack/compute/simple_tenant_usage.py b/nova/api/openstack/compute/simple_tenant_usage.py index 794e8ba07e..051ddb8d7b 100644 --- a/nova/api/openstack/compute/simple_tenant_usage.py +++ b/nova/api/openstack/compute/simple_tenant_usage.py @@ -26,6 +26,7 @@ from nova.api.openstack.compute.views import usages as usages_view from nova.api.openstack import extensions from nova.api.openstack import wsgi import nova.conf +from nova import context as nova_context from nova import exception from nova.i18n import _ from nova import objects @@ -104,13 +105,43 @@ class SimpleTenantUsageController(wsgi.Controller): return flavor_ref + def _get_instances_all_cells(self, context, period_start, period_stop, + tenant_id, limit, marker): + all_instances = [] + cells = objects.CellMappingList.get_all(context) + for cell in cells: + with nova_context.target_cell(context, cell): + try: + instances = ( + objects.InstanceList.get_active_by_window_joined( + context, period_start, period_stop, tenant_id, + expected_attrs=['flavor'], limit=limit, + marker=marker)) + except exception.MarkerNotFound: + # NOTE(danms): We need to keep looking through the later + # cells to find the marker + continue + all_instances.extend(instances) + # NOTE(danms): We must have found a marker if we had one, + # so make sure we don't require a marker in the next cell + marker = None + if limit: + limit -= len(instances) + if limit <= 0: + break + if marker is not None and len(all_instances) == 0: + # NOTE(danms): If we did not find the marker in any cell, + # mimic the db_api behavior here + raise exception.MarkerNotFound(marker=marker) + + return all_instances + def _tenant_usages_for_period(self, context, period_start, period_stop, tenant_id=None, detailed=True, limit=None, marker=None): - - instances = objects.InstanceList.get_active_by_window_joined( - context, period_start, period_stop, tenant_id, - expected_attrs=['flavor'], limit=limit, marker=marker) + instances = self._get_instances_all_cells(context, period_start, + period_stop, tenant_id, + limit, marker) rval = {} flavors = {} all_server_usages = [] diff --git a/nova/tests/unit/api/openstack/compute/test_simple_tenant_usage.py b/nova/tests/unit/api/openstack/compute/test_simple_tenant_usage.py index c8b836bdab..70e278ea5d 100644 --- a/nova/tests/unit/api/openstack/compute/test_simple_tenant_usage.py +++ b/nova/tests/unit/api/openstack/compute/test_simple_tenant_usage.py @@ -119,6 +119,8 @@ class SimpleTenantUsageTestV21(test.TestCase): self.alt_user_context = context.RequestContext('fakeadmin_0', 'faketenant_1', is_admin=False) + self.num_cells = len(objects.CellMappingList.get_all( + self.admin_context)) def _test_verify_index(self, start, stop, limit=None): url = '?start=%s&end=%s' @@ -131,13 +133,23 @@ class SimpleTenantUsageTestV21(test.TestCase): res_dict = self.controller.index(req) usages = res_dict['tenant_usages'] + + if limit: + num = 1 + else: + # NOTE(danms): We call our fake data mock once per cell, + # and the default fixture has two cells (cell0 and cell1), + # so all our math will be doubled. + num = self.num_cells + for i in range(TENANTS): - self.assertEqual(SERVERS * HOURS, int(usages[i]['total_hours'])) - self.assertEqual(SERVERS * (ROOT_GB + EPHEMERAL_GB) * HOURS, + self.assertEqual(SERVERS * HOURS * num, + int(usages[i]['total_hours'])) + self.assertEqual(SERVERS * (ROOT_GB + EPHEMERAL_GB) * HOURS * num, int(usages[i]['total_local_gb_usage'])) - self.assertEqual(SERVERS * MEMORY_MB * HOURS, + self.assertEqual(SERVERS * MEMORY_MB * HOURS * num, int(usages[i]['total_memory_mb_usage'])) - self.assertEqual(SERVERS * VCPUS * HOURS, + self.assertEqual(SERVERS * VCPUS * HOURS * num, int(usages[i]['total_vcpus_usage'])) self.assertFalse(usages[i].get('server_usages')) @@ -216,9 +228,17 @@ class SimpleTenantUsageTestV21(test.TestCase): req.environ['nova.context'] = self.user_context res_dict = self.controller.show(req, tenant_id) + if limit: + num = 1 + else: + # NOTE(danms): We call our fake data mock once per cell, + # and the default fixture has two cells (cell0 and cell1), + # so all our math will be doubled. + num = self.num_cells + usage = res_dict['tenant_usage'] servers = usage['server_usages'] - self.assertEqual(TENANTS * SERVERS, len(usage['server_usages'])) + self.assertEqual(TENANTS * SERVERS * num, len(usage['server_usages'])) server_uuids = [getattr(uuids, 'instance_%d' % x) for x in range(SERVERS)] for j in range(SERVERS): @@ -292,10 +312,12 @@ class SimpleTenantUsageTestV40(SimpleTenantUsageTestV21): version = '2.40' def test_next_links_show(self): - self._test_verify_show(START, STOP, limit=SERVERS * TENANTS) + self._test_verify_show(START, STOP, + limit=SERVERS * TENANTS) def test_next_links_index(self): - self._test_verify_index(START, STOP, limit=SERVERS * TENANTS) + self._test_verify_index(START, STOP, + limit=SERVERS * TENANTS) class SimpleTenantUsageLimitsTestV21(test.TestCase): @@ -311,7 +333,7 @@ class SimpleTenantUsageLimitsTestV21(test.TestCase): return fakes.HTTPRequest.blank(url, version=self.version) def assert_limit(self, mock_get, limit): - mock_get.assert_called_once_with( + mock_get.assert_called_with( mock.ANY, mock.ANY, mock.ANY, mock.ANY, expected_attrs=['flavor'], limit=1000, marker=None) @@ -332,7 +354,8 @@ class SimpleTenantUsageLimitsTestV240(SimpleTenantUsageLimitsTestV21): version = '2.40' def assert_limit_and_marker(self, mock_get, limit, marker): - mock_get.assert_called_once_with( + # NOTE(danms): Make sure we called at least once with the marker + mock_get.assert_any_call( mock.ANY, mock.ANY, mock.ANY, mock.ANY, expected_attrs=['flavor'], limit=3, marker=marker)