Refactor uuid handling for Ranger service resources

This commit provides the following uuid management:

(1) Remove uuid record from database after the uuid owned by
a Ranger service (cms, fms, ims) resource is deleted.

(2) Remove stale uuid record from database when such
record is inadvertently created during unsuccessful Ranger
service resource creation.

(3) Add authentication for uuidgen service delete uuid API.

Change-Id: Ifebd68851ff6c0996e7b19d331f4dd99682bd7d2
This commit is contained in:
st6218 2020-04-24 15:24:13 -07:00 committed by Chi Lo
parent 36bacfb2cf
commit f9ce6832f2
25 changed files with 489 additions and 102 deletions

View File

@ -389,12 +389,12 @@ rds = {'port': CONF.rds.port,
cli = {'base_region': CONF.cli.base_region}
def server_request_auth(server_name):
if server_name[1:] == 'ms':
# cms, fms, ims, rms
def server_request_auth(service_name):
services = ['cms', 'fms', 'ims', 'rms', 'uuid']
if service_name in services:
policy_name = CONF.ranger_base + '/etc/policy.json'
else:
# policy_N/A for services 'rds', 'audit', and 'uuid'
# policy_N/A for services 'rds', and 'audit'
policy_name = None
# authentication settings

View File

@ -1,5 +1,5 @@
from oslo_db.sqlalchemy import models
from sqlalchemy import BigInteger, Column, Integer, Text
from sqlalchemy import BigInteger, Column, Integer, Text, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
@ -36,3 +36,17 @@ class ResourceStatus(Base, CommonBaseModel):
err_msg=self.err_msg,
operation=self.operation
)
class RegionEndPoint(Base, CommonBaseModel):
__tablename__ = 'region_end_point'
region_id = Column(ForeignKey('region.region_id'), primary_key=True)
end_point_type = Column(String(64), primary_key=True)
public_url = Column(String(64), nullable=False)
def __json__(self):
return dict(
end_point_type=self.end_point_type,
public_url=self.public_url
)

View File

@ -0,0 +1,45 @@
import logging
from orm.common.orm_common.sql_alchemy.db_models import RegionEndPoint
from sqlalchemy import and_
logger = logging.getLogger(__name__)
class RegionEndPointRecord:
def __init__(self, session):
self.__region_end_point = RegionEndPoint()
self.__TableName = "region_end_point"
if session:
self.setDBSession(session)
def setDBSession(self, session):
self.session = session
@property
def region_end_point(self):
return self.__region_end_point
@region_end_point.setter
def region_end_point(self, region_end_point):
self.__region_end_point = region_end_point
def read_region_end_point(self, region_id, end_point_type):
try:
record = self.session.query(RegionEndPoint).filter(
and_(RegionEndPoint.region_id == region_id,
RegionEndPoint.end_point_type == end_point_type))
sql_endpoint = record.first()
if sql_endpoint:
return sql_endpoint.public_url
else:
logger.debug("Public Url end point not found")
return None
except Exception as ex:
message = "Failed to get Endpoint for region:{} type:{}-{}".format(
region_id, endpoint_type, str(ex))
logger.exception(message)
raise

View File

@ -4,4 +4,11 @@ class Error(Exception):
class ErrorStatus(Error):
def __init__(self, status_code, message=""):
self.status_code = status_code
self.message = message
class NotFound(Error):
def __init__(self, status_code=404, message=None):
self.status_code = status_code
self.message = message

View File

@ -4,13 +4,12 @@ import requests
import time
from orm.common.client.audit.audit_client.api import audit
from orm.common.orm_common.sql_alchemy.region_end_point_record \
import RegionEndPointRecord
from orm.common.orm_common.sql_alchemy.resource_status_record \
import ResourceStatusRecord
from pecan import conf
# from cms_rest.logger import get_logger
#
from pecan import conf, request
conf = None
LOG = logging.getLogger(__name__)
@ -42,6 +41,7 @@ def create_or_validate_uuid(uuid, uuid_type):
2) validate a uuid if one is being set
returns uuid string
"""
_check_conf_initialization()
url = conf.api.uuid_server.base + conf.api.uuid_server.uuids
@ -65,9 +65,11 @@ def create_or_validate_uuid(uuid, uuid_type):
LOG.info('Failed in make_uuid:' + str(e))
return None
if resp.status_code == 400:
LOG.debug('Duplicate key for uuid: {}'.format(uuid))
raise TypeError('Duplicate key for uuid: ' + str(uuid))
# add uuid to uuids table success status_code = 200
if resp.status_code != 200:
message = 'Create or validate UUID failed: {}'.format(resp.text)
LOG.error(message)
raise TypeError(message)
resp = resp.json()
return resp['uuid']
@ -212,11 +214,49 @@ def get_resource_status(resource_id):
return result.json()
def delete_uuid(uuid):
try:
_check_conf_initialization()
headers = {}
headers['X-Auth-Region'] = request.headers[
'X-Auth-Region'] if 'X-Auth-Region' in \
request.headers else ''
headers['X-Auth-Token'] = request.headers[
'X-Auth-Token'] if 'X-Auth-Token' in \
request.headers else ''
url = "{}{}/{}".format(conf.api.uuid_server.base,
conf.api.uuid_server.uuids,
uuid)
resp = requests.delete(url, headers=headers)
except Exception as ex:
LOG.error(
"Exception - Uuidgen service failed to delete uuid : {}".format(
str(ex)))
return False
if resp.status_code != 200:
LOG.error("Uuidgen service failed to delete uuid {}: {}".format(
uuid, resp.text))
return False
return True
def get_resource_status_from_db(session, resource_ids):
resource_status_record = ResourceStatusRecord(session)
return resource_status_record.read_resource_status(resource_ids)
def get_region_end_point_from_db(session, region_id, end_point_type):
region_end_point_record = RegionEndPointRecord(session)
return region_end_point_record.read_region_end_point(region_id,
end_point_type)
def get_time_human():
"""this function return the timestamp for output JSON
:return: timestamp in wanted format

