Initial patch for Trircle stateless architecture
Initial patch to implement the framework of Tricircle, this is the part for Nova api gateway and Cinder api gateway, keystone authentication integrated. Change-Id: I7e33948d4850cf1eabeb9c865fc79c2475323988 Blueprint: https://blueprints.launchpad.net/tricircle/+spec/implement-stateless
This commit is contained in:
parent
fe14b6f244
commit
1aad4ae585
|
@ -27,6 +27,7 @@ from tricircle.api import app
|
|||
from tricircle.common import config
|
||||
from tricircle.common.i18n import _LI
|
||||
from tricircle.common.i18n import _LW
|
||||
from tricircle.common import restapp
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -45,16 +46,16 @@ def main():
|
|||
LOG.warning(_LW("Wrong worker number, worker = %(workers)s"), workers)
|
||||
workers = 1
|
||||
|
||||
LOG.info(_LI("Server on http://%(host)s:%(port)s with %(workers)s"),
|
||||
LOG.info(_LI("Admin API on http://%(host)s:%(port)s with %(workers)s"),
|
||||
{'host': host, 'port': port, 'workers': workers})
|
||||
|
||||
service = wsgi.Server(CONF, 'Tricircle', application, host, port)
|
||||
app.serve(service, CONF, workers)
|
||||
service = wsgi.Server(CONF, 'Tricircle Admin_API', application, host, port)
|
||||
restapp.serve(service, CONF, workers)
|
||||
|
||||
LOG.info(_LI("Configuration:"))
|
||||
CONF.log_opt_values(LOG, std_logging.INFO)
|
||||
|
||||
app.wait()
|
||||
restapp.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
# Copyright 2015 Huawei Technologies 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.
|
||||
|
||||
# Much of this module is based on the work of the Ironic team
|
||||
# see http://git.openstack.org/cgit/openstack/ironic/tree/ironic/cmd/api.py
|
||||
|
||||
import logging as std_logging
|
||||
import sys
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import wsgi
|
||||
|
||||
from tricircle.common import config
|
||||
from tricircle.common.i18n import _LI
|
||||
from tricircle.common.i18n import _LW
|
||||
from tricircle.common import restapp
|
||||
|
||||
from tricircle.cinder_apigw import app
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def main():
|
||||
config.init(app.common_opts, sys.argv[1:])
|
||||
application = app.setup_app()
|
||||
|
||||
host = CONF.bind_host
|
||||
port = CONF.bind_port
|
||||
workers = CONF.api_workers
|
||||
|
||||
if workers < 1:
|
||||
LOG.warning(_LW("Wrong worker number, worker = %(workers)s"), workers)
|
||||
workers = 1
|
||||
|
||||
LOG.info(_LI("Cinder_APIGW on http://%(host)s:%(port)s with %(workers)s"),
|
||||
{'host': host, 'port': port, 'workers': workers})
|
||||
|
||||
service = wsgi.Server(CONF, 'Tricircle Cinder_APIGW',
|
||||
application, host, port)
|
||||
restapp.serve(service, CONF, workers)
|
||||
|
||||
LOG.info(_LI("Configuration:"))
|
||||
CONF.log_opt_values(LOG, std_logging.INFO)
|
||||
|
||||
restapp.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,63 @@
|
|||
# Copyright 2015 Huawei Technologies 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.
|
||||
|
||||
# Much of this module is based on the work of the Ironic team
|
||||
# see http://git.openstack.org/cgit/openstack/ironic/tree/ironic/cmd/api.py
|
||||
|
||||
import logging as std_logging
|
||||
import sys
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import wsgi
|
||||
|
||||
from tricircle.common import config
|
||||
from tricircle.common.i18n import _LI
|
||||
from tricircle.common.i18n import _LW
|
||||
from tricircle.common import restapp
|
||||
|
||||
from tricircle.nova_apigw import app
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def main():
|
||||
config.init(app.common_opts, sys.argv[1:])
|
||||
application = app.setup_app()
|
||||
|
||||
host = CONF.bind_host
|
||||
port = CONF.bind_port
|
||||
workers = CONF.api_workers
|
||||
|
||||
if workers < 1:
|
||||
LOG.warning(_LW("Wrong worker number, worker = %(workers)s"), workers)
|
||||
workers = 1
|
||||
|
||||
LOG.info(_LI("Nova_APIGW on http://%(host)s:%(port)s with %(workers)s"),
|
||||
{'host': host, 'port': port, 'workers': workers})
|
||||
|
||||
service = wsgi.Server(CONF, 'Tricircle Nova_APIGW',
|
||||
application, host, port)
|
||||
restapp.serve(service, CONF, workers)
|
||||
|
||||
LOG.info(_LI("Configuration:"))
|
||||
CONF.log_opt_values(LOG, std_logging.INFO)
|
||||
|
||||
restapp.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -29,10 +29,12 @@ PUBLIC_NETWORK_GATEWAY=10.100.100.3
|
|||
|
||||
|
||||
Q_ENABLE_TRICIRCLE=True
|
||||
enable_plugin tricircle https://git.openstack.org/openstack/tricircle master
|
||||
enable_plugin tricircle https://github.com/openstack/tricircle/ experiment
|
||||
|
||||
# Tricircle Services
|
||||
enable_service t-api
|
||||
enable_service t-ngw
|
||||
enable_service t-cgw
|
||||
|
||||
# Use Neutron instead of nova-network
|
||||
disable_service n-net
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Test if any tricircle services are enabled
|
||||
# is_tricircle_enabled
|
||||
function is_tricircle_enabled {
|
||||
[[ ,${ENABLED_SERVICES} =~ ,"t-" ]] && return 0
|
||||
[[ ,${ENABLED_SERVICES} =~ ,"t-api" ]] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ function create_tricircle_accounts {
|
|||
local tricircle_api=$(get_or_create_service "tricircle" \
|
||||
"Cascading" "OpenStack Cascading Service")
|
||||
get_or_create_endpoint $tricircle_api \
|
||||
"$REGION_NAME" \
|
||||
"$TRICIRCLE_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"
|
||||
|
@ -29,6 +29,52 @@ function create_tricircle_accounts {
|
|||
fi
|
||||
}
|
||||
|
||||
# create_nova_apigw_accounts() - Set up common required nova_apigw
|
||||
# work as nova api serice
|
||||
# service accounts in keystone
|
||||
# Project User Roles
|
||||
# -----------------------------------------------------------------
|
||||
# $SERVICE_TENANT_NAME nova_apigw service
|
||||
|
||||
function create_nova_apigw_accounts {
|
||||
if [[ "$ENABLED_SERVICES" =~ "t-ngw" ]]; then
|
||||
create_service_user "nova_apigw"
|
||||
|
||||
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
|
||||
local tricircle_nova_apigw=$(get_or_create_service "nova" \
|
||||
"compute" "Nova Compute Service")
|
||||
get_or_create_endpoint $tricircle_nova_apigw \
|
||||
"$TRICIRCLE_REGION_NAME" \
|
||||
"$SERVICE_PROTOCOL://$TRICIRCLE_NOVA_APIGW_HOST:$TRICIRCLE_NOVA_APIGW_PORT/v2.1/" \
|
||||
"$SERVICE_PROTOCOL://$TRICIRCLE_NOVA_APIGW_HOST:$TRICIRCLE_NOVA_APIGW_PORT/v2.1/" \
|
||||
"$SERVICE_PROTOCOL://$TRICIRCLE_NOVA_APIGW_HOST:$TRICIRCLE_NOVA_APIGW_PORT/v2.1/"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# create_cinder_apigw_accounts() - Set up common required cinder_apigw
|
||||
# work as cinder api serice
|
||||
# service accounts in keystone
|
||||
# Project User Roles
|
||||
# ---------------------------------------------------------------------
|
||||
# $SERVICE_TENANT_NAME cinder_apigw service
|
||||
|
||||
function create_cinder_apigw_accounts {
|
||||
if [[ "$ENABLED_SERVICES" =~ "t-cgw" ]]; then
|
||||
create_service_user "cinder_apigw"
|
||||
|
||||
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
|
||||
local tricircle_cinder_apigw=$(get_or_create_service "cinder" \
|
||||
"volume" "Cinder Volume Service")
|
||||
get_or_create_endpoint $tricircle_cinder_apigw \
|
||||
"$TRICIRCLE_REGION_NAME" \
|
||||
"$SERVICE_PROTOCOL://$TRICIRCLE_CINDER_APIGW_HOST:$TRICIRCLE_CINDER_APIGW_PORT/v2/" \
|
||||
"$SERVICE_PROTOCOL://$TRICIRCLE_CINDER_APIGW_HOST:$TRICIRCLE_CINDER_APIGW_PORT/v2/" \
|
||||
"$SERVICE_PROTOCOL://$TRICIRCLE_CINDER_APIGW_HOST:$TRICIRCLE_CINDER_APIGW_PORT/v2/"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# create_tricircle_cache_dir() - Set up cache dir for tricircle
|
||||
function create_tricircle_cache_dir {
|
||||
|
||||
|
@ -53,7 +99,7 @@ function configure_tricircle_api {
|
|||
iniset $TRICIRCLE_API_CONF client admin_password $ADMIN_PASSWORD
|
||||
iniset $TRICIRCLE_API_CONF client admin_tenant demo
|
||||
iniset $TRICIRCLE_API_CONF client auto_refresh_endpoint True
|
||||
iniset $TRICIRCLE_API_CONF client top_site_name $OS_REGION_NAME
|
||||
iniset $TRICIRCLE_API_CONF client top_site_name $TRICIRCLE_REGION_NAME
|
||||
|
||||
iniset $TRICIRCLE_API_CONF oslo_concurrency lock_path $TRICIRCLE_STATE_PATH/lock
|
||||
|
||||
|
@ -74,22 +120,79 @@ function configure_tricircle_api {
|
|||
fi
|
||||
}
|
||||
|
||||
function configure_tricircle_nova_apigw {
|
||||
if is_service_enabled t-ngw ; then
|
||||
echo "Configuring Tricircle Nova APIGW"
|
||||
|
||||
touch $TRICIRCLE_NOVA_APIGW_CONF
|
||||
iniset $TRICIRCLE_NOVA_APIGW_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
|
||||
iniset $TRICIRCLE_NOVA_APIGW_CONF DEFAULT verbose True
|
||||
iniset $TRICIRCLE_NOVA_APIGW_CONF DEFAULT use_syslog $SYSLOG
|
||||
iniset $TRICIRCLE_NOVA_APIGW_CONF database connection `database_connection_url tricircle`
|
||||
|
||||
iniset $TRICIRCLE_NOVA_APIGW_CONF oslo_concurrency lock_path $TRICIRCLE_STATE_PATH/lock
|
||||
|
||||
setup_colorized_logging $TRICIRCLE_NOVA_APIGW_CONF DEFAULT tenant_name
|
||||
|
||||
if is_service_enabled keystone; then
|
||||
|
||||
create_tricircle_cache_dir
|
||||
|
||||
# Configure auth token middleware
|
||||
configure_auth_token_middleware $TRICIRCLE_NOVA_APIGW_CONF tricircle \
|
||||
$TRICIRCLE_AUTH_CACHE_DIR
|
||||
|
||||
else
|
||||
iniset $TRICIRCLE_NOVA_APIGW_CONF DEFAULT auth_strategy noauth
|
||||
fi
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function configure_tricircle_cinder_apigw {
|
||||
if is_service_enabled t-cgw ; then
|
||||
echo "Configuring Tricircle Cinder APIGW"
|
||||
|
||||
touch $TRICIRCLE_CINDER_APIGW_CONF
|
||||
iniset $TRICIRCLE_CINDER_APIGW_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
|
||||
iniset $TRICIRCLE_CINDER_APIGW_CONF DEFAULT verbose True
|
||||
iniset $TRICIRCLE_CINDER_APIGW_CONF DEFAULT use_syslog $SYSLOG
|
||||
iniset $TRICIRCLE_CINDER_APIGW_CONF database connection `database_connection_url tricircle`
|
||||
|
||||
iniset $TRICIRCLE_CINDER_APIGW_CONF oslo_concurrency lock_path $TRICIRCLE_STATE_PATH/lock
|
||||
|
||||
setup_colorized_logging $TRICIRCLE_CINDER_APIGW_CONF DEFAULT tenant_name
|
||||
|
||||
if is_service_enabled keystone; then
|
||||
|
||||
create_tricircle_cache_dir
|
||||
|
||||
# Configure auth token middleware
|
||||
configure_auth_token_middleware $TRICIRCLE_CINDER_APIGW_CONF tricircle \
|
||||
$TRICIRCLE_AUTH_CACHE_DIR
|
||||
|
||||
else
|
||||
iniset $TRICIRCLE_CINDER_APIGW_CONF DEFAULT auth_strategy noauth
|
||||
fi
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
if [[ "$Q_ENABLE_TRICIRCLE" == "True" ]]; then
|
||||
if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then
|
||||
echo summary "Tricircle pre-install"
|
||||
elif [[ "$1" == "stack" && "$2" == "install" ]]; then
|
||||
echo_summary "Installing Tricircle"
|
||||
|
||||
git_clone $TRICIRCLE_REPO $TRICIRCLE_DIR $TRICIRCLE_BRANCH
|
||||
|
||||
|
||||
elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
|
||||
echo_summary "Configuring Tricircle"
|
||||
|
||||
sudo install -d -o $STACK_USER -m 755 $TRICIRCLE_CONF_DIR
|
||||
|
||||
configure_tricircle_api
|
||||
configure_tricircle_nova_apigw
|
||||
configure_tricircle_cinder_apigw
|
||||
|
||||
echo export PYTHONPATH=\$PYTHONPATH:$TRICIRCLE_DIR >> $RC_DIR/.localrc.auto
|
||||
|
||||
|
@ -105,6 +208,20 @@ if [[ "$Q_ENABLE_TRICIRCLE" == "True" ]]; then
|
|||
|
||||
run_process t-api "python $TRICIRCLE_API --config-file $TRICIRCLE_API_CONF"
|
||||
fi
|
||||
|
||||
if is_service_enabled t-ngw; then
|
||||
|
||||
create_nova_apigw_accounts
|
||||
|
||||
run_process t-ngw "python $TRICIRCLE_NOVA_APIGW --config-file $TRICIRCLE_NOVA_APIGW_CONF"
|
||||
fi
|
||||
|
||||
if is_service_enabled t-cgw; then
|
||||
|
||||
create_cinder_apigw_accounts
|
||||
|
||||
run_process t-cgw "python $TRICIRCLE_CINDER_APIGW --config-file $TRICIRCLE_CINDER_APIGW_CONF"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$1" == "unstack" ]]; then
|
||||
|
@ -112,5 +229,13 @@ if [[ "$Q_ENABLE_TRICIRCLE" == "True" ]]; then
|
|||
if is_service_enabled t-api; then
|
||||
stop_process t-api
|
||||
fi
|
||||
|
||||
if is_service_enabled t-ngw; then
|
||||
stop_process t-ngw
|
||||
fi
|
||||
|
||||
if is_service_enabled t-cgw; then
|
||||
stop_process t-cgw
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
# Git information
|
||||
TRICIRCLE_REPO=${TRICIRCLE_REPO:-https://git.openstack.org/cgit/openstack/tricircle/}
|
||||
TRICIRCLE_DIR=$DEST/tricircle
|
||||
TRICIRCLE_BRANCH=${TRICIRCLE_BRANCH:-master}
|
||||
TRICIRCLE_BRANCH=${TRICIRCLE_BRANCH:-experiment}
|
||||
|
||||
# common variables
|
||||
TRICIRCLE_REGION_NAME=${TRICIRCLE_REGION_NAME:-TopRegion}
|
||||
TRICIRCLE_CONF_DIR=${TRICIRCLE_CONF_DIR:-/etc/tricircle}
|
||||
TRICIRCLE_STATE_PATH=${TRICIRCLE_STATE_PATH:-/var/lib/tricircle}
|
||||
|
||||
# tricircle rest api
|
||||
# tricircle rest admin api
|
||||
TRICIRCLE_API=$TRICIRCLE_DIR/cmd/api.py
|
||||
TRICIRCLE_API_CONF=$TRICIRCLE_CONF_DIR/api.conf
|
||||
|
||||
|
@ -16,6 +17,24 @@ TRICIRCLE_API_HOST=${TRICIRCLE_API_HOST:-$SERVICE_HOST}
|
|||
TRICIRCLE_API_PORT=${TRICIRCLE_API_PORT:-19999}
|
||||
TRICIRCLE_API_PROTOCOL=${TRICIRCLE_API_PROTOCOL:-$SERVICE_PROTOCOL}
|
||||
|
||||
# tricircle nova_apigw
|
||||
TRICIRCLE_NOVA_APIGW=$TRICIRCLE_DIR/cmd/nova_apigw.py
|
||||
TRICIRCLE_NOVA_APIGW_CONF=$TRICIRCLE_CONF_DIR/nova_apigw.conf
|
||||
|
||||
TRICIRCLE_NOVA_APIGW_LISTEN_ADDRESS=${TRICIRCLE_NOVA_APIGW_LISTEN_ADDRESS:-0.0.0.0}
|
||||
TRICIRCLE_NOVA_APIGW_HOST=${TRICIRCLE_NOVA_APIGW_HOST:-$SERVICE_HOST}
|
||||
TRICIRCLE_NOVA_APIGW_PORT=${TRICIRCLE_NOVA_APIGW_PORT:-19998}
|
||||
TRICIRCLE_NOVA_APIGW_PROTOCOL=${TRICIRCLE_NOVA_APIGW_PROTOCOL:-$SERVICE_PROTOCOL}
|
||||
|
||||
# tricircle cinder_apigw
|
||||
TRICIRCLE_CINDER_APIGW=$TRICIRCLE_DIR/cmd/cinder_apigw.py
|
||||
TRICIRCLE_CINDER_APIGW_CONF=$TRICIRCLE_CONF_DIR/cinder_apigw.conf
|
||||
|
||||
TRICIRCLE_CINDER_APIGW_LISTEN_ADDRESS=${TRICIRCLE_CINDER_APIGW_LISTEN_ADDRESS:-0.0.0.0}
|
||||
TRICIRCLE_CINDER_APIGW_HOST=${TRICIRCLE_CINDER_APIGW_HOST:-$SERVICE_HOST}
|
||||
TRICIRCLE_CINDER_APIGW_PORT=${TRICIRCLE_CINDER_APIGW_PORT:-19997}
|
||||
TRICIRCLE_CINDER_APIGW_PROTOCOL=${TRICIRCLE_CINDER_APIGW_PROTOCOL:-$SERVICE_PROTOCOL}
|
||||
|
||||
TRICIRCLE_AUTH_CACHE_DIR=${TRICIRCLE_AUTH_CACHE_DIR:-/var/cache/tricircle}
|
||||
|
||||
export PYTHONPATH=$PYTHONPATH:$TRICIRCLE_DIR
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
[DEFAULT]
|
||||
output_file = etc/cinder_apigw.conf.sample
|
||||
wrap_width = 79
|
||||
namespace = tricircle.cinder_apigw
|
||||
namespace = oslo.log
|
||||
namespace = oslo.messaging
|
||||
namespace = oslo.policy
|
||||
namespace = oslo.service.periodic_task
|
||||
namespace = oslo.service.service
|
||||
namespace = oslo.service.sslutils
|
||||
namespace = oslo.db
|
||||
namespace = oslo.middleware
|
||||
namespace = oslo.concurrency
|
||||
namespace = keystonemiddleware.auth_token
|
|
@ -0,0 +1,14 @@
|
|||
[DEFAULT]
|
||||
output_file = etc/nova_apigw.conf.sample
|
||||
wrap_width = 79
|
||||
namespace = tricircle.nova_apigw
|
||||
namespace = oslo.log
|
||||
namespace = oslo.messaging
|
||||
namespace = oslo.policy
|
||||
namespace = oslo.service.periodic_task
|
||||
namespace = oslo.service.service
|
||||
namespace = oslo.service.sslutils
|
||||
namespace = oslo.db
|
||||
namespace = oslo.middleware
|
||||
namespace = oslo.concurrency
|
||||
namespace = keystonemiddleware.auth_token
|
|
@ -14,10 +14,10 @@ pecan>=1.0.0
|
|||
greenlet>=0.3.2
|
||||
httplib2>=0.7.5
|
||||
requests!=2.8.0,>=2.5.2
|
||||
Werkzeug>=0.7 # BSD License
|
||||
Jinja2>=2.8 # BSD License (3 clause)
|
||||
keystonemiddleware!=2.4.0,>=2.0.0
|
||||
netaddr!=0.7.16,>=0.7.12
|
||||
netifaces>=0.10.4
|
||||
retrying!=1.3.0,>=1.2.3 # Apache-2.0
|
||||
SQLAlchemy<1.1.0,>=0.9.9
|
||||
WebOb>=1.2.3
|
||||
|
@ -43,5 +43,4 @@ oslo.serialization>=1.10.0 # Apache-2.0
|
|||
oslo.service>=0.12.0 # Apache-2.0
|
||||
oslo.utils!=2.6.0,>=2.4.0 # Apache-2.0
|
||||
oslo.versionedobjects>=0.9.0
|
||||
SQLAlchemy<1.1.0,>=0.9.9
|
||||
sqlalchemy-migrate>=0.9.6
|
||||
|
|
|
@ -49,3 +49,7 @@ output_file = tricircle/locale/tricircle.pot
|
|||
oslo.config.opts =
|
||||
tricircle.api = tricircle.api.opts:list_opts
|
||||
tricircle.client = tricircle.common.opts:list_opts
|
||||
|
||||
tricircle.nova_apigw = tricircle.nova_apigw.opts:list_opts
|
||||
|
||||
tricircle.cinder_apigw = tricircle.cinder_apigw.opts:list_opts
|
||||
|
|
|
@ -13,14 +13,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystonemiddleware import auth_token
|
||||
from oslo_config import cfg
|
||||
from oslo_middleware import request_id
|
||||
from oslo_service import service
|
||||
import pecan
|
||||
|
||||
import tricircle.common.exceptions as t_exc
|
||||
from oslo_config import cfg
|
||||
|
||||
from tricircle.common.i18n import _
|
||||
from tricircle.common import restapp
|
||||
|
||||
|
||||
common_opts = [
|
||||
|
@ -69,41 +67,10 @@ def setup_app(*args, **kwargs):
|
|||
app = pecan.make_app(
|
||||
pecan_config.app.root,
|
||||
debug=False,
|
||||
wrap_app=_wrap_app,
|
||||
wrap_app=restapp.auth_app,
|
||||
force_canonical=False,
|
||||
hooks=[],
|
||||
guess_content_type_from_ext=True
|
||||
)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
def _wrap_app(app):
|
||||
app = request_id.RequestId(app)
|
||||
|
||||
if cfg.CONF.auth_strategy == 'noauth':
|
||||
pass
|
||||
elif cfg.CONF.auth_strategy == 'keystone':
|
||||
# NOTE(zhiyuan) pkg_resources will try to load tricircle to get module
|
||||
# version, passing "project" as empty string to bypass it
|
||||
app = auth_token.AuthProtocol(app, {'project': ''})
|
||||
else:
|
||||
raise t_exc.InvalidConfigurationOption(
|
||||
opt_name='auth_strategy', opt_value=cfg.CONF.auth_strategy)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
_launcher = None
|
||||
|
||||
|
||||
def serve(api_service, conf, workers=1):
|
||||
global _launcher
|
||||
if _launcher:
|
||||
raise RuntimeError(_('serve() can only be called once'))
|
||||
|
||||
_launcher = service.launch(conf, api_service, workers=workers)
|
||||
|
||||
|
||||
def wait():
|
||||
_launcher.wait()
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
# Copyright (c) 2015 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.
|
||||
|
||||
import pecan
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from tricircle.common.i18n import _
|
||||
from tricircle.common import restapp
|
||||
|
||||
|
||||
common_opts = [
|
||||
cfg.StrOpt('bind_host', default='0.0.0.0',
|
||||
help=_("The host IP to bind to")),
|
||||
cfg.IntOpt('bind_port', default=19997,
|
||||
help=_("The port to bind to")),
|
||||
cfg.IntOpt('api_workers', default=1,
|
||||
help=_("number of api workers")),
|
||||
cfg.StrOpt('api_extensions_path', default="",
|
||||
help=_("The path for API extensions")),
|
||||
cfg.StrOpt('auth_strategy', default='keystone',
|
||||
help=_("The type of authentication to use")),
|
||||
cfg.BoolOpt('allow_bulk', default=True,
|
||||
help=_("Allow the usage of the bulk API")),
|
||||
cfg.BoolOpt('allow_pagination', default=False,
|
||||
help=_("Allow the usage of the pagination")),
|
||||
cfg.BoolOpt('allow_sorting', default=False,
|
||||
help=_("Allow the usage of the sorting")),
|
||||
cfg.StrOpt('pagination_max_limit', default="-1",
|
||||
help=_("The maximum number of items returned in a single "
|
||||
"response, value was 'infinite' or negative integer "
|
||||
"means no limit")),
|
||||
]
|
||||
|
||||
|
||||
def setup_app(*args, **kwargs):
|
||||
config = {
|
||||
'server': {
|
||||
'port': cfg.CONF.bind_port,
|
||||
'host': cfg.CONF.bind_host
|
||||
},
|
||||
'app': {
|
||||
'root': 'tricircle.cinder_apigw.controllers.root.RootController',
|
||||
'modules': ['tricircle.cinder_apigw'],
|
||||
'errors': {
|
||||
400: '/error',
|
||||
'__force_dict__': True
|
||||
}
|
||||
}
|
||||
}
|
||||
pecan_config = pecan.configuration.conf_from_dict(config)
|
||||
|
||||
# app_hooks = [], hook collection will be put here later
|
||||
|
||||
app = pecan.make_app(
|
||||
pecan_config.app.root,
|
||||
debug=False,
|
||||
wrap_app=restapp.auth_app,
|
||||
force_canonical=False,
|
||||
hooks=[],
|
||||
guess_content_type_from_ext=True
|
||||
)
|
||||
|
||||
return app
|
|
@ -0,0 +1,108 @@
|
|||
# Copyright (c) 2015 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.
|
||||
|
||||
import pecan
|
||||
|
||||
import oslo_log.log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RootController(object):
|
||||
|
||||
@pecan.expose()
|
||||
def _lookup(self, version, *remainder):
|
||||
if version == 'v2':
|
||||
return V2Controller(), remainder
|
||||
|
||||
@pecan.expose(generic=True, template='json')
|
||||
def index(self):
|
||||
return {
|
||||
"versions": [
|
||||
{
|
||||
"status": "CURRENT",
|
||||
"updated": "2012-11-21T11:33:21Z",
|
||||
"id": "v2.0",
|
||||
"links": [
|
||||
{
|
||||
"href": pecan.request.application_url + "/v2/",
|
||||
"rel": "self"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@index.when(method='POST')
|
||||
@index.when(method='PUT')
|
||||
@index.when(method='DELETE')
|
||||
@index.when(method='HEAD')
|
||||
@index.when(method='PATCH')
|
||||
def not_supported(self):
|
||||
pecan.abort(405)
|
||||
|
||||
|
||||
class V2Controller(object):
|
||||
|
||||
_media_type1 = "application/vnd.openstack.volume+xml;version=1"
|
||||
_media_type2 = "application/vnd.openstack.volume+json;version=1"
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.sub_controllers = {
|
||||
|
||||
}
|
||||
|
||||
for name, ctrl in self.sub_controllers.items():
|
||||
setattr(self, name, ctrl)
|
||||
|
||||
@pecan.expose(generic=True, template='json')
|
||||
def index(self):
|
||||
return {
|
||||
"version": {
|
||||
"status": "CURRENT",
|
||||
"updated": "2012-11-21T11:33:21Z",
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": self._media_type1
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": self._media_type2
|
||||
}
|
||||
],
|
||||
"id": "v2.0",
|
||||
"links": [
|
||||
{
|
||||
"href": pecan.request.application_url + "/v2/",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://docs.openstack.org/",
|
||||
"type": "text/html",
|
||||
"rel": "describedby"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@index.when(method='POST')
|
||||
@index.when(method='PUT')
|
||||
@index.when(method='DELETE')
|
||||
@index.when(method='HEAD')
|
||||
@index.when(method='PATCH')
|
||||
def not_supported(self):
|
||||
pecan.abort(405)
|
|
@ -0,0 +1,22 @@
|
|||
# Copyright 2015 Huawei Technologies 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.
|
||||
|
||||
import tricircle.cinder_apigw.app
|
||||
|
||||
|
||||
def list_opts():
|
||||
return [
|
||||
('DEFAULT', tricircle.cinder_apigw.app.common_opts),
|
||||
]
|
|
@ -40,7 +40,7 @@ def init(opts, args, **kwargs):
|
|||
logging.register_options(cfg.CONF)
|
||||
|
||||
cfg.CONF(args=args, project='tricircle',
|
||||
version='%%(prog)s %s' % version.version_info.release_string(),
|
||||
version=version.version_info,
|
||||
**kwargs)
|
||||
|
||||
_setup_logging()
|
||||
|
@ -53,7 +53,7 @@ def _setup_logging():
|
|||
LOG.info(_LI("Logging enabled!"))
|
||||
LOG.info(_LI("%(prog)s version %(version)s"),
|
||||
{'prog': sys.argv[0],
|
||||
'version': version.version_info.release_string()})
|
||||
'version': version.version_info})
|
||||
LOG.debug("command line: %s", " ".join(sys.argv))
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# 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.
|
||||
|
||||
from keystonemiddleware import auth_token
|
||||
from oslo_config import cfg
|
||||
from oslo_middleware import request_id
|
||||
from oslo_service import service
|
||||
|
||||
import exceptions as t_exc
|
||||
from i18n import _
|
||||
|
||||
|
||||
def auth_app(app):
|
||||
app = request_id.RequestId(app)
|
||||
|
||||
if cfg.CONF.auth_strategy == 'noauth':
|
||||
pass
|
||||
elif cfg.CONF.auth_strategy == 'keystone':
|
||||
# NOTE(zhiyuan) pkg_resources will try to load tricircle to get module
|
||||
# version, passing "project" as empty string to bypass it
|
||||
app = auth_token.AuthProtocol(app, {'project': ''})
|
||||
else:
|
||||
raise t_exc.InvalidConfigurationOption(
|
||||
opt_name='auth_strategy', opt_value=cfg.CONF.auth_strategy)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
_launcher = None
|
||||
|
||||
|
||||
def serve(api_service, conf, workers=1):
|
||||
global _launcher
|
||||
if _launcher:
|
||||
raise RuntimeError(_('serve() can only be called once'))
|
||||
|
||||
_launcher = service.launch(conf, api_service, workers=workers)
|
||||
|
||||
|
||||
def wait():
|
||||
_launcher.wait()
|
|
@ -12,6 +12,4 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pbr.version
|
||||
|
||||
version_info = pbr.version.VersionInfo('tricircle')
|
||||
version_info = "tricircle 1.0"
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
# Copyright (c) 2015 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.
|
||||
import pecan
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from tricircle.common.i18n import _
|
||||
from tricircle.common import restapp
|
||||
|
||||
|
||||
common_opts = [
|
||||
cfg.StrOpt('bind_host', default='0.0.0.0',
|
||||
help=_("The host IP to bind to")),
|
||||
cfg.IntOpt('bind_port', default=19998,
|
||||
help=_("The port to bind to")),
|
||||
cfg.IntOpt('api_workers', default=1,
|
||||
help=_("number of api workers")),
|
||||
cfg.StrOpt('api_extensions_path', default="",
|
||||
help=_("The path for API extensions")),
|
||||
cfg.StrOpt('auth_strategy', default='keystone',
|
||||
help=_("The type of authentication to use")),
|
||||
cfg.BoolOpt('allow_bulk', default=True,
|
||||
help=_("Allow the usage of the bulk API")),
|
||||
cfg.BoolOpt('allow_pagination', default=False,
|
||||
help=_("Allow the usage of the pagination")),
|
||||
cfg.BoolOpt('allow_sorting', default=False,
|
||||
help=_("Allow the usage of the sorting")),
|
||||
cfg.StrOpt('pagination_max_limit', default="-1",
|
||||
help=_("The maximum number of items returned in a single "
|
||||
"response, value was 'infinite' or negative integer "
|
||||
"means no limit")),
|
||||
]
|
||||
|
||||
|
||||
def setup_app(*args, **kwargs):
|
||||
config = {
|
||||
'server': {
|
||||
'port': cfg.CONF.bind_port,
|
||||
'host': cfg.CONF.bind_host
|
||||
},
|
||||
'app': {
|
||||
'root': 'tricircle.nova_apigw.controllers.root.RootController',
|
||||
'modules': ['tricircle.nova_apigw'],
|
||||
'errors': {
|
||||
400: '/error',
|
||||
'__force_dict__': True
|
||||
}
|
||||
}
|
||||
}
|
||||
pecan_config = pecan.configuration.conf_from_dict(config)
|
||||
|
||||
# app_hooks = [], hook collection will be put here later
|
||||
|
||||
app = pecan.make_app(
|
||||
pecan_config.app.root,
|
||||
debug=False,
|
||||
wrap_app=restapp.auth_app,
|
||||
force_canonical=False,
|
||||
hooks=[],
|
||||
guess_content_type_from_ext=True
|
||||
)
|
||||
|
||||
return app
|
|
@ -0,0 +1,107 @@
|
|||
# Copyright (c) 2015 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.
|
||||
|
||||
import pecan
|
||||
|
||||
import oslo_log.log as logging
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RootController(object):
|
||||
|
||||
@pecan.expose()
|
||||
def _lookup(self, version, *remainder):
|
||||
if version == 'v2.1':
|
||||
return V21Controller(), remainder
|
||||
|
||||
@pecan.expose(generic=True, template='json')
|
||||
def index(self):
|
||||
return {
|
||||
"versions": [
|
||||
{
|
||||
"status": "CURRENT",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"href": pecan.request.application_url + "/v2.1/",
|
||||
"rel": "self"
|
||||
}
|
||||
],
|
||||
"min_version": "2.1",
|
||||
"version": "2.12",
|
||||
"id": "v2.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@index.when(method='POST')
|
||||
@index.when(method='PUT')
|
||||
@index.when(method='DELETE')
|
||||
@index.when(method='HEAD')
|
||||
@index.when(method='PATCH')
|
||||
def not_supported(self):
|
||||
pecan.abort(405)
|
||||
|
||||
|
||||
class V21Controller(object):
|
||||
|
||||
_media_type = "application/vnd.openstack.compute+json;version=2.1"
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.sub_controllers = {
|
||||
}
|
||||
|
||||
for name, ctrl in self.sub_controllers.items():
|
||||
setattr(self, name, ctrl)
|
||||
|
||||
@pecan.expose(generic=True, template='json')
|
||||
def index(self):
|
||||
return {
|
||||
"version": {
|
||||
"status": "CURRENT",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"href": pecan.request.application_url + "/v2.1/",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://docs.openstack.org/",
|
||||
"type": "text/html",
|
||||
"rel": "describedby"
|
||||
}
|
||||
],
|
||||
"min_version": "2.1",
|
||||
"version": "2.12",
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": self._media_type
|
||||
}
|
||||
],
|
||||
"id": "v2.1"
|
||||
}
|
||||
}
|
||||
|
||||
@index.when(method='POST')
|
||||
@index.when(method='PUT')
|
||||
@index.when(method='DELETE')
|
||||
@index.when(method='HEAD')
|
||||
@index.when(method='PATCH')
|
||||
def not_supported(self):
|
||||
pecan.abort(405)
|
|
@ -0,0 +1,22 @@
|
|||
# Copyright 2015 Huawei Technologies 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.
|
||||
|
||||
import tricircle.nova_apigw.app
|
||||
|
||||
|
||||
def list_opts():
|
||||
return [
|
||||
('DEFAULT', tricircle.nova_apigw.app.common_opts),
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
# Copyright (c) 2015 Huawei Technologies 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.
|
||||
|
||||
from oslotest import base
|
||||
|
||||
|
||||
class TestCase(base.BaseTestCase):
|
||||
"""Test case base class for all unit tests."""
|
|
@ -0,0 +1,172 @@
|
|||
# Copyright (c) 2015 Huawei Technologies 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.
|
||||
|
||||
import pecan
|
||||
from pecan.configuration import set_config
|
||||
from pecan.testing import load_test_app
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as fixture_config
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from tricircle.cinder_apigw import app
|
||||
from tricircle.tests import base
|
||||
|
||||
|
||||
OPT_GROUP_NAME = 'keystone_authtoken'
|
||||
cfg.CONF.import_group(OPT_GROUP_NAME, "keystonemiddleware.auth_token")
|
||||
|
||||
|
||||
class Cinder_API_GW_FunctionalTest(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(Cinder_API_GW_FunctionalTest, self).setUp()
|
||||
|
||||
self.addCleanup(set_config, {}, overwrite=True)
|
||||
|
||||
cfg.CONF.register_opts(app.common_opts)
|
||||
|
||||
self.CONF = self.useFixture(fixture_config.Config()).conf
|
||||
|
||||
self.CONF.set_override('auth_strategy', 'noauth')
|
||||
|
||||
self.app = self._make_app()
|
||||
|
||||
def _make_app(self, enable_acl=False):
|
||||
self.config = {
|
||||
'app': {
|
||||
'root':
|
||||
'tricircle.cinder_apigw.controllers.root.RootController',
|
||||
'modules': ['tricircle.cinder_apigw'],
|
||||
'enable_acl': enable_acl,
|
||||
'errors': {
|
||||
400: '/error',
|
||||
'__force_dict__': True
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return load_test_app(self.config)
|
||||
|
||||
def tearDown(self):
|
||||
super(Cinder_API_GW_FunctionalTest, self).tearDown()
|
||||
cfg.CONF.unregister_opts(app.common_opts)
|
||||
pecan.set_config({}, overwrite=True)
|
||||
|
||||
|
||||
class TestRootController(Cinder_API_GW_FunctionalTest):
|
||||
"""Test version listing on root URI."""
|
||||
|
||||
def test_get(self):
|
||||
response = self.app.get('/')
|
||||
self.assertEqual(response.status_int, 200)
|
||||
json_body = jsonutils.loads(response.body)
|
||||
versions = json_body.get('versions')
|
||||
self.assertEqual(1, len(versions))
|
||||
self.assertEqual(versions[0]["id"], "v2.0")
|
||||
|
||||
def _test_method_returns_405(self, method):
|
||||
api_method = getattr(self.app, method)
|
||||
response = api_method('/', expect_errors=True)
|
||||
self.assertEqual(response.status_int, 405)
|
||||
|
||||
def test_post(self):
|
||||
self._test_method_returns_405('post')
|
||||
|
||||
def test_put(self):
|
||||
self._test_method_returns_405('put')
|
||||
|
||||
def test_patch(self):
|
||||
self._test_method_returns_405('patch')
|
||||
|
||||
def test_delete(self):
|
||||
self._test_method_returns_405('delete')
|
||||
|
||||
def test_head(self):
|
||||
self._test_method_returns_405('head')
|
||||
|
||||
|
||||
class TestV2Controller(Cinder_API_GW_FunctionalTest):
|
||||
|
||||
def test_get(self):
|
||||
response = self.app.get('/v2/')
|
||||
self.assertEqual(response.status_int, 200)
|
||||
json_body = jsonutils.loads(response.body)
|
||||
version = json_body.get('version')
|
||||
self.assertEqual(version["id"], "v2.0")
|
||||
|
||||
def _test_method_returns_405(self, method):
|
||||
api_method = getattr(self.app, method)
|
||||
response = api_method('/v2/', expect_errors=True)
|
||||
self.assertEqual(response.status_int, 405)
|
||||
|
||||
def test_post(self):
|
||||
self._test_method_returns_405('post')
|
||||
|
||||
def test_put(self):
|
||||
self._test_method_returns_405('put')
|
||||
|
||||
def test_patch(self):
|
||||
self._test_method_returns_405('patch')
|
||||
|
||||
def test_delete(self):
|
||||
self._test_method_returns_405('delete')
|
||||
|
||||
def test_head(self):
|
||||
self._test_method_returns_405('head')
|
||||
|
||||
|
||||
class TestErrors(Cinder_API_GW_FunctionalTest):
|
||||
|
||||
def test_404(self):
|
||||
response = self.app.get('/assert_called_once', expect_errors=True)
|
||||
self.assertEqual(response.status_int, 404)
|
||||
|
||||
def test_bad_method(self):
|
||||
response = self.app.patch('/v2/123',
|
||||
expect_errors=True)
|
||||
self.assertEqual(response.status_int, 404)
|
||||
|
||||
|
||||
class TestRequestID(Cinder_API_GW_FunctionalTest):
|
||||
|
||||
def test_request_id(self):
|
||||
response = self.app.get('/')
|
||||
self.assertIn('x-openstack-request-id', response.headers)
|
||||
self.assertTrue(
|
||||
response.headers['x-openstack-request-id'].startswith('req-'))
|
||||
id_part = response.headers['x-openstack-request-id'].split('req-')[1]
|
||||
self.assertTrue(uuidutils.is_uuid_like(id_part))
|
||||
|
||||
|
||||
class TestKeystoneAuth(Cinder_API_GW_FunctionalTest):
|
||||
|
||||
def setUp(self):
|
||||
super(Cinder_API_GW_FunctionalTest, self).setUp()
|
||||
|
||||
self.addCleanup(set_config, {}, overwrite=True)
|
||||
|
||||
cfg.CONF.register_opts(app.common_opts)
|
||||
|
||||
self.CONF = self.useFixture(fixture_config.Config()).conf
|
||||
|
||||
cfg.CONF.set_override('auth_strategy', 'keystone')
|
||||
|
||||
self.app = self._make_app()
|
||||
|
||||
def test_auth_enforced(self):
|
||||
response = self.app.get('/', expect_errors=True)
|
||||
self.assertEqual(response.status_int, 401)
|
|
@ -0,0 +1,173 @@
|
|||
# Copyright (c) 2015 Huawei Technologies 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.
|
||||
|
||||
import pecan
|
||||
from pecan.configuration import set_config
|
||||
from pecan.testing import load_test_app
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as fixture_config
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from tricircle.nova_apigw import app
|
||||
from tricircle.tests import base
|
||||
|
||||
|
||||
OPT_GROUP_NAME = 'keystone_authtoken'
|
||||
cfg.CONF.import_group(OPT_GROUP_NAME, "keystonemiddleware.auth_token")
|
||||
|
||||
|
||||
class Nova_API_GW_FunctionalTest(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(Nova_API_GW_FunctionalTest, self).setUp()
|
||||
|
||||
self.addCleanup(set_config, {}, overwrite=True)
|
||||
|
||||
cfg.CONF.register_opts(app.common_opts)
|
||||
|
||||
self.CONF = self.useFixture(fixture_config.Config()).conf
|
||||
|
||||
self.CONF.set_override('auth_strategy', 'noauth')
|
||||
|
||||
self.app = self._make_app()
|
||||
|
||||
def _make_app(self, enable_acl=False):
|
||||
self.config = {
|
||||
'app': {
|
||||
'root': 'tricircle.nova_apigw.controllers.root.RootController',
|
||||
'modules': ['tricircle.nova_apigw'],
|
||||
'enable_acl': enable_acl,
|
||||
'errors': {
|
||||
400: '/error',
|
||||
'__force_dict__': True
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return load_test_app(self.config)
|
||||
|
||||
def tearDown(self):
|
||||
super(Nova_API_GW_FunctionalTest, self).tearDown()
|
||||
cfg.CONF.unregister_opts(app.common_opts)
|
||||
pecan.set_config({}, overwrite=True)
|
||||
|
||||
|
||||
class TestRootController(Nova_API_GW_FunctionalTest):
|
||||
"""Test version listing on root URI."""
|
||||
|
||||
def test_get(self):
|
||||
response = self.app.get('/')
|
||||
self.assertEqual(response.status_int, 200)
|
||||
json_body = jsonutils.loads(response.body)
|
||||
versions = json_body.get('versions')
|
||||
self.assertEqual(1, len(versions))
|
||||
self.assertEqual(versions[0]["min_version"], "2.1")
|
||||
self.assertEqual(versions[0]["id"], "v2.1")
|
||||
|
||||
def _test_method_returns_405(self, method):
|
||||
api_method = getattr(self.app, method)
|
||||
response = api_method('/', expect_errors=True)
|
||||
self.assertEqual(response.status_int, 405)
|
||||
|
||||
def test_post(self):
|
||||
self._test_method_returns_405('post')
|
||||
|
||||
def test_put(self):
|
||||
self._test_method_returns_405('put')
|
||||
|
||||
def test_patch(self):
|
||||
self._test_method_returns_405('patch')
|
||||
|
||||
def test_delete(self):
|
||||
self._test_method_returns_405('delete')
|
||||
|
||||
def test_head(self):
|
||||
self._test_method_returns_405('head')
|
||||
|
||||
|
||||
class TestV21Controller(Nova_API_GW_FunctionalTest):
|
||||
|
||||
def test_get(self):
|
||||
response = self.app.get('/v2.1/')
|
||||
self.assertEqual(response.status_int, 200)
|
||||
json_body = jsonutils.loads(response.body)
|
||||
version = json_body.get('version')
|
||||
self.assertEqual(version["min_version"], "2.1")
|
||||
self.assertEqual(version["id"], "v2.1")
|
||||
|
||||
def _test_method_returns_405(self, method):
|
||||
api_method = getattr(self.app, method)
|
||||
response = api_method('/v2.1', expect_errors=True)
|
||||
self.assertEqual(response.status_int, 405)
|
||||
|
||||
def test_post(self):
|
||||
self._test_method_returns_405('post')
|
||||
|
||||
def test_put(self):
|
||||
self._test_method_returns_405('put')
|
||||
|
||||
def test_patch(self):
|
||||
self._test_method_returns_405('patch')
|
||||
|
||||
def test_delete(self):
|
||||
self._test_method_returns_405('delete')
|
||||
|
||||
def test_head(self):
|
||||
self._test_method_returns_405('head')
|
||||
|
||||
|
||||
class TestErrors(Nova_API_GW_FunctionalTest):
|
||||
|
||||
def test_404(self):
|
||||
response = self.app.get('/assert_called_once', expect_errors=True)
|
||||
self.assertEqual(response.status_int, 404)
|
||||
|
||||
def test_bad_method(self):
|
||||
response = self.app.patch('/v2.1/123',
|
||||
expect_errors=True)
|
||||
self.assertEqual(response.status_int, 404)
|
||||
|
||||
|
||||
class TestRequestID(Nova_API_GW_FunctionalTest):
|
||||
|
||||
def test_request_id(self):
|
||||
response = self.app.get('/')
|
||||
self.assertIn('x-openstack-request-id', response.headers)
|
||||
self.assertTrue(
|
||||
response.headers['x-openstack-request-id'].startswith('req-'))
|
||||
id_part = response.headers['x-openstack-request-id'].split('req-')[1]
|
||||
self.assertTrue(uuidutils.is_uuid_like(id_part))
|
||||
|
||||
|
||||
class TestKeystoneAuth(Nova_API_GW_FunctionalTest):
|
||||
|
||||
def setUp(self):
|
||||
super(Nova_API_GW_FunctionalTest, self).setUp()
|
||||
|
||||
self.addCleanup(set_config, {}, overwrite=True)
|
||||
|
||||
cfg.CONF.register_opts(app.common_opts)
|
||||
|
||||
self.CONF = self.useFixture(fixture_config.Config()).conf
|
||||
|
||||
cfg.CONF.set_override('auth_strategy', 'keystone')
|
||||
|
||||
self.app = self._make_app()
|
||||
|
||||
def test_auth_enforced(self):
|
||||
response = self.app.get('/', expect_errors=True)
|
||||
self.assertEqual(response.status_int, 401)
|
Loading…
Reference in New Issue