Add an environment_format.py like the template one

This to make the section checking mechanism less spread out
and more consistent. This can also be used by the global
environment loader.

Change-Id: I7ca7ad754fb702877dedc416a30f573d239933ad
This commit is contained in:
Angus Salkeld 2013-08-20 16:35:25 +10:00
parent 044a8aaf69
commit 4034963bd7
6 changed files with 132 additions and 47 deletions

View File

@ -24,6 +24,7 @@ from heat.api.openstack.v1 import util
from heat.common import identifier
from heat.common import wsgi
from heat.common import template_format
from heat.common import environment_format
from heat.rpc import api as engine_api
from heat.rpc import client as rpc_client
from heat.common import urlfetch
@ -59,15 +60,17 @@ class InstantiationData(object):
self.data = data
@staticmethod
def format_parse(data, data_type, add_template_sections=True):
def format_parse(data, data_type):
"""
Parse the supplied data as JSON or YAML, raising the appropriate
exception if it is in the wrong format.
"""
try:
return template_format.parse(data,
add_template_sections)
if data_type == 'Environment':
return environment_format.parse(data)
else:
return template_format.parse(data)
except ValueError:
err_reason = _("%s not in valid format") % data_type
raise exc.HTTPBadRequest(err_reason)
@ -115,17 +118,9 @@ class InstantiationData(object):
env = env_data
else:
env = self.format_parse(env_data,
'Environment',
add_template_sections=False)
for field in env:
if field not in ('parameters', 'resource_registry'):
reason = _("%s not in valid in the environment") % field
raise exc.HTTPBadRequest(reason)
if not env.get(self.PARAM_USER_PARAMS):
env[self.PARAM_USER_PARAMS] = {}
'Environment')
environment_format.default_for_missing(env)
parameters = self.data.get(self.PARAM_USER_PARAMS, {})
env[self.PARAM_USER_PARAMS].update(parameters)
return env

View File

@ -0,0 +1,50 @@
# 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.common.template_format import yaml
SECTIONS = (PARAMETERS, RESOURCE_REGISTRY) = \
('parameters', 'resource_registry')
def parse(env_str):
'''
Takes a string and returns a dict containing the parsed structure.
This includes determination of whether the string is using the
JSON or YAML format.
'''
try:
env = yaml.safe_load(env_str)
except (yaml.scanner.ScannerError, yaml.parser.ParserError) as e:
raise ValueError(e)
else:
if env is None:
env = {}
for param in env:
if param not in SECTIONS:
raise ValueError('environment has wrong section "%s"' % param)
return env
def default_for_missing(env):
'''
Checks a parsed environment for missing sections.
'''
for param in SECTIONS:
if param not in env:
env[param] = {}

View File