View File

@ -34,7 +34,7 @@ class CustomerController(rest.RestController):
except ErrorStatus as exception:
LOG.log_exception("CustomerController - Failed to GetCustomerDetails", exception)
raise err_utils.get_error(request.transaction_id,
message=exception.message,
message=str(exception),
status_code=exception.status_code)
except Exception as exception:
@ -57,8 +57,9 @@ class CustomerController(rest.RestController):
try:
uuid = utils.create_or_validate_uuid(customer.uuid, 'custId')
except TypeError:
raise ErrorStatus(409.1, 'Unable to create Customer ID {0}'.format(customer.uuid))
except TypeError as exception:
LOG.error("UUID Error: " + str(exception))
raise ErrorStatus(409, str(exception))
result = customer_logic.create_customer(customer, uuid, request.transaction_id)
@ -106,14 +107,14 @@ class CustomerController(rest.RestController):
except ErrorStatus as exception:
LOG.log_exception("Failed in UpdateCustomer", exception)
raise err_utils.get_error(request.transaction_id,
message=exception.message,
message=str(exception),
status_code=exception.status_code)
except Exception as exception:
LOG.log_exception("CustomerController - Failed to UpdateCustomer", exception)
raise err_utils.get_error(request.transaction_id,
status_code=500,
error_details=exception.message)
error_details=str(exception))
return result
@ -146,7 +147,7 @@ class CustomerController(rest.RestController):
LOG.log_exception("CustomerController - Failed to GetCustomerlist", exception)
raise err_utils.get_error(request.transaction_id,
status_code=500,
error_details=exception.message)
error_details=str(exception))
@wsexpose(None, str, rest_content_types='json', status_code=204)
def delete(self, customer_id):
@ -167,7 +168,7 @@ class CustomerController(rest.RestController):
LOG.log_exception("CustomerController - Failed to DeleteCustomer",
exception)
raise err_utils.get_error(request.transaction_id,
message=exception.message,
message=str(exception),
status_code=exception.status_code)
except Exception as exception:
@ -175,4 +176,4 @@ class CustomerController(rest.RestController):
exception)
raise err_utils.get_error(request.transaction_id,
status_code=500,
error_details=exception.message)
error_details=str(exception))

View File

@ -181,6 +181,10 @@ class CustomerLogic(object):
except Exception as exp:
LOG.log_exception("CustomerLogic - Failed to CreateCustomer", exp)
datamanager.rollback()
# cleanup uuids when create customer fails
utils.delete_uuid(uuid)
raise
return customer_result_wrapper
@ -765,6 +769,10 @@ class CustomerLogic(object):
datamanager.flush() # i want to get any exception created by this delete
datamanager.commit()
# after successful customer delete, delete customer id from uuids table
utils.delete_uuid(customer_id)
except Exception as exp:
LOG.log_exception("CustomerLogic - Failed to delete customer", exp)
datamanager.rollback()

View File

@ -1,5 +1,3 @@
from orm.common.orm_common.injector import injector
from orm.common.orm_common.utils import api_error_utils as err_utils
from orm.common.orm_common.utils import utils as common_utils
@ -13,6 +11,7 @@ from orm.services.flavor_manager.fms_rest.logic.error_base import ErrorStatus
from orm.services.flavor_manager.fms_rest.utils import authentication
from pecan import conf, request, rest
from wsmeext.pecan import wsexpose
di = injector.get_di()
@ -36,13 +35,12 @@ class FlavorController(rest.RestController):
LOG.info("FlavorController - Createflavor: " + str(flavors))
authentication.authorize(request, 'flavor:create')
common_utils.set_utils_conf(conf)
try:
try:
uuid = common_utils.create_or_validate_uuid(flavors.flavor.id, 'fmsId')
except TypeError:
LOG.error("UUID already exists")
raise ErrorStatus(409, 'UUID already exists')
except TypeError as exception:
LOG.error("UUID Error: " + str(exception))
raise ErrorStatus(409, str(exception))
result = flavor_logic.create_flavor(flavors, uuid, request.transaction_id)

