Make sure we can create an empty template

The initial bug was for HOT, but this fixes the same issue
in CFN too.

1) all calls to template[section] should return {} and not
   None by default (hot was correct, but not cfn)
2) the validate needs to access the raw template "self.t" so
   make sure we have a similar logic there too.
3) when warning for zero resources, look for len(resoruces) == 0 not
   None.

Change-Id: Iee6e2abbf13173c17d92f47b8a7efe207c29a984
Closes-bug: #1339893
This commit is contained in:
Angus Salkeld 2014-07-14 21:26:43 +10:00
parent 2f0fc89e78
commit f6894260ca
6 changed files with 102 additions and 8 deletions

View File

@ -53,12 +53,14 @@ class CfnTemplate(template.Template):
else:
default = {}
return self.t.get(section, default)
# if a section is None (empty yaml section) return {}
# to be consistent with an empty json section.
return self.t.get(section) or default
def param_schemata(self):
params = self.t.get(self.PARAMETERS, {}).iteritems()
params = self.t.get(self.PARAMETERS) or {}
return dict((name, parameters.Schema.from_dict(name, schema))
for name, schema in params)
for name, schema in params.iteritems())
def parameters(self, stack_identifier, user_params):
return parameters.Parameters(stack_identifier, self,
@ -125,8 +127,9 @@ class CfnTemplate(template.Template):
description=description)
return name, defn
resources = self.t.get(self.RESOURCES, {}).items()
return dict(rsrc_defn_item(name, data) for name, data in resources)
resources = self.t.get(self.RESOURCES) or {}
return dict(rsrc_defn_item(name, data)
for name, data in resources.items())
def add_resource(self, definition, name=None):
if name is None:

View File

@ -70,6 +70,8 @@ class HOTemplate(template.Template):
else:
default = {}
# if a section is None (empty yaml section) return {}
# to be consistent with an empty json section.
the_section = self.t.get(section) or default
# In some cases (e.g. parameters), also translate each entry of
@ -212,8 +214,9 @@ class HOTemplate(template.Template):
update_policy)
return name, defn
resources = self.t.get(self.RESOURCES, {}).items()
return dict(rsrc_defn_item(name, data) for name, data in resources)
resources = self.t.get(self.RESOURCES) or {}
return dict(rsrc_defn_item(name, data)
for name, data in resources.items())
def add_resource(self, definition, name=None):
if name is None:

View File

@ -219,7 +219,7 @@ class Template(collections.Mapping):
# check resources
tmpl_resources = self[self.RESOURCES]
if not tmpl_resources:
if len(tmpl_resources) == 0:
LOG.warn(_('Template does not contain any resources, so '
'the template would not really do anything when '
'being instantiated.'))

View File

@ -0,0 +1,75 @@
#
# 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.common import template_format
from heat.engine import parser
from heat.engine import template
from heat.tests import common
from heat.tests import utils
class StackTest(common.HeatTestCase):
def setUp(self):
super(StackTest, self).setUp()
self.username = 'parser_stack_test_user'
self.ctx = utils.dummy_context()
def _assert_can_create(self, templ):
stack = parser.Stack(self.ctx, 'update_stack_arn_test',
template.Template(templ))
stack.store()
stack.create()
self.assertEqual((parser.Stack.CREATE, parser.Stack.COMPLETE),
stack.state)
def test_heat_empty_json(self):
tmpl = {'HeatTemplateFormatVersion': '2012-12-12',
'Resources': {}, 'Parameters': {}, 'Outputs': {}}
self._assert_can_create(tmpl)
def test_cfn_empty_json(self):
tmpl = {'AWSTemplateFormatVersion': '2010-09-09',
'Resources': {}, 'Parameters': {}, 'Outputs': {}}
self._assert_can_create(tmpl)
def test_hot_empty_json(self):
tmpl = {'heat_template_version': '2013-05-23',
'resources': {}, 'parameters': {}, 'outputs': {}}
self._assert_can_create(tmpl)
def test_heat_empty_yaml(self):
t = template_format.parse('''
HeatTemplateFormatVersion: 2012-12-12
Parameters:
Resources:
Outputs:
''')
self._assert_can_create(t)
def test_cfn_empty_yaml(self):
t = template_format.parse('''
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Resources:
Outputs:
''')
self._assert_can_create(t)
def test_hot_empty_yaml(self):
t = template_format.parse('''
heat_template_version: 2013-05-23
parameters:
resources:
outputs:
''')
self._assert_can_create(t)

View File

@ -123,6 +123,7 @@ class HOTemplateTest(HeatTestCase):
self.assertIsNone(stack.parameters._validate_user_parameters())
self.assertIsNone(stack.parameters._validate_tmpl_parameters())
self.assertIsNone(stack.validate())
def test_translate_resources_good(self):
"""Test translation of resources into internal engine format."""

View File

@ -13,6 +13,7 @@
# under the License.
from heat.common import exception
from heat.common import template_format
from heat.engine.cfn.template import CfnTemplate
from heat.engine import plugin_manager
from heat.engine import template
@ -151,6 +152,17 @@ class TestTemplateValidate(HeatTestCase):
tmpl.validate)
self.assertIn('Parameteers', str(err))
def test_template_validate_cfn_empty(self):
t = template_format.parse('''
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Resources:
Outputs:
''')
tmpl = template.Template(t)
err = tmpl.validate()
self.assertIsNone(err)
def test_template_validate_hot_good(self):
t = {
'heat_template_version': '2013-05-23',