diff --git a/novaclient/__init__.py b/novaclient/__init__.py index 85cadcf62..99d9f4a74 100644 --- a/novaclient/__init__.py +++ b/novaclient/__init__.py @@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1") # when client supported the max version, and bumped sequentially, otherwise # the client may break due to server side new version may include some # backward incompatible change. -API_MAX_VERSION = api_versions.APIVersion("2.39") +API_MAX_VERSION = api_versions.APIVersion("2.38") diff --git a/novaclient/tests/unit/v2/fakes.py b/novaclient/tests/unit/v2/fakes.py index 0e9819951..646cc0961 100644 --- a/novaclient/tests/unit/v2/fakes.py +++ b/novaclient/tests/unit/v2/fakes.py @@ -72,7 +72,6 @@ class FakeHTTPClient(base_client.HTTPClient): self.auth_url = 'auth_url' self.tenant_id = 'tenant_id' self.callstack = [] - self.visited = [] self.projectid = 'projectid' self.user = 'user' self.region_name = 'region_name' @@ -135,21 +134,12 @@ class FakeHTTPClient(base_client.HTTPClient): v2_image = True callback = callback.replace('get_v2_', 'get_') - simulate_pagination_next_links = [ - 'get_os_simple_tenant_usage', - 'get_os_simple_tenant_usage_tenant_id', - ] - if callback in simulate_pagination_next_links: - while callback in self.visited: - callback += '_next' - if not hasattr(self, callback): raise AssertionError('Called unknown API method: %s %s, ' 'expected fakes method name: %s' % (method, url, callback)) # Note the call - self.visited.append(callback) self.callstack.append((method, url, kwargs.get('body'))) status, headers, body = getattr(self, callback)(**kwargs) @@ -1548,8 +1538,6 @@ class FakeHTTPClient(base_client.HTTPClient): six.u('name'): six.u('f15image1'), six.u('tenant_id'): six.u('7b0a1d73f8fb41718f3343c207597869'), - six.u('instance_id'): - six.u('f079e394-1111-457b-b350-bb5ecc685cdd'), six.u('vcpus'): 1, six.u('memory_mb'): 512, six.u('state'): six.u('active'), @@ -1559,37 +1547,6 @@ class FakeHTTPClient(base_client.HTTPClient): six.u('start'): six.u('2011-12-25 19:48:41.750687'), six.u('total_local_gb_usage'): 0.0}]}) - def get_os_simple_tenant_usage_next(self, **kw): - return (200, FAKE_RESPONSE_HEADERS, - {six.u('tenant_usages'): [{ - six.u('total_memory_mb_usage'): 25451.762807466665, - six.u('total_vcpus_usage'): 49.71047423333333, - six.u('total_hours'): 49.71047423333333, - six.u('tenant_id'): - six.u('7b0a1d73f8fb41718f3343c207597869'), - six.u('stop'): six.u('2012-01-22 19:48:41.750722'), - six.u('server_usages'): [{ - six.u('hours'): 49.71047423333333, - six.u('uptime'): 27035, - six.u('local_gb'): 0, - six.u('ended_at'): None, - six.u('name'): six.u('f15image1'), - six.u('tenant_id'): - six.u('7b0a1d73f8fb41718f3343c207597869'), - six.u('instance_id'): - six.u('f079e394-2222-457b-b350-bb5ecc685cdd'), - six.u('vcpus'): 1, - six.u('memory_mb'): 512, - six.u('state'): six.u('active'), - six.u('flavor'): six.u('m1.tiny'), - six.u('started_at'): - six.u('2012-01-20 18:06:06.479998')}], - six.u('start'): six.u('2011-12-25 19:48:41.750687'), - six.u('total_local_gb_usage'): 0.0}]}) - - def get_os_simple_tenant_usage_next_next(self, **kw): - return (200, FAKE_RESPONSE_HEADERS, {six.u('tenant_usages'): []}) - def get_os_simple_tenant_usage_tenantfoo(self, **kw): return (200, FAKE_RESPONSE_HEADERS, {six.u('tenant_usage'): { @@ -1606,8 +1563,6 @@ class FakeHTTPClient(base_client.HTTPClient): six.u('name'): six.u('f15image1'), six.u('tenant_id'): six.u('7b0a1d73f8fb41718f3343c207597869'), - six.u('instance_id'): - six.u('f079e394-1111-457b-b350-bb5ecc685cdd'), six.u('vcpus'): 1, six.u('memory_mb'): 512, six.u('state'): six.u('active'), six.u('flavor'): six.u('m1.tiny'), @@ -1629,8 +1584,6 @@ class FakeHTTPClient(base_client.HTTPClient): six.u('ended_at'): None, six.u('name'): six.u('f15image1'), six.u('tenant_id'): six.u('7b0a1d73f8fb41718f3343c207597869'), - six.u('instance_id'): - six.u('f079e394-1111-457b-b350-bb5ecc685cdd'), six.u('vcpus'): 1, six.u('memory_mb'): 512, six.u('state'): six.u('active'), six.u('flavor'): six.u('m1.tiny'), @@ -1651,8 +1604,6 @@ class FakeHTTPClient(base_client.HTTPClient): six.u('ended_at'): None, six.u('name'): six.u('f15image1'), six.u('tenant_id'): six.u('7b0a1d73f8fb41718f3343c207597869'), - six.u('instance_id'): - six.u('f079e394-1111-457b-b350-bb5ecc685cdd'), six.u('vcpus'): 1, six.u('memory_mb'): 512, six.u('state'): six.u('active'), six.u('flavor'): six.u('m1.tiny'), @@ -1660,31 +1611,6 @@ class FakeHTTPClient(base_client.HTTPClient): six.u('start'): six.u('2011-12-25 19:48:41.750687'), six.u('total_local_gb_usage'): 0.0}}) - def get_os_simple_tenant_usage_tenant_id_next(self, **kw): - return (200, {}, {six.u('tenant_usage'): { - six.u('total_memory_mb_usage'): 25451.762807466665, - six.u('total_vcpus_usage'): 49.71047423333333, - six.u('total_hours'): 49.71047423333333, - six.u('tenant_id'): six.u('7b0a1d73f8fb41718f3343c207597869'), - six.u('stop'): six.u('2012-01-22 19:48:41.750722'), - six.u('server_usages'): [{ - six.u('hours'): 49.71047423333333, - six.u('uptime'): 27035, six.u('local_gb'): 0, - six.u('ended_at'): None, - six.u('name'): six.u('f15image1'), - six.u('tenant_id'): six.u('7b0a1d73f8fb41718f3343c207597869'), - six.u('instance_id'): - six.u('f079e394-2222-457b-b350-bb5ecc685cdd'), - six.u('vcpus'): 1, six.u('memory_mb'): 512, - six.u('state'): six.u('active'), - six.u('flavor'): six.u('m1.tiny'), - six.u('started_at'): six.u('2012-01-20 18:06:06.479998')}], - six.u('start'): six.u('2011-12-25 19:48:41.750687'), - six.u('total_local_gb_usage'): 0.0}}) - - def get_os_simple_tenant_usage_tenant_id_next_next(self, **kw): - return (200, {}, {six.u('tenant_usage'): {}}) - # # Aggregates # @@ -2410,7 +2336,6 @@ class FakeSessionMockClient(base_client.SessionClient, FakeHTTPClient): def __init__(self, *args, **kwargs): self.callstack = [] - self.visited = [] self.auth = mock.Mock() self.session = mock.Mock() self.session.get_endpoint.return_value = FakeHTTPClient.get_endpoint( diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py index 6f5069116..1b3af35b6 100644 --- a/novaclient/tests/unit/v2/test_shell.py +++ b/novaclient/tests/unit/v2/test_shell.py @@ -50,7 +50,7 @@ class ShellFixture(fixtures.Fixture): def tearDown(self): # For some method like test_image_meta_bad_action we are # testing a SystemExit to be thrown and object self.shell has - # no time to get instantiated which is OK in this case, so + # no time to get instantatiated which is OK in this case, so # we make sure the method is there before launching it. if hasattr(self.shell, 'cs'): self.shell.cs.clear_callstack() @@ -1749,36 +1749,12 @@ class ShellTest(utils.TestCase): {'removeFloatingIp': {'address': '11.0.0.1'}}) def test_usage_list(self): - cmd = 'usage-list --start 2000-01-20 --end 2005-02-01' - stdout, _ = self.run_command(cmd) + self.run_command('usage-list --start 2000-01-20 --end 2005-02-01') self.assert_called('GET', '/os-simple-tenant-usage?' + 'start=2000-01-20T00:00:00&' + 'end=2005-02-01T00:00:00&' + 'detailed=1') - # Servers, RAM MB-Hours, CPU Hours, Disk GB-Hours - self.assertIn('1 | 25451.76 | 49.71 | 0.00', stdout) - - def test_usage_list_stitch_together_next_results(self): - cmd = 'usage-list --start 2000-01-20 --end 2005-02-01' - stdout, _ = self.run_command(cmd, api_version='2.39') - self.assert_called('GET', - '/os-simple-tenant-usage?' - 'start=2000-01-20T00:00:00&' - 'end=2005-02-01T00:00:00&' - 'detailed=1', pos=0) - markers = [ - 'f079e394-1111-457b-b350-bb5ecc685cdd', - 'f079e394-2222-457b-b350-bb5ecc685cdd', - ] - for pos, marker in enumerate(markers): - self.assert_called('GET', - '/os-simple-tenant-usage?' - 'start=2000-01-20T00:00:00&' - 'end=2005-02-01T00:00:00&' - 'marker=%s&detailed=1' % (marker), pos=pos + 1) - # Servers, RAM MB-Hours, CPU Hours, Disk GB-Hours - self.assertIn('2 | 50903.53 | 99.42 | 0.00', stdout) def test_usage_list_no_args(self): timeutils.set_time_override(datetime.datetime(2005, 2, 1, 0, 0)) @@ -1791,34 +1767,12 @@ class ShellTest(utils.TestCase): 'detailed=1') def test_usage(self): - cmd = 'usage --start 2000-01-20 --end 2005-02-01 --tenant test' - stdout, _ = self.run_command(cmd) + self.run_command('usage --start 2000-01-20 --end 2005-02-01 ' + '--tenant test') self.assert_called('GET', '/os-simple-tenant-usage/test?' + 'start=2000-01-20T00:00:00&' + 'end=2005-02-01T00:00:00') - # Servers, RAM MB-Hours, CPU Hours, Disk GB-Hours - self.assertIn('1 | 25451.76 | 49.71 | 0.00', stdout) - - def test_usage_stitch_together_next_results(self): - cmd = 'usage --start 2000-01-20 --end 2005-02-01' - stdout, _ = self.run_command(cmd, api_version='2.39') - self.assert_called('GET', - '/os-simple-tenant-usage/tenant_id?' - 'start=2000-01-20T00:00:00&' - 'end=2005-02-01T00:00:00', pos=0) - markers = [ - 'f079e394-1111-457b-b350-bb5ecc685cdd', - 'f079e394-2222-457b-b350-bb5ecc685cdd', - ] - for pos, marker in enumerate(markers): - self.assert_called('GET', - '/os-simple-tenant-usage/tenant_id?' - 'start=2000-01-20T00:00:00&' - 'end=2005-02-01T00:00:00&' - 'marker=%s' % (marker), pos=pos + 1) - # Servers, RAM MB-Hours, CPU Hours, Disk GB-Hours - self.assertIn('2 | 50903.53 | 99.42 | 0.00', stdout) def test_usage_no_tenant(self): self.run_command('usage --start 2000-01-20 --end 2005-02-01') diff --git a/novaclient/tests/unit/v2/test_usage.py b/novaclient/tests/unit/v2/test_usage.py index 8c18e1526..e67178b41 100644 --- a/novaclient/tests/unit/v2/test_usage.py +++ b/novaclient/tests/unit/v2/test_usage.py @@ -73,52 +73,3 @@ class UsageTest(utils.TestCase): 'GET', "/os-simple-tenant-usage/tenantfoo?start=%s&end=%s" % (start, stop)) - - -class UsageV39Test(UsageTest): - def setUp(self): - super(UsageV39Test, self).setUp() - self.cs.api_version = api_versions.APIVersion('2.39') - - def test_usage_list_with_paging(self): - now = datetime.datetime.now() - usages = self.cs.usage.list(now, now, marker='some-uuid', limit=3) - self.assert_request_id(usages, fakes.FAKE_REQUEST_ID_LIST) - - self.cs.assert_called( - 'GET', - '/os-simple-tenant-usage?' + - ('start=%s&' % now.isoformat()) + - ('end=%s&' % now.isoformat()) + - ('limit=3&marker=some-uuid&detailed=0')) - for u in usages: - self.assertIsInstance(u, usage.Usage) - - def test_usage_list_detailed_with_paging(self): - now = datetime.datetime.now() - usages = self.cs.usage.list( - now, now, detailed=True, marker='some-uuid', limit=3) - self.assert_request_id(usages, fakes.FAKE_REQUEST_ID_LIST) - - self.cs.assert_called( - 'GET', - '/os-simple-tenant-usage?' + - ('start=%s&' % now.isoformat()) + - ('end=%s&' % now.isoformat()) + - ('limit=3&marker=some-uuid&detailed=1')) - for u in usages: - self.assertIsInstance(u, usage.Usage) - - def test_usage_get_with_paging(self): - now = datetime.datetime.now() - u = self.cs.usage.get( - 'tenantfoo', now, now, marker='some-uuid', limit=3) - self.assert_request_id(u, fakes.FAKE_REQUEST_ID_LIST) - - self.cs.assert_called( - 'GET', - '/os-simple-tenant-usage/tenantfoo?' + - ('start=%s&' % now.isoformat()) + - ('end=%s&' % now.isoformat()) + - ('limit=3&marker=some-uuid')) - self.assertIsInstance(u, usage.Usage) diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py index 08e6f7055..b621025a2 100644 --- a/novaclient/v2/shell.py +++ b/novaclient/v2/shell.py @@ -19,7 +19,6 @@ from __future__ import print_function import argparse -import collections import copy import datetime import functools @@ -3444,43 +3443,7 @@ def do_usage_list(cs, args): setattr(u, simplerows[3], "%.2f" % u.total_vcpus_usage) setattr(u, simplerows[4], "%.2f" % u.total_local_gb_usage) - def get_marker(usage_list): - marker = None - if usage_list: - usage = usage_list[-1] - if hasattr(usage, 'server_usages') and usage.server_usages: - marker = usage.server_usages[-1]['instance_id'] - return marker - - def merge_usage(usages, next_usage_list): - for next_usage in next_usage_list: - if next_usage.tenant_id in usages: - usage = usages[next_usage.tenant_id] - usage.server_usages.extend(next_usage.server_usages) - usage.total_hours += next_usage.total_hours - usage.total_memory_mb_usage += next_usage.total_memory_mb_usage - usage.total_vcpus_usage += next_usage.total_vcpus_usage - usage.total_local_gb_usage += next_usage.total_local_gb_usage - else: - usages[next_usage.tenant_id] = next_usage - - if cs.api_version < api_versions.APIVersion('2.39'): - usage_list = cs.usage.list(start, end, detailed=True) - else: - # If the number of instances used to calculate the usage is greater - # than osapi_max_limit, the usage will be split across multiple - # requests and the responses will need to be merged back together. - usages = collections.OrderedDict() - usage_list = cs.usage.list(start, end, detailed=True) - merge_usage(usages, usage_list) - marker = get_marker(usage_list) - while marker: - next_usage_list = cs.usage.list( - start, end, detailed=True, marker=marker) - marker = get_marker(next_usage_list) - if marker: - merge_usage(usages, next_usage_list) - usage_list = usages.values() + usage_list = cs.usage.list(start, end, detailed=True) print(_("Usage from %(start)s to %(end)s:") % {'start': start.strftime(dateformat), @@ -3531,41 +3494,15 @@ def do_usage(cs, args): setattr(u, simplerows[2], "%.2f" % u.total_vcpus_usage) setattr(u, simplerows[3], "%.2f" % u.total_local_gb_usage) - def get_marker(usage): - marker = None - if hasattr(usage, 'server_usages') and usage.server_usages: - marker = usage.server_usages[-1]['instance_id'] - return marker - - def merge_usage(usage, next_usage): - usage.server_usages.extend(next_usage.server_usages) - usage.total_hours += next_usage.total_hours - usage.total_memory_mb_usage += next_usage.total_memory_mb_usage - usage.total_vcpus_usage += next_usage.total_vcpus_usage - usage.total_local_gb_usage += next_usage.total_local_gb_usage - if args.tenant: - tenant_id = args.tenant + usage = cs.usage.get(args.tenant, start, end) else: if isinstance(cs.client, client.SessionClient): auth = cs.client.auth - tenant_id = auth.get_auth_ref(cs.client.session).project_id + project_id = auth.get_auth_ref(cs.client.session).project_id + usage = cs.usage.get(project_id, start, end) else: - tenant_id = cs.client.tenant_id - - if cs.api_version < api_versions.APIVersion('2.39'): - usage = cs.usage.get(tenant_id, start, end) - else: - # If the number of instances used to calculate the usage is greater - # than osapi_max_limit, the usage will be split across multiple - # requests and the responses will need to be merged back together. - usage = cs.usage.get(tenant_id, start, end) - marker = get_marker(usage) - while marker: - next_usage = cs.usage.get(tenant_id, start, end, marker=marker) - marker = get_marker(next_usage) - if marker: - merge_usage(usage, next_usage) + usage = cs.usage.get(cs.client.tenant_id, start, end) print(_("Usage from %(start)s to %(end)s:") % {'start': start.strftime(dateformat), diff --git a/novaclient/v2/usage.py b/novaclient/v2/usage.py index 199e3111a..dacf87b55 100644 --- a/novaclient/v2/usage.py +++ b/novaclient/v2/usage.py @@ -17,7 +17,6 @@ Usage interface. import oslo_utils -from novaclient import api_versions from novaclient import base @@ -47,19 +46,7 @@ class UsageManager(base.ManagerWithFind): Manage :class:`Usage` resources. """ resource_class = Usage - usage_prefix = 'os-simple-tenant-usage' - def _usage_query(self, start, end, marker=None, limit=None, detailed=None): - query = "?start=%s&end=%s" % (start.isoformat(), end.isoformat()) - if limit: - query = "%s&limit=%s" % (query, int(limit)) - if marker: - query = "%s&marker=%s" % (query, marker) - if detailed is not None: - query = "%s&detailed=%s" % (query, int(bool(detailed))) - return query - - @api_versions.wraps("2.0", "2.38") def list(self, start, end, detailed=False): """ Get usage for all tenants @@ -70,31 +57,11 @@ class UsageManager(base.ManagerWithFind): instance whose usage is part of the report :rtype: list of :class:`Usage`. """ - query_string = self._usage_query(start, end, detailed=detailed) - url = '/%s%s' % (self.usage_prefix, query_string) - return self._list(url, 'tenant_usages') + return self._list( + "/os-simple-tenant-usage?start=%s&end=%s&detailed=%s" % + (start.isoformat(), end.isoformat(), int(bool(detailed))), + "tenant_usages") - @api_versions.wraps("2.39") - def list(self, start, end, detailed=False, marker=None, limit=None): - """ - Get usage for all tenants - - :param start: :class:`datetime.datetime` Start date in UTC - :param end: :class:`datetime.datetime` End date in UTC - :param detailed: Whether to include information about each - instance whose usage is part of the report - :param marker: Begin returning usage data for instances that appear - later in the instance list than that represented by - this instance UUID (optional). - :param limit: Maximum number of instances to include in the usage - (optional). - :rtype: list of :class:`Usage`. - """ - query_string = self._usage_query(start, end, marker, limit, detailed) - url = '/%s%s' % (self.usage_prefix, query_string) - return self._list(url, 'tenant_usages') - - @api_versions.wraps("2.0", "2.38") def get(self, tenant_id, start, end): """ Get usage for a specific tenant. @@ -104,25 +71,6 @@ class UsageManager(base.ManagerWithFind): :param end: :class:`datetime.datetime` End date in UTC :rtype: :class:`Usage` """ - query_string = self._usage_query(start, end) - url = '/%s/%s%s' % (self.usage_prefix, tenant_id, query_string) - return self._get(url, 'tenant_usage') - - @api_versions.wraps("2.39") - def get(self, tenant_id, start, end, marker=None, limit=None): - """ - Get usage for a specific tenant. - - :param tenant_id: Tenant ID to fetch usage for - :param start: :class:`datetime.datetime` Start date in UTC - :param end: :class:`datetime.datetime` End date in UTC - :param marker: Begin returning usage data for instances that appear - later in the instance list than that represented by - this instance UUID (optional). - :param limit: Maximum number of instances to include in the usage - (optional). - :rtype: :class:`Usage` - """ - query_string = self._usage_query(start, end, marker, limit) - url = '/%s/%s%s' % (self.usage_prefix, tenant_id, query_string) - return self._get(url, 'tenant_usage') + return self._get("/os-simple-tenant-usage/%s?start=%s&end=%s" % + (tenant_id, start.isoformat(), end.isoformat()), + "tenant_usage") diff --git a/releasenotes/notes/microversion-v2_39-484adba0806b08bf.yaml b/releasenotes/notes/microversion-v2_39-484adba0806b08bf.yaml deleted file mode 100644 index f81827188..000000000 --- a/releasenotes/notes/microversion-v2_39-484adba0806b08bf.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Added microversion v2.39 which introduces pagination support for usage - with the help of new optional parameters 'limit' and 'marker'.