Support WSGI deployment for Tricircle Admin API(part1)

1. What is the problem
Currently Tricircle Admin API is running through python command
line and will start oslo_service wsgi server directly.

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

Completion Criteria
a). Provide WSGI application script file(s) (e.g. to be used by web
server). There shouldn't be any web server restriction and the
application could be deploying to any web server that support
WSGI applications.

b). Switch devstack jobs to deploy control-plane API services in
WSGI with Apache. Usage of Apache is already the default in Devstack,
let's keep using it for consistency unless there is some efforts to
support another web server but this is not the case at this time.

2. What is the solution for the problem
The first step is to finish these two goals:
a). Provide WSGI application script file
b). Update devstack related script in Tricircle to use Apache as
the web server.
The second step will clean and update other documentation
accordingly

3. What the features need to be implemented to the Tricircle to
realize the solution
No new feature delivered to end user.

Change-Id: I828f2d846725d18bb4a66a5d357c717e6b7d28bb
Signed-off-by: joehuang <joehuang@huawei.com>
This commit is contained in:
joehuang 2017-03-02 02:39:34 -05:00
parent 8a7ab6a581
commit 6eb93e844d
12 changed files with 209 additions and 23 deletions

View File

@ -0,0 +1,39 @@
# apache configuration template for tricircle-api
Listen %PUBLICPORT%
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %D(us)" tricircle_combined
<Directory %TRICIRCLE_BIN%>
Require all granted
</Directory>
<VirtualHost *:%PUBLICPORT%>
WSGIDaemonProcess tricircle-api processes=%APIWORKERS% threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV%
WSGIProcessGroup tricircle-api
WSGIScriptAlias / %PUBLICWSGI%
WSGIApplicationGroup %{GLOBAL}
WSGIPassAuthorization On
<IfVersion >= 2.4>
ErrorLogFormat "%M"
</IfVersion>
ErrorLog /var/log/%APACHE_NAME%/tricircle-api.log
CustomLog /var/log/%APACHE_NAME%/tricircle_access.log tricircle_combined
%SSLENGINE%
%SSLCERTFILE%
%SSLKEYFILE%
</VirtualHost>
%SSLLISTEN%<VirtualHost *:443>
%SSLLISTEN% %SSLENGINE%
%SSLLISTEN% %SSLCERTFILE%
%SSLLISTEN% %SSLKEYFILE%
%SSLLISTEN%</VirtualHost>
Alias /tricircle %PUBLICWSGI%
<Location /tricircle>
SetHandler wsgi-script
Options +ExecCGI
WSGIProcessGroup tricircle-api
WSGIApplicationGroup %{GLOBAL}
WSGIPassAuthorization On
</Location>

View File

