Merge "Ignore RESOLVE translation errors when translating before_props" into stable/ocata

This commit is contained in:
Zuul 2018-08-06 17:14:52 +00:00 committed by Gerrit Code Review
commit ec32eb4c73
4 changed files with 68 additions and 33 deletions

View File

@ -1075,7 +1075,7 @@ class Resource(object):
"""Return specified rules for resource."""
def translate_properties(self, properties,
client_resolve=True):
client_resolve=True, ignore_resolve_error=False):
"""Translates properties with resource specific rules.
The properties parameter is a properties object and the
@ -1085,7 +1085,7 @@ class Resource(object):
rules = self.translation_rules(properties) or []
for rule in rules:
try:
rule.execute_rule(client_resolve)
rule.execute_rule(client_resolve, ignore_resolve_error)
except exception.ResourcePropertyConflict as ex:
path = [self.stack.t.RESOURCES, self.name,
self.stack.t.get_section_name(
@ -1265,7 +1265,7 @@ class Resource(object):
after_props = after.properties(self.properties_schema,
self.context)
self.translate_properties(after_props)
self.translate_properties(before_props)
self.translate_properties(before_props, ignore_resolve_error=True)
if cfg.CONF.observe_on_update and before_props:
if not self.resource_id:

View File

@ -11,9 +11,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import six
from oslo_log import log as logging
from oslo_utils import encodeutils
import six
from heat.common import exception
from heat.common.i18n import _
@ -22,6 +22,8 @@ from heat.engine import function
from heat.engine.hot import functions as hot_funcs
from heat.engine import properties
LOG = logging.getLogger(__name__)
class TranslationRule(object):
"""Translating mechanism one properties to another.
@ -112,7 +114,7 @@ class TranslationRule(object):
raise ValueError(_('client_plugin and finder should be specified '
'for Resolve rule'))
def execute_rule(self, client_resolve=True):
def execute_rule(self, client_resolve=True, ignore_resolve_error=False):
try:
self._prepare_data(self.properties.data, self.translation_path,
self.properties.props)
@ -137,7 +139,8 @@ class TranslationRule(object):
self.translate_property(self.translation_path, self.properties.data,
value=value, value_data=value_data,
value_key=value_key,
client_resolve=client_resolve)
client_resolve=client_resolve,
ignore_resolve_error=ignore_resolve_error)
def _prepare_data(self, data, path, props):
def get_props(props, key):
@ -177,13 +180,14 @@ class TranslationRule(object):
get_props(props, current_key))
def _exec_action(self, key, data, value=None, value_key=None,
value_data=None, client_resolve=True):
value_data=None, client_resolve=True,
ignore_resolve_error=False):
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)
self._exec_resolve(key, data, ignore_resolve_error)
elif self.rule == TranslationRule.DELETE:
self._exec_delete(key, data)
@ -229,7 +233,7 @@ class TranslationRule(object):
def translate_property(self, path, data, return_value=False, value=None,
value_data=None, value_key=None,
client_resolve=True):
client_resolve=True, ignore_resolve_error=False):
if isinstance(data, function.Function):
if return_value:
raise AttributeError('No chance to translate value due to '
@ -243,7 +247,8 @@ class TranslationRule(object):
self._exec_action(current_key, data,
value=value, value_data=value_data,
value_key=value_key,
client_resolve=client_resolve)
client_resolve=client_resolve,
ignore_resolve_error=ignore_resolve_error)
return
if data.get(current_key) is None:
return
@ -257,17 +262,19 @@ class TranslationRule(object):
'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)
self.translate_property(
path[1:], item, return_value=return_value,
value=value, value_data=value_data,
value_key=value_key,
client_resolve=client_resolve,
ignore_resolve_error=ignore_resolve_error)
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)
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,
ignore_resolve_error=ignore_resolve_error)
def _exec_add(self, translation_key, translation_data, value):
if not isinstance(translation_data[translation_key], list):
@ -323,32 +330,43 @@ class TranslationRule(object):
if value_data and value_data.get(value_key):
del value_data[value_key]
def _exec_resolve(self, translation_key, translation_data):
def _exec_resolve(self, translation_key, translation_data,
ignore_resolve_error=False):
def resolve_and_find(translation_value):
def resolve_and_find(translation_value, ignore_resolve_error):
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))
resolved_value.append(
resolve_and_find(item,
ignore_resolve_error))
return resolved_value
finder = getattr(self.client_plugin, self.finder)
if self.entity:
return finder(self.entity, translation_value)
else:
return finder(translation_value)
try:
if self.entity:
return finder(self.entity, translation_value)
else:
return finder(translation_value)
except Exception as ex:
if ignore_resolve_error:
LOG.info("Ignoring error in RESOLVE translation: %s",
six.text_type(ex))
return translation_value
raise
if isinstance(translation_data, list):
for item in translation_data:
translation_value = item.get(translation_key)
resolved_value = resolve_and_find(translation_value)
resolved_value = resolve_and_find(translation_value,
ignore_resolve_error)
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)
resolved_value = resolve_and_find(translation_value,
ignore_resolve_error)
if resolved_value is not None:
translation_data[translation_key] = resolved_value

View File

@ -3672,7 +3672,7 @@ class ServersTest(common.HeatTestCase):
args='Update Image')
self.patchobject(glance.GlanceClientPlugin,
'find_image_by_name_or_id',
side_effect=[1, ex])
side_effect=ex)
update_props = self.server_props.copy()
update_props['image'] = 'Update Image'
update_template = server.t.freeze(properties=update_props)

View File

@ -465,10 +465,13 @@ class TestTranslationRule(common.HeatTestCase):
self.assertIsNone(props.get('far'))
def _test_resolve_rule(self, is_list=False):
def _test_resolve_rule(self, is_list=False,
check_error=False):
class FakeClientPlugin(object):
def find_name_id(self, entity=None,
src_value='far'):
if check_error:
raise exception.NotFound()
if entity == 'rose':
return 'pink'
return 'yellow'
@ -599,6 +602,20 @@ class TestTranslationRule(common.HeatTestCase):
rule.execute_rule()
self.assertEqual([], props.get('far'))
def test_resolve_rule_ignore_error(self):
client_plugin, schema = self._test_resolve_rule(check_error=True)
data = {'far': 'one'}
props = properties.Properties(schema, data)
rule = translation.TranslationRule(
props,
translation.TranslationRule.RESOLVE,
['far'],
client_plugin=client_plugin,
finder='find_name_id')
rule.execute_rule(ignore_resolve_error=True)
self.assertEqual('one', props.get('far'))
def test_resolve_rule_other(self):
client_plugin, schema = self._test_resolve_rule()
data = {'far': 'one'}