Do not execute event of transitional lease

If the continuous execution of an event is called just after the lease
creation is called, it can fail with the invalid lease status
transition error from CREATING to STARTING.

This patch adds a check before the event execution whether the lease
status of the event is not transitional but stable and pend the
execution to the next time if it is transitional.

Change-Id: I033dd814d384131de8e7494d22cd42f1ea67112b
Closes-Bug: #1820476
This commit is contained in:
Tetsuro Nakamura 2019-03-17 04:56:02 +00:00
parent 81f3ba9bb3
commit bf57492926
4 changed files with 56 additions and 3 deletions

View File

@ -155,6 +155,10 @@ class ManagerService(service_utils.RPCServer):
LOG.info("Trying to execute events: %s", events)
for event in events:
if not status.LeaseStatus.is_stable(event['lease_id']):
LOG.info("Skip event %s because the status of the lease %s "
"is still transitional", event, event['lease_id'])
continue
db_api.event_update(event['id'],
{'status': status.event.IN_PROGRESS})
try:

View File

@ -168,6 +168,16 @@ class LeaseStatus(BaseStatus):
return True
@classmethod
def is_stable(cls, lease_id):
"""Check if the lease status is stable
:param lease_id: Lease ID
:return: True if the status is in (PENDING, ACTIVE, TERMINATED, ERROR)
"""
lease = db_api.lease_get(lease_id)
return (lease['status'] in cls.STABLE)
@classmethod
def lease_status(cls, transition, result_in):
"""Decorator for managing a lease status.

View File

@ -145,6 +145,7 @@ class ServiceTestCase(tests.TestCase):
'resource_id': '111',
'resource_type': 'virtual:instance',
'status': 'FAKE PROGRESS'}],
'status': status.LeaseStatus.PENDING,
'start_date': datetime.datetime(2013, 12, 20, 13, 00),
'end_date': datetime.datetime(2013, 12, 20, 15, 00),
'trust_id': 'exxee111qwwwwe'}
@ -231,8 +232,12 @@ class ServiceTestCase(tests.TestCase):
def test_event_success(self):
events = self.patch(self.db_api, 'event_get_all_sorted_by_filters')
event_update = self.patch(self.db_api, 'event_update')
events.return_value = [{'id': '111-222-333', 'time': self.good_date},
{'id': '444-555-666', 'time': self.good_date}]
events.return_value = [{'id': '111-222-333',
'lease_id': 'lease_id1',
'time': self.good_date},
{'id': '444-555-666',
'lease_id': 'lease_id2',
'time': self.good_date}]
self.patch(eventlet, 'spawn_n')
self.manager._event()
@ -245,7 +250,9 @@ class ServiceTestCase(tests.TestCase):
events = self.patch(self.db_api, 'event_get_all_sorted_by_filters')
event_update = self.patch(self.db_api, 'event_update')
self.patch(eventlet, 'spawn_n').side_effect = Exception
events.return_value = [{'id': '111-222-333', 'time': self.good_date}]
events.return_value = [{'id': '111-222-333',
'lease_id': self.lease_id,
'time': self.good_date}]
self.manager._event()
@ -253,6 +260,23 @@ class ServiceTestCase(tests.TestCase):
mock.call('111-222-333', {'status': status.event.IN_PROGRESS}),
mock.call('111-222-333', {'status': status.event.ERROR})])
def test_event_pass(self):
events = self.patch(self.db_api, 'event_get_all_sorted_by_filters')
events.return_value = [{'id': '111-222-333',
'lease_id': self.lease_id,
'time': self.good_date}]
self.lease_get = self.patch(self.db_api, 'lease_get')
lease = self.lease.copy()
lease.update({'status': status.LeaseStatus.CREATING})
self.lease_get.return_value = lease
event_update = self.patch(self.db_api, 'event_update')
self.manager._event()
event_update.assert_not_called()
def test_exec_event_success(self):
event = {'id': '111-222-333',
'event_type': 'start_lease',

View File

@ -154,6 +154,21 @@ class LeaseStatusTestCase(tests.TestCase):
self.assertFalse(result)
def test_is_stable(self):
lease_id = self.lease_id
lease_pending = {'id': lease_id,
'status': status.LeaseStatus.PENDING}
lease_creating = {'id': lease_id,
'status': status.LeaseStatus.CREATING}
self.patch(self.db_api, 'lease_get').return_value = lease_pending
result = self.status.LeaseStatus.is_stable(lease_id)
self.assertTrue(result)
self.patch(self.db_api, 'lease_get').return_value = lease_creating
result = self.status.LeaseStatus.is_stable(lease_id)
self.assertFalse(result)
def test_lease_status(self):
lease = {
'status': status.LeaseStatus.PENDING