11
11
# License for the specific language governing permissions and limitations
12
12
# under the License.
17
16
from requests import exceptions
20
19
from heat.common import exception
20
from heat.common.i18n import _
21
21
from heat.common import template_format
22
22
from heat.common import urlfetch
23
23
from heat.engine import attributes
27
27
from heat.engine import template
30
def generate_class(name, template_name):
32
data = urlfetch.get(template_name, allowed_schemes=('file',))
34
return TemplateResource
30
def generate_class(name, template_name, env):
31
data = TemplateResource.get_template_file(template_name, ('file',))
35
32
tmpl = template.Template(template_format.parse(data))
36
properties_schema = properties.Properties.schema_from_params(
37
tmpl.param_schemata())
38
attributes_schema = attributes.Attributes.schema_from_outputs(
33
props, attrs = TemplateResource.get_schemas(tmpl, env.param_defaults)
40
34
cls = type(name, (TemplateResource,),
41
{"properties_schema": properties_schema,
42
"attributes_schema": attributes_schema})
35
{'properties_schema': props,
36
'attributes_schema': attrs})
78
72
if self.validation_exception is None:
79
73
self._generate_schema(self.t)
76
def get_template_file(template_name, allowed_schemes):
78
return urlfetch.get(template_name, allowed_schemes=allowed_schemes)
79
except (IOError, exceptions.RequestException) as r_exc:
80
args = {'name': template_name, 'exc': six.text_type(r_exc)}
81
msg = _('Could not fetch remote template '
82
'"%(name)s": %(exc)s') % args
83
raise exception.NotFound(msg_fmt=msg)
86
def get_schemas(tmpl, param_defaults):
87
return ((properties.Properties.schema_from_params(
88
tmpl.param_schemata(param_defaults))),
89
(attributes.Attributes.schema_from_outputs(
81
92
def _generate_schema(self, definition):
82
93
self._parsed_nested = None
84
95
tmpl = template.Template(self.child_template())
85
except ValueError as download_error:
96
except (exception.NotFound, ValueError) as download_error:
86
97
self.validation_exception = download_error
87
98
tmpl = template.Template(
88
99
{"HeatTemplateFormatVersion": "2012-12-12"})
90
101
# re-generate the properties and attributes from the template.
91
self.properties_schema = (properties.Properties
92
.schema_from_params(tmpl.param_schemata()))
93
self.attributes_schema = (attributes.Attributes
94
.schema_from_outputs(tmpl[tmpl.OUTPUTS]))
102
self.properties_schema, self.attributes_schema = self.get_schemas(
103
tmpl, self.stack.env.param_defaults)
96
105
self.properties = definition.properties(self.properties_schema,
147
156
def implementation_signature(self):
148
157
self._generate_schema(self.t)
149
schema_names = ([prop for prop in self.properties_schema] +
150
[at for at in self.attributes_schema])
151
schema_hash = hashlib.sha1(';'.join(schema_names))
152
templ_hash = hashlib.sha1(self.template_data())
153
return (schema_hash.hexdigest(), templ_hash.hexdigest())
158
return super(TemplateResource, self).implementation_signature()
155
160
def template_data(self):
156
161
# we want to have the latest possible template.
161
166
t_data = self.stack.t.files.get(self.template_name)
162
167
if not t_data and self.template_name.endswith((".yaml", ".template")):
164
t_data = urlfetch.get(self.template_name,
165
allowed_schemes=self.allowed_schemes)
166
except (exceptions.RequestException, IOError) as r_exc:
167
reported_excp = ValueError(_("Could not fetch remote template "
168
"'%(name)s': %(exc)s") % {
169
'name': self.template_name,
169
t_data = self.get_template_file(self.template_name,
170
self.allowed_schemes)
171
except exception.NotFound as err:
172
174
if t_data is None:
173
175
if self.nested() is not None:
266
268
def FnGetRefId(self):
267
269
if not self.nested():
268
return unicode(self.name)
270
return six.text_type(self.name)
272
if 'OS::stack_id' in self.nested().outputs:
273
return self.nested().output('OS::stack_id')
269
275
return self.nested().identifier().arn()
277
def FnGetAtt(self, key, *path):
278
stack = self.nested()
282
def _get_inner_resource(resource_name):
285
return self.nested()[resource_name]
287
raise exception.ResourceNotFound(
288
resource_name=resource_name,
289
stack_name=self.nested().name)
291
def get_rsrc_attr(resource_name, *attr_path):
292
resource = _get_inner_resource(resource_name)
293
return resource.FnGetAtt(*attr_path)
295
def get_rsrc_id(resource_name):
296
resource = _get_inner_resource(resource_name)
297
return resource.FnGetRefId()
299
# first look for explicit resource.x.y
300
if key.startswith('resource.'):
301
npath = key.split(".", 2)[1:] + list(path)
303
return get_rsrc_attr(*npath)
305
return get_rsrc_id(*npath)
307
# then look for normal outputs
308
if key in stack.outputs:
309
return attributes.select_from_attribute(stack.output(key), path)
311
# otherwise the key must be wrong.
312
raise exception.InvalidTemplateAttribute(resource=self.name,