outputs:
instance_ip: { get_attr: [my_instance, PublicIp] }
+
+
+get_resource
+------------
+The *get_resource* function allows for referencing another resource within the
+same template. At runtime, it will be resolved to reference ID of the resource,
+which is resource type specific. For example, a reference to a floating IP
+resource will return the respective IP address at runtime.
+The syntax of the get_resource function is as follows:
+
+::
+
+ get_resource: <resource ID>
+
+The *resource ID* of the referenced resources as used in the current template is
+given as single parameter to the get_resource function.
+
+
+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.
+The syntax of the str_replace function is as follows:
+
+::
+
+ str_replace:
+ template: <template string>
+ params: <parameter mappings>
+
+template
+ The *template* argument defines the template string that contains
+ placeholders which will be substituted at runtime.
+params
+ The *params* argument provides parameter mappings in the form of a
+ dictionary, which will be used for placeholder substitution in the template
+ string at runtime. Within parameter mappings one can make use of other
+ functions (e.g. get_attr to use resource attribute values) for template
+ substitution.
+
+The example below shows a simple use of the str_replace function in the outputs
+section of a template to build a URL for logging into a deployed application.
+
+::
+
+ resources:
+ my_instance:
+ type: OS::Nova::Compute
+ # general metadata and properties ...
+
+ outputs:
+ Login_URL:
+ description: The URL to log into the deployed application
+ value:
+ str_replace:
+ template: http://$host/MyApplication
+ params:
+ host: { get_attr: [ my_instance, PublicIp ] }
+
+The str_replace function can also be used for constructing bigger chunks of text
+like scripts for initializing compute instances as shown in the example below:
+
+::
+
+ parameters:
+ DBRootPassword:
+ type: string
+ description: Root password for MySQL
+ hidden: true
+
+ resources:
+ my_instance:
+ type: OS::Nova::Compute
+ properties:
+ # general properties ...
+ userdata:
+ str_replace:
+ template: |
+ #!/bin/bash
+ echo "Hello world"
+ echo "Setting MySQL root password"
+ mysqladmin -u root password $db_rootpassword
+ # do more things ...
+ params:
+ 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
+provided parameter. The script for doing this is provided as userdata to the
+compute instance, leveraging the str_replace function.
# License for the specific language governing permissions and limitations
# under the License.
+from string import Template
+
from heat.common import exception
from heat.engine import template
from heat.engine.parameters import ParamSchema
return template._resolve(match_param_ref, handle_param_ref, s)
+ @staticmethod
+ def resolve_resource_refs(s, resources):
+ '''
+ Resolve constructs of the form { "get_resource" : "resource" }
+ '''
+ def match_resource_ref(key, value):
+ return key == 'get_resource' and value in resources
+
+ def handle_resource_ref(arg):
+ return resources[arg].FnGetRefId()
+
+ return template._resolve(match_resource_ref, handle_resource_ref, s)
+
@staticmethod
def resolve_attributes(s, resources):
"""
return template._resolve(match_get_attr, handle_get_attr, s)
+ @staticmethod
+ def resolve_replace(s):
+ """
+ Resolve template string substitution via function str_replace
+
+ Resolves the str_replace function of the form
+
+ str_replace:
+ template: <string template>
+ params:
+ <param dictionary>
+ """
+ def handle_str_replace(args):
+ if not isinstance(args, dict):
+ raise TypeError('Arguments to "str_replace" must be a'
+ 'dictionary')
+
+ try:
+ template = args['template']
+ params = args['params']
+ except KeyError:
+ example = ('''str_replace:
+ template: This is $var1 template $var2
+ params:
+ - var1: a
+ - var2: string''')
+ raise KeyError('"str_replace" syntax should be %s' %
+ example)
+
+ if not isinstance(template, basestring):
+ raise TypeError('"template" parameter must be a string')
+ if not isinstance(params, dict):
+ raise TypeError(
+ '"params" parameter must be a dictionary')
+
+ return Template(template).substitute(params)
+
+ return template._resolve(lambda k, v: k == 'str_replace',
+ handle_str_replace, s)
+
def param_schemata(self):
params = self[PARAMETERS].iteritems()
return dict((name, HOTParamSchema(schema)) for name, schema in params)
self.assertEqual(tmpl.resolve_param_refs(snippet, params),
snippet_resolved)
+ def test_str_replace(self):
+ """Test str_replace function."""
+
+ snippet = {'str_replace': {'template': 'Template $var1 string $var2',
+ 'params': {'var1': 'foo', 'var2': 'bar'}}}
+ snippet_resolved = 'Template foo string bar'
+
+ tmpl = parser.Template(hot_tpl_empty)
+
+ self.assertEqual(tmpl.resolve_replace(snippet), snippet_resolved)
+
+ def test_str_replace_syntax(self):
+ """
+ Test str_replace function syntax.
+
+ Pass wrong syntax (array instead of dictionary) to function and
+ validate that we get a TypeError.
+ """
+
+ snippet = {'str_replace': [{'template': 'Template $var1 string $var2'},
+ {'params': {'var1': 'foo', 'var2': 'bar'}}]}
+
+ tmpl = parser.Template(hot_tpl_empty)
+
+ self.assertRaises(TypeError, tmpl.resolve_replace, snippet)
+
+ def test_str_replace_invalid_param_keys(self):
+ """
+ Test str_replace function parameter keys.
+
+ Pass wrong parameters to function and verify that we get
+ a KeyError.
+ """
+
+ 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',
+ 'parms': {'var1': 'foo', 'var2': 'bar'}}}
+
+ self.assertRaises(KeyError, tmpl.resolve_replace, snippet)
+
+ def test_str_replace_invalid_param_types(self):
+ """
+ Test str_replace function parameter values.
+
+ Pass parameter values of wrong type to function and verify that we get
+ a TypeError.
+ """
+
+ snippet = {'str_replace': {'template': 12345,
+ 'params': {'var1': 'foo', 'var2': 'bar'}}}
+
+ tmpl = parser.Template(hot_tpl_empty)
+
+ self.assertRaises(TypeError, tmpl.resolve_replace, snippet)
+
+ snippet = {'str_replace': {'template': 'Template $var1 string $var2',
+ 'params': ['var1', 'foo', 'var2', 'bar']}}
+
+ self.assertRaises(TypeError, tmpl.resolve_replace, snippet)
+
class StackTest(test_parser.StackTest):
"""Test stack function when stack was created from HOT template."""
{'Value': {'get_attr': ['resource1', 'NotThere']}},
self.stack)
+ @utils.stack_delete_after
+ def test_get_resource(self):
+ """Test resolution of get_resource occurrences in HOT template."""
+
+ hot_tpl = template_format.parse('''
+ heat_template_version: 2013-05-23
+ resources:
+ resource1:
+ type: GenericResourceType
+ ''')
+
+ self.stack = parser.Stack(self.ctx, 'test_get_resource',
+ template.Template(hot_tpl))
+ self.stack.store()
+ self.stack.create()
+ self.assertEqual(self.stack.state,
+ (parser.Stack.CREATE, parser.Stack.COMPLETE))
+
+ snippet = {'value': {'get_resource': 'resource1'}}
+ resolved = hot.HOTemplate.resolve_resource_refs(snippet, self.stack)
+ self.assertEqual(resolved, {'value': 'resource1'})
+
class HOTParamValidatorTest(HeatTestCase):
"Test HOTParamValidator"