rework functional tests to be a tempest plugin
Change-Id: Ic38b628a4c17e2a8d307ecdeb08c639975a364aa
This commit is contained in:
parent
54e55e4b47
commit
01786798d8
133
devstack/create_config
Executable file
133
devstack/create_config
Executable file
@ -0,0 +1,133 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# create_config script for devstack plugin script
|
||||||
|
# Build config for run functional tests with or wuthout tempest
|
||||||
|
|
||||||
|
set -o xtrace
|
||||||
|
set +o errexit
|
||||||
|
|
||||||
|
TIMEOUT=${TIMEOUT:-180}
|
||||||
|
GCE_SCHEMA=${GCE_SCHEMA:-etc/gceapi/protocols/v1.json}
|
||||||
|
GCE_CRED_TYPE=${GCE_CRED_TYPE:-os_token}
|
||||||
|
GCE_API_PROTOCOL=${GCE_API_PROTOCOL:-http}
|
||||||
|
GCE_HOST=${GCE_HOST:-localhost}
|
||||||
|
GCE_PORT=${GCE_PORT:-8787}
|
||||||
|
GCE_DISCOVERY_URL=${GCE_DISCOVERY_URL:-/discovery/v1/apis/\{api\}/\{apiVersion\}/rest}
|
||||||
|
ZONE=${ZONE:-nova}
|
||||||
|
REGION=${REGION:-region-one}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CONFIG="$1"
|
||||||
|
if [[ -z "$TEST_CONFIG" ]]; then
|
||||||
|
die $LINENO "Please pass config name"
|
||||||
|
fi
|
||||||
|
sudo rm -f $GCEAPI_DIR/$TEST_CONFIG
|
||||||
|
|
||||||
|
if [[ -n "$TOP_DIR" ]]; then
|
||||||
|
source $TOP_DIR/accrc/admin/admin
|
||||||
|
unset OS_AUTH_TYPE
|
||||||
|
fi
|
||||||
|
|
||||||
|
openstack endpoint list
|
||||||
|
if [[ "$?" -ne "0" ]]; then
|
||||||
|
die $LINENO "OpenStack CLI doesn't work. Looks like credentials are absent."
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# create separate user/project
|
||||||
|
project_name="project-$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 8)"
|
||||||
|
eval $(openstack project create -f shell -c id $project_name)
|
||||||
|
project_id=$id
|
||||||
|
[[ -n "$project_id" ]] || { echo "Can't create project"; exit 1; }
|
||||||
|
user_name="user-$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 8)"
|
||||||
|
password='password'
|
||||||
|
eval $(openstack user create "$user_name" --project "$project_id" --password "$password" --email "$user_name@example.com" -f shell -c id)
|
||||||
|
user_id=$id
|
||||||
|
[[ -n "$user_id" ]] || { echo "Can't create user"; exit 1; }
|
||||||
|
# add 'Member' role for swift access
|
||||||
|
role_id=$(openstack role show Member -c id -f value)
|
||||||
|
openstack role add --project $project_id --user $user_id $role_id
|
||||||
|
|
||||||
|
# prepare flavors
|
||||||
|
flavor_name="n1.standard.1"
|
||||||
|
if [[ -z "$(nova flavor-list | grep $flavor_name)" ]]; then
|
||||||
|
nova flavor-create --is-public True $flavor_name 16 512 0 1
|
||||||
|
[[ "$?" -eq 0 ]] || { echo "Failed to prepare flavor"; exit 1; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create default network
|
||||||
|
if [[ -n $(openstack service list | grep neutron) ]]; then
|
||||||
|
# neutron networking
|
||||||
|
networking="neutron"
|
||||||
|
net_id=$(neutron net-create --tenant-id $project_id "default" | grep ' id ' | awk '{print $4}')
|
||||||
|
[[ -n "$net_id" ]] || { echo "net-create failed"; exit 1; }
|
||||||
|
subnet_id=$(neutron subnet-create --tenant-id $project_id --ip_version 4 --gateway 10.240.0.1 --name "private_subnet" $net_id 10.240.0.0/16 | grep ' id ' | awk '{print $4}')
|
||||||
|
[[ -n "$subnet_id" ]] || { echo "subnet-create failed"; exit 1; }
|
||||||
|
router_id=$(neutron router-create --tenant-id $project_id "private_router" | grep ' id ' | awk '{print $4}')
|
||||||
|
[[ -n "$router_id" ]] || { echo "router-create failed"; exit 1; }
|
||||||
|
neutron router-interface-add $router_id $subnet_id
|
||||||
|
[[ "$?" -eq 0 ]] || { echo "router-interface-add failed"; exit 1; }
|
||||||
|
public_net_id=$(neutron net-list | grep public | awk '{print $2}')
|
||||||
|
[[ -n "$public_net_id" ]] || { echo "can't find public network"; exit 1; }
|
||||||
|
neutron router-gateway-set $router_id $public_net_id
|
||||||
|
[[ "$?" -eq 0 ]] || { echo "router-gateway-set failed"; exit 1; }
|
||||||
|
else
|
||||||
|
# nova networking
|
||||||
|
networking="nova-network"
|
||||||
|
nova network-create "default" --fixed-range-v4 10.240.0.0/16 --gateway 10.240.0.1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#create image in raw format
|
||||||
|
os_image_name="cirros-0.3.4-raw-image"
|
||||||
|
if [[ -z "$(openstack image list | grep $os_image_name)" ]]; then
|
||||||
|
image_name="cirros-0.3.4-x86_64-disk.img"
|
||||||
|
cirros_image_url="http://download.cirros-cloud.net/0.3.4/$image_name"
|
||||||
|
sudo rm -f /tmp/$image_name
|
||||||
|
wget -nv -P /tmp $cirros_image_url
|
||||||
|
[[ "$?" -eq 0 ]] || { echo "Failed to download image"; exit 1; }
|
||||||
|
openstack image create --disk-format raw --container-format bare --public --file "/tmp/$image_name" $os_image_name
|
||||||
|
[[ "$?" -eq 0 ]] || { echo "Failed to prepare image"; exit 1; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
export OS_PROJECT_NAME=$project_name
|
||||||
|
export OS_TENANT_NAME=$project_name
|
||||||
|
export OS_USERNAME=$user_name
|
||||||
|
export OS_PASSWORD=$password
|
||||||
|
|
||||||
|
|
||||||
|
# convert flavor name: becase GCE dowsn't allows '.' and converts '-' into '.'
|
||||||
|
flavor_name=${flavor_name//\./-}
|
||||||
|
|
||||||
|
sudo bash -c "cat > $GCEAPI_DIR/$TEST_CONFIG <<EOF
|
||||||
|
[gce]
|
||||||
|
# Generic options
|
||||||
|
build_timeout = $TIMEOUT
|
||||||
|
build_interval = 1
|
||||||
|
|
||||||
|
# GCE API schema
|
||||||
|
schema = $GCE_SCHEMA
|
||||||
|
|
||||||
|
# GCE auth options
|
||||||
|
cred_type = $GCE_CRED_TYPE
|
||||||
|
auth_url = $OS_AUTH_URL
|
||||||
|
username = $OS_USERNAME
|
||||||
|
password = $OS_PASSWORD
|
||||||
|
|
||||||
|
# GCE services address
|
||||||
|
protocol = $GCE_API_PROTOCOL
|
||||||
|
host = $GCE_HOST
|
||||||
|
port = $GCE_PORT
|
||||||
|
|
||||||
|
# GCE API URLs
|
||||||
|
discovery_url = $GCE_DISCOVERY_URL
|
||||||
|
|
||||||
|
# GCE resource IDs for testing
|
||||||
|
project_id = $OS_PROJECT_NAME
|
||||||
|
zone = $ZONE
|
||||||
|
networking = $networking
|
||||||
|
region = $REGION
|
||||||
|
machine_type = $flavor_name
|
||||||
|
image = $OS_PROJECT_NAME/global/images/$os_image_name
|
||||||
|
EOF"
|
||||||
|
|
||||||
|
sudo chown -f $STACK_USER $GCEAPI_DIR/$TEST_CONFIG
|
@ -211,14 +211,20 @@ function install_gceapi() {
|
|||||||
|
|
||||||
# start_gceapi() - Start running processes, including screen
|
# start_gceapi() - Start running processes, including screen
|
||||||
function start_gceapi() {
|
function start_gceapi() {
|
||||||
screen_it gce-api "cd $GCEAPI_DIR && $GCEAPI_BIN_DIR/gce-api --config-file $GCEAPI_CONF_DIR/gceapi.conf"
|
run_process gce-api "$GCEAPI_BIN_DIR/gce-api --config-file $GCEAPI_CONF_DIR/gceapi.conf"
|
||||||
|
|
||||||
|
echo "Waiting for GCE API to start..."
|
||||||
|
if ! wait_for_service $SERVICE_TIMEOUT \
|
||||||
|
"$SERVICE_PROTOCOL://$SERVICE_HOST:$GCEAPI_SERVICE_PORT/"; then
|
||||||
|
die $LINENO "GCE API did not start"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# stop_gceapi() - Stop running processes
|
# stop_gceapi() - Stop running processes
|
||||||
function stop_gceapi() {
|
function stop_gceapi() {
|
||||||
# Kill the gceapi screen windows
|
# Kill the gceapi screen windows
|
||||||
screen -S $SCREEN_NAME -p gce-api -X kill
|
stop_process gce-api
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanup_gceapi() {
|
function cleanup_gceapi() {
|
||||||
@ -227,6 +233,15 @@ function cleanup_gceapi() {
|
|||||||
sudo rm -rf $GCEAPI_KEYSTONE_SIGNING_DIR
|
sudo rm -rf $GCEAPI_KEYSTONE_SIGNING_DIR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function configure_functional_tests() {
|
||||||
|
(source $GCEAPI_DIR/devstack/create_config "functional_tests.conf")
|
||||||
|
if [[ "$?" -ne "0" ]]; then
|
||||||
|
warn $LINENO "GCE API tests config could not be created."
|
||||||
|
elif is_service_enabled tempest; then
|
||||||
|
cat "$GCEAPI_DIR/functional_tests.conf" >> $TEMPEST_CONFIG
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# main dispatcher
|
# main dispatcher
|
||||||
if [[ "$1" == "stack" && "$2" == "install" ]]; then
|
if [[ "$1" == "stack" && "$2" == "install" ]]; then
|
||||||
echo_summary "Installing gce-api"
|
echo_summary "Installing gce-api"
|
||||||
@ -239,6 +254,7 @@ elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
|||||||
echo_summary "Initializing gce-api"
|
echo_summary "Initializing gce-api"
|
||||||
init_gceapi
|
init_gceapi
|
||||||
start_gceapi
|
start_gceapi
|
||||||
|
configure_functional_tests
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$1" == "unstack" ]]; then
|
if [[ "$1" == "unstack" ]]; then
|
||||||
|
@ -17,18 +17,23 @@
|
|||||||
# Sleep some time until all services are starting
|
# Sleep some time until all services are starting
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
export TEST_CONFIG_DIR=$(readlink -f .)
|
export GCEAPI_DIR=$(readlink -f .)
|
||||||
export TEST_CONFIG="functional_tests.conf"
|
export TEST_CONFIG="functional_tests.conf"
|
||||||
|
|
||||||
# save original creds(admin) for later usage
|
|
||||||
OLD_OS_PROJECT_NAME=$OS_PROJECT_NAME
|
|
||||||
OLD_OS_USERNAME=$OS_USERNAME
|
|
||||||
OLD_OS_PASSWORD=$OS_PASSWORD
|
|
||||||
|
|
||||||
# bug somewhere
|
# bug somewhere
|
||||||
unset OS_AUTH_TYPE
|
unset OS_AUTH_TYPE
|
||||||
|
|
||||||
if [[ ! -f $TEST_CONFIG_DIR/$TEST_CONFIG ]]; then
|
function die() {
|
||||||
|
echo "ERROR in $1: $2"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
export -f die
|
||||||
|
function warn() {
|
||||||
|
echo "WARNING in $1: $2"
|
||||||
|
}
|
||||||
|
export -f warn
|
||||||
|
|
||||||
|
if [[ ! -f $GCEAPI_DIR/$TEST_CONFIG ]]; then
|
||||||
|
|
||||||
openstack endpoint list --os-identity-api-version=3
|
openstack endpoint list --os-identity-api-version=3
|
||||||
openstack service list --long
|
openstack service list --long
|
||||||
@ -37,119 +42,28 @@ if [[ ! -f $TEST_CONFIG_DIR/$TEST_CONFIG ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# create separate user/project
|
STACK_USER=$(whoami) $GCEAPI_DIR/devstack/create_config $TEST_CONFIG
|
||||||
project_name="project-$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 8)"
|
if [[ "$?" -ne "0" ]]; then
|
||||||
eval $(openstack project create -f shell -c id $project_name)
|
echo "Config creation has failed."
|
||||||
project_id=$id
|
exit 1
|
||||||
[[ -n "$project_id" ]] || { echo "Can't create project"; exit 1; }
|
|
||||||
user_name="user-$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 8)"
|
|
||||||
password='password'
|
|
||||||
eval $(openstack user create "$user_name" --project "$project_id" --password "$password" --email "$user_name@example.com" -f shell -c id)
|
|
||||||
user_id=$id
|
|
||||||
[[ -n "$user_id" ]] || { echo "Can't create user"; exit 1; }
|
|
||||||
# add 'Member' role for swift access
|
|
||||||
role_id=$(openstack role show Member -c id -f value)
|
|
||||||
openstack role add --project $project_id --user $user_id $role_id
|
|
||||||
|
|
||||||
# prepare flavors
|
|
||||||
flavor_name="n1.standard.1"
|
|
||||||
if [[ -z "$(nova flavor-list | grep $flavor_name)" ]]; then
|
|
||||||
nova flavor-create --is-public True $flavor_name 16 512 0 1
|
|
||||||
[[ "$?" -eq 0 ]] || { echo "Failed to prepare flavor"; exit 1; }
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# create default network
|
|
||||||
if [[ -n $(openstack service list | grep neutron) ]]; then
|
|
||||||
# neutron networking
|
|
||||||
networking="neutron"
|
|
||||||
net_id=$(neutron net-create --tenant-id $project_id "default" | grep ' id ' | awk '{print $4}')
|
|
||||||
[[ -n "$net_id" ]] || { echo "net-create failed"; exit 1; }
|
|
||||||
subnet_id=$(neutron subnet-create --tenant-id $project_id --ip_version 4 --gateway 10.240.0.1 --name "private_subnet" $net_id 10.240.0.0/16 | grep ' id ' | awk '{print $4}')
|
|
||||||
[[ -n "$subnet_id" ]] || { echo "subnet-create failed"; exit 1; }
|
|
||||||
router_id=$(neutron router-create --tenant-id $project_id "private_router" | grep ' id ' | awk '{print $4}')
|
|
||||||
[[ -n "$router_id" ]] || { echo "router-create failed"; exit 1; }
|
|
||||||
neutron router-interface-add $router_id $subnet_id
|
|
||||||
[[ "$?" -eq 0 ]] || { echo "router-interface-add failed"; exit 1; }
|
|
||||||
public_net_id=$(neutron net-list | grep public | awk '{print $2}')
|
|
||||||
[[ -n "$public_net_id" ]] || { echo "can't find public network"; exit 1; }
|
|
||||||
neutron router-gateway-set $router_id $public_net_id
|
|
||||||
[[ "$?" -eq 0 ]] || { echo "router-gateway-set failed"; exit 1; }
|
|
||||||
else
|
|
||||||
# nova networking
|
|
||||||
networking="nova-network"
|
|
||||||
nova network-create "default" --fixed-range-v4 10.240.0.0/16 --gateway 10.240.0.1
|
|
||||||
fi
|
|
||||||
|
|
||||||
#create image in raw format
|
|
||||||
os_image_name="cirros-0.3.4-raw-image"
|
|
||||||
if [[ -z "$(openstack image list | grep $os_image_name)" ]]; then
|
|
||||||
image_name="cirros-0.3.4-x86_64-disk.img"
|
|
||||||
cirros_image_url="http://download.cirros-cloud.net/0.3.4/$image_name"
|
|
||||||
sudo rm -f /tmp/$image_name
|
|
||||||
wget -nv -P /tmp $cirros_image_url
|
|
||||||
[[ "$?" -eq 0 ]] || { echo "Failed to download image"; exit 1; }
|
|
||||||
openstack image create --disk-format raw --container-format bare --public --file "/tmp/$image_name" $os_image_name
|
|
||||||
[[ "$?" -eq 0 ]] || { echo "Failed to prepare image"; exit 1; }
|
|
||||||
fi
|
|
||||||
|
|
||||||
export OS_PROJECT_NAME=$project_name
|
|
||||||
export OS_TENANT_NAME=$project_name
|
|
||||||
export OS_USERNAME=$user_name
|
|
||||||
export OS_PASSWORD=$password
|
|
||||||
|
|
||||||
sudo bash -c "cat > $TEST_CONFIG_DIR/$TEST_CONFIG <<EOF
|
|
||||||
[gce]
|
|
||||||
# Generic options
|
|
||||||
build_timeout=${TIMEOUT:-180}
|
|
||||||
build_interval=1
|
|
||||||
|
|
||||||
# GCE API schema
|
|
||||||
schema=${GCE_SCHEMA:-'etc/gceapi/protocols/v1.json'}
|
|
||||||
|
|
||||||
# GCE auth options
|
|
||||||
cred_type=${GCE_CRED_TYPE:-'os_token'}
|
|
||||||
auth_url=${OS_AUTH_URL}
|
|
||||||
username=${OS_USERNAME}
|
|
||||||
password=${OS_PASSWORD}
|
|
||||||
|
|
||||||
# GCE services address
|
|
||||||
protocol=${GCE_API_PROTOCOL:-'http'}
|
|
||||||
host=${GCE_HOST:-'localhost'}
|
|
||||||
port=${GCE_PORT:-8787}
|
|
||||||
|
|
||||||
# GCE API URLs
|
|
||||||
discovery_url=${GCE_DISCOVERY_URL:-'/discovery/v1/apis/{api}/{apiVersion}/rest'}
|
|
||||||
|
|
||||||
# GCE resource IDs for testing
|
|
||||||
project_id=${OS_PROJECT_NAME}
|
|
||||||
zone=${ZONE:-'nova'}
|
|
||||||
networking=${networking}
|
|
||||||
region=${REGION:-'region-one'}
|
|
||||||
# convert flavor name: becase GCE dowsn't allows '.' and converts '-' into '.'
|
|
||||||
machine_type=${flavor_name//\./-}
|
|
||||||
image=${OS_PROJECT_NAME}/global/images/${os_image_name}
|
|
||||||
EOF"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sudo pip install -r test-requirements.txt
|
|
||||||
sudo pip install google-api-python-client
|
sudo pip install virtualenv
|
||||||
|
sudo rm -rf .venv
|
||||||
|
sudo virtualenv .venv --system-site-package
|
||||||
|
sudo chown -R $USER .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip install -r test-requirements.txt
|
||||||
|
pip install google-api-python-client
|
||||||
sudo OS_STDOUT_CAPTURE=-1 OS_STDERR_CAPTURE=-1 OS_TEST_TIMEOUT=500 OS_TEST_LOCK_PATH=${TMPDIR:-'/tmp'} \
|
sudo OS_STDOUT_CAPTURE=-1 OS_STDERR_CAPTURE=-1 OS_TEST_TIMEOUT=500 OS_TEST_LOCK_PATH=${TMPDIR:-'/tmp'} \
|
||||||
python -m subunit.run discover -t ./ ./gceapi/tests/functional/api | subunit-2to1 | tools/colorizer.py
|
python -m subunit.run discover -t ./ ./gceapi/tests/functional/api | subunit-2to1 | tools/colorizer.py
|
||||||
RETVAL=$?
|
RETVAL=$?
|
||||||
|
deactivate
|
||||||
|
|
||||||
# Here can be some commands for log archiving, etc...
|
# Here can be some commands for log archiving, etc...
|
||||||
|
|
||||||
echo Enumerate resources to check what left after tests
|
|
||||||
for i in instances images disks snapshots
|
|
||||||
do
|
|
||||||
echo "List of "$i
|
|
||||||
gcloud compute $i list
|
|
||||||
echo ""
|
|
||||||
done
|
|
||||||
export OS_PROJECT_NAME=$OLD_OS_PROJECT_NAME
|
|
||||||
export OS_TENANT_NAME=$OLD_OS_PROJECT_NAME
|
|
||||||
export OS_USERNAME=$OLD_OS_USERNAME
|
|
||||||
export OS_PASSWORD=$OLD_OS_PASSWORD
|
|
||||||
openstack flavor list
|
openstack flavor list
|
||||||
openstack image list
|
openstack image list
|
||||||
openstack server list --all-projects
|
openstack server list --all-projects
|
||||||
|
@ -14,84 +14,22 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
from os import environ
|
import logging as std_logging
|
||||||
from os import path
|
import os
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from gceapi.tests.functional import config_opts
|
||||||
|
|
||||||
|
|
||||||
OPTIONS_GROUP = cfg.OptGroup(name='gce', title='GCE options')
|
LOG = logging.getLogger('gceapi')
|
||||||
OPTIONS = [
|
|
||||||
# Generic options
|
|
||||||
cfg.IntOpt('build_timeout',
|
|
||||||
default=180,
|
|
||||||
help='Timeout'),
|
|
||||||
cfg.IntOpt('build_interval',
|
|
||||||
default=1,
|
|
||||||
help='Interval'),
|
|
||||||
|
|
||||||
# GCE auth options
|
|
||||||
cfg.StrOpt('cred_type',
|
|
||||||
default='os_token',
|
|
||||||
help='Method how to get credentials:'
|
|
||||||
'\n\tos_token - request token from OS keystone directly'
|
|
||||||
'\n\tgcloud_auth - use app credentials that should be'
|
|
||||||
'obtained before via gcloud auth'),
|
|
||||||
cfg.StrOpt('username',
|
|
||||||
default='demo',
|
|
||||||
help='User name'),
|
|
||||||
cfg.StrOpt('password',
|
|
||||||
default='password',
|
|
||||||
help='User password'),
|
|
||||||
cfg.StrOpt('auth_url',
|
|
||||||
default='http://localhost:5000/v2.0/',
|
|
||||||
help='OAuth API relative URL'),
|
|
||||||
|
|
||||||
# GCE API schema
|
def get_base_dir():
|
||||||
cfg.StrOpt('schema',
|
cur_dir = os.path.dirname(__file__)
|
||||||
default='etc/gceapi/protocols/v1.json',
|
base_dir = os.path.dirname(os.path.dirname(os.path.dirname(cur_dir)))
|
||||||
help='Json file with API schema for validation'),
|
return os.environ.get('TEST_CONFIG_DIR', base_dir)
|
||||||
|
|
||||||
# GCE services address
|
|
||||||
cfg.StrOpt('protocol',
|
|
||||||
default='http',
|
|
||||||
help='GCE protocl (http or https)'),
|
|
||||||
cfg.StrOpt('host',
|
|
||||||
default='localhost',
|
|
||||||
help='GCE service host'),
|
|
||||||
cfg.IntOpt('port',
|
|
||||||
default=8787,
|
|
||||||
help='GCE service port'),
|
|
||||||
|
|
||||||
# GCE API URLs
|
|
||||||
cfg.StrOpt('discovery_url',
|
|
||||||
default='/discovery/v1/apis/{api}/{apiVersion}/rest',
|
|
||||||
help='Discovery API relative URL'),
|
|
||||||
|
|
||||||
# GCE resource IDs for testing
|
|
||||||
# Note that Google's project has Name, ID and Number, for project
|
|
||||||
# identification ID should be used, but in Openstack project has
|
|
||||||
# Name and ID, where Name is corresponds to Project ID in Google, ID is
|
|
||||||
# Openstack ID's and has no relation to Google's ID and Number.
|
|
||||||
cfg.StrOpt('project_id',
|
|
||||||
default='test',
|
|
||||||
help='GCE Project ID for testing'),
|
|
||||||
cfg.StrOpt('zone',
|
|
||||||
default='nova',
|
|
||||||
help='GCE Zone for testing'),
|
|
||||||
cfg.StrOpt('region',
|
|
||||||
default='us-central1',
|
|
||||||
help='GCE Region for testing'),
|
|
||||||
cfg.StrOpt('networking',
|
|
||||||
default='neutron',
|
|
||||||
help='Types of OS networking: neutron or nova-network'),
|
|
||||||
|
|
||||||
cfg.StrOpt('machine_type',
|
|
||||||
default='n1-standard-1',
|
|
||||||
help='Machine type - a type of instance ot be created'),
|
|
||||||
cfg.StrOpt('image',
|
|
||||||
default='debian-cloud/global/images/debian-7-wheezy-v20150929',
|
|
||||||
help='Image to create instances'),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# This should never be called outside of this class
|
# This should never be called outside of this class
|
||||||
@ -101,34 +39,30 @@ class ConfigPrivate(object):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialize a configuration from a conf directory and conf file."""
|
"""Initialize a configuration from a conf directory and conf file."""
|
||||||
super(ConfigPrivate, self).__init__()
|
super(ConfigPrivate, self).__init__()
|
||||||
base_dir = self._get_base_dir()
|
|
||||||
cfg_file_path = self._get_default_config_path(base_dir)
|
|
||||||
config_files = []
|
|
||||||
if path.exists(cfg_file_path):
|
|
||||||
config_files.append(cfg_file_path)
|
|
||||||
cfg.CONF.register_group(OPTIONS_GROUP)
|
|
||||||
cfg.CONF.register_opts(OPTIONS, group=OPTIONS_GROUP)
|
|
||||||
cfg.CONF([], project='gceapi', default_config_files=config_files)
|
|
||||||
self.gce = cfg.CONF.gce
|
|
||||||
# Load API scheme for API calls validation
|
|
||||||
with open(self._get_default_schema_path(base_dir), 'r') as f:
|
|
||||||
from json import load
|
|
||||||
self.gce.schema = load(f)
|
|
||||||
|
|
||||||
@staticmethod
|
# if this was run from tempest runner then config already parsed
|
||||||
def _get_base_dir():
|
if config_opts.OPTIONS_GROUP.name in cfg.CONF:
|
||||||
cur_dir = path.dirname(__file__)
|
self.gce = cfg.CONF.gce
|
||||||
base_dir = path.dirname(path.dirname(path.dirname(cur_dir)))
|
return
|
||||||
return environ.get('TEST_CONFIG_DIR', base_dir)
|
|
||||||
|
cfg_file_path = self._get_default_config_path(get_base_dir())
|
||||||
|
config_files = []
|
||||||
|
if os.path.exists(cfg_file_path):
|
||||||
|
config_files.append(cfg_file_path)
|
||||||
|
|
||||||
|
conf = cfg.CONF
|
||||||
|
conf([], project='gceapi', default_config_files=config_files)
|
||||||
|
conf.register_group(config_opts.OPTIONS_GROUP)
|
||||||
|
group_name = config_opts.OPTIONS_GROUP.name
|
||||||
|
for opt in config_opts.OPTIONS:
|
||||||
|
conf.register_opt(opt, group=group_name)
|
||||||
|
self.gce = cfg.CONF.gce
|
||||||
|
conf.log_opt_values(LOG, std_logging.DEBUG)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_default_config_path(base_dir):
|
def _get_default_config_path(base_dir):
|
||||||
conf_file = environ.get('TEST_CONFIG', 'functional_tests.conf')
|
conf_file = os.environ.get('TEST_CONFIG', 'functional_tests.conf')
|
||||||
return path.join(base_dir, conf_file)
|
return os.path.join(base_dir, conf_file)
|
||||||
|
|
||||||
def _get_default_schema_path(self, base_dir):
|
|
||||||
schema_file = environ.get('TEST_SCHEMA', self.gce.schema)
|
|
||||||
return path.join(base_dir, schema_file)
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigProxy(object):
|
class ConfigProxy(object):
|
||||||
|
92
gceapi/tests/functional/config_opts.py
Normal file
92
gceapi/tests/functional/config_opts.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# Copyright 2012 OpenStack Foundation
|
||||||
|
# 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 oslo_config import cfg
|
||||||
|
|
||||||
|
|
||||||
|
OPTIONS_GROUP = cfg.OptGroup(name='gce', title='GCE options')
|
||||||
|
OPTIONS = [
|
||||||
|
# Generic options
|
||||||
|
cfg.IntOpt('build_timeout',
|
||||||
|
default=180,
|
||||||
|
help='Timeout'),
|
||||||
|
cfg.IntOpt('build_interval',
|
||||||
|
default=1,
|
||||||
|
help='Interval'),
|
||||||
|
|
||||||
|
# GCE auth options
|
||||||
|
cfg.StrOpt('cred_type',
|
||||||
|
default='os_token',
|
||||||
|
help='Method how to get credentials:'
|
||||||
|
'\n\tos_token - request token from OS keystone directly'
|
||||||
|
'\n\tgcloud_auth - use app credentials that should be'
|
||||||
|
'obtained before via gcloud auth'),
|
||||||
|
cfg.StrOpt('username',
|
||||||
|
default='demo',
|
||||||
|
help='User name'),
|
||||||
|
cfg.StrOpt('password',
|
||||||
|
default='password',
|
||||||
|
help='User password'),
|
||||||
|
cfg.StrOpt('auth_url',
|
||||||
|
default='http://localhost:5000/v2.0/',
|
||||||
|
help='OAuth API relative URL'),
|
||||||
|
|
||||||
|
# GCE API schema
|
||||||
|
cfg.StrOpt('schema',
|
||||||
|
default='etc/gceapi/protocols/v1.json',
|
||||||
|
help='Json file with API schema for validation'),
|
||||||
|
|
||||||
|
# GCE services address
|
||||||
|
cfg.StrOpt('protocol',
|
||||||
|
default='http',
|
||||||
|
help='GCE protocl (http or https)'),
|
||||||
|
cfg.StrOpt('host',
|
||||||
|
default='localhost',
|
||||||
|
help='GCE service host'),
|
||||||
|
cfg.IntOpt('port',
|
||||||
|
default=8787,
|
||||||
|
help='GCE service port'),
|
||||||
|
|
||||||
|
# GCE API URLs
|
||||||
|
cfg.StrOpt('discovery_url',
|
||||||
|
default='/discovery/v1/apis/{api}/{apiVersion}/rest',
|
||||||
|
help='Discovery API relative URL'),
|
||||||
|
|
||||||
|
# GCE resource IDs for testing
|
||||||
|
# Note that Google's project has Name, ID and Number, for project
|
||||||
|
# identification ID should be used, but in Openstack project has
|
||||||
|
# Name and ID, where Name is corresponds to Project ID in Google, ID is
|
||||||
|
# Openstack ID's and has no relation to Google's ID and Number.
|
||||||
|
cfg.StrOpt('project_id',
|
||||||
|
default='test',
|
||||||
|
help='GCE Project ID for testing'),
|
||||||
|
cfg.StrOpt('zone',
|
||||||
|
default='nova',
|
||||||
|
help='GCE Zone for testing'),
|
||||||
|
cfg.StrOpt('region',
|
||||||
|
default='us-central1',
|
||||||
|
help='GCE Region for testing'),
|
||||||
|
cfg.StrOpt('networking',
|
||||||
|
default='neutron',
|
||||||
|
help='Types of OS networking: neutron or nova-network'),
|
||||||
|
|
||||||
|
cfg.StrOpt('machine_type',
|
||||||
|
default='n1-standard-1',
|
||||||
|
help='Machine type - a type of instance ot be created'),
|
||||||
|
cfg.StrOpt('image',
|
||||||
|
default='debian-cloud/global/images/debian-7-wheezy-v20150929',
|
||||||
|
help='Image to create instances'),
|
||||||
|
]
|
38
gceapi/tests/functional/plugin.py
Normal file
38
gceapi/tests/functional/plugin.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright 2012 OpenStack Foundation
|
||||||
|
# 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 os
|
||||||
|
|
||||||
|
from tempest import config
|
||||||
|
from tempest.test_discover import plugins
|
||||||
|
|
||||||
|
from gceapi.tests.functional import config_opts as gce_config
|
||||||
|
|
||||||
|
|
||||||
|
class GCETempestPlugin(plugins.TempestPlugin):
|
||||||
|
def load_tests(self):
|
||||||
|
base_path = os.path.split(os.path.dirname(os.path.dirname(
|
||||||
|
os.path.dirname(os.path.abspath(__file__)))))[0]
|
||||||
|
test_dir = "gceapi/tests/functional"
|
||||||
|
full_test_dir = os.path.join(base_path, test_dir)
|
||||||
|
return full_test_dir, base_path
|
||||||
|
|
||||||
|
def register_opts(self, conf):
|
||||||
|
if gce_config.OPTIONS_GROUP.name not in conf:
|
||||||
|
config.register_opt_group(conf, gce_config.OPTIONS_GROUP,
|
||||||
|
gce_config.OPTIONS)
|
||||||
|
|
||||||
|
def get_opt_lists(self):
|
||||||
|
return [(gce_config.OPTIONS_GROUP.name, config.OPTIONS)]
|
@ -15,6 +15,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
import time
|
import time
|
||||||
@ -32,7 +33,7 @@ from gceapi.tests.functional import config
|
|||||||
from gceapi.tests.functional import credentials
|
from gceapi.tests.functional import credentials
|
||||||
|
|
||||||
|
|
||||||
CONF = config.CONF.gce
|
CONF = config.CONF
|
||||||
LOG = logging.getLogger("gceapi")
|
LOG = logging.getLogger("gceapi")
|
||||||
API_NAME = 'compute'
|
API_NAME = 'compute'
|
||||||
API_VER = 'v1'
|
API_VER = 'v1'
|
||||||
@ -87,6 +88,30 @@ class LocalRefResolver(jsonschema.RefResolver):
|
|||||||
return super(LocalRefResolver, self).resolve_from_url(url)
|
return super(LocalRefResolver, self).resolve_from_url(url)
|
||||||
|
|
||||||
|
|
||||||
|
class SchemaHolder(object):
|
||||||
|
|
||||||
|
_instance = None
|
||||||
|
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
if not cls._instance:
|
||||||
|
cls._instance = super(SchemaHolder, cls).__new__(
|
||||||
|
cls, *args, **kwargs)
|
||||||
|
return cls._instance
|
||||||
|
|
||||||
|
_schema = None
|
||||||
|
|
||||||
|
def get_schema(self, schema_file):
|
||||||
|
if self._schema:
|
||||||
|
return self._schema
|
||||||
|
|
||||||
|
schema_path = os.path.join(config.get_base_dir(), schema_file)
|
||||||
|
# Load API scheme for API calls validation
|
||||||
|
with open(schema_path, 'r') as f:
|
||||||
|
self._schema = json.load(f)
|
||||||
|
|
||||||
|
return self._schema
|
||||||
|
|
||||||
|
|
||||||
class GCEApi(object):
|
class GCEApi(object):
|
||||||
def __init__(self, cred_provider):
|
def __init__(self, cred_provider):
|
||||||
self._compute = None
|
self._compute = None
|
||||||
@ -95,7 +120,8 @@ class GCEApi(object):
|
|||||||
self._scheme_ref_resolver = 0
|
self._scheme_ref_resolver = 0
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self._schema = schema.Schemas(CONF.schema)
|
_schema = SchemaHolder().get_schema(CONF.gce.schema)
|
||||||
|
self._schema = schema.Schemas(_schema)
|
||||||
self._scheme_ref_resolver = LocalRefResolver.from_schema(
|
self._scheme_ref_resolver = LocalRefResolver.from_schema(
|
||||||
self._schema.schemas)
|
self._schema.schemas)
|
||||||
self._build_api()
|
self._build_api()
|
||||||
@ -131,15 +157,15 @@ class GCEApi(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def _host_url(self):
|
def _host_url(self):
|
||||||
cfg = CONF
|
cfg = CONF.gce
|
||||||
if self._is_standard_port(cfg.protocol, cfg.port):
|
if self._is_standard_port(cfg.protocol, cfg.port):
|
||||||
return '{}://{}'.format(cfg.protocol, cfg.host)
|
return '{}://{}'.format(cfg.protocol, cfg.host)
|
||||||
return '{}://{}:{}'.format(cfg.protocol, cfg.host, cfg.port)
|
return '{}://{}:{}'.format(cfg.protocol, cfg.host, cfg.port)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _discovery_url(self):
|
def _discovery_url(self):
|
||||||
t = '{}{}' if CONF.discovery_url.startswith('/') else '{}/{}'
|
t = '{}{}' if CONF.gce.discovery_url.startswith('/') else '{}/{}'
|
||||||
return t.format(self._host_url, CONF.discovery_url)
|
return t.format(self._host_url, CONF.gce.discovery_url)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _api_url(self):
|
def _api_url(self):
|
||||||
@ -147,14 +173,14 @@ class GCEApi(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def project_url(self):
|
def project_url(self):
|
||||||
return '{}/projects/{}'.format(self._api_url, CONF.project_id)
|
return '{}/projects/{}'.format(self._api_url, CONF.gce.project_id)
|
||||||
|
|
||||||
def get_zone_url(self, resource=None, zone=None):
|
def get_zone_url(self, resource=None, zone=None):
|
||||||
if resource and self._is_absolute_url(resource):
|
if resource and self._is_absolute_url(resource):
|
||||||
return resource
|
return resource
|
||||||
z = zone
|
z = zone
|
||||||
if z is None:
|
if z is None:
|
||||||
z = CONF.zone
|
z = CONF.gce.zone
|
||||||
if not self._is_absolute_url(z):
|
if not self._is_absolute_url(z):
|
||||||
t = '{}/{}' if z.startswith('zones/') else '{}/zones/{}'
|
t = '{}/{}' if z.startswith('zones/') else '{}/zones/{}'
|
||||||
z = t.format(self.project_url, z)
|
z = t.format(self.project_url, z)
|
||||||
@ -167,7 +193,7 @@ class GCEApi(object):
|
|||||||
return resource
|
return resource
|
||||||
r = region
|
r = region
|
||||||
if r is None:
|
if r is None:
|
||||||
r = CONF.region
|
r = CONF.gce.region
|
||||||
if not self._is_absolute_url(r):
|
if not self._is_absolute_url(r):
|
||||||
t = '{}/{}' if r.startswith('regions/') else '{}/regions/{}'
|
t = '{}/{}' if r.startswith('regions/') else '{}/regions/{}'
|
||||||
r = t.format(self.project_url, r)
|
r = t.format(self.project_url, r)
|
||||||
@ -197,7 +223,7 @@ class GCETestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def cfg(self):
|
def cfg(self):
|
||||||
return CONF
|
return CONF.gce
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def trace(msg):
|
def trace(msg):
|
||||||
@ -209,7 +235,7 @@ class GCETestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
cls._credentials_provider = credentials.CredentialsProvider(CONF)
|
cls._credentials_provider = credentials.CredentialsProvider(CONF.gce)
|
||||||
cls._api = GCEApi(cls._credentials_provider)
|
cls._api = GCEApi(cls._credentials_provider)
|
||||||
cls._api.init()
|
cls._api.init()
|
||||||
super(GCETestCase, cls).setUpClass()
|
super(GCETestCase, cls).setUpClass()
|
||||||
|
@ -33,6 +33,9 @@ console_scripts =
|
|||||||
gce-api=gceapi.cmd.api:main
|
gce-api=gceapi.cmd.api:main
|
||||||
gce-api-manage=gceapi.cmd.manage:main
|
gce-api-manage=gceapi.cmd.manage:main
|
||||||
|
|
||||||
|
tempest.test_plugins =
|
||||||
|
gce_tests = gceapi.tests.functional.plugin:GCETempestPlugin
|
||||||
|
|
||||||
[build_sphinx]
|
[build_sphinx]
|
||||||
all_files = 1
|
all_files = 1
|
||||||
build-dir = doc/build
|
build-dir = doc/build
|
||||||
|
Loading…
Reference in New Issue
Block a user