Merge "Performance enhancement of v2 list APIs"
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 = {}
|
||||
|
||||
|
||||
@@ -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)")
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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'))
|
||||
|
||||
Reference in New Issue
Block a user