Merge "Performance enhancement of v2 list APIs"

This commit is contained in:
Zuul
2024-09-09 18:43:39 +00:00
committed by Gerrit Code Review
16 changed files with 453 additions and 283 deletions

View File

@@ -50,16 +50,14 @@ def lcmocc_task_href(lcmocc_id, task, endpoint):
def make_lcmocc_links(lcmocc, endpoint):
links = objects.VnfLcmOpOccV2_Links()
links.self = objects.Link(href=lcmocc_href(lcmocc.id, endpoint))
links.vnfInstance = objects.Link(
href=inst_utils.inst_href(lcmocc.vnfInstanceId, endpoint))
links.retry = objects.Link(
href=lcmocc_task_href(lcmocc.id, 'retry', endpoint))
links.rollback = objects.Link(
href=lcmocc_task_href(lcmocc.id, 'rollback', endpoint))
links.fail = objects.Link(
href=lcmocc_task_href(lcmocc.id, 'fail', endpoint))
links = {'self': {'href': lcmocc_href(lcmocc['id'], endpoint)}}
links['vnfInstance'] = {
'href': inst_utils.inst_href(lcmocc['vnfInstanceId'], endpoint)}
links['retry'] = {
'href': lcmocc_task_href(lcmocc['id'], 'retry', endpoint)}
links['rollback'] = {
'href': lcmocc_task_href(lcmocc['id'], 'rollback', endpoint)}
links['fail'] = {'href': lcmocc_task_href(lcmocc['id'], 'fail', endpoint)}
# TODO(oda-g): add when implemented
# links.grant
# links.cancel

View File

@@ -41,17 +41,15 @@ def inst_href(inst_id, endpoint):
def make_inst_links(inst, endpoint):
links = objects.VnfInstanceV2_Links()
self_href = inst_href(inst.id, endpoint)
links.self = objects.Link(href=self_href)
if inst.instantiationState == 'NOT_INSTANTIATED':
links.instantiate = objects.Link(href=self_href + "/instantiate")
self_href = inst_href(inst['id'], endpoint)
links = {'self': {'href': self_href}}
if inst['instantiationState'] == 'NOT_INSTANTIATED':
links['instantiate'] = {'href': self_href + "/instantiate"}
else: # 'INSTANTIATED'
links.terminate = objects.Link(href=self_href + "/terminate")
links.scale = objects.Link(href=self_href + "/scale")
links.heal = objects.Link(href=self_href + "/heal")
links.changeExtConn = objects.Link(href=self_href + "/change_ext_conn")
links.changeVnfPkg = objects.Link(href=self_href + "/change_vnfpkg")
links['terminate'] = {'href': self_href + "/terminate"}
links['scale'] = {'href': self_href + "/scale"}
links['heal'] = {'href': self_href + "/heal"}
links['changeExtConn'] = {'href': self_href + "/change_ext_conn"}
# NOTE: add when the operation supported
return links

View File

@@ -44,8 +44,10 @@ class VnfFmControllerV1(sol_wsgi.SolAPIController):
def __init__(self):
self.nfvo_client = nfvo_client.NfvoClient()
self.endpoint = CONF.v2_vnfm.endpoint
self._fm_view = vnffm_view.AlarmViewBuilder(self.endpoint)
self._subsc_view = vnffm_view.FmSubscriptionViewBuilder(self.endpoint)
self._fm_view = vnffm_view.AlarmViewBuilder(self.endpoint,
CONF.v2_vnfm.vnffm_alarm_page_size)
self._subsc_view = vnffm_view.FmSubscriptionViewBuilder(self.endpoint,
CONF.v2_vnfm.subscription_page_size)
def supported_api_versions(self, action):
return api_version.v1_fm_versions
@@ -61,15 +63,7 @@ class VnfFmControllerV1(sol_wsgi.SolAPIController):
return ['application/json', 'text/plain']
def index(self, request):
filter_param = request.GET.get('filter')
if filter_param is not None:
filters = self._fm_view.parse_filter(filter_param)
else:
filters = None
page_size = CONF.v2_vnfm.vnffm_alarm_page_size
pager = self._fm_view.parse_pager(request, page_size)
filters, _, pager = self._fm_view.parse_query_params(request)
alarms = fm_alarm_utils.get_alarms_all(request.context,
marker=pager.marker)
@@ -142,15 +136,7 @@ class VnfFmControllerV1(sol_wsgi.SolAPIController):
location=self_href)
def subscription_list(self, request):
filter_param = request.GET.get('filter')
if filter_param is not None:
filters = self._subsc_view.parse_filter(filter_param)
else:
filters = None
page_size = CONF.v2_vnfm.subscription_page_size
pager = self._subsc_view.parse_pager(request, page_size)
filters, _, pager = self._subsc_view.parse_query_params(request)
subscs = fm_subsc_utils.get_subsc_all(request.context,
marker=pager.marker)

View File

@@ -27,10 +27,9 @@ CONF = config.CONF
class AlarmViewBuilder(base_view.BaseViewBuilder):
_EXCLUDE_DEFAULT = []
def __init__(self, endpoint):
self.endpoint = endpoint
def parse_selector(self, req):
# no selector in the API
return None
def detail(self, alarm, selector=None):
# NOTE: _links is not saved in DB. create when it is necessary.
@@ -39,14 +38,13 @@ class AlarmViewBuilder(base_view.BaseViewBuilder):
resp = alarm.to_dict()
if selector is not None:
resp = selector.filter(alarm, resp)
return resp
class FmSubscriptionViewBuilder(base_view.BaseViewBuilder):
def __init__(self, endpoint):
self.endpoint = endpoint
def parse_selector(self, req):
# no selector in the API
return None
def detail(self, subsc, selector=None):
# NOTE: _links is not saved in DB. create when it is necessary.
@@ -60,6 +58,4 @@ class FmSubscriptionViewBuilder(base_view.BaseViewBuilder):
# NOTE: authentication is not included in FmSubscriptionV1
resp.pop('authentication', None)
if selector is not None:
resp = selector.filter(subsc, resp)
return resp

View File

