Display subnet cidr information in net-list

Fixes bug 1074415

This commit introduces extend_list() in ListCommand class. This method
can be used to update a retrieved list (e.g., add additional information
or convert some field to more human-readable value).

Change-Id: Icf5ab616ab4d9add16c921e1944ba37b376b2ab2
This commit is contained in:
Akihiro MOTOKI 2013-01-10 03:22:14 +09:00
parent 093bac1bc6
commit ab5399e64d
3 changed files with 127 additions and 28 deletions
quantumclient

@ -341,7 +341,7 @@ class DeleteCommand(QuantumCommand):
class ListCommand(QuantumCommand, lister.Lister):
"""List resourcs that belong to a given tenant
"""List resources that belong to a given tenant
"""
@ -357,11 +357,10 @@ class ListCommand(QuantumCommand, lister.Lister):
add_extra_argument(parser, 'filter_specs', 'filters options')
return parser
def get_data(self, parsed_args):
self.log.debug('get_data(%s)' % parsed_args)
def retrieve_list(self, parsed_args):
"""Retrieve a list of resources from Quantum server"""
quantum_client = self.get_client()
search_opts = parse_args_to_dict(parsed_args.filter_specs)
self.log.debug('search options: %s', search_opts)
quantum_client.format = parsed_args.request_format
fields = parsed_args.fields
@ -377,12 +376,21 @@ class ListCommand(QuantumCommand, lister.Lister):
search_opts.update({'verbose': 'True'})
obj_lister = getattr(quantum_client,
"list_%ss" % self.resource)
data = obj_lister(**search_opts)
info = []
collection = self.resource + "s"
if collection in data:
info = data[collection]
return data.get(collection, [])
def extend_list(self, data, parsed_args):
"""Update a retrieved list.
This method provides a way to modify a original list returned from
the quantum server. For example, you can add subnet cidr information
to a list network.
"""
pass
def setup_columns(self, info, parsed_args):
_columns = len(info) > 0 and sorted(info[0].keys()) or []
if not _columns:
# clean the parsed_args.columns so that cliff will not break
@ -398,6 +406,12 @@ class ListCommand(QuantumCommand, lister.Lister):
s, _columns, formatters=self._formatters, )
for s in info), )
def get_data(self, parsed_args):
self.log.debug('get_data(%s)' % parsed_args)
data = self.retrieve_list(parsed_args)
self.extend_list(data, parsed_args)
return self.setup_columns(data, parsed_args)
class ShowCommand(QuantumCommand, show.ShowOne):
"""Show information of a given resource

@ -18,6 +18,7 @@
import argparse
import logging
from quantumclient.common import utils
from quantumclient.quantum.v2_0 import CreateCommand
from quantumclient.quantum.v2_0 import DeleteCommand
from quantumclient.quantum.v2_0 import ListCommand
@ -27,7 +28,8 @@ from quantumclient.quantum.v2_0 import UpdateCommand
def _format_subnets(network):
try:
return '\n'.join(network['subnets'])
return '\n'.join([' '.join([s['id'], s.get('cidr', '')])
for s in network['subnets']])
except Exception:
return ''
@ -40,20 +42,28 @@ class ListNetwork(ListCommand):
_formatters = {'subnets': _format_subnets, }
list_columns = ['id', 'name', 'subnets']
def extend_list(self, data, parsed_args):
"""Add subnet information to a network list"""
quantum_client = self.get_client()
search_opts = {'fields': ['id', 'cidr']}
subnets = quantum_client.list_subnets(**search_opts).get('subnets', [])
subnet_dict = dict([(s['id'], s) for s in subnets])
for n in data:
if 'subnets' in n:
n['subnets'] = [(subnet_dict.get(s) or {"id": s})
for s in n['subnets']]
class ListExternalNetwork(ListCommand):
class ListExternalNetwork(ListNetwork):
"""List external networks that belong to a given tenant"""
resource = 'network'
log = logging.getLogger(__name__ + '.ListExternalNetwork')
_formatters = {'subnets': _format_subnets, }
list_colums = ['id', 'name', 'subnets']
def get_data(self, parsed_args):
def retrieve_list(self, parsed_args):
if '--' not in parsed_args.filter_specs:
parsed_args.filter_specs.append('--')
parsed_args.filter_specs.append('--router:external=True')
return super(ListExternalNetwork, self).get_data(parsed_args)
return super(ListExternalNetwork, self).retrieve_list(parsed_args)
class ShowNetwork(ShowCommand):

