From b0585a6dadbeb8de76a8440d4b4d70eb17fd05d4 Mon Sep 17 00:00:00 2001 From: Angus Salkeld Date: Thu, 13 Jun 2013 13:59:08 +1000 Subject: [PATCH] Initial Environment class and test This implements the "resource-registry" and "parameters" section I am holding off on the "properties" section until we really know we need it. blueprint environments Change-Id: Ib6e9e5cd1c68c255dc048bdde21a6b3e1dc54243 --- heat/engine/environment.py | 99 ++++++++++++++++++++++++++++++++++ heat/tests/test_environment.py | 64 ++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 heat/engine/environment.py create mode 100644 heat/tests/test_environment.py diff --git a/heat/engine/environment.py b/heat/engine/environment.py new file mode 100644 index 00000000..1f6cd8d5 --- /dev/null +++ b/heat/engine/environment.py @@ -0,0 +1,99 @@ +# 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. + +# The environment should look like this: +# Note: the base_url, urls and files should be handled earlier +# and by the time it gets to the engine they are all just names. +# +# Use case 1: I want to use all the resource types from provider X +#resource_registry: +# "OS::*": "Dreamhost::*" +# # could also use a url like this (assuming they could all be +# # expressed in nested stacks) +# "OS::*": http://dreamhost.com/bla/resources-types/*" +# +# Use case 2: I want to use mostly the default resources except my +# custom one for a particular resource in the template. +#resource_registry: +# resources: +# my_db_server: +# "OS::DBInstance": file://~/all_my_cool_templates/db.yaml +# +# Use case 3: I always want to always map resource type X to Y +#resource_registry: +# "OS::Networking::FloatingIP": "OS::Nova::FloatingIP" +# "OS::Loadbalancer": file://~/all_my_cool_templates/lb.yaml +# +# Use case 4: I use custom resources a lot and want to shorten the +# url/path +#resource_registry: +# base_url: http://bla.foo/long/url/ +# resources: +# my_db_server: +# "OS::DBInstance": dbaas.yaml +# +# Use case 5: I want to put some common parameters in the environment +#parameters: +# KeyName: heat_key +# InstanceType: m1.large +# DBUsername: wp_admin +# LinuxDistribution: F17 + + +class Environment(object): + + def __init__(self, env=None): + """Create an Environment from a dict of varing format. + 1) old-school flat parameters + 2) or newer {resource_registry: bla, parameters: foo} + + :param env: the json environment + """ + if env is None: + env = {} + self.resource_registry = env.get('resource_registry', {}) + if 'resources' not in self.resource_registry: + self.resource_registry['resources'] = {} + if 'parameters' in env: + self.params = env['parameters'] + else: + self.params = dict((k, v) for (k, v) in env.iteritems() + if k != 'resource_registry') + + def get_resource_type(self, resource_type, resource_name): + """Get the specific resource type that the user wants to implement + 'resource_type'. + """ + impl = self.resource_registry['resources'].get(resource_name) + if impl and resource_type in impl: + return impl[resource_type] + + # handle: "OS::Compute::Server" -> "Rackspace::Compute::Server" + impl = self.resource_registry.get(resource_type) + if impl: + return impl + # handle: "OS::*" -> "Dreamhost::*" + for k, v in iter(self.resource_registry.items()): + if k.endswith('*'): + orig_prefix = k[:-1] + if resource_type.startswith(orig_prefix): + return v[:-1] + resource_type[len(orig_prefix):] + # no special handling, just return what we were given. + return resource_type + + def user_env_as_dict(self): + """Get the environment as a dict, ready for storing in the db.""" + return {'resource_registry': self.resource_registry, + 'parameters': self.params} diff --git a/heat/tests/test_environment.py b/heat/tests/test_environment.py new file mode 100644 index 00000000..a3363954 --- /dev/null +++ b/heat/tests/test_environment.py @@ -0,0 +1,64 @@ +# 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 testtools + +from heat.engine import environment + + +class EnvironmentTest(testtools.TestCase): + def test_load_old_parameters(self): + old = {u'a': u'ff', u'b': u'ss'} + expected = {u'parameters': old, + u'resource_registry': {u'resources': {}}} + env = environment.Environment(old) + self.assertEqual(expected, env.user_env_as_dict()) + + def test_load_new_env(self): + new_env = {u'parameters': {u'a': u'ff', u'b': u'ss'}, + u'resource_registry': {u'OS::Food': 'fruity'}} + env = environment.Environment(new_env) + self.assertEqual(new_env, env.user_env_as_dict()) + + def test_global_registry(self): + new_env = {u'parameters': {u'a': u'ff', u'b': u'ss'}, + u'resource_registry': {u'OS::*': 'CloudX::*'}} + env = environment.Environment(new_env) + self.assertEqual('CloudX::Compute::Server', + env.get_resource_type('OS::Compute::Server', + 'my_db_server')) + + def test_map_one_resource_type(self): + new_env = {u'parameters': {u'a': u'ff', u'b': u'ss'}, + u'resource_registry': {u'resources': + {u'my_db_server': + {u'OS::DBInstance': 'db.yaml'}}}} + env = environment.Environment(new_env) + self.assertEqual('db.yaml', + env.get_resource_type('OS::DBInstance', + 'my_db_server')) + self.assertEqual('OS::Compute::Server', + env.get_resource_type('OS::Compute::Server', + 'my_other_server')) + + def test_map_all_resources_of_type(self): + new_env = {u'parameters': {u'a': u'ff', u'b': u'ss'}, + u'resource_registry': + {u'OS::Networking::FloatingIP': 'OS::Nova::FloatingIP', + u'OS::Loadbalancer': 'lb.yaml'}} + env = environment.Environment(new_env) + self.assertEqual('OS::Nova::FloatingIP', + env.get_resource_type('OS::Networking::FloatingIP', + 'my_fip')) -- 2.45.2