Merge "RMS direct access to database for region resources"

This commit is contained in:
Zuul 2020-08-20 18:24:29 +00:00 committed by Gerrit Code Review
commit 88b95a0dcb
5 changed files with 94 additions and 90 deletions

View File

@ -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')

View File

@ -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")

View File

@ -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

View File

@ -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)

View File

@ -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))