@ -15,14 +15,20 @@ function is_tricircle_enabled {
function create_tricircle_accounts {
if [[ "$ENABLED_SERVICES" =~ "t-api" ]]; then
create_service_user "tricircle"
create_service_user "tricircle" "admin"
local tricircle_api=$(get_or_create_service "tricircle" \
"tricircle" "Cross Neutron Networking Automation Service")
local tricircle_api_url="$SERVICE_PROTOCOL://$TRICIRCLE_API_HOST/tricircle"
if [[ "$TRICIRCLE_DEPLOY_WITH_WSGI" == "False" ]]; then
tricircle_api_url="$SERVICE_PROTOCOL://$TRICIRCLE_API_HOST:$TRICIRCLE_API_PORT/"
fi
get_or_create_endpoint $tricircle_api \
"$CENTRAL_REGION_NAME" \
"$SERVICE_PROTOCOL://$TRICIRCLE_API_HOST:$TRICIRCLE_API_PORT/v1.0" \
"$SERVICE_PROTOCOL://$TRICIRCLE_API_HOST:$TRICIRCLE_API_PORT/v1.0" \
"$SERVICE_PROTOCOL://$TRICIRCLE_API_HOST:$TRICIRCLE_API_PORT/v1.0"
"$tricircle_api_url" \
"$tricircle_api_url" \
"$tricircle_api_url"
fi
}
@ -130,6 +136,68 @@ function configure_tricircle_api {
fi
}
# configure_tricircle_api_wsgi() - Set WSGI config files
function configure_tricircle_api_wsgi {
local tricircle_api_apache_conf
local venv_path=""
local tricircle_bin_dir=""
local tricircle_ssl_listen="#"
tricircle_bin_dir=$(get_python_exec_prefix)
tricircle_api_apache_conf=$(apache_site_config_for tricircle-api)
if is_ssl_enabled_service "tricircle-api"; then
tricircle_ssl_listen=""
tricircle_ssl="SSLEngine On"
tricircle_certfile="SSLCertificateFile $TRICIRCLE_SSL_CERT"
tricircle_keyfile="SSLCertificateKeyFile $TRICIRCLE_SSL_KEY"
fi
# configure venv bin if VENV is used
if [[ ${USE_VENV} = True ]]; then
venv_path="python-path=${PROJECT_VENV["tricircle"]}/lib/$(python_version)/site-packages"
tricircle_bin_dir=${PROJECT_VENV["tricircle"]}/bin
fi
sudo cp $TRICIRCLE_API_APACHE_TEMPLATE $tricircle_api_apache_conf
sudo sed -e "
s|%PUBLICPORT%|$TRICIRCLE_API_PORT|g;
s|%APACHE_NAME%|$APACHE_NAME|g;
s|%PUBLICWSGI%|$tricircle_bin_dir/tricircle-api-wsgi|g;
s|%SSLENGINE%|$tricircle_ssl|g;
s|%SSLCERTFILE%|$tricircle_certfile|g;
s|%SSLKEYFILE%|$tricircle_keyfile|g;
s|%SSLLISTEN%|$tricircle_ssl_listen|g;
s|%USER%|$STACK_USER|g;
s|%VIRTUALENV%|$venv_path|g
s|%APIWORKERS%|$API_WORKERS|g
" -i $tricircle_api_apache_conf
}
# start_tricircle_api_wsgi() - Start the API processes ahead of other things
function start_tricircle_api_wsgi {
enable_apache_site tricircle-api
restart_apache_server
tail_log tricircle-api /var/log/$APACHE_NAME/tricircle-api.log
echo "Waiting for tricircle-api to start..."
if ! wait_for_service $SERVICE_TIMEOUT $TRICIRCLE_API_PROTOCOL://$TRICIRCLE_API_HOST/tricircle; then
die $LINENO "tricircle-api did not start"
fi
}
# stop_tricircle_api_wsgi() - Disable the api service and stop it.
function stop_tricircle_api_wsgi {
disable_apache_site tricircle-api
restart_apache_server
}
# cleanup_tricircle_api_wsgi() - Remove residual data files, anything left over from previous
# runs that a clean run would need to clean up
function cleanup_tricircle_api_wsgi {
sudo rm -f $(apache_site_config_for tricircle-api)
}
function configure_tricircle_xjob {
if is_service_enabled t-job ; then
echo "Configuring Tricircle xjob"
@ -214,6 +282,10 @@ elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
enable_service t-api t-job
configure_tricircle_api
configure_tricircle_xjob
if [[ "$TRICIRCLE_DEPLOY_WITH_WSGI" == "True" ]]; then
configure_tricircle_api_wsgi
fi
fi
echo export PYTHONPATH=\$PYTHONPATH:$TRICIRCLE_DIR >> $RC_DIR/.localrc.auto
@ -243,12 +315,14 @@ elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
create_tricircle_accounts
run_process t-api "tricircle-api --config-file $TRICIRCLE_API_CONF"
if [[ "$TRICIRCLE_DEPLOY_WITH_WSGI" == "True" ]]; then
start_tricircle_api_wsgi
else
run_process t-api "tricircle-api --config-file $TRICIRCLE_API_CONF"
fi
fi
if is_service_enabled t-job; then
run_process t-job "tricircle-xjob --config-file $TRICIRCLE_XJOB_CONF"
fi
fi
@ -256,7 +330,12 @@ fi
if [[ "$1" == "unstack" ]]; then
if is_service_enabled t-api; then
stop_process t-api
if [[ "$TRICIRCLE_DEPLOY_WITH_WSGI" == "True" ]]; then
stop_tricircle_api_wsgi
clean_tricircle_api_wsgi
else
stop_process t-api
fi
fi
if is_service_enabled t-job; then

View File

@ -7,6 +7,7 @@ TRICIRCLE_BRANCH=${TRICIRCLE_BRANCH:-master}
CENTRAL_REGION_NAME=${CENTRAL_REGION_NAME:-CentralRegion}
TRICIRCLE_NEUTRON_PORT=${TRICIRCLE_NEUTRON_PORT:-20001}
TRICIRCLE_START_SERVICES=${TRICIRCLE_START_SERVICES:-True}
TRICIRCLE_DEPLOY_WITH_WSGI=${TRICIRCLE_DEPLOY_WITH_WSGI:-True}
# these default settings are used for devstack based gate/check jobs
TRICIRCLE_DEFAULT_VLAN_BRIDGE=${TRICIRCLE_DEFAULT_VLAN_BRIDGE:-br-vlan}
@ -20,7 +21,9 @@ TRICIRCLE_CONF_DIR=${TRICIRCLE_CONF_DIR:-/etc/tricircle}
TRICIRCLE_STATE_PATH=${TRICIRCLE_STATE_PATH:-/var/lib/tricircle}
# tricircle rest admin api
TRICIRCLE_API=$TRICIRCLE_DIR/tricircle/cmd/api.py
TRICIRCLE_API_CONF=$TRICIRCLE_CONF_DIR/api.conf
TRICIRCLE_API_APACHE_TEMPLATE=$TRICIRCLE_DIR/devstack/apache-tricircle-api.template
TRICIRCLE_API_LISTEN_ADDRESS=${TRICIRCLE_API_LISTEN_ADDRESS:-0.0.0.0}
TRICIRCLE_API_HOST=${TRICIRCLE_API_HOST:-$SERVICE_HOST}

View File

@ -47,13 +47,13 @@ token=$(openstack token issue | awk 'NR==5 {print $4}')
echo $token
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "RegionOne"}}'
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "Pod1", "az_name": "az1"}}'
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "Pod2", "az_name": "az2"}}'
echo "******************************"

