diff --git a/orm/services/region_manager/rms/controllers/v2/orm/resources/regions.py b/orm/services/region_manager/rms/controllers/v2/orm/resources/regions.py index 2ae9082e..66c4da23 100755 --- a/orm/services/region_manager/rms/controllers/v2/orm/resources/regions.py +++ b/orm/services/region_manager/rms/controllers/v2/orm/resources/regions.py @@ -15,10 +15,8 @@ from orm.services.region_manager.rms.services import error_base from orm.services.region_manager.rms.services import services as RegionService from orm.services.region_manager.rms.utils import authentication -from pecan import conf as pecan_conf from pecan import request from pecan import rest -import requests import wsme from wsme import types as wtypes from wsmeext.pecan import wsexpose @@ -190,45 +188,6 @@ class RegionsController(rest.RestController): metadata = RegionMetadataController() status = RegionStatusController() - def has_no_resources(self, region_id): - # function to check if any resource (flavor, customer, or image) is - # assigned to the region_id - try: - resources = { - 'flavors': [pecan_conf.api.fms_server.base, - pecan_conf.api.fms_server.flavors], - 'customers': [pecan_conf.api.cms_server.base, - pecan_conf.api.cms_server.customers], - 'images': [pecan_conf.api.ims_server.base, - pecan_conf.api.ims_server.images] - } - - keystone_ep = authentication.get_keystone_ep( - request.headers['X-Auth-Region']) - - headers = {'Keystone-Endpoint': keystone_ep, - 'X-Auth-Region': request.headers['X-Auth-Region'], - 'X-Auth-Token': request.headers['X-Auth-Token']} - - for resource in resources: - resource_get_url = '%s%s/?region=%s' % ( - resources[resource][0], - resources[resource][1], region_id) - resp = requests.get(resource_get_url, - headers=headers, - verify=pecan_conf.verify) - resp_dict = resp.json() - - if resp_dict[resource]: - return False - - return True - - except Exception as e: - raise err_utils.get_error(request.transaction_id, - status_code=401, - message=str(e)) - @wsexpose(Regions, str, str, [str], str, str, str, str, str, str, str, str, str, str, str, str, status_code=200, rest_content_types='json') def get_all(self, type=None, status=None, metadata=None, @@ -263,8 +222,9 @@ class RegionsController(rest.RestController): 'ranger_agent_version': ranger_agent_version, 'clli': clli, 'regionname': regionname, 'osversion': osversion, 'location_type': location_type, 'state': state, - 'domain_name': domain_name, 'country': country, 'city': city, - 'street': street, 'zip': zip, 'vlcp_name': vlcp_name} + 'domain_name': domain_name, 'country': country, + 'city': city, 'street': street, 'zip': zip, + 'vlcp_name': vlcp_name} logger.debug("Parameters: {}".format(str(url_args))) try: @@ -358,46 +318,41 @@ class RegionsController(rest.RestController): @wsexpose(None, str, rest_content_types='json', status_code=204) def delete(self, region_id): - utils.set_utils_conf(pecan_conf) - # currently ORM resource types are 'flavor', 'customer', and 'image' - proceed_to_delete = self.has_no_resources(region_id) - if proceed_to_delete: - logger.info("Delete Region") - authentication.authorize(request, 'region:delete') - try: + logger.info("Delete Region") + authentication.authorize(request, 'region:delete') + try: - logger.debug("delete region {}".format(region_id)) - RegionService.delete_region(region_id) - logger.debug("region deleted") + logger.debug("delete region {}".format(region_id)) + RegionService.delete_region(region_id) + logger.debug("region deleted") - event_details = 'Region {} deleted'.format(region_id) - utils.audit_trail('delete region', request.transaction_id, - request.headers, region_id, - event_details=event_details) + event_details = 'Region {} deleted'.format(region_id) + utils.audit_trail('delete region', request.transaction_id, + request.headers, region_id, + event_details=event_details) - # issue NotFoundError for "Delete Region" when group_id not found - # which is returned by RegionService.delete_region function - except error_base.NotFoundError as exp: - logger.error("RegionsController - Region not found") - raise err_utils.get_error( - request.transaction_id, - message="Cannot delete - " + exp.message, - status_code=exp.status_code) - - except Exception as exp: - logger.exception( - "error in deleting region .. reason:- {}".format(str(exp))) - raise err_utils.get_error(request.transaction_id, - status_code=500, - message=str(exp)) - return - else: - region_resources_exist_msg = "Region {} cannot be deleted as " \ - "resources are assigned.".format(region_id) + # issue NotFoundError for "Delete Region" when group_id not found + # which is returned by RegionService.delete_region function + except error_base.NotFoundError as exp: + logger.error("RegionsController - Region not found") + raise err_utils.get_error( + request.transaction_id, + message="Cannot delete - " + exp.message, + status_code=exp.status_code) + except error_base.ConflictError as exp: + logger.error("Region with resources cannot be deleted") raise err_utils.get_error(request.transaction_id, status_code=400, - message=region_resources_exist_msg) + message=exp.message) + + except Exception as exp: + logger.exception( + "Error in deleting region .. reason:- {}".format(str(exp))) + raise err_utils.get_error(request.transaction_id, + status_code=500, + message=str(exp)) + return @wsexpose(RegionsData, str, body=RegionsData, status_code=201, rest_content_types='json') diff --git a/orm/services/region_manager/rms/services/services.py b/orm/services/region_manager/rms/services/services.py index 5f73e57e..9f367933 100755 --- a/orm/services/region_manager/rms/services/services.py +++ b/orm/services/region_manager/rms/services/services.py @@ -77,6 +77,7 @@ def delete_region(region_id): :return: """ LOG.debug("logic:- delete region {}".format(region_id)) + try: db = data_manager_factory.get_data_manager() # logic to allow 'delete_region' to issue NotFoundError when region_id is non-existent @@ -84,6 +85,13 @@ def delete_region(region_id): if not region: raise error_base.NotFoundError(message="Region '{}' not found".format(region_id)) + # Region with resources cannnot be deleted + resource_exist = db.query_region_resources(region_id) + if resource_exist: + region_resources_exist_msg = "Region {} cannot be deleted as " \ + "resources are assigned.".format(region_id) + raise error_base.ConflictError(message=region_resources_exist_msg) + db.delete_region(region_id) LOG.debug("region deleted") diff --git a/orm/services/region_manager/rms/storage/my_sql/data_manager.py b/orm/services/region_manager/rms/storage/my_sql/data_manager.py index 8778d855..dc5cd1d1 100755 --- a/orm/services/region_manager/rms/storage/my_sql/data_manager.py +++ b/orm/services/region_manager/rms/storage/my_sql/data_manager.py @@ -1,11 +1,19 @@ import datetime import logging +from orm.services.customer_manager.cms_rest.data.sql_alchemy.models import ( + Customer, CustomerRegion) +from orm.services.customer_manager.cms_rest.data.sql_alchemy.models import \ + Region as CmsRegion +from orm.services.flavor_manager.fms_rest.data.sql_alchemy.db_models import ( + Flavor, FlavorRegion) +from orm.services.image_manager.ims.persistency.sql_alchemy.db_models import ( + Image, ImageRegion) + from orm.services.region_manager.rms.model import model as PythonModels from orm.services.region_manager.rms.services import error_base -from orm.services.region_manager.rms.storage.base_data_manager import (BaseDataManager, - DuplicateEntryError, - EntityNotFound) +from orm.services.region_manager.rms.storage.base_data_manager import ( + BaseDataManager, DuplicateEntryError, EntityNotFound) import oslo_db from .data_models import (Group, GroupRegion, Region, RegionEndPoint, @@ -177,6 +185,43 @@ class DataManager(BaseDataManager): logger.exception("fail to update region {}".format(str(exp))) raise + def query_region_resources(self, region_id): + try: + resource_exist = False + session = self._engine_facade.get_session() + with session.begin(): + # query customer resource for the region + query = session.query(Customer) + query = query.join(CustomerRegion).filter( + CustomerRegion.customer_id == Customer.id) + query = query.join(CmsRegion).filter( + CmsRegion.id == CustomerRegion.region_id, + CmsRegion.type == 'single', CmsRegion.name == region_id) + if query.first() is not None: + resource_exist = True + else: + # query flavor resource for the region + query = session.query(Flavor) + query = query.join(FlavorRegion).filter( + FlavorRegion.flavor_internal_id == Flavor.internal_id, + FlavorRegion.region_name == region_id) + if query.first() is not None: + resource_exist = True + else: + # query image resource for the region + query = session.query(Image) + query = query.join(ImageRegion).filter( + ImageRegion.image_id == Image.id, + ImageRegion.region_name == region_id) + if query.first() is not None: + resource_exist = True + + return resource_exist + except Exception as exp: + logger.exception( + "fail to verify if region {} has resources".format(region_id)) + raise + def delete_region(self, region_id): # delete a region from `region` table and also the region's # entries from `region_meta_data` and `region_end_points` tables diff --git a/orm/tests/unit/rms/controllers/v1/orm/resources/test_region.py b/orm/tests/unit/rms/controllers/v1/orm/resources/test_region.py index ee9c1ac9..480849b6 100755 --- a/orm/tests/unit/rms/controllers/v1/orm/resources/test_region.py +++ b/orm/tests/unit/rms/controllers/v1/orm/resources/test_region.py @@ -257,10 +257,9 @@ class TestAddRegion(FunctionalTest): @patch.object(regions, 'request') @patch.object(regions, 'err_utils') @patch.object(regions.RegionService, 'delete_region') - @patch.object(regions.RegionsController, 'has_no_resources', return_value=True) @patch.object(regions.authentication, 'authorize', return_value=True) def test_delete_region_error(self, mock_auth, mock_delete_logic, - mock_get_error, mock_request, mock_controller): + mock_get_error, mock_request): mock_get_error.get_error = self.get_error mock_request.transaction_id = "555" mock_delete_logic.side_effect = regions.error_base.ErrorStatus(message="unknown error", status_code=500) diff --git a/orm/tests/unit/rms/services/test_services.py b/orm/tests/unit/rms/services/test_services.py index 4200cd0f..a834df40 100755 --- a/orm/tests/unit/rms/services/test_services.py +++ b/orm/tests/unit/rms/services/test_services.py @@ -51,6 +51,9 @@ class db(object): def get_region_by_id_or_name(self, id_name): return id_name + def query_region_resources(self, id_name): + return False + def add_region(self, **kw): if self.exp: raise Exception("any") @@ -313,22 +316,16 @@ class TestServices(FunctionalTest): message = exp.message self.assertEqual(message, "id not found") - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) @patch.object(services.data_manager_factory, 'get_data_manager', return_value=db(exp=True)) - def test_delete_region_error(self, mock_db_get_group, - mock_get_region_id_name): + def test_delete_region_error(self, mock_db_get_group): try: result = services.delete_region(self._to_wsme_from_input(full_region)) except Exception as exp: message = str(exp) self.assertEqual(message, "not deleted") - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) @patch.object(services.data_manager_factory, 'get_data_manager', return_value=db()) - def test_delete_region_success(self, mock_db_get_group, - mock_get_region_id_name): + def test_delete_region_success(self, mock_db_get_group): result = services.delete_region(self._to_wsme_from_input(full_region))