HOT str_replace to use string.replace, not string.Template

str_replace uses python templates, whereas Fn::Replace uses python
string.replace.

During the original review for Fn::Replace, python templates were
decided against because $ would often need double-escaping in shell scripts.
https://review.openstack.org/#/c/31736/

Having different behaviours between Fn::Replace and str_replace will
add complication for users migrating existing templates to HOT.

Another advantage of using straight string replacement is seen when
the template generates a executable script. In this case it is generally
possible to write a template that can also be executed directly in a
dev/test environment. This would often not be possible if the template
format required placeholders to be prefixed with a $.

Whatever behaviour exists when Havana is release will have to be
supported indefinitely so now is the time to decide if this is going
to be fixed.

Closes-Bug: #1228640
Change-Id: I72879b374a3c61dfe0e4004251ab709d914f2e25
This commit is contained in:
Steve Baker 2013-09-23 13:41:32 +12:00
parent b21ce20427
commit f424d6f6c3
3 changed files with 14 additions and 19 deletions

View File

@ -464,8 +464,8 @@ str_replace
-----------
The *str_replace* function allows for dynamically constructing strings by
providing a template string with placeholders and a list of mappings to assign
values to those placeholders at runtime. The functionality of this function is
similar to that of Python Template strings.
values to those placeholders at runtime. The placeholders are replaced with
mapping values wherever a mapping key exactly matches a placeholder.
The syntax of the str_replace function is as follows:
::
@ -499,7 +499,7 @@ section of a template to build a URL for logging into a deployed application.
description: The URL to log into the deployed application
value:
str_replace:
template: http://$host/MyApplication
template: http://host/MyApplication
params:
host: { get_attr: [ my_instance, PublicIp ] }
@ -528,7 +528,7 @@ like scripts for initializing compute instances as shown in the example below:
mysqladmin -u root password $db_rootpassword
# do more things ...
params:
db_rootpassword: { get_param: DBRootPassword }
$db_rootpassword: { get_param: DBRootPassword }
In the example above, one can imagine that MySQL is being configured on a
compute instance and the root password is going to be set based on a user

View File

@ -12,8 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import string
from heat.common import exception
from heat.engine import template
from heat.engine.parameters import ParamSchema
@ -260,7 +258,7 @@ class HOTemplate(template.Template):
raise KeyError()
except KeyError:
example = ('''str_replace:
template: This is $var1 template $var2
template: This is var1 template var2
params:
var1: a
var2: string''')
@ -271,13 +269,10 @@ class HOTemplate(template.Template):
if not isinstance(params, dict):
raise TypeError(
'"params" parameter must be a dictionary')
if isinstance(args, list):
for key in params.iterkeys():
value = params.get(key, '')
text = text.replace(key, value)
return text
return string.Template(text).safe_substitute(params)
for key in params.iterkeys():
value = params.get(key, '')
text = text.replace(key, value)
return text
match_str_replace = lambda k, v: k in ['str_replace', 'Fn::Replace']
return template._resolve(match_str_replace,

View File

@ -269,7 +269,7 @@ class HOTemplateTest(HeatTestCase):
def test_str_replace(self):
"""Test str_replace function."""
snippet = {'str_replace': {'template': 'Template $var1 string $var2',
snippet = {'str_replace': {'template': 'Template var1 string var2',
'params': {'var1': 'foo', 'var2': 'bar'}}}
snippet_resolved = 'Template foo string bar'
@ -297,7 +297,7 @@ class HOTemplateTest(HeatTestCase):
validate that we get a TypeError.
"""
snippet = {'str_replace': [{'template': 'Template $var1 string $var2'},
snippet = {'str_replace': [{'template': 'Template var1 string var2'},
{'params': {'var1': 'foo', 'var2': 'bar'}}]}
tmpl = parser.Template(hot_tpl_empty)
@ -312,14 +312,14 @@ class HOTemplateTest(HeatTestCase):
a KeyError.
"""
snippet = {'str_replace': {'tmpl': 'Template $var1 string $var2',
snippet = {'str_replace': {'tmpl': 'Template var1 string var2',
'params': {'var1': 'foo', 'var2': 'bar'}}}
tmpl = parser.Template(hot_tpl_empty)
self.assertRaises(KeyError, tmpl.resolve_replace, snippet)
snippet = {'str_replace': {'tmpl': 'Template $var1 string $var2',
snippet = {'str_replace': {'tmpl': 'Template var1 string var2',
'parms': {'var1': 'foo', 'var2': 'bar'}}}
self.assertRaises(KeyError, tmpl.resolve_replace, snippet)
@ -339,7 +339,7 @@ class HOTemplateTest(HeatTestCase):
self.assertRaises(TypeError, tmpl.resolve_replace, snippet)
snippet = {'str_replace': {'template': 'Template $var1 string $var2',
snippet = {'str_replace': {'template': 'Template var1 string var2',
'params': ['var1', 'foo', 'var2', 'bar']}}
self.assertRaises(TypeError, tmpl.resolve_replace, snippet)