Add WSGI support for `cloudkitty-api'
Recommands to setup cloudkitty through an other WSGI services like Apache 'mod_wsgi'. And the community has set a community wide goal in Pike cycle: "Control Plane API endpoints deployment via WSGI" https://governance.openstack.org/tc/goals/pike/deploy-api-in-wsgi.html Work Item: Add WSGI support 1. Provide WSGI application script file. 2. Removing the cloudkitty-api command line. 3. Adding cloudkitty-api wsgi_scripts, by 'cloudkitty-api -p 8889' to run. Work Item: Make the devstack setup ck-api with wsgi 1. Switch devstack jobs to deploy control-plane API services in WSGI with Apache. 2. Default to deploy with Apache by global ENABLE_HTTPD_MOD_WSGI_SERVICES, in local.conf expose CLOUDKITTY_USE_MOD_WSGI=False to run without Apache. Work Item: Update the docs about installation 1. Installing the cloudkitty-api behind mod_wsgi. 2. Updating the installation about the cloudkitty-api. Implements: blueprint wsgi-support Change-Id: I207587c5360bb80c0e856cd0239e4073578951aa
This commit is contained in:
parent
efb35ee3a0
commit
2dc80310ba
@ -15,9 +15,7 @@
|
||||
#
|
||||
# @author: Stéphane Albert
|
||||
#
|
||||
import logging
|
||||
import os
|
||||
from wsgiref import simple_server
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
@ -26,6 +24,7 @@ import pecan
|
||||
|
||||
from cloudkitty.api import config as api_config
|
||||
from cloudkitty.api import hooks
|
||||
from cloudkitty import service
|
||||
from cloudkitty import storage
|
||||
|
||||
|
||||
@ -34,8 +33,7 @@ LOG = log.getLogger(__name__)
|
||||
auth_opts = [
|
||||
cfg.StrOpt('api_paste_config',
|
||||
default="api_paste.ini",
|
||||
help="Configuration file for WSGI definition of API."
|
||||
),
|
||||
help="Configuration file for WSGI definition of API."),
|
||||
cfg.StrOpt('auth_strategy',
|
||||
choices=['noauth', 'keystone'],
|
||||
default='keystone',
|
||||
@ -45,11 +43,11 @@ auth_opts = [
|
||||
|
||||
api_opts = [
|
||||
cfg.IPOpt('host_ip',
|
||||
default="0.0.0.0",
|
||||
help='Host serving the API.'),
|
||||
default='0.0.0.0',
|
||||
help='The listen IP for the cloudkitty API server.'),
|
||||
cfg.PortOpt('port',
|
||||
default=8889,
|
||||
help='Host port serving the API.'),
|
||||
help='The port for the cloudkitty API server.'),
|
||||
cfg.BoolOpt('pecan_debug',
|
||||
default=False,
|
||||
help='Toggle Pecan Debug Middleware.'),
|
||||
@ -103,35 +101,9 @@ def load_app():
|
||||
return deploy.loadapp("config:" + cfg_file)
|
||||
|
||||
|
||||
def build_server():
|
||||
# Create the WSGI server and start it
|
||||
host = CONF.api.host_ip
|
||||
port = CONF.api.port
|
||||
LOG.info('Starting server in PID %s', os.getpid())
|
||||
LOG.info("Configuration:")
|
||||
cfg.CONF.log_opt_values(LOG, logging.INFO)
|
||||
|
||||
if host == '0.0.0.0':
|
||||
LOG.info('serving on 0.0.0.0:%(sport)s, view at \
|
||||
http://127.0.0.1:%(vport)s',
|
||||
{'sport': port, 'vport': port})
|
||||
else:
|
||||
LOG.info("serving on http://%(host)s:%(port)s",
|
||||
{'host': host, 'port': port})
|
||||
|
||||
server_cls = simple_server.WSGIServer
|
||||
handler_cls = simple_server.WSGIRequestHandler
|
||||
|
||||
app = load_app()
|
||||
|
||||
srv = simple_server.make_server(
|
||||
host,
|
||||
port,
|
||||
app,
|
||||
server_cls,
|
||||
handler_cls)
|
||||
|
||||
return srv
|
||||
def build_wsgi_app(argv=None):
|
||||
service.prepare_service([])
|
||||
return load_app()
|
||||
|
||||
|
||||
def app_factory(global_config, **local_conf):
|
||||
|
@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 Objectif Libre
|
||||
# -*- mode: python -*-
|
||||
#
|
||||
# Copyright 2013 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
@ -12,21 +13,12 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Stéphane Albert
|
||||
#
|
||||
|
||||
"""Use this file for deploying the API under mod_wsgi.
|
||||
|
||||
See http://pecan.readthedocs.org/en/latest/deployment.html for details.
|
||||
"""
|
||||
|
||||
from cloudkitty.api import app
|
||||
from cloudkitty import service
|
||||
|
||||
|
||||
def main():
|
||||
service.prepare_service()
|
||||
server = app.build_server()
|
||||
try:
|
||||
server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
application = app.build_wsgi_app(argv=[])
|
15
devstack/apache-cloudkitty.template
Normal file
15
devstack/apache-cloudkitty.template
Normal file
@ -0,0 +1,15 @@
|
||||
Listen %PORT%
|
||||
|
||||
<VirtualHost *:%PORT%>
|
||||
WSGIDaemonProcess cloudkitty-api processes=2 threads=10 user=%USER% display-name=%{GROUP} %VIRTUALENV%
|
||||
WSGIProcessGroup cloudkitty-api
|
||||
WSGIScriptAlias / %WSGIAPP%
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
ErrorLog /var/log/%APACHE_NAME%/cloudkitty.log
|
||||
CustomLog /var/log/%APACHE_NAME%/cloudkitty_access.log combined
|
||||
</VirtualHost>
|
||||
|
||||
WSGISocketPrefix /var/run/%APACHE_NAME%
|
@ -73,9 +73,19 @@ function is_cloudkitty_enabled {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Remove WSGI files, disable and remove Apache vhost file
|
||||
function _cloudkitty_cleanup_apache_wsgi {
|
||||
if is_service_enabled ck-api && [ "$CLOUDKITTY_USE_MOD_WSGI" == "True" ]; then
|
||||
sudo rm -f "$CLOUDKITTY_WSGI_DIR"/*
|
||||
sudo rm -rf "$CLOUDKITTY_WSGI_DIR"
|
||||
sudo rm -f $(apache_site_config_for cloudkitty)
|
||||
fi
|
||||
}
|
||||
|
||||
# cleanup_cloudkitty() - Remove residual data files, anything left over from previous
|
||||
# runs that a clean run would need to clean up
|
||||
function cleanup_cloudkitty {
|
||||
_cloudkitty_cleanup_apache_wsgi
|
||||
# Clean up dirs
|
||||
rm -rf $CLOUDKITTY_AUTH_CACHE_DIR/*
|
||||
rm -rf $CLOUDKITTY_CONF_DIR/*
|
||||
@ -85,6 +95,31 @@ function cleanup_cloudkitty {
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# Configure mod_wsgi
|
||||
function _cloudkitty_config_apache_wsgi {
|
||||
sudo mkdir -m 755 -p $CLOUDKITTY_WSGI_DIR
|
||||
|
||||
local cloudkitty_apache_conf=$(apache_site_config_for cloudkitty)
|
||||
local venv_path=""
|
||||
|
||||
# Copy proxy vhost and wsgi file
|
||||
sudo cp $CLOUDKITTY_DIR/cloudkitty/api/app.wsgi $CLOUDKITTY_WSGI_DIR/app.wsgi
|
||||
|
||||
if [[ ${USE_VENV} = True ]]; then
|
||||
venv_path="python-path=${PROJECT_VENV["cloudkitty"]}/lib/$(python_version)/site-packages"
|
||||
fi
|
||||
|
||||
sudo cp $CLOUDKITTY_DIR/devstack/apache-cloudkitty.template $cloudkitty_apache_conf
|
||||
sudo sed -e "
|
||||
s|%PORT%|$CLOUDKITTY_SERVICE_PORT|g;
|
||||
s|%APACHE_NAME%|$APACHE_NAME|g;
|
||||
s|%WSGIAPP%|$CLOUDKITTY_WSGI_DIR/app.wsgi|g;
|
||||
s|%USER%|$STACK_USER|g;
|
||||
s|%VIRTUALENV%|$venv_path|g
|
||||
" -i $cloudkitty_apache_conf
|
||||
}
|
||||
|
||||
# configure_cloudkitty() - Set config files, create data dirs, etc
|
||||
function configure_cloudkitty {
|
||||
setup_develop $CLOUDKITTY_DIR
|
||||
@ -137,6 +172,10 @@ function configure_cloudkitty {
|
||||
|
||||
# keystone middleware
|
||||
configure_auth_token_middleware $CLOUDKITTY_CONF cloudkitty $CLOUDKITTY_AUTH_CACHE_DIR
|
||||
|
||||
if is_service_enabled ck-api && [ "$CLOUDKITTY_USE_MOD_WSGI" == "True" ]; then
|
||||
_cloudkitty_config_apache_wsgi
|
||||
fi
|
||||
}
|
||||
|
||||
# create_cloudkitty_cache_dir() - Part of the init_cloudkitty() process
|
||||
@ -195,7 +234,14 @@ function install_cloudkitty {
|
||||
# start_cloudkitty() - Start running processes, including screen
|
||||
function start_cloudkitty {
|
||||
run_process ck-proc "$CLOUDKITTY_BIN_DIR/cloudkitty-processor --config-file=$CLOUDKITTY_CONF"
|
||||
run_process ck-api "$CLOUDKITTY_BIN_DIR/cloudkitty-api --config-file=$CLOUDKITTY_CONF"
|
||||
if [[ "$CLOUDKITTY_USE_MOD_WSGI" == "False" ]]; then
|
||||
run_process ck-api "$CLOUDKITTY_BIN_DIR/cloudkitty-api --config-file=$CLOUDKITTY_CONF"
|
||||
elif is_service_enabled ck-api; then
|
||||
enable_apache_site cloudkitty
|
||||
restart_apache_server
|
||||
tail_log cloudkitty /var/log/$APACHE_NAME/cloudkitty.log
|
||||
tail_log cloudkitty-api /var/log/$APACHE_NAME/cloudkitty_access.log
|
||||
fi
|
||||
echo "Waiting for ck-api ($CLOUDKITTY_SERVICE_HOST:$CLOUDKITTY_SERVICE_PORT) to start..."
|
||||
if ! wait_for_service $SERVICE_TIMEOUT $CLOUDKITTY_SERVICE_PROTOCOL://$CLOUDKITTY_SERVICE_HOST:$CLOUDKITTY_SERVICE_PORT; then
|
||||
die $LINENO "ck-api did not start"
|
||||
@ -205,9 +251,19 @@ function start_cloudkitty {
|
||||
# stop_cloudkitty() - Stop running processes
|
||||
function stop_cloudkitty {
|
||||
# Kill the cloudkitty screen windows
|
||||
for serv in ck-api ck-proc; do
|
||||
stop_process $serv
|
||||
done
|
||||
if is_service_enabled ck-proc ; then
|
||||
stop_process ck-proc
|
||||
fi
|
||||
|
||||
if is_service_enabled ck-api ; then
|
||||
if [ "$CLOUDKITTY_USE_MOD_WSGI" == "True" ]; then
|
||||
disable_apache_site cloudkitty
|
||||
restart_apache_server
|
||||
else
|
||||
# Kill the cloudkitty screen windows
|
||||
stop_process ck-api
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# install_python_cloudkittyclient() - Collect source and prepare
|
||||
|
@ -10,12 +10,12 @@ CLOUDKITTY_DIR=$DEST/cloudkitty
|
||||
CLOUDKITTY_CONF_DIR=/etc/cloudkitty
|
||||
CLOUDKITTY_CONF=$CLOUDKITTY_CONF_DIR/cloudkitty.conf
|
||||
CLOUDKITTY_API_LOG_DIR=/var/log/cloudkitty
|
||||
CLOUDKITTY_WSGI_DIR=${CLOUDKITTY_WSGI_DIR:-/var/www/cloudkitty}
|
||||
CLOUDKITTY_AUTH_CACHE_DIR=${CLOUDKITTY_AUTH_CACHE_DIR:-/var/cache/cloudkitty}
|
||||
CLOUDKITTY_DATA_DIR=${CLOUDKITTY_DATA_DIR:-/var/lib/cloudkitty}
|
||||
CLOUDKITTY_REPORTS_DIR=${DATA_DIR}/cloudkitty/reports
|
||||
|
||||
# Horizon enabled file
|
||||
|
||||
CLOUDKITTY_DASHBOARD=$DEST/cloudkitty-dashboard/cloudkittydashboard
|
||||
CLOUDKITTY_ENABLED_DIR=${CLOUDKITTY_ENABLED_DIR:-${CLOUDKITTY_DASHBOARD}/enabled}
|
||||
CLOUDKITTY_HORIZON_ENABLED_DIR=${CLOUDKITTY_HORIZON_ENABLED_DIR:-$HORIZON_DIR/openstack_dashboard/enabled}
|
||||
@ -32,6 +32,7 @@ CLOUDKITTY_SERVICE_HOST=${CLOUDKITTY_SERVICE_HOST:-$SERVICE_HOST}
|
||||
CLOUDKITTY_SERVICE_PORT=${CLOUDKITTY_SERVICE_PORT:-8889}
|
||||
CLOUDKITTY_SERVICE_HOSTPORT="$CLOUDKITTY_SERVICE_HOST:$CLOUDKITTY_SERVICE_PORT"
|
||||
CLOUDKITTY_SERVICE_PROTOCOL=${CLOUDKITTY_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL}
|
||||
CLOUDKITTY_USE_MOD_WSGI=${CLOUDKITTY_USE_MOD_WSGI:-${ENABLE_HTTPD_MOD_WSGI_SERVICES}}
|
||||
|
||||
# Set CloudKitty auth info
|
||||
CLOUDKITTY_PRICING_USER=${CLOUDKITTY_PRICING_USER:-"admin"}
|
||||
|
@ -21,6 +21,7 @@ Installation
|
||||
|
||||
devstack
|
||||
installation
|
||||
mod_wsgi
|
||||
|
||||
|
||||
Architecture
|
||||
|
@ -327,17 +327,30 @@ Start cloudkitty
|
||||
If you installed cloudkitty from packages
|
||||
-----------------------------------------
|
||||
|
||||
Start the API and processing services::
|
||||
Start the processing services::
|
||||
|
||||
systemctl start cloudkitty-api.service
|
||||
systemctl start cloudkitty-processor.service
|
||||
|
||||
If you installed cloudkitty from sources
|
||||
-----------------------------------------
|
||||
|
||||
Start the API and processing services::
|
||||
Start the processing services::
|
||||
|
||||
cloudkitty-api --config-file /etc/cloudkitty/cloudkitty.conf
|
||||
cloudkitty-processor --config-file /etc/cloudkitty/cloudkitty.conf
|
||||
|
||||
Choose and start the API server
|
||||
-------------------------------
|
||||
|
||||
Cloudkitty includes the ``cloudkitty-api`` command. It can be
|
||||
used to run the API server. For smaller or proof-of-concept
|
||||
installations this is a reasonable choice. For larger installations it
|
||||
is strongly recommended to install the API server in a WSGI host
|
||||
such as mod_wsgi (see :doc:`mod_wsgi`). Doing so will provide better
|
||||
performance and more options for making adjustments specific to the
|
||||
installation environment.
|
||||
|
||||
If you are using the ``cloudkitty-api`` command it can be started
|
||||
as::
|
||||
|
||||
$ cloudkitty-api -p 8889
|
||||
|
||||
|
53
doc/source/mod_wsgi.rst
Normal file
53
doc/source/mod_wsgi.rst
Normal file
@ -0,0 +1,53 @@
|
||||
..
|
||||
Copyright 2013 New Dream Network, LLC (DreamHost)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
not use this file except in compliance with the License. You may obtain
|
||||
a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
===================================
|
||||
Installing the API behind mod_wsgi
|
||||
===================================
|
||||
|
||||
Cloudkitty comes with a few example files for configuring the API
|
||||
service to run behind Apache with ``mod_wsgi``.
|
||||
|
||||
app.wsgi
|
||||
========
|
||||
|
||||
The file ``cloudkitty/api/app.wsgi`` sets up the V1 API WSGI
|
||||
application. The file needs to be copied to /var/www/cloudkitty/,
|
||||
and should not need to be modified.
|
||||
|
||||
etc/apache2/cloudkitty
|
||||
======================
|
||||
|
||||
The ``etc/apache2/cloudkitty`` file contains example settings that
|
||||
work with a copy of cloudkitty installed via devstack.
|
||||
|
||||
.. literalinclude:: ../../etc/apache2/cloudkitty
|
||||
|
||||
1. On deb-based systems copy or symlink the file to
|
||||
``/etc/apache2/sites-available``. For rpm-based systems the file will go in
|
||||
``/etc/httpd/conf.d``.
|
||||
|
||||
2. Modify the ``WSGIDaemonProcess`` directive to set the ``user`` and
|
||||
``group`` values to an appropriate user on your server. In many
|
||||
installations ``cloudkitty`` will be correct.
|
||||
|
||||
3. Enable the cloudkitty site. On deb-based systems::
|
||||
|
||||
$ a2ensite cloudkitty
|
||||
$ service apache2 reload
|
||||
|
||||
On rpm-based systems::
|
||||
|
||||
$ service httpd reload
|
39
etc/apache2/cloudkitty
Normal file
39
etc/apache2/cloudkitty
Normal file
@ -0,0 +1,39 @@
|
||||
# Copyright (c) 2013 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# This is an example Apache2 configuration file for using the
|
||||
# cloudkitty API through mod_wsgi.
|
||||
|
||||
# Note: If you are using a Debian-based system then the paths
|
||||
# "/var/log/httpd" and "/var/run/httpd" will use "apache2" instead
|
||||
# of "httpd".
|
||||
#
|
||||
# The number of processes and threads is an example only and should
|
||||
# be adjusted according to local requirements.
|
||||
|
||||
Listen 8889
|
||||
|
||||
<VirtualHost *:8889>
|
||||
WSGIDaemonProcess cloudkitty-api processes=2 threads=10 user=SOMEUSER display-name=%{GROUP}
|
||||
WSGIProcessGroup cloudkitty-api
|
||||
WSGIScriptAlias / /var/www/cloudkitty/app.wsgi
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
<IfVersion >= 2.4>
|
||||
ErrorLogFormat "%{cu}t %M"
|
||||
</IfVersion>
|
||||
ErrorLog /var/log/httpd/cloudkitty_error.log
|
||||
CustomLog /var/log/httpd/cloudkitty_access.log combined
|
||||
</VirtualHost>
|
||||
|
||||
WSGISocketPrefix /var/run/httpd
|
@ -24,12 +24,14 @@ packages =
|
||||
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
cloudkitty-api = cloudkitty.cli.api:main
|
||||
cloudkitty-dbsync = cloudkitty.cli.dbsync:main
|
||||
cloudkitty-processor = cloudkitty.cli.processor:main
|
||||
cloudkitty-storage-init = cloudkitty.cli.storage:main
|
||||
cloudkitty-writer = cloudkitty.cli.writer:main
|
||||
|
||||
wsgi_scripts =
|
||||
cloudkitty-api = cloudkitty.api.app:build_wsgi_app
|
||||
|
||||
oslo.config.opts =
|
||||
cloudkitty.common.config = cloudkitty.common.config:list_opts
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user