View File

@ -54,7 +54,6 @@ def validate_tenants_regions_list(requested_tenants, requested_regions,
def create_flavor(flavor, flavor_uuid, transaction_id):
DataManager = di.resolver.unpack(create_flavor)
datamanager = DataManager()
try:
valid_tenants_list, valid_regions_list = [], []
flavor.flavor.handle_region_groups()
@ -107,6 +106,7 @@ def create_flavor(flavor, flavor_uuid, transaction_id):
return ret_flavor
except oslo_db.exception.DBDuplicateEntry as exception:
utils.delete_uuid(flavor_uuid)
raise ErrorStatus(
409.2, "Flavor name '{}' already exists".format(
flavor.flavor.name))
@ -115,10 +115,7 @@ def create_flavor(flavor, flavor_uuid, transaction_id):
LOG.log_exception("FlavorLogic - Failed to CreateFlavor",
str(exp))
datamanager.rollback()
if "Duplicate entry" in str(exp):
raise ConflictError(
409,
"Flavor {} already exists".format(flavor.flavor.name))
utils.delete_uuid(flavor_uuid)
raise
finally:
datamanager.close()
@ -186,7 +183,7 @@ def update_flavor(flavor, flavor_uuid, transaction_id): # pragma: no cover
@di.dependsOn('data_manager')
def delete_flavor_by_uuid(flavor_uuid): # , transaction_id):
def delete_flavor_by_uuid(flavor_uuid):
DataManager = di.resolver.unpack(delete_flavor_by_uuid)
datamanager = DataManager()
@ -196,8 +193,8 @@ def delete_flavor_by_uuid(flavor_uuid): # , transaction_id):
sql_flavor = flavor_rec.get_flavor_by_id(flavor_uuid)
if sql_flavor is None:
raise NotFoundError(
message="Flavor '{}' not found".format(flavor_uuid))
message_not_found = "Flavor '{}' not found".format(flavor_uuid)
raise ErrorStatus(404, message_not_found)
existing_region_names = sql_flavor.get_existing_region_names()
if len(existing_region_names) > 0:
@ -240,6 +237,10 @@ def delete_flavor_by_uuid(flavor_uuid): # , transaction_id):
# get any exception created by this delete
datamanager.flush()
datamanager.commit()
# after successful flavor delete, delete flavor id from uuids table
utils.delete_uuid(flavor_uuid)
except Exception as exp:
LOG.log_exception("FlavorLogic - Failed to delete flavor", str(exp))
datamanager.rollback()

View File

@ -23,3 +23,5 @@ verify = config.ssl_verify
database = {
'connection_string': config.db_connect
}
authentication = config.server_request_auth(server['name'])

View File

@ -7,10 +7,15 @@ from oslo_log import log as logging
from pecan.commands import CommandRunner
from pecan import make_app
from orm.common.orm_common.policy import policy
from orm.services.id_generator.uuidgen.utils import authentication
LOG = logging.getLogger(__name__)
def setup_app(config):
token_conf = authentication.get_token_conf(config)
policy.init(config.authentication.policy_file, token_conf)
app_conf = dict(config.app)
app = make_app(app_conf.pop('root'),
logging=getattr(config, 'logging', {}),

View File

@ -3,10 +3,13 @@ import logging
import re
import uuid
from pecan import expose, response
from pecan import expose, request, response
from pecan.rest import RestController
from orm.common.orm_common.utils.error_base import NotFound
from orm.common.orm_common.utils import utils
from orm.services.id_generator.uuidgen.db.db_manager import DBManager
from orm.services.id_generator.uuidgen.utils import authentication
LOG = logging.getLogger(__name__)
@ -23,54 +26,85 @@ def respond(reason, code, message):
class UUIDController(RestController):
@expose(template='json')
def get(self, **kw):
if 'uuid' in kw:
uuid = kw['uuid']
else:
response.status = 400
messageToReturn = respond(
"badRequest", response.status, 'Missing UUID parameter.')
return messageToReturn
def get_one(self, uuid):
LOG.info("UUIDController.get_one uuid=" + uuid)
try:
db_manager = DBManager()
results = db_manager.get_uuid_details(uuid)
if results is None:
response.status = 404
message = "UUID {} not found".format(uuid)
messageToReturn = respond(
"badRequest", response.status, 'UUID not found')
"NotFound", response.status, message)
return messageToReturn
return results.get_dict()
except Exception as e:
response.status = 500
messageToReturn = respond(
"badRequest", response.status, 'Database error')
"BadRequest", response.status, 'Database error')
LOG.error(str(messageToReturn) + "Exception: " + str(e))
return messageToReturn
@expose(template='json')
def delete(self, **kw):
if 'uuid' in kw:
uuid = kw['uuid']
else:
def delete(self, uuid):
LOG.info("UUIDController.delete uuid=" + uuid)
# authenticate the request
try:
self.validate_headers()
db_manager = DBManager()
db_session = db_manager.get_session()
# Get keystone endpoint so that authientication.authorize()
# does not need to request rms service for the endpoint
auth_region = request.headers.get('X-Auth-Region')
keystone_ep = utils.get_region_end_point_from_db(
db_session, auth_region, 'identity')
if keystone_ep is None:
raise NotFound
authentication.authorize(request, 'uuid:delete', keystone_ep)
except KeyError as e:
response.status = 400
message = "Missing mandatory parameters - {}".format(str(e))
messageToReturn = respond(
"badRequest", response.status, 'Missing UUID parameter.')
"MissingParams", response.status, message)
return messageToReturn
except NotFound as e:
response.status = 404
message = "EP for region:{} type:identity not found".format(
auth_region)
messageToReturn = respond(
"EndpointNotFound", response.status, message)
return messageToReturn
except Exception as e:
response.status = 401
message = "Failed to authenticate. UUID {} not deleted. {}".format(
uuid, str(e))
messageToReturn = respond(
"FailedAuthentication", response.status, message)
LOG.error(str(messageToReturn) + " Exception: " + str(e))
return messageToReturn
try:
db_manager = DBManager()
results = db_manager.delete_uuid(uuid)
if results == 0:
response.status = 404
message = "UUID {} not found".format(uuid)
messageToReturn = respond(
"badRequest", response.status, 'UUID not found')
"FailedDeletion", response.status, message)
return messageToReturn
return {}
except Exception as e:
response.status = 500
message = "Database error - {}".format(str(e))
messageToReturn = respond(
"badRequest", response.status, 'Database error')
"ServerError", response.status, message)
LOG.error(str(messageToReturn) + "Exception: " + str(e))
return messageToReturn
@ -84,6 +118,7 @@ class UUIDController(RestController):
messageToReturn = None
uuid_type = ''
customer_id = None
if 'uuid_type' in kw:
uuid_type = kw['uuid_type']
del kw['uuid_type']
@ -94,7 +129,7 @@ class UUIDController(RestController):
if len(kw):
response.status = 400
messageToReturn = respond("badRequest", 400, 'Unknown parameter(s):' + ', '.join(list(kw.keys())))
messageToReturn = respond("BadRequest", 400, 'Unknown parameter(s):' + ', '.join(list(kw.keys())))
LOG.info("UUIDController.post - " + str(messageToReturn))
return messageToReturn
@ -103,7 +138,7 @@ class UUIDController(RestController):
if not re.match(r'^[A-Za-z0-9]+$', customer_id):
response.status = 400
messageToReturn = respond("badRequest", 400, "Only alphanumeric characters allowed!")
messageToReturn = respond("BadRequest", 400, "Only alphanumeric characters allowed!")
LOG.info("UUIDController.post - " + str(messageToReturn))
return messageToReturn
@ -119,22 +154,20 @@ class UUIDController(RestController):
"uuid_type": uuid_type
}
except Exception as e:
# ignore case of uuid already exist, this can append when creating customer with specific uuid,
# we just need to save it in the database that we will not give this value in the future requests
# but we don't need to throw exception if already exist, this is not our responsible
# if it is duplicate uuid it will fail in the service which uses this uuid (cms, fms)
if e.inner_exception.orig[0] == 1062:
LOG.info("Duplicate UUID=" + uuid)
# if create_uuid detects duplicate UUID error we will throw
# exception in the calling service (cms, fms, or ims)
if 'Duplicate entry' in str(e):
response.status = 409
messageToReturn = respond('Duplicate Entry', response.status,
'Duplicate UUID {}'.format(uuid))
LOG.error(str(messageToReturn) + str(e))
return messageToReturn
else:
response.status = 500
messageToReturn = respond("badRequest", 500, 'Database error')
LOG.error(str(messageToReturn) + "Exception: " + str(e))
messageToReturn = respond(
'BadRequest', response.status, 'Database error')
LOG.error(str(messageToReturn) + str(e))
return messageToReturn
return {
"uuid": uuid,
"issued_at": datetime.datetime.utcnow().isoformat() + 'Z',
"uuid_type": uuid_type
}
def create_new_uuid(self, uuid_type):
uu = uuid.uuid4().hex
@ -149,6 +182,13 @@ class UUIDController(RestController):
}
except Exception as e:
response.status = 500
messageToReturn = respond("badRequest", 500, 'Database error')
messageToReturn = respond("BadRequest", 500, 'Database error')
LOG.error(str(messageToReturn) + "Exception: " + str(e))
return messageToReturn
def validate_headers(self):
if request.headers.get('X-Auth-Region') is None:
raise KeyError("Header missing X-Auth-Region")
if request.headers.get('X-Auth-Token') is None:
raise KeyError("Header missing X-Auth-Token")

