]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Connect metadata server to the engine via RPC
authorTomas Sedovic <tomas@sedovic.cz>
Fri, 4 May 2012 13:16:11 +0000 (15:16 +0200)
committerTomas Sedovic <tomas@sedovic.cz>
Sat, 5 May 2012 00:22:42 +0000 (02:22 +0200)
Similarly to the way heat-api works, the engine does all the heavy lifting (db
access, etc.) while the metadata server provides the API layer that communicates
with the engine.

Signed-off-by: Tomas Sedovic <tomas@sedovic.cz>
bin/heat-metadata
heat/common/config.py
heat/db/sqlalchemy/models.py
heat/engine/manager.py
heat/metadata/api/v1/metadata.py

index f95334e22bb41169858568eaefdc6ffdd8a5f88b..f58dcad2d50c52e4110d3c0fd5c602f3f4c36133 100755 (executable)
@@ -34,6 +34,7 @@ if os.path.exists(os.path.join(possible_topdir, 'heat', '__init__.py')):
 gettext.install('heat', unicode=1)
 
 import logging
+from heat import rpc
 from heat.common import config
 from heat.common import wsgi
 from paste import httpserver
@@ -45,6 +46,7 @@ if __name__ == '__main__':
         conf = config.HeatMetadataConfigOpts()
         conf()
         config.FLAGS = conf
+        rpc.configure(conf)
         config.setup_logging(conf)
 
         app = config.load_paste_app(conf)
index 3021736151abf01dc83fc1737d38029957b88256..be14f9d765788484044086639d9c4f389de032ae 100644 (file)
@@ -148,7 +148,9 @@ class HeatMetadataConfigOpts(cfg.CommonConfigOpts):
             version='%%prog %s' % version.version_string(),
             default_config_files=default_config_files,
             **kwargs)
-        self.register_cli_opts([cfg.IntOpt('bind_port', default=8000)])
+        opts = [cfg.IntOpt('bind_port', default=8000)]
+        opts.extend(rpc_opts)
+        self.register_cli_opts(opts)
 
 
 class HeatEngineConfigOpts(cfg.CommonConfigOpts):
index bd55fcbf46a873f86fd55a831192521bf84a579d..e7730aac9006a68fb891dde80bc1b5c6040be3b4 100644 (file)
@@ -89,6 +89,16 @@ class HeatBase(object):
         for k, v in values.iteritems():
             setattr(self, k, v)
 
