Fix stack preview

Don't execute translation rule for property that contains
a GetParam function that can't be resolved at the moment.
Such situation happens when we try to resolve get_param function
that refer to parameter with None value. We receive parameter value
from parent stack, where this value is a reference to some resource
without resource_id, so this situation is legal for stack preview
and we shouldn't fail. Note, that we can reproduce this behaviour
only with resources with hidden parameters and overrided  get_resource_id
method, that returns None if resoruce creation has not been started yet.

Change-Id: Ia1097940db983721c8b5116db7ee0a2c4c45339d
Closes-Bug: #1548802
This commit is contained in:
Oleksii Chuprykov 2016-03-04 19:42:20 +02:00
parent 73fc655d1c
commit a7d63111a3
3 changed files with 90 additions and 1 deletions

View File

@ -11,6 +11,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_utils import encodeutils
from heat.common import exception
from heat.common.i18n import _
from heat.engine.cfn import functions as cfn_funcs
from heat.engine import function
@ -154,7 +157,14 @@ class TranslationRule(object):
if isinstance(param, hot_funcs.Removed):
raise AttributeError(_('Property uses removed function.'))
if isinstance(param, (hot_funcs.GetParam, cfn_funcs.ParamRef)):
return function.resolve(param)
try:
return function.resolve(param)
except exception.UserParameterMissing as ex:
# We can't resolve parameter now. Abort translation.
err_msg = encodeutils.exception_to_unicode(ex)
raise AttributeError(
_('Can not resolve parameter '
'due to: %s') % err_msg)
elif isinstance(param, list):
return [resolve_param(param_item) for param_item in param]
else:

View File

@ -16,6 +16,7 @@ import six
from heat.common import exception
from heat.engine.cfn import functions as cfn_funcs
from heat.engine import function
from heat.engine.hot import functions as hot_funcs
from heat.engine import parameters
from heat.engine import properties
@ -797,3 +798,40 @@ class TestTranslationRule(common.HeatTestCase):
rule.execute_rule()
self.assertEqual([param], props.data.get('far'))
def test_property_no_translation_if_user_parameter_missing(self):
"""Test translation in the case of missing parameter"""
schema = {
'source': properties.Schema(
properties.Schema.STRING
),
'destination': properties.Schema(
properties.Schema.STRING
)}
class DummyStack(dict):
@property
def parameters(self):
return mock.Mock()
param = hot_funcs.GetParam(DummyStack(),
'get_param',
'source_param')
param.parameters = {}
data = {'source': param, 'destination': ''}
props = properties.Properties(schema, data,
resolver=function.resolve)
rule = translation.TranslationRule(
props,
translation.TranslationRule.REPLACE,
['destination'],
value_path=['source'])
rule.execute_rule()
# ensure that translation rule was not applied
self.assertEqual({'source': param, 'destination': ''},
data)

View File

@ -186,3 +186,44 @@ outputs:
self.assertEqual('abc', res['properties']['value'])
self.assertEqual([], res['required_by'])
def test_res_group_with_nested_template(self):
main_template = '''
heat_template_version: 2015-04-30
resources:
fixed_network:
type: "OS::Neutron::Net"
rg:
type: "OS::Heat::ResourceGroup"
properties:
count: 1
resource_def:
type: nested.yaml
properties:
fixed_network_id: {get_resource: fixed_network}
'''
nested_template = '''
heat_template_version: 2015-04-30
parameters:
fixed_network_id:
type: string
resources:
port:
type: "OS::Neutron::Port"
properties:
network_id:
get_param: fixed_network_id
'''
stack_name = self._stack_rand_name()
result = self.client.stacks.preview(
disable_rollback=True,
stack_name=stack_name,
template=main_template,
files={'nested.yaml': nested_template}).to_dict()
# ensure that fixed network and port here
self.assertEqual('fixed_network',
result['resources'][0]['resource_name'])
self.assertEqual('port',
result['resources'][1][0][0]['resource_name'])