Connect metadata server to the engine via RPC

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>
This commit is contained in:
Tomas Sedovic 2012-05-04 15:16:11 +02:00
parent 247266e7bc
commit 9d69b20402
5 changed files with 109 additions and 27 deletions

View File

@ -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)

View 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):

View 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.

View 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]

View 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,