diff --git a/heat/engine/resource.py b/heat/engine/resource.py index 706de990c3..0d173090ab 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -969,13 +969,18 @@ class Resource(object): while (count[self.CREATE] <= retry_limit and count[self.DELETE] <= retry_limit): - if count[action]: + pre_func = None + if count[action] > 0: delay = timeutils.retry_backoff_delay(count[action], jitter_max=2.0) waiter = scheduler.TaskRunner(self.pause) yield waiter.as_task(timeout=delay) + elif action == self.CREATE: + # Only validate properties in first create call. + pre_func = self.properties.validate + try: - yield self._do_action(action, self.properties.validate) + yield self._do_action(action, pre_func) if action == self.CREATE: first_failure = None break diff --git a/heat/tests/test_resource.py b/heat/tests/test_resource.py index 6791a11a14..c84d0d3b88 100644 --- a/heat/tests/test_resource.py +++ b/heat/tests/test_resource.py @@ -965,6 +965,37 @@ class ResourceTest(common.HeatTestCase): scheduler.TaskRunner(res.create)() self.assertEqual((res.CREATE, res.COMPLETE), res.state) + @mock.patch.object(properties.Properties, 'validate') + @mock.patch.object(timeutils, 'retry_backoff_delay') + def test_create_validate(self, m_re, m_v): + tmpl = rsrc_defn.ResourceDefinition('test_resource', 'Foo', + {'Foo': 'abc'}) + res = generic_rsrc.ResourceWithProps('test_resource', tmpl, self.stack) + + generic_rsrc.ResourceWithProps.handle_create = mock.Mock() + generic_rsrc.ResourceWithProps.handle_delete = mock.Mock() + m_v.side_effect = [True, exception.StackValidationFailed()] + generic_rsrc.ResourceWithProps.handle_create.side_effect = [ + exception.ResourceInError(resource_name='test_resource', + resource_status='ERROR', + resource_type='GenericResourceType', + resource_action='CREATE', + status_reason='just because'), + exception.ResourceInError(resource_name='test_resource', + resource_status='ERROR', + resource_type='GenericResourceType', + resource_action='CREATE', + status_reason='just because'), + None + ] + + generic_rsrc.ResourceWithProps.handle_delete.return_value = None + m_re.return_value = 0.01 + scheduler.TaskRunner(res.create)() + self.assertEqual(2, m_re.call_count) + self.assertEqual(1, m_v.call_count) + self.assertEqual((res.CREATE, res.COMPLETE), res.state) + def test_create_fail_retry(self): tmpl = rsrc_defn.ResourceDefinition('test_resource', 'Foo', {'Foo': 'abc'})