@@ -47,9 +47,12 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
self.nfvo_client = nfvo_client.NfvoClient()
self.endpoint = CONF.v2_vnfm.endpoint
self.conductor_rpc = conductor_rpc_v2.VnfLcmRpcApiV2()
self._inst_view = vnflcm_view.InstanceViewBuilder(self.endpoint)
self._lcmocc_view = vnflcm_view.LcmOpOccViewBuilder(self.endpoint)
self._subsc_view = vnflcm_view.SubscriptionViewBuilder(self.endpoint)
self._inst_view = vnflcm_view.InstanceViewBuilder(self.endpoint,
CONF.v2_vnfm.vnf_instance_page_size)
self._lcmocc_view = vnflcm_view.LcmOpOccViewBuilder(self.endpoint,
CONF.v2_vnfm.lcm_op_occ_page_size)
self._subsc_view = vnflcm_view.SubscriptionViewBuilder(self.endpoint,
CONF.v2_vnfm.subscription_page_size)
def api_versions(self, request):
return sol_wsgi.SolResponse(200, api_version.supported_versions_v2)
@@ -113,27 +116,19 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
return sol_wsgi.SolResponse(201, resp_body, location=location)
def index(self, request):
filter_param = request.GET.get('filter')
if filter_param is not None:
filters = self._inst_view.parse_filter(filter_param)
else:
filters = None
# validate_filter
filters, selector, pager = self._inst_view.parse_query_params(request)
selector = self._inst_view.parse_selector(request.GET)
pager = self._inst_view.parse_pager(request)
insts = inst_utils.get_inst_all(request.context,
marker=pager.marker)
# NOTE: insts is dict
insts = self._inst_view.get_dict_all(request.context, filters,
selector, pager)
if config.CONF.oslo_policy.enhanced_tacker_policy:
insts = [inst for inst in insts if request.context.can(
POLICY_NAME.format('index'),
target=self._get_policy_target(inst),
target=self._get_policy_target_dict(inst),
fatal=False)]
resp_body = self._inst_view.detail_list(insts, filters,
selector, pager)
resp_body = self._inst_view.detail_dict_list(insts, filters,
selector, pager)
return sol_wsgi.SolResponse(200, resp_body, link=pager.get_link())
@@ -216,27 +211,26 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
return sol_wsgi.SolResponse(202, None, location=location)
def _get_policy_target(self, vnf_instance):
vendor = vnf_instance.vnfProvider
return self._get_policy_target_dict(vnf_instance.to_dict())
if vnf_instance.instantiationState == 'NOT_INSTANTIATED':
def _get_policy_target_dict(self, inst_dict):
vendor = inst_dict['vnfProvider']
if inst_dict['instantiationState'] == 'NOT_INSTANTIATED':
area = '*'
tenant = '*'
else:
vim_type = None
area = None
if vnf_instance.obj_attr_is_set('vimConnectionInfo'):
for _, vim_conn_info in vnf_instance.vimConnectionInfo.items():
area = vim_conn_info.get('extra', {}).get('area')
vim_type = vim_conn_info.vimType
if area and vim_type:
break
for vim_conn_info in inst_dict.get(
'vimConnectionInfo', {}).values():
area = vim_conn_info.get('extra', {}).get('area')
vim_type = vim_conn_info['vimType']
if area and vim_type:
break
tenant = None
if (vnf_instance.obj_attr_is_set('instantiatedVnfInfo') and
vnf_instance.instantiatedVnfInfo.obj_attr_is_set(
'metadata')):
tenant = (vnf_instance.instantiatedVnfInfo
.metadata.get('tenant'))
tenant = inst_dict.get('instantiatedVnfInfo', {}).get(
'metadata', {}).get('tenant')
target = {
'vendor': vendor,
@@ -508,13 +502,7 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
return sol_wsgi.SolResponse(201, resp_body, location=self_href)
def subscription_list(self, request):
filter_param = request.GET.get('filter')
if filter_param is not None:
filters = self._subsc_view.parse_filter(filter_param)
else:
filters = None
pager = self._subsc_view.parse_pager(request)
filters, _, pager = self._subsc_view.parse_query_params(request)
subscs = subsc_utils.get_subsc_all(request.context,
marker=pager.marker)
@@ -539,21 +527,14 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
return sol_wsgi.SolResponse(204, None)
def lcm_op_occ_list(self, request):
filter_param = request.GET.get('filter')
if filter_param is not None:
filters = self._lcmocc_view.parse_filter(filter_param)
else:
filters = None
filters, selector, pager = self._lcmocc_view.parse_query_params(
request)
selector = self._lcmocc_view.parse_selector(request.GET)
lcmoccs = self._lcmocc_view.get_dict_all(request.context, filters,
selector, pager)
pager = self._lcmocc_view.parse_pager(request)
lcmoccs = lcmocc_utils.get_lcmocc_all(request.context,
marker=pager.marker)
resp_body = self._lcmocc_view.detail_list(lcmoccs, filters,
selector, pager)
resp_body = self._lcmocc_view.detail_dict_list(lcmoccs, filters,
selector, pager)
return sol_wsgi.SolResponse(200, resp_body, link=pager.get_link())

View File

@@ -26,6 +26,8 @@ from tacker.sol_refactored.common import lcm_op_occ_utils as lcmocc_utils
from tacker.sol_refactored.common import subscription_utils as subsc_utils
from tacker.sol_refactored.common import vnf_instance_utils as inst_utils
from tacker.sol_refactored import objects
from tacker.sol_refactored.objects.v2 import vnf_instance
from tacker.sol_refactored.objects.v2 import vnf_lcm_op_occ
LOG = logging.getLogger(__name__)
@@ -96,7 +98,6 @@ class FilterExpr(object):
raise sol_ex.InvalidAttributeFilter(
sol_detail="AttrName %s is invalid" % '/'.join([
str(x) for x in self.attr]))
LOG.debug("Key %s type %s", self.attr, type(val))
# If not str, assume type conversion is already done.
# Note: It is assumed that the type doesn't change between calls,
# which can be problematic with KeyValuePairs.
@@ -209,6 +210,88 @@ class AttributeSelector(object):
return odict
class EnhanceAttributeSelector(object):
def __init__(self, all_attrs, mandatory_attrs, default_exclude_attrs,
all_fields=None, fields=None, exclude_fields=None,
exclude_default=None):
self.all_attrs = all_attrs
self.return_attrs = set()
self.exclude_fields = set()
self.fields = set()
self.extra_attrs = set()
if all_fields is not None:
if fields is not None or exclude_fields is not None or \
exclude_default is not None:
raise sol_ex.InvalidAttributeSelector()
self.return_attrs = all_attrs.copy()
elif fields is not None:
if exclude_fields is not None:
raise sol_ex.InvalidAttributeSelector()
if exclude_default is not None:
self.return_attrs = all_attrs - default_exclude_attrs
else:
self.return_attrs = mandatory_attrs.copy()
for field in fields.split(','):
if '/' in field:
self.fields.add(field)
self.return_attrs.add(field.split('/')[0])
elif exclude_fields is not None:
if exclude_default is not None:
raise sol_ex.InvalidAttributeSelector()
self.return_attrs = all_attrs.copy()
for field in exclude_fields.split(','):
if '/' in field:
self.exclude_fields.add(field)
else:
self.return_attrs.remove(field)
else:
self.return_attrs = all_attrs - default_exclude_attrs
def add_extra_attrs(self, attrs):
self.extra_attrs |= attrs - self.return_attrs
def filter(self, odict):
for attr in self.extra_attrs:
if attr in odict:
del odict[attr]
for attr in self.exclude_fields:
klist = attr.split('/')
if len(klist) == 1:
# not occur. just consistency check
continue
sub_dict = odict
for key in klist[:-1]:
sub_dict = sub_dict.get(key, {})
if sub_dict.get(klist[-1]) is not None:
del sub_dict[klist[-1]]
saved = {}
for attr in self.fields:
klist = attr.split('/')
if len(klist) == 1:
# not occur. just consistency check
continue
if klist[0] not in saved:
saved[klist[0]] = odict[klist[0]]
del odict[klist[0]]
# construct
sub_dict = odict
saved_sub_dict = saved
# first check path is valid
for key in klist[:-1]:
saved_sub_dict = saved_sub_dict.get(key, {})
val = saved_sub_dict.get(klist[-1])
if val is None:
continue
for key in klist[:-1]:
sub_dict = sub_dict.setdefault(key, {})
sub_dict[klist[-1]] = val
return odict
class BaseViewBuilder(object):
value_regexp = r"([^',)]+|('[^']*')+)"
value_re = re.compile(value_regexp)
@@ -218,8 +301,9 @@ class BaseViewBuilder(object):
opOne = ['eq', 'neq', 'gt', 'gte', 'lt', 'lte']
opMulti = ['in', 'nin', 'cont', 'ncont']
def __init__(self):
pass
def __init__(self, endpoint, page_size):
self.endpoint = endpoint
self.page_size = page_size
def parse_attr(self, attr):
def tilde_unescape(string):
@@ -264,6 +348,9 @@ class BaseViewBuilder(object):
def parse_filter(self, filter):
"""Implement SOL013 5.2 Attribute-based filtering"""
if filter is None:
return []
loc = 0
res = []
while True:
@@ -302,25 +389,26 @@ class BaseViewBuilder(object):
return AttributeSelector(self._EXCLUDE_DEFAULT, **params)
def match_filters(self, val, filters):
if filters is None:
return True
for f in filters:
if not f.match(val):
return False
return True
def parse_pager(self, request, page_size):
def parse_pager(self, request):
"""Implement SOL013 5.4 Handling of large query results"""
marker = request.GET.get('nextpage_opaque_marker')
req_url = request.url
return Pager(marker, req_url, page_size)
return Pager(marker, req_url, self.page_size)
def detail_list(self, values, filters, selector, pager):
resp_body = [self.detail(v, selector) for v in values
if self.match_filters(v, filters)]
def parse_query_params(self, request):
filters = self.parse_filter(request.GET.get('filter'))
selector = self.parse_selector(request.GET)
pager = self.parse_pager(request)
return filters, selector, pager
def _handle_pager(self, pager, resp_body):
if pager.page_size == 0:
pager.next_marker = None
return resp_body
@@ -332,72 +420,146 @@ class BaseViewBuilder(object):
pager.next_marker = None
return resp_body
def detail_list(self, values, filters, selector, pager):
resp_body = [self.detail(v, selector) for v in values
if self.match_filters(v, filters)]
return self._handle_pager(pager, resp_body)
class InstanceViewBuilder(BaseViewBuilder):
_EXCLUDE_DEFAULT = ['vnfConfigurableProperties',
class EnhanceViewBuilder(BaseViewBuilder):
def parse_selector(self, req):
"""Implement SOL013 5.3 Attribute selectors"""
params = {}
for k in ['all_fields', 'fields', 'exclude_fields', 'exclude_default']:
v = req.get(k)
if v is not None:
params[k] = v
return EnhanceAttributeSelector(self._ALL, self._MANDATORY,
self._EXCLUDE_DEFAULT, **params)
def get_dict_all(self, context, filters, selector, pager):
# calc db fields
extra_attrs = set()
db_filters = []
rm_filters = []
for item in filters:
if item.attr[0] not in selector.all_attrs:
# never match
return []
extra_attrs.add(item.attr[0])
# NOTE: cont and ncont are not supported at the moment.
if len(item.attr) == 1 and item.op not in ['cont', 'ncont']:
if item.op in self.opOne:
db_filters.append(
(item.op, item.attr[0], item.values[0]))
else: # opMulti
db_filters.append(
(item.op, item.attr[0], item.values))
rm_filters.append(item)
for item in rm_filters:
filters.remove(item)
selector.add_extra_attrs(extra_attrs)
attrs = selector.return_attrs | selector.extra_attrs
limit = None
if (pager.page_size > 0 and len(filters) == 0 and
len(selector.extra_attrs) == 0):
# short cut. set limit if no filtering need later.
# NOTE: +1 to find there are more data
limit = pager.page_size + 1
if pager.marker:
db_filters.append(('gt', 'id', pager.marker))
return self.obj_cls.get_dict_all(context, attrs, db_filters, limit)
def detail_dict_list(self, values, filters, selector, pager):
if filters:
resp_body = [self.detail_dict(v, selector) for v in values
if self.match_filters(v, filters)]
else:
# short cut a bit
resp_body = [self.detail_dict(v, selector) for v in values]
return self._handle_pager(pager, resp_body)
class InstanceViewBuilder(EnhanceViewBuilder):
_ALL = {'id',
'vnfInstanceName',
'vnfInstanceDescription',
'vnfdId',
'vnfProvider',
'vnfProductName',
'vnfSoftwareVersion',
'vnfdVersion',
'instantiationState',
'vnfConfigurableProperties',
'vimConnectionInfo',
'instantiatedVnfInfo',
'metadata',
'extensions'}
_EXCLUDE_DEFAULT = {'vnfConfigurableProperties',
'vimConnectionInfo',
'instantiatedVnfInfo',
'metadata',
'extensions']
'extensions'}
_MANDATORY = _ALL - _EXCLUDE_DEFAULT
obj_cls = vnf_instance.VnfInstanceV2
def __init__(self, endpoint):
self.endpoint = endpoint
def parse_filter(self, filter):
return super().parse_filter(filter)
def parse_pager(self, request):
page_size = CONF.v2_vnfm.vnf_instance_page_size
return super().parse_pager(request, page_size)
def parse_selector(self, request):
selector = super().parse_selector(request)
if config.CONF.oslo_policy.enhanced_tacker_policy:
selector.add_extra_attrs({'vimConnectionInfo',
'instantiatedVnfInfo'})
return selector
def detail(self, inst, selector=None):
# NOTE: _links is not saved in DB. create when it is necessary.
if not inst.obj_attr_is_set('_links'):
inst._links = inst_utils.make_inst_links(inst, self.endpoint)
return self.detail_dict(inst.to_dict(), selector)
resp = inst.to_dict()
def detail_dict(self, inst, selector):
# NOTE: _links is not saved in DB.
inst['_links'] = inst_utils.make_inst_links(inst, self.endpoint)
if selector is not None:
inst = selector.filter(inst)
# remove credential data from vim_connection_info
# see SOL003 4.4.1.6
cred_data = ['password', 'bearer_token', 'client_secret']
for vim_info in resp.get('vimConnectionInfo', {}).values():
for vim_info in inst.get('vimConnectionInfo', {}).values():
if 'accessInfo' in vim_info:
for cred_key in cred_data:
if cred_key in vim_info['accessInfo']:
vim_info['accessInfo'].pop(cred_key)
if selector is not None:
resp = selector.filter(inst, resp)
return resp
def detail_list(self, insts, filters, selector, pager):
return super().detail_list(insts, filters, selector, pager)
return inst
class LcmOpOccViewBuilder(BaseViewBuilder):
_EXCLUDE_DEFAULT = ['operationParams',
class LcmOpOccViewBuilder(EnhanceViewBuilder):
_ALL = {'id',
'operationState',
'stateEnteredTime',
'startTime',
'vnfInstanceId',
'grantId',
'operation',
'isAutomaticInvocation',
'operationParams',
'isCancelPending',
'cancelMode',
'error',
'resourceChanges',
'changedInfo',
'changedExtConnectivity',
'modificationsTriggeredByVnfPkgChange',
'vnfSnapshotInfoId'}
_EXCLUDE_DEFAULT = {'operationParams',
'error',
'resourceChanges',
'changedInfo',
'changedExtConnectivity']
def __init__(self, endpoint):
self.endpoint = endpoint
def parse_filter(self, filter):
return super().parse_filter(filter)
def parse_pager(self, request):
page_size = CONF.v2_vnfm.lcm_op_occ_page_size
return super().parse_pager(request, page_size)
def detail(self, lcmocc, selector=None):
# NOTE: _links is not saved in DB. create when it is necessary.
if not lcmocc.obj_attr_is_set('_links'):
lcmocc._links = lcmocc_utils.make_lcmocc_links(lcmocc,
self.endpoint)
resp = lcmocc.to_dict()
'changedExtConnectivity'}
_MANDATORY = _ALL - _EXCLUDE_DEFAULT
obj_cls = vnf_lcm_op_occ.VnfLcmOpOccV2
def _pop_cred(self, resp):
op_param = resp.get('operationParams', {})
cred_data = ['password', 'bearer_token', 'client_secret']
for vim_info in op_param.get('vimConnectionInfo', {}).values():
@@ -425,30 +587,31 @@ class LcmOpOccViewBuilder(BaseViewBuilder):
.pop('clientPassword'))
changed_info = resp.get('changedInfo', {})
if changed_info:
for vim_info in changed_info.get('vimConnectionInfo', {}).values():
for cred_key in cred_data:
if cred_key in vim_info['accessInfo']:
vim_info['accessInfo'].pop(cred_key)
for vim_info in changed_info.get('vimConnectionInfo', {}).values():
for cred_key in cred_data:
if cred_key in vim_info['accessInfo']:
vim_info['accessInfo'].pop(cred_key)
def detail(self, lcmocc, selector=None):
return self.detail_dict(lcmocc.to_dict(), selector)
def detail_dict(self, lcmocc, selector):
# NOTE: _links is not saved in DB.
lcmocc['_links'] = lcmocc_utils.make_lcmocc_links(lcmocc,
self.endpoint)
if selector is not None:
resp = selector.filter(lcmocc, resp)
return resp
lcmocc = selector.filter(lcmocc)
def detail_list(self, lcmoccs, filters, selector, pager):
return super().detail_list(lcmoccs, filters, selector, pager)
# remove credential data
self._pop_cred(lcmocc)
return lcmocc
class SubscriptionViewBuilder(BaseViewBuilder):
def __init__(self, endpoint):
self.endpoint = endpoint
def parse_filter(self, filter):
return super().parse_filter(filter)
def parse_pager(self, request):
page_size = CONF.v2_vnfm.subscription_page_size
return super().parse_pager(request, page_size)
def parse_selector(self, req):
# no selector in the API
return None
def detail(self, subsc, selector=None):
# NOTE: _links is not saved in DB. create when it is necessary.
@@ -462,8 +625,6 @@ class SubscriptionViewBuilder(BaseViewBuilder):
# NOTE: authentication is not included in LccnSubscription
resp.pop('authentication', None)
if selector is not None:
resp = selector.filter(subsc, resp)
return resp
def detail_list(self, subscs, filters, pager):

