Add get cron-trigger by id support

Currently we can only do a CURD action on a cron-trigger by name.
This patch refer to workflow implementation and re-encapsulate
DB API so that users can manage a cron-trigger by id or name.

Closes-Bug: 1684469

Change-Id: I9ff657b2604647e734b5539e9bd6a524a3a20efb
This commit is contained in:
int32bit 2017-08-22 16:36:38 +08:00 committed by Nikolay Mahotkin
parent b791850ba2
commit f84952a3b1
7 changed files with 145 additions and 35 deletions

View File

@ -32,17 +32,16 @@ LOG = logging.getLogger(__name__)
class CronTriggersController(rest.RestController): class CronTriggersController(rest.RestController):
@rest_utils.wrap_wsme_controller_exception @rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(resources.CronTrigger, wtypes.text) @wsme_pecan.wsexpose(resources.CronTrigger, wtypes.text)
def get(self, name): def get(self, identifier):
"""Returns the named cron_trigger. """Returns the named cron_trigger.
:param name: Name of cron trigger to retrieve :param identifier: Id or name of cron trigger to retrieve
""" """
acl.enforce('cron_triggers:get', context.ctx()) acl.enforce('cron_triggers:get', context.ctx())
LOG.info('Fetch cron trigger [name=%s]', name) LOG.info('Fetch cron trigger [identifier=%s]', identifier)
db_model = db_api.get_cron_trigger(name)
db_model = db_api.get_cron_trigger(identifier)
return resources.CronTrigger.from_db_model(db_model) return resources.CronTrigger.from_db_model(db_model)
@rest_utils.wrap_wsme_controller_exception @rest_utils.wrap_wsme_controller_exception
@ -77,16 +76,16 @@ class CronTriggersController(rest.RestController):
@rest_utils.wrap_wsme_controller_exception @rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204) @wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
def delete(self, name): def delete(self, identifier):
"""Delete cron trigger. """Delete cron trigger.
:param name: Name of cron trigger to delete :param identifier: Id or name of cron trigger to delete
""" """
acl.enforce('cron_triggers:delete', context.ctx()) acl.enforce('cron_triggers:delete', context.ctx())
LOG.info("Delete cron trigger [name=%s]", name) LOG.info("Delete cron trigger [identifier=%s]", identifier)
triggers.delete_cron_trigger(name) triggers.delete_cron_trigger(identifier)
@rest_utils.wrap_wsme_controller_exception @rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(resources.CronTriggers, types.uuid, int, @wsme_pecan.wsexpose(resources.CronTriggers, types.uuid, int,

View File

@ -376,13 +376,17 @@ def delete_delayed_calls(**kwargs):
# Cron triggers. # Cron triggers.
def get_cron_trigger(name): def get_cron_trigger(identifier):
return IMPL.get_cron_trigger(name) return IMPL.get_cron_trigger(identifier)
def load_cron_trigger(name): def get_cron_trigger_by_id(id):
return IMPL.get_cron_trigger_by_id(id)
def load_cron_trigger(identifier):
"""Unlike get_cron_trigger this method is allowed to return None.""" """Unlike get_cron_trigger this method is allowed to return None."""
return IMPL.load_cron_trigger(name) return IMPL.load_cron_trigger(identifier)
def get_cron_triggers(**kwargs): def get_cron_triggers(**kwargs):
@ -415,16 +419,17 @@ def create_cron_trigger(values):
return IMPL.create_cron_trigger(values) return IMPL.create_cron_trigger(values)
def update_cron_trigger(name, values, query_filter=None): def update_cron_trigger(identifier, values, query_filter=None):
return IMPL.update_cron_trigger(name, values, query_filter=query_filter) return IMPL.update_cron_trigger(identifier, values,
query_filter=query_filter)
def create_or_update_cron_trigger(name, values): def create_or_update_cron_trigger(identifier, values):
return IMPL.create_or_update_cron_trigger(name, values) return IMPL.create_or_update_cron_trigger(identifier, values)
def delete_cron_trigger(name): def delete_cron_trigger(identifier):
return IMPL.delete_cron_trigger(name) return IMPL.delete_cron_trigger(identifier)
def delete_cron_triggers(**kwargs): def delete_cron_triggers(**kwargs):

View File

@ -1141,20 +1141,35 @@ def _get_completed_root_executions_query(columns):
@b.session_aware() @b.session_aware()
def get_cron_trigger(name, session=None): def get_cron_trigger(identifier, session=None):
cron_trigger = _get_db_object_by_name(models.CronTrigger, name) cron_trigger = _get_db_object_by_name_or_id(
models.CronTrigger,
identifier)
if not cron_trigger: if not cron_trigger:
raise exc.DBEntityNotFoundError( raise exc.DBEntityNotFoundError(
"Cron trigger not found [name=%s]" % name "Cron trigger not found [identifier=%s]" % identifier
) )
return cron_trigger return cron_trigger
@b.session_aware() @b.session_aware()
def load_cron_trigger(name, session=None): def get_cron_trigger_by_id(id, session=None):
return _get_db_object_by_name(models.CronTrigger, name) ctx = context.ctx()
cron_trigger = _get_db_object_by_id(models.CronTrigger, id,
insecure=ctx.is_admin)
if not cron_trigger:
raise exc.DBEntityNotFoundError(
"Cron trigger not found [id=%s]" % id
)
return cron_trigger
@b.session_aware()
def load_cron_trigger(identifier, session=None):
return _get_db_object_by_name_or_id(models.CronTrigger, identifier)
@b.session_aware() @b.session_aware()
@ -1200,8 +1215,8 @@ def create_cron_trigger(values, session=None):
@b.session_aware() @b.session_aware()
def update_cron_trigger(name, values, session=None, query_filter=None): def update_cron_trigger(identifier, values, session=None, query_filter=None):
cron_trigger = get_cron_trigger(name) cron_trigger = get_cron_trigger(identifier)
if query_filter: if query_filter:
try: try:
@ -1233,19 +1248,19 @@ def update_cron_trigger(name, values, session=None, query_filter=None):
@b.session_aware() @b.session_aware()
def create_or_update_cron_trigger(name, values, session=None): def create_or_update_cron_trigger(identifier, values, session=None):
cron_trigger = _get_db_object_by_name(models.CronTrigger, name) cron_trigger = _get_db_object_by_name_or_id(models.CronTrigger, identifier)
if not cron_trigger: if not cron_trigger:
return create_cron_trigger(values) return create_cron_trigger(values)
else: else:
updated, _ = update_cron_trigger(name, values) updated, _ = update_cron_trigger(identifier, values)
return updated return updated
@b.session_aware() @b.session_aware()
def delete_cron_trigger(name, session=None): def delete_cron_trigger(identifier, session=None):
cron_trigger = get_cron_trigger(name) cron_trigger = get_cron_trigger(identifier)
# Delete the cron trigger by ID and get the affected row count. # Delete the cron trigger by ID and get the affected row count.
table = models.CronTrigger.__table__ table = models.CronTrigger.__table__

View File

@ -136,12 +136,12 @@ def create_cron_trigger(name, workflow_name, workflow_input,
return trig return trig
def delete_cron_trigger(name, trust_id=None, delete_trust=True): def delete_cron_trigger(identifier, trust_id=None, delete_trust=True):
if not trust_id: if not trust_id:
trigger = db_api.get_cron_trigger(name) trigger = db_api.get_cron_trigger(identifier)
trust_id = trigger.trust_id trust_id = trigger.trust_id
modified_count = db_api.delete_cron_trigger(name) modified_count = db_api.delete_cron_trigger(identifier)
if modified_count and delete_trust: if modified_count and delete_trust:
# Delete trust only together with deleting trigger. # Delete trust only together with deleting trigger.

View File

@ -37,7 +37,7 @@ WF = models.WorkflowDefinition(
WF.update({'id': '123e4567-e89b-12d3-a456-426655440000', 'name': 'my_wf'}) WF.update({'id': '123e4567-e89b-12d3-a456-426655440000', 'name': 'my_wf'})
TRIGGER = { TRIGGER = {
'id': '123', 'id': '02abb422-55ef-4bb2-8cb9-217a583a6a3f',
'name': 'my_cron_trigger', 'name': 'my_cron_trigger',
'pattern': '* * * * *', 'pattern': '* * * * *',
'workflow_name': WF.name, 'workflow_name': WF.name,
@ -94,6 +94,13 @@ class TestCronTriggerController(base.APITest):
self.assertEqual(404, resp.status_int) self.assertEqual(404, resp.status_int)
@mock.patch.object(db_api, "get_cron_trigger", MOCK_TRIGGER)
def test_get_by_id(self):
resp = self.app.get(
"/v2/cron_triggers/02abb422-55ef-4bb2-8cb9-217a583a6a3f")
self.assertEqual(200, resp.status_int)
self.assertDictEqual(TRIGGER, resp.json)
@mock.patch.object(db_api, "get_workflow_definition", MOCK_WF) @mock.patch.object(db_api, "get_workflow_definition", MOCK_WF)
@mock.patch.object(db_api, "create_cron_trigger") @mock.patch.object(db_api, "create_cron_trigger")
def test_post(self, mock_mtd): def test_post(self, mock_mtd):
@ -143,6 +150,16 @@ class TestCronTriggerController(base.APITest):
self.assertEqual(1, delete_trust.call_count) self.assertEqual(1, delete_trust.call_count)
self.assertEqual(204, resp.status_int) self.assertEqual(204, resp.status_int)
@mock.patch.object(db_api, "get_cron_trigger", MOCK_TRIGGER)
@mock.patch.object(db_api, "delete_cron_trigger", MOCK_DELETE)
@mock.patch.object(security, "delete_trust")
def test_delete_by_id(self, delete_trust):
resp = self.app.delete(
'/v2/cron_triggers/02abb422-55ef-4bb2-8cb9-217a583a6a3f')
self.assertEqual(1, delete_trust.call_count)
self.assertEqual(204, resp.status_int)
@mock.patch.object(db_api, "delete_cron_trigger", MOCK_NOT_FOUND) @mock.patch.object(db_api, "delete_cron_trigger", MOCK_NOT_FOUND)
def test_delete_not_found(self): def test_delete_not_found(self):
resp = self.app.delete( resp = self.app.delete(

View File

@ -2190,6 +2190,7 @@ class TaskExecutionTest(SQLAlchemyTest):
CRON_TRIGGERS = [ CRON_TRIGGERS = [
{ {
'id': '11111111-1111-1111-1111-111111111111',
'name': 'trigger1', 'name': 'trigger1',
'pattern': '* * * * *', 'pattern': '* * * * *',
'workflow_name': 'my_wf', 'workflow_name': 'my_wf',
@ -2202,6 +2203,7 @@ CRON_TRIGGERS = [
'project_id': '<default-project>' 'project_id': '<default-project>'
}, },
{ {
'id': '22222222-2222-2222-2222-2222222c2222',
'name': 'trigger2', 'name': 'trigger2',
'pattern': '* * * * *', 'pattern': '* * * * *',
'workflow_name': 'my_wf', 'workflow_name': 'my_wf',
@ -2286,6 +2288,19 @@ class CronTriggerTest(SQLAlchemyTest):
self.assertEqual(updated, updated) self.assertEqual(updated, updated)
self.assertEqual(0, updated_count) self.assertEqual(0, updated_count)
def test_update_cron_trigger_by_id(self):
created = db_api.create_cron_trigger(CRON_TRIGGERS[0])
self.assertIsNone(created.updated_at)
updated, updated_count = db_api.update_cron_trigger(
created.id,
{'pattern': '*/1 * * * *'}
)
self.assertEqual('*/1 * * * *', updated.pattern)
self.assertEqual(1, updated_count)
def test_create_or_update_cron_trigger(self): def test_create_or_update_cron_trigger(self):
name = 'not-existing-id' name = 'not-existing-id'
@ -2317,6 +2332,46 @@ class CronTriggerTest(SQLAlchemyTest):
self.assertEqual(created0, fetched[0]) self.assertEqual(created0, fetched[0])
self.assertEqual(created1, fetched[1]) self.assertEqual(created1, fetched[1])
def test_get_cron_trigger(self):
cron_trigger = db_api.create_cron_trigger(CRON_TRIGGERS[0])
# Get by id is ok
fetched = db_api.get_cron_trigger(cron_trigger.id)
self.assertEqual(cron_trigger, fetched)
# Get by name is ok
fetched = db_api.get_cron_trigger(cron_trigger.name)
self.assertEqual(cron_trigger, fetched)
def test_get_cron_trigger_not_found(self):
self.assertRaises(
exc.DBEntityNotFoundError,
db_api.get_cron_trigger,
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
)
self.assertRaises(
exc.DBEntityNotFoundError,
db_api.get_cron_trigger,
'not-exists-cron-trigger',
)
def test_get_cron_trigger_by_id(self):
cron_trigger_1 = db_api.create_cron_trigger(CRON_TRIGGERS[0])
cron_trigger_2 = db_api.create_cron_trigger(CRON_TRIGGERS[1])
fetched = db_api.get_cron_trigger_by_id(cron_trigger_1.id)
self.assertEqual(cron_trigger_1, fetched)
fetched = db_api.get_cron_trigger_by_id(cron_trigger_2.id)
self.assertEqual(cron_trigger_2, fetched)
self.assertRaises(
exc.DBEntityNotFoundError,
db_api.get_cron_trigger_by_id,
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
)
def test_get_cron_triggers_other_tenant(self): def test_get_cron_triggers_other_tenant(self):
created0 = db_api.create_cron_trigger(CRON_TRIGGERS[0]) created0 = db_api.create_cron_trigger(CRON_TRIGGERS[0])
@ -2348,6 +2403,22 @@ class CronTriggerTest(SQLAlchemyTest):
created.name created.name
) )
def test_delete_cron_trigger_by_id(self):
created = db_api.create_cron_trigger(CRON_TRIGGERS[0])
fetched = db_api.get_cron_trigger(created.name)
self.assertEqual(created, fetched)
rowcount = db_api.delete_cron_trigger(created.id)
self.assertEqual(1, rowcount)
self.assertRaises(
exc.DBEntityNotFoundError,
db_api.get_cron_trigger,
created.id
)
def test_cron_trigger_repr(self): def test_cron_trigger_repr(self):
s = db_api.create_cron_trigger(CRON_TRIGGERS[0]).__repr__() s = db_api.create_cron_trigger(CRON_TRIGGERS[0]).__repr__()

View File

@ -0,0 +1,3 @@
---
features:
- Support to manage a cron-trigger instance by id.