Fix API pagination problem in multi servers

This patch fixes the problem regarding pagination of target APIs
in case of running by multiple Tacker servers.

It changes the method of getting paginated records so that they
are able to be done by specifying the last record's id in the last
page.

Closes-Bug: #1978901
Change-Id: Ie0a51f1b837b7426595c40efcbbc022f0ea66f65
This commit is contained in:
Koichi Edagawa 2022-07-22 12:06:40 +09:00 committed by Yasufumi Ogawa
parent a71771ac85
commit fd41f08914
12 changed files with 604 additions and 310 deletions

View File

@ -44,7 +44,8 @@ class ViewBuilder(base.BaseViewBuilder):
def _basic_subscription_info(self, vnf_lcm_subscription, filter=None):
if filter is None:
if 'filter' in vnf_lcm_subscription:
filter_dict = {}
filter_dict = json.loads(
vnf_lcm_subscription.filter)
if 'filter' in vnf_lcm_subscription.filter:
filter_dict = json.loads(

View File

@ -56,8 +56,11 @@ from tacker import manager
from tacker import objects
from tacker.objects import fields
from tacker.objects.fields import ErrorPoint as EP
from tacker.objects.vnf_instance import VnfInstanceList as vnf_instance_list
from tacker.objects import vnf_lcm_op_occs as vnf_lcm_op_occs_obj
from tacker.objects.vnf_lcm_op_occs import VnfLcmOpOccList as vnf_lcm_op_list
from tacker.objects import vnf_lcm_subscriptions as subscription_obj
from tacker.objects.vnf_lcm_subscriptions import LccnSubscriptionList as s_list
from tacker.plugins.common import constants
from tacker.policies import vnf_lcm as vnf_lcm_policies
from tacker.tosca import utils as toscautils
@ -192,9 +195,6 @@ class VnfLcmController(wsgi.Controller):
self._vnfm_plugin = manager.TackerManager.get_service_plugins()['VNFM']
self._view_builder_op_occ = vnf_op_occs_view.ViewBuilder()
self._view_builder_subscription = vnf_subscription_view.ViewBuilder()
self._nextpages_vnf_instances = {}
self._nextpages_lcm_op_occs = {}
self._nextpages_subscriptions = {}
def _get_vnf_instance_href(self, vnf_instance):
return '{}vnflcm/v1/vnf_instances/{}'.format(
@ -560,13 +560,6 @@ class VnfLcmController(wsgi.Controller):
return vnf_package_info[0]
def _delete_expired_nextpages(self, nextpages):
for k, v in list(nextpages.items()):
if timeutils.is_older_than(v['created_time'],
CONF.vnf_lcm.nextpage_expiration_time):
LOG.debug('Old nextpages are deleted. id: %s' % k)
nextpages.pop(k)
@wsgi.response(http_client.OK)
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND))
def show(self, request, id):
@ -596,39 +589,43 @@ class VnfLcmController(wsgi.Controller):
nextpage = request.GET.get('nextpage_opaque_marker')
allrecords = request.GET.get('all_records')
limit = None
marker_obj = None
result = []
if allrecords != 'yes' and nextpage:
self._delete_expired_nextpages(self._nextpages_vnf_instances)
# get maximum record size per page
if allrecords != 'yes':
limit = CONF.vnf_lcm.vnf_instance_num
if nextpage in self._nextpages_vnf_instances:
result = self._nextpages_vnf_instances.pop(
nextpage)['nextpage']
else:
vnf_instances = objects.VnfInstanceList.get_by_filters(
request.context, filters=filters)
# get next page marker object from nextpage id
if nextpage:
marker_obj = objects.VnfInstance.get_by_id(request.context,
nextpage)
try:
# get records from DB within maximum record size per page
# except for getting all records case
result = vnf_instance_list.get_by_marker_filter(request.context,
limit, marker_obj, filters=filters)
except Exception as e:
LOG.exception(traceback.format_exc())
return self._make_problem_detail(
str(e), 500, title='Internal Server Error')
result = self._view_builder.index(vnf_instances)
result = self._view_builder.index(result)
res = webob.Response(content_type='application/json')
res.status_int = 200
if (allrecords != 'yes' and
len(result) > CONF.vnf_lcm.vnf_instance_num):
nextpageid = uuidutils.generate_uuid()
# if the number of records obtained from DB is equal to maximum record
# size per page, the id of the last record is used as next page marker
# and set it to Link header of the response
if (allrecords != 'yes' and len(result) >= limit):
nextpageid = result[(limit - 1)]['id']
links = ('Link', '<%s?nextpage_opaque_marker=%s>; rel="next"' % (
request.path_url, nextpageid))
res.headerlist.append(links)
res.body = jsonutils.dump_as_bytes(
result[: CONF.vnf_lcm.vnf_instance_num])
self._delete_expired_nextpages(self._nextpages_vnf_instances)
remain = result[CONF.vnf_lcm.vnf_instance_num:]
self._nextpages_vnf_instances.update({nextpageid:
{'created_time': timeutils.utcnow(), 'nextpage': remain}})
else:
res.body = jsonutils.dump_as_bytes(result)
res.body = jsonutils.dump_as_bytes(result)
return res
@ -1061,9 +1058,9 @@ class VnfLcmController(wsgi.Controller):
@wsgi.response(http_client.OK)
def subscription_list(self, request):
nextpage_opaque_marker = None
paging = 1
filter_string = ""
ignore_nextpages = False
limit = None
marker_obj = None
subscription_data = []
query_params = request.query_string
@ -1083,9 +1080,6 @@ class VnfLcmController(wsgi.Controller):
filter_string = query_param_key_value[1]
if query_param_key_value[0] == 'nextpage_opaque_marker':
nextpage_opaque_marker = query_param_key_value[1]
if query_param_key_value[0] == 'page':
paging = int(query_param_key_value[1])
ignore_nextpages = True
if filter_string:
# check enumerations columns
@ -1114,55 +1108,48 @@ class VnfLcmController(wsgi.Controller):
title='Bad Request')
nextpage = nextpage_opaque_marker
if allrecords != 'yes' and not ignore_nextpages and nextpage:
self._delete_expired_nextpages(self._nextpages_subscriptions)
if nextpage in self._nextpages_subscriptions:
subscription_data = self._nextpages_subscriptions.pop(
nextpage)['nextpage']
else:
try:
filter_string_parsed = self._view_builder_subscription. \
validate_filter(filter_string)
if nextpage_opaque_marker:
start_index = paging - 1
else:
start_index = None
try:
filter_string_parsed = self._view_builder_subscription. \
validate_filter(filter_string)
vnf_lcm_subscriptions = (
subscription_obj.LccnSubscriptionList.
get_by_filters(request.context,
read_deleted='no',
filters=filter_string_parsed,
nextpage_opaque_marker=start_index))
# get maximum record size per page
if allrecords != 'yes':
limit = CONF.vnf_lcm.subscription_num
LOG.debug("vnf_lcm_subscriptions %s" % vnf_lcm_subscriptions)
subscription_data = self._view_builder_subscription. \
subscription_list(vnf_lcm_subscriptions)
except Exception as e:
LOG.error(traceback.format_exc())
return self._make_problem_detail(
str(e), 500, title='Internal Server Error')
# get next page marker object from nextpage id
if nextpage:
marker_obj = objects.LccnSubscription.get_by_id(
request.context, nextpage)
# get records from DB within maximum record size per page
# except for getting all records case
result = s_list.get_by_marker_filter(
request.context, limit,
marker_obj, filters=filter_string_parsed,
read_deleted='no')
LOG.debug("vnf_lcm_subscriptions %s" % result)
subscription_data = self._view_builder_subscription. \
subscription_list(result)
except Exception as e:
LOG.error(traceback.format_exc())
return self._make_problem_detail(
str(e), 500, title='Internal Server Error')
# make response
res = webob.Response(content_type='application/json')
res.status_int = 200
if (allrecords != 'yes' and not ignore_nextpages and
len(subscription_data) > CONF.vnf_lcm.subscription_num):
nextpageid = uuidutils.generate_uuid()
# if the number of records obtained from DB is equal to maximum record
# size per page, the id of the last record is used as next page marker
# and set it to Link header of the response
if (allrecords != 'yes' and len(subscription_data) >= limit):
nextpageid = subscription_data[(limit - 1)]['id']
links = ('Link', '<%s?nextpage_opaque_marker=%s>; rel="next"' % (
request.path_url, nextpageid))
res.headerlist.append(links)
remain = subscription_data[CONF.vnf_lcm.subscription_num:]
subscription_data = (
subscription_data[: CONF.vnf_lcm.subscription_num])
self._delete_expired_nextpages(self._nextpages_subscriptions)
self._nextpages_subscriptions.update({nextpageid:
{'created_time': timeutils.utcnow(), 'nextpage': remain}})
res.body = jsonutils.dump_as_bytes(subscription_data)
LOG.debug("subscription_list res %s" % res)
@ -1748,52 +1735,53 @@ class VnfLcmController(wsgi.Controller):
nextpage = request.GET.get('nextpage_opaque_marker')
allrecords = request.GET.get('all_records')
limit = None
marker_obj = None
result = []
if allrecords != 'yes' and nextpage:
self._delete_expired_nextpages(self._nextpages_lcm_op_occs)
self._view_builder_op_occ.validate_attribute_fields(
all_fields=all_fields, fields=fields,
exclude_fields=exclude_fields,
exclude_default=exclude_default)
if nextpage in self._nextpages_lcm_op_occs:
result = self._nextpages_lcm_op_occs.pop(nextpage)['nextpage']
else:
self._view_builder_op_occ.validate_attribute_fields(
all_fields=all_fields, fields=fields,
exclude_fields=exclude_fields,
exclude_default=exclude_default)
filters = self._view_builder_op_occ.validate_filter(filters)
filters = self._view_builder_op_occ.validate_filter(filters)
# get maximum record size per page
if allrecords != 'yes':
limit = CONF.vnf_lcm.lcm_op_occ_num
try:
vnf_lcm_op_occs = (
vnf_lcm_op_occs_obj.VnfLcmOpOccList.get_by_filters(
request.context, read_deleted='no', filters=filters))
except Exception as e:
LOG.exception(traceback.format_exc())
return self._make_problem_detail(
str(e), 500, title='Internal Server Error')
# get next page marker object from nextpage id
if nextpage:
marker_obj = vnf_lcm_op_occs_obj.VnfLcmOpOcc.get_by_id(
request.context, nextpage)
result = self._view_builder_op_occ.index(request, vnf_lcm_op_occs,
all_fields=all_fields, exclude_fields=exclude_fields,
fields=fields, exclude_default=exclude_default)
try:
# get records from DB within maximum record size per page
# except for getting all records case
result = vnf_lcm_op_list.get_by_marker_filter(request.context,
limit, marker_obj, filters=filters, read_deleted='no')
except Exception as e:
LOG.exception(traceback.format_exc())
return self._make_problem_detail(
str(e), 500, title='Internal Server Error')
result = self._view_builder_op_occ.index(request, result,
all_fields=all_fields, exclude_fields=exclude_fields,
fields=fields, exclude_default=exclude_default)
res = webob.Response(content_type='application/json')
res.status_int = 200
if allrecords != 'yes' and len(result) > CONF.vnf_lcm.lcm_op_occ_num:
nextpageid = uuidutils.generate_uuid()
# if the number of records obtained from DB is equal to maximum record
# size per page, the id of the last record is used as next page marker
# and set it to Link header of the response
if (allrecords != 'yes' and len(result) >= limit):
nextpageid = result[(limit - 1)]['id']
links = ('Link', '<%s?nextpage_opaque_marker=%s>; rel="next"' % (
request.path_url, nextpageid))
res.headerlist.append(links)
res.body = jsonutils.dump_as_bytes(
result[: CONF.vnf_lcm.lcm_op_occ_num])
self._delete_expired_nextpages(self._nextpages_lcm_op_occs)
remain = result[CONF.vnf_lcm.lcm_op_occ_num:]
self._nextpages_lcm_op_occs.update({nextpageid:
{'created_time': timeutils.utcnow(), 'nextpage': remain}})
else:
res.body = jsonutils.dump_as_bytes(result)
res.body = jsonutils.dump_as_bytes(result)
return res

