Initial metadata server API

This implements the basic capabilities we need from the metadata server. Each
API call returns proper HTTP responses (404, 409, etc.).

The server is currently not connected to a real database. Rather, it uses a
simple mock. This allows for quick initial API changes before things stabilize.

The immediate next steps are to integrate the server with the cfn tools
(cfn-metadata being the prime candidate) to see what may be wrong/missing.

And then to connect the server to a real database.

Signed-off-by: Tomas Sedovic <tomas@sedovic.cz>
changes/40/40/1
Tomas Sedovic 11 years ago
parent c061dc0029
commit 9843bc8baa

@ -30,7 +30,27 @@ class API(wsgi.Router):
mapper = routes.Mapper()
metadata_controller = metadata.create_resource(conf)
mapper.connect('/', controller=metadata_controller, action='index',
mapper.connect('/',
controller=metadata_controller, action='entry_point',
conditions=dict(method=['GET']))
mapper.connect('/stacks/',
controller=metadata_controller, action='list_stacks',
conditions=dict(method=['GET']))
mapper.connect('/stacks/:stack_name/resources/',
controller=metadata_controller, action='list_resources',
conditions=dict(method=['GET']))
mapper.connect('/stacks/:stack_name/resources/:resource_id',
controller=metadata_controller, action='get_resource',
conditions=dict(method=['GET']))
mapper.connect('/stacks/:stack_name',
controller=metadata_controller, action='create_stack',
conditions=dict(method=['PUT']))
mapper.connect('/stacks/:stack_name/resources/:resource_id',
controller=metadata_controller, action='update_metadata',
conditions=dict(method=['PUT']))
# TODO(shadower): make sure all responses are JSON-encoded
# currently, calling an unknown route uses the default handler which
# produces a HTML response.
super(API, self).__init__(mapper)

@ -14,17 +14,76 @@
# under the License.
import logging
import json
from webob.exc import Response
from heat.common import wsgi
from heat.metadata import db as db_api
from heat.metadata.db import (ConflictError, StackNotFoundError,
ResourceNotFoundError)
def json_response(http_status, data):
"""Create a JSON response with a specific HTTP code."""
response = Response(json.dumps(data))
response.status = http_status
response.content_type = 'application/json'
return response
def json_error(http_status, message):
"""Create a JSON error response."""
body = {'error': message}
return json_response(http_status, body)
class MetadataController:
def __init__(self, options):
self.options = options
def index(self, req):
return []
def entry_point(self, req):
return {
'name': 'Heat Metadata Server API',
'version': '1',
}
def list_stacks(self, req):
return db_api.list_stacks()
def list_resources(self, req, stack_name):
try:
resources = db_api.list_resources(stack_name)
except StackNotFoundError:
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)
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)
return json_response(201, {
'resource': resource_id,
'metadata': body,
})
def create_resource(options):
"""

@ -0,0 +1,64 @@
DB = {}
class ConflictError(Exception):
pass
class StackNotFoundError(Exception):
pass
class ResourceNotFoundError(Exception):
pass
def list_stacks():
return DB.keys()
def create_stack(name, stack):
global DB
if name in DB:
raise ConflictError(name)
data = {}
# TODO(shadower): validate the stack input format
data['name'] = name
data['heat_id'] = stack['id']
data['resources'] = {}
DB[name] = data
return data
def list_resources(stack_name):
if not stack_name in DB:
raise StackNotFoundError(stack_name)
stack = DB[stack_name]
try:
resources = stack['resources'].keys()
except:
resources = []
return resources
def get_resource(stack_name, resource_id):
if not stack_name in DB:
raise StackNotFoundError(stack_name)
stack = DB[stack_name]
if not resource_id in stack['resources']:
raise ResourceNotFoundError(resource_id)
return stack['resources'][resource_id]
def create_resource_metadata(stack_name, resource_id, metadata):
if not stack_name in DB:
raise StackNotFoundError(stack_name)
stack = DB[stack_name]
if resource_id in stack['resources']:
raise ConflictError(resource_id)
stack['resources'][resource_id] = metadata
def update_resource_metadata(stack_name, resource_id, metadata):
if not stack_name in DB:
raise StackNotFoundError(stack_name)
stack = DB[stack_name]
if not resource_id in stack['resources']:
raise ResourceNotFoundError(resource_id)
stack['resources'][resource_id] = metadata
Loading…
Cancel
Save