View File

@ -43,10 +43,10 @@ token=$(openstack token issue | awk 'NR==5 {print $4}')
echo $token
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "RegionOne"}}'
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "Pod1", "az_name": "az1"}}'
echo "******************************"

View File

@ -25,8 +25,8 @@ the OpenStack Identity service. They also require a base service url that can
be got from the OpenStack Tricircle endpoint. This will be the root url that
every call below will be added to build a full path.
For instance, if the Tricircle service url is http://127.0.0.1:19999/v1.0 then
the full API call for /pods is http://127.0.0.1:19999/v1.0/pods.
For instance, if the Tricircle service url is http://127.0.0.1/tricircle/v1.0
then the full API call for /pods is http://127.0.0.1/tricircle/v1.0/pods.
As such, for the rest of this document we will leave out the root url where
GET /pods really means GET {tricircle_service_url}/pods.

View File

@ -265,13 +265,13 @@ How to play
- 5 Create pod instances for the Tricircle to manage the mapping between
availability zones and OpenStack instances, "$token" is obtained in step 4 ::
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "CentralRegion"}}'
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "RegionOne", "az_name": "az1"}}'
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "RegionTwo", "az_name": "az2"}}'
Pay attention to "region_name" parameter we specify when creating pod. Pod name

View File

@ -67,10 +67,10 @@ installing DevStack in virtual machine.
availability zone and OpenStack instances, the "$token" is obtained in the
step 7::
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "CentralRegion"}}'
curl -X POST http://127.0.0.1:19999/v1.0/pods -H "Content-Type: application/json" \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods -H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "RegionOne", "az_name": "az1"}}'
Pay attention to "region_name" parameter we specify when creating pod. Pod name

View File

@ -0,0 +1,6 @@
---
prelude: >
Tricircle Admin API now supports WSGI deployment. The endpoint of
Tricircle Admin API could be accessed via the format of
http://host/tricircle, and no need to expose special port, thus
reduce the risk of port management.

View File

@ -45,9 +45,11 @@ output_file = tricircle/locale/tricircle.pot
[entry_points]
console_scripts =
tricircle-db-manage = tricircle.cmd.manage:main
tricircle-api = tricircle.cmd.api:main
tricircle-db-manage = tricircle.cmd.manage:main
tricircle-xjob = tricircle.cmd.xjob:main
wsgi_scripts =
tricircle-api-wsgi = tricircle.api.wsgi:init_application
oslo.config.opts =
tricircle.api = tricircle.api.opts:list_opts
tricircle.common = tricircle.common.opts:list_opts

57
tricircle/api/wsgi.py Normal file
View File

@ -0,0 +1,57 @@
# Copyright (c) 2017 Huawei Tech. Co,. Ltd.
# All Rights Reserved.
#
# 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.
"""WSGI script for Tricircle API
WSGI handler for running Tricircle API under Apache2, nginx, gunicorn etc.
Community wide goal in Pike:
https://governance.openstack.org/tc/goals/pike/deploy-api-in-wsgi.html
"""
import os
import os.path
from oslo_config import cfg
from oslo_log import log as logging
from tricircle.api import app
from tricircle.common import config
from tricircle.common.i18n import _LI
CONFIG_FILE = 'api.conf'
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
def _get_config_file(env=None):
if env is None:
env = os.environ
dir_name = env.get('TRICIRCLE_CONF_DIR', '/etc/tricircle').strip()
return os.path.join(dir_name, CONFIG_FILE)
def init_application():
# initialize the config system
conf_file = _get_config_file()
config.init(app.common_opts, ['--config-file', conf_file])
LOG.info(_LI("Configuration:"))
CONF.log_opt_values(LOG, logging.INFO)
# return WSGI app
return app.setup_app()

View File

@ -28,11 +28,11 @@ source $DEVSTACK_DIR/openrc admin admin
token=$(openstack token issue | awk 'NR==5 {print $4}')
echo $token
curl -X POST http://127.0.0.1:19999/v1.0/pods \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods \
-H "Content-Type: application/json" \
-H "X-Auth-Token: $token" -d '{"pod": {"region_name": "RegionOne"}}'
curl -X POST http://127.0.0.1:19999/v1.0/pods \
curl -X POST http://127.0.0.1/tricircle/v1.0/pods \
-H "Content-Type: application/json" \
-H "X-Auth-Token: $token" \
-d '{"pod": {"region_name": "Pod1", "az_name": "az1"}}'