From fc6f076c2a857062e0aad6d7349a8f0170bbb42b Mon Sep 17 00:00:00 2001 From: dongwenjuan Date: Wed, 19 Apr 2017 17:59:10 +0800 Subject: [PATCH] add resource show API Implement: blueprint resource-show-API Change-Id: If888554105e28726b721a7d881a25ff87607435b Signed-off-by: dongwenjuan --- vitrage/api/controllers/v1/resource.py | 35 ++++++- vitrage/api_handler/apis/resource.py | 21 ++++ .../tests/functional/api_handler/test_apis.py | 99 +++++++++++++++++++ .../tests/api/resources/test_resources.py | 43 +++++++- 4 files changed, 193 insertions(+), 5 deletions(-) diff --git a/vitrage/api/controllers/v1/resource.py b/vitrage/api/controllers/v1/resource.py index e6942a0ee..446b3f9e4 100644 --- a/vitrage/api/controllers/v1/resource.py +++ b/vitrage/api/controllers/v1/resource.py @@ -25,7 +25,7 @@ LOG = log.getLogger(__name__) class ResourcesController(RootRestController): @pecan.expose('json') - def get(self, **kwargs): + def get_all(self, **kwargs): LOG.info('get list resource with args: %s', kwargs) resource_type = kwargs.get('resource_type', None) @@ -43,7 +43,7 @@ class ResourcesController(RootRestController): try: return self._get_resources(resource_type, all_tenants) except Exception as e: - LOG.exception('failed to get resources %s', e) + LOG.exception('failed to list resources %s', e) abort(404, str(e)) @staticmethod @@ -62,3 +62,34 @@ class ResourcesController(RootRestController): except Exception as e: LOG.exception('failed to get resources %s ', e) abort(404, str(e)) + + @pecan.expose('json') + def get(self, vitrage_id): + + LOG.info('get resource show with vitrage_id: %s', vitrage_id) + + enforce("get resource", + pecan.request.headers, + pecan.request.enforcer, + {}) + + try: + return self._show_resource(vitrage_id) + except Exception as e: + LOG.exception('failed to show resource %s, %s' % vitrage_id, e) + abort(404, str(e)) + + @staticmethod + def _show_resource(vitrage_id): + try: + resource = pecan.request.client.call( + pecan.request.context, + 'show_resource', + vitrage_id=vitrage_id) + LOG.info(resource) + return json.loads(resource) + except Exception as e: + LOG.exception('failed to show resource with vitrage_id(%s),' + 'Exception: %s', + vitrage_id, e) + abort(404, str(e)) diff --git a/vitrage/api_handler/apis/resource.py b/vitrage/api_handler/apis/resource.py index 81fa51b4b..00d6dd7cf 100644 --- a/vitrage/api_handler/apis/resource.py +++ b/vitrage/api_handler/apis/resource.py @@ -53,3 +53,24 @@ class ResourceApis(EntityGraphApisBase): resources = self.entity_graph.get_vertices(query_dict=query) return json.dumps({'resources': [resource.properties for resource in resources]}) + + def show_resource(self, ctx, vitrage_id): + LOG.debug('Show resource with vitrage_id: %s', str(vitrage_id)) + + project_id = ctx.get(self.TENANT_PROPERTY, None) + is_admin_project = ctx.get(self.IS_ADMIN_PROJECT_PROPERTY, False) + + resource = self.entity_graph.get_vertex(vitrage_id) + if resource: + project = resource.get(VProps.PROJECT_ID) + if is_admin_project: + return json.dumps(resource.properties) + else: + if project and project_id == project: + return json.dumps(resource.properties) + LOG.warn('Have no authority to get resource with vitrage_id(%s)', + str(vitrage_id)) + else: + LOG.warn('Can not find the resource with vitrage_id(%s)', + str(vitrage_id)) + return None diff --git a/vitrage/tests/functional/api_handler/test_apis.py b/vitrage/tests/functional/api_handler/test_apis.py index 23160fd4d..4cea8346b 100644 --- a/vitrage/tests/functional/api_handler/test_apis.py +++ b/vitrage/tests/functional/api_handler/test_apis.py @@ -274,6 +274,93 @@ class TestApis(TestEntityGraphUnitBase): # Test assertions self.assertEqual(7, len(resources)) + def test_resource_show_with_admin_and_no_project_resource(self): + # Setup + graph = self._create_graph() + apis = ResourceApis(graph, None) + ctx = {'tenant': 'project_1', 'is_admin': True} + + # Action + resource = apis.show_resource(ctx, 'zone_1') + resource = json.loads(resource) + + # Test assertions + self.assertIsNotNone(resource) + self._check_resource_propeties(resource, 'zone_1', + NOVA_ZONE_DATASOURCE) + + def test_resource_show_with_not_admin_and_no_project_resource(self): + # Setup + graph = self._create_graph() + apis = ResourceApis(graph, None) + ctx = {'tenant': 'project_1', 'is_admin': False} + + # Action + resource = apis.show_resource(ctx, 'zone_1') + + # Test assertions + self.assertIsNone(resource) + + def test_resource_show_with_not_admin_and_resource_in_project(self): + # Setup + graph = self._create_graph() + apis = ResourceApis(graph, None) + ctx = {'tenant': 'project_1', 'is_admin': False} + + # Action + resource = apis.show_resource(ctx, 'instance_2') + resource = json.loads(resource) + + # Test assertions + self.assertIsNotNone(resource) + self._check_resource_propeties(resource, 'instance_2', + NOVA_INSTANCE_DATASOURCE, + project_id='project_1') + + def test_resource_show_with_not_admin_and_resource_in_other_project(self): + # Setup + graph = self._create_graph() + apis = ResourceApis(graph, None) + ctx = {'tenant': 'project_2', 'is_admin': False} + + # Action + resource = apis.show_resource(ctx, 'instance_2') + + # Test assertions + self.assertIsNone(resource) + + def test_resource_show_with_admin_and_resource_in_project(self): + # Setup + graph = self._create_graph() + apis = ResourceApis(graph, None) + ctx = {'tenant': 'project_1', 'is_admin': True} + + # Action + resource = apis.show_resource(ctx, 'instance_2') + resource = json.loads(resource) + + # Test assertions + self.assertIsNotNone(resource) + self._check_resource_propeties(resource, 'instance_2', + NOVA_INSTANCE_DATASOURCE, + project_id='project_1') + + def test_resource_show_with_admin_and_resource_in_other_project(self): + # Setup + graph = self._create_graph() + apis = ResourceApis(graph, None) + ctx = {'tenant': 'project_2', 'is_admin': True} + + # Action + resource = apis.show_resource(ctx, 'instance_2') + resource = json.loads(resource) + + # Test assertions + self.assertIsNotNone(resource) + self._check_resource_propeties(resource, 'instance_2', + NOVA_INSTANCE_DATASOURCE, + project_id='project_1') + def _check_projects_entities(self, alarms, project_id, @@ -289,6 +376,18 @@ class TestApis(TestEntityGraphUnitBase): (tmp_project_id and tmp_project_id == project_id)) self.assertEqual(True, condition) + def _check_resource_propeties(self, resource, vitrage_id, + resource_type, project_id=None): + self.assertEqual(resource[VProps.VITRAGE_ID], vitrage_id) + self.assertEqual(resource[VProps.ID], vitrage_id) + self.assertEqual(resource[VProps.CATEGORY], EntityCategory.RESOURCE) + self.assertEqual(resource[VProps.TYPE], resource_type) + self.assertEqual(resource[VProps.STATE], 'active') + self.assertFalse(resource[VProps.IS_DELETED]) + self.assertFalse(resource[VProps.IS_PLACEHOLDER]) + if project_id: + self.assertEqual(resource[VProps.PROJECT_ID], project_id) + def _create_graph(self): graph = NXGraph('Multi tenancy graph') diff --git a/vitrage_tempest_tests/tests/api/resources/test_resources.py b/vitrage_tempest_tests/tests/api/resources/test_resources.py index 49f5d9e94..1b99ba6a9 100644 --- a/vitrage_tempest_tests/tests/api/resources/test_resources.py +++ b/vitrage_tempest_tests/tests/api/resources/test_resources.py @@ -28,6 +28,8 @@ LOG = logging.getLogger(__name__) class TestResource(BaseApiTest): """Test class for Vitrage resource API tests.""" + properties = ('vitrage_id', 'type', 'id', 'state', 'aggregated_state') + @classmethod def setUpClass(cls): super(TestResource, cls).setUpClass() @@ -129,6 +131,32 @@ class TestResource(BaseApiTest): finally: self._delete_instances() + def test_compare_resource_show(self): + """resource_show test""" + resource_list = self.vitrage_client.resource.list() + self.assertNotEqual(len(resource_list), 0) + for resource in resource_list: + api_resource_show = \ + self.vitrage_client.resource.show(resource['vitrage_id']) + cli_resource_show = utils.run_vitrage_command( + 'vitrage resource show ' + resource['vitrage_id'], self.conf) + + self._compare_resource_show( + api_resource_show, cli_resource_show) + + def test_resource_show_with_no_existing_resource(self): + """resource_show test no existing resource""" + try: + resource = \ + self.vitrage_client.resource.show('test_for_no_existing') + self.assertIsNone(resource) + except Exception as e: + LOG.exception(e) + traceback.print_exc() + raise + finally: + self._delete_instances() + def _compare_resources(self, api_resources, cli_resources): self.assertNotEqual(len(api_resources), 0, 'The resources taken from rest api is empty') @@ -145,10 +173,19 @@ class TestResource(BaseApiTest): self.assertEqual(len(sorted_cli_resources), len(sorted_api_resources)) - properties = ('vitrage_id', 'type', 'id', 'state', - 'aggregated_state', 'operational_state') for cli_resource, api_resource in \ zip(sorted_cli_resources, sorted_api_resources): - for item in properties: + for item in self.properties: self.assertEqual(cli_resource.get(item), api_resource.get(item)) + + def _compare_resource_show(self, api_resource_show, + cli_resource_show): + self.assertIsNotNone(api_resource_show, + 'The resource show taken from rest api is empty') + self.assertIsNotNone(cli_resource_show, + 'The resource show taken from terminal is empty') + + for item in self.properties: + self.assertEqual(api_resource_show.get(item), + cli_resource_show.get(item))