+    def update_and_save(self, values, session=None):
+        if not session:
+            session = Session.object_session(self)
+            if not session:
+                session = get_session()
+        session.begin()
+        for k, v in values.iteritems():
+            setattr(self, k, v)
+        session.commit()
+
     def iteritems(self):
         """Make the model object behave like a dict.
 
index 262356d2fa54fbcef4105abb7c0ee4f1813099a1..ece2c59cf475fccc6dc6a84af7c8b9f5cb86feac 100644 (file)
@@ -15,6 +15,7 @@
 
 
 import contextlib
+from copy import deepcopy
 import functools
 import os
 import socket
@@ -214,3 +215,61 @@ class EngineManager(manager.Manager):
                     'ResourceStatus': e.name}
 
         return {'events': [parse_event(e) for e in events]}
+
+    def metadata_list_stacks(self, context):
+        """
+        Return the names of the stacks registered with Heat.
+        """
+        stacks = db_api.stack_get_all(None)
+        return [s.name for s in stacks]
+
+    def metadata_list_resources(self, context, stack_name):
+        """
+        Return the resource IDs of the given stack.
+        """
+        stack = db_api.stack_get(None, stack_name)
+        if stack:
+            return [r.name for r in stack.resources]
+        else:
+            return None
+
+    def metadata_get_resource(self, context, stack_name, resource_id):
+        """
+        Get the metadata for the given resource.
+        """
+        s = db_api.stack_get(None, stack_name)
+        if not s:
+            return ['stack', None]
+
+        raw_template = db_api.raw_template_get(None, s.raw_template_id)
+        template = raw_template.template
+
+        if not resource_id in template.get('Resources', {}):
+            return ['resource', None]
+
+        metadata = template['Resources'][resource_id].get('Metadata', {})
+        return [None, metadata]
+
+    def metadata_update(self, context, stack_name, resource_id, metadata):
+        """
+        Update the metadata for the given resource.
+        """
+        s = db_api.stack_get(None, stack_name)
+        if not s:
+            return ['stack', None]
+
+        raw_template = db_api.raw_template_get(None, s.raw_template_id)
+
+        if not resource_id in raw_template.template.get('Resources', {}):
+            return ['resource', None]
+
+        # TODO(shadower) deep copy of the template is required here. Without it,
+        # we directly modify raw_template.template by assigning the new
+        # metadata. When we then call raw_template.update_and_save, the session
+        # will detect no changes and thus not update the database.
+        # Just updating the values and calling save didn't seem to work either.
+        # There's probably an idiomatic way I'm missing right now.
+        t = deepcopy(raw_template.template)
+        t['Resources'][resource_id]['Metadata'] = metadata
+        raw_template.update_and_save({'template': t})
+        return [None, metadata]
index 8c114a153c9e2db64f3bc1cf503f1321c8d8b126..77fc7ad52dbc06abee97e5b781399a68488ac96b 100644 (file)
@@ -19,9 +19,11 @@ import json
 from webob.exc import Response
 
 from heat.common import wsgi
+from heat import context
 from heat.metadata import db as db_api
 from heat.metadata.db import (ConflictError, StackNotFoundError,
                               ResourceNotFoundError)
+from heat import rpc
 
 
 def json_response(http_status, data):
@@ -47,39 +49,46 @@ class MetadataController:
         }
 
     def list_stacks(self, req):
-        return db_api.list_stacks()
+        con = context.get_admin_context()
+        resp = rpc.call(con, 'engine',
+                              {'method': 'metadata_list_stacks'})
+        return resp
 
     def list_resources(self, req, stack_name):
-        try:
-            resources = db_api.list_resources(stack_name)
-        except StackNotFoundError:
+        con = context.get_admin_context()
+        resources = rpc.call(con, 'engine',
+                             {'method': 'metadata_list_resources',
+                              'args': {'stack_name': stack_name}})
+        if resources:
+            return resources
+        else:
             return json_error(404, 'The stack "%s" does not exist.' % stack_name)
-        return resources
 
     def get_resource(self, req, stack_name, resource_id):
-        try:
-            resource = db_api.get_resource(stack_name, resource_id)
-        except StackNotFoundError:
-            return json_error(404, 'The stack "%s" does not exist.' % stack_name)
-        except ResourceNotFoundError:
-            return json_error(404, 'The resource "%s" does not exist.' % resource_id)
-        return resource
-
-    def create_stack(self, req, body, stack_name):
-        try:
-            stack = db_api.create_stack(stack_name, body)
-        except ConflictError:
-            return json_error(409, 'The stack "%s" already exists.' % stack_name)
-        return json_response(201, stack)
+        con = context.get_admin_context()
+        [error, metadata] = rpc.call(con, 'engine',
+                                     {'method': 'metadata_get_resource',
+                                      'args': {'stack_name': stack_name,
+                                               'resource_id': resource_id}})
+        if error:
+            if error == 'stack':
+                return json_error(404, 'The stack "%s" does not exist.' % stack_name)
+            else:
+                return json_error(404, 'The resource "%s" does not exist.' % resource_id)
+        return metadata
 
     def update_metadata(self, req, body, stack_name, resource_id):
-        try:
-            db_api.update_resource_metadata(stack_name, resource_id, body)
-        except StackNotFoundError:
-            return json_error(409, 'The stack "%s" does not exist.' % stack_name)
-        except ResourceNotFoundError:
-            # The resource doesn't exit yet, create it.
-            db_api.create_resource_metadata(stack_name, resource_id, body)
+        con = context.get_admin_context()
+        [error, metadata] = rpc.call(con, 'engine',
+                                     {'method': 'metadata_update',
+                                      'args': {'stack_name': stack_name,
+                                               'resource_id': resource_id,
+                                               'metadata': body}})
+        if error:
+            if error == 'stack':
+                return json_error(404, 'The stack "%s" does not exist.' % stack_name)
+            else:
+                return json_error(404, 'The resource "%s" does not exist.' % resource_id)
         return json_response(201, {
             'resource': resource_id,
             'metadata': body,