Stop periodic watcher tasks before deleting stack

In the case where a stack that has a watch task associated with it is
being deleted and the engine successfully acquires a lock, no attempt to
stop the stack will be made since it has no action in-progress.  This
will result in orphaned watcher tasks being left behind, since the
watcher tasks are normally stopped as part of the call to
ThreadGroup.stop().

To fix this, explicitly stop the periodic watcher tasks before calling
stack.delete().

Change-Id: Idf5b7c1100fc85743ac6dc5831731f7ecc96bfd6
Closes-Bug: #1315044
This commit is contained in:
Jason Dunsmore 2014-05-01 14:17:45 -05:00
parent 5dca8ff3fb
commit 33ea357342
2 changed files with 26 additions and 0 deletions

View File

@ -150,6 +150,10 @@ class ThreadGroupManager(object):
self.groups[stack_id].add_timer(cfg.CONF.periodic_interval, self.groups[stack_id].add_timer(cfg.CONF.periodic_interval,
func, *args, **kwargs) func, *args, **kwargs)
def stop_timers(self, stack_id):
if stack_id in self.groups:
self.groups[stack_id].stop_timers()
def stop(self, stack_id, graceful=False): def stop(self, stack_id, graceful=False):
'''Stop any active threads on a stack.''' '''Stop any active threads on a stack.'''
if stack_id in self.groups: if stack_id in self.groups:
@ -712,6 +716,7 @@ class EngineService(service.Service):
# Successfully acquired lock # Successfully acquired lock
if acquire_result is None: if acquire_result is None:
self.thread_group_mgr.stop_timers(stack.id)
self.thread_group_mgr.start_with_acquired_lock(stack, lock, self.thread_group_mgr.start_with_acquired_lock(stack, lock,
stack.delete) stack.delete)
return return

View File

@ -680,6 +680,27 @@ class StackServiceCreateUpdateDeleteTest(HeatTestCase):
self.man.thread_group_mgr.groups[sid].wait() self.man.thread_group_mgr.groups[sid].wait()
self.m.VerifyAll() self.m.VerifyAll()
def test_stack_delete_acquired_lock_stop_timers(self):
stack_name = 'service_delete_test_stack'
stack = get_wordpress_stack(stack_name, self.ctx)
sid = stack.store()
st = db_api.stack_get(self.ctx, sid)
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.ctx, stack=st).MultipleTimes().AndReturn(stack)
self.man.tg = DummyThreadGroup()
self.m.StubOutWithMock(stack_lock.StackLock, 'try_acquire')
stack_lock.StackLock.try_acquire().AndReturn(self.man.engine_id)
self.m.ReplayAll()
self.man.thread_group_mgr.add_timer(stack.id, 'test')
self.assertEqual(1, len(self.man.thread_group_mgr.groups[sid].timers))
self.assertIsNone(self.man.delete_stack(self.ctx, stack.identifier()))
self.assertEqual(0, len(self.man.thread_group_mgr.groups[sid].timers))
self.man.thread_group_mgr.groups[sid].wait()
self.m.VerifyAll()
def test_stack_delete_current_engine_active_lock(self): def test_stack_delete_current_engine_active_lock(self):
stack_name = 'service_delete_test_stack' stack_name = 'service_delete_test_stack'
stack = get_wordpress_stack(stack_name, self.ctx) stack = get_wordpress_stack(stack_name, self.ctx)