Skip to content

Commit 96cc5eb

Browse files
committed
Add support to list all security group rules
Both nova and neutron allow security group rules to be listed without specifying the owning security group. This patch set makes the group argument on 'os security group rule list' optional. Behavior is unchanged when the argument is specified. When the argument is not specified then all accessible security group rules will be listed. The listing will include the owning security group for each rule. Change-Id: I6914baecf70a65354e1e82dad92c6afbd32b4973 Related-Bug: #1519512
1 parent d72f622 commit 96cc5eb

3 files changed

Lines changed: 104 additions & 16 deletions

File tree

doc/source/command-objects/security-group-rule.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ List security group rules
6262
.. code:: bash
6363
6464
os security group rule list
65-
<group>
65+
[<group>]
6666
6767
.. describe:: <group>
6868

openstackclient/compute/v2/security_group.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ def get_parser(self, prog_name):
278278
parser.add_argument(
279279
'group',
280280
metavar='<group>',
281+
nargs='?',
281282
help='List all rules in this security group (name or ID)',
282283
)
283284
return parser
@@ -286,26 +287,35 @@ def take_action(self, parsed_args):
286287
self.log.debug("take_action(%s)", parsed_args)
287288

288289
compute_client = self.app.client_manager.compute
289-
group = utils.find_resource(
290-
compute_client.security_groups,
291-
parsed_args.group,
290+
columns = column_headers = (
291+
"ID",
292+
"IP Protocol",
293+
"IP Range",
294+
"Port Range",
295+
"Remote Security Group",
292296
)
293297

298+
rules_to_list = []
299+
if parsed_args.group:
300+
group = utils.find_resource(
301+
compute_client.security_groups,
302+
parsed_args.group,
303+
)
304+
rules_to_list = group.rules
305+
else:
306+
columns = columns + ('parent_group_id',)
307+
column_headers = column_headers + ('Security Group',)
308+
for group in compute_client.security_groups.list():
309+
rules_to_list.extend(group.rules)
310+
294311
# Argh, the rules are not Resources...
295312
rules = []
296-
for rule in group.rules:
313+
for rule in rules_to_list:
297314
rules.append(security_group_rules.SecurityGroupRule(
298315
compute_client.security_group_rules,
299316
_xform_security_group_rule(rule),
300317
))
301318

302-
columns = column_headers = (
303-
"ID",
304-
"IP Protocol",
305-
"IP Range",
306-
"Port Range",
307-
"Remote Security Group",
308-
)
309319
return (column_headers,
310320
(utils.get_item_properties(
311321
s, columns,

openstackclient/tests/compute/v2/test_security_group_rule.py

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,28 @@
6868
SECURITY_GROUP_RULE_REMOTE_GROUP],
6969
}
7070

71+
security_group_2_id = '12'
72+
security_group_2_name = 'he-shoots'
73+
security_group_2_description = 'he scores'
74+
75+
SECURITY_GROUP_2_RULE = {
76+
'id': '2',
77+
'group': {},
78+
'ip_protocol': 'tcp',
79+
'ip_range': {},
80+
'parent_group_id': security_group_2_id,
81+
'from_port': 80,
82+
'to_port': 80,
83+
}
84+
85+
SECURITY_GROUP_2 = {
86+
'id': security_group_2_id,
87+
'name': security_group_2_name,
88+
'description': security_group_2_description,
89+
'tenant_id': identity_fakes.project_id,
90+
'rules': [SECURITY_GROUP_2_RULE],
91+
}
92+
7193

7294
class FakeSecurityGroupRuleResource(fakes.FakeResource):
7395

@@ -383,12 +405,22 @@ class TestSecurityGroupRuleList(TestSecurityGroupRule):
383405
def setUp(self):
384406
super(TestSecurityGroupRuleList, self).setUp()
385407

386-
self.secgroups_mock.get.return_value = FakeSecurityGroupRuleResource(
408+
security_group_mock = FakeSecurityGroupRuleResource(
387409
None,
388410
copy.deepcopy(SECURITY_GROUP),
389411
loaded=True,
390412
)
391413

414+
security_group_2_mock = FakeSecurityGroupRuleResource(
415+
None,
416+
copy.deepcopy(SECURITY_GROUP_2),
417+
loaded=True,
418+
)
419+
420+
self.secgroups_mock.get.return_value = security_group_mock
421+
self.secgroups_mock.list.return_value = [security_group_mock,
422+
security_group_2_mock]
423+
392424
# Get the command object to test
393425
self.cmd = security_group.ListSecurityGroupRule(self.app, None)
394426

@@ -420,18 +452,64 @@ def test_security_group_rule_list(self):
420452
security_group_rule_cidr,
421453
'0:0',
422454
'',
423-
), (
455+
), (
424456
security_group_rule_id,
425457
'icmp',
426458
security_group_rule_cidr,
427459
'',
428460
'',
429-
), (
461+
), (
430462
security_group_rule_id,
431463
'tcp',
432464
'',
433465
'80:80',
434466
'default',
435-
),
467+
),)
468+
self.assertEqual(datalist, tuple(data))
469+
470+
def test_security_group_rule_list_no_group(self):
471+
472+
parsed_args = self.check_parser(self.cmd, [], [])
473+
474+
# DisplayCommandBase.take_action() returns two tuples
475+
columns, data = self.cmd.take_action(parsed_args)
476+
477+
collist = (
478+
'ID',
479+
'IP Protocol',
480+
'IP Range',
481+
'Port Range',
482+
'Remote Security Group',
483+
'Security Group',
436484
)
485+
self.assertEqual(collist, columns)
486+
datalist = ((
487+
security_group_rule_id,
488+
'tcp',
489+
security_group_rule_cidr,
490+
'0:0',
491+
'',
492+
security_group_id,
493+
), (
494+
security_group_rule_id,
495+
'icmp',
496+
security_group_rule_cidr,
497+
'',
498+
'',
499+
security_group_id,
500+
), (
501+
security_group_rule_id,
502+
'tcp',
503+
'',
504+
'80:80',
505+
'default',
506+
security_group_id,
507+
), (
508+
'2',
509+
'tcp',
510+
'',
511+
'80:80',
512+
'',
513+
security_group_2_id,
514+
),)
437515
self.assertEqual(datalist, tuple(data))

0 commit comments

Comments
 (0)