View File

@ -55,7 +55,7 @@ class DBManager(object):
self.engine.dispose()
except Exception as ex:
logger.exception(
"Error adding uuid {} : {}".format(_uuid, str(exp)))
"Error adding uuid {} : {}".format(_uuid, str(ex)))
raise ex
def get_uuid_details(self, _uuid):
@ -66,7 +66,7 @@ class DBManager(object):
return uuid.first()
except Exception as ex:
logger.exception(
"Error getting uuid {} : {}".format(_uuid, str(exp)))
"Error getting uuid {} : {}".format(_uuid, str(ex)))
raise ex
def delete_uuid(self, _uuid):
@ -79,5 +79,5 @@ class DBManager(object):
return result
except Exception as ex:
logger.exception(
"Error deleting uuid {} : {}".format(_uuid, str(exp)))
"Error deleting uuid {} : {}".format(_uuid, str(ex)))
raise ex

View File

@ -0,0 +1,32 @@
import logging
from orm.common.client.keystone.keystone_utils import tokens
from orm.common.orm_common.policy import policy
from pecan import conf
logger = logging.getLogger(__name__)
def authorize(request, action, keystone_ep=None):
if not _is_authorization_enabled(conf):
return
policy.authorize(action, request, conf, keystone_ep)
def _is_authorization_enabled(app_conf):
return app_conf.authentication.enabled
def get_token_conf(app_conf):
mech_id = app_conf.authentication.mech_id
mech_password = app_conf.authentication.mech_pass
rms_url = app_conf.authentication.rms_url
tenant_name = app_conf.authentication.tenant_name
keystone_version = app_conf.authentication.keystone_version
user_domain_name = app_conf.authentication.user_domain_name
project_domain_name = app_conf.authentication.project_domain_name
conf = tokens.TokenConf(mech_id, mech_password, rms_url, tenant_name,
keystone_version, user_domain_name,
project_domain_name)
return conf

