Port Private Flavor Tenant python2 logic changes
Change-Id: Icb7aab24f15c7ec970330d84baf03a9c07f00897
This commit is contained in:
parent
b78d9f0f81
commit
2ccdfdf103
@ -59,20 +59,20 @@ class FlavorController(rest.RestController):
|
||||
except ErrorStatus as exception:
|
||||
LOG.log_exception("FlavorController - Failed to CreateFlavor", exception)
|
||||
raise err_utils.get_error(request.transaction_id,
|
||||
message=exception.message,
|
||||
message=str(exception),
|
||||
status_code=exception.status_code)
|
||||
|
||||
except ValueError as exception:
|
||||
LOG.log_exception("FlavorController - Failed to CreateFlavor", exception)
|
||||
raise err_utils.get_error(request.transaction_id,
|
||||
status_code=400,
|
||||
error_details=exception.message)
|
||||
error_details=str(exception))
|
||||
|
||||
except Exception as exception:
|
||||
LOG.log_exception("FlavorController - Failed to CreateFlavor", exception)
|
||||
raise err_utils.get_error(request.transaction_id,
|
||||
status_code=500,
|
||||
error_details=exception.message)
|
||||
error_details=str(exception))
|
||||
|
||||
@wsexpose(FlavorWrapper, str, body=FlavorWrapper, rest_content_types='json')
|
||||
def put(self, flavor_id, flavors):
|
||||
@ -94,7 +94,7 @@ class FlavorController(rest.RestController):
|
||||
except ErrorStatus as exception:
|
||||
LOG.log_exception("FlavorController - Failed to GetFlavorDetails", exception)
|
||||
raise err_utils.get_error(request.transaction_id,
|
||||
message=exception.message,
|
||||
message=str(exception),
|
||||
status_code=exception.status_code)
|
||||
|
||||
except Exception as exception:
|
||||
@ -121,7 +121,7 @@ class FlavorController(rest.RestController):
|
||||
except ErrorStatus as exception:
|
||||
LOG.log_exception("FlavorController - Failed to GetFlavorlist", exception)
|
||||
raise err_utils.get_error(request.transaction_id,
|
||||
message=exception.message,
|
||||
message=str(exception),
|
||||
status_code=exception.status_code)
|
||||
|
||||
except Exception as exception:
|
||||
@ -148,7 +148,7 @@ class FlavorController(rest.RestController):
|
||||
except ErrorStatus as exception:
|
||||
LOG.log_exception("FlavorController - Failed to delete flavor", exception)
|
||||
raise err_utils.get_error(request.transaction_id,
|
||||
message=exception.message,
|
||||
message=str(exception),
|
||||
status_code=exception.status_code)
|
||||
|
||||
except Exception as exception:
|
||||
|
@ -22,7 +22,6 @@ class TenantController(rest.RestController):
|
||||
flavor_logic, utils = di.resolver.unpack(TenantController)
|
||||
LOG.info("TenantController - add tenants: " + str(tenant_wrapper))
|
||||
authentication.authorize(request, 'flavor:add_flavor_tenants')
|
||||
|
||||
try:
|
||||
result = flavor_logic.add_tenants(flavor_id, tenant_wrapper, request.transaction_id)
|
||||
|
||||
@ -34,21 +33,20 @@ class TenantController(rest.RestController):
|
||||
request.headers, flavor_id,
|
||||
event_details=event_details)
|
||||
return result
|
||||
|
||||
except ValueError as exception:
|
||||
LOG.log_exception("TenantController - Failed to add tenants", exception)
|
||||
LOG.log_exception("TenantController - Failed to add tenants", str(exception))
|
||||
raise err_utils.get_error(request.transaction_id,
|
||||
message=exception.message,
|
||||
message=str(exception),
|
||||
status_code=400)
|
||||
|
||||
except ErrorStatus as exception:
|
||||
LOG.log_exception("TenantController - Failed to add tenants", exception)
|
||||
LOG.log_exception("TenantController - Failed to add tenants", str(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("TenantController - Failed to add tenants", exception)
|
||||
LOG.log_exception("TenantController - Failed to add tenants", str(exception))
|
||||
raise err_utils.get_error(request.transaction_id,
|
||||
status_code=500,
|
||||
error_details=str(exception))
|
||||
@ -72,13 +70,13 @@ class TenantController(rest.RestController):
|
||||
event_details=event_details)
|
||||
|
||||
except ErrorStatus as exception:
|
||||
LOG.log_exception("TenantController - Failed to delete tenant", exception)
|
||||
LOG.log_exception("TenantController - Failed to delete tenant", str(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("TenantController - Failed to delete tenant", exception)
|
||||
LOG.log_exception("TenantController - Failed to delete tenant", str(exception))
|
||||
raise err_utils.get_error(request.transaction_id,
|
||||
status_code=500,
|
||||
error_details=str(exception))
|
||||
|
@ -1,7 +1,8 @@
|
||||
import logging
|
||||
|
||||
# from orm.services.flavor_manager.fms_rest.logic.error_base import DuplicateEntityError
|
||||
from orm.services.flavor_manager.fms_rest.data.sql_alchemy.flavor.flavor_record import FlavorRecord
|
||||
from orm.services.flavor_manager.fms_rest.data.sql_alchemy.flavor.\
|
||||
flavor_record import FlavorRecord
|
||||
from oslo_db.sqlalchemy.enginefacade import LegacyEngineFacade
|
||||
|
||||
from pecan import conf
|
||||
@ -86,3 +87,27 @@ class DataManager(object):
|
||||
self.flavor_record = FlavorRecord(self.session)
|
||||
return self.flavor_record
|
||||
return None
|
||||
|
||||
def get_valid_tenant_region_list(self, requested_tenants,
|
||||
requested_regions):
|
||||
|
||||
datamanager = DataManager()
|
||||
# convert tenant and region lists to sql-friendly list format
|
||||
tenants_list = str(tuple(requested_tenants)).rstrip(',)') + ')'
|
||||
regions_list = str(tuple(requested_regions)).rstrip(',)') + ')'
|
||||
|
||||
# --- use sql query for processing time considerations
|
||||
# get valid tenants list for the region(s) by checking
|
||||
# tenant/region status in resource_status table if
|
||||
# status shows 'Success' and operation not 'delete'
|
||||
sql_query = '''select a.uuid, b.name from customer a,
|
||||
cms_region b, customer_region c, resource_status d
|
||||
where c.customer_id = a.id and c.region_id = b.id
|
||||
and d.resource_id = a.uuid and d.region = b.name
|
||||
and ((d.status = 'Success' and d.operation != 'delete')
|
||||
or (d.status = 'Error' and d.operation = 'modify'))
|
||||
and a.uuid in %s and b.name in %s'''
|
||||
|
||||
results = datamanager.session.connection().execute(sql_query % (tenants_list, regions_list)).fetchall()
|
||||
|
||||
return results
|
||||
|
@ -334,8 +334,6 @@ class Flavor(Base, FMSBaseModel):
|
||||
if self.visibility == "public" and len(self.flavor_tenants) > 0:
|
||||
raise ValueError(
|
||||
"tenants should not be specified for a public flavor")
|
||||
elif self.visibility == "private" and len(self.flavor_tenants) == 0:
|
||||
raise ValueError("Tenants must be specified for a private flavor")
|
||||
elif self.visibility not in ["private", "public"]:
|
||||
raise ValueError(
|
||||
"Flavor visibility can be 'public' or 'private',"
|
||||
|
@ -18,6 +18,35 @@ LOG = get_logger(__name__)
|
||||
di = injector.get_di()
|
||||
|
||||
|
||||
def validate_tenants_regions_list(requested_tenants, requested_regions,
|
||||
action, datamanager):
|
||||
regions_list, tenants_list = [], []
|
||||
results = datamanager.get_valid_tenant_region_list(requested_tenants,
|
||||
requested_regions)
|
||||
|
||||
valid_tenants_list, valid_regions_list = [], []
|
||||
|
||||
# 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))
|
||||
|
||||
# second element in the results tuple is the region - compile the region
|
||||
# data into valid_regions_list and eliminate duplicates from the list
|
||||
valid_regions_list = [x[1] for x in results]
|
||||
valid_regions_list = list(dict.fromkeys(valid_regions_list))
|
||||
|
||||
# update the tenants list with validated tenants from query results
|
||||
# and will be reflected in the create/get flavor as well as
|
||||
# add/ tenant responses
|
||||
requested_tenants = valid_tenants_list
|
||||
requested_regions = valid_regions_list
|
||||
|
||||
return requested_tenants, requested_regions
|
||||
|
||||
|
||||
@di.dependsOn('data_manager')
|
||||
def create_flavor(flavor, flavor_uuid, transaction_id):
|
||||
DataManager = di.resolver.unpack(create_flavor)
|
||||
@ -31,6 +60,22 @@ def create_flavor(flavor, flavor_uuid, transaction_id):
|
||||
flavor.flavor.name = calculate_name(flavor)
|
||||
|
||||
LOG.debug("Flavor name is [{}] ".format(flavor.flavor.name))
|
||||
flavor_regions = []
|
||||
for region in flavor.flavor.regions:
|
||||
flavor_regions.append(region.name)
|
||||
|
||||
# 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.flavor.visibility == 'private':
|
||||
valid_tenants_list, valid_regions_list = \
|
||||
validate_tenants_regions_list(flavor.flavor.tenants,
|
||||
# flavor.flavor.regions,
|
||||
flavor_regions,
|
||||
'create', datamanager)
|
||||
# replace the original tenant list in the private flavor
|
||||
# with the valid_tenants_list
|
||||
flavor.flavor.tenants = valid_tenants_list
|
||||
|
||||
sql_flavor = flavor.to_db_model()
|
||||
|
||||
@ -217,6 +262,7 @@ def add_regions(flavor_uuid, regions, transaction_id):
|
||||
|
||||
existing_region_names = sql_flavor.get_existing_region_names()
|
||||
|
||||
flvr_tenant_list, flvr_region_list = [], []
|
||||
for region in regions.regions:
|
||||
if region.name == '' or region.name.isspace():
|
||||
raise ErrorStatus(400, 'Cannot add region with an empty name')
|
||||
@ -227,10 +273,25 @@ def add_regions(flavor_uuid, regions, transaction_id):
|
||||
db_region = FlavorRegion(region_name=region.name,
|
||||
region_type='single')
|
||||
sql_flavor.add_region(db_region)
|
||||
flvr_region_list.append(region.name)
|
||||
|
||||
# get any exception created by previous actions against the database
|
||||
datamanager.flush()
|
||||
|
||||
# private flavor new logic
|
||||
# validate tenants assigned to the flavor
|
||||
for tenant in sql_flavor.flavor_tenants:
|
||||
flvr_tenant_list.append(tenant.tenant_id)
|
||||
|
||||
valid_tenants_list, valid_regions_list = \
|
||||
validate_tenants_regions_list(flvr_tenant_list,
|
||||
flvr_region_list,
|
||||
'create', datamanager)
|
||||
# update tenant list
|
||||
for tenant in flvr_tenant_list:
|
||||
if tenant not in valid_tenants_list:
|
||||
sql_flavor.remove_tenant(tenant)
|
||||
|
||||
send_to_rds_if_needed(
|
||||
sql_flavor, existing_region_names, "put", transaction_id)
|
||||
|
||||
@ -298,6 +359,8 @@ 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)
|
||||
@ -309,6 +372,21 @@ def add_tenants(flavor_uuid, tenants, transaction_id):
|
||||
raise ErrorStatus(405, 'Cannot add tenant to a public flavor')
|
||||
|
||||
existing_region_names = sql_flavor.get_existing_region_names()
|
||||
existing_region_list = []
|
||||
|
||||
for x in existing_region_names:
|
||||
existing_region_list.append(x)
|
||||
if tenants.tenants:
|
||||
valid_tenants_list, valid_regions_list = \
|
||||
validate_tenants_regions_list(tenants.tenants,
|
||||
existing_region_list,
|
||||
'create', datamanager)
|
||||
# replace tenants.tenants with only the valid tenants
|
||||
tenants.tenants = valid_tenants_list
|
||||
|
||||
# issue error message if tenant list is empty
|
||||
if not tenants.tenants:
|
||||
raise ValueError("At least one valid tenant must be provided")
|
||||
|
||||
for tenant in tenants.tenants:
|
||||
if not isinstance(tenant, str):
|
||||
@ -357,11 +435,6 @@ def delete_tenant(flavor_uuid, tenant_id, transaction_id):
|
||||
raise ValueError("{} is a public flavor, delete tenant"
|
||||
" action is not relevant".format(flavor_uuid))
|
||||
|
||||
if len(sql_flavor.flavor_tenants) == 1 \
|
||||
and sql_flavor.flavor_tenants[0].tenant_id == tenant_id:
|
||||
raise ValueError(
|
||||
'Private flavor must have at least one tenant')
|
||||
|
||||
existing_region_names = sql_flavor.get_existing_region_names()
|
||||
sql_flavor.remove_tenant(tenant_id)
|
||||
# get any exception created by previous actions against the database
|
||||
|
@ -2,6 +2,8 @@
|
||||
import logging
|
||||
import time
|
||||
|
||||
from orm.services.flavor_manager.fms_rest.data.sql_alchemy.data_manager \
|
||||
import DataManager
|
||||
from orm.services.resource_distributor.rds.services import region_resource_id_status as regionResourceIdStatus
|
||||
from orm.services.resource_distributor.rds.services import (yaml_customer_builder, yaml_flavor_builder,
|
||||
yaml_group_builder, yaml_image_builder)
|
||||
@ -79,6 +81,27 @@ def _set_all_statuses_to_error(input_data, message=None):
|
||||
status="Error")
|
||||
|
||||
|
||||
def get_valid_tenants(tenants, region):
|
||||
# identify valid tenants for a particular region and save in
|
||||
# valid_tenants_list; if no tenants validated return empty list
|
||||
requested_tenants, valid_tenants_list = [], []
|
||||
for tenant in tenants:
|
||||
requested_tenants.append(tenant['tenant_id'])
|
||||
requested_region = [region]
|
||||
|
||||
datamanager = DataManager()
|
||||
customer_region = datamanager.get_record('customer_region')
|
||||
results = datamanager.get_valid_tenant_region_list(
|
||||
requested_tenants, requested_region)
|
||||
|
||||
for x in results:
|
||||
valid_tenants_list.append(x[0])
|
||||
# prep result_tenant_list from result_rows and remove NoneTypes from list
|
||||
valid_tenants_list = filter(None, valid_tenants_list)
|
||||
|
||||
return valid_tenants_list
|
||||
|
||||
|
||||
def _create_data_to_sot(input_data):
|
||||
"""create data.
|
||||
|
||||
@ -102,7 +125,29 @@ def _create_data_to_sot(input_data):
|
||||
elif input_data.resource_type == "group":
|
||||
yamldata = yaml_group_builder.yamlbuilder(jsondata, target)
|
||||
elif input_data.resource_type == "flavor":
|
||||
if input_data.model['visibility'] == 'private':
|
||||
ok_tenants_list = []
|
||||
ok_tenants = {}
|
||||
|
||||
# skip tenant validation if tenants list is empty
|
||||
if input_data.model['tenants']:
|
||||
valid_tenants_list = get_valid_tenants(
|
||||
input_data.model['tenants'], target['name'])
|
||||
|
||||
for tenant in valid_tenants_list:
|
||||
ok_tenants['tenant_id'] = tenant
|
||||
ok_tenants_list.append(ok_tenants.copy())
|
||||
|
||||
# Note: If ok_tenant_list is empty, just create heat template
|
||||
# for private flavor with empty tenant list
|
||||
if not ok_tenants_list:
|
||||
ok_tenants['tenant_id'] = None
|
||||
ok_tenants_list.append(ok_tenants.copy())
|
||||
jsondata['tenants'] = ok_tenants_list
|
||||
|
||||
# now issue yamldata for flavor either public or private
|
||||
yamldata = yaml_flavor_builder.yamlbuilder(jsondata, target)
|
||||
|
||||
elif input_data.resource_type == "image":
|
||||
yamldata = yaml_image_builder.yamlbuilder(jsondata, target)
|
||||
targetslist.append({"region_id": target['name'],
|
||||
|
@ -52,7 +52,8 @@ def yamlbuilder(alldata, region):
|
||||
extra_specs[key] = value
|
||||
# Handle tenants
|
||||
for tenant in alldata['tenants']:
|
||||
tenants.append(tenant['tenant_id'])
|
||||
if tenant['tenant_id']:
|
||||
tenants.append(tenant['tenant_id'])
|
||||
|
||||
# Generate the output
|
||||
resources['resources'] = {}
|
||||
|
@ -52,29 +52,43 @@ class TestFlavorLogic(FunctionalTest):
|
||||
self.assertRaises(flavor_logic.ErrorStatus, flavor_logic.create_flavor,
|
||||
flavor, 'uuid', 'transaction')
|
||||
|
||||
@patch.object(flavor_logic, 'validate_tenants_regions_list')
|
||||
@patch.object(flavor_logic, 'FlavorWrapper')
|
||||
def test_create_flavor_success(self, mock_flavorwrapper):
|
||||
def test_create_flavor_success(self, mock_flavorwrapper, mock_validate):
|
||||
mock_flavorwrapper.from_db_model.return_value = get_flavor_mock()
|
||||
|
||||
# Flavor is public - test success
|
||||
flavor = get_flavor_mock()
|
||||
flavor.flavor.visibility = 'public'
|
||||
global error
|
||||
error = 31
|
||||
injector.override_injected_dependency(
|
||||
('rds_proxy', get_rds_proxy_mock()))
|
||||
res_flavor = flavor_logic.create_flavor(get_flavor_mock(), 'uuid',
|
||||
res_flavor = flavor_logic.create_flavor(flavor, 'uuid',
|
||||
'transaction')
|
||||
mock_validate.assert_not_called()
|
||||
self.assertEqual(res_flavor.flavor.profile, 'N1')
|
||||
self.assertEqual(res_flavor.flavor.ram, '1024')
|
||||
self.assertEqual(res_flavor.flavor.vcpus, '1')
|
||||
self.assertEqual(res_flavor.flavor.series, cfg.CONF.fms.flavor_series[0])
|
||||
self.assertEqual(res_flavor.flavor.id, 'g')
|
||||
|
||||
# Test that flavor validate model works by passing bad swap value
|
||||
flavor = get_flavor_mock()
|
||||
flavor.flavor.swap = '1024000'
|
||||
self.assertRaises(flavor_logic.ErrorStatus, flavor_logic.create_flavor,
|
||||
flavor, 'uuid', 'transaction')
|
||||
|
||||
# Flavor is private - test success
|
||||
flavor.flavor.validate_model = MagicMock()
|
||||
flavor.flavor.visibility = 'private'
|
||||
flavor.flavor.tenants = ['1234']
|
||||
flavor.flavor.regions = [Region(name='test_region')]
|
||||
mock_validate.return_value = [['1234'], ['rgn1']]
|
||||
|
||||
res_flavor = flavor_logic.create_flavor(flavor, 'uuid',
|
||||
'transaction')
|
||||
mock_validate.assert_called()
|
||||
self.assertEqual(res_flavor.flavor.profile, 'N1')
|
||||
self.assertEqual(res_flavor.flavor.ram, '1024')
|
||||
self.assertEqual(res_flavor.flavor.vcpus, '1')
|
||||
@ -582,16 +596,6 @@ class TestFlavorLogic(FunctionalTest):
|
||||
'tenant_id',
|
||||
'transaction')
|
||||
|
||||
global FLAVOR_MOCK
|
||||
tenant = MagicMock()
|
||||
tenant.tenant_id = 'tenant_id'
|
||||
FLAVOR_MOCK.flavor_tenants = [tenant]
|
||||
error = 6
|
||||
self.assertRaises(ValueError,
|
||||
flavor_logic.delete_tenant, 'uuid',
|
||||
'tenant_id',
|
||||
'transaction')
|
||||
|
||||
@patch.object(flavor_logic, 'send_to_rds_if_needed')
|
||||
@patch.object(flavor_logic, 'get_flavor_by_uuid')
|
||||
@patch.object(models, 'request')
|
||||
|
Loading…
x
Reference in New Issue
Block a user