Added goal filter in Watcher API
Although it was proposed via python-watcherclient, the feature was not implemented on the Watcher API. As the notion of host aggregate is currently unused in Watcher, decision was made to only implement the filtering of goal within the Watcher API whilst removing the host_aggregate filter from the Watcher client. Thus, this patchset adds this missing functionality by adding the 'goal' parameter to the API. Change-Id: I54d248f7e470249c6412650ddf50a3e3631d2a09 Related-Bug: #1510189
This commit is contained in:
parent
fe3f6e73be
commit
4e71a0c655
|
@ -197,10 +197,11 @@ class AuditTemplatesController(rest.RestController):
|
|||
'detail': ['GET'],
|
||||
}
|
||||
|
||||
def _get_audit_templates_collection(self, marker, limit,
|
||||
def _get_audit_templates_collection(self, filters, marker, limit,
|
||||
sort_key, sort_dir, expand=False,
|
||||
resource_url=None):
|
||||
|
||||
api_utils.validate_search_filters(
|
||||
filters, objects.audit_template.AuditTemplate.fields.keys())
|
||||
limit = api_utils.validate_limit(limit)
|
||||
sort_dir = api_utils.validate_sort_dir(sort_dir)
|
||||
|
||||
|
@ -212,6 +213,7 @@ class AuditTemplatesController(rest.RestController):
|
|||
|
||||
audit_templates = objects.AuditTemplate.list(
|
||||
pecan.request.context,
|
||||
filters,
|
||||
limit,
|
||||
marker_obj, sort_key=sort_key,
|
||||
sort_dir=sort_dir)
|
||||
|
@ -223,26 +225,30 @@ class AuditTemplatesController(rest.RestController):
|
|||
sort_key=sort_key,
|
||||
sort_dir=sort_dir)
|
||||
|
||||
@wsme_pecan.wsexpose(AuditTemplateCollection, types.uuid, int,
|
||||
wtypes.text, wtypes.text)
|
||||
def get_all(self, marker=None, limit=None,
|
||||
@wsme_pecan.wsexpose(AuditTemplateCollection, wtypes.text,
|
||||
types.uuid, int, wtypes.text, wtypes.text)
|
||||
def get_all(self, goal=None, marker=None, limit=None,
|
||||
sort_key='id', sort_dir='asc'):
|
||||
"""Retrieve a list of audit templates.
|
||||
|
||||
:param goal: goal name to filter by (case sensitive)
|
||||
:param marker: pagination marker for large data sets.
|
||||
:param limit: maximum number of resources to return in a single result.
|
||||
:param sort_key: column to sort results by. Default: id.
|
||||
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
|
||||
"""
|
||||
return self._get_audit_templates_collection(marker, limit, sort_key,
|
||||
sort_dir)
|
||||
filters = api_utils.as_filters_dict(goal=goal)
|
||||
|
||||
@wsme_pecan.wsexpose(AuditTemplateCollection, types.uuid, int,
|
||||
return self._get_audit_templates_collection(
|
||||
filters, marker, limit, sort_key, sort_dir)
|
||||
|
||||
@wsme_pecan.wsexpose(AuditTemplateCollection, wtypes.text, types.uuid, int,
|
||||
wtypes.text, wtypes.text)
|
||||
def detail(self, marker=None, limit=None,
|
||||
def detail(self, goal=None, marker=None, limit=None,
|
||||
sort_key='id', sort_dir='asc'):
|
||||
"""Retrieve a list of audit templates with detail.
|
||||
|
||||
:param goal: goal name to filter by (case sensitive)
|
||||
:param marker: pagination marker for large data sets.
|
||||
:param limit: maximum number of resources to return in a single result.
|
||||
:param sort_key: column to sort results by. Default: id.
|
||||
|
@ -253,9 +259,11 @@ class AuditTemplatesController(rest.RestController):
|
|||
if parent != "audit_templates":
|
||||
raise exception.HTTPNotFound
|
||||
|
||||
filters = api_utils.as_filters_dict(goal=goal)
|
||||
|
||||
expand = True
|
||||
resource_url = '/'.join(['audit_templates', 'detail'])
|
||||
return self._get_audit_templates_collection(marker, limit,
|
||||
return self._get_audit_templates_collection(filters, marker, limit,
|
||||
sort_key, sort_dir, expand,
|
||||
resource_url)
|
||||
|
||||
|
@ -263,7 +271,7 @@ class AuditTemplatesController(rest.RestController):
|
|||
def get_one(self, audit_template):
|
||||
"""Retrieve information about the given audit template.
|
||||
|
||||
:param audit template_uuid: UUID or name of an audit template.
|
||||
:param audit audit_template: UUID or name of an audit template.
|
||||
"""
|
||||
if self.from_audit_templates:
|
||||
raise exception.OperationNotPermitted
|
||||
|
|
|
@ -50,6 +50,15 @@ def validate_sort_dir(sort_dir):
|
|||
return sort_dir
|
||||
|
||||
|
||||
def validate_search_filters(filters, allowed_fields):
|
||||
# Very leightweight validation for now
|
||||
# todo: improve this (e.g. https://www.parse.com/docs/rest/guide/#queries)
|
||||
for filter_name in filters.keys():
|
||||
if filter_name not in allowed_fields:
|
||||
raise wsme.exc.ClientSideError(
|
||||
_("Invalid filter: %s") % filter_name)
|
||||
|
||||
|
||||
def apply_jsonpatch(doc, patch):
|
||||
for p in patch:
|
||||
if p['op'] == 'add' and p['path'].count('/') == 1:
|
||||
|
@ -58,3 +67,12 @@ def apply_jsonpatch(doc, patch):
|
|||
' the resource is not allowed')
|
||||
raise wsme.exc.ClientSideError(msg % p['path'])
|
||||
return jsonpatch.apply_patch(doc, jsonpatch.JsonPatch(patch))
|
||||
|
||||
|
||||
def as_filters_dict(**filters):
|
||||
filters_dict = {}
|
||||
for filter_name, filter_value in filters.items():
|
||||
if filter_value:
|
||||
filters_dict[filter_name] = filter_value
|
||||
|
||||
return filters_dict
|
||||
|
|
|
@ -164,7 +164,7 @@ class AuditTemplate(base.WatcherObject):
|
|||
return audit_template
|
||||
|
||||
@classmethod
|
||||
def list(cls, context, limit=None, marker=None,
|
||||
def list(cls, context, filters=None, limit=None, marker=None,
|
||||
sort_key=None, sort_dir=None):
|
||||
"""Return a list of :class:`AuditTemplate` objects.
|
||||
|
||||
|
@ -174,6 +174,7 @@ class AuditTemplate(base.WatcherObject):
|
|||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: AuditTemplate(context)
|
||||
:param filters: dict mapping the filter key to a value.
|
||||
:param limit: maximum number of resources to return in a single result.
|
||||
:param marker: pagination marker for large data sets.
|
||||
:param sort_key: column to sort results by.
|
||||
|
@ -183,6 +184,7 @@ class AuditTemplate(base.WatcherObject):
|
|||
|
||||
db_audit_templates = cls.dbapi.get_audit_template_list(
|
||||
context,
|
||||
filters=filters,
|
||||
limit=limit,
|
||||
marker=marker,
|
||||
sort_key=sort_key,
|
||||
|
|
|
@ -207,6 +207,25 @@ class TestListAuditTemplate(api_base.FunctionalTest):
|
|||
next_marker = response['audit_templates'][-1]['uuid']
|
||||
self.assertIn(next_marker, response['next'])
|
||||
|
||||
def test_filter_by_goal(self):
|
||||
cfg.CONF.set_override('goals', {"DUMMY": "DUMMY", "BASIC": "BASIC"},
|
||||
group='watcher_goals', enforce_type=True)
|
||||
|
||||
for id_ in range(2):
|
||||
obj_utils.create_test_audit_template(
|
||||
self.context, id=id_, uuid=utils.generate_uuid(),
|
||||
name='My Audit Template {0}'.format(id_),
|
||||
goal="DUMMY")
|
||||
|
||||
for id_ in range(2, 5):
|
||||
obj_utils.create_test_audit_template(
|
||||
self.context, id=id_, uuid=utils.generate_uuid(),
|
||||
name='My Audit Template {0}'.format(id_),
|
||||
goal="BASIC")
|
||||
|
||||
response = self.get_json('/audit_templates?goal=BASIC')
|
||||
self.assertEqual(3, len(response['audit_templates']))
|
||||
|
||||
|
||||
class TestPatch(api_base.FunctionalTest):
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
|
||||
import wsme
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from watcher.api.controllers.v1 import utils
|
||||
from watcher.tests import base
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
|
@ -47,3 +47,21 @@ class TestApiUtils(base.TestCase):
|
|||
self.assertRaises(wsme.exc.ClientSideError,
|
||||
utils.validate_sort_dir,
|
||||
'fake-sort')
|
||||
|
||||
def test_validate_search_filters(self):
|
||||
allowed_fields = ["allowed", "authorized"]
|
||||
|
||||
test_filters = {"allowed": 1, "authorized": 2}
|
||||
try:
|
||||
utils.validate_search_filters(test_filters, allowed_fields)
|
||||
except Exception as exc:
|
||||
self.fail(exc)
|
||||
|
||||
def test_validate_search_filters_with_invalid_key(self):
|
||||
allowed_fields = ["allowed", "authorized"]
|
||||
|
||||
test_filters = {"allowed": 1, "unauthorized": 2}
|
||||
|
||||
self.assertRaises(
|
||||
wsme.exc.ClientSideError, utils.validate_search_filters,
|
||||
test_filters, allowed_fields)
|
||||
|
|
|
@ -227,7 +227,7 @@ class TestClients(base.BaseTestCase):
|
|||
@mock.patch.object(clients.OpenStackClients, 'session')
|
||||
def test_clients_neutron_diff_vers(self, mock_session):
|
||||
'''neutronclient currently only has one version (v2)'''
|
||||
cfg.CONF.set_override('api_version', '2',
|
||||
cfg.CONF.set_override('api_version', '2.0',
|
||||
group='neutron_client')
|
||||
osc = clients.OpenStackClients()
|
||||
osc._neutron = None
|
||||
|
|
Loading…
Reference in New Issue