View File

@ -45,8 +45,9 @@ class ImageController(rest.RestController):
try:
uuid = utils.create_or_validate_uuid(image_wrapper.image.id, 'imsId')
except TypeError:
raise ErrorStatus(409.1, message='Image UUID already exists')
except TypeError as exception:
LOG.error("UUID Error: " + str(exception))
raise ErrorStatus(409, str(exception))
try:
ret_image = image_logic.create_image(image_wrapper, uuid,
@ -69,14 +70,14 @@ class ImageController(rest.RestController):
except ErrorStatus as exception:
LOG.log_exception("ImageController - Failed to CreateImage", exception)
raise err_utils.get_error(request.transaction_id,
message=exception.message,
message=str(exception),
status_code=exception.status_code)
except Exception as exception:
LOG.log_exception("ImageController - Failed to CreateImage", exception)
raise err_utils.get_error(request.transaction_id,
status_code=500,
error_details=exception.message)
error_details=str(exception))
@wsexpose(ImageWrapper, str, body=ImageWrapper, rest_content_types='json', status_code=200)
def put(self, image_id, image_wrapper):
@ -105,7 +106,7 @@ class ImageController(rest.RestController):
except ErrorStatus as exception:
LOG.log_exception("Failed in UpdateImage", exception)
raise err_utils.get_error(request.transaction_id,
message=exception.message,
message=str(exception),
status_code=exception.status_code)
except Exception as exception:
@ -127,7 +128,7 @@ class ImageController(rest.RestController):
except ErrorStatus as exception:
LOG.log_exception("ImageController - Failed to GetImageDetails", exception)
raise err_utils.get_error(request.transaction_id,
message=exception.message,
message=str(exception),
status_code=exception.status_code)
except Exception as exception:
@ -150,7 +151,7 @@ class ImageController(rest.RestController):
except ErrorStatus as exception:
LOG.log_exception("ImageController - Failed to GetImagelist", exception)
raise err_utils.get_error(request.transaction_id,
message=exception.message,
message=str(exception),
status_code=exception.status_code)
except Exception as exception:

View File

@ -47,6 +47,7 @@ def create_image(image_wrapper, image_uuid, transaction_id):
return ret_image
except oslo_db.exception.DBDuplicateEntry as exception:
utils.delete_uuid(image_uuid)
raise ErrorStatus(
409.2, "Image name '{}' already exists".format(
image_wrapper.image.name))
@ -54,6 +55,7 @@ def create_image(image_wrapper, image_uuid, transaction_id):
except Exception as exp:
LOG.log_exception("ImageLogic - Failed to CreateImage", exp)
datamanager.rollback()
utils.delete_uuid(image_uuid)
raise
@ -135,8 +137,8 @@ def delete_image_by_uuid(image_uuid, transaction_id):
sql_image = image_rec.get_image_by_id(image_uuid)
if sql_image is None:
raise NotFoundError(
message="Image '{}' not found".format(image_uuid))
message_not_found = "Image '{}' not found".format(image_uuid)
raise ErrorStatus(404, message_not_found)
image_existing_region_names = sql_image.get_existing_region_names()
if len(image_existing_region_names) > 0:
@ -173,6 +175,9 @@ def delete_image_by_uuid(image_uuid, transaction_id):
# delete
datamanager.commit()
# after successful image delete, delete image id from uuids table
utils.delete_uuid(image_uuid)
except Exception as exp:
LOG.log_exception("ImageLogic - Failed to delete image", exp)
datamanager.rollback()

