diff --git a/tacker/api/views/vnf_lcm.py b/tacker/api/views/vnf_lcm.py index d23a1cac7..83cbdb692 100644 --- a/tacker/api/views/vnf_lcm.py +++ b/tacker/api/views/vnf_lcm.py @@ -69,3 +69,7 @@ class ViewBuilder(object): def show(self, vnf_instance): return self._get_vnf_instance_info(vnf_instance) + + def index(self, vnf_instances): + return [self._get_vnf_instance_info(vnf_instance) + for vnf_instance in vnf_instances] diff --git a/tacker/api/vnflcm/v1/controller.py b/tacker/api/vnflcm/v1/controller.py index fe9bf5437..411cf940b 100644 --- a/tacker/api/vnflcm/v1/controller.py +++ b/tacker/api/vnflcm/v1/controller.py @@ -202,8 +202,12 @@ class VnfLcmController(wsgi.Controller): return self._view_builder.show(vnf_instance) + @wsgi.response(http_client.OK) + @wsgi.expected_errors((http_client.FORBIDDEN)) def index(self, request): - raise webob.exc.HTTPNotImplemented() + context = request.environ['tacker.context'] + vnf_instances = objects.VnfInstanceList.get_all(context) + return self._view_builder.index(vnf_instances) def delete(self, request, id): raise webob.exc.HTTPNotImplemented() diff --git a/tacker/policies/vnf_lcm.py b/tacker/policies/vnf_lcm.py index 4ccb26c43..411a30895 100644 --- a/tacker/policies/vnf_lcm.py +++ b/tacker/policies/vnf_lcm.py @@ -76,7 +76,18 @@ rules = [ 'path': '/vnflcm/v1/vnf_instances/{vnfInstanceId}/heal' } ] - ) + ), + policy.DocumentedRuleDefault( + name=VNFLCM % 'index', + check_str=base.RULE_ADMIN_OR_OWNER, + description="Query VNF instances.", + operations=[ + { + 'method': 'GET', + 'path': '/vnflcm/v1/vnf_instances' + } + ] + ), ] diff --git a/tacker/tests/unit/vnflcm/test_controller.py b/tacker/tests/unit/vnflcm/test_controller.py index d38785160..4a84ef51f 100644 --- a/tacker/tests/unit/vnflcm/test_controller.py +++ b/tacker/tests/unit/vnflcm/test_controller.py @@ -972,3 +972,35 @@ class TestController(base.TestCase): expected_type=expected_type)) self.assertEqual(expected_message, exception.msg) + + @mock.patch.object(objects.VnfInstanceList, "get_all") + def test_index(self, mock_vnf_list): + req = fake_request.HTTPRequest.blank('/vnf_instances') + vnf_instance_1 = fakes.return_vnf_instance() + vnf_instance_2 = fakes.return_vnf_instance( + fields.VnfInstanceState.INSTANTIATED) + + mock_vnf_list.return_value = [vnf_instance_1, vnf_instance_2] + resp = self.controller.index(req) + expected_result = [fakes.fake_vnf_instance_response(), + fakes.fake_vnf_instance_response( + fields.VnfInstanceState.INSTANTIATED)] + self.assertEqual(expected_result, resp) + + @mock.patch.object(objects.VnfInstanceList, "get_all") + def test_index_empty_response(self, mock_vnf_list): + req = fake_request.HTTPRequest.blank('/vnf_instances') + + mock_vnf_list.return_value = [] + resp = self.controller.index(req) + self.assertEqual([], resp) + + @ddt.data('HEAD', 'PUT', 'DELETE', 'PATCH') + def test_index_invalid_http_method(self, method): + # Wrong HTTP method + req = fake_request.HTTPRequest.blank( + '/vnf_instances') + req.headers['Content-Type'] = 'application/json' + req.method = method + resp = req.get_response(self.app) + self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code) diff --git a/tacker/wsgi.py b/tacker/wsgi.py index 0981c3ce3..9209ae9a6 100644 --- a/tacker/wsgi.py +++ b/tacker/wsgi.py @@ -1043,8 +1043,8 @@ class Resource(Application): if not response: resp_obj = None - if isinstance(action_result, (dict, str)) \ - or action_result is None: + if (isinstance(action_result, (dict, list, str)) or + action_result is None): resp_obj = ResponseObject(action_result) elif isinstance(action_result, ResponseObject): resp_obj = action_result