View File

@@ -94,9 +94,11 @@ class VnfPmControllerV2(sol_wsgi.SolAPIController):
def __init__(self):
self.nfvo_client = nfvo_client.NfvoClient()
self.endpoint = CONF.v2_vnfm.endpoint
self._pm_job_view = vnfpm_view.PmJobViewBuilder(self.endpoint)
self._pm_job_view = vnfpm_view.PmJobViewBuilder(self.endpoint,
CONF.v2_vnfm.vnfpm_pmjob_page_size)
self._pm_threshold_view = (
vnfpm_view.PmThresholdViewBuilder(self.endpoint))
vnfpm_view.PmThresholdViewBuilder(self.endpoint,
CONF.v2_vnfm.vnfpm_pmthreshold_page_size))
cls = plugin.get_class(
CONF.prometheus_plugin.performance_management_package,
CONF.prometheus_plugin.performance_management_class)
@@ -200,16 +202,8 @@ class VnfPmControllerV2(sol_wsgi.SolAPIController):
location=location)
def index(self, request):
filter_param = request.GET.get('filter')
if filter_param is not None:
filters = self._pm_job_view.parse_filter(filter_param)
else:
filters = None
# validate_filter
selector = self._pm_job_view.parse_selector(request.GET)
page_size = CONF.v2_vnfm.vnfpm_pmjob_page_size
pager = self._pm_job_view.parse_pager(request, page_size)
filters, selector, pager = self._pm_job_view.parse_query_params(
request)
pm_job = pm_job_utils.get_pm_job_all(request.context,
marker=pager.marker)
resp_body = self._pm_job_view.detail_list(pm_job, filters,
@@ -372,12 +366,8 @@ class VnfPmControllerV2(sol_wsgi.SolAPIController):
location=location)
def index_threshold(self, request):
filter_param = request.GET.get('filter')
filters = (self._pm_threshold_view.parse_filter(filter_param)
if filter_param else None)
page_size = CONF.v2_vnfm.vnfpm_pmthreshold_page_size
pager = self._pm_threshold_view.parse_pager(request, page_size)
filters, _, pager = self._pm_threshold_view.parse_query_params(
request)
pm_job = pm_threshold_utils.get_pm_threshold_all(request.context,
marker=pager.marker)
resp_body = self._pm_threshold_view.detail_list(pm_job, filters,

View File

@@ -28,9 +28,6 @@ CONF = config.CONF
class PmJobViewBuilder(base_view.BaseViewBuilder):
_EXCLUDE_DEFAULT = []
def __init__(self, endpoint):
self.endpoint = endpoint
def detail(self, pm_job, selector=None):
# NOTE: _links is not saved in DB. create when it is necessary.
if not pm_job.obj_attr_is_set('_links'):
@@ -56,10 +53,9 @@ class PmJobViewBuilder(base_view.BaseViewBuilder):
class PmThresholdViewBuilder(base_view.BaseViewBuilder):
_EXCLUDE_DEFAULT = []
def __init__(self, endpoint):
self.endpoint = endpoint
def parse_selector(self, req):
# no selector in the API
return None
def detail(self, threshold, selector=None):
# NOTE: _links is not saved in DB. create when it is necessary.
@@ -70,6 +66,4 @@ class PmThresholdViewBuilder(base_view.BaseViewBuilder):
resp = threshold.to_dict()
resp.pop('authentication', None)
resp.pop('metadata', None)
if selector is not None:
resp = selector.filter(threshold, resp)
return resp

View File

@@ -399,6 +399,58 @@ class TackerPersistentObject(TackerObject):
result = query.all()
return [cls.from_db_obj(item) for item in result]
@classmethod
@db_api.context_manager.reader
def get_dict_all(cls, context, attrs, filters, limit):
model_cls = getattr(models, cls.__name__)
args = []
for attr in attrs:
args.append(getattr(model_cls, get_model_field(attr)))
query = context.session.query(*args)
if filters:
args = []
for op, attr, val in filters:
column = getattr(model_cls, get_model_field(attr))
if op == 'eq':
args.append(column.__eq__(val))
elif op == 'neq':
args.append(column.__ne__(val))
elif op == 'lt':
args.append(column.__lt__(val))
elif op == 'gt':
args.append(column.__gt__(val))
elif op == 'gte':
args.append(column.__ge__(val))
elif op == 'lte':
args.append(column.__le__(val))
elif op == 'in':
args.append(column.in_(val))
elif op == 'nin':
args.append(column.not_in(val))
query = query.filter(*args)
if limit is not None:
query = query.limit(limit)
result = query.all()
ret = [item._asdict() for item in result]
json_attrs = [attr for attr in attrs
if str(getattr(model_cls, get_model_field(attr)).type) == 'JSON']
for item in ret:
for attr in attrs:
attr_ = get_model_field(attr)
val = item[attr_]
if val is None:
del item[attr_]
continue
if attr != attr_:
item[attr] = val
del item[attr_]
# convert to dict if its type is JSON.
if attr in json_attrs and isinstance(val, str):
# NOTE: It is str normally but there is a case it is
# already dict.
item[attr] = jsonutils.loads(val)
return ret
@classmethod
def from_db_obj(cls, db_obj):
inst = cls()

View File

@@ -437,8 +437,6 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
for inst in body:
self.assertIn('vnfInstanceName', inst)
self.assertIn('vnfInstanceDescription', inst)
self.assertIn('vimConnectionInfo', inst)
self.assertIn('instantiatedVnfInfo', inst)
self.assertIn('metadata', inst)
@@ -450,24 +448,20 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
for inst in body:
self.assertNotIn('vnfInstanceName', inst)
self.assertNotIn('vnfInstanceDescription', inst)
self.assertNotIn('vimConnectionInfo', inst)
self.assertNotIn('instantiatedVnfInfo', inst)
self.assertIn('metadata', inst)
# * exclude_fields=<list>
# -> check the attribute specified in "exclude_fields" is not set
filter_expr = {'filter': f'(eq,id,{inst_id})',
'exclude_fields': 'vnfInstanceName'}
'exclude_fields': 'metadata'}
resp, body = self.list_vnf_instance(filter_expr)
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
for inst in body:
self.assertNotIn('vnfInstanceName', inst)
self.assertIn('vnfInstanceDescription', inst)
self.assertIn('vimConnectionInfo', inst)
self.assertIn('instantiatedVnfInfo', inst)
self.assertIn('metadata', inst)
self.assertNotIn('metadata', inst)
# * exclude_default
# -> check the attribute omitted in "exclude_default" is not set.
filter_expr = {'filter': f'(eq,id,{inst_id})',
@@ -476,8 +470,6 @@ class CommonVnfLcmTest(base_v2.BaseSolV2Test):
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
for inst in body:
self.assertIn('vnfInstanceName', inst)
self.assertIn('vnfInstanceDescription', inst)
self.assertNotIn('vimConnectionInfo', inst)
self.assertNotIn('instantiatedVnfInfo', inst)
self.assertNotIn('metadata', inst)

View File

@@ -411,8 +411,6 @@ class IndividualVnfcMgmtBasicTest(base_v2.BaseSolV2Test):
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
for inst in body:
self.assertIn('vnfInstanceName', inst)
self.assertIn('vnfInstanceDescription', inst)
self.assertIn('vimConnectionInfo', inst)
self.assertIn('instantiatedVnfInfo', inst)
self.assertIn('metadata', inst)
@@ -424,24 +422,20 @@ class IndividualVnfcMgmtBasicTest(base_v2.BaseSolV2Test):
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
for inst in body:
self.assertNotIn('vnfInstanceName', inst)
self.assertNotIn('vnfInstanceDescription', inst)
self.assertNotIn('vimConnectionInfo', inst)
self.assertNotIn('instantiatedVnfInfo', inst)
self.assertIn('metadata', inst)
# * exclude_fields=<list>
# -> check the attribute specified in "exclude_fields" is not set
filter_expr = {'filter': f'(eq,id,{inst_id})',
'exclude_fields': 'vnfInstanceName'}
'exclude_fields': 'metadata'}
resp, body = self.list_vnf_instance(filter_expr)
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
for inst in body:
self.assertNotIn('vnfInstanceName', inst)
self.assertIn('vnfInstanceDescription', inst)
self.assertIn('vimConnectionInfo', inst)
self.assertIn('instantiatedVnfInfo', inst)
self.assertIn('metadata', inst)
self.assertNotIn('metadata', inst)
# * exclude_default
# -> check the attribute omitted in "exclude_default" is not set.
filter_expr = {'filter': f'(eq,id,{inst_id})',
@@ -450,8 +444,6 @@ class IndividualVnfcMgmtBasicTest(base_v2.BaseSolV2Test):
self.assertEqual(200, resp.status_code)
self.check_resp_headers_in_get(resp)
for inst in body:
self.assertIn('vnfInstanceName', inst)
self.assertIn('vnfInstanceDescription', inst)
self.assertNotIn('vimConnectionInfo', inst)
self.assertNotIn('instantiatedVnfInfo', inst)
self.assertNotIn('metadata', inst)

View File

@@ -2419,27 +2419,26 @@ class TestLcmOpOccUtils(base.BaseTestCase):
def test_make_lcmocc_links(self):
lcmocc = objects.VnfLcmOpOccV2(
id='test-1', vnfInstanceId='instance-1', operation='INSTANTIATE')
lcmocc = lcmocc.to_dict()
endpoint = 'http://127.0.0.1:9890'
expected_result = objects.VnfLcmOpOccV2_Links()
expected_result.self = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc.id}')
expected_result.vnfInstance = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_instances/{lcmocc.vnfInstanceId}')
expected_result.retry = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc.id}/retry')
expected_result.rollback = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc.id}/rollback')
expected_result.fail = objects.Link(
href=f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc.id}/fail')
lcmocc_id = lcmocc['id']
inst_id = lcmocc['vnfInstanceId']
h_self = f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc_id}'
h_inst = f'{endpoint}/vnflcm/v2/vnf_instances/{inst_id}'
h_retry = f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc_id}/retry'
h_rback = f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc_id}/rollback'
h_fail = f'{endpoint}/vnflcm/v2/vnf_lcm_op_occs/{lcmocc_id}/fail'
expected_result = {
'self': {'href': h_self},
'vnfInstance': {'href': h_inst},
'retry': {'href': h_retry},
'rollback': {'href': h_rback},
'fail': {'href': h_fail}
}
result = lcmocc_utils.make_lcmocc_links(lcmocc, endpoint)
self.assertEqual(expected_result.self.href, result.self.href)
self.assertEqual(expected_result.vnfInstance.href,
result.vnfInstance.href)
self.assertEqual(expected_result.retry.href, result.retry.href)
self.assertEqual(expected_result.rollback.href, result.rollback.href)
self.assertEqual(expected_result.fail.href, result.fail.href)
self.assertEqual(expected_result, result)
def test_make_lcmocc_notif_data(self):
subsc_short = objects.LccnSubscriptionV2(

View File

@@ -488,48 +488,48 @@ def get_test_data_policy_index():
area='area_A@region_A', tenant='tenant_A')
# OK
test_data.append({
'vnf_instance_list': [inst_1],
'vnf_instance_list': [inst_1.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A',
'TENANT_tenant_A'],
'expected_vnf_inst_ids': [inst_1.id]
})
test_data.append({
'vnf_instance_list': [inst_1],
'vnf_instance_list': [inst_1.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': ['AREA_all@all', 'VENDOR_all', 'TENANT_all'],
'expected_vnf_inst_ids': [inst_1.id]
})
test_data.append({
'vnf_instance_list': [inst_1],
'vnf_instance_list': [inst_1.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': ['AREA_all@region_A', 'VENDOR_all', 'TENANT_all'],
'expected_vnf_inst_ids': [inst_1.id]
})
# wrong region role
test_data.append({
'vnf_instance_list': [inst_1],
'vnf_instance_list': [inst_1.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': ['AREA_all@region_B', 'VENDOR_all', 'TENANT_all'],
'expected_vnf_inst_ids': []
})
# wrong area role
test_data.append({
'vnf_instance_list': [inst_1],
'vnf_instance_list': [inst_1.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': ['AREA_area_B@region_A', 'VENDOR_provider_A', 'TENANT_all'],
'expected_vnf_inst_ids': []
})
# wrong vendor role
test_data.append({
'vnf_instance_list': [inst_1],
'vnf_instance_list': [inst_1.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': ['AREA_area_A@region_A', 'VENDOR_provider_B', 'TENANT_all'],
'expected_vnf_inst_ids': []
})
# wrong tenant role
test_data.append({
'vnf_instance_list': [inst_1],
'vnf_instance_list': [inst_1.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A', 'TENANT_B'],
'expected_vnf_inst_ids': []
@@ -539,7 +539,7 @@ def get_test_data_policy_index():
'ETSINFV.OPENSTACK_KEYSTONE.V_3', 'INSTANTIATED', 'provider_A',
tenant='tenant_A')
test_data.append({
'vnf_instance_list': [inst_2],
'vnf_instance_list': [inst_2.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A'],
'expected_vnf_inst_ids': []
@@ -549,7 +549,7 @@ def get_test_data_policy_index():
'ETSINFV.OPENSTACK_KEYSTONE.V_3', 'NOT_INSTANTIATED', 'provider_A',
tenant='tenant_A')
test_data.append({
'vnf_instance_list': [inst_3],
'vnf_instance_list': [inst_3.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': ['VENDOR_provider_A'],
'expected_vnf_inst_ids': [inst_3.id]
@@ -560,7 +560,7 @@ def get_test_data_policy_index():
tenant='namespace_A')
# OK
test_data.append({
'vnf_instance_list': [inst_4],
'vnf_instance_list': [inst_4.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': [
'AREA_area_A@region_A',
@@ -569,7 +569,7 @@ def get_test_data_policy_index():
'expected_vnf_inst_ids': [inst_4.id]
})
test_data.append({
'vnf_instance_list': [inst_4],
'vnf_instance_list': [inst_4.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': [
'AREA_all@region_A',
@@ -578,7 +578,7 @@ def get_test_data_policy_index():
'expected_vnf_inst_ids': [inst_4.id]
})
test_data.append({
'vnf_instance_list': [inst_4],
'vnf_instance_list': [inst_4.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': [
'AREA_all@all',
@@ -588,7 +588,7 @@ def get_test_data_policy_index():
})
# wrong region role
test_data.append({
'vnf_instance_list': [inst_4],
'vnf_instance_list': [inst_4.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': [
'AREA_all@region_B',
@@ -598,7 +598,7 @@ def get_test_data_policy_index():
})
# wrong region role
test_data.append({
'vnf_instance_list': [inst_4],
'vnf_instance_list': [inst_4.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': [
'AREA_area_B@region_A',
@@ -608,7 +608,7 @@ def get_test_data_policy_index():
})
# wrong vendor role
test_data.append({
'vnf_instance_list': [inst_4],
'vnf_instance_list': [inst_4.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': [
'AREA_area_A@region_A',
@@ -618,7 +618,7 @@ def get_test_data_policy_index():
})
# wrong namespace
test_data.append({
'vnf_instance_list': [inst_4],
'vnf_instance_list': [inst_4.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': [
'AREA_all@all',
@@ -630,7 +630,7 @@ def get_test_data_policy_index():
inst_5 = make_vnf_instance(
'kubernetes', 'INSTANTIATED', 'provider_A', area='area_A@region_A')
test_data.append({
'vnf_instance_list': [inst_5],
'vnf_instance_list': [inst_5.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': [
'AREA_area_A@region_A',
@@ -642,7 +642,7 @@ def get_test_data_policy_index():
'kubernetes', 'NOT_INSTANTIATED', 'provider_A')
# OK
test_data.append({
'vnf_instance_list': [inst_6],
'vnf_instance_list': [inst_6.to_dict()],
'rules': rule_area_vendor_tenant,
'roles': [
'VENDOR_provider_A',
@@ -761,14 +761,15 @@ class TestVnflcmV2(db_base.SqlTestCase):
result = self.controller.create(request=self.request, body=body)
self.assertEqual(201, result.status)
@mock.patch.object(inst_utils, 'get_inst_all')
def test_index(self, mock_inst):
def test_index(self):
request = requests.Request()
request.context = self.context
request.GET = {'filter': f'(eq,vnfdId,{SAMPLE_VNFD_ID})'}
mock_inst.return_value = [objects.VnfInstanceV2(
inst = objects.VnfInstanceV2(
id='inst-1', vnfdId=SAMPLE_VNFD_ID,
instantiationState='NOT_INSTANTIATED')]
instantiationState='NOT_INSTANTIATED')
self.controller._inst_view.get_dict_all = mock.Mock(
return_value=[inst.to_dict()])
result = self.controller.index(request)
self.assertEqual(200, result.status)
@@ -1251,15 +1252,16 @@ class TestVnflcmV2(db_base.SqlTestCase):
request=self.request, id='subsc-1')
self.assertEqual(204, result.status)
@mock.patch.object(lcmocc_utils, 'get_lcmocc_all')
def test_lcm_op_occ_list(self, mock_lcmocc):
def test_lcm_op_occ_list(self):
request = requests.Request()
request.context = self.context
request.GET = {
'filter': f'(eq,operation,'
f'{fields.LcmOperationType.INSTANTIATE})'}
mock_lcmocc.return_value = [objects.VnfLcmOpOccV2(
id='lcmocc-1', operation='INSTANTIATE', vnfInstanceId='inst-1')]
lcmocc = objects.VnfLcmOpOccV2(
id='lcmocc-1', operation='INSTANTIATE', vnfInstanceId='inst-1')
self.controller._lcmocc_view.get_dict_all = mock.Mock(
return_value=[lcmocc.to_dict()])
result = self.controller.lcm_op_occ_list(request)
self.assertEqual(200, result.status)
@@ -2350,11 +2352,11 @@ class TestVnflcmV2EnhancedPolicy(TestVnflcmV2):
@ddt.data(*get_test_data_policy_index())
@ddt.unpack
@mock.patch.object(inst_utils, 'get_inst_all')
def test_index_enhanced_policy(self, mock_inst, vnf_instance_list,
def test_index_enhanced_policy(self, vnf_instance_list,
rules, roles, expected_vnf_inst_ids):
self._overwrite_policy(rules)
mock_inst.return_value = vnf_instance_list
self.controller._inst_view.get_dict_all = mock.Mock(
return_value=vnf_instance_list)
request = self._fake_request(roles)
request.GET = {}

View File

@@ -141,10 +141,37 @@ class TestAttributeSelector(base.BaseTestCase):
self.assertEqual(r, {'bar': 2, 'baz': 3})
class TestEnhanceAttributeSelector(base.BaseTestCase):
def test_filter_extra_attrs(self):
selector = vnflcm_view.EnhanceAttributeSelector(
{'foo', 'bar'}, {'foo', 'bar'}, set())
selector.add_extra_attrs({'baz'})
r = selector.filter({'foo': 1, 'bar': 2, 'baz': 3})
self.assertEqual(r, {'foo': 1, 'bar': 2})
def test_filter_exclude_fields(self):
selector = vnflcm_view.EnhanceAttributeSelector(
{'aaa'}, set(), set(), exclude_fields='aaa/foo,ccc/bar')
r = selector.filter({'aaa': {'foo': 1, 'bar': 2, 'baz': 3},
'bbb': 4, 'ccc': {'foo': 5, 'bar': 6}})
self.assertEqual(r, {'aaa': {'bar': 2, 'baz': 3}, 'bbb': 4,
'ccc': {'foo': 5}})
def test_filter_fields(self):
selector = vnflcm_view.EnhanceAttributeSelector(
{'aaa', 'bbb', 'ccc'}, {'aaa'}, {'bbb', 'ccc'},
fields='bbb/foo,bbb/baz,ccc/bar')
r = selector.filter({'aaa': 1, 'bbb': {'foo': 1, 'bar': 2, 'baz': 3},
'ccc': {'foo': 4, 'bar': 5}})
self.assertEqual(r, {'aaa': 1, 'bbb': {'foo': 1, 'baz': 3},
'ccc': {'bar': 5}})
class TestBaseViewBuilder(base.BaseTestCase):
def test_parse_filter(self):
builder = vnflcm_view.BaseViewBuilder()
builder = vnflcm_view.BaseViewBuilder('endpoint', 100)
f1 = builder.parse_filter("(eq,foo/bar,abc)")
self.assertEqual(len(f1), 1)
self.assertEqual(f1[0].attr, ['foo', 'bar'])
@@ -173,7 +200,7 @@ class TestBaseViewBuilder(base.BaseTestCase):
self.assertEqual(len(f5[0].values), 1)
def test_parse_filter_invalid(self):
builder = vnflcm_view.BaseViewBuilder()
builder = vnflcm_view.BaseViewBuilder('endpoint', 100)
self.assertRaises(sol_ex.InvalidAttributeFilter,
builder.parse_filter,
"(le,foo/bar,abc)")

View File

@@ -46,7 +46,7 @@ class TestVnfpmV2(base.BaseTestCase):
self.request.context = self.context
self.controller = vnfpm_v2.VnfPmControllerV2()
self.endpoint = CONF.v2_vnfm.endpoint
self._pm_job_view = vnfpm_view.PmJobViewBuilder(self.endpoint)
self._pm_job_view = vnfpm_view.PmJobViewBuilder(self.endpoint, 100)
def test_check_performance_metric_or_group(self):
vnfpm_v2._check_performance_metric_or_group(

View File

@@ -36,19 +36,20 @@ class TestPmJobViewBuilder(base.BaseTestCase):
self.request = mock.Mock()
self.request.context = self.context
self.endpoint = CONF.v2_vnfm.endpoint
self.page_size = CONF.v2_vnfm.vnfpm_pmjob_page_size
@mock.patch.object(BaseViewBuilder, 'parse_filter')
def test_parse_filter(self, mock_parse_filter):
mock_parse_filter.return_value = 1
result = PmJobViewBuilder(self.endpoint).parse_filter('filter_param')
result = PmJobViewBuilder(self.endpoint, self.page_size).parse_filter(
'filter_param')
self.assertEqual(1, result)
@mock.patch.object(BaseViewBuilder, 'parse_pager')
def test_parse_pager(self, mock_parse_pager):
mock_parse_pager.return_value = 1
page_size = CONF.v2_vnfm.vnfpm_pmjob_page_size
result = PmJobViewBuilder(self.endpoint).parse_pager(
self.request, page_size)
result = PmJobViewBuilder(self.endpoint, self.page_size).parse_pager(
self.request)
self.assertEqual(1, result)
def test_detail(self):
@@ -63,13 +64,13 @@ class TestPmJobViewBuilder(base.BaseTestCase):
),
)
)
result = PmJobViewBuilder(self.endpoint).detail(pm_job)
result = PmJobViewBuilder(self.endpoint, self.page_size).detail(pm_job)
self.assertEqual('pm_job_1', result.get('id'))
@mock.patch.object(BaseViewBuilder, 'detail_list')
def test_report_detail(self, mock_detail_list):
mock_detail_list.return_value = 1
result = PmJobViewBuilder(self.endpoint).detail_list(
result = PmJobViewBuilder(self.endpoint, self.page_size).detail_list(
'pm_jobs', 'filters', 'selector', 'pager')
self.assertEqual(1, result)
@@ -83,20 +84,20 @@ class TestPmThresholdViewBuilder(base.BaseTestCase):
self.request = mock.Mock()
self.request.context = self.context
self.endpoint = CONF.v2_vnfm.endpoint
self.page_size = CONF.v2_vnfm.vnfpm_pmthreshold_page_size
@mock.patch.object(BaseViewBuilder, 'parse_filter')
def test_parse_filter(self, mock_parse_filter):
mock_parse_filter.return_value = 1
result = PmThresholdViewBuilder(
self.endpoint).parse_filter('filter_param')
self.endpoint, self.page_size).parse_filter('filter_param')
self.assertEqual(1, result)
@mock.patch.object(BaseViewBuilder, 'parse_pager')
def test_parse_pager(self, mock_parse_pager):
mock_parse_pager.return_value = 1
page_size = CONF.v2_vnfm.vnfpm_pmthreshold_page_size
result = PmThresholdViewBuilder(self.endpoint).parse_pager(
self.request, page_size)
result = PmThresholdViewBuilder(
self.endpoint, self.page_size).parse_pager(self.request)
self.assertEqual(1, result)
def test_detail(self):
@@ -111,5 +112,6 @@ class TestPmThresholdViewBuilder(base.BaseTestCase):
),
)
)
result = PmThresholdViewBuilder(self.endpoint).detail(pm_threshold)
result = PmThresholdViewBuilder(
self.endpoint, self.page_size).detail(pm_threshold)
self.assertEqual('pm_threshold_1', result.get('id'))