diff --git a/doc/docbkx/api-ref/src/wadls/heat-api/src/heat-api-1.0.wadl b/doc/docbkx/api-ref/src/wadls/heat-api/src/heat-api-1.0.wadl index 146ed7a7c4..be9340fee5 100644 --- a/doc/docbkx/api-ref/src/wadls/heat-api/src/heat-api-1.0.wadl +++ b/doc/docbkx/api-ref/src/wadls/heat-api/src/heat-api-1.0.wadl @@ -142,6 +142,12 @@
+ ++ A JSON envionment for the stack. +
User-defined parameter names to pass to the template. @@ -226,6 +232,12 @@
+ A JSON envionment for the stack. +
User-defined parameter names to pass to the template. diff --git a/heat/api/openstack/v1/stacks.py b/heat/api/openstack/v1/stacks.py index 9dcec53eb1..6e7f897def 100644 --- a/heat/api/openstack/v1/stacks.py +++ b/heat/api/openstack/v1/stacks.py @@ -44,11 +44,13 @@ class InstantiationData(object): PARAM_TEMPLATE, PARAM_TEMPLATE_URL, PARAM_USER_PARAMS, + PARAM_ENVIRONMENT, ) = ( 'stack_name', 'template', 'template_url', 'parameters', + 'environment', ) def __init__(self, data): @@ -99,11 +101,33 @@ class InstantiationData(object): return self.format_parse(template_data, 'Template') - def user_params(self): + def environment(self): """ - Get the user-supplied parameters for the stack in JSON format. + Get the user-supplied environment for the stack in YAML format. + If the user supplied Parameters then merge these into the + environment global options. """ - return self.data.get(self.PARAM_USER_PARAMS, {}) + env = {} + if self.PARAM_ENVIRONMENT in self.data: + env_data = self.data[self.PARAM_ENVIRONMENT] + if isinstance(env_data, dict): + 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 self.PARAM_USER_PARAMS not in env: + env[self.PARAM_USER_PARAMS] = {} + + parameters = self.data.get(self.PARAM_USER_PARAMS, {}) + env[self.PARAM_USER_PARAMS].update(parameters) + return env def args(self): """ @@ -180,7 +204,7 @@ class StackController(object): result = self.engine.create_stack(req.context, data.stack_name(), data.template(), - data.user_params(), + data.environment(), data.args()) except rpc_common.RemoteError as ex: return util.remote_error(ex) @@ -255,7 +279,7 @@ class StackController(object): res = self.engine.update_stack(req.context, identity, data.template(), - data.user_params(), + data.environment(), data.args()) except rpc_common.RemoteError as ex: return util.remote_error(ex) diff --git a/heat/tests/test_api_openstack_v1.py b/heat/tests/test_api_openstack_v1.py index b1e35b033a..4c4694c2ca 100644 --- a/heat/tests/test_api_openstack_v1.py +++ b/heat/tests/test_api_openstack_v1.py @@ -114,21 +114,54 @@ blarg: wibble data = stacks.InstantiationData(body) self.assertRaises(webob.exc.HTTPBadRequest, data.template) - def test_user_params(self): + def test_parameters(self): params = {'foo': 'bar', 'blarg': 'wibble'} body = {'parameters': params} data = stacks.InstantiationData(body) - self.assertEqual(data.user_params(), params) + self.assertEqual(data.environment(), body) - def test_user_params_missing(self): - params = {'foo': 'bar', 'blarg': 'wibble'} - body = {'not the parameters': params} + def test_environment_only_params(self): + env = {'parameters': {'foo': 'bar', 'blarg': 'wibble'}} + body = {'environment': env} data = stacks.InstantiationData(body) - self.assertEqual(data.user_params(), {}) + self.assertEqual(data.environment(), env) + + def test_environment_and_parameters(self): + body = {'parameters': {'foo': 'bar'}, + 'environment': {'parameters': {'blarg': 'wibble'}}} + expect = {'parameters': {'blarg': 'wibble', + 'foo': 'bar'}} + data = stacks.InstantiationData(body) + self.assertEqual(data.environment(), expect) + + def test_parameters_override_environment(self): + # This tests that the cli parameters will override + # any parameters in the environment. + body = {'parameters': {'foo': 'bar', + 'tester': 'Yes'}, + 'environment': {'parameters': {'blarg': 'wibble', + 'tester': 'fail'}}} + expect = {'parameters': {'blarg': 'wibble', + 'foo': 'bar', + 'tester': 'Yes'}} + data = stacks.InstantiationData(body) + self.assertEqual(data.environment(), expect) + + def test_environment_bad_format(self): + body = {'environment': {'somethingnotsupported': {'blarg': 'wibble'}}} + data = stacks.InstantiationData(body) + self.assertRaises(webob.exc.HTTPBadRequest, data.environment) + + def test_environment_missing(self): + env = {'foo': 'bar', 'blarg': 'wibble'} + body = {'not the environment': env} + data = stacks.InstantiationData(body) + self.assertEqual(data.environment(), {'parameters': {}}) def test_args(self): body = { 'parameters': {}, + 'environment': {}, 'stack_name': 'foo', 'template': {}, 'template_url': 'http://example.com/', @@ -324,7 +357,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'create_stack', 'args': {'stack_name': identity.stack_name, 'template': template, - 'params': parameters, + 'params': {'parameters': parameters}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndReturn(dict(identity)) @@ -358,7 +391,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'create_stack', 'args': {'stack_name': stack_name, 'template': template, - 'params': parameters, + 'params': {'parameters': parameters}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("AttributeError")) @@ -367,7 +400,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'create_stack', 'args': {'stack_name': stack_name, 'template': template, - 'params': parameters, + 'params': {'parameters': parameters}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("UnknownUserParameter")) @@ -401,7 +434,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'create_stack', 'args': {'stack_name': stack_name, 'template': template, - 'params': parameters, + 'params': {'parameters': parameters}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("StackExists")) @@ -430,7 +463,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'create_stack', 'args': {'stack_name': stack_name, 'template': template, - 'params': parameters, + 'params': {'parameters': parameters}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError( @@ -719,7 +752,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'update_stack', 'args': {'stack_identity': dict(identity), 'template': template, - 'params': parameters, + 'params': {'parameters': parameters}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndReturn(dict(identity)) @@ -751,7 +784,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'method': 'update_stack', 'args': {'stack_identity': dict(identity), 'template': template, - 'params': parameters, + 'params': {u'parameters': parameters}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("StackNotFound"))