Added validation to the users/databases/root calls.
* Added a custom extension manager to make extension behavior normal * Added proper serializer/deserializer to the user/database/root calls * Added exception map for processing exceptions * Fixed all the returns to return wsgi.Result * Added validation method for create user/database/root
This commit is contained in:
parent
f635542677
commit
80413fc4b3
@ -16,62 +16,73 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import routes
|
||||||
|
import webob.dec
|
||||||
|
import logging
|
||||||
|
|
||||||
from reddwarf.openstack.common import extensions
|
from reddwarf.openstack.common import extensions
|
||||||
|
from reddwarf.common import wsgi
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
ExtensionsDescriptor = extensions.ExtensionDescriptor
|
ExtensionsDescriptor = extensions.ExtensionDescriptor
|
||||||
ResourceExtension = extensions.ResourceExtension
|
ResourceExtension = extensions.ResourceExtension
|
||||||
|
|
||||||
|
|
||||||
|
class ReddwarfExtensionMiddleware(extensions.ExtensionMiddleware):
|
||||||
|
|
||||||
|
def __init__(self, application, config, ext_mgr=None):
|
||||||
|
ext_mgr = ext_mgr or ExtensionManager(
|
||||||
|
config['api_extensions_path'])
|
||||||
|
mapper = routes.Mapper()
|
||||||
|
|
||||||
|
# extended resources
|
||||||
|
for resource_ext in ext_mgr.get_resources():
|
||||||
|
LOG.debug(_('Extended resource: %s'), resource_ext.collection)
|
||||||
|
LOG.debug(resource_ext.deserializer)
|
||||||
|
# The only difference here is that we are using our common
|
||||||
|
# wsgi.Resource instead of the openstack common wsgi.Resource
|
||||||
|
controller_resource = wsgi.Resource(resource_ext.controller,
|
||||||
|
resource_ext.deserializer,
|
||||||
|
resource_ext.serializer)
|
||||||
|
|
||||||
|
self._map_custom_collection_actions(resource_ext, mapper,
|
||||||
|
controller_resource)
|
||||||
|
kargs = dict(controller=controller_resource,
|
||||||
|
collection=resource_ext.collection_actions,
|
||||||
|
member=resource_ext.member_actions)
|
||||||
|
if resource_ext.parent:
|
||||||
|
kargs['parent_resource'] = resource_ext.parent
|
||||||
|
mapper.resource(resource_ext.collection,
|
||||||
|
resource_ext.collection, **kargs)
|
||||||
|
|
||||||
|
# extended actions
|
||||||
|
action_resources = self._action_ext_resources(application, ext_mgr,
|
||||||
|
mapper)
|
||||||
|
for action in ext_mgr.get_actions():
|
||||||
|
LOG.debug(_('Extended action: %s'), action.action_name)
|
||||||
|
resource = action_resources[action.collection]
|
||||||
|
resource.add_action(action.action_name, action.handler)
|
||||||
|
|
||||||
|
# extended requests
|
||||||
|
req_controllers = self._request_ext_resources(application, ext_mgr,
|
||||||
|
mapper)
|
||||||
|
for request_ext in ext_mgr.get_request_extensions():
|
||||||
|
LOG.debug(_('Extended request: %s'), request_ext.key)
|
||||||
|
controller = req_controllers[request_ext.key]
|
||||||
|
controller.add_handler(request_ext.handler)
|
||||||
|
|
||||||
|
self._router = routes.middleware.RoutesMiddleware(self._dispatch,
|
||||||
|
mapper)
|
||||||
|
|
||||||
|
super(extensions.ExtensionMiddleware, self).__init__(application)
|
||||||
|
|
||||||
|
|
||||||
def factory(global_config, **local_config):
|
def factory(global_config, **local_config):
|
||||||
"""Paste factory."""
|
"""Paste factory."""
|
||||||
def _factory(app):
|
def _factory(app):
|
||||||
extensions.DEFAULT_XMLNS = "http://docs.openstack.org/reddwarf"
|
extensions.DEFAULT_XMLNS = "http://docs.openstack.org/reddwarf"
|
||||||
ext_mgr = TenantExtensionManager(
|
ext_mgr = extensions.ExtensionManager(
|
||||||
global_config.get('api_extensions_path', ''))
|
global_config.get('api_extensions_path', ''))
|
||||||
return extensions.ExtensionMiddleware(app, global_config, ext_mgr)
|
return ReddwarfExtensionMiddleware(app, global_config, ext_mgr)
|
||||||
return _factory
|
return _factory
|
||||||
|
|
||||||
|
|
||||||
# Not sure if this is the way we should do it.
|
|
||||||
# Might need to make openstack common more extensible for tenants
|
|
||||||
# or any random values in the routes methods (index, show, etc...)
|
|
||||||
class TenantExtensionManager(extensions.ExtensionManager):
|
|
||||||
|
|
||||||
def __init__(self, path):
|
|
||||||
super(TenantExtensionManager, self).__init__(path)
|
|
||||||
|
|
||||||
#TODO(hub-cap): fix openstack-common.extensions to work with tenant ids
|
|
||||||
def get_resources(self):
|
|
||||||
"""Returns a list of ResourceExtension objects."""
|
|
||||||
resources = []
|
|
||||||
extension_resource = TenantExtensionsResource(self)
|
|
||||||
res_ext = extensions.ResourceExtension('{tenant_id}/extensions',
|
|
||||||
extension_resource,
|
|
||||||
serializer=extension_resource.serializer)
|
|
||||||
resources.append(res_ext)
|
|
||||||
for alias, ext in self.extensions.iteritems():
|
|
||||||
try:
|
|
||||||
resources.extend(ext.get_resources())
|
|
||||||
except AttributeError:
|
|
||||||
# NOTE(dprince): Extension aren't required to have resource
|
|
||||||
# extensions
|
|
||||||
pass
|
|
||||||
return resources
|
|
||||||
|
|
||||||
|
|
||||||
class TenantExtensionsResource(extensions.ExtensionsResource):
|
|
||||||
|
|
||||||
def __init__(self, extension_manager):
|
|
||||||
super(TenantExtensionsResource, self).__init__(extension_manager)
|
|
||||||
|
|
||||||
def index(self, req, tenant_id):
|
|
||||||
return super(TenantExtensionsResource, self).index(req)
|
|
||||||
|
|
||||||
def show(self, req, id, tenant_id):
|
|
||||||
return super(TenantExtensionsResource, self).show(req, id)
|
|
||||||
|
|
||||||
def delete(self, req, id, tenant_id):
|
|
||||||
return super(TenantExtensionsResource, self).delete(req, id)
|
|
||||||
|
|
||||||
def create(self, req, tenant_id):
|
|
||||||
return super(TenantExtensionsResource, self).create(req)
|
|
||||||
|
@ -35,6 +35,8 @@ Server = openstack_wsgi.Server
|
|||||||
Debug = openstack_wsgi.Debug
|
Debug = openstack_wsgi.Debug
|
||||||
Middleware = openstack_wsgi.Middleware
|
Middleware = openstack_wsgi.Middleware
|
||||||
JSONDictSerializer = openstack_wsgi.JSONDictSerializer
|
JSONDictSerializer = openstack_wsgi.JSONDictSerializer
|
||||||
|
XMLDictSerializer = openstack_wsgi.XMLDictSerializer
|
||||||
|
RequestDeserializer = openstack_wsgi.RequestDeserializer
|
||||||
|
|
||||||
eventlet.patcher.monkey_patch(all=False, socket=True)
|
eventlet.patcher.monkey_patch(all=False, socket=True)
|
||||||
|
|
||||||
@ -60,7 +62,6 @@ class VersionedURLMap(object):
|
|||||||
app = self.urlmap.get(version, Fault(http_exc))
|
app = self.urlmap.get(version, Fault(http_exc))
|
||||||
else:
|
else:
|
||||||
app = self.urlmap
|
app = self.urlmap
|
||||||
|
|
||||||
return app(environ, start_response)
|
return app(environ, start_response)
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from reddwarf.common import extensions
|
from reddwarf.common import extensions
|
||||||
|
from reddwarf.common import wsgi
|
||||||
from reddwarf.extensions.mysql import service
|
from reddwarf.extensions.mysql import service
|
||||||
|
|
||||||
|
|
||||||
@ -43,23 +44,34 @@ class Mysql(extensions.ExtensionsDescriptor):
|
|||||||
|
|
||||||
def get_resources(self):
|
def get_resources(self):
|
||||||
resources = []
|
resources = []
|
||||||
|
serializer = wsgi.ReddwarfResponseSerializer(
|
||||||
|
body_serializers={'application/xml':
|
||||||
|
wsgi.ReddwarfXMLDictSerializer()})
|
||||||
resource = extensions.ResourceExtension(
|
resource = extensions.ResourceExtension(
|
||||||
'databases',
|
'databases',
|
||||||
service.SchemaController(),
|
service.SchemaController(),
|
||||||
parent={'member_name': 'instance',
|
parent={'member_name': 'instance',
|
||||||
'collection_name': '{tenant_id}/instances'})
|
'collection_name': '{tenant_id}/instances'},
|
||||||
|
deserializer=wsgi.RequestDeserializer(),
|
||||||
|
serializer=serializer)
|
||||||
resources.append(resource)
|
resources.append(resource)
|
||||||
resource = extensions.ResourceExtension(
|
resource = extensions.ResourceExtension(
|
||||||
'users',
|
'users',
|
||||||
service.UserController(),
|
service.UserController(),
|
||||||
parent={'member_name': 'instance',
|
parent={'member_name': 'instance',
|
||||||
'collection_name': '{tenant_id}/instances'})
|
'collection_name': '{tenant_id}/instances'},
|
||||||
|
# deserializer=extensions.ExtensionsXMLSerializer()
|
||||||
|
deserializer=wsgi.RequestDeserializer(),
|
||||||
|
serializer=serializer)
|
||||||
resources.append(resource)
|
resources.append(resource)
|
||||||
resource = extensions.ResourceExtension(
|
resource = extensions.ResourceExtension(
|
||||||
'root',
|
'root',
|
||||||
service.RootController(),
|
service.RootController(),
|
||||||
parent={'member_name': 'instance',
|
parent={'member_name': 'instance',
|
||||||
'collection_name': '{tenant_id}/instances'})
|
'collection_name': '{tenant_id}/instances'},
|
||||||
|
deserializer=wsgi.RequestDeserializer(),
|
||||||
|
serializer=serializer)
|
||||||
|
|
||||||
resources.append(resource)
|
resources.append(resource)
|
||||||
|
|
||||||
return resources
|
return resources
|
||||||
|
@ -31,6 +31,29 @@ LOG = logging.getLogger(__name__)
|
|||||||
class BaseController(wsgi.Controller):
|
class BaseController(wsgi.Controller):
|
||||||
"""Base controller class."""
|
"""Base controller class."""
|
||||||
|
|
||||||
|
exclude_attr = []
|
||||||
|
exception_map = {
|
||||||
|
webob.exc.HTTPUnprocessableEntity: [
|
||||||
|
],
|
||||||
|
webob.exc.HTTPBadRequest: [
|
||||||
|
exception.BadRequest,
|
||||||
|
],
|
||||||
|
webob.exc.HTTPNotFound: [
|
||||||
|
exception.NotFound,
|
||||||
|
],
|
||||||
|
webob.exc.HTTPConflict: [
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _extract_required_params(self, params, model_name):
|
||||||
|
params = params or {}
|
||||||
|
model_params = params.get(model_name, {})
|
||||||
|
return utils.stringify_keys(utils.exclude(model_params,
|
||||||
|
*self.exclude_attr))
|
||||||
|
|
||||||
|
|
||||||
class RootController(BaseController):
|
class RootController(BaseController):
|
||||||
"""Controller for instance functionality"""
|
"""Controller for instance functionality"""
|
||||||
@ -44,7 +67,7 @@ class RootController(BaseController):
|
|||||||
auth_tok=req.headers["X-Auth-Token"],
|
auth_tok=req.headers["X-Auth-Token"],
|
||||||
tenant=tenant_id)
|
tenant=tenant_id)
|
||||||
is_root_enabled = models.Root.load(context, instance_id)
|
is_root_enabled = models.Root.load(context, instance_id)
|
||||||
return views.RootEnabledView(is_root_enabled).data()
|
return wsgi.Result(views.RootEnabledView(is_root_enabled).data(), 201)
|
||||||
|
|
||||||
def create(self, req, body, tenant_id, instance_id):
|
def create(self, req, body, tenant_id, instance_id):
|
||||||
""" Enable the root user for the db instance """
|
""" Enable the root user for the db instance """
|
||||||
@ -54,7 +77,7 @@ class RootController(BaseController):
|
|||||||
auth_tok=req.headers["X-Auth-Token"],
|
auth_tok=req.headers["X-Auth-Token"],
|
||||||
tenant=tenant_id)
|
tenant=tenant_id)
|
||||||
root = models.Root.create(context, instance_id)
|
root = models.Root.create(context, instance_id)
|
||||||
return views.RootCreatedView(root).data()
|
return wsgi.Result(views.RootCreatedView(root).data(), 201)
|
||||||
|
|
||||||
|
|
||||||
class UserController(BaseController):
|
class UserController(BaseController):
|
||||||
@ -67,15 +90,12 @@ class UserController(BaseController):
|
|||||||
raise exception.BadRequest("The request contains an empty body")
|
raise exception.BadRequest("The request contains an empty body")
|
||||||
|
|
||||||
if not body.get('users', ''):
|
if not body.get('users', ''):
|
||||||
raise exception.BadRequest("Required element/key 'users' was not "
|
raise exception.BadRequest(key='users')
|
||||||
"specified")
|
|
||||||
for user in body.get('users'):
|
for user in body.get('users'):
|
||||||
if not user.get('name'):
|
if not user.get('name'):
|
||||||
raise exception.BadRequest("Required attribute/key 'name' was "
|
raise exception.BadRequest(key='name')
|
||||||
"not specified")
|
|
||||||
if not user.get('password'):
|
if not user.get('password'):
|
||||||
raise exception.BadRequest("Required attribute/key 'password' "
|
raise exception.BadRequest(key='password')
|
||||||
"was not specified")
|
|
||||||
|
|
||||||
def index(self, req, tenant_id, instance_id):
|
def index(self, req, tenant_id, instance_id):
|
||||||
"""Return all users."""
|
"""Return all users."""
|
||||||
@ -85,8 +105,7 @@ class UserController(BaseController):
|
|||||||
auth_tok=req.headers["X-Auth-Token"],
|
auth_tok=req.headers["X-Auth-Token"],
|
||||||
tenant=tenant_id)
|
tenant=tenant_id)
|
||||||
users = models.Users.load(context, instance_id)
|
users = models.Users.load(context, instance_id)
|
||||||
# Not exactly sure why we cant return a wsgi.Result() here
|
return wsgi.Result(views.UsersView(users).data(), 201)
|
||||||
return views.UsersView(users).data()
|
|
||||||
|
|
||||||
def create(self, req, body, tenant_id, instance_id):
|
def create(self, req, body, tenant_id, instance_id):
|
||||||
"""Creates a set of users"""
|
"""Creates a set of users"""
|
||||||
@ -96,14 +115,11 @@ class UserController(BaseController):
|
|||||||
context = rd_context.ReddwarfContext(
|
context = rd_context.ReddwarfContext(
|
||||||
auth_tok=req.headers["X-Auth-Token"],
|
auth_tok=req.headers["X-Auth-Token"],
|
||||||
tenant=tenant_id)
|
tenant=tenant_id)
|
||||||
try:
|
self.validate(body)
|
||||||
self.validate(body)
|
|
||||||
except exception.BadRequest as br:
|
|
||||||
return webob.exc.HTTPBadRequest(br)
|
|
||||||
users = body['users']
|
users = body['users']
|
||||||
model_users = models.populate_users(users)
|
model_users = models.populate_users(users)
|
||||||
models.User.create(context, instance_id, model_users)
|
models.User.create(context, instance_id, model_users)
|
||||||
return webob.exc.HTTPAccepted()
|
return wsgi.Result(202)
|
||||||
|
|
||||||
def delete(self, req, tenant_id, instance_id, id):
|
def delete(self, req, tenant_id, instance_id, id):
|
||||||
LOG.info("Deleting user for instance '%s'" % instance_id)
|
LOG.info("Deleting user for instance '%s'" % instance_id)
|
||||||
@ -114,7 +130,7 @@ class UserController(BaseController):
|
|||||||
user = guest_models.MySQLUser()
|
user = guest_models.MySQLUser()
|
||||||
user.name = id
|
user.name = id
|
||||||
models.User.delete(context, instance_id, user.serialize())
|
models.User.delete(context, instance_id, user.serialize())
|
||||||
return webob.exc.HTTPAccepted()
|
return wsgi.Result(202)
|
||||||
|
|
||||||
|
|
||||||
class SchemaController(BaseController):
|
class SchemaController(BaseController):
|
||||||
@ -140,7 +156,7 @@ class SchemaController(BaseController):
|
|||||||
tenant=tenant_id)
|
tenant=tenant_id)
|
||||||
schemas = models.Schemas.load(context, instance_id)
|
schemas = models.Schemas.load(context, instance_id)
|
||||||
# Not exactly sure why we cant return a wsgi.Result() here
|
# Not exactly sure why we cant return a wsgi.Result() here
|
||||||
return views.SchemasView(schemas).data()
|
return wsgi.Result(views.SchemasView(schemas).data(), 201)
|
||||||
|
|
||||||
def create(self, req, body, tenant_id, instance_id):
|
def create(self, req, body, tenant_id, instance_id):
|
||||||
"""Creates a set of schemas"""
|
"""Creates a set of schemas"""
|
||||||
@ -150,14 +166,11 @@ class SchemaController(BaseController):
|
|||||||
context = rd_context.ReddwarfContext(
|
context = rd_context.ReddwarfContext(
|
||||||
auth_tok=req.headers["X-Auth-Token"],
|
auth_tok=req.headers["X-Auth-Token"],
|
||||||
tenant=tenant_id)
|
tenant=tenant_id)
|
||||||
try:
|
self.validate(body)
|
||||||
self.validate(body)
|
|
||||||
except exception.BadRequest as br:
|
|
||||||
return webob.exc.HTTPBadRequest(br)
|
|
||||||
schemas = body['databases']
|
schemas = body['databases']
|
||||||
model_schemas = models.populate_databases(schemas)
|
model_schemas = models.populate_databases(schemas)
|
||||||
models.Schema.create(context, instance_id, model_schemas)
|
models.Schema.create(context, instance_id, model_schemas)
|
||||||
return webob.exc.HTTPAccepted()
|
return wsgi.Result(202)
|
||||||
|
|
||||||
def delete(self, req, tenant_id, instance_id, id):
|
def delete(self, req, tenant_id, instance_id, id):
|
||||||
LOG.info("Deleting schema for instance '%s'" % instance_id)
|
LOG.info("Deleting schema for instance '%s'" % instance_id)
|
||||||
@ -168,4 +181,4 @@ class SchemaController(BaseController):
|
|||||||
schema = guest_models.MySQLDatabase()
|
schema = guest_models.MySQLDatabase()
|
||||||
schema.name = id
|
schema.name = id
|
||||||
models.Schema.delete(context, instance_id, schema.serialize())
|
models.Schema.delete(context, instance_id, schema.serialize())
|
||||||
return webob.exc.HTTPAccepted()
|
return wsgi.Result(202)
|
||||||
|
Loading…
Reference in New Issue
Block a user