Move parsing of parameters out of template parser

The format of the params received by the manager is a property of the Heat
API protocol, not of the template, so it makes sense not to have the parser
extracting the template parameter data from them. This simplifies the
implementation of #123 (Nested Stacks).

Change-Id: I8eaf50caf79f69359cbc8ee1f0193c08d7944d1c
Signed-off-by: Zane Bitter <zbitter@redhat.com>
This commit is contained in:
Zane Bitter 2012-06-17 16:05:57 +02:00
parent 892b99bff4
commit 582b8b29cb
4 changed files with 87 additions and 26 deletions

View File

@ -20,6 +20,7 @@ import logging
import webob
import json
import urlparse
import re
import httplib
import eventlet
@ -39,6 +40,25 @@ from novaclient.exceptions import AuthorizationFailure
logger = logging.getLogger('heat.engine.manager')
greenpool = eventlet.GreenPool()
_param_key = re.compile(r'Parameters\.member\.(.*?)\.ParameterKey$')
def _extract_user_params(params):
def get_param_pairs():
for k in params:
keymatch = _param_key.match(k)
if keymatch:
key = params[k]
v = 'Parameters.member.%s.ParameterValue' % keymatch.group(1)
try:
value = params[v]
except KeyError:
logger.error('Could not apply parameter %s' % key)
yield (key, value)
return dict(get_param_pairs())
class EngineManager(manager.Manager):
"""
@ -126,7 +146,7 @@ class EngineManager(manager.Manager):
for s in stacks:
ps = parser.Stack(context, s.name,
s.raw_template.parsed_template.template,
s.id, params)
s.id, _extract_user_params(params))
mem = {}
mem['StackId'] = s.id
mem['StackName'] = s.name
@ -152,7 +172,7 @@ class EngineManager(manager.Manager):
if s:
ps = parser.Stack(context, s.name,
s.raw_template.parsed_template.template,
s.id, params)
s.id, _extract_user_params(params))
mem = {}
mem['StackId'] = s.id
mem['StackName'] = s.name
@ -193,12 +213,14 @@ class EngineManager(manager.Manager):
if db_api.stack_get_by_name(None, stack_name):
return {'Error': 'Stack already exists with that name.'}
user_params = _extract_user_params(params)
metadata_server = config.FLAGS.heat_metadata_server_url
# We don't want to reset the stack template, so we are making
# an instance just for validation.
template_copy = deepcopy(template)
stack_validator = parser.Stack(context, stack_name,
template_copy, 0, params,
template_copy, 0,
user_params,
metadata_server=metadata_server)
response = stack_validator.validate()
stack_validator = None
@ -207,7 +229,7 @@ class EngineManager(manager.Manager):
response['ValidateTemplateResult']['Description']:
return response
stack = parser.Stack(context, stack_name, template, 0, params,
stack = parser.Stack(context, stack_name, template, 0, user_params,
metadata_server=metadata_server)
rt = {}
rt['template'] = template
@ -253,7 +275,8 @@ class EngineManager(manager.Manager):
return webob.exc.HTTPBadRequest(explanation=msg)
try:
s = parser.Stack(context, 'validate', template, 0, params)
s = parser.Stack(context, 'validate', template, 0,
_extract_user_params(params))
except KeyError as ex:
res = ('A Fn::FindInMap operation referenced '
'a non-existent map [%s]' % str(ex))
@ -298,7 +321,7 @@ class EngineManager(manager.Manager):
ps = parser.Stack(context, st.name,
st.raw_template.parsed_template.template,
st.id, params)
st.id, _extract_user_params(params))
greenpool.spawn_n(ps.delete)
return None

View File

@ -68,7 +68,7 @@ class Stack(object):
# user Parameters
if parms is not None:
self._apply_user_parameters(parms)
self.parms.update(parms)
self.resources = dict((name,
Resource(name, data, self))
@ -295,19 +295,6 @@ class Stack(object):
# TODO(asalkeld) if any of this fails we Should
# restart the whole stack
def _apply_user_parameters(self, parms):
for p in parms:
if 'Parameters.member.' in p and 'ParameterKey' in p:
s = p.split('.')
try:
key_name = 'Parameters.member.%s.ParameterKey' % s[2]
value_name = 'Parameters.member.%s.ParameterValue' % s[2]
logger.debug('applying user parameter %s=%s' %
(key_name, value_name))
self.parms[parms[key_name]] = parms[value_name]
except Exception:
logger.error('Could not apply parameter %s' % p)
def parameter_get(self, key):
if not key in self.parms:
raise exception.UserParameterMissing(key=key)

View File

@ -0,0 +1,55 @@
import nose
import unittest
from nose.plugins.attrib import attr
import heat.engine.manager as manager
@attr(tag=['unit', 'manager'])
@attr(speed='fast')
class managerTest(unittest.TestCase):
def test_params_extract(self):
p = {'Parameters.member.Foo.ParameterKey': 'foo',
'Parameters.member.Foo.ParameterValue': 'bar',
'Parameters.member.Blarg.ParameterKey': 'blarg',
'Parameters.member.Blarg.ParameterValue': 'wibble'}
params = manager._extract_user_params(p)
self.assertEqual(len(params), 2)
self.assertTrue('foo' in params)
self.assertEqual(params['foo'], 'bar')
self.assertTrue('blarg' in params)
self.assertEqual(params['blarg'], 'wibble')
def test_params_extract_dots(self):
p = {'Parameters.member.Foo.Bar.ParameterKey': 'foo',
'Parameters.member.Foo.Bar.ParameterValue': 'bar',
'Parameters.member.Foo.Baz.ParameterKey': 'blarg',
'Parameters.member.Foo.Baz.ParameterValue': 'wibble'}
params = manager._extract_user_params(p)
self.assertEqual(len(params), 2)
self.assertTrue('foo' in params)
self.assertEqual(params['foo'], 'bar')
self.assertTrue('blarg' in params)
self.assertEqual(params['blarg'], 'wibble')
def test_params_extract_garbage(self):
p = {'Parameters.member.Foo.Bar.ParameterKey': 'foo',
'Parameters.member.Foo.Bar.ParameterValue': 'bar',
'Foo.Baz.ParameterKey': 'blarg',
'Foo.Baz.ParameterValue': 'wibble'}
params = manager._extract_user_params(p)
self.assertEqual(len(params), 1)
self.assertTrue('foo' in params)
self.assertEqual(params['foo'], 'bar')
def test_params_extract_garbage_prefix(self):
p = {'prefixParameters.member.Foo.Bar.ParameterKey': 'foo',
'Parameters.member.Foo.Bar.ParameterValue': 'bar'}
params = manager._extract_user_params(p)
self.assertFalse(params)
def test_params_extract_garbage_suffix(self):
p = {'Parameters.member.Foo.Bar.ParameterKeysuffix': 'foo',
'Parameters.member.Foo.Bar.ParameterValue': 'bar'}
params = manager._extract_user_params(p)
self.assertFalse(params)

View File

@ -34,11 +34,9 @@ class instancesTest(unittest.TestCase):
t = json.loads(f.read())
f.close()
params = {}
parameters = {}
params['KeyStoneCreds'] = None
t['Parameters']['KeyName']['Value'] = 'test'
stack = parser.Stack(None, 'test_stack', t, 0, params)
stack = parser.Stack(None, 'test_stack', t, 0)
self.m.StubOutWithMock(db_api, 'resource_get_by_name_and_stack')
db_api.resource_get_by_name_and_stack(None, 'test_resource_name',
@ -82,11 +80,9 @@ class instancesTest(unittest.TestCase):
t = json.loads(f.read())
f.close()
params = {}
parameters = {}
params['KeyStoneCreds'] = None
t['Parameters']['KeyName']['Value'] = 'test'
stack = parser.Stack(None, 'test_stack', t, 0, params)
stack = parser.Stack(None, 'test_stack', t, 0)
self.m.StubOutWithMock(db_api, 'resource_get_by_name_and_stack')
db_api.resource_get_by_name_and_stack(None, 'test_resource_name',