View File

@ -33,9 +33,11 @@ class UUIDController(rest.RestController):
logger.info("UUIDController - Getting UUID " + uuid)
authentication.authorize(request, 'uuid:get_one')
url = conf.api.uuid_server.base + conf.api.uuid_server.uuids
url = "{}{}/{}".format(conf.api.uuid_server.base,
conf.api.uuid_server.uuids,
uuid)
try:
resp = requests.get(url, params={'uuid': uuid})
resp = requests.get(url)
except Exception as ex:
logger.exception(
"Failed to get uuid : {}".format(str(ex)))
@ -59,9 +61,19 @@ class UUIDController(rest.RestController):
logger.info("UUIDController - Deleting UUID " + uuid)
authentication.authorize(request, 'uuid:delete')
url = conf.api.uuid_server.base + conf.api.uuid_server.uuids
headers = {}
headers['X-Auth-Region'] = request.headers[
'X-Auth-Region'] if 'X-Auth-Region' in \
request.headers else ''
headers['X-Auth-Token'] = request.headers[
'X-Auth-Token'] if 'X-Auth-Token' in \
request.headers else ''
url = "{}{}/{}".format(conf.api.uuid_server.base,
conf.api.uuid_server.uuids,
uuid)
try:
resp = requests.delete(url, params={'uuid': uuid})
resp = requests.delete(url, headers=headers)
except Exception as ex:
logger.exception(
"Failed to delete uuid : {}".format(str(ex)))

View File

@ -10,9 +10,17 @@ class TestUtil(TestCase):
self.mock_response = mock.Mock()
utils.conf = mock_conf
auth_headers = {'X-RANGER-Client': 'cliet',
'X-RANGER-Requester': 'requestor',
'X-Auth-Region': 'region',
'X-Auth-Token': 'token'}
utils.request = mock.Mock()
utils.request.headers = auth_headers
def respond(self, value, code):
self.mock_response.json.return_value = value
self.mock_response.status_code = code
self.mock_response.text = 'xxxxx'
return self.mock_response
@mock.patch('requests.post')
@ -137,11 +145,11 @@ class TestUtil(TestCase):
self.assertEqual(returned_uuid, None)
@mock.patch('requests.post')
def test_create_existing_uuid_with_400(self, mock_post):
def test_create_existing_uuid_with_uuid_fail(self, mock_post):
uuid = '987654321'
uuid_type = 'testId'
mock_post.return_value = self.respond({'uuid': uuid, 'uuid_type': uuid_type}, 409)
self.assertRaises(TypeError, utils.create_or_validate_uuid(uuid, uuid_type))
self.assertRaises(TypeError, utils.create_or_validate_uuid, uuid, uuid_type)
@mock.patch('pecan.conf')
def test_report_config(self, mock_conf):
@ -174,3 +182,20 @@ class TestUtil(TestCase):
my_response.status_code = 404
mock_get.return_value = my_response
self.assertIsNone(utils.get_resource_status('A'))
@mock.patch('requests.delete')
def test_delete_uuid_success(self, mock_delete):
mock_delete.return_value = self.respond(None, 200)
result = utils.delete_uuid('987654321')
self.assertEqual(result, True)
@mock.patch('requests.delete')
def test_delete_uuid_failed(self, mock_delete):
mock_delete.return_value = self.respond("Failed", 500)
result = utils.delete_uuid('987654321')
self.assertEqual(result, False)
@mock.patch('requests.delete', side_effect=SystemError())
def test_delete_uuid_exception(self, mock_delete):
result = utils.delete_uuid('987654321')
self.assertEqual(result, False)

View File

@ -41,8 +41,10 @@ class TestFlavorLogic(FunctionalTest):
error = None
FunctionalTest.tearDown(self)
@patch.object(utils, 'delete_uuid')
@patch.object(flavor_logic, 'FlavorWrapper')
def test_create_flavor_duplicate_entry(self, mock_flavorwrapper):
def test_create_flavor_invalid_model(self, mock_flavorwrapper,
mock_delete):
mock_flavorwrapper.from_db_model.return_value = get_flavor_mock()
global error
error = 31
@ -50,13 +52,15 @@ class TestFlavorLogic(FunctionalTest):
('rds_proxy', get_rds_proxy_mock()))
flavor = get_flavor_mock()
flavor.flavor.validate_model = MagicMock(
side_effect=flavor_logic.ErrorStatus(409, 'Duplicate entry'))
side_effect=flavor_logic.ErrorStatus(400, 'Invalid model'))
self.assertRaises(flavor_logic.ErrorStatus, flavor_logic.create_flavor,
flavor, 'uuid', 'transaction')
@patch.object(utils, 'delete_uuid')
@patch.object(flavor_logic, 'validate_tenants_regions_list')
@patch.object(flavor_logic, 'FlavorWrapper')
def test_create_flavor_success(self, mock_flavorwrapper, mock_validate):
def test_create_flavor_success(self, mock_flavorwrapper, mock_validate,
mock_delete):
mock_flavorwrapper.from_db_model.return_value = get_flavor_mock()
# Flavor is public - test success
@ -345,8 +349,10 @@ class TestFlavorLogic(FunctionalTest):
self.assertRaises(flavor_logic.ErrorStatus, flavor_logic.delete_tags,
'a', None, 'a')
@patch.object(utils, 'delete_uuid')
@patch.object(utils, 'get_resource_status_from_db')
def test_delete_flavor_by_uuid_success(self, mock_get_resource):
def test_delete_flavor_by_uuid_success(self, mock_get_resource,
mock_delete):
global error
error = 10
@ -394,7 +400,7 @@ class TestFlavorLogic(FunctionalTest):
('data_manager', get_datamanager_mock))
# assertRaises NotFoundError when deleting a flavor that doesn't exist
with self.assertRaises(flavor_logic.NotFoundError):
with self.assertRaises(flavor_logic.ErrorStatus):
flavor_logic.delete_flavor_by_uuid('some_id')
def test_delete_flavor_by_uuid_flavor_has_regions(self):

