Skip to content

Commit 564c8ff

Browse files
committed
Refactor security group show to use SDK
Refactored the 'os security group show' command to use the SDK when neutron is enabled, but continue to use the nova client when nova network is enabled. Added a release note for the change in security group rules output due to Network v2. The column names remain unchanged to maintain backwards compatibility. Change-Id: I25233ddb8115d18b8b88affb3de13346084a339d Partial-Bug: #1519511 Implements: blueprint neutron-client
1 parent f8ac17a commit 564c8ff

9 files changed

Lines changed: 310 additions & 93 deletions

File tree

openstackclient/compute/v2/security_group.py

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,6 @@ def _xform_security_group_rule(sgroup):
5656
return info
5757

5858

59-
def _xform_and_trim_security_group_rule(sgroup):
60-
info = _xform_security_group_rule(sgroup)
61-
# Trim parent security group ID since caller has this information.
62-
info.pop('parent_group_id', None)
63-
# Trim keys with empty string values.
64-
keys_to_trim = [
65-
'ip_protocol',
66-
'ip_range',
67-
'port_range',
68-
'remote_security_group',
69-
]
70-
for key in keys_to_trim:
71-
if key in info and not info[key]:
72-
info.pop(key)
73-
return info
74-
75-
7659
class CreateSecurityGroup(command.ShowOne):
7760
"""Create a new security group"""
7861

@@ -215,40 +198,3 @@ def take_action(self, parsed_args):
215198
(utils.get_item_properties(
216199
s, columns,
217200
) for s in rules))
218-
219-
220-
class ShowSecurityGroup(command.ShowOne):
221-
"""Display security group details"""
222-
223-
def get_parser(self, prog_name):
224-
parser = super(ShowSecurityGroup, self).get_parser(prog_name)
225-
parser.add_argument(
226-
'group',
227-
metavar='<group>',
228-
help='Security group to display (name or ID)',
229-
)
230-
return parser
231-
232-
def take_action(self, parsed_args):
233-
234-
compute_client = self.app.client_manager.compute
235-
info = {}
236-
info.update(utils.find_resource(
237-
compute_client.security_groups,
238-
parsed_args.group,
239-
)._info)
240-
rules = []
241-
for r in info['rules']:
242-
formatted_rule = _xform_and_trim_security_group_rule(r)
243-
rules.append(utils.format_dict(formatted_rule))
244-
245-
# Format rules into a list of strings
246-
info.update(
247-
{'rules': utils.format_list(rules, separator='\n')}
248-
)
249-
# Map 'tenant_id' column to 'project_id'
250-
info.update(
251-
{'project_id': info.pop('tenant_id')}
252-
)
253-
254-
return zip(*sorted(six.iteritems(info)))

openstackclient/network/utils.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
15+
# Transform compute security group rule for display.
16+
def transform_compute_security_group_rule(sg_rule):
17+
info = {}
18+
info.update(sg_rule)
19+
from_port = info.pop('from_port')
20+
to_port = info.pop('to_port')
21+
if isinstance(from_port, int) and isinstance(to_port, int):
22+
port_range = {'port_range': "%u:%u" % (from_port, to_port)}
23+
elif from_port is None and to_port is None:
24+
port_range = {'port_range': ""}
25+
else:
26+
port_range = {'port_range': "%s:%s" % (from_port, to_port)}
27+
info.update(port_range)
28+
if 'cidr' in info['ip_range']:
29+
info['ip_range'] = info['ip_range']['cidr']
30+
else:
31+
info['ip_range'] = ''
32+
if info['ip_protocol'] is None:
33+
info['ip_protocol'] = ''
34+
elif info['ip_protocol'].lower() == 'icmp':
35+
info['port_range'] = ''
36+
group = info.pop('group')
37+
if 'name' in group:
38+
info['remote_security_group'] = group['name']
39+
else:
40+
info['remote_security_group'] = ''
41+
return info

openstackclient/network/v2/security_group.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,81 @@
1414
"""Security Group action implementations"""
1515

1616
import argparse
17+
import six
1718

