From 25e0d2ab2794dc68cccec0d1e7b463b7d7f7e65f Mon Sep 17 00:00:00 2001 From: Terry Howe Date: Fri, 11 Jul 2014 09:05:37 -0600 Subject: [PATCH] Add network extension list Network extension list support Change-Id: I013f68ef2c3329c8db59e2441dd8d4ffafd4470e Closes-Bug: #1337685 --- openstackclient/common/extension.py | 54 ++++++++++++++----- .../tests/common/test_extension.py | 52 +++++++++++++++++- openstackclient/tests/network/v2/fakes.py | 35 ++++++++++++ 3 files changed, 126 insertions(+), 15 deletions(-) create mode 100644 openstackclient/tests/network/v2/fakes.py diff --git a/openstackclient/common/extension.py b/openstackclient/common/extension.py index 91ee228be5..be7426daa0 100644 --- a/openstackclient/common/extension.py +++ b/openstackclient/common/extension.py @@ -15,6 +15,7 @@ """Extension action implementations""" +import itertools import logging from cliff import lister @@ -25,28 +26,30 @@ from openstackclient.common import utils class ListExtension(lister.Lister): """List extension command""" - # TODO(mfisch): add support for volume and network - # when the underlying APIs support it. - log = logging.getLogger(__name__ + '.ListExtension') def get_parser(self, prog_name): parser = super(ListExtension, self).get_parser(prog_name) parser.add_argument( - '--long', + '--compute', action='store_true', default=False, - help='List additional fields in output') + help='List extensions for the Compute API') parser.add_argument( '--identity', action='store_true', default=False, help='List extensions for the Identity API') parser.add_argument( - '--compute', + '--long', action='store_true', default=False, - help='List extensions for the Compute API') + help='List additional fields in output') + parser.add_argument( + '--network', + action='store_true', + default=False, + help='List extensions for the Network API') parser.add_argument( '--volume', action='store_true', @@ -69,7 +72,7 @@ class ListExtension(lister.Lister): # user specifies one or more of the APIs to show # for now, only identity and compute are supported. show_all = (not parsed_args.identity and not parsed_args.compute - and not parsed_args.volume) + and not parsed_args.volume and not parsed_args.network) if parsed_args.identity or show_all: identity_client = self.app.client_manager.identity @@ -95,8 +98,33 @@ class ListExtension(lister.Lister): message = "Extensions list not supported by Volume API" self.log.warning(message) - return (columns, - (utils.get_item_properties( - s, columns, - formatters={}, - ) for s in data)) + # Resource classes for the above + extension_tuples = ( + utils.get_item_properties( + s, + columns, + formatters={}, + ) for s in data + ) + + # Dictionaries for the below + if parsed_args.network or show_all: + network_client = self.app.client_manager.network + try: + data = network_client.list_extensions()['extensions'] + dict_tuples = ( + utils.get_dict_properties( + s, + columns, + formatters={}, + ) for s in data + ) + extension_tuples = itertools.chain( + extension_tuples, + dict_tuples + ) + except Exception: + message = "Extensions list not supported by Network API" + self.log.warning(message) + + return (columns, extension_tuples) diff --git a/openstackclient/tests/common/test_extension.py b/openstackclient/tests/common/test_extension.py index 2e6e7050f8..5561345b50 100644 --- a/openstackclient/tests/common/test_extension.py +++ b/openstackclient/tests/common/test_extension.py @@ -18,6 +18,7 @@ from openstackclient.tests import fakes from openstackclient.tests import utils from openstackclient.tests.identity.v2_0 import fakes as identity_fakes +from openstackclient.tests.network.v2 import fakes as network_fakes class TestExtension(utils.TestCommand): @@ -29,12 +30,15 @@ class TestExtension(utils.TestCommand): endpoint=fakes.AUTH_URL, token=fakes.AUTH_TOKEN, ) - - # Get shortcuts to the ExtensionManager Mocks self.identity_extensions_mock = ( self.app.client_manager.identity.extensions) self.identity_extensions_mock.reset_mock() + network = network_fakes.FakeNetworkV2Client() + self.app.client_manager.network = network + self.network_extensions_mock = network.list_extensions + self.network_extensions_mock.reset_mock() + class TestExtensionList(TestExtension): @@ -48,6 +52,13 @@ class TestExtensionList(TestExtension): loaded=True, ), ] + self.network_extensions_mock.list.return_value = [ + fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.EXTENSION), + loaded=True, + ), + ] # Get the command object to test self.cmd = extension.ListExtension(self.app, None) @@ -71,6 +82,11 @@ class TestExtensionList(TestExtension): identity_fakes.extension_alias, identity_fakes.extension_description, ), + ( + network_fakes.extension_name, + network_fakes.extension_alias, + network_fakes.extension_description, + ), ) self.assertEqual(tuple(data), datalist) @@ -101,6 +117,14 @@ class TestExtensionList(TestExtension): identity_fakes.extension_updated, identity_fakes.extension_links, ), + ( + network_fakes.extension_name, + network_fakes.extension_namespace, + network_fakes.extension_description, + network_fakes.extension_alias, + network_fakes.extension_updated, + network_fakes.extension_links, + ), ) self.assertEqual(tuple(data), datalist) @@ -126,3 +150,27 @@ class TestExtensionList(TestExtension): identity_fakes.extension_description, ), ) self.assertEqual(tuple(data), datalist) + + def test_extension_list_network(self): + arglist = [ + '--network', + ] + verifylist = [ + ('network', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.network_extensions_mock.assert_called_with() + + collist = ('Name', 'Alias', 'Description') + self.assertEqual(columns, collist) + datalist = ( + ( + network_fakes.extension_name, + network_fakes.extension_alias, + network_fakes.extension_description, + ), + ) + self.assertEqual(tuple(data), datalist) diff --git a/openstackclient/tests/network/v2/fakes.py b/openstackclient/tests/network/v2/fakes.py new file mode 100644 index 0000000000..ea191c8e8c --- /dev/null +++ b/openstackclient/tests/network/v2/fakes.py @@ -0,0 +1,35 @@ +# 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. +# + +import mock + +extension_name = 'Matrix' +extension_namespace = 'http://docs.openstack.org/network/' +extension_description = 'Simulated reality' +extension_updated = '2013-07-09T12:00:0-00:00' +extension_alias = 'Dystopian' +extension_links = '[{"href":''"https://github.com/os/network", "type"}]' + +NETEXT = { + 'name': extension_name, + 'namespace': extension_namespace, + 'description': extension_description, + 'updated': extension_updated, + 'alias': extension_alias, + 'links': extension_links, +} + + +class FakeNetworkV2Client(object): + def __init__(self, **kwargs): + self.list_extensions = mock.Mock(return_value={'extensions': [NETEXT]})