Merge "Additional changes to private flavors"
This commit is contained in:
commit
93d0818457
@ -111,3 +111,14 @@ class DataManager(object):
|
||||
results = datamanager.session.connection().execute(sql_query % (tenants_list, regions_list)).fetchall()
|
||||
|
||||
return results
|
||||
|
||||
def get_valid_tenant_list(self, requested_tenants):
|
||||
# validate if tenants in list exist in customer table
|
||||
|
||||
datamanager = DataManager()
|
||||
# convert tenant and region lists to sql-friendly list format
|
||||
tenants_list = str(tuple(requested_tenants)).rstrip(',)') + ')'
|
||||
sql_query = '''select uuid from customer where uuid in %s'''
|
||||
valid_tenants_list = datamanager.session.connection().execute(sql_query % (tenants_list)).fetchall()
|
||||
|
||||
return valid_tenants_list
|
||||
|
@ -346,6 +346,13 @@ class Flavor(Base, FMSBaseModel):
|
||||
|
||||
return existing_region_names
|
||||
|
||||
def get_existing_tenant_ids(self):
|
||||
existing_tenant_ids = []
|
||||
for tenant in self.flavor_tenants:
|
||||
existing_tenant_ids.append(tenant.tenant_id)
|
||||
|
||||
return existing_tenant_ids
|
||||
|
||||
|
||||
'''
|
||||
' FlavorExtraSpec is a DataObject contains all fields defined in
|
||||
|
@ -14,26 +14,32 @@ from orm.common.orm_common.utils import utils
|
||||
from oslo_config import cfg
|
||||
import oslo_db
|
||||
|
||||
|
||||
LOG = get_logger(__name__)
|
||||
|
||||
di = injector.get_di()
|
||||
|
||||
|
||||
def format_tenant_list(tenant_region_list):
|
||||
# x[0] is the first element (tenant) in the tenant_region_list of tuples
|
||||
# compile all the tenants and delete the NoneTypes from the tenant list
|
||||
result_tenant_list = [x[0] for x in tenant_region_list if x[0]]
|
||||
|
||||
# clean up valid_tenants_list by removing duplicate items
|
||||
valid_tenants_list = list(dict.fromkeys(result_tenant_list))
|
||||
|
||||
return valid_tenants_list
|
||||
|
||||
|
||||
def validate_tenants_regions_list(requested_tenants, requested_regions,
|
||||
action, datamanager):
|
||||
regions_list, tenants_list = [], []
|
||||
datamanager):
|
||||
valid_tenants_list, valid_regions_list = [], []
|
||||
results = datamanager.get_valid_tenant_region_list(requested_tenants,
|
||||
requested_regions)
|
||||
|
||||
valid_tenants_list, valid_regions_list = [], []
|
||||
|
||||
if results:
|
||||
# the first element in the results tuple is the tenant prep
|
||||
# result_tenant_list from result_rows and remove NoneTypes from list
|
||||
result_tenant_list = [x[0] for x in results]
|
||||
result_tenant_list = filter(None, result_tenant_list)
|
||||
# lastly clean up valid_tenants_list list by removing duplicate items
|
||||
valid_tenants_list = list(dict.fromkeys(result_tenant_list))
|
||||
# first element in the results tuple is the tenant
|
||||
valid_tenants_list = format_tenant_list(results)
|
||||
|
||||
# second element in the results tuple is the region - compile the
|
||||
# region data into valid_regions_list and eliminate duplicates
|
||||
@ -63,18 +69,23 @@ def create_flavor(flavor, flavor_uuid, transaction_id):
|
||||
|
||||
# Execute the following logic only if at least one region AND one
|
||||
# tenant are provided in a private flavor:
|
||||
# Validate which tenants from the original tenants list to
|
||||
# be assigned to the private flavor; if no valid tenants
|
||||
# found, the valid_tenants_list will return empty list
|
||||
if (flavor_regions and flavor.flavor.visibility == 'private' and
|
||||
flavor.flavor.tenants):
|
||||
valid_tenants_list, valid_regions_list = \
|
||||
validate_tenants_regions_list(flavor.flavor.tenants,
|
||||
flavor_regions,
|
||||
'create', datamanager)
|
||||
# identify which tenants from requested tenants list to be assigned
|
||||
# to private flavor given the requested regions list; if no tenant
|
||||
# identified, the valid_tenants_list will return empty list
|
||||
if flavor_regions and flavor.flavor.visibility == 'private':
|
||||
if flavor.flavor.tenants:
|
||||
valid_tenants_list, valid_regions_list = \
|
||||
validate_tenants_regions_list(flavor.flavor.tenants,
|
||||
flavor_regions, datamanager)
|
||||
|
||||
# replace the original tenant list in the private flavor
|
||||
# with the valid_tenants_list
|
||||
flavor.flavor.tenants = valid_tenants_list
|
||||
else:
|
||||
# disallow tenant assignment if no flavor region assigned
|
||||
if flavor.flavor.tenants:
|
||||
raise ErrorStatus(
|
||||
400, 'Cannot add tenants with no flavor region assigned ')
|
||||
|
||||
sql_flavor = flavor.to_db_model()
|
||||
|
||||
@ -268,12 +279,17 @@ def add_regions(flavor_uuid, regions, transaction_id):
|
||||
# private flavor new logic
|
||||
# validate tenants assigned to the flavor
|
||||
for tenant in sql_flavor.flavor_tenants:
|
||||
flvr_tenant_list.append(tenant.tenant_id)
|
||||
flvr_tenant_list = sql_flavor.get_existing_tenant_ids()
|
||||
|
||||
# existing_region_names = db_flavor.get_existing_region_names()
|
||||
# add existing flavor regions to flvr_region_list in order for
|
||||
# the validate_tenants_regions_list to process correctly
|
||||
flvr_region_list = sql_flavor.get_existing_region_names()
|
||||
|
||||
valid_tenants_list, valid_regions_list = \
|
||||
validate_tenants_regions_list(flvr_tenant_list,
|
||||
flvr_region_list,
|
||||
'create', datamanager)
|
||||
flvr_region_list, datamanager)
|
||||
|
||||
# update tenant list
|
||||
for tenant in flvr_tenant_list:
|
||||
if tenant not in valid_tenants_list:
|
||||
@ -289,7 +305,7 @@ def add_regions(flavor_uuid, regions, transaction_id):
|
||||
return ret
|
||||
|
||||
except ErrorStatus as exp:
|
||||
LOG.log_exception("FlavorLogic - Failed to update flavor", str(exp))
|
||||
LOG.log_exception("FlavorLogic - Failed to add regions", str(exp))
|
||||
datamanager.rollback()
|
||||
raise exp
|
||||
except Exception as exp:
|
||||
@ -303,11 +319,52 @@ def add_regions(flavor_uuid, regions, transaction_id):
|
||||
datamanager.close()
|
||||
|
||||
|
||||
def delete_orphaned_tenants(sql_flavor, remaining_regions, datamanager):
|
||||
# this function deletes all 'orphaned tenants' - i.e., tenants that
|
||||
# are no longer associated with regions still assigned to the flavor
|
||||
|
||||
try:
|
||||
# get existing tenants_list and orig_regions_list BEFORE remove_region
|
||||
existing_tenants_list = sql_flavor.get_existing_tenant_ids()
|
||||
|
||||
valid_tenants_list, valid_regions_list = [], []
|
||||
# use 'remaining_regions' to identify the valid tenants list
|
||||
# for all regions assigned to flavor MINUS the deleted region
|
||||
if remaining_regions and existing_tenants_list:
|
||||
valid_tenants_list, valid_regions_list = \
|
||||
validate_tenants_regions_list(existing_tenants_list,
|
||||
remaining_regions,
|
||||
datamanager)
|
||||
|
||||
# remove orphaned tenants identified
|
||||
if valid_tenants_list:
|
||||
for tenant in existing_tenants_list:
|
||||
if tenant not in valid_tenants_list:
|
||||
sql_flavor.remove_tenant(tenant)
|
||||
else:
|
||||
if existing_tenants_list:
|
||||
for tenant in existing_tenants_list:
|
||||
sql_flavor.remove_tenant(tenant)
|
||||
|
||||
datamanager.flush() # get any exception from remove_tenant action
|
||||
datamanager.commit()
|
||||
|
||||
except ErrorStatus as exp:
|
||||
LOG.log_exception("FlavorLogic - Failed to remove tenant", str(exp))
|
||||
datamanager.rollback()
|
||||
raise exp
|
||||
|
||||
except Exception as exp:
|
||||
LOG.log_exception(
|
||||
"FlavorLogic - Failed to remove tenant - exception:", str(exp))
|
||||
datamanager.rollback()
|
||||
raise exp
|
||||
|
||||
|
||||
@di.dependsOn('data_manager')
|
||||
def delete_region(flavor_uuid, region_name, transaction_id, force_delete):
|
||||
DataManager = di.resolver.unpack(delete_region)
|
||||
datamanager = DataManager()
|
||||
|
||||
try:
|
||||
flavor_rec = datamanager.get_record('flavor')
|
||||
sql_flavor = flavor_rec.get_flavor_by_id(flavor_uuid)
|
||||
@ -317,26 +374,33 @@ def delete_region(flavor_uuid, region_name, transaction_id, force_delete):
|
||||
|
||||
existing_region_names = sql_flavor.get_existing_region_names()
|
||||
sql_flavor.remove_region(region_name)
|
||||
remaining_regions = sql_flavor.get_existing_region_names()
|
||||
|
||||
# get any exception created by previous actions against the database
|
||||
datamanager.flush()
|
||||
|
||||
send_to_rds_if_needed(sql_flavor, existing_region_names, "put",
|
||||
transaction_id)
|
||||
|
||||
if force_delete:
|
||||
datamanager.commit()
|
||||
else:
|
||||
datamanager.rollback()
|
||||
|
||||
except ErrorStatus as exp:
|
||||
LOG.log_exception("FlavorLogic - Failed to update flavor", str(exp))
|
||||
LOG.log_exception("FlavorLogic - Failed to delete region", str(exp))
|
||||
datamanager.rollback()
|
||||
raise exp
|
||||
|
||||
except Exception as exp:
|
||||
LOG.log_exception("FlavorLogic - Failed to delete region", str(exp))
|
||||
LOG.log_exception(
|
||||
"FlavorLogic - Failed to delete region - exception:", str(exp))
|
||||
datamanager.rollback()
|
||||
raise exp
|
||||
|
||||
else:
|
||||
delete_orphaned_tenants(sql_flavor, remaining_regions, datamanager)
|
||||
|
||||
finally:
|
||||
datamanager.close()
|
||||
|
||||
@ -345,9 +409,6 @@ def delete_region(flavor_uuid, region_name, transaction_id, force_delete):
|
||||
def add_tenants(flavor_uuid, tenants, transaction_id):
|
||||
DataManager = di.resolver.unpack(add_tenants)
|
||||
datamanager = DataManager()
|
||||
|
||||
valid_tenants_list, valid_regions_list = [], []
|
||||
|
||||
try:
|
||||
flavor_rec = datamanager.get_record('flavor')
|
||||
sql_flavor = flavor_rec.get_flavor_by_id(flavor_uuid)
|
||||
@ -358,32 +419,42 @@ def add_tenants(flavor_uuid, tenants, transaction_id):
|
||||
if sql_flavor.visibility == "public":
|
||||
raise ErrorStatus(405, 'Cannot add tenant to a public flavor')
|
||||
|
||||
existing_region_names = sql_flavor.get_existing_region_names()
|
||||
existing_region_list = []
|
||||
existing_region_list = sql_flavor.get_existing_region_names()
|
||||
|
||||
for x in existing_region_names:
|
||||
existing_region_list.append(x)
|
||||
# remove any empty strings in tenants list
|
||||
while ('' in tenants.tenants):
|
||||
tenants.tenants.remove('')
|
||||
|
||||
if tenants.tenants:
|
||||
valid_tenants_list, valid_regions_list = \
|
||||
validate_tenants_regions_list(tenants.tenants,
|
||||
existing_region_list,
|
||||
'create', datamanager)
|
||||
for tenant in tenants.tenants:
|
||||
if not isinstance(tenant, str):
|
||||
raise ValueError("tenant type must be a string type,"
|
||||
" got {} type".format(type(tenant)))
|
||||
|
||||
if not valid_tenants_list:
|
||||
if existing_region_list:
|
||||
# get lists of valid tenants/regions from CMS
|
||||
valid_tenants_list, valid_regions_list = \
|
||||
validate_tenants_regions_list(tenants.tenants,
|
||||
existing_region_list,
|
||||
datamanager)
|
||||
else:
|
||||
# disallow tenant assignment if no flavor region assigned
|
||||
raise ErrorStatus(
|
||||
400, 'Cannot add tenants with no flavor region assigned')
|
||||
|
||||
if not (tenants.tenants and valid_tenants_list):
|
||||
raise ValueError("At least one valid tenant must be provided")
|
||||
|
||||
for tenant in valid_tenants_list:
|
||||
if not isinstance(tenant, str):
|
||||
raise ValueError("tenant type must be a string type,"
|
||||
" got {} type".format(type(tenant)))
|
||||
|
||||
db_tenant = FlavorTenant(tenant_id=tenant)
|
||||
sql_flavor.add_tenant(db_tenant)
|
||||
|
||||
send_to_rds_if_needed(
|
||||
sql_flavor, existing_region_list, "put", transaction_id)
|
||||
|
||||
# get any exception created by previous actions against the database
|
||||
datamanager.flush()
|
||||
send_to_rds_if_needed(
|
||||
sql_flavor, existing_region_names, "put", transaction_id)
|
||||
|
||||
datamanager.commit()
|
||||
|
||||
flavor = get_flavor_by_uuid(flavor_uuid)
|
||||
@ -391,7 +462,7 @@ def add_tenants(flavor_uuid, tenants, transaction_id):
|
||||
return ret
|
||||
|
||||
except (ErrorStatus, ValueError) as exp:
|
||||
LOG.log_exception("FlavorLogic - Failed to update flavor", str(exp))
|
||||
LOG.log_exception("FlavorLogic - Failed to add tenants", str(exp))
|
||||
datamanager.rollback()
|
||||
raise
|
||||
except Exception as exp:
|
||||
@ -408,14 +479,13 @@ def add_tenants(flavor_uuid, tenants, transaction_id):
|
||||
def delete_tenant(flavor_uuid, tenant_id, transaction_id):
|
||||
DataManager = di.resolver.unpack(delete_tenant)
|
||||
datamanager = DataManager()
|
||||
|
||||
try:
|
||||
flavor_rec = datamanager.get_record('flavor')
|
||||
sql_flavor = flavor_rec.get_flavor_by_id(flavor_uuid)
|
||||
if not sql_flavor:
|
||||
raise ErrorStatus(404,
|
||||
'flavor id {0} not found'.format(flavor_uuid))
|
||||
# if trying to delete the only one tenant then return value error
|
||||
|
||||
if sql_flavor.visibility == "public":
|
||||
raise ValueError("{} is a public flavor, delete tenant"
|
||||
" action is not relevant".format(flavor_uuid))
|
||||
@ -756,7 +826,6 @@ def get_flavor_by_uuid(flavor_uuid):
|
||||
datamanager = DataManager()
|
||||
try:
|
||||
flavor_record = datamanager.get_record('flavor')
|
||||
|
||||
sql_flavor = flavor_record.get_flavor_by_id(flavor_uuid)
|
||||
|
||||
if not sql_flavor:
|
||||
|
@ -508,10 +508,11 @@ class TestFlavorLogic(FunctionalTest):
|
||||
ret_flavor = MagicMock()
|
||||
tenants = ['test_tenant']
|
||||
ret_flavor.flavor.tenants = tenants
|
||||
ret_flavor.flavor.regions = [Region(name='test_region')]
|
||||
mock_gfbu.return_value = ret_flavor
|
||||
mock_val.return_value = ['test_tenant'], ['test_region']
|
||||
global error
|
||||
error = 31
|
||||
error = 3
|
||||
injector.override_injected_dependency(
|
||||
('rds_proxy', get_rds_proxy_mock()))
|
||||
|
||||
@ -546,7 +547,6 @@ class TestFlavorLogic(FunctionalTest):
|
||||
TenantWrapper(tenants),
|
||||
'transaction')
|
||||
|
||||
# test that no valid tenant found
|
||||
error = 31
|
||||
mock_val.return_value = [], ['test_region']
|
||||
self.assertRaises(ValueError,
|
||||
@ -554,6 +554,7 @@ class TestFlavorLogic(FunctionalTest):
|
||||
TenantWrapper(tenants),
|
||||
'transaction')
|
||||
|
||||
error = 3
|
||||
mock_val.return_value = ['test_tenant'], ['test_region']
|
||||
mock_strin.side_effect = exc.FlushError(
|
||||
'conflicts with persistent instance')
|
||||
|
Loading…
x
Reference in New Issue
Block a user