1819
from openstackclient.common import utils
1920
from openstackclient.network import common
21+
from openstackclient.network import utils as network_utils
22+
23+
24+
def _format_network_security_group_rules(sg_rules):
25+
# For readability and to align with formatting compute security group
26+
# rules, trim keys with caller known (e.g. security group and tenant ID)
27+
# or empty values.
28+
for sg_rule in sg_rules:
29+
empty_keys = [k for k, v in six.iteritems(sg_rule) if not v]
30+
for key in empty_keys:
31+
sg_rule.pop(key)
32+
sg_rule.pop('security_group_id', None)
33+
sg_rule.pop('tenant_id', None)
34+
return utils.format_list_of_dicts(sg_rules)
35+
36+
37+
def _format_compute_security_group_rule(sg_rule):
38+
info = network_utils.transform_compute_security_group_rule(sg_rule)
39+
# Trim parent security group ID since caller has this information.
40+
info.pop('parent_group_id', None)
41+
# Trim keys with empty string values.
42+
keys_to_trim = [
43+
'ip_protocol',
44+
'ip_range',
45+
'port_range',
46+
'remote_security_group',
47+
]
48+
for key in keys_to_trim:
49+
if key in info and not info[key]:
50+
info.pop(key)
51+
return utils.format_dict(info)
52+
53+
54+
def _format_compute_security_group_rules(sg_rules):
55+
rules = []
56+
for sg_rule in sg_rules:
57+
rules.append(_format_compute_security_group_rule(sg_rule))
58+
return utils.format_list(rules, separator='\n')
59+
60+
61+
_formatters_network = {
62+
'security_group_rules': _format_network_security_group_rules,
63+
}
64+
65+
66+
_formatters_compute = {
67+
'rules': _format_compute_security_group_rules,
68+
}
69+
70+
71+
def _get_columns(item):
72+
# Build the display columns and a list of the property columns
73+
# that need to be mapped (display column name, property name).
74+
columns = list(item.keys())
75+
property_column_mappings = []
76+
if 'security_group_rules' in columns:
77+
columns.append('rules')
78+
columns.remove('security_group_rules')
79+
property_column_mappings.append(('rules', 'security_group_rules'))
80+
if 'tenant_id' in columns:
81+
columns.append('project_id')
82+
columns.remove('tenant_id')
83+
property_column_mappings.append(('project_id', 'tenant_id'))
84+
display_columns = sorted(columns)
85+
86+
# Build the property columns and apply any column mappings.
87+
property_columns = sorted(columns)
88+
for property_column_mapping in property_column_mappings:
89+
property_index = property_columns.index(property_column_mapping[0])
90+
property_columns[property_index] = property_column_mapping[1]
91+
return tuple(display_columns), property_columns
2092

2193

2294
class DeleteSecurityGroup(common.NetworkAndComputeCommand):
@@ -143,3 +215,39 @@ def take_action_compute(self, client, parsed_args):
143215
data.name,
144216
data.description,
145217
)
218+
219+
220+
class ShowSecurityGroup(common.NetworkAndComputeShowOne):
221+
"""Display security group details"""
222+
223+
def update_parser_common(self, parser):
224+
parser.add_argument(
225+
'group',
226+
metavar='<group>',
227+
help='Security group to display (name or ID)',
228+
)
229+
return parser
230+
231+
def take_action_network(self, client, parsed_args):
232+
obj = client.find_security_group(parsed_args.group,
233+
ignore_missing=False)
234+
display_columns, property_columns = _get_columns(obj)
235+
data = utils.get_item_properties(
236+
obj,
237+
property_columns,
238+
formatters=_formatters_network
239+
)
240+
return (display_columns, data)
241+
242+
def take_action_compute(self, client, parsed_args):
243+
obj = utils.find_resource(
244+
client.security_groups,
245+
parsed_args.group,
246+
)
247+
display_columns, property_columns = _get_columns(obj._info)
248+
data = utils.get_dict_properties(
249+
obj._info,
250+
property_columns,
251+
formatters=_formatters_compute
252+
)
253+
return (display_columns, data)

openstackclient/network/v2/security_group_rule.py

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,11 @@
1818
from openstackclient.common import exceptions
1919
from openstackclient.common import utils
2020
from openstackclient.network import common
21-
22-
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
21+
from openstackclient.network import utils as network_utils
4922

5023

5124
def _format_security_group_rule_show(obj):
52-
data = _xform_security_group_rule(obj)
25+
data = network_utils.transform_compute_security_group_rule(obj)
5326
return zip(*sorted(six.iteritems(data)))
5427

5528

openstackclient/tests/compute/v2/fakes.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@ def create_one_security_group(attrs=None, methods=None):
333333
security_group_attrs.update(attrs)
334334

335335
# Set default methods.
336-
security_group_methods = {}
336+
security_group_methods = {
337+
'keys': ['id', 'name', 'description', 'tenant_id', 'rules'],
338+
}
337339

