Don't validate rsrc properties with external_id

This also moves the external_id validation
from resource create to stack validate.

Change-Id: I815599ea3eb8d62a81a78f5e2e2dfc8c9f6dec05
Closes-Bug: #1651681
This commit is contained in:
rabi 2016-12-21 10:30:54 +05:30
parent 07b156525b
commit eb7b5a3d49
4 changed files with 27 additions and 24 deletions

View File

@ -298,6 +298,10 @@ class Resource(object):
self.current_template_id = resource.current_template_id
self.root_stack_id = resource.root_stack_id
@property
def external_id(self):
return self.t.external_id()
@property
def stack(self):
stack = self._stackref()
@ -864,18 +868,17 @@ class Resource(object):
runner(timeout=timeout, progress_callback=progress_callback)
def _validate_external_resource(self, external_id):
if self.entity:
def validate_external(self):
if self.external_id is not None and self.entity:
try:
self.resource_id = external_id
self.resource_id = self.external_id
self._show_resource()
except Exception as ex:
LOG.debug("%s", ex)
if self.client_plugin().is_not_found(ex):
error_message = _("Invalid external resource: Resource "
"%(external_id)s not found in "
"%(entity)s.") % {
'external_id': external_id,
'external_id': self.external_id,
'entity': self.entity}
raise exception.StackValidationFailed(
message="%s" % error_message)
@ -888,21 +891,19 @@ class Resource(object):
Subclasses should provide a handle_create() method to customise
creation.
"""
external = self.t.external_id()
if external is not None:
self._validate_external_resource(external_id=external)
yield self._do_action(self.ADOPT,
resource_data={'resource_id': external})
self.check()
return
action = self.CREATE
if (self.action, self.status) != (self.INIT, self.COMPLETE):
exc = exception.Error(_('State %s invalid for create')
% six.text_type(self.state))
raise exception.ResourceFailure(exc, self, action)
if self.external_id is not None:
yield self._do_action(self.ADOPT,
resource_data={
'resource_id': self.external_id})
self.check()
return
# This method can be called when we replace a resource, too. In that
# case, a hook has already been dealt with in `Resource.update` so we
# shouldn't do it here again:
@ -1267,14 +1268,14 @@ class Resource(object):
if before is None:
before = self.frozen_definition()
external = after.external_id()
if before.external_id() != external:
after_external_id = after.external_id()
if self.external_id != after_external_id:
msg = _("Update to property %(prop)s of %(name)s (%(res)s)"
) % {'prop': hot_tmpl.HOTemplate20161014.RES_EXTERNAL_ID,
'res': self.type(), 'name': self.name}
exc = exception.NotSupported(feature=msg)
raise exception.ResourceFailure(exc, self, action)
elif external is not None:
elif after_external_id is not None:
LOG.debug("Skip update on external resource.")
return

View File

@ -839,8 +839,11 @@ class Stack(collections.Mapping):
# Don't validate identical definitions multiple times
if res.name not in unique_defn_names:
continue
try:
if res.external_id is not None:
res.validate_external()
continue
if self.resource_validate:
result = res.validate()
else:

View File

@ -353,14 +353,12 @@ class ResourceTest(common.HeatTestCase):
external_id=external_id)
res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
res.entity = 'test'
res.client = mock.Mock()
res.client_plugin = mock.Mock()
test_obj = mock.Mock()
res.client().test = test_obj
test_obj.get.side_effect = exception.EntityNotFound
self.patchobject(res.client_plugin, 'is_not_found',
return_value=True)
self.patchobject(res, '_show_resource', side_effect=Exception())
e = self.assertRaises(exception.StackValidationFailed,
scheduler.TaskRunner(res.create))
res.validate_external)
message = ("Invalid external resource: Resource %(external_id)s not "
"found in %(entity)s.") % {'external_id': external_id,
'entity': res.entity}

View File

@ -2716,6 +2716,7 @@ class StackTest(common.HeatTestCase):
new_callable=mock.PropertyMock) as mock_dependencies:
mock_dependency = mock.MagicMock()
mock_dependency.name = 'res'
mock_dependency.external_id = None
mock_dependency.validate.side_effect = AssertionError(expected_msg)
mock_dependencies.Dependencies.return_value = [mock_dependency]
stc = stack.Stack(self.ctx, utils.random_name(), self.tmpl)