Merge "Retry event actions"
This commit is contained in:
commit
0fe88e62ae
|
@ -40,7 +40,11 @@ manager_opts = [
|
|||
default=60,
|
||||
help='Minutes prior to the end of a lease in which actions '
|
||||
'like notification and snapshot are taken. If this is '
|
||||
'set to 0, then these actions are not taken.')
|
||||
'set to 0, then these actions are not taken.'),
|
||||
cfg.IntOpt('event_max_retries',
|
||||
default=1,
|
||||
max=50,
|
||||
help='Number of times to retry an event action.')
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -49,6 +53,8 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
LEASE_DATE_FORMAT = "%Y-%m-%d %H:%M"
|
||||
|
||||
EVENT_INTERVAL = 10
|
||||
|
||||
|
||||
class ManagerService(service_utils.RPCServer):
|
||||
"""Service class for the blazar-manager service.
|
||||
|
@ -66,7 +72,7 @@ class ManagerService(service_utils.RPCServer):
|
|||
|
||||
def start(self):
|
||||
super(ManagerService, self).start()
|
||||
self.tg.add_timer(10, self._event)
|
||||
self.tg.add_timer(EVENT_INTERVAL, self._event)
|
||||
for m in self.monitors:
|
||||
m.start_monitoring()
|
||||
|
||||
|
@ -146,25 +152,45 @@ class ManagerService(service_utils.RPCServer):
|
|||
if event['time'] < datetime.datetime.utcnow():
|
||||
db_api.event_update(event['id'],
|
||||
{'status': status.event.IN_PROGRESS})
|
||||
event_type = event['event_type']
|
||||
event_fn = getattr(self, event_type, None)
|
||||
if event_fn is None:
|
||||
raise exceptions.EventError(error='Event type %s is not '
|
||||
'supported' % event_type)
|
||||
try:
|
||||
eventlet.spawn_n(service_utils.with_empty_context(event_fn),
|
||||
lease_id=event['lease_id'],
|
||||
event_id=event['id'])
|
||||
lease = db_api.lease_get(event['lease_id'])
|
||||
with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
|
||||
self._send_notification(lease,
|
||||
ctx,
|
||||
events=['event.%s' % event_type])
|
||||
eventlet.spawn_n(
|
||||
service_utils.with_empty_context(self._exec_event),
|
||||
event)
|
||||
except Exception:
|
||||
db_api.event_update(event['id'],
|
||||
{'status': status.event.ERROR})
|
||||
LOG.exception('Error occurred while event handling.')
|
||||
|
||||
def _exec_event(self, event):
|
||||
"""Execute an event function"""
|
||||
event_fn = getattr(self, event['event_type'], None)
|
||||
if event_fn is None:
|
||||
raise exceptions.EventError(
|
||||
error='Event type %s is not supported'
|
||||
% event['event_type'])
|
||||
try:
|
||||
event_fn(lease_id=event['lease_id'], event_id=event['id'])
|
||||
except common_ex.InvalidStatus:
|
||||
now = datetime.datetime.utcnow()
|
||||
if now < event['time'] + datetime.timedelta(
|
||||
seconds=CONF.manager.event_max_retries * 10):
|
||||
# Set the event status UNDONE for retrying the event
|
||||
db_api.event_update(event['id'],
|
||||
{'status': status.event.UNDONE})
|
||||
else:
|
||||
db_api.event_update(event['id'],
|
||||
{'status': status.event.ERROR})
|
||||
LOG.exception('Error occurred while handling event.')
|
||||
except Exception:
|
||||
db_api.event_update(event['id'],
|
||||
{'status': status.event.ERROR})
|
||||
LOG.exception('Error occurred while handling event.')
|
||||
else:
|
||||
lease = db_api.lease_get(event['lease_id'])
|
||||
with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
|
||||
self._send_notification(
|
||||
lease, ctx, events=['event.%s' % event['event_type']])
|
||||
|
||||
def _date_from_string(self, date_string, date_format=LEASE_DATE_FORMAT):
|
||||
try:
|
||||
date = datetime.datetime.strptime(date_string, date_format)
|
||||
|
|
|
@ -226,46 +226,115 @@ class ServiceTestCase(tests.TestCase):
|
|||
|
||||
self.assertFalse(event_update.called)
|
||||
|
||||
def test_event_all_okay(self):
|
||||
def test_event_success(self):
|
||||
events = self.patch(self.db_api, 'event_get_first_sorted_by_filters')
|
||||
event_update = self.patch(self.db_api, 'event_update')
|
||||
events.return_value = {'id': '111-222-333', 'time': self.good_date,
|
||||
'event_type': 'end_lease',
|
||||
'lease_id': self.lease_id}
|
||||
events.return_value = {'id': '111-222-333',
|
||||
'time': self.good_date}
|
||||
self.patch(eventlet, 'spawn_n')
|
||||
|
||||
self.manager._event()
|
||||
|
||||
event_update.assert_called_once_with('111-222-333',
|
||||
{'status': 'IN_PROGRESS'})
|
||||
event_update.assert_called_once_with(
|
||||
'111-222-333', {'status': status.event.IN_PROGRESS})
|
||||
|
||||
def test_event_spawn_fail(self):
|
||||
events = self.patch(self.db_api, 'event_get_first_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}
|
||||
|
||||
self.manager._event()
|
||||
|
||||
event_update.assert_has_calls([
|
||||
mock.call('111-222-333', {'status': status.event.IN_PROGRESS}),
|
||||
mock.call('111-222-333', {'status': status.event.ERROR})])
|
||||
|
||||
def test_exec_event_success(self):
|
||||
event = {'id': '111-222-333',
|
||||
'event_type': 'start_lease',
|
||||
'lease_id': self.lease_id}
|
||||
start_lease = self.patch(self.manager, 'start_lease')
|
||||
|
||||
self.manager._exec_event(event)
|
||||
|
||||
start_lease.assert_called_once_with(lease_id=event['lease_id'],
|
||||
event_id=event['id'])
|
||||
self.lease_get.assert_called_once_with(event['lease_id'])
|
||||
expected_context = self.trust_ctx.return_value
|
||||
self.fake_notifier.assert_called_once_with(
|
||||
expected_context.__enter__.return_value,
|
||||
notifier_api.format_lease_payload(self.lease),
|
||||
'lease.event.end_lease')
|
||||
'lease.event.start_lease')
|
||||
|
||||
def test_event_wrong_event_status(self):
|
||||
events = self.patch(self.db_api, 'event_get_first_sorted_by_filters')
|
||||
self.patch(self.db_api, 'event_update')
|
||||
events.return_value = {'id': '111-222-333', 'time': self.good_date,
|
||||
'event_type': 'wrong_type',
|
||||
'lease_id': self.lease_id}
|
||||
def test_exec_event_invalid_event_type(self):
|
||||
event = {'id': '111-222-333',
|
||||
'event_type': 'invalid',
|
||||
'lease_id': self.lease_id}
|
||||
|
||||
self.assertRaises(manager_ex.EventError,
|
||||
self.manager._event)
|
||||
self.manager._exec_event,
|
||||
event)
|
||||
|
||||
def test_event_wrong_eventlet_fail(self):
|
||||
events = self.patch(self.db_api, 'event_get_first_sorted_by_filters')
|
||||
def test_exec_event_retry(self):
|
||||
event = {'id': '111-222-333',
|
||||
'event_type': 'start_lease',
|
||||
'lease_id': self.lease_id,
|
||||
'time': self.good_date}
|
||||
start_lease = self.patch(self.manager, 'start_lease')
|
||||
start_lease.side_effect = exceptions.InvalidStatus
|
||||
event_update = self.patch(self.db_api, 'event_update')
|
||||
calls = [mock.call('111-222-333', {'status': 'IN_PROGRESS'}),
|
||||
mock.call('111-222-333', {'status': 'ERROR'})]
|
||||
self.patch(eventlet, 'spawn_n').side_effect = Exception
|
||||
events.return_value = {'id': '111-222-333', 'time': self.good_date,
|
||||
'event_type': 'end_lease',
|
||||
'lease_id': self.lease_id}
|
||||
|
||||
self.manager._event()
|
||||
with mock.patch.object(datetime, 'datetime',
|
||||
mock.Mock(wraps=datetime.datetime)) as patched:
|
||||
patched.utcnow.return_value = (self.good_date
|
||||
+ datetime.timedelta(seconds=1))
|
||||
self.manager._exec_event(event)
|
||||
|
||||
event_update.assert_has_calls(calls)
|
||||
start_lease.assert_called_once_with(lease_id=event['lease_id'],
|
||||
event_id=event['id'])
|
||||
event_update.assert_called_once_with(
|
||||
event['id'], {'status': status.event.UNDONE})
|
||||
self.lease_get.assert_not_called()
|
||||
|
||||
def test_exec_event_no_more_retry(self):
|
||||
event = {'id': '111-222-333',
|
||||
'event_type': 'start_lease',
|
||||
'lease_id': self.lease_id,
|
||||
'time': self.good_date}
|
||||
start_lease = self.patch(self.manager, 'start_lease')
|
||||
start_lease.side_effect = exceptions.InvalidStatus
|
||||
event_update = self.patch(self.db_api, 'event_update')
|
||||
|
||||
with mock.patch.object(datetime, 'datetime',
|
||||
mock.Mock(wraps=datetime.datetime)) as patched:
|
||||
patched.utcnow.return_value = (self.good_date
|
||||
+ datetime.timedelta(days=1))
|
||||
self.manager._exec_event(event)
|
||||
|
||||
start_lease.assert_called_once_with(lease_id=event['lease_id'],
|
||||
event_id=event['id'])
|
||||
event_update.assert_called_once_with(
|
||||
event['id'], {'status': status.event.ERROR})
|
||||
self.lease_get.assert_not_called()
|
||||
|
||||
def test_exec_event_handle_exception(self):
|
||||
event = {'id': '111-222-333',
|
||||
'event_type': 'start_lease',
|
||||
'lease_id': self.lease_id,
|
||||
'time': self.good_date}
|
||||
start_lease = self.patch(self.manager, 'start_lease')
|
||||
start_lease.side_effect = Exception
|
||||
event_update = self.patch(self.db_api, 'event_update')
|
||||
|
||||
self.manager._exec_event(event)
|
||||
|
||||
start_lease.assert_called_once_with(lease_id=event['lease_id'],
|
||||
event_id=event['id'])
|
||||
event_update.assert_called_once_with(
|
||||
event['id'], {'status': status.event.ERROR})
|
||||
self.lease_get.assert_not_called()
|
||||
|
||||
def test_get_lease(self):
|
||||
lease = self.manager.get_lease(self.lease_id)
|
||||
|
|
Loading…
Reference in New Issue