diff options
| author | Todd Willey <todd@ansolabs.com> | 2011-01-17 18:49:11 +0000 |
|---|---|---|
| committer | Tarmac <> | 2011-01-17 18:49:11 +0000 |
| commit | 3b94033b06ccc2d503d899e9fd7a3c8c6e2a7cba (patch) | |
| tree | 170ef113ef53cae8d24012ac9db92d03d067fdd9 /nova/api | |
| parent | 93deb2e9a375a18300eff258f2353e597932c47b (diff) | |
| parent | 6906137b99181925f091ca547d019499c3bc1701 (diff) | |
| download | nova-3b94033b06ccc2d503d899e9fd7a3c8c6e2a7cba.tar.gz nova-3b94033b06ccc2d503d899e9fd7a3c8c6e2a7cba.tar.xz nova-3b94033b06ccc2d503d899e9fd7a3c8c6e2a7cba.zip | |
Further decouple api routing decisions and move into paste.deploy configuration. This makes paste back the nova-api binary.
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/__init__.py | 93 | ||||
| -rw-r--r-- | nova/api/ec2/__init__.py | 80 | ||||
| -rw-r--r-- | nova/api/ec2/apirequest.py | 7 | ||||
| -rw-r--r-- | nova/api/ec2/cloud.py | 6 | ||||
| -rw-r--r-- | nova/api/openstack/__init__.py | 28 |
5 files changed, 49 insertions, 165 deletions
diff --git a/nova/api/__init__.py b/nova/api/__init__.py index 803470570..0fedbbfad 100644 --- a/nova/api/__init__.py +++ b/nova/api/__init__.py @@ -15,96 +15,5 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -""" -Root WSGI middleware for all API controllers. -**Related Flags** - -:osapi_subdomain: subdomain running the OpenStack API (default: api) -:ec2api_subdomain: subdomain running the EC2 API (default: ec2) - -""" - -import routes -import webob.dec - -from nova import flags -from nova import wsgi -from nova.api import ec2 -from nova.api import openstack -from nova.api.ec2 import metadatarequesthandler - - -flags.DEFINE_string('osapi_subdomain', 'api', - 'subdomain running the OpenStack API') -flags.DEFINE_string('ec2api_subdomain', 'ec2', - 'subdomain running the EC2 API') - -FLAGS = flags.FLAGS - - -class API(wsgi.Router): - """Routes top-level requests to the appropriate controller.""" - - def __init__(self, default_api): - osapi_subdomain = {'sub_domain': [FLAGS.osapi_subdomain]} - ec2api_subdomain = {'sub_domain': [FLAGS.ec2api_subdomain]} - if default_api == 'os': - osapi_subdomain = {} - elif default_api == 'ec2': - ec2api_subdomain = {} - mapper = routes.Mapper() - mapper.sub_domains = True - - mapper.connect("/", controller=self.osapi_versions, - conditions=osapi_subdomain) - mapper.connect("/v1.0/{path_info:.*}", controller=openstack.API(), - conditions=osapi_subdomain) - - mapper.connect("/", controller=self.ec2api_versions, - conditions=ec2api_subdomain) - mapper.connect("/services/{path_info:.*}", controller=ec2.API(), - conditions=ec2api_subdomain) - mrh = metadatarequesthandler.MetadataRequestHandler() - for s in ['/latest', - '/2009-04-04', - '/2008-09-01', - '/2008-02-01', - '/2007-12-15', - '/2007-10-10', - '/2007-08-29', - '/2007-03-01', - '/2007-01-19', - '/1.0']: - mapper.connect('%s/{path_info:.*}' % s, controller=mrh, - conditions=ec2api_subdomain) - - super(API, self).__init__(mapper) - - @webob.dec.wsgify - def osapi_versions(self, req): - """Respond to a request for all OpenStack API versions.""" - response = { - "versions": [ - dict(status="CURRENT", id="v1.0")]} - metadata = { - "application/xml": { - "attributes": dict(version=["status", "id"])}} - return wsgi.Serializer(req.environ, metadata).to_content_type(response) - - @webob.dec.wsgify - def ec2api_versions(self, req): - """Respond to a request for all EC2 versions.""" - # available api versions - versions = [ - '1.0', - '2007-01-19', - '2007-03-01', - '2007-08-29', - '2007-10-10', - '2007-12-15', - '2008-02-01', - '2008-09-01', - '2009-04-04', - ] - return ''.join('%s\n' % v for v in versions) +"""No-op __init__ for directory full of api goodies.""" diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 2fa1f636c..d0adf5e21 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -30,10 +30,9 @@ from nova import context from nova import exception from nova import flags from nova import log as logging +from nova import utils from nova import wsgi from nova.api.ec2 import apirequest -from nova.api.ec2 import admin -from nova.api.ec2 import cloud from nova.auth import manager @@ -42,8 +41,6 @@ LOG = logging.getLogger("nova.api") flags.DEFINE_boolean('use_forwarded_for', False, 'Treat X-Forwarded-For as the canonical remote address. ' 'Only enable this if you have a sanitizing proxy.') -flags.DEFINE_boolean('use_lockout', False, - 'Whether or not to use lockout middleware.') flags.DEFINE_integer('lockout_attempts', 5, 'Number of failed auths before lockout.') flags.DEFINE_integer('lockout_minutes', 15, @@ -54,13 +51,8 @@ flags.DEFINE_list('lockout_memcached_servers', None, 'Memcached servers or None for in process cache.') -class API(wsgi.Middleware): - """Routing for all EC2 API requests.""" - - def __init__(self): - self.application = Authenticate(Router(Authorizer(Executor()))) - if FLAGS.use_lockout: - self.application = Lockout(self.application) +class RequestLogging(wsgi.Middleware): + """Access-Log akin logging for all EC2 API requests.""" @webob.dec.wsgify def __call__(self, req): @@ -192,26 +184,14 @@ class Authenticate(wsgi.Middleware): return self.application -class Router(wsgi.Middleware): - - """Add ec2.'controller', .'action', and .'action_args' to WSGI environ.""" +class Requestify(wsgi.Middleware): - def __init__(self, application): - super(Router, self).__init__(application) - self.map = routes.Mapper() - self.map.connect("/{controller_name}/") - self.controllers = dict(Cloud=cloud.CloudController(), - Admin=admin.AdminController()) + def __init__(self, app, controller_name): + super(Requestify, self).__init__(app) + self.controller = utils.import_class(controller_name)() @webob.dec.wsgify def __call__(self, req): - # Obtain the appropriate controller and action for this request. - try: - match = self.map.match(req.path_info) - controller_name = match['controller_name'] - controller = self.controllers[controller_name] - except: - raise webob.exc.HTTPNotFound() non_args = ['Action', 'Signature', 'AWSAccessKeyId', 'SignatureMethod', 'SignatureVersion', 'Version', 'Timestamp'] args = dict(req.params) @@ -229,8 +209,8 @@ class Router(wsgi.Middleware): LOG.debug(_('arg: %s\t\tval: %s'), key, value) # Success! - req.environ['ec2.controller'] = controller - req.environ['ec2.action'] = action + api_request = apirequest.APIRequest(self.controller, action, args) + req.environ['ec2.request'] = api_request req.environ['ec2.action_args'] = args return self.application @@ -291,16 +271,14 @@ class Authorizer(wsgi.Middleware): @webob.dec.wsgify def __call__(self, req): context = req.environ['ec2.context'] - controller_name = req.environ['ec2.controller'].__class__.__name__ - action = req.environ['ec2.action'] - allowed_roles = self.action_roles[controller_name].get(action, - ['none']) + controller = req.environ['ec2.request'].controller.__class__.__name__ + action = req.environ['ec2.request'].action + allowed_roles = self.action_roles[controller].get(action, ['none']) if self._matches_any_role(context, allowed_roles): return self.application else: LOG.audit(_("Unauthorized request for controller=%s " - "and action=%s"), controller_name, action, - context=context) + "and action=%s"), controller, action, context=context) raise webob.exc.HTTPUnauthorized() def _matches_any_role(self, context, roles): @@ -327,14 +305,10 @@ class Executor(wsgi.Application): @webob.dec.wsgify def __call__(self, req): context = req.environ['ec2.context'] - controller = req.environ['ec2.controller'] - action = req.environ['ec2.action'] - args = req.environ['ec2.action_args'] - - api_request = apirequest.APIRequest(controller, action) + api_request = req.environ['ec2.request'] result = None try: - result = api_request.send(context, **args) + result = api_request.invoke(context) except exception.NotFound as ex: LOG.info(_('NotFound raised: %s'), str(ex), context=context) return self._error(req, context, type(ex).__name__, str(ex)) @@ -393,18 +367,18 @@ class Versions(wsgi.Application): return ''.join('%s\n' % v for v in versions) +def request_logging_factory(global_args, **local_args): + def logger(app): + return RequestLogging(app) + return logger + + def authenticate_factory(global_args, **local_args): def authenticator(app): return Authenticate(app) return authenticator -def router_factory(global_args, **local_args): - def router(app): - return Router(app) - return router - - def authorizer_factory(global_args, **local_args): def authorizer(app): return Authorizer(app) @@ -417,3 +391,15 @@ def executor_factory(global_args, **local_args): def versions_factory(global_args, **local_args): return Versions() + + +def requestify_factory(global_args, **local_args): + def requestifier(app): + return Requestify(app, local_args['controller']) + return requestifier + + +def lockout_factory(global_args, **local_args): + def locksmith(app): + return Lockout(app) + return locksmith diff --git a/nova/api/ec2/apirequest.py b/nova/api/ec2/apirequest.py index d0b417db1..78576470a 100644 --- a/nova/api/ec2/apirequest.py +++ b/nova/api/ec2/apirequest.py @@ -83,11 +83,12 @@ def _try_convert(value): class APIRequest(object): - def __init__(self, controller, action): + def __init__(self, controller, action, args): self.controller = controller self.action = action + self.args = args - def send(self, context, **kwargs): + def invoke(self, context): try: method = getattr(self.controller, _camelcase_to_underscore(self.action)) @@ -100,7 +101,7 @@ class APIRequest(object): raise Exception(_error) args = {} - for key, value in kwargs.items(): + for key, value in self.args.items(): parts = key.split(".") key = _camelcase_to_underscore(parts[0]) if isinstance(value, str) or isinstance(value, unicode): diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index a1ae70fb0..57d41ed67 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -254,15 +254,15 @@ class CloudController(object): name, _sep, host = region.partition('=') endpoint = '%s://%s:%s%s' % (FLAGS.ec2_prefix, host, - FLAGS.cc_port, + FLAGS.ec2_port, FLAGS.ec2_suffix) regions.append({'regionName': name, 'regionEndpoint': endpoint}) else: regions = [{'regionName': 'nova', 'regionEndpoint': '%s://%s:%s%s' % (FLAGS.ec2_prefix, - FLAGS.cc_host, - FLAGS.cc_port, + FLAGS.ec2_host, + FLAGS.ec2_port, FLAGS.ec2_suffix)}] return {'regionInfo': regions} diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index f96e2af91..302d50ac8 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -23,11 +23,9 @@ WSGI middleware for OpenStack API controllers. import routes import webob.dec import webob.exc -import webob from nova import flags from nova import log as logging -from nova import utils from nova import wsgi from nova.api.openstack import faults from nova.api.openstack import backup_schedules @@ -40,32 +38,16 @@ from nova.api.openstack import shared_ip_groups LOG = logging.getLogger('nova.api.openstack') FLAGS = flags.FLAGS -flags.DEFINE_string('os_api_auth', - 'nova.api.openstack.auth.AuthMiddleware', - 'The auth mechanism to use for the OpenStack API implemenation') - -flags.DEFINE_string('os_api_ratelimiting', - 'nova.api.openstack.ratelimiting.RateLimitingMiddleware', - 'Default ratelimiting implementation for the Openstack API') - flags.DEFINE_string('os_krm_mapping_file', 'krm_mapping.json', 'Location of OpenStack Flavor/OS:EC2 Kernel/Ramdisk/Machine JSON file.') - flags.DEFINE_bool('allow_admin_api', False, 'When True, this API service will accept admin operations.') -class API(wsgi.Middleware): - """WSGI entry point for all OpenStack API requests.""" - - def __init__(self): - auth_middleware = utils.import_class(FLAGS.os_api_auth) - ratelimiting_middleware = \ - utils.import_class(FLAGS.os_api_ratelimiting) - app = auth_middleware(ratelimiting_middleware(APIRouter())) - super(API, self).__init__(app) +class FaultWrapper(wsgi.Middleware): + """Calls down the middleware stack, making exceptions into faults.""" @webob.dec.wsgify def __call__(self, req): @@ -140,3 +122,9 @@ def router_factory(global_cof, **local_conf): def versions_factory(global_conf, **local_conf): return Versions() + + +def fault_wrapper_factory(global_conf, **local_conf): + def fwrap(app): + return FaultWrapper(app) + return fwrap |
