From 94c9cd5c66512d52b31dfaa42bc3d1cc7fd81702 Mon Sep 17 00:00:00 2001 From: Richard Theis Date: Mon, 11 Apr 2016 13:45:12 -0500 Subject: [PATCH] Add options to security group rule list Add the following options to the 'os security group rule list' command: --long: Display direction and ethertype for Network v2 --all-projects: Display information from all projects for Compute v2 Change-Id: If8a1cbd7669cdfa6577d6d2f6fffd9e999a39a82 Partial-Bug: #1519512 Implements: blueprint neutron-client --- .../command-objects/security-group-rule.rst | 15 +++ doc/source/command-objects/security-group.rst | 2 +- .../network/v2/security_group_rule.py | 46 ++++++++- .../network/v2/test_security_group_rule.py | 99 ++++++++++++++++--- .../notes/bug-1519512-65df002102b7fb99.yaml | 10 +- 5 files changed, 149 insertions(+), 23 deletions(-) diff --git a/doc/source/command-objects/security-group-rule.rst b/doc/source/command-objects/security-group-rule.rst index 2f212e5ebf..8218c81aa0 100644 --- a/doc/source/command-objects/security-group-rule.rst +++ b/doc/source/command-objects/security-group-rule.rst @@ -98,8 +98,23 @@ List security group rules .. code:: bash os security group rule list + [--all-projects] + [--long] [] +.. option:: --all-projects + + Display information from all projects (admin only) + + *Network version 2 ignores this option and will always display information* + *for all projects (admin only).* + +.. option:: --long + + List additional fields in output + + *Compute version 2 does not have additional fields to display.* + .. describe:: List all rules in this security group (name or ID) diff --git a/doc/source/command-objects/security-group.rst b/doc/source/command-objects/security-group.rst index 9fc4c987ba..2c6e7a8adc 100644 --- a/doc/source/command-objects/security-group.rst +++ b/doc/source/command-objects/security-group.rst @@ -69,7 +69,7 @@ List security groups Display information from all projects (admin only) *Network version 2 ignores this option and will always display information* - *for all projects.* + *for all projects (admin only).* security group set ------------------ diff --git a/openstackclient/network/v2/security_group_rule.py b/openstackclient/network/v2/security_group_rule.py index 67472de05d..5b22a0dd83 100644 --- a/openstackclient/network/v2/security_group_rule.py +++ b/openstackclient/network/v2/security_group_rule.py @@ -13,6 +13,7 @@ """Security Group Rule action implementations""" +import argparse import six try: @@ -242,14 +243,50 @@ class ListSecurityGroupRule(common.NetworkAndComputeLister): ) return parser + def update_parser_network(self, parser): + # Accept but hide the argument for consistency with compute. + # Network will always return all projects for an admin. + parser.add_argument( + '--all-projects', + action='store_true', + default=False, + help=argparse.SUPPRESS + ) + parser.add_argument( + '--long', + action='store_true', + default=False, + help=_("List additional fields in output") + ) + return parser + + def update_parser_compute(self, parser): + parser.add_argument( + '--all-projects', + action='store_true', + default=False, + help=_("Display information from all projects (admin only)") + ) + # Accept but hide the argument for consistency with network. + # There are no additional fields to display at this time. + parser.add_argument( + '--long', + action='store_false', + default=False, + help=argparse.SUPPRESS + ) + return parser + def _get_column_headers(self, parsed_args): column_headers = ( 'ID', 'IP Protocol', 'IP Range', 'Port Range', - 'Remote Security Group', ) + if parsed_args.long: + column_headers = column_headers + ('Direction', 'Ethertype',) + column_headers = column_headers + ('Remote Security Group',) if parsed_args.group is None: column_headers = column_headers + ('Security Group',) return column_headers @@ -261,8 +298,10 @@ class ListSecurityGroupRule(common.NetworkAndComputeLister): 'protocol', 'remote_ip_prefix', 'port_range_min', - 'remote_group_id', ) + if parsed_args.long: + columns = columns + ('direction', 'ethertype',) + columns = columns + ('remote_group_id',) # Get the security group rules using the requested query. query = {} @@ -309,7 +348,8 @@ class ListSecurityGroupRule(common.NetworkAndComputeLister): rules_to_list = group.rules else: columns = columns + ('parent_group_id',) - for group in client.security_groups.list(): + search = {'all_tenants': parsed_args.all_projects} + for group in client.security_groups.list(search_opts=search): rules_to_list.extend(group.rules) # NOTE(rtheis): Turn the raw rules into resources. diff --git a/openstackclient/tests/network/v2/test_security_group_rule.py b/openstackclient/tests/network/v2/test_security_group_rule.py index c2fa12568f..df7414aa48 100644 --- a/openstackclient/tests/network/v2/test_security_group_rule.py +++ b/openstackclient/tests/network/v2/test_security_group_rule.py @@ -532,31 +532,46 @@ class TestListSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork): _security_group_rules = [_security_group_rule_tcp, _security_group_rule_icmp] - expected_columns_with_group = ( + expected_columns_with_group_and_long = ( + 'ID', + 'IP Protocol', + 'IP Range', + 'Port Range', + 'Direction', + 'Ethertype', + 'Remote Security Group', + ) + expected_columns_no_group = ( 'ID', 'IP Protocol', 'IP Range', 'Port Range', 'Remote Security Group', + 'Security Group', ) - expected_columns_no_group = \ - expected_columns_with_group + ('Security Group',) - expected_data_with_group = [] + expected_data_with_group_and_long = [] expected_data_no_group = [] for _security_group_rule in _security_group_rules: - expected_rule_with_group = ( + expected_data_with_group_and_long.append(( + _security_group_rule.id, + _security_group_rule.protocol, + _security_group_rule.remote_ip_prefix, + security_group_rule._format_network_port_range( + _security_group_rule), + _security_group_rule.direction, + _security_group_rule.ethertype, + _security_group_rule.remote_group_id, + )) + expected_data_no_group.append(( _security_group_rule.id, _security_group_rule.protocol, _security_group_rule.remote_ip_prefix, security_group_rule._format_network_port_range( _security_group_rule), _security_group_rule.remote_group_id, - ) - expected_rule_no_group = expected_rule_with_group + \ - (_security_group_rule.security_group_id,) - expected_data_with_group.append(expected_rule_with_group) - expected_data_no_group.append(expected_rule_no_group) + _security_group_rule.security_group_id, + )) def setUp(self): super(TestListSecurityGroupRuleNetwork, self).setUp() @@ -570,7 +585,7 @@ class TestListSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork): self.cmd = security_group_rule.ListSecurityGroupRule( self.app, self.namespace) - def test_list_no_group(self): + def test_list_default(self): self._security_group_rule_tcp.port_range_min = 80 parsed_args = self.check_parser(self.cmd, [], []) @@ -580,12 +595,14 @@ class TestListSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork): self.assertEqual(self.expected_columns_no_group, columns) self.assertEqual(self.expected_data_no_group, list(data)) - def test_list_with_group(self): + def test_list_with_group_and_long(self): self._security_group_rule_tcp.port_range_min = 80 arglist = [ + '--long', self._security_group.id, ] verifylist = [ + ('long', True), ('group', self._security_group.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -595,8 +612,24 @@ class TestListSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork): self.network.security_group_rules.assert_called_once_with(**{ 'security_group_id': self._security_group.id, }) - self.assertEqual(self.expected_columns_with_group, columns) - self.assertEqual(self.expected_data_with_group, list(data)) + self.assertEqual(self.expected_columns_with_group_and_long, columns) + self.assertEqual(self.expected_data_with_group_and_long, list(data)) + + def test_list_with_ignored_options(self): + self._security_group_rule_tcp.port_range_min = 80 + arglist = [ + '--all-projects', + ] + verifylist = [ + ('all_projects', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.network.security_group_rules.assert_called_once_with(**{}) + self.assertEqual(self.expected_columns_no_group, columns) + self.assertEqual(self.expected_data_no_group, list(data)) class TestListSecurityGroupRuleCompute(TestSecurityGroupRuleCompute): @@ -665,11 +698,13 @@ class TestListSecurityGroupRuleCompute(TestSecurityGroupRuleCompute): # Get the command object to test self.cmd = security_group_rule.ListSecurityGroupRule(self.app, None) - def test_list_no_group(self): + def test_list_default(self): parsed_args = self.check_parser(self.cmd, [], []) columns, data = self.cmd.take_action(parsed_args) - self.compute.security_groups.list.assert_called_once_with() + self.compute.security_groups.list.assert_called_once_with( + search_opts={'all_tenants': False} + ) self.assertEqual(self.expected_columns_no_group, columns) self.assertEqual(self.expected_data_no_group, list(data)) @@ -689,6 +724,38 @@ class TestListSecurityGroupRuleCompute(TestSecurityGroupRuleCompute): self.assertEqual(self.expected_columns_with_group, columns) self.assertEqual(self.expected_data_with_group, list(data)) + def test_list_all_projects(self): + arglist = [ + '--all-projects', + ] + verifylist = [ + ('all_projects', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + self.compute.security_groups.list.assert_called_once_with( + search_opts={'all_tenants': True} + ) + self.assertEqual(self.expected_columns_no_group, columns) + self.assertEqual(self.expected_data_no_group, list(data)) + + def test_list_with_ignored_options(self): + arglist = [ + '--long', + ] + verifylist = [ + ('long', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + self.compute.security_groups.list.assert_called_once_with( + search_opts={'all_tenants': False} + ) + self.assertEqual(self.expected_columns_no_group, columns) + self.assertEqual(self.expected_data_no_group, list(data)) + class TestShowSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork): diff --git a/releasenotes/notes/bug-1519512-65df002102b7fb99.yaml b/releasenotes/notes/bug-1519512-65df002102b7fb99.yaml index b5f5fbb531..87b14d6556 100644 --- a/releasenotes/notes/bug-1519512-65df002102b7fb99.yaml +++ b/releasenotes/notes/bug-1519512-65df002102b7fb99.yaml @@ -2,9 +2,13 @@ features: - The ``security group rule list`` command now uses Network v2 when enabled which results in ``egress`` security group rules - being displayed. In addition, security group rules for all - projects will be displayed when the ``group`` argument is not - specified (admin only). + being displayed. The ``--long`` option was also added for + Network v2 to display direction and ethertype information. + In addition, security group rules for all projects will be + displayed when the ``group`` argument is not specified + (admin only). This is done by default when using Network v2, + but requires the new ``--all-projects`` option when using + Compute v2. [Bug `1519512 `_] fixes: - The ``security group rule list`` command no longer ignores