diff --git a/doc/source/command-objects/network.rst b/doc/source/command-objects/network.rst index 5d9a5ca860..8cc250d542 100644 --- a/doc/source/command-objects/network.rst +++ b/doc/source/command-objects/network.rst @@ -181,17 +181,60 @@ List networks .. code:: bash os network list - [--external] + [--external | --internal] [--long] + [--name ] + [--enable | --disable] + [--project [--project-domain ]] + [--share | --no-share] + [--status ] .. option:: --external List external networks +.. option:: --internal + + List internal networks + .. option:: --long List additional fields in output +.. option:: --name + + List networks according to their name + +.. option:: --enable + + List enabled networks + +.. option:: --disable + + List disabled networks + +.. option:: --project + + List networks according to their project (name or ID) + +.. option:: --project-domain + + Domain the project belongs to (name or ID). + This can be used in case collisions between project names exist. + +.. option:: --share + + List networks shared between projects + +.. option:: --no-share + + List networks not shared between projects + +.. option:: --status + + List networks according to their status + ('ACTIVE', 'BUILD', 'DOWN', 'ERROR') + network set ----------- diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index ccc02fd8e6..6529f8699b 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -295,21 +295,66 @@ class ListNetwork(common.NetworkAndComputeLister): """List networks""" def update_parser_common(self, parser): - parser.add_argument( + router_ext_group = parser.add_mutually_exclusive_group() + router_ext_group.add_argument( '--external', action='store_true', - default=False, help=_("List external networks") ) + router_ext_group.add_argument( + '--internal', + action='store_true', + help=_("List internal networks") + ) parser.add_argument( '--long', action='store_true', - default=False, help=_("List additional fields in output") ) + parser.add_argument( + '--name', + metavar='', + help=_("List networks according to their name") + ) + admin_state_group = parser.add_mutually_exclusive_group() + admin_state_group.add_argument( + '--enable', + action='store_true', + help=_("List enabled networks") + ) + admin_state_group.add_argument( + '--disable', + action='store_true', + help=_("List disabled networks") + ) + parser.add_argument( + '--project', + metavar='', + help=_("List networks according to their project (name or ID)") + ) + identity_common.add_project_domain_option_to_parser(parser) + shared_group = parser.add_mutually_exclusive_group() + shared_group.add_argument( + '--share', + action='store_true', + help=_("List networks shared between projects") + ) + shared_group.add_argument( + '--no-share', + action='store_true', + help=_("List networks not shared between projects") + ) + parser.add_argument( + '--status', + metavar='', + choices=['ACTIVE', 'BUILD', 'DOWN', 'ERROR'], + help=_("List networks according to their status " + "('ACTIVE', 'BUILD', 'DOWN', 'ERROR')") + ) return parser def take_action_network(self, client, parsed_args): + identity_client = self.app.client_manager.identity if parsed_args.long: columns = ( 'id', @@ -347,10 +392,36 @@ class ListNetwork(common.NetworkAndComputeLister): 'Subnets', ) + args = {} + if parsed_args.external: - args = {'router:external': True} - else: - args = {} + args['router:external'] = True + elif parsed_args.internal: + args['router:external'] = False + + if parsed_args.name is not None: + args['name'] = parsed_args.name + + if parsed_args.enable: + args['admin_state_up'] = True + elif parsed_args.disable: + args['admin_state_up'] = False + + if parsed_args.project: + project = identity_common.find_project( + identity_client, + parsed_args.project, + parsed_args.project_domain, + ) + args['tenant_id'] = project.id + + if parsed_args.share: + args['shared'] = True + elif parsed_args.no_share: + args['shared'] = False + + if parsed_args.status: + args['status'] = parsed_args.status data = client.networks(**args) diff --git a/openstackclient/tests/unit/network/v2/test_network.py b/openstackclient/tests/unit/network/v2/test_network.py index 84ead0938b..9a37564567 100644 --- a/openstackclient/tests/unit/network/v2/test_network.py +++ b/openstackclient/tests/unit/network/v2/test_network.py @@ -13,6 +13,7 @@ import mock from mock import call +import random from osc_lib import exceptions from osc_lib import utils @@ -491,6 +492,23 @@ class TestListNetwork(TestNetwork): self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) + def test_list_internal(self): + arglist = [ + '--internal', + ] + verifylist = [ + ('internal', True), + ('long', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.networks.assert_called_once_with( + **{'router:external': False} + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + def test_network_list_long(self): arglist = [ '--long', @@ -510,6 +528,150 @@ class TestListNetwork(TestNetwork): self.assertEqual(self.columns_long, columns) self.assertEqual(self.data_long, list(data)) + def test_list_name(self): + test_name = "fakename" + arglist = [ + '--name', test_name, + ] + verifylist = [ + ('external', False), + ('long', False), + ('name', test_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.networks.assert_called_once_with( + **{'name': test_name} + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_network_list_enable(self): + arglist = [ + '--enable', + ] + verifylist = [ + ('long', False), + ('external', False), + ('enable', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.networks.assert_called_once_with( + **{'admin_state_up': True} + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_network_list_disable(self): + arglist = [ + '--disable', + ] + verifylist = [ + ('long', False), + ('external', False), + ('disable', True) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.networks.assert_called_once_with( + **{'admin_state_up': False} + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_network_list_project(self): + project = identity_fakes_v3.FakeProject.create_one_project() + self.projects_mock.get.return_value = project + arglist = [ + '--project', project.id, + ] + verifylist = [ + ('project', project.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + self.network.networks.assert_called_once_with( + **{'tenant_id': project.id} + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_networ_list_project_domain(self): + project = identity_fakes_v3.FakeProject.create_one_project() + self.projects_mock.get.return_value = project + arglist = [ + '--project', project.id, + '--project-domain', project.domain_id, + ] + verifylist = [ + ('project', project.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + filters = {'tenant_id': project.id} + + self.network.networks.assert_called_once_with(**filters) + + def test_network_list_share(self): + arglist = [ + '--share', + ] + verifylist = [ + ('long', False), + ('share', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.networks.assert_called_once_with( + **{'shared': True} + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_network_list_no_share(self): + arglist = [ + '--no-share', + ] + verifylist = [ + ('long', False), + ('no_share', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.networks.assert_called_once_with( + **{'shared': False} + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_network_list_status(self): + choices = ['ACTIVE', 'BUILD', 'DOWN', 'ERROR'] + test_status = random.choice(choices) + arglist = [ + '--status', test_status, + ] + verifylist = [ + ('long', False), + ('status', test_status), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.networks.assert_called_once_with( + **{'status': test_status} + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + class TestSetNetwork(TestNetwork): diff --git a/releasenotes/notes/bug-1578819-d1efccfefb18356d.yaml b/releasenotes/notes/bug-1578819-d1efccfefb18356d.yaml new file mode 100644 index 0000000000..47c870d660 --- /dev/null +++ b/releasenotes/notes/bug-1578819-d1efccfefb18356d.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Add ``--internal``, ``--name``, ``--project`` and ``--project-domain``, + ``--enable`` and ``--disable``, ``--share`` and ``--no share``, ``--status`` + options to the ``network list`` command. + [Bug `1578819 `_]