Support attribute filtering for List VNF
Supported Attribute Filtering, filter defined in SOL013. Implements: blueprint support-etsi-nfv-specs Spec: https://specs.openstack.org/openstack/tacker-specs/specs/victoria/enhancement_enhance-vnf-lcm-api-support.html Change-Id: I98ce706a5081bbfa4947d782e2e28cd7667c5fdd
This commit is contained in:
parent
128cd17766
commit
60dd90d02b
|
@ -410,6 +410,8 @@ List VNF Instance
|
|||
.. rest_method:: GET /vnflcm/v1/vnf_instances
|
||||
|
||||
The GET method queries information about multiple VNF instances.
|
||||
In Victoria release, added attribute-based filtering expression (for VnfInstance)
|
||||
that follows clause 5.2 of ETSI GS NFV SOL13.
|
||||
|
||||
Response Codes
|
||||
--------------
|
||||
|
|
|
@ -13,11 +13,15 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tacker.api import views as base
|
||||
from tacker.common import utils
|
||||
from tacker.objects import fields
|
||||
from tacker.objects import vnf_instance as _vnf_instance
|
||||
|
||||
|
||||
class ViewBuilder(object):
|
||||
class ViewBuilder(base.BaseViewBuilder):
|
||||
|
||||
FLATTEN_ATTRIBUTES = _vnf_instance.VnfInstance.FLATTEN_ATTRIBUTES
|
||||
|
||||
def _get_links(self, vnf_instance):
|
||||
links = {
|
||||
|
@ -54,7 +58,8 @@ class ViewBuilder(object):
|
|||
|
||||
return {"_links": links}
|
||||
|
||||
def _get_vnf_instance_info(self, vnf_instance):
|
||||
def _get_vnf_instance_info(self,
|
||||
vnf_instance, api_version=None):
|
||||
vnf_instance_dict = vnf_instance.to_dict()
|
||||
if 'vnf_metadata' in vnf_instance_dict:
|
||||
metadata_val = vnf_instance_dict.pop('vnf_metadata')
|
||||
|
@ -63,6 +68,9 @@ class ViewBuilder(object):
|
|||
vnf_instance_dict = utils.convert_snakecase_to_camelcase(
|
||||
vnf_instance_dict)
|
||||
|
||||
if api_version == "2.6.1":
|
||||
del vnf_instance_dict["vnfPkgId"]
|
||||
|
||||
links = self._get_links(vnf_instance)
|
||||
|
||||
vnf_instance_dict.update(links)
|
||||
|
@ -74,6 +82,6 @@ class ViewBuilder(object):
|
|||
def show(self, vnf_instance):
|
||||
return self._get_vnf_instance_info(vnf_instance)
|
||||
|
||||
def index(self, vnf_instances):
|
||||
return [self._get_vnf_instance_info(vnf_instance)
|
||||
def index(self, vnf_instances, api_version=None):
|
||||
return [self._get_vnf_instance_info(vnf_instance, api_version)
|
||||
for vnf_instance in vnf_instances]
|
||||
|
|
|
@ -207,8 +207,16 @@ class VnfLcmController(wsgi.Controller):
|
|||
@wsgi.expected_errors((http_client.FORBIDDEN))
|
||||
def index(self, request):
|
||||
context = request.environ['tacker.context']
|
||||
vnf_instances = objects.VnfInstanceList.get_all(context)
|
||||
return self._view_builder.index(vnf_instances)
|
||||
context.can(vnf_lcm_policies.VNFLCM % 'index')
|
||||
|
||||
filters = request.GET.get('filter')
|
||||
filters = self._view_builder.validate_filter(filters)
|
||||
|
||||
vnf_instances = objects.VnfInstanceList.get_by_filters(
|
||||
request.context, filters=filters)
|
||||
|
||||
api_version = request.headers['Version']
|
||||
return self._view_builder.index(vnf_instances, api_version)
|
||||
|
||||
@check_vnf_state(action="delete",
|
||||
instantiation_state=[fields.VnfInstanceState.NOT_INSTANTIATED],
|
||||
|
|
|
@ -18,15 +18,18 @@ from oslo_utils import timeutils
|
|||
from oslo_utils import uuidutils
|
||||
from oslo_versionedobjects import base as ovoo_base
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy_filters import apply_filters
|
||||
|
||||
from tacker._i18n import _
|
||||
from tacker.common import exceptions
|
||||
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 import objects
|
||||
from tacker.objects import base
|
||||
from tacker.objects import fields
|
||||
from tacker.objects import vnf_instantiated_info
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -100,6 +103,23 @@ def _vnf_instance_list(context, columns_to_join=None):
|
|||
return query.all()
|
||||
|
||||
|
||||
@db_api.context_manager.reader
|
||||
def _vnf_instance_list_by_filter(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 = apply_filters(query, filters)
|
||||
|
||||
return query.all()
|
||||
|
||||
|
||||
def _make_vnf_instance_list(context, vnf_instance_list, db_vnf_instance_list,
|
||||
expected_attrs):
|
||||
vnf_instance_cls = VnfInstance
|
||||
|
@ -143,6 +163,34 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject,
|
|||
'vnf_metadata': fields.DictOfStringsField(nullable=True, default={})
|
||||
}
|
||||
|
||||
ALL_ATTRIBUTES = {
|
||||
'id': ('id', "string", 'VnfInstance'),
|
||||
'vnfInstanceName': ('vnf_instance_name', 'string', 'VnfInstance'),
|
||||
'vnfInstanceDescription': (
|
||||
'vnf_instance_description', 'string', 'VnfInstance'),
|
||||
'instantiationState': ('instantiation_state', 'string', 'VnfInstance'),
|
||||
'taskState': ('task_state', 'string', 'VnfInstance'),
|
||||
'vnfdId': ('vnfd_id', 'string', 'VnfInstance'),
|
||||
'vnfProvider': ('vnf_provider', 'string', 'VnfInstance'),
|
||||
'vnfProductName': ('vnf_product_name', 'string', 'VnfInstance'),
|
||||
'vnfSoftwareVersion': (
|
||||
'vnf_software_version', 'string', 'VnfInstance'),
|
||||
'vnfdVersion': ('vnfd_version', 'string', 'VnfInstance'),
|
||||
'tenantId': ('tenant_id', 'string', 'VnfInstance'),
|
||||
'vnfPkgId': ('vnf_pkg_id', 'string', 'VnfInstance'),
|
||||
'vimConnectionInfo/*': ('vim_connection_info', 'key_value_pair',
|
||||
{"key_column": "key", "value_column": "value",
|
||||
"model": "VnfInstance"}),
|
||||
'metadata/*': ('vnf_metadata', 'key_value_pair',
|
||||
{"key_column": "key", "value_column": "value",
|
||||
"model": "VnfInstance"}),
|
||||
}
|
||||
|
||||
ALL_ATTRIBUTES.update(
|
||||
vnf_instantiated_info.InstantiatedVnfInfo.ALL_ATTRIBUTES)
|
||||
|
||||
FLATTEN_ATTRIBUTES = utils.flatten_dict(ALL_ATTRIBUTES.copy())
|
||||
|
||||
def __init__(self, context=None, **kwargs):
|
||||
super(VnfInstance, self).__init__(context, **kwargs)
|
||||
self.obj_set_defaults()
|
||||
|
@ -286,3 +334,14 @@ class VnfInstanceList(ovoo_base.ObjectListBase, base.TackerObject):
|
|||
columns_to_join=expected_attrs)
|
||||
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):
|
||||
expected_attrs = ["instantiated_vnf_info"]
|
||||
db_vnf_instances = _vnf_instance_list_by_filter(
|
||||
context, columns_to_join=expected_attrs,
|
||||
filters=filters)
|
||||
|
||||
return _make_vnf_instance_list(context, cls(), db_vnf_instances,
|
||||
expected_attrs)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
from oslo_log import log as logging
|
||||
|
||||
from tacker.common import exceptions
|
||||
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
|
||||
|
@ -78,9 +79,48 @@ class InstantiatedVnfInfo(base.TackerObject, base.TackerObjectDictCompat,
|
|||
default=None),
|
||||
'additional_params': fields.DictOfStringsField(nullable=True,
|
||||
default={})
|
||||
|
||||
}
|
||||
|
||||
ALL_ATTRIBUTES = {
|
||||
'instantiatedInfo': {
|
||||
'flavourId': ('id', 'string', 'VnfInstantiatedInfo'),
|
||||
'vnfInstanceId':
|
||||
('vnf_instance_id', 'string', 'VnfInstantiatedInfo'),
|
||||
'vnfState': ('vnf_state', 'string', 'VnfInstantiatedInfo'),
|
||||
'instanceId': ('instance_id', 'string', 'VnfInstantiatedInfo'),
|
||||
'instantiationLevelId':
|
||||
('instantiation_level_id', 'string', 'VnfInstantiatedInfo'),
|
||||
'extCpInfo/*': ('ext_cp_info', 'key_value_pair',
|
||||
{"key_column": "key", "value_column": "value",
|
||||
"model": "VnfInstantiatedInfo"}),
|
||||
'extVirtualLinkInfo/*': ('ext_virtual_link_info', 'key_value_pair',
|
||||
{"key_column": "key", "value_column": "value",
|
||||
"model": "VnfInstantiatedInfo"}),
|
||||
'extManagedVirtualLinkInfo/*': (
|
||||
'ext_managed_virtual_link_info', 'key_value_pair',
|
||||
{"key_column": "key", "value_column": "value",
|
||||
"model": "VnfInstantiatedInfo"}),
|
||||
'vnfcResourceInfo/*': (
|
||||
'vnfc_resource_info', 'key_value_pair',
|
||||
{"key_column": "key", "value_column": "value",
|
||||
"model": "VnfInstantiatedInfo"}),
|
||||
'vnfVirtualLinkResourceInfo/*': (
|
||||
'vnf_virtual_link_resource_info', 'key_value_pair',
|
||||
{"key_column": "key", "value_column": "value",
|
||||
"model": "VnfInstantiatedInfo"}),
|
||||
'virtualStorageResourceInfo/*': (
|
||||
'virtual_storage_resource_info', 'key_value_pair',
|
||||
{"key_column": "key", "value_column": "value",
|
||||
"model": "VnfInstantiatedInfo"}),
|
||||
'additionalParams/*': (
|
||||
'additional_params', 'key_value_pair',
|
||||
{"key_column": "key", "value_column": "value",
|
||||
"model": "VnfInstantiatedInfo"}),
|
||||
}
|
||||
}
|
||||
|
||||
FLATTEN_ATTRIBUTES = utils.flatten_dict(ALL_ATTRIBUTES.copy())
|
||||
|
||||
@staticmethod
|
||||
def _from_db_object(context, inst_vnf_info, db_inst_vnf_info):
|
||||
|
||||
|
|
|
@ -130,6 +130,19 @@ class TestVnfInstance(SqlTestCase):
|
|||
self.assertTrue(result.objects, list)
|
||||
self.assertTrue(result.objects)
|
||||
|
||||
def test_vnf_instance_list_get_by_filters(self):
|
||||
vnf_instance_data = fakes.get_vnf_instance_data(
|
||||
self.vnf_package.vnfd_id)
|
||||
vnf_instance = objects.VnfInstance(context=self.context,
|
||||
**vnf_instance_data)
|
||||
vnf_instance.create()
|
||||
filters = {'field': 'instantiation_state', 'model': 'VnfInstance',
|
||||
'value': 'NOT_INSTANTIATED',
|
||||
'op': '=='}
|
||||
vnf_instance_list = objects.VnfInstanceList.get_by_filters(
|
||||
self.context, filters=filters)
|
||||
self.assertEqual(1, len(vnf_instance_list))
|
||||
|
||||
@mock.patch('tacker.objects.vnf_instance._destroy_vnf_instance')
|
||||
def test_destroy(self, mock_vnf_destroy):
|
||||
vnf_instance_data = fakes.get_vnf_instance_data(
|
||||
|
|
|
@ -172,7 +172,7 @@ def _fake_vnf_instance_not_instantiated_response(
|
|||
|
||||
def fake_vnf_instance_response(
|
||||
instantiated_state=fields.VnfInstanceState.NOT_INSTANTIATED,
|
||||
**updates):
|
||||
api_version=None, **updates):
|
||||
if instantiated_state == fields.VnfInstanceState.NOT_INSTANTIATED:
|
||||
data = _fake_vnf_instance_not_instantiated_response(**updates)
|
||||
else:
|
||||
|
@ -191,6 +191,9 @@ def fake_vnf_instance_response(
|
|||
|
||||
data['instantiatedVnfInfo'] = _instantiated_vnf_info()
|
||||
|
||||
if api_version == '2.6.1':
|
||||
del data['vnfPkgId']
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
|
|
@ -17,11 +17,12 @@ from unittest import mock
|
|||
import ddt
|
||||
from oslo_serialization import jsonutils
|
||||
from six.moves import http_client
|
||||
import urllib
|
||||
from webob import exc
|
||||
|
||||
from tacker.api.vnflcm.v1 import controller
|
||||
from tacker.common import exceptions
|
||||
import tacker.conductor.conductorrpc.vnf_lcm_rpc as vnf_lcm_rpc
|
||||
from tacker.conductor.conductorrpc.vnf_lcm_rpc import VNFLcmRPCAPI
|
||||
from tacker.extensions import nfvo
|
||||
from tacker import objects
|
||||
from tacker.objects import fields
|
||||
|
@ -327,7 +328,7 @@ class TestController(base.TestCase):
|
|||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "instantiate")
|
||||
@mock.patch.object(VNFLcmRPCAPI, "instantiate")
|
||||
def test_instantiate_with_deployment_flavour(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id, mock_save,
|
||||
|
@ -384,7 +385,7 @@ class TestController(base.TestCase):
|
|||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "instantiate")
|
||||
@mock.patch.object(VNFLcmRPCAPI, "instantiate")
|
||||
def test_instantiate_with_instantiation_level(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id, mock_save,
|
||||
|
@ -415,7 +416,7 @@ class TestController(base.TestCase):
|
|||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "instantiate")
|
||||
@mock.patch.object(VNFLcmRPCAPI, "instantiate")
|
||||
def test_instantiate_with_no_inst_level_in_flavour(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id, mock_save,
|
||||
|
@ -448,7 +449,7 @@ class TestController(base.TestCase):
|
|||
@mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "instantiate")
|
||||
@mock.patch.object(VNFLcmRPCAPI, "instantiate")
|
||||
def test_instantiate_with_non_existing_instantiation_level(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id,
|
||||
|
@ -480,7 +481,7 @@ class TestController(base.TestCase):
|
|||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@mock.patch.object(objects.VnfPackageVnfd, 'get_by_id')
|
||||
@mock.patch.object(objects.VnfPackage, "get_by_id")
|
||||
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "instantiate")
|
||||
@mock.patch.object(VNFLcmRPCAPI, "instantiate")
|
||||
def test_instantiate_with_vim_connection(
|
||||
self, mock_instantiate, mock_vnf_package_get_by_id,
|
||||
mock_vnf_package_vnfd_get_by_id, mock_save,
|
||||
|
@ -821,7 +822,7 @@ class TestController(base.TestCase):
|
|||
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "terminate")
|
||||
@mock.patch.object(VNFLcmRPCAPI, "terminate")
|
||||
@ddt.data({'terminationType': 'FORCEFUL'},
|
||||
{'terminationType': 'GRACEFUL'},
|
||||
{'terminationType': 'GRACEFUL',
|
||||
|
@ -961,7 +962,7 @@ class TestController(base.TestCase):
|
|||
|
||||
@mock.patch.object(objects.VnfInstance, "get_by_id")
|
||||
@mock.patch.object(objects.VnfInstance, "save")
|
||||
@mock.patch.object(vnf_lcm_rpc.VNFLcmRPCAPI, "heal")
|
||||
@mock.patch.object(VNFLcmRPCAPI, "heal")
|
||||
@ddt.data({'cause': 'healing'}, {})
|
||||
def test_heal(self, body, mock_rpc_heal, mock_save,
|
||||
mock_vnf_by_id):
|
||||
|
@ -1096,24 +1097,29 @@ class TestController(base.TestCase):
|
|||
|
||||
self.assertEqual(expected_message, exception.msg)
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_all")
|
||||
def test_index(self, mock_vnf_list):
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(' ', '2.6.1')
|
||||
def test_index(self, api_version, mock_vnf_list):
|
||||
req = fake_request.HTTPRequest.blank('/vnf_instances')
|
||||
req.headers['Version'] = api_version
|
||||
vnf_instance_1 = fakes.return_vnf_instance()
|
||||
vnf_instance_2 = fakes.return_vnf_instance(
|
||||
fields.VnfInstanceState.INSTANTIATED)
|
||||
|
||||
mock_vnf_list.return_value = [vnf_instance_1, vnf_instance_2]
|
||||
resp = self.controller.index(req)
|
||||
expected_result = [fakes.fake_vnf_instance_response(),
|
||||
expected_result = [fakes.fake_vnf_instance_response(
|
||||
api_version=api_version),
|
||||
fakes.fake_vnf_instance_response(
|
||||
fields.VnfInstanceState.INSTANTIATED)]
|
||||
fields.VnfInstanceState.INSTANTIATED,
|
||||
api_version=api_version)]
|
||||
self.assertEqual(expected_result, resp)
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_all")
|
||||
def test_index_empty_response(self, mock_vnf_list):
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(' ', '2.6.1')
|
||||
def test_index_empty_response(self, api_version, mock_vnf_list):
|
||||
req = fake_request.HTTPRequest.blank('/vnf_instances')
|
||||
|
||||
req.headers['Version'] = api_version
|
||||
mock_vnf_list.return_value = []
|
||||
resp = self.controller.index(req)
|
||||
self.assertEqual([], resp)
|
||||
|
@ -1212,3 +1218,212 @@ class TestController(base.TestCase):
|
|||
"is in this state.")
|
||||
self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id,
|
||||
resp.json['conflictingRequest']['message'])
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'filter': "(eq,vnfInstanceName,'dummy_name')"},
|
||||
{'filter': "(in,vnfInstanceName,'dummy_name')"},
|
||||
{'filter': "(cont,vnfInstanceName,'dummy_name')"},
|
||||
{'filter': "(neq,vnfInstanceName,'dummy_name')"},
|
||||
{'filter': "(nin,vnfInstanceName,'dummy_name')"},
|
||||
{'filter': "(ncont,vnfInstanceName,'dummy_name')"},
|
||||
{'filter': "(gt,vnfdVersion, 1)"},
|
||||
{'filter': "(gte,vnfdVersion, 1)"},
|
||||
{'filter': "(lt,vnfdVersion, 1)"},
|
||||
{'filter': "(lte,vnfdVersion, 1)"},
|
||||
)
|
||||
def test_index_filter_operator(self, filter_params, mock_vnf_list):
|
||||
"""Tests all supported operators in filter expression."""
|
||||
api_version = '2.6.1'
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_instances?' + query)
|
||||
req.headers['Version'] = api_version
|
||||
|
||||
vnf_instance_1 = fakes.return_vnf_instance()
|
||||
vnf_instance_2 = fakes.return_vnf_instance(
|
||||
fields.VnfInstanceState.INSTANTIATED)
|
||||
|
||||
mock_vnf_list.return_value = [vnf_instance_1, vnf_instance_2]
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
expected_result = [fakes.fake_vnf_instance_response(
|
||||
api_version=api_version),
|
||||
fakes.fake_vnf_instance_response(
|
||||
fields.VnfInstanceState.INSTANTIATED,
|
||||
api_version=api_version)]
|
||||
self.assertEqual(expected_result, res_dict)
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
def test_index_filter_combination(self, mock_vnf_list):
|
||||
"""Test multiple filter parameters separated by semicolon."""
|
||||
params = {
|
||||
'filter': "(eq,vnfInstanceName,'dummy_name');"
|
||||
"(eq,vnfInstanceDescription,'dummy_desc')"}
|
||||
|
||||
api_version = '2.6.1'
|
||||
query = urllib.parse.urlencode(params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_instances?' + query)
|
||||
req.headers['Version'] = '2.6.1'
|
||||
|
||||
vnf_instance_1 = fakes.return_vnf_instance()
|
||||
vnf_instance_2 = fakes.return_vnf_instance(
|
||||
fields.VnfInstanceState.INSTANTIATED)
|
||||
|
||||
mock_vnf_list.return_value = [vnf_instance_1, vnf_instance_2]
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
expected_result = [fakes.fake_vnf_instance_response(
|
||||
api_version=api_version),
|
||||
fakes.fake_vnf_instance_response(
|
||||
fields.VnfInstanceState.INSTANTIATED,
|
||||
api_version=api_version)]
|
||||
self.assertEqual(expected_result, res_dict)
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'filter': "(eq,vnfInstanceName,dummy_value)"},
|
||||
{'filter': "(eq,vnfInstanceDescription,dummy value)"},
|
||||
{'filter': "(eq,instantiationState,'NOT_INSTANTIATED')"},
|
||||
{'filter': "(eq,taskState,'ACTIVE')"},
|
||||
{'filter': "(eq,vnfdId,'dummy_vnfd_id')"},
|
||||
{'filter': "(eq,vnfProvider,'''dummy ''hi'' value''')"},
|
||||
{'filter': "(eq,vnfProductName,'dummy_product_name')"},
|
||||
{'filter': "(eq,vnfSoftwareVersion,'1.0')"},
|
||||
{'filter': "(eq,vnfdVersion,'dummy_vnfd_version')"},
|
||||
{'filter': "(eq,tenantId,'dummy_tenant_id')"},
|
||||
{'filter': "(eq,vnfPkgId,'dummy_pkg_id')"},
|
||||
{'filter': "(eq,vimConnectionInfo/accessInfo/region,'dummy_id')"},
|
||||
{'filter': "(eq,instantiatedInfo/flavourId,'dummy_flavour')"},
|
||||
{'filter': "(eq,instantiatedInfo/vnfInstanceId,'dummy_vnf_id')"},
|
||||
{'filter': "(eq,instantiatedInfo/vnfState,'ACTIVE')"},
|
||||
{'filter': "(eq,instantiatedInfo/instanceId,'dummy_vnf_id')"},
|
||||
{'filter':
|
||||
"(eq,instantiatedInfo/instantiationLevelId,'dummy_level_id')"},
|
||||
{'filter': "(eq,instantiatedInfo/extCpInfo/id,'dummy_id')"},
|
||||
{'filter': "(eq,instantiatedInfo/extVirtualLinkInfo/name,'dummy')"},
|
||||
{'filter':
|
||||
"(eq,instantiatedInfo/extManagedVirtualLinkInfo/id,'dummy_id')"},
|
||||
{'filter': "(eq,instantiatedInfo/vnfcResourceInfo/vduId,'dummy_id')"},
|
||||
{'filter':
|
||||
"(eq,instantiatedInfo/vnfVirtualLinkResourceInfo/"
|
||||
"vnfVirtualLinkDescId,'dummy_id')"},
|
||||
{'filter':
|
||||
"(eq,instantiatedInfo/virtualStorageResourceInfo/"
|
||||
"virtualStorageDescId,'dummy_id')"},
|
||||
{'filter': "(eq,instantiatedInfo/additionalParams/error,'dummy')"},
|
||||
)
|
||||
def test_index_filter_attributes(self, filter_params,
|
||||
mock_vnf_list):
|
||||
"""Test various attributes supported for filter parameter."""
|
||||
api_version = '2.6.1'
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_instances?' + query)
|
||||
req.headers['Version'] = '2.6.1'
|
||||
|
||||
vnf_instance_1 = fakes.return_vnf_instance()
|
||||
vnf_instance_2 = fakes.return_vnf_instance(
|
||||
fields.VnfInstanceState.INSTANTIATED)
|
||||
|
||||
mock_vnf_list.return_value = [vnf_instance_1, vnf_instance_2]
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
expected_result = [fakes.fake_vnf_instance_response(
|
||||
api_version=api_version),
|
||||
fakes.fake_vnf_instance_response(
|
||||
fields.VnfInstanceState.INSTANTIATED,
|
||||
api_version=api_version)]
|
||||
self.assertEqual(expected_result, res_dict)
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'filter': "(eq,vnfInstanceName,value"},
|
||||
{'filter': "eq,vnfInstanceName,value)"},
|
||||
{'filter': "(eq,vnfInstanceName,value);"},
|
||||
{'filter': "(eq , vnfInstanceName ,value)"},
|
||||
)
|
||||
def test_index_filter_invalid_expression(self, filter_params,
|
||||
mock_vnf_list):
|
||||
"""Test invalid filter expression."""
|
||||
api_version = '2.6.1'
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_instances?' + query)
|
||||
req.headers['Version'] = api_version
|
||||
|
||||
self.assertRaises(exceptions.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'filter': "(eq,vnfInstanceName,singl'quote)"},
|
||||
{'filter': "(eq,vnfInstanceName,three''' quotes)"},
|
||||
{'filter': "(eq,vnfInstanceName,round ) bracket)"},
|
||||
{'filter': "(eq,vnfInstanceName,'dummy 'hi' value')"},
|
||||
{'filter': "(eq,vnfInstanceName,'dummy's value')"},
|
||||
{'filter': "(eq,vnfInstanceName,'three ''' quotes')"},
|
||||
)
|
||||
def test_index_filter_invalid_string_values(self, filter_params,
|
||||
mock_vnf_list):
|
||||
"""Test invalid string values as per ETSI NFV SOL013 5.2.2."""
|
||||
api_version = '2.6.1'
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_instances?' + query)
|
||||
req.headers['Version'] = api_version
|
||||
self.assertRaises(exceptions.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'filter': '(eq,vnfdId,value1,value2)'},
|
||||
{'filter': '(fake,vnfdId,dummy_vnfd_id)'},
|
||||
{'filter': '(,vnfdId,dummy_vnfd_id)'},
|
||||
)
|
||||
def test_index_filter_invalid_operator(self, filter_params,
|
||||
mock_vnf_list):
|
||||
"""Test invalid operator in filter expression."""
|
||||
api_version = '2.6.1'
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_instances?' + query)
|
||||
req.headers['Version'] = api_version
|
||||
self.assertRaises(exceptions.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'filter': '(eq,fakeattr,fakevalue)'},
|
||||
{'filter': '(eq,,fakevalue)'},
|
||||
)
|
||||
def test_index_filter_invalid_attribute(self, filter_params,
|
||||
mock_vnf_list):
|
||||
"""Test invalid attribute in filter expression."""
|
||||
api_version = '2.6.1'
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_instances?' + query)
|
||||
req.headers['Version'] = api_version
|
||||
self.assertRaises(exceptions.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
|
||||
@ddt.data(
|
||||
{'filter': '(eq,data/size,fake_value)'},
|
||||
{'filter': '(gt,data/createdAt,fake_value)'},
|
||||
{'filter': '(eq,data/minDisk,fake_value)'},
|
||||
{'filter': '(eq,data/minRam,fake_value)'},
|
||||
)
|
||||
def test_index_filter_invalid_value_type(self, filter_params,
|
||||
mock_vnf_list):
|
||||
"""Test values which doesn't match with attribute data type."""
|
||||
api_version = '2.6.1'
|
||||
query = urllib.parse.urlencode(filter_params)
|
||||
req = fake_request.HTTPRequest.blank(
|
||||
'/vnflcm/v1/vnf_instances?' + query)
|
||||
req.headers['Version'] = api_version
|
||||
self.assertRaises(exceptions.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
|
Loading…
Reference in New Issue