Add regex matching for job_list()

This change implements regex matching for filters on string
    values passed to job_list() in the REST api.
    No existing internal calls that use job_get_all()
    are affected.

    Partial-bug: #1503345

Change-Id: Id19eeae194d7e4c97f041e067f1ee8a57a675815
This commit is contained in:
Trevor McKay 2016-02-10 17:16:09 -05:00
parent cfa193fd34
commit 2f9d4f5a80
6 changed files with 80 additions and 16 deletions

View File

@ -349,12 +349,21 @@ class LocalApi(object):
return self._manager.job_get(context, _get_id(job))
@r.wrap(r.Job)
def job_get_all(self, context, **kwargs):
def job_get_all(self, context, regex_search=False, **kwargs):
"""Get all Jobs filtered by **kwargs.
e.g. job_get_all(name='myjob', type='MapReduce')
:param context: The context, and associated authentication, to use with
this operation
:param regex_search: If True, enable regex matching for filter
values. See the user guide for more information
on how regex matching is handled. If False,
no regex matching is done.
:param kwargs: Specifies values for named fields by which
to constrain the search
"""
return self._manager.job_get_all(context, **kwargs)
return self._manager.job_get_all(context, regex_search, **kwargs)
@r.wrap(r.Job)
def job_create(self, context, values):

View File

@ -504,12 +504,21 @@ class ConductorManager(db_base.Base):
"""Return the Job or None if it does not exist."""
return self.db.job_get(context, job)
def job_get_all(self, context, **kwargs):
def job_get_all(self, context, regex_search=False, **kwargs):
"""Get all Jobs filtered by **kwargs.
e.g. job_get_all(name='myjob', type='MapReduce')
:param context: The context, and associated authentication, to use with
this operation
:param regex_search: If True, enable regex matching for filter
values. See the user guide for more information
on how regex matching is handled. If False,
no regex matching is done.
:param kwargs: Specifies values for named fields by which
to constrain the search
"""
return self.db.job_get_all(context, **kwargs)
return self.db.job_get_all(context, regex_search, **kwargs)
def job_create(self, context, values):
"""Create a Job from the values dictionary."""

View File

@ -380,12 +380,21 @@ def job_get(context, job):
@to_dict
def job_get_all(context, **kwargs):
def job_get_all(context, regex_search=False, **kwargs):
"""Get all Jobs filtered by **kwargs.
e.g. job_get_all(name='myjob', type='MapReduce')
:param context: The context, and associated authentication, to use with
this operation
:param regex_search: If True, enable regex matching for filter
values. See the user guide for more information
on how regex matching is handled. If False,
no regex matching is done.
:param kwargs: Specifies values for named fields by which
to constrain the search
"""
return IMPL.job_get_all(context, **kwargs)
return IMPL.job_get_all(context, regex_search, **kwargs)
@to_dict

View File

@ -924,8 +924,14 @@ def job_get(context, job_id):
return _job_get(context, get_session(), job_id)
def job_get_all(context, **kwargs):
def job_get_all(context, regex_search=False, **kwargs):
regex_cols = ['name', 'description']
query = model_query(m.Job, context)
if regex_search:
query, kwargs = regex_filter(query,
m.Job, regex_cols, kwargs)
return query.filter_by(**kwargs).all()

View File

@ -197,7 +197,7 @@ def data_source_update(id, values):
def get_jobs(**kwargs):
return conductor.job_get_all(context.ctx(), **kwargs)
return conductor.job_get_all(context.ctx(), regex_search=True, **kwargs)
def get_job(id):

View File

@ -16,10 +16,12 @@
import copy
import datetime
import mock
from sqlalchemy import exc as sa_exc
import testtools
from sahara import context
from sahara.db.sqlalchemy import models as m
from sahara import exceptions as ex
from sahara.service.castellan import config as castellan
import sahara.tests.unit.conductor.base as test_base
@ -585,19 +587,28 @@ class JobTest(test_base.ConductorManagerTestCase):
def test_job_search(self):
ctx = context.ctx()
ctx.tenant_id = SAMPLE_JOB['tenant_id']
self.api.job_create(ctx, SAMPLE_JOB)
job = copy.copy(SAMPLE_JOB)
job["name"] = "frederica"
job["description"] = "thebestjob"
ctx.tenant_id = job['tenant_id']
self.api.job_create(ctx, job)
lst = self.api.job_get_all(ctx)
self.assertEqual(1, len(lst))
kwargs = {'name': SAMPLE_JOB['name'],
'tenant_id': SAMPLE_JOB['tenant_id']}
kwargs = {'name': job['name'],
'tenant_id': job['tenant_id']}
lst = self.api.job_get_all(ctx, **kwargs)
self.assertEqual(1, len(lst))
# Valid field but no matching value
lst = self.api.job_get_all(ctx, **{'name': SAMPLE_JOB['name']+"foo"})
lst = self.api.job_get_all(ctx, **{'name': job['name']+"foo"})
self.assertEqual(0, len(lst))
# Valid field with substrings
kwargs = {'name': "red",
'description': "best"}
lst = self.api.job_get_all(ctx, **kwargs)
self.assertEqual(0, len(lst))
# Invalid field
@ -605,6 +616,26 @@ class JobTest(test_base.ConductorManagerTestCase):
self.api.job_get_all,
ctx, **{'badfield': 'somevalue'})
@mock.patch('sahara.db.sqlalchemy.api.regex_filter')
def test_job_search_regex(self, regex_filter):
# do this so we can return the correct value
def _regex_filter(query, cls, regex_cols, search_opts):
return query, search_opts
regex_filter.side_effect = _regex_filter
ctx = context.ctx()
self.api.job_get_all(ctx)
self.assertEqual(0, regex_filter.call_count)
self.api.job_get_all(ctx, regex_search=True, name="fox")
self.assertEqual(1, regex_filter.call_count)
args, kwargs = regex_filter.call_args
self.assertTrue(type(args[1] is m.Job))
self.assertEqual(args[2], ["name", "description"])
self.assertEqual(args[3], {"name": "fox"})
def test_job_update_delete_when_protected(self):
ctx = context.ctx()
sample = copy.deepcopy(SAMPLE_JOB)