From 3278b3a022c34b1abe28e1ed7b16ed60a059a441 Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Sat, 12 Dec 2015 10:28:48 +0800 Subject: [PATCH] Router: Add "router list" command using SDK Add "router list" command. It takes one "--long" option. By default, the command will print router id, name, status, admin state up, distributed, ha and project id. With "--long" option, it will also print routes and external gateway info. Change-Id: I9d21904c41c11ee1fa107f985744878a1dc2f970 Implements: blueprint neutron-client Partial-bug: #1519503 --- doc/source/command-objects/router.rst | 20 ++++ doc/source/commands.rst | 1 + openstackclient/network/v2/router.py | 93 ++++++++++++++++ .../tests/network/v2/test_router.py | 105 ++++++++++++++++++ setup.cfg | 1 + 5 files changed, 220 insertions(+) create mode 100644 doc/source/command-objects/router.rst create mode 100644 openstackclient/network/v2/router.py create mode 100644 openstackclient/tests/network/v2/test_router.py diff --git a/doc/source/command-objects/router.rst b/doc/source/command-objects/router.rst new file mode 100644 index 000000000..f7b5a67e0 --- /dev/null +++ b/doc/source/command-objects/router.rst @@ -0,0 +1,20 @@ +====== +router +====== + +Network v2 + +router list +----------- + +List routers + +.. program:: router list +.. code:: bash + + os router list + [--long] + +.. option:: --long + + List additional fields in output diff --git a/doc/source/commands.rst b/doc/source/commands.rst index 1c6c2d8ab..0ec4f71bc 100644 --- a/doc/source/commands.rst +++ b/doc/source/commands.rst @@ -107,6 +107,7 @@ referring to both Compute and Volume quotas. * ``request token``: (**Identity**) temporary OAuth-based token * ``role``: (**Identity**) a policy object used to determine authorization * ``role assignment``: (**Identity**) a relationship between roles, users or groups, and domains or projects +* ``router``: (**Network**) - a virtual router * ``security group``: (**Compute**, **Network**) - groups of network access rules * ``security group rule``: (**Compute**, **Network**) - the individual rules that define protocol/IP/port access * ``server``: (**Compute**) virtual machine instance diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py new file mode 100644 index 000000000..cf5dae59f --- /dev/null +++ b/openstackclient/network/v2/router.py @@ -0,0 +1,93 @@ +# 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. +# + +"""Router action implementations""" + +import json +import logging + +from cliff import lister + +from openstackclient.common import utils + + +def _format_admin_state(state): + return 'UP' if state else 'DOWN' + + +def _format_external_gateway_info(info): + try: + return json.dumps(info) + except (TypeError, KeyError): + return '' + + +_formatters = { + 'admin_state_up': _format_admin_state, + 'external_gateway_info': _format_external_gateway_info, +} + + +class ListRouter(lister.Lister): + """List routers""" + + log = logging.getLogger(__name__ + '.ListRouter') + + def get_parser(self, prog_name): + parser = super(ListRouter, self).get_parser(prog_name) + parser.add_argument( + '--long', + action='store_true', + default=False, + help='List additional fields in output', + ) + return parser + + def take_action(self, parsed_args): + self.log.debug('take_action(%s)' % parsed_args) + client = self.app.client_manager.network + + columns = ( + 'id', + 'name', + 'status', + 'admin_state_up', + 'distributed', + 'ha', + 'tenant_id', + ) + column_headers = ( + 'ID', + 'Name', + 'Status', + 'State', + 'Distributed', + 'HA', + 'Project', + ) + if parsed_args.long: + columns = columns + ( + 'routes', + 'external_gateway_info', + ) + column_headers = column_headers + ( + 'Routes', + 'External gateway info', + ) + + data = client.routers() + return (column_headers, + (utils.get_item_properties( + s, columns, + formatters=_formatters, + ) for s in data)) diff --git a/openstackclient/tests/network/v2/test_router.py b/openstackclient/tests/network/v2/test_router.py new file mode 100644 index 000000000..d91daceb8 --- /dev/null +++ b/openstackclient/tests/network/v2/test_router.py @@ -0,0 +1,105 @@ +# 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 + +from openstackclient.network.v2 import router +from openstackclient.tests.network.v2 import fakes as network_fakes + + +class TestRouter(network_fakes.TestNetworkV2): + + def setUp(self): + super(TestRouter, self).setUp() + + # Get a shortcut to the network client + self.network = self.app.client_manager.network + + +class TestListRouter(TestRouter): + + # The routers going to be listed up. + routers = network_fakes.FakeRouter.create_routers(count=3) + + columns = ( + 'ID', + 'Name', + 'Status', + 'State', + 'Distributed', + 'HA', + 'Project', + ) + columns_long = columns + ( + 'Routes', + 'External gateway info', + ) + + data = [] + for r in routers: + data.append(( + r.id, + r.name, + r.status, + router._format_admin_state(r.admin_state_up), + r.distributed, + r.ha, + r.tenant_id, + )) + data_long = [] + for i in range(0, len(routers)): + r = routers[i] + data_long.append( + data[i] + ( + r.routes, + router._format_external_gateway_info(r.external_gateway_info), + ) + ) + + def setUp(self): + super(TestListRouter, self).setUp() + + # Get the command object to test + self.cmd = router.ListRouter(self.app, self.namespace) + + self.network.routers = mock.Mock(return_value=self.routers) + + def test_router_list_no_options(self): + arglist = [] + verifylist = [ + ('long', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + self.network.routers.assert_called_with() + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_router_list_long(self): + arglist = [ + '--long', + ] + verifylist = [ + ('long', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + self.network.routers.assert_called_with() + self.assertEqual(self.columns_long, columns) + self.assertEqual(self.data_long, list(data)) diff --git a/setup.cfg b/setup.cfg index 27b00d45b..01615a338 100644 --- a/setup.cfg +++ b/setup.cfg @@ -332,6 +332,7 @@ openstack.network.v2 = network_list = openstackclient.network.v2.network:ListNetwork network_set = openstackclient.network.v2.network:SetNetwork network_show = openstackclient.network.v2.network:ShowNetwork + router_list = openstackclient.network.v2.router:ListRouter openstack.object_store.v1 = object_store_account_set = openstackclient.object.v1.account:SetAccount