diff --git a/novaclient/__init__.py b/novaclient/__init__.py index c114e5b9c..6795d8827 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.60") +API_MAX_VERSION = api_versions.APIVersion("2.61") diff --git a/novaclient/tests/unit/fakes.py b/novaclient/tests/unit/fakes.py index b2820a48a..a9447f71f 100644 --- a/novaclient/tests/unit/fakes.py +++ b/novaclient/tests/unit/fakes.py @@ -131,6 +131,19 @@ class FakeClient(object): self.client.callstack = [] + def assert_not_called(self, method, url, body=None): + """Assert that an HTTP method was not called in the test. + + :param method: HTTP method name which is expected not to be called + :param url: Expected request url not to be called with given method + :param body: Expected request body not to be called with given method + and url. Default is None. + """ + not_expected = (method, url, body) + for entry in self.client.callstack: + assert not_expected != entry[0:3], ( + 'API %s %s body=%s was called.' % not_expected) + def clear_callstack(self): self.client.callstack = [] diff --git a/novaclient/tests/unit/v2/fakes.py b/novaclient/tests/unit/v2/fakes.py index e853ef223..7b905b9eb 100644 --- a/novaclient/tests/unit/v2/fakes.py +++ b/novaclient/tests/unit/v2/fakes.py @@ -837,6 +837,8 @@ class FakeSessionClient(base_client.SessionClient): included_fields = ['id', 'name'] if self.api_version >= api_versions.APIVersion('2.55'): included_fields.append('description') + if self.api_version >= api_versions.APIVersion('2.61'): + included_fields.append('extra_specs') for flavor in flavors['flavors']: for k in list(flavor): if k not in included_fields: @@ -897,6 +899,11 @@ class FakeSessionClient(base_client.SessionClient): new_flavor['description'] = 'test description' flavors['flavors'].append(new_flavor) + # Add extra_specs in the response for all flavors. + if self.api_version >= api_versions.APIVersion('2.61'): + for flavor in flavors['flavors']: + flavor['extra_specs'] = {'test': 'value'} + return (200, FAKE_RESPONSE_HEADERS, flavors) def get_flavors_1(self, **kw): diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py index df646691e..997063416 100644 --- a/novaclient/tests/unit/v2/test_shell.py +++ b/novaclient/tests/unit/v2/test_shell.py @@ -104,6 +104,9 @@ class ShellTest(utils.TestCase): def assert_called_anytime(self, method, url, body=None): return self.shell.cs.assert_called_anytime(method, url, body) + def assert_not_called(self, method, url, body=None): + return self.shell.cs.assert_not_called(method, url, body) + def test_agents_list_with_hypervisor(self): self.run_command('agent-list --hypervisor xen') self.assert_called('GET', '/os-agents?hypervisor=xen') @@ -1168,6 +1171,16 @@ class ShellTest(utils.TestCase): self.assert_called('GET', '/flavors/aa1/os-extra_specs') self.assert_called_anytime('GET', '/flavors/detail') + def test_flavor_list_with_extra_specs_2_61_or_later(self): + """Tests that the 'os-extra_specs' API is not called + when the '--extra-specs' option is specified since microversion 2.61. + """ + out, _ = self.run_command('flavor-list --extra-specs', + api_version='2.61') + self.assert_not_called('GET', '/flavors/aa1/os-extra_specs') + self.assert_called_anytime('GET', '/flavors/detail') + self.assertIn('extra_specs', out) + def test_flavor_list_with_all(self): self.run_command('flavor-list --all') self.assert_called('GET', '/flavors/detail?is_public=None') @@ -1196,9 +1209,17 @@ class ShellTest(utils.TestCase): def test_flavor_show_with_description(self): """Tests that the description is shown in version >= 2.55.""" out, _ = self.run_command('flavor-show 1', api_version='2.55') - self.assert_called_anytime('GET', '/flavors/1') + self.assert_called('GET', '/flavors/1', pos=-2) + self.assert_called('GET', '/flavors/1/os-extra_specs', pos=-1) self.assertIn('description', out) + def test_flavor_show_2_61_or_later(self): + """Tests that the 'os-extra_specs' is not called in version >= 2.61.""" + out, _ = self.run_command('flavor-show 1', api_version='2.61') + self.assert_not_called('GET', '/flavors/1/os-extra_specs') + self.assert_called_anytime('GET', '/flavors/1') + self.assertIn('extra_specs', out) + def test_flavor_show_with_alphanum_id(self): self.run_command('flavor-show aa1') self.assert_called_anytime('GET', '/flavors/aa1') @@ -3612,6 +3633,7 @@ class ShellTest(utils.TestCase): 54, # There are no version-wrapped shell method changes for this. 57, # There are no version-wrapped shell method changes for this. 60, # There are no client-side changes for volume multiattach. + 61, # There are no version-wrapped shell method changes for this. ]) versions_supported = set(range(0, novaclient.API_MAX_VERSION.ver_minor + 1)) diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py index 4801cfcf8..d53fc05bc 100644 --- a/novaclient/v2/shell.py +++ b/novaclient/v2/shell.py @@ -1016,11 +1016,13 @@ def _print_flavor_list(cs, flavors, show_extra_specs=False): 'Is_Public', ] + formatters = {} if show_extra_specs: - formatters = {'extra_specs': _print_flavor_extra_specs} + # Starting with microversion 2.61, extra specs are included + # in the flavor details response. + if cs.api_version < api_versions.APIVersion('2.61'): + formatters = {'extra_specs': _print_flavor_extra_specs} headers.append('extra_specs') - else: - formatters = {} if cs.api_version >= api_versions.APIVersion('2.55'): headers.append('Description') @@ -1316,7 +1318,10 @@ def _print_flavor(flavor): info = flavor.to_dict() # ignore links, we don't need to present those info.pop('links') - info.update({"extra_specs": _print_flavor_extra_specs(flavor)}) + # Starting with microversion 2.61, extra specs are included + # in the flavor details response. + if 'extra_specs' not in info: + info.update({"extra_specs": _print_flavor_extra_specs(flavor)}) utils.print_dict(info) diff --git a/releasenotes/notes/microversion-v2_61-9a8faa02fddf9ed6.yaml b/releasenotes/notes/microversion-v2_61-9a8faa02fddf9ed6.yaml new file mode 100644 index 000000000..a96b65d3a --- /dev/null +++ b/releasenotes/notes/microversion-v2_61-9a8faa02fddf9ed6.yaml @@ -0,0 +1,13 @@ +--- +other: + - | + Starting from microversion 2.61, the responses of the 'Flavor' APIs + include the 'extra_specs' parameter. Therefore 'Flavors extra-specs' + (os-extra_specs) API calls have been removed in the following commands + since microversion 2.61. + + * ``nova flavor-list`` + * ``nova flavor-show`` + + There are no behavior changes in the CLI. This is just a performance + optimization.