Give cfn a separate Template class

Change-Id: Iddeeef7e0303fcbf09fc936a96ec68dbccd5489e
This commit is contained in:
Zane Bitter 2014-03-03 15:28:29 -05:00
parent 00eb5295d1
commit f7a52b5005
6 changed files with 96 additions and 55 deletions

View File

@ -0,0 +1,67 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from heat.engine import parameters
from heat.engine import template
from heat.engine.cfn import functions
class CfnTemplate(template.Template):
'''A stack template.'''
SECTIONS = (VERSION, DESCRIPTION, MAPPINGS,
PARAMETERS, RESOURCES, OUTPUTS) = \
('AWSTemplateFormatVersion', 'Description', 'Mappings',
'Parameters', 'Resources', 'Outputs')
SECTIONS_NO_DIRECT_ACCESS = set([PARAMETERS, VERSION])
def __getitem__(self, section):
'''Get the relevant section in the template.'''
if section not in self.SECTIONS:
raise KeyError(_('"%s" is not a valid template section') % section)
if section in self.SECTIONS_NO_DIRECT_ACCESS:
raise KeyError(
_('Section %s can not be accessed directly.') % section)
if section == self.DESCRIPTION:
default = 'No description'
else:
default = {}
return self.t.get(section, default)
def version(self):
for key in ('HeatTemplateFormatVersion', 'AWSTemplateFormatVersion'):
if key in self.t:
return key, self.t[key]
# All user templates are forced to include a version string. This is
# just a convenient default for unit tests.
return 'HeatTemplateFormatVersion', '2012-12-12'
def param_schemata(self):
params = self.t.get(self.PARAMETERS, {}).iteritems()
return dict((name, parameters.Schema.from_dict(schema))
for name, schema in params)
def parameters(self, stack_identifier, user_params, validate_value=True,
context=None):
return parameters.Parameters(stack_identifier, self,
user_params=user_params,
validate_value=validate_value,
context=context)
def functions(self):
return functions.function_mapping(*self.version())

View File

