|
14 | 14 | """Security Group action implementations""" |
15 | 15 |
|
16 | 16 | import argparse |
| 17 | +import six |
17 | 18 |
|
18 | 19 | from openstackclient.common import utils |
19 | 20 | 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 |
20 | 92 |
|
21 | 93 |
|
22 | 94 | class DeleteSecurityGroup(common.NetworkAndComputeCommand): |
@@ -143,3 +215,39 @@ def take_action_compute(self, client, parsed_args): |
143 | 215 | data.name, |
144 | 216 | data.description, |
145 | 217 | ) |
| 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) |
0 commit comments