From b487adbf8b52485bd804a3713235453bdbcf4cd7 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Tue, 27 Nov 2012 16:15:56 +0100 Subject: [PATCH] Load resources dynamically Automatically load all resources as "plugins" when importing the package heat.engine.resources, instead of having to list them explicitly. Change-Id: I9d11ab9a5b1dd21bc5f9c2f0aad95c035a9c9aa0 Signed-off-by: Zane Bitter --- heat/engine/resource.py | 19 ++++++++- heat/engine/resources/__init__.py | 34 ++++++++++++++++ heat/engine/resources/register.py | 67 ------------------------------- heat/engine/service.py | 1 + 4 files changed, 52 insertions(+), 69 deletions(-) delete mode 100644 heat/engine/resources/register.py diff --git a/heat/engine/resource.py b/heat/engine/resource.py index 8d0cff129c..6e07f02083 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -28,6 +28,22 @@ from heat.openstack.common import log as logging logger = logging.getLogger(__name__) +_resource_classes = {} + + +def get_class(resource_type): + return _resource_classes.get(resource_type) + + +def _register_class(resource_type, resource_class): + logger.info(_('Registering resource type %s') % resource_type) + if resource_type in _resource_classes: + logger.warning(_('Replacing existing resource type %s') % + resource_type) + + _resource_classes[resource_type] = resource_class + + class Metadata(object): ''' A descriptor for accessing the metadata of a resource while ensuring the @@ -86,8 +102,7 @@ class Resource(object): return super(Resource, cls).__new__(cls) # Select the correct subclass to instantiate - from heat.engine.resources import register - ResourceClass = register.get_class(json['Type']) or GenericResource + ResourceClass = get_class(json['Type']) or GenericResource return ResourceClass(name, json, stack) def __init__(self, name, json_snippet, stack): diff --git a/heat/engine/resources/__init__.py b/heat/engine/resources/__init__.py index e8e4035941..087ac64e2a 100644 --- a/heat/engine/resources/__init__.py +++ b/heat/engine/resources/__init__.py @@ -12,3 +12,37 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + + +def _register_resources(type_pairs): + from heat.engine import resource + + for res_name, res_class in type_pairs: + resource._register_class(res_name, res_class) + + +def _get_module_resources(module): + if callable(getattr(module, 'resource_mapping', None)): + try: + return module.resource_mapping().iteritems() + except Exception as ex: + logger.error(_('Failed to load resources from %s') % str(module)) + else: + return [] + + +def _register_modules(modules): + import itertools + + resource_lists = (_get_module_resources(m) for m in modules) + _register_resources(itertools.chain.from_iterable(resource_lists)) + + +def _initialise(): + import sys + from heat.common import plugin_loader + + _register_modules(plugin_loader.load_modules(sys.modules[__name__])) + + +_initialise() diff --git a/heat/engine/resources/register.py b/heat/engine/resources/register.py deleted file mode 100644 index a61d657add..0000000000 --- a/heat/engine/resources/register.py +++ /dev/null @@ -1,67 +0,0 @@ -# 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. - -""" -Register of resource types and their mapping to Resource classes. -""" - -from heat.engine.resources import autoscaling -from heat.engine.resources import cloud_watch -from heat.engine.resources import dbinstance -from heat.engine.resources import eip -from heat.engine.resources import instance -from heat.engine.resources import loadbalancer -from heat.engine.resources import s3 -from heat.engine.resources import security_group -from heat.engine.resources import stack -from heat.engine.resources import user -from heat.engine.resources import volume -from heat.engine.resources import wait_condition -from heat.engine.resources.quantum import floatingip -from heat.engine.resources.quantum import net -from heat.engine.resources.quantum import port -from heat.engine.resources.quantum import router -from heat.engine.resources.quantum import subnet - -from heat.openstack.common import log as logging - -logger = logging.getLogger('heat.engine.resources.register') - - -_modules = [ - autoscaling, cloud_watch, dbinstance, eip, instance, loadbalancer, s3, - security_group, stack, user, volume, wait_condition, floatingip, net, port, - router, subnet, -] - -_resource_classes = {} - - -def get_class(resource_type): - return _resource_classes.get(resource_type) - - -def _register_class(resource_type, resource_class): - logger.info(_('Registering resource type %s') % resource_type) - if resource_type in _resource_classes: - logger.warning(_('Replacing existing resource type %s') % - resource_type) - - _resource_classes[resource_type] = resource_class - - -for m in _modules: - for res_type, res_class in m.resource_mapping().items(): - _register_class(res_type, res_class) diff --git a/heat/engine/service.py b/heat/engine/service.py index 8c844af97d..d4256b7553 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -22,6 +22,7 @@ from heat.engine import api from heat.engine.event import Event from heat.engine import identifier from heat.engine import parser +from heat.engine import resources from heat.engine import watchrule from heat.openstack.common import cfg