@ -37,7 +37,7 @@ yaml.SafeLoader.add_constructor(u'tag:yaml.org,2002:timestamp',
_construct_yaml_str)
def parse(tmpl_str, add_template_sections=True):
def parse(tmpl_str):
'''
Takes a string and returns a dict containing the parsed structure.
This includes determination of whether the string is using the
@ -53,7 +53,7 @@ def parse(tmpl_str, add_template_sections=True):
else:
if tpl is None:
tpl = {}
if add_template_sections and u'heat_template_version' not in tpl:
if u'heat_template_version' not in tpl:
default_for_missing(tpl, u'HeatTemplateFormatVersion',
HEAT_VERSIONS)
return tpl

View File

@ -142,7 +142,8 @@ blarg: wibble
def test_parameters(self):
params = {'foo': 'bar', 'blarg': 'wibble'}
body = {'parameters': params}
body = {'parameters': params,
'resource_registry': {}}
data = stacks.InstantiationData(body)
self.assertEqual(data.environment(), body)
@ -156,7 +157,8 @@ blarg: wibble
body = {'parameters': {'foo': 'bar'},
'environment': {'parameters': {'blarg': 'wibble'}}}
expect = {'parameters': {'blarg': 'wibble',
'foo': 'bar'}}
'foo': 'bar'},
'resource_registry': {}}
data = stacks.InstantiationData(body)
self.assertEqual(data.environment(), expect)
@ -169,12 +171,14 @@ blarg: wibble
'tester': 'fail'}}}
expect = {'parameters': {'blarg': 'wibble',
'foo': 'bar',
'tester': 'Yes'}}
'tester': 'Yes'},
'resource_registry': {}}
data = stacks.InstantiationData(body)
self.assertEqual(data.environment(), expect)
def test_environment_bad_format(self):
body = {'environment': {'somethingnotsupported': {'blarg': 'wibble'}}}
env = {'somethingnotsupported': {'blarg': 'wibble'}}
body = {'environment': json.dumps(env)}
data = stacks.InstantiationData(body)
self.assertRaises(webob.exc.HTTPBadRequest, data.environment)
@ -182,7 +186,9 @@ blarg: wibble
env = {'foo': 'bar', 'blarg': 'wibble'}
body = {'not the environment': env}
data = stacks.InstantiationData(body)
self.assertEqual(data.environment(), {'parameters': {}})
self.assertEqual(data.environment(),
{'parameters': {},
'resource_registry': {}})
def test_args(self):
body = {
@ -443,7 +449,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'create_stack',
'args': {'stack_name': identity.stack_name,
'template': template,
'params': {'parameters': parameters},
'params': {'parameters': parameters,
'resource_registry': {}},
'files': {},
'args': {'timeout_mins': 30}},
'version': self.api_version},
@ -480,7 +487,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'create_stack',
'args': {'stack_name': identity.stack_name,
'template': template,
'params': {'parameters': parameters},
'params': {'parameters': parameters,
'resource_registry': {}},
'files': {'my.yaml': 'This is the file contents.'},
'args': {'timeout_mins': 30}},
'version': self.api_version},
@ -517,7 +525,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'create_stack',
'args': {'stack_name': stack_name,
'template': template,
'params': {'parameters': parameters},
'params': {'parameters': parameters,
'resource_registry': {}},
'files': {},
'args': {'timeout_mins': 30}},
'version': self.api_version},
@ -527,7 +536,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'create_stack',
'args': {'stack_name': stack_name,
'template': template,
'params': {'parameters': parameters},
'params': {'parameters': parameters,
'resource_registry': {}},
'files': {},
'args': {'timeout_mins': 30}},
'version': self.api_version},
@ -537,7 +547,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'create_stack',
'args': {'stack_name': stack_name,
'template': template,
'params': {'parameters': parameters},
'params': {'parameters': parameters,
'resource_registry': {}},
'files': {},
'args': {'timeout_mins': 30}},
'version': self.api_version},
@ -584,7 +595,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'create_stack',
'args': {'stack_name': stack_name,
'template': template,
'params': {'parameters': parameters},
'params': {'parameters': parameters,
'resource_registry': {}},
'files': {},
'args': {'timeout_mins': 30}},
'version': self.api_version},
@ -618,7 +630,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'create_stack',
'args': {'stack_name': stack_name,
'template': template,
'params': {'parameters': parameters},
'params': {'parameters': parameters,
'resource_registry': {}},
'files': {},
'args': {'timeout_mins': 30}},
'version': self.api_version},
@ -957,7 +970,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'update_stack',
'args': {'stack_identity': dict(identity),
'template': template,
'params': {'parameters': parameters},
'params': {'parameters': parameters,
'resource_registry': {}},
'files': {},
'args': {'timeout_mins': 30}},
'version': self.api_version},
@ -992,7 +1006,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
'method': 'update_stack',
'args': {'stack_identity': dict(identity),
'template': template,
'params': {u'parameters': parameters},
'params': {u'parameters': parameters,
u'resource_registry': {}},
'files': {},
'args': {'timeout_mins': 30}},
'version': self.api_version},

View File

@ -0,0 +1,43 @@
# 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.common import environment_format
from heat.tests import common
class YamlEnvironmentTest(common.HeatTestCase):
def test_minimal_yaml(self):
yaml1 = ''
yaml2 = '''
parameters: {}
resource_registry: {}
'''
tpl1 = environment_format.parse(yaml1)
environment_format.default_for_missing(tpl1)
tpl2 = environment_format.parse(yaml2)
self.assertEqual(tpl1, tpl2)
def test_wrong_sections(self):
env = '''
parameters: {}
resource_regis: {}
'''
self.assertRaises(ValueError, environment_format.parse, env)
def test_bad_yaml(self):
env = '''
parameters: }
'''
self.assertRaises(ValueError, environment_format.parse, env)

View File

@ -90,24 +90,6 @@ Outputs: {}
self.assertEqual(tpl1, tpl2)
class YamlEnvironmentTest(HeatTestCase):
def test_no_template_sections(self):
env = '''
parameters: {}
resource_registry: {}
'''
parsed_env = template_format.parse(env, add_template_sections=False)
self.assertEqual('parameters' in parsed_env, True)
self.assertEqual('resource_registry' in parsed_env, True)
self.assertEqual('Parameters' in parsed_env, False)
self.assertEqual('Mappings' in parsed_env, False)
self.assertEqual('Resources' in parsed_env, False)
self.assertEqual('Outputs' in parsed_env, False)
class JsonYamlResolvedCompareTest(HeatTestCase):
def setUp(self):