Only validate properties once during create resource

While create a resource, we might retry to create or delete that resource.
Within every action properties validate was act as pre-function before
actually call any action. While the first creat run, if anything goes wrong
during property validation, a validation error will raise right away. Which
will definitely riase in the very first action run. But if it successed,
it still required to revalidate each time an action triggered (whatever is
creat or delete). This patch will ignore properties validate if it's not
the first create run.
Closes-Bug: #1691672

Change-Id: Ibf592a254a862613eddb77ea5933ec6ba0cd2d1a
(cherry picked from commit 4a15c3387a)
This commit is contained in:
ricolin 2017-05-18 14:55:26 +08:00 committed by Rico Lin
parent e544ebc859
commit e671d93b15
2 changed files with 38 additions and 2 deletions

View File

@ -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

View File

@ -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'})