From 4d7c6b6ec7c9e3afbc238f70f09dda4274941217 Mon Sep 17 00:00:00 2001 From: Akihiro MOTOKI Date: Fri, 14 Dec 2012 21:20:45 +0900 Subject: [PATCH] Display security group name in security-group-rule-list It is useful to display security group name rather than its id for security_group_id and source_group_id. Also add '--no-nameconv' option to disable conversion from security group id to its name. When security-group-rule-list is executed by admin user it is likely more than one groups have same name. This option is useful for such cases. Change-Id: I7fd0f1fb26fce8ed24e0f710666866607e681bc8 --- quantumclient/quantum/v2_0/securitygroup.py | 49 +++++++++ .../tests/unit/test_cli20_securitygroup.py | 100 ++++++++++++++++++ 2 files changed, 149 insertions(+) diff --git a/quantumclient/quantum/v2_0/securitygroup.py b/quantumclient/quantum/v2_0/securitygroup.py index ffbd2ae05..9442cccda 100644 --- a/quantumclient/quantum/v2_0/securitygroup.py +++ b/quantumclient/quantum/v2_0/securitygroup.py @@ -79,6 +79,55 @@ class ListSecurityGroupRule(quantumv20.ListCommand): _formatters = {} list_columns = ['id', 'security_group_id', 'direction', 'protocol', 'source_ip_prefix', 'source_group_id'] + replace_rules = {'security_group_id': 'security_group', + 'source_group_id': 'source_group'} + + def get_parser(self, prog_name): + parser = super(ListSecurityGroupRule, self).get_parser(prog_name) + parser.add_argument( + '--no-nameconv', action='store_true', + help='Do not convert security group ID to its name') + return parser + + @staticmethod + def replace_columns(cols, rules, reverse=False): + if reverse: + rules = dict((rules[k], k) for k in rules.keys()) + return [rules.get(col, col) for col in cols] + + def retrieve_list(self, parsed_args): + parsed_args.fields = self.replace_columns(parsed_args.fields, + self.replace_rules, + reverse=True) + return super(ListSecurityGroupRule, self).retrieve_list(parsed_args) + + def extend_list(self, data, parsed_args): + if parsed_args.no_nameconv: + return + quantum_client = self.get_client() + search_opts = {'fields': ['id', 'name']} + secgroups = quantum_client.list_security_groups(**search_opts) + secgroups = secgroups.get('security_groups', []) + sg_dict = dict([(sg['id'], sg['name']) + for sg in secgroups if sg['name']]) + for rule in data: + for key in self.replace_rules: + rule[key] = sg_dict.get(rule[key], rule[key]) + + def setup_columns(self, info, parsed_args): + parsed_args.columns = self.replace_columns(parsed_args.columns, + self.replace_rules, + reverse=True) + # NOTE(amotoki): 2nd element of the tuple returned by setup_columns() + # is a generator, so if you need to create a look using the generator + # object, you need to recreate a generator to show a list expectedly. + info = super(ListSecurityGroupRule, self).setup_columns(info, + parsed_args) + cols = info[0] + if not parsed_args.no_nameconv: + cols = self.replace_columns(info[0], self.replace_rules) + parsed_args.columns = cols + return (cols, info[1]) class ShowSecurityGroupRule(quantumv20.ShowCommand): diff --git a/quantumclient/tests/unit/test_cli20_securitygroup.py b/quantumclient/tests/unit/test_cli20_securitygroup.py index c5fcf5fc1..d1dd08547 100644 --- a/quantumclient/tests/unit/test_cli20_securitygroup.py +++ b/quantumclient/tests/unit/test_cli20_securitygroup.py @@ -18,6 +18,8 @@ import sys +import mox + from quantumclient.quantum.v2_0 import securitygroup from quantumclient.tests.unit import test_cli20 @@ -137,6 +139,10 @@ class CLITestV20SecurityGroups(test_cli20.CLITestV20Base): resources = "security_group_rules" cmd = securitygroup.ListSecurityGroupRule( test_cli20.MyApp(sys.stdout), None) + self.mox.StubOutWithMock(securitygroup.ListSecurityGroupRule, + "extend_list") + securitygroup.ListSecurityGroupRule.extend_list(mox.IsA(list), + mox.IgnoreArg()) self._test_list_resources(resources, cmd, True) def test_show_security_group_rule(self): @@ -146,3 +152,97 @@ class CLITestV20SecurityGroups(test_cli20.CLITestV20Base): args = ['--fields', 'id', self.test_id] self._test_show_resource(resource, cmd, self.test_id, args, ['id']) + + def _test_list_security_group_rules_extend(self, data=None, expected=None, + args=[], conv=True, + query_field=False): + def setup_list_stub(resources, data, query): + reses = {resources: data} + resstr = self.client.serialize(reses) + resp = (test_cli20.MyResp(200), resstr) + path = getattr(self.client, resources + '_path') + self.client.httpclient.request( + test_cli20.end_url(path, query), 'GET', + body=None, + headers=mox.ContainsKeyValue( + 'X-Auth-Token', test_cli20.TOKEN)).AndReturn(resp) + + # Setup the default data + _data = {'cols': ['id', 'security_group_id', 'source_group_id'], + 'data': [('ruleid1', 'myid1', 'myid1'), + ('ruleid2', 'myid2', 'myid3'), + ('ruleid3', 'myid2', 'myid2')]} + _expected = {'cols': ['id', 'security_group', 'source_group'], + 'data': [('ruleid1', 'group1', 'group1'), + ('ruleid2', 'group2', 'group3'), + ('ruleid3', 'group2', 'group2')]} + if data is None: + data = _data + list_data = [dict(zip(data['cols'], d)) for d in data['data']] + if expected is None: + expected = {} + expected['cols'] = expected.get('cols', _expected['cols']) + expected['data'] = expected.get('data', _expected['data']) + + resources = "security_group_rules" + cmd = securitygroup.ListSecurityGroupRule( + test_cli20.MyApp(sys.stdout), None) + self.mox.StubOutWithMock(cmd, 'get_client') + self.mox.StubOutWithMock(self.client.httpclient, 'request') + cmd.get_client().AndReturn(self.client) + query = '' + if query_field: + query = '&'.join(['fields=' + f for f in data['cols']]) + setup_list_stub('security_group_rules', list_data, query) + if conv: + cmd.get_client().AndReturn(self.client) + setup_list_stub('security_groups', + [{'id': 'myid1', 'name': 'group1'}, + {'id': 'myid2', 'name': 'group2'}, + {'id': 'myid3', 'name': 'group3'}], + query='fields=id&fields=name') + self.mox.ReplayAll() + + cmd_parser = cmd.get_parser('list_security_group_rules') + parsed_args = cmd_parser.parse_args(args) + result = cmd.get_data(parsed_args) + self.mox.VerifyAll() + self.mox.UnsetStubs() + # Check columns + self.assertEqual(result[0], expected['cols']) + # Check data + _result = [x for x in result[1]] + self.assertEqual(len(_result), len(expected['data'])) + for res, exp in zip(_result, expected['data']): + self.assertEqual(len(res), len(exp)) + self.assertEqual(res, exp) + + def test_list_security_group_rules_extend_source_id(self): + self._test_list_security_group_rules_extend() + + def test_list_security_group_rules_extend_no_nameconv(self): + expected = {'cols': ['id', 'security_group_id', 'source_group_id'], + 'data': [('ruleid1', 'myid1', 'myid1'), + ('ruleid2', 'myid2', 'myid3'), + ('ruleid3', 'myid2', 'myid2')]} + args = ['--no-nameconv'] + self._test_list_security_group_rules_extend(expected=expected, + args=args, conv=False) + + def test_list_security_group_rules_extend_with_columns(self): + args = '-c id -c security_group_id -c source_group_id'.split() + self._test_list_security_group_rules_extend(args=args) + + def test_list_security_group_rules_extend_with_columns_no_id(self): + args = '-c id -c security_group -c source_group'.split() + self._test_list_security_group_rules_extend(args=args) + + def test_list_security_group_rules_extend_with_fields(self): + args = '-F id -F security_group_id -F source_group_id'.split() + self._test_list_security_group_rules_extend(args=args, + query_field=True) + + def test_list_security_group_rules_extend_with_fields_no_id(self): + args = '-F id -F security_group -F source_group'.split() + self._test_list_security_group_rules_extend(args=args, + query_field=True)