diff --git a/cyborg/api/app.py b/cyborg/api/app.py index 95862da8..a677ba74 100644 --- a/cyborg/api/app.py +++ b/cyborg/api/app.py @@ -13,13 +13,21 @@ # License for the specific language governing permissions and limitations # under the License. +import os import pecan from oslo_config import cfg +from oslo_log import log +from paste import deploy from cyborg.api import config from cyborg.api import hooks from cyborg.api import middleware +import cyborg.conf + + +CONF = cyborg.conf.CONF +LOG = log.getLogger(__name__) def get_pecan_config(): @@ -29,6 +37,9 @@ def get_pecan_config(): def setup_app(pecan_config=None, extra_hooks=None): + if not pecan_config: + pecan_config = get_pecan_config() + app_hooks = [hooks.ConfigHook(), hooks.ConductorAPIHook(), hooks.ContextHook(pecan_config.app.acl_public_routes), @@ -36,31 +47,31 @@ def setup_app(pecan_config=None, extra_hooks=None): if extra_hooks: app_hooks.extend(extra_hooks) - if not pecan_config: - pecan_config = get_pecan_config() - - pecan.configuration.set_config(dict(pecan_config), overwrite=True) - + app_conf = dict(pecan_config.app) app = pecan.make_app( - pecan_config.app.root, - static_root=pecan_config.app.static_root, - debug=False, + app_conf.pop('root'), force_canonical=getattr(pecan_config.app, 'force_canonical', True), hooks=app_hooks, - wrap_app=middleware.ParsableErrorMiddleware + wrap_app=middleware.ParsableErrorMiddleware, + **app_conf ) - app = middleware.AuthTokenMiddleware( - app, dict(cfg.CONF), - public_api_routes=pecan_config.app.acl_public_routes) - return app -class VersionSelectorApplication(object): - def __init__(self): - pc = get_pecan_config() - self.v1 = setup_app(pecan_config=pc) +def load_app(): + cfg_file = None + cfg_path = CONF.api.api_paste_config + if not os.path.isabs(cfg_path): + cfg_file = CONF.find_file(cfg_path) + elif os.path.exists(cfg_path): + cfg_file = cfg_path - def __call__(self, environ, start_response): - return self.v1(environ, start_response) + if not cfg_file: + raise cfg.ConfigFilesNotFoundError([CONF.api.api_paste_config]) + LOG.info("Full WSGI config used: %s", cfg_file) + return deploy.loadapp("config:" + cfg_file) + + +def app_factory(global_config, **local_conf): + return setup_app() diff --git a/cyborg/api/hooks.py b/cyborg/api/hooks.py index ffc3744e..9c40861d 100644 --- a/cyborg/api/hooks.py +++ b/cyborg/api/hooks.py @@ -92,12 +92,3 @@ class ContextHook(hooks.PecanHook): is_admin = policy.authorize('is_admin', creds, creds) state.request.context = context.RequestContext( is_admin=is_admin, **creds) - - def after(self, state): - if state.request.context == {}: - # An incorrect url path will not create RequestContext - return - # RequestContext will generate a request_id if no one - # passing outside, so it always contain a request_id. - request_id = state.request.context.request_id - state.response.headers['Openstack-Request-Id'] = request_id diff --git a/cyborg/api/middleware/auth_token.py b/cyborg/api/middleware/auth_token.py index 95b53230..71a734ea 100644 --- a/cyborg/api/middleware/auth_token.py +++ b/cyborg/api/middleware/auth_token.py @@ -62,3 +62,13 @@ class AuthTokenMiddleware(auth_token.AuthProtocol): return self.app(env, start_response) return super(AuthTokenMiddleware, self).__call__(env, start_response) + + @classmethod + def factory(cls, global_config, **local_conf): + public_routes = local_conf.get('acl_public_routes', '') + public_api_routes = [path.strip() for path in public_routes.split(',')] + + def _factory(app): + return cls(app, global_config, public_api_routes=public_api_routes) + + return _factory diff --git a/cyborg/common/service.py b/cyborg/common/service.py index 159bf711..579f63b6 100644 --- a/cyborg/common/service.py +++ b/cyborg/common/service.py @@ -103,7 +103,7 @@ class WSGIService(service.ServiceBase): :returns: None """ self.name = name - self.app = app.VersionSelectorApplication() + self.app = app.load_app() self.workers = (CONF.api.api_workers or processutils.get_worker_count()) if self.workers and self.workers < 1: diff --git a/cyborg/conf/api.py b/cyborg/conf/api.py index 28eb8869..96cf69d2 100644 --- a/cyborg/conf/api.py +++ b/cyborg/conf/api.py @@ -45,6 +45,9 @@ opts = [ "host URL. If the API is operating behind a proxy, you " "will want to change this to represent the proxy's URL. " "Defaults to None.")), + cfg.StrOpt('api_paste_config', + default="api-paste.ini", + help="Configuration file for WSGI definition of API."), ] opt_group = cfg.OptGroup(name='api', diff --git a/devstack/lib/cyborg b/devstack/lib/cyborg index b7532261..f9f00baa 100644 --- a/devstack/lib/cyborg +++ b/devstack/lib/cyborg @@ -37,6 +37,7 @@ CYBORG_STATE_PATH=/var/lib/cyborg CYBORG_AUTH_CACHE_DIR=${CYBORG_AUTH_CACHE_DIR:-/var/cache/cyborg} CYBORG_CONF_DIR=${CYBORG_CONF_DIR:-/etc/cyborg} CYBORG_CONF_FILE=$CYBORG_CONF_DIR/cyborg.conf +CYBORG_API_PASTE_INI=$CYBORG_CONF_DIR/api-paste.ini CYBORG_ROOTWRAP_CONF=$CYBORG_CONF_DIR/rootwrap.conf CYBORG_POLICY_JSON=$CYBORG_CONF_DIR/policy.json CYBORG_SERVICE_HOST=${CYBORG_SERVICE_HOST:-$SERVICE_HOST} @@ -173,6 +174,7 @@ function configure_cyborg_conductor { sudo cp $CYBORG_DIR/etc/cyborg/rootwrap.conf $CYBORG_ROOTWRAP_CONF sudo cp -r $CYBORG_DIR/etc/cyborg/rootwrap.d $CYBORG_CONF_DIR + sudo cp -p $CYBORG_DIR/etc/cyborg/api-paste.ini $CYBORG_API_PASTE_INI local cyborg_rootwrap cyborg_rootwrap=$(get_rootwrap_location cyborg) local rootwrap_isudoer_cmd="$cyborg_rootwrap $CYBORG_CONF_DIR/rootwrap.conf *" diff --git a/etc/cyborg/api-paste.ini b/etc/cyborg/api-paste.ini new file mode 100644 index 00000000..7717f958 --- /dev/null +++ b/etc/cyborg/api-paste.ini @@ -0,0 +1,19 @@ +[pipeline:main] +pipeline = cors request_id authtoken api_v1 + +[app:api_v1] +paste.app_factory = cyborg.api.app:app_factory + +[filter:authtoken] +acl_public_routes = /, /v1 +paste.filter_factory = cyborg.api.middleware.auth_token:AuthTokenMiddleware.factory + +[filter:osprofiler] +paste.filter_factory = cyborg.common.profiler:WsgiMiddleware.factory + +[filter:request_id] +paste.filter_factory = oslo_middleware:RequestId.factory + +[filter:cors] +paste.filter_factory = oslo_middleware.cors:filter_factory +oslo_config_project = cyborg diff --git a/setup.cfg b/setup.cfg index 45a18894..c8569b83 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,6 +26,7 @@ data_files = etc/cyborg = etc/cyborg/rootwrap.conf etc/cyborg/policy.json + etc/cyborg/api-paste.ini etc/cyborg/rootwrap.d = etc/cyborg/rootwrap.d/*