diff --git a/setup.cfg b/setup.cfg index 94edae2f..315c153a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -85,6 +85,7 @@ openstack.tackerclient.v1 = vnf_package_delete = tackerclient.osc.v1.vnfpkgm.vnf_package:DeleteVnfPackage vnflcm_create = tackerclient.osc.v1.vnflcm.vnflcm:CreateVnfLcm vnflcm_show = tackerclient.osc.v1.vnflcm.vnflcm:ShowVnfLcm + vnflcm_list = tackerclient.osc.v1.vnflcm.vnflcm:ListVnfLcm vnflcm_instantiate = tackerclient.osc.v1.vnflcm.vnflcm:InstantiateVnfLcm vnflcm_terminate = tackerclient.osc.v1.vnflcm.vnflcm:TerminateVnfLcm vnflcm_delete = tackerclient.osc.v1.vnflcm.vnflcm:DeleteVnfLcm diff --git a/tackerclient/osc/v1/vnflcm/vnflcm.py b/tackerclient/osc/v1/vnflcm/vnflcm.py index cfbad1a7..c8448aeb 100644 --- a/tackerclient/osc/v1/vnflcm/vnflcm.py +++ b/tackerclient/osc/v1/vnflcm/vnflcm.py @@ -25,6 +25,17 @@ from osc_lib import utils from tackerclient.common import exceptions from tackerclient.i18n import _ from tackerclient.osc import sdk_utils +from tackerclient.osc import utils as tacker_osc_utils + +_attr_map = ( + ('id', 'ID', tacker_osc_utils.LIST_BOTH), + ('vnfInstanceName', 'VNF Instance Name', tacker_osc_utils.LIST_BOTH), + ('instantiationState', 'Instantiation State', tacker_osc_utils.LIST_BOTH), + ('vnfProvider', 'VNF Provider', tacker_osc_utils.LIST_BOTH), + ('vnfSoftwareVersion', 'VNF Software Version', tacker_osc_utils.LIST_BOTH), + ('vnfProductName', 'VNF Product Name', tacker_osc_utils.LIST_BOTH), + ('vnfdId', 'VNFD ID', tacker_osc_utils.LIST_BOTH) +) LOG = logging.getLogger(__name__) @@ -149,6 +160,25 @@ class ShowVnfLcm(command.ShowOne): return (display_columns, data) +class ListVnfLcm(command.Lister): + _description = _("List VNF Instance") + + def get_parser(self, prog_name): + parser = super(ListVnfLcm, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + _params = {} + client = self.app.client_manager.tackerclient + vnf_instances = client.list_vnf_instances(**_params) + headers, columns = tacker_osc_utils.get_column_definitions( + _attr_map, long_listing=True) + return (headers, + (utils.get_dict_properties( + s, columns, mixed_case_fields=_mixed_case_fields, + ) for s in vnf_instances)) + + def instantiate_vnf_args2body(file_path): if file_path is not None and os.access(file_path, os.R_OK) is False: diff --git a/tackerclient/tests/unit/osc/v1/test_vnflcm.py b/tackerclient/tests/unit/osc/v1/test_vnflcm.py index 753a3ccf..dbe060e0 100644 --- a/tackerclient/tests/unit/osc/v1/test_vnflcm.py +++ b/tackerclient/tests/unit/osc/v1/test_vnflcm.py @@ -23,6 +23,7 @@ from oslo_utils.fixture import uuidsentinel import six from tackerclient.common import exceptions +from tackerclient.osc import utils as tacker_osc_utils from tackerclient.osc.v1.vnflcm import vnflcm from tackerclient.tests.unit.osc import base from tackerclient.tests.unit.osc.v1.fixture_data import client @@ -49,6 +50,10 @@ def _get_columns_vnflcm(action='create'): 'VNF Software Version', 'VNFD ID', 'VNFD Version', 'Links'] if action == 'show': columns.extend(['Instantiated Vnf Info', 'VIM Connection Info']) + if action == 'list': + columns = [ele for ele in columns if ele not in + ['VNFD Version', 'VNF Instance Description']] + columns.remove('Links') return columns @@ -142,6 +147,35 @@ class TestShowVnfLcm(TestVnfLcm): columns) +class TestListVnfLcm(TestVnfLcm): + + vnf_instances = vnflcm_fakes.create_vnf_instances(count=3) + + def setUp(self): + super(TestListVnfLcm, self).setUp() + self.list_vnf_instance = vnflcm.ListVnfLcm( + self.app, self.app_args, cmd_name='vnflcm list') + + def test_take_action(self): + parsed_args = self.check_parser(self.list_vnf_instance, [], []) + self.requests_mock.register_uri( + 'GET', os.path.join(self.url, 'vnflcm/v1/vnf_instances'), + json=self.vnf_instances, headers=self.header) + actual_columns, data = self.list_vnf_instance.take_action(parsed_args) + + headers, columns = tacker_osc_utils.get_column_definitions( + vnflcm._attr_map, long_listing=True) + + expected_data = [] + for vnf_instance_obj in self.vnf_instances: + expected_data.append(vnflcm_fakes.get_vnflcm_data( + vnf_instance_obj, columns=columns, list_action=True)) + + self.assertItemsEqual(_get_columns_vnflcm(action='list'), + actual_columns) + self.assertItemsEqual(expected_data, list(data)) + + class TestInstantiateVnfLcm(TestVnfLcm): def setUp(self): diff --git a/tackerclient/tests/unit/osc/v1/vnflcm_fakes.py b/tackerclient/tests/unit/osc/v1/vnflcm_fakes.py index 1a6d7060..02a76172 100644 --- a/tackerclient/tests/unit/osc/v1/vnflcm_fakes.py +++ b/tackerclient/tests/unit/osc/v1/vnflcm_fakes.py @@ -111,13 +111,21 @@ def vnf_instance_response(attrs=None, instantiation_state='NOT_INSTANTIATED'): return dummy_vnf_instance -def get_vnflcm_data(vnf_instance): +def get_vnflcm_data(vnf_instance, list_action=False, columns=None): """Get the vnf instance data. :return: A tuple object sorted based on the name of the columns. """ + + if list_action: + for item in ['vnfInstanceDescription', 'vnfdVersion']: + vnf_instance.pop(item) + # return the list of data as per column order + if columns: + return tuple([vnf_instance[key] for key in columns]) + return tuple([vnf_instance[key] for key in sorted(vnf_instance.keys())]) diff --git a/tackerclient/v1_0/client.py b/tackerclient/v1_0/client.py index d71854b3..6e84ca06 100644 --- a/tackerclient/v1_0/client.py +++ b/tackerclient/v1_0/client.py @@ -317,8 +317,11 @@ class ClientBase(object): if retrieve_all: res = [] for r in self._pagination(collection, path, **params): - res.extend(r[collection]) - return {collection: res} + if type(r) is list: + res.extend(r) + else: + res.extend(r[collection]) + return {collection: res} if collection else res else: return self._pagination(collection, path, **params) @@ -333,6 +336,11 @@ class ClientBase(object): yield res next = False try: + # TODO(tpatil): Handle pagination for list data type + # once it's supported by tacker. + if type(res) is list: + break + for link in res['%s_links' % collection]: if link['rel'] == linkrel: query_str = urlparse.urlparse(link['href']).query @@ -795,6 +803,12 @@ class VnfLCMClient(ClientBase): def show_vnf_instance(self, vnf_id, **_params): return self.get(self.vnf_instance_path % vnf_id, params=_params) + @APIParamsCall + def list_vnf_instances(self, retrieve_all=True, **_params): + vnf_instances = self.list(None, self.vnf_instances_path, + retrieve_all, **_params) + return vnf_instances + @APIParamsCall def instantiate_vnf_instance(self, vnf_id, body): return self.post((self.vnf_instance_path + "/instantiate") % vnf_id, @@ -1065,6 +1079,10 @@ class Client(object): return self.vnf_lcm_client.show_vnf_instance(vnf_instance, **_params) + def list_vnf_instances(self, retrieve_all=True, **_params): + return self.vnf_lcm_client.list_vnf_instances( + retrieve_all=retrieve_all, **_params) + def instantiate_vnf_instance(self, vnf_id, body): return self.vnf_lcm_client.instantiate_vnf_instance(vnf_id, body)