diff --git a/doc/source/command-objects/subnet-pool.rst b/doc/source/command-objects/subnet-pool.rst index 005b83579..3330d62d5 100644 --- a/doc/source/command-objects/subnet-pool.rst +++ b/doc/source/command-objects/subnet-pool.rst @@ -104,11 +104,49 @@ List subnet pools os subnet pool list [--long] + [--share | --no-share] + [--default | --no-default] + [--project [--project-domain ]] + [--name ] + [--address-scope ] .. option:: --long List additional fields in output +.. option:: --share + + List subnets shared between projects + +.. option:: --no-share + + List subnets not shared between projects + +.. option:: --default + + List subnets used as the default external subnet pool + +.. option:: --no-default + + List subnets not used as the default external subnet pool + +.. option:: --project + + List subnets 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:: --name + + List only subnets of given name in output + +.. option:: --address-scope + + List only subnets of given address scope (name or ID) in output + subnet pool set --------------- diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py index d3fab8acb..6852ca27a 100644 --- a/openstackclient/network/v2/subnet_pool.py +++ b/openstackclient/network/v2/subnet_pool.py @@ -226,41 +226,82 @@ class ListSubnetPool(command.Lister): default=False, help=_("List additional fields in output") ) + shared_group = parser.add_mutually_exclusive_group() + shared_group.add_argument( + '--share', + action='store_true', + help=_("List subnets shared between projects"), + ) + shared_group.add_argument( + '--no-share', + action='store_true', + help=_("List subnets not shared between projects"), + ) + default_group = parser.add_mutually_exclusive_group() + default_group.add_argument( + '--default', + action='store_true', + help=_("List subnets used as the default external subnet pool"), + ) + default_group.add_argument( + '--no-default', + action='store_true', + help=_("List subnets not used as the default external subnet pool") + ) + parser.add_argument( + '--project', + metavar='', + help=_("List subnets according to their project (name or ID)") + ) + identity_common.add_project_domain_option_to_parser(parser) + parser.add_argument( + '--name', + metavar='', + help=_("List only subnets of given name in output") + ) + parser.add_argument( + '--address-scope', + metavar='', + help=_("List only subnets of given address scope (name or ID) " + "in output") + ) return parser def take_action(self, parsed_args): - data = self.app.client_manager.network.subnet_pools() + identity_client = self.app.client_manager.identity + network_client = self.app.client_manager.network + filters = {} + if parsed_args.share: + filters['shared'] = True + elif parsed_args.no_share: + filters['shared'] = False + if parsed_args.default: + filters['is_default'] = True + elif parsed_args.no_default: + filters['is_default'] = False + if parsed_args.project: + project_id = identity_common.find_project( + identity_client, + parsed_args.project, + parsed_args.project_domain, + ).id + filters['tenant_id'] = project_id + if parsed_args.name is not None: + filters['name'] = parsed_args.name + if parsed_args.address_scope: + address_scope = network_client.find_address_scope( + parsed_args.address_scope, + ignore_missing=False) + filters['address_scope_id'] = address_scope.id + data = network_client.subnet_pools(**filters) + headers = ('ID', 'Name', 'Prefixes') + columns = ('id', 'name', 'prefixes') if parsed_args.long: - headers = ( - 'ID', - 'Name', - 'Prefixes', - 'Default Prefix Length', - 'Address Scope', - 'Default Subnet Pool', - 'Shared', - ) - columns = ( - 'id', - 'name', - 'prefixes', - 'default_prefixlen', - 'address_scope_id', - 'is_default', - 'shared', - ) - else: - headers = ( - 'ID', - 'Name', - 'Prefixes', - ) - columns = ( - 'id', - 'name', - 'prefixes', - ) + headers += ('Default Prefix Length', 'Address Scope', + 'Default Subnet Pool', 'Shared') + columns += ('default_prefixlen', 'address_scope_id', + 'is_default', 'shared') return (headers, (utils.get_item_properties( diff --git a/openstackclient/tests/unit/network/v2/test_subnet_pool.py b/openstackclient/tests/unit/network/v2/test_subnet_pool.py index e0e1969ba..251323d94 100644 --- a/openstackclient/tests/unit/network/v2/test_subnet_pool.py +++ b/openstackclient/tests/unit/network/v2/test_subnet_pool.py @@ -400,6 +400,144 @@ class TestListSubnetPool(TestSubnetPool): self.assertEqual(self.columns_long, columns) self.assertEqual(self.data_long, list(data)) + def test_subnet_pool_list_no_share(self): + arglist = [ + '--no-share', + ] + verifylist = [ + ('share', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + filters = {'shared': False} + + self.network.subnet_pools.assert_called_once_with(**filters) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_subnet_pool_list_share(self): + arglist = [ + '--share', + ] + verifylist = [ + ('share', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + filters = {'shared': True} + + self.network.subnet_pools.assert_called_once_with(**filters) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_subnet_pool_list_no_default(self): + arglist = [ + '--no-default', + ] + verifylist = [ + ('default', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + filters = {'is_default': False} + + self.network.subnet_pools.assert_called_once_with(**filters) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_subnet_pool_list_default(self): + arglist = [ + '--default', + ] + verifylist = [ + ('default', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + filters = {'is_default': True} + + self.network.subnet_pools.assert_called_once_with(**filters) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_subnet_pool_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) + filters = {'tenant_id': project.id} + + self.network.subnet_pools.assert_called_once_with(**filters) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_subnet_pool_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), + ('project_domain', project.domain_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.subnet_pools.assert_called_once_with(**filters) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_subnet_pool_list_name(self): + subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool() + self.network.find_network = mock.Mock(return_value=subnet_pool) + arglist = [ + '--name', subnet_pool.name, + ] + verifylist = [ + ('name', subnet_pool.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + filters = {'name': subnet_pool.name} + + self.network.subnet_pools.assert_called_once_with(**filters) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_subnet_pool_list_address_scope(self): + addr_scope = network_fakes.FakeAddressScope.create_one_address_scope() + self.network.find_address_scope = mock.Mock(return_value=addr_scope) + arglist = [ + '--address-scope', addr_scope.id, + ] + verifylist = [ + ('address_scope', addr_scope.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + filters = {'address_scope_id': addr_scope.id} + + self.network.subnet_pools.assert_called_once_with(**filters) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + class TestSetSubnetPool(TestSubnetPool): diff --git a/releasenotes/notes/bug-1613926-2d0e405831c0b5a9.yaml b/releasenotes/notes/bug-1613926-2d0e405831c0b5a9.yaml new file mode 100644 index 000000000..fca316c16 --- /dev/null +++ b/releasenotes/notes/bug-1613926-2d0e405831c0b5a9.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Make ``subnet pool list`` command supports listing up subnets with + some filtering options by adding ``--share`` and ``--no-share``, + ``--project`` and ``--project-domain``, ``--default`` and ``--no-default``, + ``--name``, ``--address-scope`` options to the command. + [Bug `1613926 `_]