@ -17,7 +17,8 @@
import sys
from mox import ContainsKeyValue
import mox
from mox import (ContainsKeyValue, IgnoreArg, IsA)
from quantumclient.common import exceptions
from quantumclient.common import utils
@ -101,6 +102,8 @@ class CLITestV20Network(CLITestV20Base):
cmd = ListNetwork(MyApp(sys.stdout), None)
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
self.mox.StubOutWithMock(ListNetwork, "extend_list")
ListNetwork.extend_list(IsA(list), IgnoreArg())
cmd.get_client().MultipleTimes().AndReturn(self.client)
reses = {resources: []}
resstr = self.client.serialize(reses)
@ -125,40 +128,109 @@ class CLITestV20Network(CLITestV20Base):
_str = self.fake_stdout.make_string()
self.assertEquals('\n', _str)
def _test_list_networks(self, cmd, detail=False, tags=[],
fields_1=[], fields_2=[]):
resources = "networks"
self.mox.StubOutWithMock(ListNetwork, "extend_list")
ListNetwork.extend_list(IsA(list), IgnoreArg())
self._test_list_resources(resources, cmd, detail, tags,
fields_1, fields_2)
def test_list_nets_detail(self):
"""list nets: -D."""
resources = "networks"
cmd = ListNetwork(MyApp(sys.stdout), None)
self._test_list_resources(resources, cmd, True)
self._test_list_networks(cmd, True)
def test_list_nets_tags(self):
"""List nets: -- --tags a b."""
resources = "networks"
cmd = ListNetwork(MyApp(sys.stdout), None)
self._test_list_resources(resources, cmd, tags=['a', 'b'])
self._test_list_networks(cmd, tags=['a', 'b'])
def test_list_nets_detail_tags(self):
"""List nets: -D -- --tags a b."""
resources = "networks"
cmd = ListNetwork(MyApp(sys.stdout), None)
self._test_list_resources(resources, cmd, detail=True, tags=['a', 'b'])
self._test_list_networks(cmd, detail=True, tags=['a', 'b'])
def _test_list_nets_extend_subnets(self, data, expected):
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=ContainsKeyValue(
'X-Auth-Token', test_cli20.TOKEN)).AndReturn(resp)
resources = "networks"
cmd = ListNetwork(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)
setup_list_stub('networks', data, '')
cmd.get_client().AndReturn(self.client)
setup_list_stub('subnets',
[{'id': 'mysubid1', 'cidr': '192.168.1.0/24'},
{'id': 'mysubid2', 'cidr': '172.16.0.0/24'},
{'id': 'mysubid3', 'cidr': '10.1.1.0/24'}],
query='fields=id&fields=cidr')
self.mox.ReplayAll()
args = []
cmd_parser = cmd.get_parser('list_networks')
parsed_args = cmd_parser.parse_args(args)
result = cmd.get_data(parsed_args)
self.mox.VerifyAll()
self.mox.UnsetStubs()
_result = [x for x in result[1]]
self.assertEqual(len(_result), len(expected))
for res, exp in zip(_result, expected):
self.assertEqual(len(res), len(exp))
for a, b in zip(res, exp):
self.assertEqual(a, b)
def test_list_nets_extend_subnets(self):
data = [{'id': 'netid1', 'name': 'net1', 'subnets': ['mysubid1']},
{'id': 'netid2', 'name': 'net2', 'subnets': ['mysubid2',
'mysubid3']}]
# id, name, subnets
expected = [('netid1', 'net1', 'mysubid1 192.168.1.0/24'),
('netid2', 'net2',
'mysubid2 172.16.0.0/24\nmysubid3 10.1.1.0/24')]
self._test_list_nets_extend_subnets(data, expected)
def test_list_nets_extend_subnets_no_subnet(self):
data = [{'id': 'netid1', 'name': 'net1', 'subnets': ['mysubid1']},
{'id': 'netid2', 'name': 'net2', 'subnets': ['mysubid4']}]
# id, name, subnets
expected = [('netid1', 'net1', 'mysubid1 192.168.1.0/24'),
('netid2', 'net2', 'mysubid4 ')]
self._test_list_nets_extend_subnets(data, expected)
def test_list_nets_fields(self):
"""List nets: --fields a --fields b -- --fields c d."""
resources = "networks"
cmd = ListNetwork(MyApp(sys.stdout), None)
self._test_list_resources(resources, cmd,
fields_1=['a', 'b'], fields_2=['c', 'd'])
self._test_list_networks(cmd,
fields_1=['a', 'b'], fields_2=['c', 'd'])
def _test_list_nets_columns(self, cmd, returned_body,
args=['-f', 'json']):
resources = 'networks'
self.mox.StubOutWithMock(ListNetwork, "extend_list")
ListNetwork.extend_list(IsA(list), IgnoreArg())
self._test_list_columns(cmd, resources, returned_body, args=args)
def test_list_nets_defined_column(self):
resources = 'networks'
cmd = ListNetwork(MyApp(sys.stdout), None)
returned_body = {"networks": [{"name": "buildname3",
"id": "id3",
"tenant_id": "tenant_3",
"subnets": []}]}
self._test_list_columns(cmd, resources, returned_body,
args=['-f', 'json', '-c', 'id'])
self._test_list_nets_columns(cmd, returned_body,
args=['-f', 'json', '-c', 'id'])
_str = self.fake_stdout.make_string()
returned_networks = utils.loads(_str)
self.assertEquals(1, len(returned_networks))
@ -167,13 +239,12 @@ class CLITestV20Network(CLITestV20Base):
self.assertEquals("id", network.keys()[0])
def test_list_nets_with_default_column(self):
resources = 'networks'
cmd = ListNetwork(MyApp(sys.stdout), None)
returned_body = {"networks": [{"name": "buildname3",
"id": "id3",
"tenant_id": "tenant_3",
"subnets": []}]}
self._test_list_columns(cmd, resources, returned_body)
self._test_list_nets_columns(cmd, returned_body)
_str = self.fake_stdout.make_string()
returned_networks = utils.loads(_str)
self.assertEquals(1, len(returned_networks))
@ -187,6 +258,8 @@ class CLITestV20Network(CLITestV20Base):
cmd = ListExternalNetwork(MyApp(sys.stdout), None)
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
self.mox.StubOutWithMock(ListNetwork, "extend_list")
ListNetwork.extend_list(IsA(list), IgnoreArg())
cmd.get_client().MultipleTimes().AndReturn(self.client)
reses = {resources: []}
resstr = self.client.serialize(reses)
@ -217,6 +290,8 @@ class CLITestV20Network(CLITestV20Base):
fields_1=[], fields_2=[]):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
self.mox.StubOutWithMock(ListNetwork, "extend_list")
ListNetwork.extend_list(IsA(list), IgnoreArg())
cmd.get_client().MultipleTimes().AndReturn(self.client)
reses = {resources: [{'id': 'myid1', },
{'id': 'myid2', }, ], }