Fix get information about multiple VNF instances

When getting information about multiple VNF instances with invalid
attribute selector or invalid attribute-based filtering parameters,
tacker return a response with HTTP Code 200 and all information
about VNF instances. However, according to the specification file,
the HTTP code 400 Bad Request shall be returned.

To fix this bug, this patch adds a new check for this api`s
parameters. If it contains unsupported parameters, the HTTP code
400 Bad Request will be returned.

Closes-Bug: #1938108
Change-Id: I3cca6d6fa664dd8f88791516042892369e4972a2
This commit is contained in:
Yi Feng 2021-07-28 11:38:52 +09:00
parent ef982945d9
commit 3bb8791f18
3 changed files with 75 additions and 1 deletions

View File

@ -14,6 +14,7 @@
# under the License.
from functools import cmp_to_key
from functools import wraps
import netaddr
from oslo_config import cfg
import oslo_i18n
@ -30,6 +31,30 @@ from tacker import wsgi
LOG = logging.getLogger(__name__)
def validate_supported_params(supported_params):
"""Decorator for Restful API methods which specifies supported parameters.
If there are unsupported parameters in the request parameters, the http
code 400 Bad Request will be returned and the user will be told which
parameters in the request are not supported.
"""
def decorator(f):
@wraps(f)
def wrapped(*args, **kwargs):
request = kwargs.get('request')
if not request:
request = args[1]
params = set(request.params.keys())
unsupported_params = params - supported_params
if unsupported_params:
msg = _("Not supported parameters: %s") \
% ','.join(unsupported_params)
raise exc.HTTPBadRequest(explanation=msg)
return f(*args, **kwargs)
return wrapped
return decorator
def get_filters(request, attr_info, skips=None):
"""Extract the filters from the request string.

View File

@ -39,6 +39,7 @@ from http import client as http_client
from urllib import parse
from tacker._i18n import _
from tacker.api import api_common
from tacker.api.schemas import vnf_lcm
from tacker.api import validation
from tacker.api.views import vnf_lcm as vnf_lcm_view
@ -562,7 +563,8 @@ class VnfLcmController(wsgi.Controller):
return self._view_builder.show(vnf_instance)
@wsgi.response(http_client.OK)
@wsgi.expected_errors((http_client.FORBIDDEN))
@wsgi.expected_errors((http_client.FORBIDDEN, http_client.BAD_REQUEST))
@api_common.validate_supported_params({'filter'})
def index(self, request):
context = request.environ['tacker.context']
context.can(vnf_lcm_policies.VNFLCM % 'index')

View File

@ -2013,6 +2013,53 @@ class TestController(base.TestCase):
self.assertRaises(exceptions.ValidationError,
self.controller.index, req)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@ddt.data(
{'attribute_not_exist': 'some_value'},
{'all_fields': {}},
{'fields': {}},
{'exclude_fields': {}},
{'exclude_default': {}},
{'nextpage_opaque_marker': 1},
{'attribute_not_exist': 'some_value', 'filter': {}},
{'attribute_not_exist': 'some_value', 'fields': {}}
)
def test_index_not_supported_params_1(self, params,
mock_vnf_list):
"""Test not supported params in request."""
query = urllib.parse.urlencode(params)
req = fake_request.HTTPRequest.blank(
'/vnflcm/v1/vnf_instances?' + query)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.index, req)
@mock.patch.object(objects.VnfInstanceList, "get_by_filters")
@ddt.data(
{'attribute_not_exist': 'some_value'},
{'all_fields': {}},
{'fields': {}},
{'exclude_fields': {}},
{'exclude_default': {}},
{'nextpage_opaque_marker': 1},
{'attribute_not_exist': 'some_value', 'filter': {}},
{'attribute_not_exist': 'some_value', 'fields': {}}
)
def test_index_not_supported_params_2(self, params,
mock_vnf_list):
query = urllib.parse.urlencode(params)
req = fake_request.HTTPRequest.blank(
f'/vnf_instances?{query}')
req.headers['Content-Type'] = 'application/json'
req.method = 'GET'
params = set(params)
supported_params = {'filter'}
unsupported_params = params - supported_params
msg = _("Not supported parameters: %s") \
% ','.join(unsupported_params)
res = '{"title": "Bad Request", "status": 400, "detail": "%s"}' % msg
resp = req.get_response(self.app)
self.assertEqual(res, resp.text)
@mock.patch.object(TackerManager, 'get_service_plugins',
return_value={'VNFM': FakeVNFMPlugin()})
@mock.patch.object(objects.VnfLcmOpOcc, "get_by_id")