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
This commit is contained in:
Richard Theis 2016-04-11 13:45:12 -05:00
parent e3a6fc27b0
commit 94c9cd5c66
5 changed files with 149 additions and 23 deletions

View File

@ -98,8 +98,23 @@ List security group rules
.. code:: bash .. code:: bash
os security group rule list os security group rule list
[--all-projects]
[--long]
[<group>] [<group>]
.. 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:: <group> .. describe:: <group>
List all rules in this security group (name or ID) List all rules in this security group (name or ID)

View File

@ -69,7 +69,7 @@ List security groups
Display information from all projects (admin only) Display information from all projects (admin only)
*Network version 2 ignores this option and will always display information* *Network version 2 ignores this option and will always display information*
*for all projects.* *for all projects (admin only).*
security group set security group set
------------------ ------------------

View File

@ -13,6 +13,7 @@
"""Security Group Rule action implementations""" """Security Group Rule action implementations"""
import argparse
import six import six
try: try:
@ -242,14 +243,50 @@ class ListSecurityGroupRule(common.NetworkAndComputeLister):
) )
return parser 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): def _get_column_headers(self, parsed_args):
column_headers = ( column_headers = (
'ID', 'ID',
'IP Protocol', 'IP Protocol',
'IP Range', 'IP Range',
'Port 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: if parsed_args.group is None:
column_headers = column_headers + ('Security Group',) column_headers = column_headers + ('Security Group',)
return column_headers return column_headers
@ -261,8 +298,10 @@ class ListSecurityGroupRule(common.NetworkAndComputeLister):
'protocol', 'protocol',
'remote_ip_prefix', 'remote_ip_prefix',
'port_range_min', '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. # Get the security group rules using the requested query.
query = {} query = {}
@ -309,7 +348,8 @@ class ListSecurityGroupRule(common.NetworkAndComputeLister):
rules_to_list = group.rules rules_to_list = group.rules
else: else:
columns = columns + ('parent_group_id',) 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) rules_to_list.extend(group.rules)
# NOTE(rtheis): Turn the raw rules into resources. # NOTE(rtheis): Turn the raw rules into resources.

View File

@ -532,31 +532,46 @@ class TestListSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
_security_group_rules = [_security_group_rule_tcp, _security_group_rules = [_security_group_rule_tcp,
_security_group_rule_icmp] _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', 'ID',
'IP Protocol', 'IP Protocol',
'IP Range', 'IP Range',
'Port Range', 'Port Range',
'Remote Security Group', '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 = [] expected_data_no_group = []
for _security_group_rule in _security_group_rules: 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.id,
_security_group_rule.protocol, _security_group_rule.protocol,
_security_group_rule.remote_ip_prefix, _security_group_rule.remote_ip_prefix,
security_group_rule._format_network_port_range( security_group_rule._format_network_port_range(
_security_group_rule), _security_group_rule),
_security_group_rule.remote_group_id, _security_group_rule.remote_group_id,
) _security_group_rule.security_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)
def setUp(self): def setUp(self):
super(TestListSecurityGroupRuleNetwork, self).setUp() super(TestListSecurityGroupRuleNetwork, self).setUp()
@ -570,7 +585,7 @@ class TestListSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
self.cmd = security_group_rule.ListSecurityGroupRule( self.cmd = security_group_rule.ListSecurityGroupRule(
self.app, self.namespace) self.app, self.namespace)
def test_list_no_group(self): def test_list_default(self):
self._security_group_rule_tcp.port_range_min = 80 self._security_group_rule_tcp.port_range_min = 80
parsed_args = self.check_parser(self.cmd, [], []) 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_columns_no_group, columns)
self.assertEqual(self.expected_data_no_group, list(data)) 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 self._security_group_rule_tcp.port_range_min = 80
arglist = [ arglist = [
'--long',
self._security_group.id, self._security_group.id,
] ]
verifylist = [ verifylist = [
('long', True),
('group', self._security_group.id), ('group', self._security_group.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) 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(**{ self.network.security_group_rules.assert_called_once_with(**{
'security_group_id': self._security_group.id, 'security_group_id': self._security_group.id,
}) })
self.assertEqual(self.expected_columns_with_group, columns) self.assertEqual(self.expected_columns_with_group_and_long, columns)
self.assertEqual(self.expected_data_with_group, list(data)) 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): class TestListSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
@ -665,11 +698,13 @@ class TestListSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
# Get the command object to test # Get the command object to test
self.cmd = security_group_rule.ListSecurityGroupRule(self.app, None) 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, [], []) parsed_args = self.check_parser(self.cmd, [], [])
columns, data = self.cmd.take_action(parsed_args) 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_columns_no_group, columns)
self.assertEqual(self.expected_data_no_group, list(data)) 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_columns_with_group, columns)
self.assertEqual(self.expected_data_with_group, list(data)) 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): class TestShowSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):

View File

@ -2,9 +2,13 @@
features: features:
- The ``security group rule list`` command now uses Network v2 - The ``security group rule list`` command now uses Network v2
when enabled which results in ``egress`` security group rules when enabled which results in ``egress`` security group rules
being displayed. In addition, security group rules for all being displayed. The ``--long`` option was also added for
projects will be displayed when the ``group`` argument is not Network v2 to display direction and ethertype information.
specified (admin only). 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 <https://bugs.launchpad.net/bugs/1519512>`_] [Bug `1519512 <https://bugs.launchpad.net/bugs/1519512>`_]
fixes: fixes:
- The ``security group rule list`` command no longer ignores - The ``security group rule list`` command no longer ignores