View File

@ -18,6 +18,7 @@ from io import BytesIO
import json
import mimetypes
import os
import traceback
import webob
import zipfile
from zipfile import ZipFile
@ -28,7 +29,6 @@ from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
from oslo_utils import excutils
from oslo_utils import timeutils
from oslo_utils import uuidutils
from tacker._i18n import _
@ -40,8 +40,10 @@ from tacker.common import exceptions
from tacker.common import utils
from tacker.conductor.conductorrpc import vnf_pkgm_rpc
from tacker.glance_store import store as glance_store
from tacker import objects
from tacker.objects import fields
from tacker.objects import vnf_package as vnf_package_obj
from tacker.objects.vnf_package import VnfPackagesList as vnf_package_list
from tacker.policies import vnf_package as vnf_package_policies
from tacker import wsgi
@ -75,13 +77,6 @@ class VnfPkgmController(wsgi.Controller):
raise webob.exc.HTTPNotFound(explanation=msg)
return vnf_package
def _delete_expired_nextpages(self, nextpages):
for k, v in nextpages.items():
if timeutils.is_older_than(v['created_time'],
CONF.vnf_package.nextpage_expiration_time):
LOG.debug('Old nextpages are deleted. id: %s' % k)
nextpages.pop(k)
@wsgi.response(http_client.CREATED)
@wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN))
@validation.schema(vnf_packages.create)
@ -162,42 +157,47 @@ class VnfPkgmController(wsgi.Controller):
filters = self._view_builder.validate_filter(filters)
results = []
limit = None
marker_obj = None
if allrecords != 'yes' and nextpage:
self._delete_expired_nextpages(self._nextpages)
if allrecords != 'yes':
limit = CONF.vnf_package.vnf_package_num
if nextpage in self._nextpages:
results = self._nextpages.pop(
nextpage)['nextpage']
else:
vnf_packages = vnf_package_obj.VnfPackagesList.get_by_filters(
request.context, read_deleted='no', filters=filters)
# get next page marker object from nextpage id
if nextpage:
marker_obj = objects.VnfPackage.get_by_id(request.context,
nextpage)
results = self._view_builder.index(vnf_packages,
all_fields=all_fields,
exclude_fields=exclude_fields,
fields=fields,
exclude_default=exclude_default)
try:
# get records from DB within maximum record size per page
# except for getting all records case
result = vnf_package_list.get_by_marker_filter(request.context,
limit, marker_obj, filters=filters, read_deleted='no')
except Exception as e:
LOG.exception(traceback.format_exc())
return self._make_problem_detail(
str(e), 500, title='Internal Server Error')
results = self._view_builder.index(result,
all_fields=all_fields,
exclude_fields=exclude_fields,
fields=fields,
exclude_default=exclude_default)
res = webob.Response(content_type='application/json')
res.status_int = 200
# if the number of records obtained from DB is equal to maximum record
# size per page, the id of the last record is used as next page marker
# and set it to Link header of the response
if (allrecords != 'yes' and
len(results) > CONF.vnf_package.vnf_package_num):
nextpageid = uuidutils.generate_uuid()
len(results) >= limit):
nextpageid = result[(limit - 1)]['id']
links = ('Link', '<%s?nextpage_opaque_marker=%s>; rel="next"' % (
request.path_url, nextpageid))
res.headerlist.append(links)
res.body = jsonutils.dump_as_bytes(
results[: CONF.vnf_package.vnf_package_num], default=str)
self._delete_expired_nextpages(self._nextpages)
remain = results[CONF.vnf_package.vnf_package_num:]
self._nextpages.update({nextpageid:
{'created_time': timeutils.utcnow(), 'nextpage': remain}})
else:
res.body = jsonutils.dump_as_bytes(results, default=str)
res.body = jsonutils.dump_as_bytes(results, default=str)
return res

