Skip to content

Commit c2f5945

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Add "security group rule show" command"
2 parents ab40add + dccde70 commit c2f5945

7 files changed

Lines changed: 236 additions & 4 deletions

File tree

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,18 @@ List security group rules
6767
.. describe:: <group>
6868

6969
List all rules in this security group (name or ID)
70+
71+
security group rule show
72+
------------------------
73+
74+
Display security group rule details
75+
76+
.. program:: security group rule show
77+
.. code:: bash
78+
79+
os security group rule show
80+
<rule>
81+
82+
.. describe:: <rule>
83+
84+
Security group rule to display (ID only)

functional/tests/network/v2/test_security_group_rule.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,10 @@ def test_security_group_rule_list(self):
5757
self.SECURITY_GROUP_NAME +
5858
opts)
5959
self.assertIn(self.SECURITY_GROUP_RULE_ID, raw_output)
60+
61+
def test_security_group_rule_show(self):
62+
opts = self.get_show_opts(self.ID_FIELD)
63+
raw_output = self.openstack('security group rule show ' +
64+
self.SECURITY_GROUP_RULE_ID +
65+
opts)
66+
self.assertEqual(self.SECURITY_GROUP_RULE_ID + "\n", raw_output)

openstackclient/network/v2/security_group_rule.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,54 @@
1313

1414
"""Security Group Rule action implementations"""
1515

16+
import six
17+
18+
from openstackclient.common import exceptions
19+
from openstackclient.common import utils
1620
from openstackclient.network import common
1721

1822

23+
def _xform_security_group_rule(sgroup):
24+
info = {}
25+
info.update(sgroup)
26+
from_port = info.pop('from_port')
27+
to_port = info.pop('to_port')
28+
if isinstance(from_port, int) and isinstance(to_port, int):
29+
port_range = {'port_range': "%u:%u" % (from_port, to_port)}
30+
elif from_port is None and to_port is None:
31+
port_range = {'port_range': ""}
32+
else:
33+
port_range = {'port_range': "%s:%s" % (from_port, to_port)}
34+
info.update(port_range)
35+
if 'cidr' in info['ip_range']:
36+
info['ip_range'] = info['ip_range']['cidr']
37+
else:
38+
info['ip_range'] = ''
39+
if info['ip_protocol'] is None:
40+
info['ip_protocol'] = ''
41+
elif info['ip_protocol'].lower() == 'icmp':
42+
info['port_range'] = ''
43+
group = info.pop('group')
44+
if 'name' in group:
45+
info['remote_security_group'] = group['name']
46+
else:
47+
info['remote_security_group'] = ''
48+
return info
49+
50+
51+
def _format_security_group_rule_show(obj):
52+
data = _xform_security_group_rule(obj)
53+
return zip(*sorted(six.iteritems(data)))
54+
55+
56+
def _get_columns(item):
57+
columns = item.keys()
58+
if 'tenant_id' in columns:
59+
columns.remove('tenant_id')
60+
columns.append('project_id')
61+
return tuple(sorted(columns))
62+
63+
1964
class DeleteSecurityGroupRule(common.NetworkAndComputeCommand):
2065
"""Delete a security group rule"""
2166

@@ -33,3 +78,44 @@ def take_action_network(self, client, parsed_args):
3378