View File

@ -29,7 +29,7 @@ class TestFlavorController(FunctionalTest):
def test_create_flavor(self):
# given
requests.post = MagicMock(return_value=ResponseMock(201, "created"))
requests.post = MagicMock(return_value=ResponseMock(200, "created"))
global return_error
return_error = 0
@ -44,7 +44,7 @@ class TestFlavorController(FunctionalTest):
def test_create_flavor_predefined_id(self):
# given
requests.post = MagicMock(return_value=ResponseMock(201, "created"))
requests.post = MagicMock(return_value=ResponseMock(200, "created"))
test_json = copy.deepcopy(FLAVOR_JSON)
test_json['flavor']['id'] = 'test'
global return_error
@ -81,14 +81,14 @@ class TestFlavorController(FunctionalTest):
return_error = 1
injector.override_injected_dependency(
('flavor_logic', get_flavor_logic_mock()))
requests.post = MagicMock(return_value=ResponseMock(400, "failed"))
requests.post = MagicMock(return_value=ResponseMock(500, "failed"))
# when
response = self.app.post_json('/v1/orm/flavors', FLAVOR_JSON,
expect_errors=True)
# assert
self.assertEqual(response.status_int, 409)
self.assertEqual(response.status_int, 500)
# Following tests not providing consistent results
# @patch.object(flavors, 'di')
@ -128,7 +128,7 @@ class TestFlavorController(FunctionalTest):
return_error = 2
injector.override_injected_dependency(
('flavor_logic', get_flavor_logic_mock()))
requests.post = MagicMock(return_value=ResponseMock(400, "failed"))
requests.post = MagicMock(return_value=ResponseMock(500, "failed"))
mock_err_utils.get_error = test_utils.get_error
# when
@ -136,7 +136,7 @@ class TestFlavorController(FunctionalTest):
expect_errors=True)
# assert
self.assertEqual(response.status_int, 409)
self.assertEqual(response.status_int, 500)
def test_update_flavor(self):
# given

View File

@ -129,9 +129,11 @@ class TestImageLogic(FunctionalTest):
class TestDeleteImageLogic(FunctionalTest):
"""test delete image."""
@mock.patch.object(utils, 'delete_uuid')
@mock.patch.object(utils, 'get_resource_status_from_db')
@mock.patch.object(image_logic, 'di')
def test_delete_image_success(self, mock_di, mock_get_resource):
def test_delete_image_success(self, mock_di, mock_get_resource,
mock_delete):
_, mock_data_manager = get_data_manager_mock(
get_existing_region_names=[])
mock_di.resolver.unpack.return_value = (mock_data_manager)
@ -143,9 +145,11 @@ class TestDeleteImageLogic(FunctionalTest):
image_logic.delete_image_by_uuid("image_uuid", "transaction_id")
@mock.patch.object(utils, 'delete_uuid')
@mock.patch.object(utils, 'get_resource_status_from_db')
@mock.patch.object(image_logic, 'di')
def test_delete_image_success_nords(self, mock_di, mock_get_resource):
def test_delete_image_success_nords(self, mock_di, mock_get_resource,
mock_delete):
_, mock_data_manager = get_data_manager_mock(
get_existing_region_names=[])
mock_di.resolver.unpack.return_value = (mock_data_manager)
@ -365,9 +369,11 @@ class TestCreateImage(FunctionalTest):
result = image_logic.create_image(mock.MagicMock(), 'test1', 'test2')
self.assertEqual('test', result)
@mock.patch.object(utils, 'delete_uuid')
@mock.patch.object(image_logic, 'di')
@mock.patch.object(image_logic, 'ImageWrapper')
def test_create_image_validate_model_failure(self, mock_image, mock_di):
def test_create_image_validate_model_failure(self, mock_image, mock_di,
mock_delete):
image = mock.MagicMock()
image.validate_model.side_effect = ValueError('test')