View File

@ -55,11 +55,7 @@ OPTS = [
cfg.IntOpt(
'vnf_instance_num',
default=100,
help="Number of vnf_instances contained in 1 page"),
cfg.IntOpt(
'nextpage_expiration_time',
default=3600,
help="Expiration time (sec) for paging")]
help="Number of vnf_instances contained in 1 page")]
vnf_lcm_group = cfg.OptGroup('vnf_lcm',
title='vnf_lcm options',

View File

@ -78,10 +78,7 @@ Related options:
help=_("List of del inputs from lower-vnfd")),
cfg.IntOpt('vnf_package_num',
default=100,
help=_("Number of vnf_packages contained in 1 page")),
cfg.IntOpt('nextpage_expiration_time',
default=3600,
help=_("Expiration time (sec) for paging")),
help=_("Number of vnf_packages contained in 1 page"))
]

View File

@ -27,6 +27,7 @@ from tacker.common import utils
from tacker.db import api as db_api
from tacker.db.db_sqlalchemy import api
from tacker.db.db_sqlalchemy import models
from tacker.db import sqlalchemyutils
from tacker.db.vnfm import vnfm_db
from tacker import objects
from tacker.objects import base
@ -127,6 +128,23 @@ def _vnf_instance_list_by_filter(context, columns_to_join=None,
return query.all()
@db_api.context_manager.reader
def _vnf_instance_list_by_filter_query(context, columns_to_join=None,
filters=None):
query = api.model_query(context, models.VnfInstance,
read_deleted="no",
project_only=True)
if columns_to_join:
for column in columns_to_join:
query = query.options(joinedload(column))
if filters:
query = common.apply_filters(query, filters)
return query
def _make_vnf_instance_list(context, vnf_instance_list, db_vnf_instance_list,
expected_attrs):
vnf_instance_cls = VnfInstance
@ -545,6 +563,22 @@ class VnfInstanceList(ovoo_base.ObjectListBase, base.TackerObject):
return _make_vnf_instance_list(context, cls(), db_vnf_instances,
expected_attrs)
@base.remotable_classmethod
def get_by_marker_filter(cls, context, limit, marker_obj,
filters=None, expected_attrs=None):
expected_attrs = ["instantiated_vnf_info"]
query = _vnf_instance_list_by_filter_query(context,
columns_to_join=expected_attrs,
filters=filters)
query = sqlalchemyutils.paginate_query(query, model=models.VnfInstance,
limit=limit,
sorts=[['id', 'asc']],
marker_obj=marker_obj)
db_vnf_instances = query.all()
return _make_vnf_instance_list(context, cls(), db_vnf_instances,
expected_attrs)
@base.remotable_classmethod
def get_by_filters(cls, context, filters=None,
expected_attrs=None):

View File

@ -24,6 +24,7 @@ from tacker.common import utils
from tacker.db import api as db_api
from tacker.db.db_sqlalchemy import api
from tacker.db.db_sqlalchemy import models
from tacker.db import sqlalchemyutils
from tacker import objects
from tacker.objects import base
from tacker.objects import common
@ -151,6 +152,19 @@ def _vnf_lcm_op_occs_get_by_filters(context, read_deleted=None,
return query.all()
@db_api.context_manager.reader
def _vnf_lcm_op_occs_get_by_filters_query(context, read_deleted=None,
filters=None):
query = api.model_query(context, models.VnfLcmOpOccs,
read_deleted=read_deleted, project_only=True)
if filters:
query = common.apply_filters(query, filters)
return query
@db_api.context_manager.reader
def _vnf_notify_get_by_id(context, vnf_instance_id, columns_to_join=None):
@ -484,6 +498,19 @@ class VnfLcmOpOccList(ovoo_base.ObjectListBase, base.TackerObject):
context, read_deleted=read_deleted, filters=filters)
return _make_vnf_lcm_op_occs_list(context, cls(), db_vnf_lcm_op_occs)
@base.remotable_classmethod
def get_by_marker_filter(cls, context, limit,
marker_obj, filters=None, read_deleted=None):
query = _vnf_lcm_op_occs_get_by_filters_query(
context, read_deleted=read_deleted, filters=filters)
query = sqlalchemyutils.paginate_query(query,
model=models.VnfLcmOpOccs,
limit=limit,
sorts=[['id', 'asc']],
marker_obj=marker_obj)
db_vnf_lcm_op_occs = query.all()
return _make_vnf_lcm_op_occs_list(context, cls(), db_vnf_lcm_op_occs)
@base.TackerObjectRegistry.register
class ResourceChanges(base.TackerObject,

View File

@ -24,6 +24,7 @@ import tacker.conf
from tacker.db import api as db_api
from tacker.db.db_sqlalchemy import api
from tacker.db.db_sqlalchemy import models
from tacker.db import sqlalchemyutils
from tacker import objects
from tacker.objects import base
from tacker.objects import common
@ -381,6 +382,37 @@ def _vnf_lcm_subscription_list_by_filters(context,
return query.order_by(models.VnfLcmSubscriptions.created_at).all()
@db_api.context_manager.reader
def _vnf_lcm_subscription_get_query(context, read_deleted=None, filters=None):
query = api.model_query(context, models.VnfLcmSubscriptions,
read_deleted=read_deleted,
project_only=True)
binary_columns = ['notification_types', 'operation_types']
if filters:
filter_data = json.dumps(filters)
if 'ChangeNotificationsFilter' in filter_data:
query = query.join(models.VnfLcmFilters)
if 'and' in filters:
filters_and = []
for filter in filters['and']:
if filter['field'] in binary_columns:
converted_value = utils.str_to_bytes(filter['value'])
filter['value'] = converted_value
filters_and.append(filter)
filters = {'and': filters_and}
else:
if filters['field'] in binary_columns:
converted_value = utils.str_to_bytes(filters['value'])
filters.update({'value': converted_value})
query = common.apply_filters(query, filters)
return query.order_by(models.VnfLcmSubscriptions.created_at)
@db_api.context_manager.writer
def _vnf_lcm_subscriptions_create(context, values, filter):
with db_api.context_manager.writer.using(context):
@ -721,6 +753,22 @@ class LccnSubscriptionList(ovoo_base.ObjectListBase, base.TackerObject):
'objects': fields.ListOfObjectsField('LccnSubscription')
}
@base.remotable_classmethod
def get_by_marker_filter(cls, context,
limit, marker_obj,
filters=None, read_deleted=None):
query = _vnf_lcm_subscription_get_query(context,
read_deleted=read_deleted,
filters=filters)
query = sqlalchemyutils.paginate_query(query,
model=models.VnfLcmSubscriptions,
limit=limit,
sorts=[['id', 'asc']],
marker_obj=marker_obj)
db_subscriptions = query.all()
return _make_subscription_list(context, cls(), db_subscriptions)
@base.remotable_classmethod
def get_by_filters(cls, context, read_deleted=None,
filters=None, nextpage_opaque_marker=None):

View File

@ -29,6 +29,7 @@ from tacker.common import utils
from tacker.db import api as db_api
from tacker.db.db_sqlalchemy import api
from tacker.db.db_sqlalchemy import models
from tacker.db import sqlalchemyutils
from tacker import objects
from tacker.objects import base
from tacker.objects import common
@ -115,6 +116,39 @@ def _update_user_defined_data(context, package_uuid, user_data):
return result
@db_api.context_manager.reader
def _vnf_packages_get_by_filters_query(context, read_deleted=None,
filters=None):
query = api.model_query(context, models.VnfPackage,
read_deleted=read_deleted,
project_only=True).options(joinedload('_metadata'))
if filters:
# Need to join VnfDeploymentFlavour, VnfSoftwareImage and
# VnfSoftwareImageMetadata db table explicitly
# only when filters contains one of the column matching
# from VnfSoftwareImage or VnfSoftwareImageMetadata db table.
filter_data = json.dumps(filters)
if 'VnfSoftwareImageMetadata' in filter_data:
query = query.join(models.VnfDeploymentFlavour).join(
models.VnfSoftwareImage).join(
models.VnfSoftwareImageMetadata)
elif 'VnfSoftwareImage' in filter_data:
query = query.join(models.VnfDeploymentFlavour).join(
models.VnfSoftwareImage)
if 'VnfPackageArtifactInfo' in filter_data:
query = query.join(models.VnfPackageArtifactInfo)
if 'VnfPackageVnfd' in filter_data:
query = query.join(models.VnfPackageVnfd)
query = common.apply_filters(query, filters)
return query
@db_api.context_manager.reader
def _vnf_package_get_by_id(context, package_uuid, columns_to_join=None):
@ -678,6 +712,22 @@ class VnfPackagesList(ovoo_base.ObjectListBase, base.TackerObject):
return _make_vnf_packages_list(context, cls(), db_vnf_packages,
expected_attrs)
@base.remotable_classmethod
def get_by_marker_filter(cls, context,
limit, marker_obj,
filters=None, read_deleted=None):
query = _vnf_packages_get_by_filters_query(context,
read_deleted=read_deleted,
filters=filters)
query = sqlalchemyutils.paginate_query(query,
model=models.VnfPackage,
limit=limit,
sorts=[['id', 'asc']],
marker_obj=marker_obj)
db_vnf_packages = query.all()
return _make_vnf_packages_list(context, cls(), db_vnf_packages)
@base.remotable_classmethod
def get_by_filters(cls, context, read_deleted=None, filters=None):
db_vnf_packages = _vnf_package_list_by_filters(context,

View File

@ -1882,7 +1882,15 @@ def _subscription_links(subscription_dict):
return subscription_dict
def return_subscription_obj(**updates):
def return_lccn_subscription(**updates):
subscription = _fake_subscription_obj(**updates)
subscription['filter'] = json.dumps(subscription['filter'])
obj = objects.LccnSubscription(**subscription)
return obj
def return_lccn_subscription_obj(**updates):
subscription = _fake_subscription_obj(**updates)
subscription['filter'] = json.dumps(subscription['filter'])
obj = objects.LccnSubscriptionRequest(**subscription)

View File

@ -1687,7 +1687,7 @@ class TestController(base.TestCase):
self.assertEqual(expected_message, exception.msg)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
def test_index(self, mock_vnf_list):
req = fake_request.HTTPRequest.blank('/vnf_instances')
vnf_instance_1 = fakes.return_vnf_instance()
@ -1701,7 +1701,8 @@ class TestController(base.TestCase):
fields.VnfInstanceState.INSTANTIATED)]
self.assertEqual(expected_result, resp.json)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter",
return_value=[])
def test_index_empty_response(self, mock_vnf_list):
req = fake_request.HTTPRequest.blank('/vnf_instances')
mock_vnf_list.return_value = []
@ -1831,7 +1832,7 @@ class TestController(base.TestCase):
self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id,
resp.json['detail'])
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
@ddt.data(
{'filter': "(eq,vnfInstanceName,'dummy_name')"},
{'filter': "(in,vnfInstanceName,'dummy_name')"},
@ -1863,7 +1864,7 @@ class TestController(base.TestCase):
fields.VnfInstanceState.INSTANTIATED)]
self.assertEqual(expected_result, res_dict.json)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
def test_index_filter_combination(self, mock_vnf_list):
"""Test multiple filter parameters separated by semicolon."""
params = {
@ -1886,7 +1887,7 @@ class TestController(base.TestCase):
fields.VnfInstanceState.INSTANTIATED)]
self.assertEqual(expected_result, res_dict.json)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
@ddt.data(
{'filter': "(eq,vnfInstanceName,dummy_value)"},
{'filter': "(eq,vnfInstanceDescription,dummy value)"},
@ -1921,7 +1922,7 @@ class TestController(base.TestCase):
{'filter': "(eq,instantiatedInfo/additionalParams/error,'dummy')"},
)
def test_index_filter_attributes(self, filter_params,
mock_vnf_list):
mock_vnf_list):
"""Test various attributes supported for filter parameter."""
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
@ -1939,7 +1940,7 @@ class TestController(base.TestCase):
fields.VnfInstanceState.INSTANTIATED)]
self.assertEqual(expected_result, res_dict.json)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
@ddt.data(
{'filter': "(eq,vnfInstanceName,value"},
{'filter': "eq,vnfInstanceName,value)"},
@ -1956,7 +1957,7 @@ class TestController(base.TestCase):
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
@ddt.data(
{'filter': "(eq,vnfInstanceName,singl'quote)"},
{'filter': "(eq,vnfInstanceName,three''' quotes)"},
@ -1974,7 +1975,7 @@ class TestController(base.TestCase):
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
@ddt.data(
{'filter': '(eq,vnfdId,value1,value2)'},
{'filter': '(fake,vnfdId,dummy_vnfd_id)'},
@ -1989,7 +1990,7 @@ class TestController(base.TestCase):
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
@ddt.data(
{'filter': '(eq,fakeattr,fakevalue)'},
{'filter': '(eq,,fakevalue)'},
@ -2003,7 +2004,7 @@ class TestController(base.TestCase):
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
@ddt.data(
{'filter': '(eq,data/size,fake_value)'},
{'filter': '(gt,data/createdAt,fake_value)'},
@ -2019,47 +2020,85 @@ class TestController(base.TestCase):
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.vnf_instance.VnfInstanceList,
"get_by_marker_filter")
@mock.patch.object(objects.VnfInstance, "get_by_id")
@ddt.data(
{'params': {'all_records': 'yes'},
'result_names': ['sample1', 'sample2', 'sample3', 'sample4']},
{'params': {'all_records': 'yes', 'nextpage_opaque_marker': 'abc'},
{'params': {'all_records': 'yes', 'nextpage_opaque_marker':
'22222222-2222-2222-2222-222222222222'},
'result_names': ['sample1', 'sample2', 'sample3', 'sample4']},
{'params': {'nextpage_opaque_marker': 'abc'},
{'params': {'nextpage_opaque_marker':
'44444444-4444-4444-4444-444444444444'},
'result_names': []},
{'params': {'nextpage_opaque_marker':
'22222222-2222-2222-2222-222222222222'},
'result_names': ['sample3', 'sample4']},
{'params': {},
'result_names': ['sample2']}
'result_names': ['sample1', 'sample2']}
)
def test_index_paging(self, values, mock_vnf_list):
cfg.CONF.set_override('vnf_instance_num', 1, group='vnf_lcm')
def test_index_paging(self, values,
mock_marker_obj,
mock_vnf_instance_list):
ids = ['11111111-1111-1111-1111-111111111111',
'22222222-2222-2222-2222-222222222222',
'33333333-3333-3333-3333-333333333333',
'44444444-4444-4444-4444-444444444444',
None]
cfg.CONF.set_override('vnf_instance_num', 2, group='vnf_lcm')
query = urllib.parse.urlencode(values['params'])
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
mock_vnf_list.return_value = [
fakes.return_vnf_instance(**{'vnf_instance_name': 'sample1'}),
fakes.return_vnf_instance(**{'vnf_instance_name': 'sample2'}),
fakes.return_vnf_instance(**{'vnf_instance_name': 'sample3'}),
fakes.return_vnf_instance(**{'vnf_instance_name': 'sample4'})
]
target_index = []
if 'all_records' in values['params'] \
and values['params']['all_records'] == 'yes':
mock_marker_obj.return_value = None
target_index = [0, 1, 2, 3]
elif 'nextpage_opaque_marker' in values['params']:
mock_marker_obj.return_value = fakes.return_vnf_instance(
**{'id': values['params']['nextpage_opaque_marker']})
marker_obj_index = ids.index(mock_marker_obj.return_value['id'])
for i in range(marker_obj_index + 1, len(ids) - 1):
target_index.append(i)
else:
mock_marker_obj.return_value = None
target_index = [0, 1]
mock_vnf_instance_list.return_value = []
for index in range(len(target_index)):
mock_vnf_instance_list.return_value.append(
fakes.return_vnf_instance(**{'id': ids[target_index[index]],
'vnf_instance_name':
values['result_names'][index]}))
expected_result = []
for name in values['result_names']:
for index in range(len(target_index)):
_links = fakes.fake_vnf_instance_response()['_links']
expected_links = (re.sub("vnf_instances/[a-zA-Z0-9-]*",
"vnf_instances/{}".format(ids[target_index[index]]),
str(_links)))
expected_links = json.loads(expected_links.replace("'", '"'))
expected_result.append(fakes.fake_vnf_instance_response(
**{'vnfInstanceName': name}))
**{'vnfInstanceName': values['result_names'][index],
'id': ids[target_index[index]],
'_links': expected_links}))
expected_result_link = None
if 'all_records' not in values['params'] and len(target_index) >= 2:
expected_result_link = (
'<http://localhost//vnflcm/v1/vnf_instances' +
'?nextpage_opaque_marker=%s>; rel="next"'
% ids[target_index[1]])
res_dict = self.controller.index(req)
if 'Link' in res_dict.headers:
next_url = re.findall('<(.*)>', res_dict.headers['Link'])[0]
query = urllib.parse.urlparse(next_url).query
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
res_dict = self.controller.index(req)
self.assertEqual(expected_result, res_dict.json)
if expected_result_link is not None:
self.assertEqual(expected_result_link, res_dict.headers['Link'])
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
@ddt.data(
{'attribute_not_exist': 'some_value'},
{'all_fields': {}},
@ -2078,7 +2117,7 @@ class TestController(base.TestCase):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.index, req)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
@ddt.data(
{'attribute_not_exist': 'some_value'},
{'all_fields': {}},
@ -3795,7 +3834,7 @@ class TestController(base.TestCase):
resp = req.get_response(self.app)
self.assertEqual(http_client.INTERNAL_SERVER_ERROR, resp.status_code)
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_marker_filter")
def test_op_occ_list(self, mock_op_occ_list):
req = fake_request.HTTPRequest.blank('/vnflcm/v1/vnf_lcm_op_occs')
@ -3815,22 +3854,59 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result)),
resp.json)
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
@mock.patch.object(objects.vnf_lcm_op_occs.VnfLcmOpOccList,
"get_by_marker_filter")
@mock.patch.object(objects.vnf_lcm_op_occs.VnfLcmOpOcc, "get_by_id")
@ddt.data(
{'params': {'all_records': 'yes'},
'result_names': ['INSTANTIATE', 'SCALE', 'HEAL', 'TERMINATE']},
{'params': {'all_records': 'yes', 'nextpage_opaque_marker': 'abc'},
{'params': {'all_records': 'yes', 'nextpage_opaque_marker':
'22222222-2222-2222-2222-222222222222'},
'result_names': ['INSTANTIATE', 'SCALE', 'HEAL', 'TERMINATE']},
{'params': {'nextpage_opaque_marker': 'abc'},
{'params': {'nextpage_opaque_marker':
'44444444-4444-4444-4444-444444444444'},
'result_names': []},
{'params': {'nextpage_opaque_marker':
'22222222-2222-2222-2222-222222222222'},
'result_names': ['HEAL', 'TERMINATE']},
{'params': {},
'result_names': ['SCALE']}
'result_names': ['INSTANTIATE', 'SCALE']}
)
def test_op_occ_list_paging(self, values, mock_op_occ_list):
cfg.CONF.set_override('lcm_op_occ_num', 1, group='vnf_lcm')
def test_op_occ_list_paging(self, values,
mock_marker_obj,
mock_op_occ_list):
ids = ['11111111-1111-1111-1111-111111111111',
'22222222-2222-2222-2222-222222222222',
'33333333-3333-3333-3333-333333333333',
'44444444-4444-4444-4444-444444444444',
None]
cfg.CONF.set_override('lcm_op_occ_num', 2, group='vnf_lcm')
query = urllib.parse.urlencode(values['params'])
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
target_index = []
if 'all_records' in values['params'] \
and values['params']['all_records'] == 'yes':
mock_marker_obj.return_value = None
target_index = [0, 1, 2, 3]
elif 'nextpage_opaque_marker' in values['params']:
mock_marker_obj.return_value = fakes.return_vnf_lcm_opoccs_obj(
**{'id': values['params']['nextpage_opaque_marker']})
if len(values['result_names']) > 0:
target_index.append(
ids.index(mock_marker_obj.return_value['id']) + 1)
target_index.append(
ids.index(mock_marker_obj.return_value['id']) + 2)
else:
mock_marker_obj.return_value = None
target_index = [0, 1]
mock_op_occ_list.return_value = []
for index in range(len(target_index)):
mock_op_occ_list.return_value.append(
fakes.return_vnf_lcm_opoccs_obj(
**{'id': ids[target_index[index]],
'operation': values['result_names'][index]}))
complex_attributes = [
'error',
@ -3838,34 +3914,36 @@ class TestController(base.TestCase):
'operationParams',
'changedInfo']
vnf_lcm_op_occ = [
fakes.return_vnf_lcm_opoccs_obj(**{'operation': 'INSTANTIATE'}),
fakes.return_vnf_lcm_opoccs_obj(**{'operation': 'SCALE'}),
fakes.return_vnf_lcm_opoccs_obj(**{'operation': 'HEAL'}),
fakes.return_vnf_lcm_opoccs_obj(**{'operation': 'TERMINATE'})
]
expected_result = []
for name in values['result_names']:
for index in range(len(target_index)):
_links = fakes.index_response()[0]['_links']
expected_links = re.sub("vnf_lcm_op_occs/[a-zA-Z0-9-]*",
"vnf_lcm_op_occs/{}".format(
ids[target_index[index]]), str(_links))
expected_links = json.loads(expected_links.replace("'", '"'))
expected_result += fakes.index_response(
remove_attrs=complex_attributes,
vnf_lcm_op_occs_updates={'operation': name})
vnf_lcm_op_occs_updates={'operation':
values['result_names'][index],
'id': ids[target_index[index]],
'_links': expected_links})
expected_result_link = None
if 'all_records' not in values['params'] and len(target_index) >= 2:
expected_result_link = (
'<http://localhost//vnflcm/v1/vnf_lcm_op_occs' +
'?nextpage_opaque_marker=%s>; rel="next"'
% ids[target_index[1]])
mock_op_occ_list.return_value = vnf_lcm_op_occ
resp = self.controller.list_lcm_op_occs(req)
if 'Link' in resp.headers:
next_url = re.findall('<(.*)>', resp.headers['Link'])[0]
query = urllib.parse.urlparse(next_url).query
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
resp = self.controller.list_lcm_op_occs(req)
self.assertEqual(
jsonutils.loads(jsonutils.dump_as_bytes(expected_result)),
resp.json)
if expected_result_link is not None:
self.assertEqual(expected_result_link, resp.headers['Link'])
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_marker_filter")
@ddt.data(
{'filter': '(eq,id,f26f181d-7891-4720-b022-b074ec1733ef)'},
{'filter': '(neq,operationState,COMPLETED)'},
@ -3881,7 +3959,7 @@ class TestController(base.TestCase):
"""(neq,operationParams,'"{"terminationType": "FORCEFUL"}"')"""},
)
def test_op_occ_filter_attributes(self, filter_params,
mock_op_occ_list):
mock_op_occ_list):
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
@ -3902,8 +3980,9 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result)),
res_dict.json)
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
def test_op_occ_filter_attributes_invalid_filter(self, mock_op_occ_list):
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_marker_filter")
def test_op_occ_filter_attributes_invalid_filter(self,
mock_op_occ_list):
query = urllib.parse.urlencode({'filter': '(lt,non_existing,4)'})
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
@ -3913,8 +3992,9 @@ class TestController(base.TestCase):
self.assertRaises(
exceptions.ValidationError, self.controller.list_lcm_op_occs, req)
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
def test_op_occ_attribute_selector_all_fields(self, mock_op_occ_list):
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_marker_filter")
def test_op_occ_attribute_selector_all_fields(self,
mock_op_occ_list):
params = {'all_fields': 'True'}
query = urllib.parse.urlencode(params)
req = fake_request.HTTPRequest.blank('/vnflcm/v1/vnf_lcm_op_occs?' +
@ -3929,7 +4009,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result)),
res_dict.json)
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_marker_filter")
@ddt.data(
{'fields': 'error'},
{'fields': 'resourceChanges'},
@ -3937,7 +4017,7 @@ class TestController(base.TestCase):
{'fields': 'changedInfo'}
)
def test_op_occ_attribute_selector_fields(self, filter_params,
mock_op_occ_list):
mock_op_occ_list):
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
@ -3959,7 +4039,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result)),
res_dict.json)
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_marker_filter")
@ddt.data(
{'exclude_fields': 'error'},
{'exclude_fields': 'resourceChanges'},
@ -3967,7 +4047,7 @@ class TestController(base.TestCase):
{'exclude_fields': 'changedInfo'}
)
def test_op_occ_attribute_selector_exclude_fields(self, filter_params,
mock_op_occ_list):
mock_op_occ_list):
query = urllib.parse.urlencode(filter_params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
@ -3982,8 +4062,9 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result)),
res_dict.json)
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_filters")
def test_op_occ_attribute_selector_fields_error(self, mock_op_occ_list):
@mock.patch.object(objects.VnfLcmOpOccList, "get_by_marker_filter")
def test_op_occ_attribute_selector_fields_error(self,
mock_op_occ_list):
query = urllib.parse.urlencode({'fields': 'non_existent_column'})
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_lcm_op_occs?' + query)
@ -4409,7 +4490,7 @@ class TestController(base.TestCase):
@mock.patch.object(vnf_subscription_view.ViewBuilder,
"validate_filter")
@mock.patch.object(objects.LccnSubscriptionList,
"get_by_filters")
"get_by_marker_filter")
def test_subscription_list_all(self,
mock_subscription_list,
mock_subscription_filter,
@ -4436,7 +4517,7 @@ class TestController(base.TestCase):
@mock.patch.object(vnf_subscription_view.ViewBuilder,
"validate_filter")
@mock.patch.object(objects.LccnSubscriptionList,
"get_by_filters")
"get_by_marker_filter")
def test_subscription_list_empty(self,
mock_subscription_list,
mock_subscription_filter,
@ -4469,66 +4550,89 @@ class TestController(base.TestCase):
resp = req.get_response(self.app)
self.assertEqual(500, resp.status_code)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM':
test_nfvo_plugin.FakeVNFMPlugin()})
@mock.patch.object(vnf_subscription_view.ViewBuilder,
"subscription_list")
@mock.patch.object(vnf_subscription_view.ViewBuilder,
"validate_filter")
@mock.patch.object(objects.LccnSubscriptionList,
"get_by_filters")
@mock.patch.object(objects.vnf_lcm_subscriptions.LccnSubscriptionList,
"get_by_marker_filter")
@mock.patch.object(objects.LccnSubscription, "get_by_id")
@ddt.data(
{'params': {'all_records': 'yes'},
'result_names': ['subscription_id_1', 'subscription_id_2',
'subscription_id_3', 'subscription_id_4']},
{'params': {'all_records': 'yes', 'nextpage_opaque_marker': 'abc'},
{'params': {'all_records': 'yes', 'nextpage_opaque_marker':
'22222222-2222-2222-2222-222222222222'},
'result_names': ['subscription_id_1', 'subscription_id_2',
'subscription_id_3', 'subscription_id_4']},
{'params': {'nextpage_opaque_marker': 'abc'},
{'params': {'nextpage_opaque_marker':
'44444444-4444-4444-4444-444444444444'},
'result_names': []},
{'params': {'nextpage_opaque_marker':
'22222222-2222-2222-2222-222222222222'},
'result_names': ['subscription_id_3', 'subscription_id_4']},
{'params': {},
'result_names': ['subscription_id_2']}
'result_names': ['subscription_id_1', 'subscription_id_2']}
)
def test_subscription_list_paging(self,
values,
mock_subscription_list,
mock_subscription_filter,
mock_subscription_view,
mock_get_service_plugins):
mock_subscription_filter.return_value = None
last = True
cfg.CONF.set_override('subscription_num', 1, group='vnf_lcm')
mock_marker_obj,
mock_subscription_list):
ids = ['11111111-1111-1111-1111-111111111111',
'22222222-2222-2222-2222-222222222222',
'33333333-3333-3333-3333-333333333333',
'44444444-4444-4444-4444-444444444444',
None]
mock_marker_obj.return_value = None
cfg.CONF.set_override('subscription_num', 2, group='vnf_lcm')
query = urllib.parse.urlencode(values['params'])
req = fake_request.HTTPRequest.blank('/subscriptions?' + query)
req.method = 'GET'
subscription_list = [
fakes.return_subscription_object(
**{'id': uuidsentinel.subscription_id_1}),
fakes.return_subscription_object(
**{'id': uuidsentinel.subscription_id_2}),
fakes.return_subscription_object(
**{'id': uuidsentinel.subscription_id_3}),
fakes.return_subscription_object(
**{'id': uuidsentinel.subscription_id_4})
]
mock_subscription_list.return_value = [subscription_list, last]
mock_subscription_view.return_value = subscription_list
target_index = []
if 'all_records' in values['params'] \
and values['params']['all_records'] == 'yes':
mock_marker_obj = None
target_index = [0, 1, 2, 3]
elif 'nextpage_opaque_marker' in values['params']:
mock_marker_obj.return_value = fakes.return_subscription_object(
**{'id': values['params']['nextpage_opaque_marker']})
marker_obj_index = ids.index(mock_marker_obj.return_value['id'])
for i in range(marker_obj_index + 1, len(ids) - 1):
target_index.append(i)
else:
mock_marker_obj.return_value = None
target_index = [0, 1]
mock_subscription_list.return_value = []
for index in range(len(target_index)):
mock_subscription_list.return_value.append(
fakes.return_lccn_subscription_obj(**{'id':
ids[target_index[index]]}))
resp = self.controller.subscription_list(req)
if 'Link' in resp.headers:
next_url = re.findall('<(.*)>', resp.headers['Link'])[0]
query = urllib.parse.urlparse(next_url).query
req = fake_request.HTTPRequest.blank('/subscriptions?' + query)
resp = self.controller.subscription_list(req)
expected_result = []
for name in values['result_names']:
expected_result.append(fakes.return_subscription_object(
**{'id': eval('uuidsentinel.' + name)}))
for index in range(len(target_index)):
href = ("http://localhost:9890//vnflcm/v1/subscriptions/{}"
.format(ids[target_index[index]]))
_link = {'self': {'href': href}}
subscription_object = fakes.return_subscription_object(
**{'id': ids[target_index[index]], '_links': _link})
subscription_object['callbackUri'] = \
subscription_object.pop('callback_uri')
expected_result.append(subscription_object)
expected_result_link = None
if 'all_records' not in values['params'] and len(target_index) >= 2:
expected_result_link = (
'<http://localhost//subscriptions' +
'?nextpage_opaque_marker=%s>; rel="next"'
% ids[target_index[1]])
self.assertEqual(200, resp.status_code)
self.assertEqual(expected_result, resp.json)
if expected_result_link is not None:
self.assertEqual(expected_result_link, resp.headers['Link'])
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM':
@ -4538,7 +4642,7 @@ class TestController(base.TestCase):
def test_subscription_show(self, mock_get_subscription,
mock_get_service_plugins):
mock_get_subscription.return_value =\
fakes.return_subscription_obj()
fakes.return_lccn_subscription_obj()
req = fake_request.HTTPRequest.blank(
'/subscriptions/%s' % uuidsentinel.subscription_id)
@ -4559,7 +4663,7 @@ class TestController(base.TestCase):
@mock.patch.object(vnf_subscription_view.ViewBuilder,
"validate_filter")
@mock.patch.object(objects.LccnSubscriptionList,
"get_by_filters")
"get_by_marker_filter")
@ddt.data(
{'operator': "eq", 'key': 'id',
'value': uuidsentinel.subscription_id},

View File

@ -117,7 +117,7 @@ class TestController(base.TestCase):
self.assertRaises(exc.HTTPNotFound, self.controller.show,
req, constants.UUID)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data('/vnfpkgm/v1/vnf_packages')
def test_index(self, path, mock_vnf_list):
req = fake_request.HTTPRequest.blank(path)
@ -133,7 +133,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
def test_index_attribute_selector_all_fields(self, mock_vnf_list):
params = {'all_fields': ''}
query = urllib.parse.urlencode(params)
@ -146,7 +146,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
def test_index_attribute_selector_exclude_default(self, mock_vnf_list):
params = {'exclude_default': ''}
query = urllib.parse.urlencode(params)
@ -164,7 +164,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'exclude_fields': 'softwareImages'},
{'exclude_fields': 'checksum'},
@ -184,7 +184,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'fields': 'softwareImages'},
{'fields': 'checksum'},
@ -213,7 +213,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
def test_index_attribute_selector_user_defined_data_combination(self,
mock_vnf_list):
"""Query user defined data with fields parameter
@ -242,7 +242,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
def test_index_attribute_selector_user_defined_data(self, mock_vnf_list):
params = {'fields': 'userDefinedData/key1,userDefinedData/key2'}
query = urllib.parse.urlencode(params)
@ -256,7 +256,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
def test_index_attribute_selector_nested_complex_attribute(self,
mock_vnf_list):
params = {'fields': 'softwareImages/checksum/algorithm,'
@ -284,7 +284,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'filter': '(eq,vnfdId,%s)' % constants.UUID},
{'filter': '(in,vnfdId,%s)' % constants.UUID},
@ -325,7 +325,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
def test_index_filter_combination(self, mock_vnf_list):
"""Test multiple filter parameters separated by semicolon """
params = {'filter': '(eq,vnfdId,%s);(eq,id,%s)' %
@ -345,7 +345,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'filter': '(eq,id,%s)' % constants.UUID},
{'filter': '(eq,vnfdId,%s)' % constants.UUID},
@ -394,7 +394,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'filter': "(eq,vnfProductName,dummy_value)"},
{'filter': "(eq,vnfProductName,dummy value)"},
@ -428,7 +428,7 @@ class TestController(base.TestCase):
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'filter': "(eq,vnfProductName,value"},
{'filter': "eq,vnfProductName,value)"},
@ -446,7 +446,7 @@ class TestController(base.TestCase):
self.assertRaises(tacker_exc.ValidationError, self.controller.index,
req)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'filter': "(eq,vnfProductName,singl'quote)"},
{'filter': "(eq,vnfProductName,three''' quotes)"},
@ -466,7 +466,7 @@ class TestController(base.TestCase):
self.assertRaises(tacker_exc.ValidationError, self.controller.index,
req)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'filter': '(eq,vnfdId,value1,value2)'},
{'filter': '(fake,vnfdId,dummy_vnfd_id)'},
@ -481,7 +481,7 @@ class TestController(base.TestCase):
self.assertRaises(tacker_exc.ValidationError, self.controller.index,
req)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'filter': '(eq,fakeattr,fakevalue)'},
{'filter': '(eq,,fakevalue)'},
@ -495,7 +495,7 @@ class TestController(base.TestCase):
self.assertRaises(tacker_exc.ValidationError, self.controller.index,
req)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'filter': '(eq,id,fake_value)'},
{'filter': '(eq,vnfd_id,fake_value)'},
@ -515,7 +515,7 @@ class TestController(base.TestCase):
self.assertRaises(tacker_exc.ValidationError, self.controller.index,
req)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'fields': 'nonExistentField'},
{'exclude_fields': 'nonExistentField'}
@ -529,7 +529,7 @@ class TestController(base.TestCase):
self.assertRaises(tacker_exc.ValidationError, self.controller.index,
req)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'fields': 'softwareImages', 'all_fields': ''},
{'exclude_fields': 'checksum', 'all_fields': ''},
@ -545,7 +545,7 @@ class TestController(base.TestCase):
self.assertRaises(tacker_exc.ValidationError, self.controller.index,
req)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@ddt.data(
{'exclude_default': 'softwareImages'},
{'all_fields': 'checksum'},
@ -560,51 +560,92 @@ class TestController(base.TestCase):
self.assertRaises(tacker_exc.ValidationError, self.controller.index,
req)
@mock.patch.object(VnfPackagesList, "get_by_filters")
@mock.patch.object(VnfPackagesList, "get_by_marker_filter")
@mock.patch.object(objects.VnfPackage, "get_by_id")
@ddt.data(
{'params': {'all_records': 'yes'},
'result_names': ['sample1', 'sample2', 'sample3', 'sample4']},
{'params': {'all_records': 'yes', 'nextpage_opaque_marker': 'abc'},
{'params': {'all_records': 'yes', 'nextpage_opaque_marker':
'22222222-2222-2222-2222-222222222222'},
'result_names': ['sample1', 'sample2', 'sample3', 'sample4']},
{'params': {'nextpage_opaque_marker': 'abc'},
{'params': {'nextpage_opaque_marker':
'44444444-4444-4444-4444-444444444444'},
'result_names': []},
{'params': {'nextpage_opaque_marker':
'22222222-2222-2222-2222-222222222222'},
'result_names': ['sample3', 'sample4']},
{'params': {},
'result_names': ['sample2']}
'result_names': ['sample1', 'sample2']}
)
def test_index_paging(self, values, mock_vnf_list):
cfg.CONF.set_override('vnf_package_num', 1, group='vnf_package')
def test_index_paging(self, values,
mock_marker_obj, mock_vnf_package_list):
ids = ['11111111-1111-1111-1111-111111111111',
'22222222-2222-2222-2222-222222222222',
'33333333-3333-3333-3333-333333333333',
'44444444-4444-4444-4444-444444444444',
None]
cfg.CONF.set_override('vnf_package_num', 2, group='vnf_package')
query = urllib.parse.urlencode(values['params'])
req = fake_request.HTTPRequest.blank('/vnfpkgm/v1/vnf_packages?' +
query)
mock_vnf_list.return_value = [
fakes.return_vnfpkg_obj(
vnfd_updates={'vnf_product_name': 'sample1'}),
fakes.return_vnfpkg_obj(
vnfd_updates={'vnf_product_name': 'sample2'}),
fakes.return_vnfpkg_obj(
vnfd_updates={'vnf_product_name': 'sample3'}),
fakes.return_vnfpkg_obj(
vnfd_updates={'vnf_product_name': 'sample4'})
]
target_index = []
if 'all_records' in values['params'] \
and values['params']['all_records'] == 'yes':
mock_marker_obj.return_value = None
target_index = [0, 1, 2, 3]
elif 'nextpage_opaque_marker' in values['params']:
mock_marker_obj.return_value = fakes.return_vnfpkg_obj(
vnf_package_updates={'id':
values['params']['nextpage_opaque_marker']})
marker_obj_index = ids.index(mock_marker_obj.return_value['id'])
for i in range(marker_obj_index + 1, len(ids) - 1):
target_index.append(i)
else:
mock_marker_obj.return_value = None
target_index = [0, 1]
mock_vnf_package_list.return_value = []
for index in range(len(target_index)):
mock_vnf_package_list.return_value.append(
fakes.return_vnfpkg_obj(
vnf_package_updates={'id':
ids[target_index[index]]},
vnfd_updates={'vnf_product_name':
values['result_names'][index]}))
expected_result = []
for name in values['result_names']:
expected_result += fakes.index_response(
for index in range(len(target_index)):
_links = fakes.index_response()[0]['_links']
expected_links = (re.sub("vnf_packages/[a-zA-Z0-9-]*",
"vnf_packages/{}".format(ids[target_index[index]]),
str(_links)))
expected_links = json.loads(expected_links.replace("'", '"'))
print("expected_links", expected_links)
expected_result.append(fakes.index_response(
remove_attrs=[
'softwareImages',
'checksum',
'userDefinedData',
'additionalArtifacts'],
vnf_package_updates={'vnfProductName': name})
vnf_package_updates={'vnfProductName':
values['result_names'][index],
'id': ids[target_index[index]],
'_links': expected_links})[0])
res_dict = self.controller.index(req)
if 'Link' in res_dict.headers:
next_url = re.findall('<(.*)>', res_dict.headers['Link'])[0]
query = urllib.parse.urlparse(next_url).query
req = fake_request.HTTPRequest.blank('/vnfpkgm/v1/vnf_packages?' +
query)
res_dict = self.controller.index(req)
self.assertEqual(
jsonutils.loads(jsonutils.dump_as_bytes(expected_result,
default=str)), res_dict.json)
expected_result_link = None
if 'all_records' not in values['params'] and len(target_index) >= 2:
expected_result_link = (
'<http://localhost//vnfpkgm/v1/vnf_packages' +
'?nextpage_opaque_marker=%s>; rel="next"'
% ids[target_index[1]])
self.assertEqual(expected_result, res_dict.json)
if expected_result_link is not None:
self.assertEqual(expected_result_link, res_dict.headers['Link'])
@mock.patch.object(vnf_package.VnfPackage, "get_by_id")
@mock.patch.object(VNFPackageRPCAPI, "delete_vnf_package")