3479
def take_action_compute(self, client, parsed_args):
3580
client.security_group_rules.delete(parsed_args.rule)
81+
82+
83+
class ShowSecurityGroupRule(common.NetworkAndComputeShowOne):
84+
"""Display security group rule details"""
85+
86+
def update_parser_common(self, parser):
87+
parser.add_argument(
88+
'rule',
89+
metavar="<rule>",
90+
help="Security group rule to display (ID only)"
91+
)
92+
return parser
93+
94+
def take_action_network(self, client, parsed_args):
95+
obj = client.find_security_group_rule(parsed_args.rule,
96+
ignore_missing=False)
97+
columns = _get_columns(obj)
98+
data = utils.get_item_properties(obj, columns)
99+
return (columns, data)
100+
101+
def take_action_compute(self, client, parsed_args):
102+
# NOTE(rtheis): Unfortunately, compute does not have an API
103+
# to get or list security group rules so parse through the
104+
# security groups to find all accessible rules in search of
105+
# the requested rule.
106+
obj = None
107+
security_group_rules = []
108+
for security_group in client.security_groups.list():
109+
security_group_rules.extend(security_group.rules)
110+
for security_group_rule in security_group_rules:
111+
if parsed_args.rule == str(security_group_rule.get('id')):
112+
obj = security_group_rule
113+
break
114+
115+
if obj is None:
116+
msg = "Could not find security group rule " \
117+
"with ID %s" % parsed_args.rule
118+
raise exceptions.CommandError(msg)
119+
120+
# NOTE(rtheis): Format security group rule
121+
return _format_security_group_rule_show(obj)

