diff --git a/heat/engine/translation.py b/heat/engine/translation.py index e0c3c931f1..90d8083eac 100644 --- a/heat/engine/translation.py +++ b/heat/engine/translation.py @@ -12,15 +12,10 @@ # under the License. import functools -import six - -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 -from heat.engine.hot import functions as hot_funcs @functools.total_ordering @@ -135,220 +130,6 @@ class TranslationRule(object): path.extend(self.custom_value_path) return path - def execute_rule(self, client_resolve=True): - try: - self._prepare_data(self.properties.data, self.translation_path, - self.properties.props) - if self.value_path: - if self.custom_value_path: - self.value_path.extend(self.custom_value_path) - self._prepare_data(self.properties.data, self.value_path, - self.properties.props) - (value_key, - value_data) = self.translate_property(self.value_path, - self.properties.data, - return_value=True) - value = (value_data[value_key] - if value_data and value_data.get(value_key) - else self.value) - else: - (value_key, value_data) = None, None - value = self.value - except AttributeError: - return - - self.translate_property(self.translation_path, self.properties.data, - value=value, value_data=value_data, - value_key=value_key, - client_resolve=client_resolve) - - def _prepare_data(self, data, path, props): - pass - - def _exec_action(self, key, data, value=None, value_key=None, - value_data=None, client_resolve=True): - if self.rule == TranslationRule.ADD: - self._exec_add(key, data, value) - elif self.rule == TranslationRule.REPLACE: - self._exec_replace(key, data, value_key, value_data, value) - elif self.rule == TranslationRule.RESOLVE and client_resolve: - self._exec_resolve(key, data) - elif self.rule == TranslationRule.DELETE: - self._exec_delete(key, data) - - def _resolve_param(self, param): - """Check whether given item is param and resolve, if it is.""" - if isinstance(param, (hot_funcs.GetParam, cfn_funcs.ParamRef)): - 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 [self._resolve_param(param_item) for param_item in param] - else: - return param - - def resolve_custom_value_path(self, translation_data, translation_key): - new_value = translation_data[self.value_name] - for key in self.custom_value_path[:-1]: - if isinstance(new_value, (list, six.string_types)): - raise ValueError( - _('Incorrectly specified custom_value_path - ' - 'cannot pull out required value from ' - 'data of %s type.') % type(new_value)) - if new_value.get(key) is None: - return - new_value = self._resolve_param(new_value[key]) - resolved_value = self._resolve_param( - new_value.get(self.custom_value_path[-1])) - if resolved_value is None: - return - if self.rule == self.REPLACE: - translation_data[translation_key] = resolved_value - del new_value[self.custom_value_path[-1]] - elif self.rule == self.ADD: - if isinstance(resolved_value, list): - translation_data[translation_key].extend(resolved_value) - else: - translation_data[translation_key].append(resolved_value) - - def translate_property(self, path, data, return_value=False, value=None, - value_data=None, value_key=None, - client_resolve=True): - if isinstance(data, function.Function): - if return_value: - raise AttributeError('No chance to translate value due to ' - 'value is function. Skip translation.') - return - current_key = path[0] - if len(path) <= 1: - if return_value: - return current_key, data - else: - self._exec_action(current_key, data, - value=value, value_data=value_data, - value_key=value_key, - client_resolve=client_resolve) - return - if data.get(current_key) is None: - return - elif isinstance(data[current_key], list): - for item in data[current_key]: - if return_value: - # Until there's no reasonable solution for cases of using - # one list for value and another list for destination, - # error would be raised. - msg = _('Cannot use value_path for properties inside ' - 'list-type properties') - raise ValueError(msg) - else: - self.translate_property(path[1:], item, - return_value=return_value, - value=value, value_data=value_data, - value_key=value_key, - client_resolve=client_resolve) - else: - return self.translate_property(path[1:], data[current_key], - return_value=return_value, - value=value, value_data=value_data, - value_key=value_key, - client_resolve=client_resolve) - - def _exec_add(self, translation_key, translation_data, value): - if not isinstance(translation_data[translation_key], list): - raise ValueError(_('Add rule must be used only for ' - 'lists.')) - if value is not None: - translation_data[translation_key].extend(value) - elif (self.value_name is not None and - translation_data.get(self.value_name) is not None): - if self.custom_value_path: - self.resolve_custom_value_path(translation_data, - translation_key) - elif isinstance(translation_data[self.value_name], list): - translation_data[translation_key].extend( - translation_data[self.value_name]) - else: - translation_data[translation_key].append( - translation_data[self.value_name]) - - def _exec_replace(self, translation_key, translation_data, - value_key, value_data, value): - value_ind = None - if translation_data and translation_data.get(translation_key): - if value_data and value_data.get(value_key): - value_ind = value_key - elif translation_data.get(self.value_name) is not None: - value_ind = self.value_name - if self.custom_value_path is not None: - data = translation_data.get(self.value_name) - for key in self.custom_value_path: - data = data.get(key) - if data is None: - value_ind = None - break - - if value_ind is not None: - raise exception.ResourcePropertyConflict(props=[translation_key, - value_ind]) - if value is not None: - translation_data[translation_key] = value - elif (self.value_name is not None and - translation_data.get(self.value_name) is not None): - if self.custom_value_path: - self.resolve_custom_value_path(translation_data, - translation_key) - else: - translation_data[ - translation_key] = translation_data[self.value_name] - del translation_data[self.value_name] - - # If value defined with value_path, need to delete value_path - # property data after it's replacing. - if value_data and value_data.get(value_key): - del value_data[value_key] - - def _exec_resolve(self, translation_key, translation_data): - - def resolve_and_find(translation_value): - if isinstance(translation_value, function.Function): - translation_value = function.resolve(translation_value) - if translation_value: - if isinstance(translation_value, list): - resolved_value = [] - for item in translation_value: - resolved_value.append(resolve_and_find(item)) - return resolved_value - finder = getattr(self.client_plugin, self.finder) - if self.entity: - return finder(self.entity, translation_value) - else: - return finder(translation_value) - - if isinstance(translation_data, list): - for item in translation_data: - translation_value = item.get(translation_key) - resolved_value = resolve_and_find(translation_value) - if resolved_value is not None: - item[translation_key] = resolved_value - else: - translation_value = translation_data.get(translation_key) - resolved_value = resolve_and_find(translation_value) - if resolved_value is not None: - translation_data[translation_key] = resolved_value - - def _exec_delete(self, translation_key, translation_data): - if isinstance(translation_data, list): - for item in translation_data: - if item.get(translation_key) is not None: - del item[translation_key] - elif translation_data.get(translation_key) is not None: - del translation_data[translation_key] - class Translation(object): """Mechanism for translating one properties to other. diff --git a/heat/tests/test_resource.py b/heat/tests/test_resource.py index e18032ef9b..30a39c3ace 100644 --- a/heat/tests/test_resource.py +++ b/heat/tests/test_resource.py @@ -172,7 +172,7 @@ class ResourceTest(common.HeatTestCase): self.assertEqual('Resource name may not contain "/"', six.text_type(ex)) - @mock.patch.object(translation.TranslationRule, '_exec_resolve') + @mock.patch.object(translation, 'resolve_and_find') @mock.patch.object(parser.Stack, 'db_resource_get') @mock.patch.object(resource.Resource, '_load_data') @mock.patch.object(resource.Resource, 'translate_properties')