Convergence: Fix duplicate events for stack actions

When stack actions such as suspend/resume/snapshot/restore are
completed, two events are logged in DB.

The above stack actions still use stack lock even under convergence.
Hence when setting the stack action as complete/failed, state_set
should not persist state.
Sending notification, events and saving Complete/Failed state in DB
is done at the time of releasing lock for these stack actions.

Change-Id: Ib3e6c1de2f2f17502049e06ae484cb2e50867fab
Closes-Bug: #1516089
This commit is contained in:
Rakesh H S 2015-11-16 20:42:03 +05:30
parent 2ceaca1cb8
commit ccf8464531
2 changed files with 66 additions and 4 deletions

View File

@ -743,8 +743,10 @@ class Stack(collections.Mapping):
self.status = status
self.status_reason = reason
if cfg.CONF.convergence_engine:
# for convergence stack lock is not used, hence persist state
if self.convergence and action in (self.UPDATE, self.DELETE,
self.CREATE):
# if convergence and stack operation is create/update/delete,
# stack lock is not used, hence persist state
self._persist_state()
return

View File

@ -446,7 +446,8 @@ class StackConvergenceCreateUpdateDeleteTest(common.HeatTestCase):
@mock.patch.object(parser.Stack, '_converge_create_or_update')
def test_updated_time_stack_create(self, mock_ccu, mock_cr):
stack = parser.Stack(utils.dummy_context(), 'convg_updated_time_test',
templatem.Template.create_empty_template())
templatem.Template.create_empty_template(),
convergence=True)
stack.converge_stack(template=stack.t, action=stack.CREATE)
self.assertIsNone(stack.updated_time)
self.assertTrue(mock_ccu.called)
@ -456,12 +457,71 @@ class StackConvergenceCreateUpdateDeleteTest(common.HeatTestCase):
tmpl = {'HeatTemplateFormatVersion': '2012-12-12',
'Resources': {'R1': {'Type': 'GenericResourceType'}}}
stack = parser.Stack(utils.dummy_context(), 'updated_time_test',
templatem.Template(tmpl))
templatem.Template(tmpl), convergence=True)
stack.converge_stack(template=stack.t, action=stack.UPDATE)
self.assertIsNotNone(stack.updated_time)
self.assertTrue(mock_ccu.called)
@mock.patch.object(parser.Stack, '_persist_state')
class TestConvgStackStateSet(common.HeatTestCase):
def setUp(self):
super(TestConvgStackStateSet, self).setUp()
cfg.CONF.set_override('convergence_engine', True)
self.stack = tools.get_stack(
'test_stack', utils.dummy_context(),
template=tools.wp_template, convergence=True)
def test_state_set_create_update_delete_complete(self, mock_ps):
self.stack.state_set(self.stack.CREATE, self.stack.COMPLETE,
'Create complete')
self.assertTrue(mock_ps.called)
mock_ps.reset_mock()
self.stack.state_set(self.stack.UPDATE, self.stack.COMPLETE,
'Update complete')
self.assertTrue(mock_ps.called)
mock_ps.reset_mock()
self.stack.state_set(self.stack.DELETE, self.stack.COMPLETE,
'Delete complete')
self.assertTrue(mock_ps.called)
def test_state_set_stack_suspend(self, mock_ps):
self.stack.state_set(self.stack.SUSPEND, self.stack.IN_PROGRESS,
'Suspend started')
self.assertTrue(mock_ps.called)
mock_ps.reset_mock()
self.stack.state_set(self.stack.SUSPEND, self.stack.COMPLETE,
'Suspend complete')
self.assertFalse(mock_ps.called)
def test_state_set_stack_resume(self, mock_ps):
self.stack.state_set(self.stack.RESUME, self.stack.IN_PROGRESS,
'Resume started')
self.assertTrue(mock_ps.called)
mock_ps.reset_mock()
self.stack.state_set(self.stack.RESUME, self.stack.COMPLETE,
'Resume complete')
self.assertFalse(mock_ps.called)
def test_state_set_stack_snapshot(self, mock_ps):
self.stack.state_set(self.stack.SNAPSHOT, self.stack.IN_PROGRESS,
'Snapshot started')
self.assertTrue(mock_ps.called)
mock_ps.reset_mock()
self.stack.state_set(self.stack.SNAPSHOT, self.stack.COMPLETE,
'Snapshot complete')
self.assertFalse(mock_ps.called)
def test_state_set_stack_restore(self, mock_ps):
self.stack.state_set(self.stack.RESTORE, self.stack.IN_PROGRESS,
'Restore started')
self.assertTrue(mock_ps.called)
mock_ps.reset_mock()
self.stack.state_set(self.stack.RESTORE, self.stack.COMPLETE,
'Restore complete')
self.assertFalse(mock_ps.called)
class TestConvgStackRollback(common.HeatTestCase):
def setUp(self):