Merge "Added goal filter in Watcher API"
This commit is contained in:
@@ -197,10 +197,11 @@ class AuditTemplatesController(rest.RestController):
|
|||||||
'detail': ['GET'],
|
'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,
|
sort_key, sort_dir, expand=False,
|
||||||
resource_url=None):
|
resource_url=None):
|
||||||
|
api_utils.validate_search_filters(
|
||||||
|
filters, objects.audit_template.AuditTemplate.fields.keys())
|
||||||
limit = api_utils.validate_limit(limit)
|
limit = api_utils.validate_limit(limit)
|
||||||
sort_dir = api_utils.validate_sort_dir(sort_dir)
|
sort_dir = api_utils.validate_sort_dir(sort_dir)
|
||||||
|
|
||||||
@@ -212,6 +213,7 @@ class AuditTemplatesController(rest.RestController):
|
|||||||
|
|
||||||
audit_templates = objects.AuditTemplate.list(
|
audit_templates = objects.AuditTemplate.list(
|
||||||
pecan.request.context,
|
pecan.request.context,
|
||||||
|
filters,
|
||||||
limit,
|
limit,
|
||||||
marker_obj, sort_key=sort_key,
|
marker_obj, sort_key=sort_key,
|
||||||
sort_dir=sort_dir)
|
sort_dir=sort_dir)
|
||||||
@@ -223,26 +225,30 @@ class AuditTemplatesController(rest.RestController):
|
|||||||
sort_key=sort_key,
|
sort_key=sort_key,
|
||||||
sort_dir=sort_dir)
|
sort_dir=sort_dir)
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(AuditTemplateCollection, types.uuid, int,
|
@wsme_pecan.wsexpose(AuditTemplateCollection, wtypes.text,
|
||||||
wtypes.text, wtypes.text)
|
types.uuid, int, wtypes.text, wtypes.text)
|
||||||
def get_all(self, marker=None, limit=None,
|
def get_all(self, goal=None, marker=None, limit=None,
|
||||||
sort_key='id', sort_dir='asc'):
|
sort_key='id', sort_dir='asc'):
|
||||||
"""Retrieve a list of audit templates.
|
"""Retrieve a list of audit templates.
|
||||||
|
|
||||||
|
:param goal: goal name to filter by (case sensitive)
|
||||||
:param marker: pagination marker for large data sets.
|
:param marker: pagination marker for large data sets.
|
||||||
:param limit: maximum number of resources to return in a single result.
|
:param limit: maximum number of resources to return in a single result.
|
||||||
:param sort_key: column to sort results by. Default: id.
|
:param sort_key: column to sort results by. Default: id.
|
||||||
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
|
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
|
||||||
"""
|
"""
|
||||||
return self._get_audit_templates_collection(marker, limit, sort_key,
|
filters = api_utils.as_filters_dict(goal=goal)
|
||||||
sort_dir)
|
|
||||||
|
|
||||||
@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)
|
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'):
|
sort_key='id', sort_dir='asc'):
|
||||||
"""Retrieve a list of audit templates with detail.
|
"""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 marker: pagination marker for large data sets.
|
||||||
:param limit: maximum number of resources to return in a single result.
|
:param limit: maximum number of resources to return in a single result.
|
||||||
:param sort_key: column to sort results by. Default: id.
|
:param sort_key: column to sort results by. Default: id.
|
||||||
@@ -253,9 +259,11 @@ class AuditTemplatesController(rest.RestController):
|
|||||||
if parent != "audit_templates":
|
if parent != "audit_templates":
|
||||||
raise exception.HTTPNotFound
|
raise exception.HTTPNotFound
|
||||||
|
|
||||||
|
filters = api_utils.as_filters_dict(goal=goal)
|
||||||
|
|
||||||
expand = True
|
expand = True
|
||||||
resource_url = '/'.join(['audit_templates', 'detail'])
|
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,
|
sort_key, sort_dir, expand,
|
||||||
resource_url)
|
resource_url)
|
||||||
|
|
||||||
@@ -263,7 +271,7 @@ class AuditTemplatesController(rest.RestController):
|
|||||||
def get_one(self, audit_template):
|
def get_one(self, audit_template):
|
||||||
"""Retrieve information about the given 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:
|
if self.from_audit_templates:
|
||||||
raise exception.OperationNotPermitted
|
raise exception.OperationNotPermitted
|
||||||
|
|||||||
@@ -50,6 +50,15 @@ def validate_sort_dir(sort_dir):
|
|||||||
return 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):
|
def apply_jsonpatch(doc, patch):
|
||||||
for p in patch:
|
for p in patch:
|
||||||
if p['op'] == 'add' and p['path'].count('/') == 1:
|
if p['op'] == 'add' and p['path'].count('/') == 1:
|
||||||
@@ -58,3 +67,12 @@ def apply_jsonpatch(doc, patch):
|
|||||||
' the resource is not allowed')
|
' the resource is not allowed')
|
||||||
raise wsme.exc.ClientSideError(msg % p['path'])
|
raise wsme.exc.ClientSideError(msg % p['path'])
|
||||||
return jsonpatch.apply_patch(doc, jsonpatch.JsonPatch(patch))
|
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
|
return audit_template
|
||||||
|
|
||||||
@classmethod
|
@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):
|
sort_key=None, sort_dir=None):
|
||||||
"""Return a list of :class:`AuditTemplate` objects.
|
"""Return a list of :class:`AuditTemplate` objects.
|
||||||
|
|
||||||
@@ -174,6 +174,7 @@ class AuditTemplate(base.WatcherObject):
|
|||||||
argument, even though we don't use it.
|
argument, even though we don't use it.
|
||||||
A context should be set when instantiating the
|
A context should be set when instantiating the
|
||||||
object, e.g.: AuditTemplate(context)
|
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 limit: maximum number of resources to return in a single result.
|
||||||
:param marker: pagination marker for large data sets.
|
:param marker: pagination marker for large data sets.
|
||||||
:param sort_key: column to sort results by.
|
: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(
|
db_audit_templates = cls.dbapi.get_audit_template_list(
|
||||||
context,
|
context,
|
||||||
|
filters=filters,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
marker=marker,
|
marker=marker,
|
||||||
sort_key=sort_key,
|
sort_key=sort_key,
|
||||||
|
|||||||
@@ -207,6 +207,25 @@ class TestListAuditTemplate(api_base.FunctionalTest):
|
|||||||
next_marker = response['audit_templates'][-1]['uuid']
|
next_marker = response['audit_templates'][-1]['uuid']
|
||||||
self.assertIn(next_marker, response['next'])
|
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):
|
class TestPatch(api_base.FunctionalTest):
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
|
|
||||||
import wsme
|
import wsme
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
from watcher.api.controllers.v1 import utils
|
from watcher.api.controllers.v1 import utils
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
@@ -47,3 +47,21 @@ class TestApiUtils(base.TestCase):
|
|||||||
self.assertRaises(wsme.exc.ClientSideError,
|
self.assertRaises(wsme.exc.ClientSideError,
|
||||||
utils.validate_sort_dir,
|
utils.validate_sort_dir,
|
||||||
'fake-sort')
|
'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')
|
@mock.patch.object(clients.OpenStackClients, 'session')
|
||||||
def test_clients_neutron_diff_vers(self, mock_session):
|
def test_clients_neutron_diff_vers(self, mock_session):
|
||||||
'''neutronclient currently only has one version (v2)'''
|
'''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')
|
group='neutron_client')
|
||||||
osc = clients.OpenStackClients()
|
osc = clients.OpenStackClients()
|
||||||
osc._neutron = None
|
osc._neutron = None
|
||||||
|
|||||||
Reference in New Issue
Block a user