338340
# Overwrite default methods.
339341
security_group_methods.update(methods)
@@ -369,7 +371,7 @@ class FakeSecurityGroupRule(object):
369371
"""Fake one or more security group rules."""
370372

371373
@staticmethod
372-
def create_one_security_group_rule(attrs={}, methods={}):
374+
def create_one_security_group_rule(attrs=None, methods=None):
373375
"""Create a fake security group rule.
374376
375377
:param Dictionary attrs:
@@ -379,6 +381,11 @@ def create_one_security_group_rule(attrs={}, methods={}):
379381
:return:
380382
A FakeResource object, with id, etc.
381383
"""
384+
if attrs is None:
385+
attrs = {}
386+
if methods is None:
387+
methods = {}
388+
382389
# Set default attributes.
383390
security_group_rule_attrs = {
384391
'from_port': -1,
@@ -406,7 +413,7 @@ def create_one_security_group_rule(attrs={}, methods={}):
406413
return security_group_rule
407414

408415
@staticmethod
409-
def create_security_group_rules(attrs={}, methods={}, count=2):
416+
def create_security_group_rules(attrs=None, methods=None, count=2):
410417
"""Create multiple fake security group rules.
411418
412419
:param Dictionary attrs:

openstackclient/tests/network/v2/fakes.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ class FakeSecurityGroup(object):
419419
"""Fake one or more security groups."""
420420

421421
@staticmethod
422-
def create_one_security_group(attrs={}, methods={}):
422+
def create_one_security_group(attrs=None, methods=None):
423423
"""Create a fake security group.
424424
425425
:param Dictionary attrs:
@@ -429,6 +429,11 @@ def create_one_security_group(attrs={}, methods={}):
429429
:return:
430430
A FakeResource object, with id, name, etc.
431431
"""
432+
if attrs is None:
433+
attrs = {}
434+
if methods is None:
435+
methods = {}
436+
432437
# Set default attributes.
433438
security_group_attrs = {
434439
'id': 'security-group-id-' + uuid.uuid4().hex,
@@ -442,7 +447,10 @@ def create_one_security_group(attrs={}, methods={}):
442447
security_group_attrs.update(attrs)
443448

444449
# Set default methods.
445-
security_group_methods = {}
450+
security_group_methods = {
451+
'keys': ['id', 'name', 'description', 'tenant_id',
452+
'security_group_rules'],
453+
}
446454

447455
# Overwrite default methods.
448456
security_group_methods.update(methods)
@@ -451,10 +459,14 @@ def create_one_security_group(attrs={}, methods={}):
451459
info=copy.deepcopy(security_group_attrs),
452460
methods=copy.deepcopy(security_group_methods),
453461
loaded=True)
462+
463+
# Set attributes with special mapping in OpenStack SDK.
464+
security_group.project_id = security_group_attrs['tenant_id']
465+
454466
return security_group
455467

456468
@staticmethod
457-
def create_security_groups(attrs={}, methods={}, count=2):
469+
def create_security_groups(attrs=None, methods=None, count=2):
458470
"""Create multiple fake security groups.
459471
460472
:param Dictionary attrs:
@@ -478,7 +490,7 @@ class FakeSecurityGroupRule(object):
478490
"""Fake one or more security group rules."""
479491

480492
@staticmethod
481-
def create_one_security_group_rule(attrs={}, methods={}):
493+
def create_one_security_group_rule(attrs=None, methods=None):
482494
"""Create a fake security group rule.
483495
484496
:param Dictionary attrs:
@@ -488,6 +500,11 @@ def create_one_security_group_rule(attrs={}, methods={}):
488500
:return:
489501
A FakeResource object, with id, etc.
490502
"""
503+
if attrs is None:
504+
attrs = {}
505+
if methods is None:
506+
methods = {}
507+
491508
# Set default attributes.
492509
security_group_rule_attrs = {
493510
'direction': 'ingress',
@@ -520,13 +537,13 @@ def create_one_security_group_rule(attrs={}, methods={}):
520537
methods=copy.deepcopy(security_group_rule_methods),
521538
loaded=True)
522539

523-
# Set attributes with special mappings.
540+
# Set attributes with special mapping in OpenStack SDK.
524541
security_group_rule.project_id = security_group_rule_attrs['tenant_id']
525542

526543
return security_group_rule
527544

528545
@staticmethod
529-
def create_security_group_rules(attrs={}, methods={}, count=2):
546+
def create_security_group_rules(attrs=None, methods=None, count=2):
530547
"""Create multiple fake security group rules.
531548
532549
:param Dictionary attrs:

0 commit comments

Comments
 (0)