--- /dev/null
+# 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.
+
+'''
+Helper utilities related to the AWS API implementations
+'''
+
+import re
+
+
+def format_response(action, response):
+ """
+ Format response from engine into API format
+ """
+ return {'%sResponse' % action: {'%sResult' % action: response}}
+
+
+def extract_user_params(params):
+ """
+ Extract a dictionary of user input parameters for the stack
+
+ In the AWS API parameters, each user parameter appears as two key-value
+ pairs with keys of the form below:
+
+ Parameters.member.1.ParameterKey
+ Parameters.member.1.ParameterValue
+
+ We reformat this into a normal dict here to match the heat
+ engine API expected format
+
+ Note this implemented outside of "create" as it will also be
+ used by update (and EstimateTemplateCost if appropriate..)
+ """
+ # Define the AWS key format to extract
+ PARAM_KEYS = (
+ PARAM_USER_KEY_re,
+ PARAM_USER_VALUE_fmt,
+ ) = (
+ re.compile(r'Parameters\.member\.(.*?)\.ParameterKey$'),
+ 'Parameters.member.%s.ParameterValue',
+ )
+
+ def get_param_pairs():
+ for k in params:
+ keymatch = PARAM_USER_KEY_re.match(k)
+ if keymatch:
+ key = params[k]
+ v = PARAM_USER_VALUE_fmt % 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())
+
+
+def reformat_dict_keys(keymap={}, inputdict={}):
+ '''
+ Utility function for mapping one dict format to another
+ '''
+ result = {}
+ for key in keymap:
+ result[keymap[key]] = inputdict[key]
+ return result
import os
import socket
import sys
-import re
import urlparse
import webob
from heat.api.aws import exception
+from heat.api.aws import utils as api_utils
from heat.common import wsgi
from heat.common import config
from heat.common import context
str(resp['StackId'])])
return resp
- def _format_response(self, action, response):
- """
- Format response from engine into API format
- """
- return {'%sResponse' % action: {'%sResult' % action: response}}
-
- @staticmethod
- def _extract_user_params(params):
- """
- Extract a dictionary of user input parameters for the stack
-
- In the AWS API parameters, each user parameter appears as two key-value
- pairs with keys of the form below:
-
- Parameters.member.1.ParameterKey
- Parameters.member.1.ParameterValue
-
- We reformat this into a normal dict here to match the heat
- engine API expected format
-
- Note this implemented outside of "create" as it will also be
- used by update (and EstimateTemplateCost if appropriate..)
- """
- # Define the AWS key format to extract
- PARAM_KEYS = (
- PARAM_USER_KEY_re,
- PARAM_USER_VALUE_fmt,
- ) = (
- re.compile(r'Parameters\.member\.(.*?)\.ParameterKey$'),
- 'Parameters.member.%s.ParameterValue',
- )
-
- def get_param_pairs():
- for k in params:
- keymatch = PARAM_USER_KEY_re.match(k)
- if keymatch:
- key = params[k]
- v = PARAM_USER_VALUE_fmt % 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())
-
- @staticmethod
- def _reformat_dict_keys(keymap={}, inputdict={}):
- '''
- Utility function for mapping one dict format to another
- '''
- result = {}
- for key in keymap:
- result[keymap[key]] = inputdict[key]
- return result
-
def list(self, req):
"""
Implements ListStacks API action
engine_api.STACK_TMPL_DESCRIPTION: 'TemplateDescription',
}
- result = self._reformat_dict_keys(keymap, s)
+ result = api_utils.reformat_dict_keys(keymap, s)
# AWS docs indicate DeletionTime is ommitted for current stacks
# This is still TODO in the engine, we don't keep data for
res = {'StackSummaries': [format_stack_summary(s)
for s in stack_list['stacks']]}
- return self._format_response('ListStacks', res)
+ return api_utils.format_response('ListStacks', res)
def describe(self, req):
"""
engine_api.OUTPUT_VALUE: 'OutputValue',
}
- return self._reformat_dict_keys(keymap, o)
+ return api_utils.reformat_dict_keys(keymap, o)
def format_stack(s):
"""
engine_api.STACK_TIMEOUT: 'TimeoutInMinutes',
}
- result = self._reformat_dict_keys(keymap, s)
+ result = api_utils.reformat_dict_keys(keymap, s)
# Reformat outputs, these are handled separately as they are
# only present in the engine output for a completely created
res = {'Stacks': [format_stack(s) for s in stack_list['stacks']]}
- return self._format_response('DescribeStacks', res)
+ return api_utils.format_response('DescribeStacks', res)
def _get_template(self, req):
"""
con = req.context
# Extract the stack input parameters
- stack_parms = self._extract_user_params(req.params)
+ stack_parms = api_utils.extract_user_params(req.params)
# Extract any additional arguments ("Request Parameters")
create_args = extract_args(req.params)
except rpc_common.RemoteError as ex:
return exception.map_remote_error(ex)
- return self._format_response(action, self._stackid_addprefix(res))
+ return api_utils.format_response(action, self._stackid_addprefix(res))
def get_template(self, req):
"""
msg = _('stack not not found')
return exception.HeatInvalidParameterValueError(detail=msg)
- return self._format_response('GetTemplate', {'TemplateBody': templ})
+ return api_utils.format_response('GetTemplate',
+ {'TemplateBody': templ})
def estimate_template_cost(self, req):
"""
Implements the EstimateTemplateCost API action
Get the estimated monthly cost of a template
"""
- return self._format_response('EstimateTemplateCost',
+ return api_utils.format_response('EstimateTemplateCost',
{'Url': 'http://en.wikipedia.org/wiki/Gratis'})
def validate_template(self, req):
return exception.map_remote_error(ex)
if res is None:
- return self._format_response('DeleteStack', '')
+ return api_utils.format_response('DeleteStack', '')
else:
- return self._format_response('DeleteStack', res['Error'])
+ return api_utils.format_response('DeleteStack', res['Error'])
def events_list(self, req):
"""
engine_api.EVENT_TIMESTAMP: 'Timestamp',
}
- result = self._reformat_dict_keys(keymap, e)
+ result = api_utils.reformat_dict_keys(keymap, e)
return self._stackid_addprefix(result)
result = [format_stack_event(e) for e in events]
- return self._format_response('DescribeStackEvents',
+ return api_utils.format_response('DescribeStackEvents',
{'StackEvents': result})
def describe_stack_resource(self, req):
engine_api.RES_STACK_NAME: 'StackName',
}
- result = self._reformat_dict_keys(keymap, r)
+ result = api_utils.reformat_dict_keys(keymap, r)
return self._stackid_addprefix(result)
result = format_resource_detail(resource_details)
- return self._format_response('DescribeStackResource',
+ return api_utils.format_response('DescribeStackResource',
{'StackResourceDetail': result})
def describe_stack_resources(self, req):
engine_api.RES_UPDATED_TIME: 'Timestamp',
}
- result = self._reformat_dict_keys(keymap, r)
+ result = api_utils.reformat_dict_keys(keymap, r)
return self._stackid_addprefix(result)
result = [format_stack_resource(r) for r in resources]
- return self._format_response('DescribeStackResources',
+ return api_utils.format_response('DescribeStackResources',
{'StackResources': result})
def list_stack_resources(self, req):
engine_api.RES_TYPE: 'ResourceType',
}
- return self._reformat_dict_keys(keymap, r)
+ return api_utils.reformat_dict_keys(keymap, r)
con = req.context
summaries = [format_resource_summary(r) for r in resources]
- return self._format_response('ListStackResources',
+ return api_utils.format_response('ListStackResources',
{'StackResourceSummaries': summaries})
--- /dev/null
+# 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.
+
+
+import sys
+import socket
+import nose
+import json
+import unittest
+from nose.plugins.attrib import attr
+
+import re
+from heat.api.aws import utils as api_utils
+
+
+@attr(tag=['unit', 'api-aws', 'AWSCommon'])
+@attr(speed='fast')
+class AWSCommon(unittest.TestCase):
+ '''
+ Tests the api/aws common componenents
+ '''
+ # The tests
+ def test_format_response(self):
+ response = api_utils.format_response("Foo", "Bar")
+ expected = {'FooResponse': {'FooResult': 'Bar'}}
+ self.assert_(response == expected)
+
+ 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 = api_utils.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 = api_utils.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 = api_utils.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 = api_utils.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 = api_utils.extract_user_params(p)
+ self.assertFalse(params)
+
+ def test_reformat_dict_keys(self):
+ keymap = {"foo": "bar"}
+ data = {"foo": 123}
+ expected = {"bar": 123}
+ result = api_utils.reformat_dict_keys(keymap, data)
+ self.assertEqual(result, expected)
+
+ def setUp(self):
+ print "setup complete"
+
+ def tearDown(self):
+ print "teardown complete"
+
+
+if __name__ == '__main__':
+ sys.argv.append(__file__)
+ nose.main()
return req
# The tests
- def test_format_response(self):
- response = self.controller._format_response("Foo", "Bar")
- expected = {'FooResponse': {'FooResult': 'Bar'}}
- self.assert_(response == expected)
-
def test_stackid_addprefix(self):
# Stub socket.gethostname so it returns "ahostname"
'StackId': 'ahostname:8000:stack/Foo/123'}
self.assert_(response == expected)
- 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 = self.controller._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 = self.controller._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 = self.controller._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 = self.controller._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 = self.controller._extract_user_params(p)
- self.assertFalse(params)
-
- def test_reformat_dict_keys(self):
- keymap = {"foo": "bar"}
- data = {"foo": 123}
- expected = {"bar": 123}
- result = self.controller._reformat_dict_keys(keymap, data)
- self.assertEqual(result, expected)
-
def test_list(self):
# Format a dummy GET request to pass into the WSGI handler
params = {'Action': 'ListStacks'}