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)
|
gettext.install('heat', unicode=1)
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from heat import rpc
|
||||||
from heat.common import config
|
from heat.common import config
|
||||||
from heat.common import wsgi
|
from heat.common import wsgi
|
||||||
from paste import httpserver
|
from paste import httpserver
|
||||||
@ -45,6 +46,7 @@ if __name__ == '__main__':
|
|||||||
conf = config.HeatMetadataConfigOpts()
|
conf = config.HeatMetadataConfigOpts()
|
||||||
conf()
|
conf()
|
||||||
config.FLAGS = conf
|
config.FLAGS = conf
|
||||||
|
rpc.configure(conf)
|
||||||
config.setup_logging(conf)
|
config.setup_logging(conf)
|
||||||
|
|
||||||
app = config.load_paste_app(conf)
|
app = config.load_paste_app(conf)
|
||||||
|
@ -148,7 +148,9 @@ class HeatMetadataConfigOpts(cfg.CommonConfigOpts):
|
|||||||
version='%%prog %s' % version.version_string(),
|
version='%%prog %s' % version.version_string(),
|
||||||
default_config_files=default_config_files,
|
default_config_files=default_config_files,
|
||||||
**kwargs)
|
**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):
|
class HeatEngineConfigOpts(cfg.CommonConfigOpts):
|
||||||
|
@ -89,6 +89,16 @@ class HeatBase(object):
|
|||||||
for k, v in values.iteritems():
|
for k, v in values.iteritems():
|
||||||
setattr(self, k, v)
|
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):
|
def iteritems(self):
|
||||||
"""Make the model object behave like a dict.
|
"""Make the model object behave like a dict.
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
from copy import deepcopy
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
@ -214,3 +215,61 @@ class EngineManager(manager.Manager):
|
|||||||
'ResourceStatus': e.name}
|
'ResourceStatus': e.name}
|
||||||
|
|
||||||
return {'events': [parse_event(e) for e in events]}
|
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 webob.exc import Response
|
||||||
|
|
||||||
from heat.common import wsgi
|
from heat.common import wsgi
|
||||||
|
from heat import context
|
||||||
from heat.metadata import db as db_api
|
from heat.metadata import db as db_api
|
||||||
from heat.metadata.db import (ConflictError, StackNotFoundError,
|
from heat.metadata.db import (ConflictError, StackNotFoundError,
|
||||||
ResourceNotFoundError)
|
ResourceNotFoundError)
|
||||||
|
from heat import rpc
|
||||||
|
|
||||||
|
|
||||||
def json_response(http_status, data):
|
def json_response(http_status, data):
|
||||||
@ -47,39 +49,46 @@ class MetadataController:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def list_stacks(self, req):
|
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):
|
def list_resources(self, req, stack_name):
|
||||||
try:
|
con = context.get_admin_context()
|
||||||
resources = db_api.list_resources(stack_name)
|
resources = rpc.call(con, 'engine',
|
||||||
except StackNotFoundError:
|
{'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 json_error(404, 'The stack "%s" does not exist.' % stack_name)
|
||||||
return resources
|
|
||||||
|
|
||||||
def get_resource(self, req, stack_name, resource_id):
|
def get_resource(self, req, stack_name, resource_id):
|
||||||
try:
|
con = context.get_admin_context()
|
||||||
resource = db_api.get_resource(stack_name, resource_id)
|
[error, metadata] = rpc.call(con, 'engine',
|
||||||
except StackNotFoundError:
|
{'method': 'metadata_get_resource',
|
||||||
return json_error(404, 'The stack "%s" does not exist.' % stack_name)
|
'args': {'stack_name': stack_name,
|
||||||
except ResourceNotFoundError:
|
'resource_id': resource_id}})
|
||||||
return json_error(404, 'The resource "%s" does not exist.' % resource_id)
|
if error:
|
||||||
return resource
|
if error == 'stack':
|
||||||
|
return json_error(404, 'The stack "%s" does not exist.' % stack_name)
|
||||||
def create_stack(self, req, body, stack_name):
|
else:
|
||||||
try:
|
return json_error(404, 'The resource "%s" does not exist.' % resource_id)
|
||||||
stack = db_api.create_stack(stack_name, body)
|
return metadata
|
||||||
except ConflictError:
|
|
||||||
return json_error(409, 'The stack "%s" already exists.' % stack_name)
|
|
||||||
return json_response(201, stack)
|
|
||||||
|
|
||||||
def update_metadata(self, req, body, stack_name, resource_id):
|
def update_metadata(self, req, body, stack_name, resource_id):
|
||||||
try:
|
con = context.get_admin_context()
|
||||||
db_api.update_resource_metadata(stack_name, resource_id, body)
|
[error, metadata] = rpc.call(con, 'engine',
|
||||||
except StackNotFoundError:
|
{'method': 'metadata_update',
|
||||||
return json_error(409, 'The stack "%s" does not exist.' % stack_name)
|
'args': {'stack_name': stack_name,
|
||||||
except ResourceNotFoundError:
|
'resource_id': resource_id,
|
||||||
# The resource doesn't exit yet, create it.
|
'metadata': body}})
|
||||||
db_api.create_resource_metadata(stack_name, resource_id, 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, {
|
return json_response(201, {
|
||||||
'resource': resource_id,
|
'resource': resource_id,
|
||||||
'metadata': body,
|
'metadata': body,
|
||||||
|
Loading…
Reference in New Issue
Block a user