@ -14,6 +14,7 @@
from heat.common import exception
from heat.engine import template
from heat.engine.cfn import template as cfn_template
from heat.engine import parameters
from heat.engine import constraints as constr
from heat.openstack.common.gettextutils import _
@ -41,7 +42,7 @@ class HOTemplate(template.Template):
"""
SECTIONS = (VERSION, DESCRIPTION, PARAMETER_GROUPS, PARAMETERS,
RESOURCES, OUTPUTS, UNDEFINED) = \
RESOURCES, OUTPUTS, MAPPINGS) = \
('heat_template_version', 'description', 'parameter_groups',
'parameters', 'resources', 'outputs', '__undefined__')
@ -49,12 +50,12 @@ class HOTemplate(template.Template):
VERSIONS = ('2013-05-23',)
_CFN_TO_HOT_SECTIONS = {template.Template.VERSION: VERSION,
template.Template.DESCRIPTION: DESCRIPTION,
template.Template.PARAMETERS: PARAMETERS,
template.Template.MAPPINGS: UNDEFINED,
template.Template.RESOURCES: RESOURCES,
template.Template.OUTPUTS: OUTPUTS}
_CFN_TO_HOT_SECTIONS = {cfn_template.CfnTemplate.VERSION: VERSION,
cfn_template.CfnTemplate.DESCRIPTION: DESCRIPTION,
cfn_template.CfnTemplate.PARAMETERS: PARAMETERS,
cfn_template.CfnTemplate.MAPPINGS: MAPPINGS,
cfn_template.CfnTemplate.RESOURCES: RESOURCES,
cfn_template.CfnTemplate.OUTPUTS: OUTPUTS}
def __init__(self, template, *args, **kwargs):
version = template[self.VERSION]
@ -79,7 +80,7 @@ class HOTemplate(template.Template):
raise KeyError(
_('Section %s can not be accessed directly.') % section)
if section == self.UNDEFINED:
if section == self.MAPPINGS:
return {}
if section == self.DESCRIPTION:

View File

@ -13,36 +13,27 @@
# License for the specific language governing permissions and limitations
# under the License.
import abc
import collections
import functools
from heat.db import api as db_api
from heat.engine import parameters
from heat.engine.cfn import functions
from heat.openstack.common.gettextutils import _
class Template(collections.Mapping):
'''A stack template.'''
SECTIONS = (VERSION, DESCRIPTION, MAPPINGS,
PARAMETERS, RESOURCES, OUTPUTS) = \
('AWSTemplateFormatVersion', 'Description', 'Mappings',
'Parameters', 'Resources', 'Outputs')
SECTIONS_NO_DIRECT_ACCESS = set([PARAMETERS, VERSION])
def __new__(cls, template, *args, **kwargs):
'''Create a new Template of the appropriate class.'''
if cls == Template:
# deferred module imports to avoid circular dependency
if 'heat_template_version' in template:
# defer import of HOT module to avoid circular dependency
# at load time
from heat.engine import hot
return hot.HOTemplate(template, *args, **kwargs)
else:
from heat.engine.cfn import template as cfn
return cfn.CfnTemplate(template, *args, **kwargs)
return super(Template, cls).__new__(cls)
@ -72,21 +63,6 @@ class Template(collections.Mapping):
self.id = new_rt.id
return self.id
def __getitem__(self, section):
'''Get the relevant section in the template.'''
if section not in self.SECTIONS:
raise KeyError(_('"%s" is not a valid template section') % section)
if section in self.SECTIONS_NO_DIRECT_ACCESS:
raise KeyError(
_('Section %s can not be accessed directly.') % section)
if section == self.DESCRIPTION:
default = 'No description'
else:
default = {}
return self.t.get(section, default)
def __iter__(self):
'''Return an iterator over the section names.'''
return (s for s in self.SECTIONS
@ -96,29 +72,26 @@ class Template(collections.Mapping):
'''Return the number of sections.'''
return len(self.SECTIONS) - len(self.SECTIONS_NO_DIRECT_ACCESS)
@abc.abstractmethod
def version(self):
for key in ('HeatTemplateFormatVersion', 'AWSTemplateFormatVersion'):
if key in self.t:
return key, self.t[key]
# All user templates are forced to include a version string. This is
# just a convenient default for unit tests.
return 'HeatTemplateFormatVersion', '2012-12-12'
'''Return a (versionkey, version) tuple for the template.'''
pass
@abc.abstractmethod
def param_schemata(self):
params = self.t.get(self.PARAMETERS, {}).iteritems()
return dict((name, parameters.Schema.from_dict(schema))
for name, schema in params)
'''Return a dict of parameters.Schema objects for the parameters.'''
pass
@abc.abstractmethod
def parameters(self, stack_identifier, user_params, validate_value=True,
context=None):
return parameters.Parameters(stack_identifier, self,
user_params=user_params,
validate_value=validate_value,
context=context)
'''Return a parameters.Parameters object for the stack.'''
pass
@abc.abstractmethod
def functions(self):
return functions.function_mapping(*self.version())
'''Return a dict of template functions keyed by name.'''
pass
def parse(self, stack, snippet):
parse = functools.partial(self.parse, stack)

View File

@ -2608,7 +2608,7 @@ class StackServiceTest(HeatTestCase):
def test_validate_new_stack_checks_resource_limit(self):
cfg.CONF.set_override('max_resources_per_stack', 5)
template = {service.parser.Template.RESOURCES: [1, 2, 3, 4, 5, 6]}
template = {'Resources': [1, 2, 3, 4, 5, 6]}
parsed_template = service.parser.Template(template)
self.assertRaises(exception.RequestLimitExceeded,
self.eng._validate_new_stack,

View File

@ -1473,7 +1473,7 @@ class StackTest(HeatTestCase):
self.assertEqual((parser.Stack.UPDATE, parser.Stack.COMPLETE),
self.stack.state)
self.assertEqual('BTemplate',
self.stack.t[template.Template.DESCRIPTION])
self.stack.t[self.stack.t.DESCRIPTION])
@utils.stack_delete_after
def test_update_modify_ok_replace(self):

View File

@ -177,7 +177,7 @@ class StackResourceTest(HeatTestCase):
def test__validate_nested_resources_checks_num_of_resources(self):
stack_resource.cfg.CONF.set_override('max_resources_per_stack', 2)
tmpl = {stack_resource.parser.Template.RESOURCES: [1]}
tmpl = {'Resources': [1]}
template = stack_resource.parser.Template(tmpl)
root_resources = mock.Mock(return_value=2)
self.parent_resource.stack.root_stack.total_resources = root_resources