openstackclient/tests/network/v2/fakes.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,15 +480,13 @@ def create_one_security_group_rule(attrs={}, methods={}):
480480
:param Dictionary methods:
481481
A dictionary with all methods
482482
:return:
483-
A FakeResource object, with id, name, etc.
483+
A FakeResource object, with id, etc.
484484
"""
485485
# Set default attributes.
486486
security_group_rule_attrs = {
487-
'description': 'security-group-rule-desc-' + uuid.uuid4().hex,
488487
'direction': 'ingress',
489488
'ethertype': 'IPv4',
490489
'id': 'security-group-rule-id-' + uuid.uuid4().hex,
491-
'name': 'security-group-rule-name-' + uuid.uuid4().hex,
492490
'port_range_max': None,
493491
'port_range_min': None,
494492
'protocol': None,
@@ -502,7 +500,11 @@ def create_one_security_group_rule(attrs={}, methods={}):
502500
security_group_rule_attrs.update(attrs)
503501

504502
# Set default methods.
505-
security_group_rule_methods = {}
503+
security_group_rule_methods = {
504+
'keys': ['direction', 'ethertype', 'id', 'port_range_max',
505+
'port_range_min', 'protocol', 'remote_group_id',
506+
'remote_ip_prefix', 'security_group_id', 'tenant_id'],
507+
}
506508

507509
# Overwrite default methods.
508510
security_group_rule_methods.update(methods)
@@ -511,6 +513,10 @@ def create_one_security_group_rule(attrs={}, methods={}):
511513
info=copy.deepcopy(security_group_rule_attrs),
512514
methods=copy.deepcopy(security_group_rule_methods),
513515
loaded=True)
516+
517+
# Set attributes with special mappings.
518+
security_group_rule.project_id = security_group_rule_attrs['tenant_id']
519+
514520
return security_group_rule
515521

516522
@staticmethod

openstackclient/tests/network/v2/test_security_group_rule.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111
# under the License.
1212
#
1313

14+
import copy
1415
import mock
1516

1617
from openstackclient.network.v2 import security_group_rule
1718
from openstackclient.tests.compute.v2 import fakes as compute_fakes
19+
from openstackclient.tests import fakes
1820
from openstackclient.tests.network.v2 import fakes as network_fakes
21+
from openstackclient.tests import utils as tests_utils
1922

2023

2124
class TestSecurityGroupRuleNetwork(network_fakes.TestNetworkV2):
@@ -98,3 +101,112 @@ def test_security_group_rule_delete(self):
98101
self.compute.security_group_rules.delete.assert_called_with(
99102
self._security_group_rule.id)
100103
self.assertIsNone(result)
104+
105+
106+
class TestShowSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
107+
108+
# The security group rule to be shown.
109+
_security_group_rule = \
110+
network_fakes.FakeSecurityGroupRule.create_one_security_group_rule()
111+
112+
columns = (
113+
'direction',
114+
'ethertype',
115+
'id',
116+
'port_range_max',
117+
'port_range_min',
118+
'project_id',
119+
'protocol',
120+
'remote_group_id',
121+
'remote_ip_prefix',
122+
'security_group_id',
123+
)
124+
125+
data = (
126+
_security_group_rule.direction,
127+
_security_group_rule.ethertype,
128+
_security_group_rule.id,
129+
_security_group_rule.port_range_max,
130+
_security_group_rule.port_range_min,
131+
_security_group_rule.project_id,
132+
_security_group_rule.protocol,
133+
_security_group_rule.remote_group_id,
134+
_security_group_rule.remote_ip_prefix,
135+
_security_group_rule.security_group_id,
136+
)
137+
138+
def setUp(self):
139+
super(TestShowSecurityGroupRuleNetwork, self).setUp()
140+
141+
self.network.find_security_group_rule = mock.Mock(
142+
return_value=self._security_group_rule)
143+
144+
# Get the command object to test
145+
self.cmd = security_group_rule.ShowSecurityGroupRule(
146+
self.app, self.namespace)
147+
148+
def test_show_no_options(self):
149+
self.assertRaises(tests_utils.ParserException,
150+
self.check_parser, self.cmd, [], [])
151+
152+
def test_show_all_options(self):
153+
arglist = [
154+
self._security_group_rule.id,
155+
]
156+
verifylist = [
157+
('rule', self._security_group_rule.id),
158+
]
159+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
160+
161+
columns, data = self.cmd.take_action(parsed_args)
162+
163+
self.network.find_security_group_rule.assert_called_with(
164+
self._security_group_rule.id, ignore_missing=False)
165+
self.assertEqual(tuple(self.columns), columns)
166+
self.assertEqual(self.data, data)
167+
168+
169+
class TestShowSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
170+
171+
# The security group rule to be shown.
172+
_security_group_rule = \
173+
compute_fakes.FakeSecurityGroupRule.create_one_security_group_rule()
174+
175+
columns, data = \
176+
security_group_rule._format_security_group_rule_show(
177+
_security_group_rule._info)
178+
179+
def setUp(self):
180+
super(TestShowSecurityGroupRuleCompute, self).setUp()
181+
182+
self.app.client_manager.network_endpoint_enabled = False
183+
184+
# Build a security group fake customized for this test.
185+
security_group_rules = [self._security_group_rule._info]
186+
security_group = fakes.FakeResource(
187+
info=copy.deepcopy({'rules': security_group_rules}),
188+
loaded=True)
189+
security_group.rules = security_group_rules
190+
self.compute.security_groups.list.return_value = [security_group]
191+
192+
# Get the command object to test
193+
self.cmd = security_group_rule.ShowSecurityGroupRule(self.app, None)
194+
195+
def test_show_no_options(self):
196+
self.assertRaises(tests_utils.ParserException,
197+
self.check_parser, self.cmd, [], [])
198+
199+
def test_show_all_options(self):
200+
arglist = [
201+
self._security_group_rule.id,
202+
]
203+
verifylist = [
204+
('rule', self._security_group_rule.id),
205+
]
206+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
207+
208+
columns, data = self.cmd.take_action(parsed_args)
209+
210+
self.compute.security_groups.list.assert_called_with()
211+
self.assertEqual(self.columns, columns)
212+
self.assertEqual(self.data, data)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
features:
3+
- |
4+
Add support for ``security group rule show`` command.
5+
[Bug `1519512 <https://bugs.launchpad.net/bugs/1519512>`_]

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ openstack.network.v2 =
340340
router_show = openstackclient.network.v2.router:ShowRouter
341341
security_group_delete = openstackclient.network.v2.security_group:DeleteSecurityGroup
342342
security_group_rule_delete = openstackclient.network.v2.security_group_rule:DeleteSecurityGroupRule
343+
security_group_rule_show = openstackclient.network.v2.security_group_rule:ShowSecurityGroupRule
343344
subnet_list = openstackclient.network.v2.subnet:ListSubnet
344345
subnet_show = openstackclient.network.v2.subnet:ShowSubnet
345346
subnet_pool_delete = openstackclient.network.v2.subnet_pool:DeleteSubnetPool

0 commit comments

Comments
 (0)