View File

@ -51,6 +51,20 @@ database = {
'connection_string': 'mysql://root:stack@localhost:3306/orm'
}
authentication = {
"enabled": False,
"mech_id": "admin",
"mech_pass": "xxxxx",
"rms_url": "http://127.0.0.1:8080",
"tenant_name": "admin",
"token_role": "admin",
"role_location": {"tenant": "admin"},
"keystone_version": "3",
"policy_file": "etc/policy.json",
"user_domain_name": "default",
"project_domain_name": "default"
}
# Custom Configurations must be in Python dictionary format::
#
# foo = {'bar':'baz'}

View File

@ -0,0 +1,18 @@
from orm.services.id_generator.uuidgen.utils import authentication
from orm.tests.unit.uuidgen import FunctionalTest
import mock
from pecan import conf
class TestUtil(FunctionalTest):
def setUp(self):
FunctionalTest.setUp(self)
self.mock_response = mock.Mock()
@mock.patch('orm.common.client.keystone.keystone_utils.tokens.TokenConf')
def test_get_token_conf(self, mock_TokenConf):
mock_TokenConf.return_value = 123
token_conf = authentication.get_token_conf(conf)
self.assertEqual(token_conf, 123)

View File

@ -0,0 +1,107 @@
from orm.services.id_generator.uuidgen.controllers.v1 import uuid_controller
from orm.tests.unit.uuidgen import FunctionalTest
from mock import MagicMock, patch
mock_data_manager = None
flow_type = 0
class TestUuidController(FunctionalTest):
def setUp(self):
FunctionalTest.setUp(self)
uuid_controller.authentication = MagicMock()
uuid_controller.DBManager = get_mock_datamanager
global flow_type
flow_type = 0
def tearDown(self):
FunctionalTest.tearDown(self)
@patch.object(uuid_controller, 'utils')
@patch.object(uuid_controller, 'DBManager')
@patch.object(uuid_controller, 'request')
def test_delete_uuid_success(self, mock_request,
mock_dbmanager, mock_utils):
mock_request.headers.get.return_value = 'value'
mock_dbmanager.delete_uuid.return_value = 1
mock_utils.get_region_end_point_from_db.return_value = 'ep'
response = self.app.delete('/v1/uuids/test_uuid')
self.assertEqual(response.status_code, 200)
@patch.object(uuid_controller, 'utils')
@patch.object(uuid_controller, 'DBManager')
@patch.object(uuid_controller, 'request')
def test_delete_uuid_missing_parameter(self, mock_request,
mock_dbmanager, mock_utils):
mock_request.headers.get.return_value = None
mock_utils.get_region_end_point_from_db.return_value = 'ep'
response = self.app.delete('/v1/uuids/test_uuid', expect_errors=True)
self.assertEqual(response.status_code, 400)
@patch.object(uuid_controller, 'utils')
@patch.object(uuid_controller, 'DBManager')
@patch.object(uuid_controller, 'request')
def test_delete_uuid_endpoint_not_found(self, mock_request,
mock_dbmanager, mock_utils):
mock_request.headers.get.return_value = 'value'
mock_utils.get_region_end_point_from_db.return_value = None
response = self.app.delete('/v1/uuids/test_uuid', expect_errors=True)
self.assertEqual(response.status_code, 404)
@patch.object(uuid_controller, 'utils')
@patch.object(uuid_controller, 'DBManager')
@patch.object(uuid_controller, 'request')
def test_delete_uuid_failed_authentication(self, mock_request,
mock_dbmanager, mock_utils):
mock_request.headers.get.return_value = 'value'
mock_utils.get_region_end_point_from_db.return_value = 'ep'
uuid_controller.authentication.authorize.side_effect = SystemError()
response = self.app.delete('/v1/uuids/test_uuid', expect_errors=True)
self.assertEqual(response.status_code, 401)
@patch.object(uuid_controller, 'utils')
@patch.object(uuid_controller, 'request')
def test_delete_uuid_not_found(self, mock_request, mock_utils):
global flow_type
flow_type = 1
mock_request.headers.get.return_value = 'value'
mock_utils.get_region_end_point_from_db.return_value = 'ep'
response = self.app.delete('/v1/uuids/test_uuid', expect_errors=True)
self.assertEqual(response.status_code, 404)
@patch.object(uuid_controller, 'utils')
@patch.object(uuid_controller, 'request')
def test_delete_uuid_database_error(self, mock_request, mock_utils):
global flow_type
flow_type = 2
mock_request.headers.get.return_value = 'value'
mock_utils.get_region_end_point_from_db.return_value = 'ep'
response = self.app.delete('/v1/uuids/test_uuid', expect_errors=True)
self.assertEqual(response.status_code, 500)
def get_mock_datamanager():
global data_manager_mock
data_manager_mock = MagicMock()
if flow_type == 1:
data_manager_mock.delete_uuid.return_value = 0
elif flow_type == 2:
data_manager_mock.delete_uuid.side_effect = SystemError()
return data_manager_mock