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:
parent
247266e7bc
commit
9d69b20402
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user