Merge "Skip validation if depends on not created resource"
This commit is contained in:
commit
cdfa0f9e59
@ -17,6 +17,7 @@ import six
|
||||
|
||||
from heat.common import exception
|
||||
from heat.engine import constraints as constr
|
||||
from heat.engine import function
|
||||
from heat.engine import parameters
|
||||
from heat.engine import support
|
||||
|
||||
@ -382,7 +383,13 @@ class Properties(collections.Mapping):
|
||||
|
||||
if key in self.data:
|
||||
try:
|
||||
value = self.resolve(self.data[key])
|
||||
unresolved_value = self.data[key]
|
||||
if validate:
|
||||
deps = function.dependencies(unresolved_value)
|
||||
if any(res.action == res.INIT for res in deps):
|
||||
validate = False
|
||||
|
||||
value = self.resolve(unresolved_value)
|
||||
return prop.get_value(value, validate)
|
||||
# the resolver function could raise any number of exceptions,
|
||||
# so handle this generically
|
||||
|
@ -14,6 +14,8 @@
|
||||
from heat.common.i18n import _
|
||||
from heat.common.i18n import _LW
|
||||
from heat.engine import attributes
|
||||
from heat.engine import constraints
|
||||
from heat.engine import properties
|
||||
from heat.engine import resource
|
||||
from heat.engine import signal_responder
|
||||
from heat.engine import stack_user
|
||||
@ -151,3 +153,10 @@ class StackUserResource(stack_user.StackUser):
|
||||
def handle_create(self):
|
||||
super(StackUserResource, self).handle_create()
|
||||
self.resource_id_set(self._get_user_id())
|
||||
|
||||
|
||||
class ResourceWithCustomConstraint(GenericResource):
|
||||
properties_schema = \
|
||||
{'Foo': properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
constraints=[constraints.CustomConstraint('neutron.network')])}
|
||||
|
@ -15,6 +15,7 @@ import six
|
||||
import testtools
|
||||
|
||||
from heat.common import exception
|
||||
from heat.engine.cfn import functions as cfn_funcs
|
||||
from heat.engine import constraints
|
||||
from heat.engine.hot import parameters as hot_param
|
||||
from heat.engine import parameters
|
||||
@ -1055,6 +1056,49 @@ class PropertiesTest(testtools.TestCase):
|
||||
except exception.StackValidationFailed:
|
||||
self.fail("Constraints should not have been evaluated.")
|
||||
|
||||
def test_resolve_ref_with_constraints(self):
|
||||
# create test custom constraint
|
||||
class IncorrectConstraint(constraints.BaseCustomConstraint):
|
||||
|
||||
expected_exceptions = (Exception,)
|
||||
|
||||
def validate_with_client(self, client, value):
|
||||
raise Exception("Test exception")
|
||||
|
||||
class TestCustomConstraint(constraints.CustomConstraint):
|
||||
@property
|
||||
def custom_constraint(self):
|
||||
return IncorrectConstraint()
|
||||
|
||||
# create schema with test constraint
|
||||
schema = {
|
||||
'foo': properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
constraints=[TestCustomConstraint('test_constraint')]
|
||||
)
|
||||
}
|
||||
|
||||
# define parameters for function
|
||||
def test_resolver(prop):
|
||||
return 'None'
|
||||
|
||||
class rsrc(object):
|
||||
action = INIT = "INIT"
|
||||
|
||||
stack = {'another_res': rsrc()}
|
||||
|
||||
# define properties with function and constraint
|
||||
props = properties.Properties(
|
||||
schema,
|
||||
{'foo': cfn_funcs.ResourceRef(
|
||||
stack, 'get_resource', 'another_res')},
|
||||
test_resolver)
|
||||
|
||||
try:
|
||||
self.assertIsNone(props.validate())
|
||||
except exception.StackValidationFailed:
|
||||
self.fail("Constraints should not have been evaluated.")
|
||||
|
||||
def test_schema_from_params(self):
|
||||
params_snippet = {
|
||||
"DBUsername": {
|
||||
|
@ -37,6 +37,8 @@ from heat.tests.common import HeatTestCase
|
||||
from heat.tests import generic_resource as generic_rsrc
|
||||
from heat.tests import utils
|
||||
|
||||
import neutronclient.common.exceptions as neutron_exp
|
||||
|
||||
|
||||
empty_template = {"HeatTemplateFormatVersion": "2012-12-12"}
|
||||
|
||||
@ -47,14 +49,18 @@ class ResourceTest(HeatTestCase):
|
||||
|
||||
resource._register_class('GenericResourceType',
|
||||
generic_rsrc.GenericResource)
|
||||
resource._register_class('ResourceWithCustomConstraint',
|
||||
generic_rsrc.ResourceWithCustomConstraint)
|
||||
|
||||
env = environment.Environment()
|
||||
env.load({u'resource_registry':
|
||||
{u'OS::Test::GenericResource': u'GenericResourceType'}})
|
||||
self.env = environment.Environment()
|
||||
self.env.load({u'resource_registry':
|
||||
{u'OS::Test::GenericResource': u'GenericResourceType',
|
||||
u'OS::Test::ResourceWithCustomConstraint':
|
||||
u'ResourceWithCustomConstraint'}})
|
||||
|
||||
self.stack = parser.Stack(utils.dummy_context(), 'test_stack',
|
||||
parser.Template(empty_template), env=env,
|
||||
stack_id=str(uuid.uuid4()))
|
||||
parser.Template(empty_template),
|
||||
env=self.env, stack_id=str(uuid.uuid4()))
|
||||
self.patch('heat.engine.resource.warnings')
|
||||
|
||||
def test_get_class_ok(self):
|
||||
@ -1015,6 +1021,46 @@ class ResourceTest(HeatTestCase):
|
||||
mock_create.side_effect = Exception()
|
||||
self.assertFalse(res.is_using_neutron())
|
||||
|
||||
def _test_skip_validation_if_custom_constraint(self, tmpl):
|
||||
stack = parser.Stack(utils.dummy_context(), 'test', tmpl, env=self.env)
|
||||
stack.store()
|
||||
path = ('heat.engine.clients.os.neutron.NetworkConstraint.'
|
||||
'validate_with_client')
|
||||
with mock.patch(path) as mock_validate:
|
||||
mock_validate.side_effect = neutron_exp.NeutronClientException
|
||||
rsrc2 = stack['bar']
|
||||
self.assertIsNone(rsrc2.validate())
|
||||
|
||||
def test_ref_skip_validation_if_custom_constraint(self):
|
||||
tmpl = template.Template({
|
||||
'HeatTemplateFormatVersion': '2012-12-12',
|
||||
'Resources': {
|
||||
'foo': {'Type': 'OS::Test::GenericResource'},
|
||||
'bar': {
|
||||
'Type': 'OS::Test::ResourceWithCustomConstraint',
|
||||
'Properties': {
|
||||
'Foo': {'Ref': 'foo'},
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
self._test_skip_validation_if_custom_constraint(tmpl)
|
||||
|
||||
def test_hot_ref_skip_validation_if_custom_constraint(self):
|
||||
tmpl = template.Template({
|
||||
'heat_template_version': '2013-05-23',
|
||||
'resources': {
|
||||
'foo': {'type': 'GenericResourceType'},
|
||||
'bar': {
|
||||
'type': 'ResourceWithCustomConstraint',
|
||||
'properties': {
|
||||
'Foo': {'get_resource': 'foo'},
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
self._test_skip_validation_if_custom_constraint(tmpl)
|
||||
|
||||
|
||||
class ResourceAdoptTest(HeatTestCase):
|
||||
def setUp(self):
|
||||
|
Loading…
Reference in New Issue
Block a user