diff options
95 files changed, 9502 insertions, 1324 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..33a0451bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*~ +.*.sw? +/docs_build/ +/docs_output/ +/releng/ @@ -14,22 +14,25 @@ Committers: pbandzi@cisco.com sama@docomolab-euro.com jose.lausuch@ericsson.com -Andrew.Caldwell@metaswitch.com morgan.richomme@orange.com -Palani.Chinnakannan@gmail.com trevor.cooper@intel.com Prabu.Kuppuswamy@spirent.com fuqiao@chinamobile.com -chitti.nimmagadda@ericsson.com -raja.karthik@hp.com -vivekanandan.p@hp.com -yuyijun@huawei.com koffirodrigue@gmail.com -Peng.Li@huawei.com +dk068x@att.com +meimei@huawei.com +valentin.boucher@orange.com +lanqinglong@huawei.com +viktor.tikkanen@nokia.com +juha.kosonen@nokia.com +zhanghaoyu7@huawei.com +raghavendrachari.kamsali@hpe.com +lixiaoguang5@huawei.com Link to TSC approval of the project: http://meetbot.opnfv.org/meetings/opnfv-meeting/2015/opnfv-meeting.2015-01-20-14.57.html -Link(s) to approval of additional committers: http://lists.opnfv.org/pipermail/opnfv-tech-discuss/2015-April/001971.html +Link(s) to approval of additional committers: +http://lists.opnfv.org/pipermail/opnfv-tech-discuss/2015-April/001971.html +http://ircbot.wl.linuxfoundation.org/meetings/opnfv-testperf/2015/opnfv-testperf.2015-09-29-13.00.html -* Addition of the following committers was approved by majority vote of exisitng committers: pbandzi@cisco.com, sama@docomolab-euro.com, jose.lausuch@ericsson.com ,Andrew.Caldwell@metaswitch.com, morgan.richomme@orange.com, iben.rodriguez@spirent.com diff --git a/commons/ims/readme.rst b/commons/ims/readme.rst new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/commons/ims/readme.rst diff --git a/commons/mobile/readme.rst b/commons/mobile/readme.rst new file mode 100644 index 000000000..07c872503 --- /dev/null +++ b/commons/mobile/readme.rst @@ -0,0 +1,116 @@ +Mobility Traffic Profiles for OPNFV +=================================== + +Mobility User-Plane ++++++++++++++++++++ + +The following tables describe per-session average (in a range) for user-plane traffic related to classes of applications. + +Downlink Mobility User-Plane +---------------------------- + +.. list-table:: Downlink Mobility User-Plane + :widths: 25 25 25 25 + :header-rows: 1 + + * - Service/protocol + - Downlink Packet Size (bytes) + - Downlink Flow Size (KB) + - Downlink per-flow Throughput (Kbps) + + * - Browsing + Apps + - 1,220 - 1,260 + - 40 - 55 + - 130 - 253 + + * - HTTPS traffic + - 1,050 - 1,085 + - 32 - 40 + - 107 - 124 + + * - Video Streaming + - 1,360 - 1,390 + - 545 - 650 + - 690 - 790 + + * - VoLTE bearer (media, excluding signaling) + - 84 – 102 + - 116 - 142 + - 18 - 24 + + +Uplink Mobility User-Plane +-------------------------- +.. list-table:: Uplink Mobility User-Plane + :widths: 25 25 25 25 + :header-rows: 1 + + * - Service/protocol + - Uplink Packet Size (bytes) + - Uplink Flow Size (KB) + - Uplink per-flow Throughput (Kbps) + + * - Browsing + Apps + - 90 – 120 + - 3 – 10 + - 6 – 18 + + * - HTTPS traffic + - 140 – 200 + - 5 – 12 + - 8 – 15 + + * - Video Streaming + - 50 – 110 + - 10 – 20 + - 12 - 20 + + * - VoLTE bearer (media, excluding signaling) + - 84 – 102 + - 112 - 135 + - 18 - 24 + + +Mobility User-Plane Traffic Distribution +---------------------------------------- +.. list-table:: Mobility User-Plane Traffic Distribution + :widths: 33 33 33 + :header-rows: 1 + + * - Service/protocol + - Downlink + - Uplink + + * - HTTP + - 40 - 70% (60 – 40 split between ‘browsing + apps’ and ‘streaming’) + - 30 - 50% (55 – 45 split between ‘browsing + apps’ and ‘streaming’) + + * - HTTPS + - 25 - 50% + - 40 - 60% + + * - Email + - 1% + - 3% + + * - P2P + - 0.1% + - 0.5% + + * - VoLTE + - 0-5% + - 5-30% + + * - Others + - 4% + - 8% + +Mobility Control-Plane +++++++++++++++++++++++ + +This section will provide average per-session mobility control-plane traffic for various protocols associated with applications. + +Mobility Sessions per Hour +++++++++++++++++++++++++++ + +This section will provide per-hour average and min-max ranges for mobility application sessions. diff --git a/commons/traffic-profile-guidelines.rst b/commons/traffic-profile-guidelines.rst new file mode 100644 index 000000000..0b965b156 --- /dev/null +++ b/commons/traffic-profile-guidelines.rst @@ -0,0 +1,64 @@ +================================ +OPNFV traffic profile guidelines +================================ + +.. contents:: + +.. _introduction: + +------------ +Introduction +------------ + +In order to have consistent testing profiles, it has been suggested to define and store traffic profiles. +These profiles shall be based on operator representative scenario. + +These reference profiles may be used by any test projects, unitary, functional or performance tests. +It is possible to adapt them to specific testcases. +It is recommended to use them in order to avoid getting as many profiles as tests. +It should be helpful to compare the results of test scenario. + +.. _howto: + +------------------------- +How to use these profiles +------------------------- + +The directory of the traffic profiles may be described as follow:: + + ├── commons + ├── ims + │ └── readme.rst + ├── mobile + │ └── readme.rst + └── traffic-profile-guidelines.rst + +the readme.rst details the profile. + + +.. _overview: + +------------------------ +Traffic profile overview +------------------------ + +The current profiles are available: + * Mobile traffic + * IMS residential traffic + * ... + +Mobile traffic +============== + +IMS residential traffic +======================= + + + + + +.. _reference: + +--------- +reference +--------- diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 000000000..69c2bd48f --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,76 @@ +######################################## +# Docker container for FUNCTEST +######################################## +# Purpose: run all the tests against the POD +# from a pre-installed docker image +# +# Maintained by Jose Lausuch +# Build: +# $ docker build -t opnfv/functest:tag . +# +# Execution: +# $ docker run -t -i \ +# -e "INSTALLER_TYPE=fuel|apex|compass|joid \ +# -e "INSTALLER_IP=10.20.0.2/172.30.10.73" \ +# -v $(pwd)/config_functest.yaml:/home/opnfv/functest/conf/config_functest.yaml +# opnfv/functest /bin/bash +# +# NOTE: providing config_functest.yaml is optional. If not provided, it will +# use the default one located in the repo + + +FROM ubuntu:14.04 +MAINTAINER Jose Lausuch <jose.lausuch@ericsson.com> +LABEL version="0.1" description="OPNFV Functest Docker container" + +ENV HOME /home/opnfv +ENV repos_dir /home/opnfv/repos +ENV creds /home/opnfv/functest/conf/openstack.creds +WORKDIR /home/opnfv + +# Packaged dependencies +RUN apt-get update && apt-get install -y \ +ssh \ +sshpass \ +curl \ +git \ +gcc \ +wget \ +python-dev \ +python-pip \ +bundler \ +postgresql \ +build-essential \ +libpq-dev \ +libxslt-dev \ +libssl-dev \ +libgmp3-dev \ +libxml2-dev \ +libffi-dev \ +crudini \ +ruby1.9.1-dev \ +--no-install-recommends + + +RUN mkdir -p ${repos_dir} +RUN mkdir -p /root/.ssh +RUN chmod 700 /root/.ssh + +RUN git config --global http.sslVerify false +RUN git clone -b stable/brahmaputra https://gerrit.opnfv.org/gerrit/functest ${repos_dir}/functest +RUN git clone https://gerrit.opnfv.org/gerrit/releng ${repos_dir}/releng +RUN git clone https://gerrit.opnfv.org/gerrit/doctor ${repos_dir}/doctor +RUN git clone https://github.com/openstack/rally.git ${repos_dir}/rally +RUN git clone https://github.com/opendaylight/integration.git ${repos_dir}/odl_integration +RUN git clone -b stable https://github.com/boucherv-orange/clearwater-live-test ${repos_dir}/vims-test +RUN git clone https://github.com/openstack/networking-bgpvpn ${repos_dir}/bgpvpn +RUN git clone https://gerrit.onosproject.org/OnosSystemTest ${repos_dir}/onos +RUN git clone https://github.com/opnfv/promise ${repos_dir}/promise + +RUN pip install -r ${repos_dir}/functest/docker/requirements.pip +RUN pip install -r ${repos_dir}/rally/requirements.txt + +ADD http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img /home/opnfv/functest/data/ + +RUN gpg --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 +RUN curl -L https://get.rvm.io | bash -s stable diff --git a/docker/common.sh b/docker/common.sh new file mode 100755 index 000000000..f03572d76 --- /dev/null +++ b/docker/common.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +# +# Author: Jose Lausuch (jose.lausuch@ericsson.com) +# +# Installs the Functest framework within the Docker container +# and run the tests automatically +# +# If config_functest.yaml is given by the docker run command, +# it must be run like this: +# +# docker run -ti \ +# -e "INSTALLER_TYPE=<something>" \ +# -e "INSTALLER_IP=<ip>" \ +# -v $(pwd)/config_functest.yaml:/home/opnfv/functest/conf/config_functest.yaml \ +# opnfv/functest /bin/bash +# +# NOTE: $(pwd)/config_functest.yaml means that it will take the one in the +# current directory. +# +# If it is not provided, take the existing one in the functest repo +# + +# this pull is to be removed right before the B release, once we build +# a release candidate docker +cd $repos_dir/functest +git pull + +mkdir -p /home/opnfv/functest/conf +config_file=/home/opnfv/functest/conf/config_functest.yaml +if [ ! -f ${config_file} ]; then + default_config_file=$(find /home/opnfv/repos -name config_functest.yaml) + cp $default_config_file $config_file + echo "config_functest.yaml not provided. Using default one" +fi + + +# Parse config_functest.yaml file +# TODO: this is not the best way to parse a yaml file in bash... + +# Directories +REPOS_DIR=$(cat $config_file | grep -w dir_repos | awk 'END {print $NF}') +FUNCTEST_REPO_DIR=$(cat $config_file | grep -w dir_repo_functest | awk 'END {print $NF}') +RALLY_REPO_DIR=$(cat $config_file | grep -w dir_repo_rally | awk 'END {print $NF}') +RELENG_REPO_DIR=$(cat $config_file | grep -w dir_repo_releng | awk 'END {print $NF}') +VIMS_REPO_DIR=$(cat $config_file | grep -w dir_repo_vims_test | awk 'END {print $NF}') +BGPVPN_REPO_DIR=$(cat $config_file | grep -w dir_repo_bgpvpn | awk 'END {print $NF}') + +FUNCTEST_DIR=$(cat $config_file | grep -w dir_functest | awk 'END {print $NF}') +FUNCTEST_RESULTS_DIR=$(cat $config_file | grep -w dir_results | awk 'END {print $NF}') +FUNCTEST_CONF_DIR=$(cat $config_file | grep -w dir_functest_conf | awk 'END {print $NF}') +FUNCTEST_DATA_DIR=$(cat $config_file | grep -w dir_functest_data | awk 'END {print $NF}') +RALLY_VENV_DIR=$(cat $config_file | grep -w dir_rally_inst | awk 'END {print $NF}') + +# Repos +RALLY_BRANCH=$(cat $config_file | grep -w rally_branch | awk 'END {print $NF}') +RALLY_COMMIT=$(cat $config_file | grep -w rally_commit | awk 'END {print $NF}') +FUNCTEST_BRANCH=$(cat $config_file | grep -w functest_branch | awk 'END {print $NF}') +FUNCTEST_COMMIT=$(cat $config_file | grep -w functest_commit | awk 'END {print $NF}') +RELENG_BRANCH=$(cat $config_file | grep -w releng_branch | awk 'END {print $NF}') +RELENG_COMMIT=$(cat $config_file | grep -w releng_commit | awk 'END {print $NF}') +VIMS_BRANCH=$(cat $config_file | grep -w vims_test_branch | awk 'END {print $NF}') +VIMS_COMMIT=$(cat $config_file | grep -w vims_test_commit | awk 'END {print $NF}') +BGPVPN_BRANCH=$(cat $config_file | grep -w bgpvpn_branch | awk 'END {print $NF}') +BGPVPN_COMMIT=$(cat $config_file | grep -w bgpvpn_commit | awk 'END {print $NF}') +ONOS_BRANCH=$(cat $config_file | grep -w onos_branch | awk 'END {print $NF}') +ONOS_COMMIT=$(cat $config_file | grep -w onos_commit | awk 'END {print $NF}') +PROMISE_BRANCH=$(cat $config_file | grep -w promise_branch | awk 'END {print $NF}') +PROMISE_COMMIT=$(cat $config_file | grep -w promise_commit | awk 'END {print $NF}') + + +echo "_____Parsed needed data from ${config_file}:" +echo "####### Directories #######" +echo "REPOS_DIR=${REPOS_DIR}" +echo "FUNCTEST_REPO_DIR=${FUNCTEST_REPO_DIR}" +echo "RALLY_REPO_DIR=${RALLY_REPO_DIR}" +echo "RELENG_REPO_DIR=${RELENG_REPO_DIR}" +echo "VIMS_REPO_DIR=${VIMS_REPO_DIR}" +echo "FUNCTEST_DIR=${FUNCTEST_DIR}" +echo "FUNCTEST_RESULTS_DIR=${FUNCTEST_RESULTS_DIR}" +echo "FUNCTEST_CONF_DIR=${FUNCTEST_CONF_DIR}" +echo "FUNCTEST_DATA_DIR=${FUNCTEST_DATA_DIR}" +echo "RALLY_VENV_DIR=${RALLY_VENV_DIR}" +echo "####### Repositories #######" +echo "FUNCTEST_BRANCH=${FUNCTEST_BRANCH}" +echo "FUNCTEST_COMMIT=${FUNCTEST_COMMIT}" +echo "RELENG_BRANCH=${RELENG_BRANCH}" +echo "RELENG_COMMIT=${RELENG_COMMIT}" +echo "RALLY_BRANCH=${RALLY_BRANCH}" +echo "RALLY_COMMIT=${RALLY_COMMIT}" +echo "VIMS_BRANCH=${VIMS_BRANCH}" +echo "VIMS_COMMIT=${VIMS_COMMIT}" +echo "ONOS_BRANCH=${ONOS_BRANCH}" +echo "ONOS_COMMIT=${ONOS_COMMIT}" +echo "PROMISE_BRANCH=${PROMISE_BRANCH}" +echo "PROMISE_COMMIT=${PROMISE_COMMIT}" +echo "############################" + +info () { + logger -s -t "FUNCTEST.info" "$*" +} + + +error () { + logger -s -t "FUNCTEST.error" "$*" + exit 1 +} diff --git a/docker/prepare_env.sh b/docker/prepare_env.sh new file mode 100755 index 000000000..48320d4cc --- /dev/null +++ b/docker/prepare_env.sh @@ -0,0 +1,210 @@ +#!/bin/bash + +# +# Author: Jose Lausuch (jose.lausuch@ericsson.com) +# +# Installs the Functest framework within the Docker container +# and run the tests automatically +# + +usage="Script to prepare the Functest environment. + +usage: + bash $(basename "$0") [--offline] [-h|--help] [-t <test_name>] + +where: + -o|--offline optional offline mode (experimental) + -h|--help show this help text + +examples: + $(basename "$0") + $(basename "$0") --offline" + +offline=false + +# Parse parameters +while [[ $# > 0 ]] + do + key="$1" + case $key in + -h|--help) + echo "$usage" + exit 0 + shift + ;; + -o|--offline) + offline=true + ;; + *) + error "unknown option $1" + exit 1 + ;; + esac + shift # past argument or value +done + +BASEDIR=`dirname $0` +source ${BASEDIR}/common.sh + +# Support for Functest offline +# NOTE: Still not 100% working when running the tests + +info "######### Preparing Functest environment #########" +if [ $offline == false ]; then + info "MODE: online" +else + info "MODE: offline" +fi + +# definition of available installer names +INSTALLERS=(fuel compass apex joid) + +if [ ! -f ${FUNCTEST_CONF_DIR}/openstack.creds ]; then + # If credentials file is not given, check if environment variables are set + # to get the creds using fetch_os_creds.sh later on + info "Checking environment variables INSTALLER_TYPE and INSTALLER_IP" + if [ -z ${INSTALLER_TYPE} ]; then + error "Environment variable 'INSTALLER_TYPE' is not defined." + elif [[ ${INSTALLERS[@]} =~ ${INSTALLER_TYPE} ]]; then + info "INSTALLER_TYPE env variable found: ${INSTALLER_TYPE}" + else + error "Invalid environment variable INSTALLER_TYPE=${INSTALLER_TYPE}" + fi + + if [ -z ${INSTALLER_IP} ]; then + error "Environment variable 'INSTALLER_IP' is not defined." + fi + info "INSTALLER_IP env variable found: ${INSTALLER_IP}" +fi + + +if [ $offline == false ]; then + # Update repos + info "Updating Releng repository...." + cd ${RELENG_REPO_DIR} + if [ ${RELENG_BRANCH} != "master" ]; then + info "Releng repo: checkout ${RELENG_BRANCH} branch..." + git checkout ${RELENG_BRANCH} + fi + info "Releng repo: pulling to latest..." + git pull + if [ ${RELENG_COMMIT} != "latest" ]; then + info "Releng repo: given commit is ${RELENG_COMMIT}. Reseting..." + git reset --hard ${RELENG_COMMIT} + fi + + info "Updating Rally repository...." + cd ${RALLY_REPO_DIR} + if [ ${RALLY_BRANCH} != "master" ]; then + info "Rally repo: checkout ${RALLY_BRANCH} branch..." + git checkout ${RALLY_BRANCH} + fi + info "Rally repo: pulling to latest..." + git pull + # We leave the reset command for later. + + info "Updating vIMS test repository...." + cd ${VIMS_REPO_DIR} + if [ ${VIMS_BRANCH} != "stable" ]; then + info "Releng repo: checkout ${VIMS_TEST_BRANCH} branch..." + git checkout ${VIMS_BRANCH} + fi + info "vIMS test repo: pulling to latest..." + git pull + if [ ${VIMS_COMMIT} != "latest" ]; then + info "vIMS test repo: given commit is ${VIMS_TEST_COMMIT}. Reseting..." + git reset --hard ${VIMS_COMMIT} + fi + + info "Updating BGPVPN repository...." + cd ${BGPVPN_REPO_DIR} + if [ ${BGPVPN_BRANCH} != "master" ]; then + info "BGPVPN repo: checkout ${BGPVPN_BRANCH} branch..." + git checkout ${BGPVPN_BRANCH} + fi + info "BGPVPN repo: pulling to latest..." + git pull + if [ ${BGPVPN_COMMIT} != "latest" ]; then + info "BGPVPN repo: given commit is ${BGPVPN_COMMIT}. Reseting..." + git reset --hard ${BGPVPN_COMMIT} + fi + + info "Updating ONOS repository...." + cd ${ONOS_REPO_DIR} + if [ ${ONOS_BRANCH} != "master" ]; then + info "ONOS repo: checkout ${ONOS} branch..." + git checkout ${ONOS_BRANCH} + fi + info "ONOS repo: pulling to latest..." + git pull + if [ ${ONOS_COMMIT} != "latest" ]; then + info "ONOS repo: given commit is ${ONOS_COMMIT}. Reseting..." + git reset --hard ${ONOS_COMMIT} + fi + + info "Updating PROMISE repository...." + cd ${PROMISE_REPO_DIR} + if [ ${PROMISE_BRANCH} != "master" ]; then + info "PROMISE repo: checkout ${PROMISE} branch..." + git checkout ${PROMISE_BRANCH} + fi + info "PROMISE repo: pulling to latest..." + git pull + if [ ${PROMISE_COMMIT} != "latest" ]; then + info "PROMISE repo: given commit is ${PROMISE_COMMIT}. Reseting..." + git reset --hard ${PROMISE_COMMIT} + fi + +fi + +# We do this regardless if its online or offline mode. +# Assumption: the docker image contains a newer rally repo than the given commit. +if [ ${RALLY_COMMIT} != "latest" ]; then + cd ${RALLY_REPO_DIR} + info "Rally repo: given commit is ${RALLY_COMMIT}. Reseting..." + git reset --hard ${RALLY_COMMIT} +fi + + +# Create directories +mkdir -p ${FUNCTEST_CONF_DIR} +mkdir -p ${FUNCTEST_DATA_DIR} +mkdir -p ${FUNCTEST_RESULTS_DIR}/ODL + + + +# Create Openstack credentials file +if [ ! -f ${FUNCTEST_CONF_DIR}/openstack.creds ]; then + ${REPOS_DIR}/releng/utils/fetch_os_creds.sh -d ${FUNCTEST_CONF_DIR}/openstack.creds \ + -i ${INSTALLER_TYPE} -a ${INSTALLER_IP} + retval=$? + if [ $retval != 0 ]; then + error "Cannot retrieve credentials file from installation. Check logs." + exit $retval + fi +else + info "OpenStack credentials file given to the docker and stored in ${FUNCTEST_CONF_DIR}/openstack.creds." +fi +# Source credentials +source ${FUNCTEST_CONF_DIR}/openstack.creds + +# Check OpenStack +info "Checking that the basic OpenStack services are functional..." +${FUNCTEST_REPO_DIR}/testcases/VIM/OpenStack/CI/libraries/check_os.sh +RETVAL=$? +if [ $RETVAL -ne 0 ]; then + exit 1 +fi + +# Prepare Functest Environment +info "Functest: prepare Functest environment" +python ${FUNCTEST_REPO_DIR}/testcases/config_functest.py --debug start +retval=$? +if [ $retval != 0 ]; then + error "Error when configuring Functest environment" + exit $retval +fi + +ifconfig eth0 mtu 1450 + +echo "1" > ${FUNCTEST_CONF_DIR}/env_active diff --git a/docker/requirements.pip b/docker/requirements.pip new file mode 100644 index 000000000..8644154cf --- /dev/null +++ b/docker/requirements.pip @@ -0,0 +1,16 @@ +pyyaml==3.10 +gitpython==1.0.1 +python-neutronclient==2.6.0 +python-novaclient==2.28.1 +python-glanceclient==1.1.0 +python-cinderclient==1.4.0 +python-ceilometerclient==1.5.1 +python-keystoneclient==1.6.0 +virtualenv==1.11.4 +pexpect==4.0 +requests==2.8.0 +robotframework==2.9.1 +robotframework-requests==0.3.8 +robotframework-sshlibrary==2.1.1 +configObj==5.0.6 +Flask==0.10.1 diff --git a/docker/run_tests.sh b/docker/run_tests.sh new file mode 100755 index 000000000..2225791a4 --- /dev/null +++ b/docker/run_tests.sh @@ -0,0 +1,215 @@ +#!/bin/bash + +# +# Author: Jose Lausuch (jose.lausuch@ericsson.com) +# +# Installs the Functest framework within the Docker container +# and run the tests automatically +# + +usage="Script to trigger the tests automatically. + +usage: + bash $(basename "$0") [--offline] [-h|--help] [-t <test_name>] + +where: + -o|--offline optional offline mode (experimental) + -h|--help show this help text + -r|--report push results to database (false by default) + -t|--test run specific set of tests + <test_name> one or more of the following: vping,odl,rally,tempest,vims,onos, promise. Separated by comma. + + +examples: + $(basename "$0") + $(basename "$0") --test vping,odl + $(basename "$0") --offline -t tempest,rally" + + +# Support for Functest offline +# NOTE: Still not 100% working when running the tests +offline=false +report="" +# Get the list of runnable tests +# Check if we are in CI mode +if [[ -n "$DEPLOY_SCENARIO" && "$DEPLOY_SCENARIO" != "none" ]]; then + testcase=`cat /home/opnfv/functest/conf/testcase-list.txt` + arr_test=("$testcase") +else + arr_test=(vping tempest vims rally) +fi + +function clean_openstack(){ + echo -e "\n\nCleaning Openstack environment..." + python ${FUNCTEST_REPO_DIR}/testcases/VIM/OpenStack/CI/libraries/clean_openstack.py \ + --debug + echo -e "\n\n" +} + +function run_test(){ + test_name=$1 + echo "" + echo "----------------------------------------------" + echo " Running test case: $i" + echo "----------------------------------------------" + echo "" + case $test_name in + "vping") + info "Running vPing test..." + python ${FUNCTEST_REPO_DIR}/testcases/vPing/CI/libraries/vPing.py \ + --debug ${report} + ;; + "odl") + info "Running ODL test..." + neutron_ip=$(keystone catalog --service identity | grep publicURL | cut -f3 -d"/" | cut -f1 -d":") + odl_ip=$(keystone catalog --service network | grep publicURL | cut -f3 -d"/" | cut -f1 -d":") + usr_name=$(env | grep OS | grep OS_USERNAME | cut -f2 -d'=') + password=$(env | grep OS | grep OS_PASSWORD | cut -f2 -d'=') + odl_port=8181 + if [ $INSTALLER_TYPE == "fuel" ]; then + odl_port=8282 + elif [ $INSTALLER_TYPE == "apex" ]; then + pass + elif [ $INSTALLER_TYPE == "joid" ]; then + pass + elif [ $INSTALLER_TYPE == "compass" ]; then + pass + else + error "INSTALLER_TYPE not valid." + exit 1 + fi + ODL_PORT=$odl_port ODL_IP=$odl_ip NEUTRON_IP=$neutron_ip USR_NAME=$usr_name PASS=$password \ + ${FUNCTEST_REPO_DIR}/testcases/Controllers/ODL/CI/start_tests.sh + + # save ODL results + odl_logs="${FUNCTEST_REPO_DIR}/testcases/Controllers/ODL/CI/logs" + if [ -d ${odl_logs} ]; then + cp -Rf ${odl_logs} ${FUNCTEST_CONF_DIR}/ODL/ + fi + ;; + "tempest") + info "Running Tempest tests..." + python ${FUNCTEST_REPO_DIR}/testcases/VIM/OpenStack/CI/libraries/run_tempest.py \ + --debug -m custom ${report} + # save tempest.conf for further troubleshooting + tempest_conf="${RALLY_VENV_DIR}/tempest/for-deployment-*/tempest.conf" + if [ -f ${tempest_conf} ]; then + cp $tempest_conf ${FUNCTEST_CONF_DIR} + fi + clean_openstack + ;; + "vims") + info "Running vIMS test..." + python ${FUNCTEST_REPO_DIR}/testcases/vIMS/CI/vIMS.py \ + --debug ${report} + clean_openstack + ;; + "rally") + info "Running Rally benchmark suite..." + cinder type-create volume-test #provisional + python ${FUNCTEST_REPO_DIR}/testcases/VIM/OpenStack/CI/libraries/run_rally.py \ + --debug all ${report} + cinder type-delete $(cinder type-list|grep test|awk '{print $2}') + clean_openstack + + ;; + "bgpvpn_template") + info "Running BGPVPN Tempest test case..." + tempest_dir=$(find /root/.rally -type d -name for-deploy*) + # TODO: + # do the call of your test case here. + # the bgpvpn repo is cloned in $BGPVPN_REPO_DIR + # tempest is installed in $tempest_dir + # Suggestion: + # mkdir ${tempest_dir}/tempest/api/bgpvpn/ + # cp ${BGPVPN_REPO_DIR}/networking_bgpvpn_tempest/<whatever you need> \ + # ${tempest_dir}/tempest/api/bgpvpn/ + # ${tempest_dir}/run_tempest.sh tempest.api.bgpvpn.<test_case_name> + ;; + "onos") + info "Running ONOS test case..." + python ${FUNCTEST_REPO_DIR}/testcases/Controllers/ONOS/Teston/CI/onosfunctest.py + ;; + "promise") + info "Running PROMISE test case..." + # TODO + ;; + "doctor") + info "Running Doctor test..." + python ${FUNCTEST_REPO_DIR}/testcases/features/doctor.py + ;; + esac +} + + +# Parse parameters +while [[ $# > 0 ]] + do + key="$1" + case $key in + -h|--help) + echo "$usage" + exit 0 + shift + ;; + -o|--offline) + offline=true + ;; + -r|--report) + report="-r" + ;; + -t|--test|--tests) + TEST="$2" + shift + ;; + *) + echo "unknown option $1 $2" + exit 1 + ;; + esac + shift # past argument or value +done + +BASEDIR=`dirname $0` +source ${BASEDIR}/common.sh + + +# Check that the given tests are correct +if [ "${TEST}" != "" ]; then + arr_test_exec=(${TEST//,/ }) + for i in "${arr_test_exec[@]}"; do + if [[ " ${arr_test[*]} " != *" $i "* ]]; then + error "Unknown test: $i. Available tests are: ${arr_test[@]}" + fi + done + info "Tests to execute: ${TEST}." +fi + +if [ $offline == false ]; then + info "MODE: online" +else + info "MODE: offline" +fi + +# Check that the functest environment has been installed +if [ ! -f ${FUNCTEST_CONF_DIR}/env_active ]; then + error "The Functest environment is not installed. \ + Please run prepare_env.sh before running this script...." +fi + + +# Source credentials +info "Sourcing Credentials ${FUNCTEST_CONF_DIR}/openstack.creds to run the tests.." +source ${FUNCTEST_CONF_DIR}/openstack.creds + +# Run tests +if [ "${TEST}" != "" ]; then + for i in "${arr_test_exec[@]}"; do + run_test $i + done +else + info "Executing all the tests" + for i in "${arr_test[@]}"; do + run_test $i + done +fi diff --git a/docs/configguide/index.rst b/docs/configguide/index.rst new file mode 100644 index 000000000..85954e770 --- /dev/null +++ b/docs/configguide/index.rst @@ -0,0 +1,374 @@ +*********************************************** +OPNFV FUNCTEST configuration/installation guide +*********************************************** + +.. toctree:: + :numbered: + :maxdepth: 2 + +============ +Introduction +============ + +** DOCUMENT IS IN PROGRESS FOR BRAHMAPUTRA ** + +This document describes how to install and configure Functest in OPNFV. + +============= +Prerequisites +============= + +The installation of the OPNFV solution is out of scope of this document but can be found in XXX. +In the rest of the document the OPNFV solution would be considered as the System Under Test (SUT). + +Several prerequisites are needed for functest: + 1) docker must be installed on the Jumphost + 2) a connectivity from the jumphost to the SUT management network is needed + 3) an external network must be configured + +Docker installation +=================== + +.. _Ubuntu: https://docs.docker.com/installation/ubuntulinux/ +.. _RHEL: https://docs.docker.com/installation/rhel/ + +Log on your jumphost then install docker (e.g. for Ubuntu):: + + curl -sSL https://get.docker.com/ | sh + +Add your user to docker group to be able to run commands without sudo:: + + sudo usermod -aG docker <your_user> + + +References: + * Ubuntu_ + * RHEL_ + +Connectivy to OPNFV management network +====================================== + +Some of the Functest tools need to have access to the OpenStack management network of the controllers `[1]`_. + +For this reason and besides the public network, you need to configure an interface on the management network as well in your jumphost (or wherever you want to deploy the Functest docker to run the tests). + +Example:: + + The OPNFV Fuel installation uses VLAN tagged 300 and subnet 192.168.1.0/24 as Openstack Management network. + Supposing that eth1 is the physical interface with access to that subnet: + $ ip link add name eth1.300 link eth1 type vlan id 300 + $ ip link set eth1.300 up + $ ip addr add 192.168.1.66/24 dev eth1.300 + + +External network on SUT +======================= + +Some of the tests on VIM need an external network. You may perform functest without an external network but some of the tests will fail. +A default floating ip pool must be configured in nova.conf. + + + +======================= +High level architecture +======================= + +The high level architecture of Functest within OPNFV can be described as follow:: + + CIMC/Lights+out management Admin Private Public Storage + PXE + + + + + IP_PRIV/24 | | + | | + + | + | | | IP_PUB/24 | + | +--------------------------+ | | + | + | | | | | | | + +-----+ Jumphost | | | | | + | | +--------------------+ | | | + | | | | | | | + | | +------------------+ | | | | | + | | | | | | | | | + | | | Tools | +------------------------------+ | | + | | | - Rally | | | | | | + | | | - Robot | | | | | | + | | | - TestON | | | | | | + | | | | | | | | | + | | | Testcases | | | | | | + | | | - VIM | | | | | | + | | | -- vPing | | | | | | + | | | -- Tempest | | | | | | + | | | -- Rally | | | | | | + | | | - Controller | | | | | | + | | | -- odl | | | | | | + | | | -- onos | | | | | | + | | | -- opencontrail | | | | | | + | | | | | | | | | + | | | Features | | | | | | + | | | - vIMS | | | | | | + | | | | | | | | | + | | +------------------+ | | | | | + | | +----------------------------------------+ | + | | Functest Docker | | | | | + | | +-------------------------------------------------+ + | | | | | | | + | +--------------------------+ | | | | + | | | | | + | +----------------+ | | | | + | | 1 | | | | | + +----+ +--------------+-+ | | | | + | | | 2 | | | | | + | | | +--------------+-+ | | | | + | | | | 3 | | | | | + | | | | +--------------+-+ | | | | + | | | | | 4 | | | | | + | +-+ | | +--------------+-+ | | | | + | | | | | 5 +-----------------------+ | | | + | +-+ | | nodes for | | | | | + | | | | deploying +---------------------------------+ | | + | +-+ | opnfv | | | | | + | | | SUT +-------------------------------------------+ | + | +-+ | | | | | + | | +----------------------------------------------------+ + | +----------------+ | | | | + | | | | | + | + + + + + +All the components needed by Functest are in the docker file. +Thanks to docker, there is no more library issues. + +This docker file will: + * prepare the environment for functional testing + * retrieve SUT credentials + * perform the tests + * push the results into the OPNFV test result database + +This docker file can be integrated into CI or deployed independantly of the CI. +A description of the Brahmaputra testcases can be retrieved in the Functest user guide `[2]`_ + +Please note that the Functest container has been designed for OPNFV, however, it would be possible to adapt it to any VIM+controller environment as most of the testcases are upstream testcases. + +=================== +Manual Installation +=================== + +Pull the Functest Docker image from the hub:: + + $ docker pull opnfv/functest + +Check that the image is available:: + + $ docker images + +Run the docker container giving the environment variables + - INSTALLER_TYPE. Possible values are "apex", "compass", "fuel", "joid" or "foreman" (Arno). + - INSTALLER_IP. each installer has its installation strategy. Functest may need to know the IP of the installer to retrieve the credentials (e.g. usually "10.20.0.2" for fuel, not neede for joid, "172.30.10.73" foreman...) + +The minimum command to create the Functest docker file can be described as follow:: + + docker run -it -e "INSTALLER_IP=10.20.0.2" -e "INSTALLER_TYPE=fuel" opnfv/functest:latest_stable /bin/bash + +Optionnaly, it is possible to precise the container name through the option --name:: + + docker run --name "CONTAINER_NAME" -it -e "INSTALLER_IP=10.20.0.2" -e "INSTALLER_TYPE=fuel" opnfv/functest:latest_stable /bin/bash + +It is also possible to to indicate the path of the OpenStack creds using -v:: + + docker run -it -e "INSTALLER_IP=10.20.0.2" -e "INSTALLER_TYPE=fuel" -v <path_to_your_local_creds_file>:/home/opnfv/functest/conf/openstack.creds opnfv/functest:latest_stable /bin/bash + +Your local file will be paste within the container under /home/opnfv/functest/conf/openstack.creds and used by the different test suites. + +Once run you shall be inside the docker container and ready to run Functest. + +Inside the container, you must have the following arborescence:: + + `-- home + `-- opnfv + |-- functest + | |-- conf + | |-- data + | `-- results + `-- repos + |-- bgpvpn + |-- functest + |-- odl_integration + |-- rally + |-- releng + `-- vims-test + + +Basically the container includes: + + * Functest directory to store the configuration (the OpenStack creds are paste in /home/opngb/functest/conf), the data (images neede for test for offline testing), results (some temporary artifacts may be stored here) + * Repositories: the functest repository will be used to prepare the environement, run the tests. Other repositories are used for the installation of the tooling (e.g. rally) and/or the retrieval of feature projects scenarios (e.g. bgpvpn) + +The arborescence under the functest repo can be described as follow:: + + . + |-- INFO + |-- LICENSE + |-- commons + | |-- ims + | |-- mobile + | `-- traffic-profile-guidelines.rst + |-- docker + | |-- Dockerfile + | |-- common.sh + | |-- prepare_env.sh + | |-- requirements.pip + | `-- run_tests.sh + |-- docs + | |-- configguide + | |-- functest.rst + | |-- images + | `-- userguide + `-- testcases + |-- Controllers + |-- VIM + |-- __init__.py + |-- config_functest.py + |-- config_functest.yaml + |-- functest_utils.py + |-- functest_utils.pyc + |-- vIMS + `-- vPing + +We may distinguish 4 different folders: + + * commons: it is a folder dedicated to store traffic profile or any test inputs that could be reused by any test project + * docker: this folder includes the scripts that will be used to setup the environment and run the tests + * docs: this folder includes the user and installation/configuration guide + * testcases: this folder includes the scripts required by Functest internal test cases + + +Firstly run the script to install functest environment:: + + $ ${repos_dir}/functest/docker/prepare_env.sh + +NOTE: ${repos_dir} is a default environment variable inside the docker container, which points to /home/opnfv/repos + +Run the script to start the tests:: + + $ ${repos_dir}/functest/docker/run_tests.sh + +NOTE: This will run ALL the tests by default, see `[2]`_ for details + +Focus on the OpenStack credentials +================================== + +The OpenStack creds are needed to test the VIM. They can be retrieved in several ways: + * using the -v option when creating + * sourcing them manually once connected on the docker, once log perform a source <openstack_creds> + * automatically retrieved via a script (CI) + +If not source you will get an error during the test environnement preparation. + +Additional Options +================== + +In case you need to provide different configuration parameters to Functest (e.g. commit IDs or branches for the repositories, …) copy the config_functest.yaml from the repository to your current directory and run docker with a volume:: + + $ wget https://git.opnfv.org/cgit/functest/plain/testcases/config_functest.yaml + $ cmd1 = "/home/opnfv/repos/functest/docker/prepare_env.sh" + $ cmd2 = "/home/opnfv/repos/functest/docker/run_tests.sh" + $ docker run -t -e "INSTALLER_TYPE=fuel" -e "INSTALLER_IP=10.20.0.2" opnfv/functest \ + -v $(pwd)/config_functest.yaml:/home/opnfv/functest/conf/config_functest.yaml \ + "${cmd1} && ${cmd2}" + +================= +Integration in CI +================= +In CI we use the docker file and execute commande within the container from Jenkins. + +Docker creation in set-functest-env builder `[3]`_:: + + envs="INSTALLER_TYPE=${INSTALLER_TYPE} -e INSTALLER_IP=${INSTALLER_IP} -e NODE_NAME=${NODE_NAME}" + [...] + docker pull opnfv/functest:latest_stable + cmd="docker run -id -e $envs ${labconfig} ${sshkey} ${res_volume} opnfv/functest:latest_stable /bin/bash" + echo "Functest: Running docker run command: ${cmd}" + ${cmd} + docker ps -a + sleep 5 + container_id=$(docker ps | grep 'opnfv/functest:latest_stable' | awk '{print $1}' | head -1) + echo "Container ID=${container_id}" + if [ -z ${container_id} ]; then + echo "Cannot find opnfv/functest container ID ${container_id}. Please check if it is existing." + docker ps -a + exit 1 + fi + echo "Starting the container: docker start ${container_id}" + docker start ${container_id} + sleep 5 + docker ps + if [ $(docker ps | grep 'opnfv/functest:latest_stable' | wc -l) == 0 ]; then + echo "The container opnfv/functest with ID=${container_id} has not been properly started. Exiting..." + exit 1 + fi + cmd="${FUNCTEST_REPO_DIR}/docker/prepare_env.sh" + echo "Executing command inside the docker: ${cmd}" + docker exec ${container_id} ${cmd} + + +Test execution in functest-all builder `[3]`_:: + + echo "Functest: run $FUNCTEST_SUITE_NAME" + cmd="${FUNCTEST_REPO_DIR}/docker/run_tests.sh --test $FUNCTEST_SUITE_NAME ${flag}" + container_id=$(docker ps -a | grep opnfv/functest | awk '{print $1}' | head -1) + docker exec $container_id $cmd + +Docker clean in functest-cleanup builder `[3]`_:: + + echo "Cleaning up docker containers/images..." + # Remove previous running containers if exist + if [[ ! -z $(docker ps -a | grep opnfv/functest) ]]; then + echo "Removing existing opnfv/functest containers..." + docker ps | grep opnfv/functest | awk '{print $1}' | xargs docker stop + docker ps -a | grep opnfv/functest | awk '{print $1}' | xargs docker rm + fi + + # Remove existing images if exist + if [[ ! -z $(docker images | grep opnfv/functest) ]]; then + echo "Docker images to remove:" + docker images | head -1 && docker images | grep opnfv/functest + image_tags=($(docker images | grep opnfv/functest | awk '{print $2}')) + for tag in "${image_tags[@]}"; do + echo "Removing docker image opnfv/functest:$tag..." + docker rmi opnfv/functest:$tag + done + fi + + +============= +Configuration +============= + +Everything is preconfigured in the docker file. So except the credentials, there is no specific configuration needed. it is possible to customize the list of tests, see `[2]` for details. + +====== +Errors +====== + + + + + +========== +References +========== +.. _`[1]`: https://ask.openstack.org/en/question/68144/keystone-unable-to-use-the-public-endpoint/ +.. _`[2]`: url functest user guide +.. _`[3]`: https://git.opnfv.org/cgit/releng/tree/jjb/functest/functest-ci-jobs.yml + + +OPNFV main site: opnfvmain_. + +OPNFV functional test page: opnfvfunctest_. + +IRC support chan: #opnfv-testperf + +.. _opnfvmain: http://www.opnfv.org +.. _opnfvfunctest: https://wiki.opnfv.org/opnfv_functional_testing +.. _`OpenRC`: http://docs.openstack.org/user-guide/common/cli_set_environment_variables_using_openstack_rc.html +.. _`Rally installation procedure`: https://rally.readthedocs.org/en/latest/tutorial/step_0_installation.html +.. _`config_test.py` : https://git.opnfv.org/cgit/functest/tree/testcases/config_functest.py +.. _`config_functest.yaml` : https://git.opnfv.org/cgit/functest/tree/testcases/config_functest.yaml diff --git a/docs/functest.rst b/docs/functest.rst index de4c537c5..ed436f586 100644 --- a/docs/functest.rst +++ b/docs/functest.rst @@ -2,15 +2,21 @@ OPNFV functional test guide =========================== +.. contents:: + +------------ +Introduction +------------ + Testing is a key challenge of OPNFV. It shall be possible to run functional tests on any OPNFV solution. The goal of this document consists in -* a description of functional tests for OPNFV -* a description of the tools needed to perform these tests -* the procedure to configure the tools and the scenarios associated with these tests + * a description of functional tests for OPNFV + * a description of the tools needed to perform these tests + * the procedure to configure the tools and the scenarios associated with these tests -Functional tests shall be automated and collected results shall be used to improve the robustness and the reliability of the overall system. +Functional tests shall be automated (as much as possible) and collected results shall be used to improve the robustness and the reliability of the overall system. Function tests may cover any domain that could lead to improve the OPNFV solution and define "Telco Cloud" KPI. @@ -30,47 +36,66 @@ ETSI NFV defined 9 use cases (ref ETSI_): * Virtualization of the Home environment .. _`Openstack Telco Working Group`: https://wiki.openstack.org/wiki/TelcoWorkingGroup +.. _`functest guide`: https://wiki.opnfv.org/_media/opnfv-_functest.pdf + Most of the use cases are also discussed in upstream projects (e.g. `Openstack Telco Working Group`_ ) -For release 1 (Arno), 5 test suites have been selected: +For release 1 (Arno), 4 test suites have been selected: * Rally Bench test suite for Openstack * Openstack Tempest test suite * OpenDaylight test suite * vPing - * vIMS The 3 first suites are directly inherited from upstream projects. -vPing, that is already present in Tempest suite, has been developped to provided a basic "hellow world" functional test example. +vPing, that is already present in Tempest suite, has been developped to provided a basic "hello world" functional test example. .. _`Continuous Integration`: https://build.opnfv.org/ci/view/functest/ -vEPC, vPE, vHGW, vCDN use cases are not considered for first release. +vIMS, vEPC, vPE, vHGW, vCDN, vWhatever use cases are not considered for first release. It does not mean that such use cases cannot be tested on OPNFV Arno. -It means that these use cases have not been integrated in the `Continuous Integration`_ and no specific work (integration or developpment) have been done for R1. +It means that these testcases have not been integrated in the `Continuous Integration`_ and no specific work (integration or developpment) have been done for the first release. +We may expect that new VNFs and new scenarios will be created and integrated in the future releases. See `functest guide`_ for details. .. _prereqs: ------------- Prerequisites ------------- -We assume that an OPNFV solution has been installed. +We assume that an OPNFV Arno solution has been installed. -.. _here: TBC +.. _here: https://wiki.opnfv.org/documentation/Arno The installation of the OPNFV solution is out of scope of this document but can be found [here_]. In the rest of the document the OPNFV solution would be considered as the System Under Test (SUT). The installation and configuration of the tools needed to perform the tests will be described in the following sections. -For release 1, the tools are not automatically installed. +For Arno SR1, the tools are automatically installed. Manual sourcing of OpenStack credentials is no more required if you are fully integrated in the continuous integration. +A script has been added to automatically retrieve the credentials. +However, if you still install manually functest, you will need to source the rc file on the machine you are running the tests. +More details will be provided in the configuration section. .. _pharos: https://wiki.opnfv.org/pharos It is recommended to install the different tools on the jump host server as defined in the pharos_ project. -The high level architecture can be described as follow: -code:: +For functest, the following libraries are needed. You can install them either with yum install or apt-get install, depending on your operating system: + * python-pip + * python-dev + * libffi-dev + * libxml2-dev + * libxslt1-dev + +You will also need some Python modules: + * sudo pip install GitPython + * sudo pip install python-novaclient + * sudo pip install python-neutronclient + * sudo pip install python-glanceclient + * sudo pip install python-keystoneclient + + +The high level architecture can be described as follow:: CIMC/Lights+out management Admin Private Public Storage PXE @@ -90,9 +115,9 @@ code:: | | | | | | | | | | | | vPing | | | | | | | | | | | | | | | - | | | vIMS | | | | | | + | | | Tempest | | | | | | | | +----------+ | | | | | - | | FuncTests +-----------------------------------------+ | + | | FuncTest +-----------------------------------------+ | | | | | | | | | | +--------------------------------------------------+ | | | | | | | @@ -124,54 +149,15 @@ code:: Description of the test cases ----------------------------- -Rally bench test suite -====================== - -.. _Rally: https://wiki.openstack.org/wiki/Rally - -The OPNFV scenarios are based on the collection of Rally_ default scenarios: - * authenticate - * cinder - * nova - * vm - * glance - * keystone - * neutron - * quotas - -The goal of this test suite is to test the different modules of OpenStack and get significant figures that could help us to define telco Cloud KPI. - -This test suite provides performance information on VIM (OpenStack) part. - -No SLA were defined for release 1, we just consider whether the tests are passed or failed. - -In the future SLA shall be considered (e.g. accepting booting time for a given image with a given flavour). - -Through its integration in Continuous Integration, the evolution of the performance of these tests shall also be considered. - -Tempest -======= - -.. _Tempest: http://docs.openstack.org/developer/tempest/overview.html - -Tempest_ is the OpenStack Integration Test Suite. We use Rally to run Tempest suite. - -The goal of this test is to check the OpenStack installation (sanity checks). - - -OpenDaylight -============ - vPing ===== -The goal of this test can be described as follow: - -code:: +The goal of this test can be described as follow:: vPing testcase +-------------+ +-------------+ | | | | + | | | | | | Boot VM1 | | | +------------------>| | | | | | @@ -180,47 +166,109 @@ code:: | Tester | | System | | | Boot VM2 | Under | | +------------------>| Test | - | | Including Ping | | - | |at the end of boot | | + | | VM2 pings VM1 | | | | | | + | | Check console log | | + | | If ping: | | + | | exit OK | | + | | else (timeout) | | + | | exit KO | | | | | | - | | Check console | | - | | Grep Ping | | - | +------------------>| | | | | | +-------------+ +-------------+ -The vPing test case is already present in Tempest suite. +This example, using OpenStack Python clients can be considered as an "Hello World" example and may be modified for future use. + +In SR1, some code has been added in order to push the results (status and duration) into a centralized test result database. + +OpenDaylight +============ + +The ODL suite consists in a set of basic tests inherited from ODL project. The suite tests the creation and deletion of network, subnet, port though OpenDaylight and Neutron. + +The list of tests can be described as follow: + * Restconf.basic: Get the controller modules via Restconf + * Neutron.Networks + + * Check OpenStack Networks :: Checking OpenStack Neutron for known networks + * Check OpenDaylight Networks :: Checking OpenDaylight Neutron API + * Create Network :: Create new network in OpenStack + * Check Network :: Check Network created in OpenDaylight + * Neutron.Networks :: Checking Network created in OpenStack are pushed + + * Neutron.Subnets + + * Check OpenStack Subnets :: Checking OpenStack Neutron for known Subnets + * Check OpenDaylight subnets :: Checking OpenDaylight Neutron API + * Create New subnet :: Create new subnet in OpenStack + * Check New subnet :: Check new subnet created in OpenDaylight + * Neutron.Subnets :: Checking Subnets created in OpenStack are pushed + + * Neutron.Ports + + * Check OpenStack ports :: Checking OpenStack Neutron for known ports + * Check OpenDaylight ports :: Checking OpenDaylight Neutron API + * Create New Port :: Create new port in OpenStack + * Check New Port :: Check new subnet created in OpenDaylight + * Neutron.Ports :: Checking Port created in OpenStack are pushed + + * Delete Ports + + * Delete previously created subnet in OpenStack + * Check subnet deleted in OpenDaylight + * Check subnet deleted in OpenStack + + * Delete network + + * Delete previously created network in OpenStack + * Check network deleted in OpenDaylight + * Check network deleted in OpenStack + + * + + +Rally bench test suite +====================== + +.. _Rally: https://wiki.openstack.org/wiki/Rally + +Rally bench test suite consist in a suite of light performance tests on some of the OpenStack components. + +The goal of this test suite is to test the different modules of OpenStack and get significant figures that could help us to define telco Cloud KPI. + +The OPNFV scenarios are based on the collection of the existing Rally_ scenarios: + * authenticate + * cinder + * nova + * requests + * glance + * keystone + * neutron + * quotas + -This example, using OpenStack python clients can be considered as an "hellow World" example and may be modified for future use. +This test suite provides performance information on VIM (OpenStack) part. +No SLA were defined for release 1, we just consider whether the tests are passed or failed. -vIMS -==== +In the future SLA shall be defined (e.g. accepting booting time for a given image with a given flavour). -vIMS is one of the testcases defined by ETSI. +Through its integration in Continuous Integration, the evolution of the performance of these tests shall also be considered. -.. figure:: images/Ims_overview.png - :scale: 50 - :alt: IMS (src wikipedia) +Tempest +======= -the goal of this test consists in deploying a virtualized IP Multimedia Subsystem (vIMS) on OPNFV, configuring it to deliver services to a set of emulated SIP endpoints, deploying a virtualized test system that implements those emulated SIP endpoints, and performing a series of simple functional tests on the vIMS, including the ability to establish SIP sessions between emulated endpoints. +.. _Tempest: http://docs.openstack.org/developer/tempest/overview.html -This functional test will verify that - * The OpenStack Nova API can be called to instantiate a set of VMs that together comprise a vIMS network function - * The OpenStack Glance service is capable of serving up the required images - * The virtual networking component of the platform can provide working IP connectivity between and among the VMs - * The platform as a whole is capable of supporting the running of a real virtualized network function that delivers a typical service offered by a network operator, i.e. voice telephony +Tempest_ is the OpenStack Integration Test Suite. We use Rally to run Tempest suite. -Functional testing of vIMS in OPNFV Release 1 will be limited to a basic, non-scalable and non-fault-tolerant deployment of IMS. -Furthermore, in this release the vIMS will perform only control plane functions (i.e. processing of SIP signaling messages) and will not be passing RTP media streams. +The Tempest.conf configuration file is automatically generated by Rally then the Tempest suite is run, each test duration is measured. -In future releases, the same software elements can be deployed with multiple instances of each VNF component to provide a fault tolerant and dynamically scalable deployment of IMS. With the addition of virtualized Session Border Controller software elements, the scope of vIMS functional testing can be further expanded to include the handling of RTP media. +We considered the smoke test suite for Arno. -.. _clearwater: http://www.projectclearwater.org/ +The goal of this test is to to check the basic OpenStack functionality on a fresh installation. -The vIMS core function is based on the clearwater_ open source solution. .. _tooling_installation: @@ -229,26 +277,169 @@ The vIMS core function is based on the clearwater_ open source solution. Tooling installation ---------------------- -2 external tools are needed for the R1 functional tests: +.. _fetch_os_creds.sh: https://git.opnfv.org/cgit/releng/tree/utils/fetch_os_creds.sh + +2 external tools are needed for the functional tests on Arno: * Rally * Robot - -Rally -===== - -.. _`Rally installation procedure`: https://rally.readthedocs.org/en/latest/tutorial/step_0_installation.html - -.. _`OpenRC`: http://docs.openstack.org/user-guide/common/cli_set_environment_variables_using_openstack_rc.html - -The Rally creation can be describe as follow (ref: `Rally installation procedure`_): - * Create or enter a folder where you want to check out the tool repos. - * $ git clone https://git.openstack.org/openstack/rally - * $ ./rally/install_rally.sh - * configure your `OpenRC`_ file to let Rally access to your OpenStack, you can either export it from Horizon or build it manually (OpenStack credentials are required) - * $ source Your_OpenRC_file - * $ rally deployment create --fromenv --name=my-opnfv-test - * $ rally-manage tempest install +Rally is used for benchmarking and running Tempest. Robot is used for running OpenDaylight test suites. + +A script (config_test.py) has been created to simplify as much as possible the installation of the different suites of tests. + +This script config_test.py_ is hosted in OPNFV repository and uses the configuration file config_functest.yaml_:: + + usage: config_functest.py [-h] [-d] [-f] path action + + positional arguments: + repo_path path to the repository + action Possible actions are: 'start|check|clean' + + optional arguments: + -h, --help show this help message and exit + -d, --debug Debug mode + -f, --force used to avoid prompting the user for confirmation when cleaning functest environment. + +Actions + * start: will prepare the functional testing environment + * check: will check the configuration (scenarios available, environment variables properly set, networks,..) + * clean: will clean the functional test environement if existing + +This script will: + * Install Rally environment + * Install Robot environment + * Install Tempest + * Retrieve test scenarios + * Create temporary neutron private network (if needed) + * Create Glance images + + +When integrated in CI, there are no additional prerequisites. +When running functest manually, the only prerequisite consists in retrieving the OpenStack credentials (rc file). +This file shall be saved on the jumphost. It must be sourced by the user (who shall have sudo rights) executing the tests. + +For the Continuous Integration we store this file under $HOME/functest/opnfv-openrc.sh on the jumphost server so CI can automatically execute the suite of tests + +The procedure to set up functional testing environment can be described as follow: + +Log on the Jumphost server. Be sure you are no root then execute:: + + [user@jumphost]$ mkdir <Your_functest_directory> + [user@jumphost]$ cd <Your_functest_directory> + [user@jumphost]$ git clone https://git.opnfv.org/functest + [user@jumphost]$ cd testcases/ + +Modify and adapt needed parameters in the config_functest.yaml. Follow the instructions below. + +Retrieve OpenStack source file (configure your `OpenRC`_ file to let Rally access to your OpenStack, you can either export it from Horizon or build it manually (OpenStack credentials are required):: + + [user@jumphost]$ source Your_OpenRC_file + [user@jumphost]$ python <functest_repo_directory>/config_functest.py -d <Your_functest_directory> start + +In SR1, a script has been created: fetch_os_creds.sh_. This script retrieves automatically the credentials of your OpenStack solution. You may run it manually:: + + [user@jumphost]$ /home/jenkins-ci/functest/fetch_os_creds.sh -d <destination> -i <installer_type> -a <installer_ip> + +with + * installer_type = fuel or foreman + * installer_ip the IP of your installer + * the destination shall be the full path including the file name. + +Examples:: + + [user@jumphost]$./fetch_os_creds.sh -d ./credentials -i foreman -a 172.30.10.73 + [user@jumphost]$./fetch_os_creds.sh -d ./credentials -i fuel -a 10.20.0.2 + + +At the end of the git clone, the tree of <functest_repo_directory> will have the following structure:: + + |-- docs/ + | |-- functest.rst + | |-- images + | |-- Ims_overview.png + |-- INFO + |-- LICENSE + |-- testcases/ + |-- config_functest.py + |-- config_functest.yaml + |-- functest_utils.py + |-- Controllers/ + | |-- ODL/ + | |-- CI/ + | | |-- create_venv.sh + | | |-- custom_tests/ + | | | |-- neutron + | | |-- integration/ + | | | |-- distributions + | | | |-- features + | | | |-- feature-selector + | | | |-- packaging + | | | |-- pom.xml + | | | |-- test + | | | |-- vm + | | |-- logs + | | |-- requirements.pip + | | |-- start_tests.sh + | | |-- test_list.txt + | |-- ODL.md + |-- functest_utils.py + |-- VIM/ + | |-- OpenStack/ + | |-- CI/ + | | |-- libraries/ + | | | |-- run_rally.py + | | |-- suites/ + | | |-- opnfv-authenticate.json + | | |-- opnfv-cinder.json + | | |-- opnfv-glance.json + | | |-- opnfv-heat.json + | | |-- opnfv-keystone.json + | | |-- opnfv-neutron.json + | | |-- opnfv-nova.json + | | |-- opnfv-quotas.json + | | |-- opnfv-requests.json + | | |-- opnfv-smoke-green.json + | | |-- opnfv-smoke.json + | | |-- opnfv-tempest.json + | | |-- opnfv-vm.json + | |-- OpenStack.md + |-- vPing/ + |-- CI/ + |-- libraries/ + |-- vPing.py + + +NOTE: the Rally environment will be installed under ~/.rally/ the default Tempest configuration (automatically generated by Rally based on OpenStack credentials) can be found under .rally/tempest/for-deployment-<deployment_id>/tempest.conf + + +Configuration of config_functest.yaml +===================================== + +Do not change the directories structure: + + * image_name: name of the image that will be created in Glance + * image_url: URL of the image to be downloaded + * image_disk_format: glance image disk format (raw, qcow2, ...) + + * neutron_private_net_name: name of an OpenStack private network. If not existing, it will be created + * neutron_private_subnet_name: private subnet network to be created if not existing + * neutron_private_subnet_cidr: range of the private subnet. + * neutron_private_subnet_start: start IP + * neutron_private_subnet_end: end IP + * neutron_router_name: name of the router between the private and the public networks + + * ping_timeout: time out of the vPing test case + * vm_flavor: name of the flavor used to create the VMs + * vm_name_1: name of the first VM + * vm_name_2: name of the second VM + * ip_1: IP of the first VM (matching the private subnet cidr) + * ip_2: IP of the second VM + + +Please note that you need to install this environment only once. +As long as the credentials of the System Under Test do not change, there is no reason to modify the testing environment. + +If you need more details on Rally installation, see `Rally installation procedure`_. You can check if the configuration of rally is fine by typing 'rally deployment check', you shall see the list of available services as follow:: @@ -272,7 +463,6 @@ You can check if the configuration of rally is fine by typing 'rally deployment | UUID | Name | Size (B) | +--------------------------------------+----------------------------------------------+------------+ | 0a15951f-6388-4d5d-8531-79e7205eb140 | cirros_2015_04_10_13_13_18 | 13167616 | - | 67734efd-75f6-4919-991e-bba9855f3ae1 | Ubuntu 12.04 64b | 260637184 | | b1504066-045a-4f8f-8919-8c665ef3f400 | Ubuntu 14.04 64b | 253297152 | +--------------------------------------+----------------------------------------------+------------+ @@ -286,76 +476,63 @@ You can check if the configuration of rally is fine by typing 'rally deployment | accdc28c-5e20-4859-a5cc-61cf9009e56d | m1.small | 1 | 512 | | 10 | +--------------------------------------+---------------------+-------+----------+-----------+-----------+ -Robot -===== -Summary: Set up python2.7 virtual environment:: + # rally show networks + Networks for user `admin` in tenant `admin`: + +--------------------------------------+------------------------------+------+ + | ID | Label | CIDR | + +--------------------------------------+------------------------------+------+ + | 4f43c349-956f-4073-9ef6-75bf4e62a0e7 | functest-net | None | + | faefaab1-e503-41fc-875b-5e3112be49ed | provider_network | None | + +--------------------------------------+------------------------------+------+ - mkvirtualenv robot - - pip install requests - pip install robotframework - pip install robotframework-sshlibrary - pip install robotframework-requests +-------------- +Manual testing +-------------- vPing ===== -Make sure that nova services are up:: +You can run the vPing testcase by typing:: + + [user@jumphost]$ python <functest_repo_directory>/vPing/vPing.py -d <Your_functest_directory> - #nova service list - +----+----------------+--------+----------+---------+-------+ - | Id | Binary | Host | Zone | Status | State | - +----+----------------+--------+----------+---------+-------+ - | 1 | nova-conductor | xxxxxx | internal | enabled | up | - | 3 | nova-network | xxxxxx | internal | enabled | up | - | 4 | nova-scheduler | xxxxxx | internal | enabled | up | - | 5 | nova-compute | xxxxxx | nova | enabled | up | - +----+----------------+--------+----------+---------+-------+ +OpenDaylight +============ -.. _vPing.py: https://git.opnfv.org/cgit/functest/tree/testcases/vPing/CI/libraries/vPing.py +You can run ODL suite as follow:: -Retrieve vPing.py_ script from OPNFV git repo + [user@jumphost]$ python <functest_repo_directory>testcases/Controllers/ODL/CI/start_tests.sh -Make sure you have sourced your OpenRC file:: +ODL wiki page describes system preparation and running tests. See `Integration Group CSIT`_. - # source Your_OpenRC_file +.. _`Integration Group CSIT`: https://wiki.opendaylight.org/view/CrossProject:Integration_Group:CSIT ------------------------------- -Functional test configuration ------------------------------- Rally bench suite ================= -Rally bench scenarios have been aggregated in json files. -A script has been developed to simplify the management of the tests and the integration in CI, get it from git:: +You can run the script as follow:: - # wget https://git.opnfv.org/cgit/functest/tree/testcases/VIM/OpenStack/CI/libraries/run_rally.py + [user@jumphost]$ python <functest_repo_directory>/testcases/VIM/OpenStack/CI/libraries/run_rally.py <functest_repo_directory> <module_to_be_tested> -Several scenarios are available (all based on native Rally scenarios): - * glance - * nova +with <module_to_be_tested> set to: * authenticate + * cinder + * nova + * requests + * glance * keystone * neutron - * vm * quotas - * request - * tempest - * all (every module except tempest) - -You can run the script as follow:: - - # python run_rally.py keystone + * all The script will: - * get the json scenario (if not already available) and put it into the scenario folder - * run rally - * generate the html result page into the result folder as opnfv-[module name]-[timestamp].html - * generate the json result page into the result folder as opnfv-[module name]-[timestamp].json - * generate OK or KO + * run rally with the selected scenario + * generate the html result page into <result_folder>/<timestamp>/opnfv-[module name].html + * generate the json result page into <result_folder>/<timestamp>/opnfv-[module name].json + * generate OK or NOK per test based on json result file Tempest suite ============= @@ -363,50 +540,132 @@ Tempest suite It is possible to use Rally to perform Tempest tests (ref: `tempest installation guide using Rally`_) You just need to run:: - # rally verify start + # rally verify start smoke -The different modes available are smoke, baremetal, compute, data_processing, identity, image, network, object_storage, orchestration, telemetry, and volume. By default if you do not precise anything then smoke tests be selected by default. +The different modes available are smoke, baremetal, compute, data_processing, identity, image, network, object_storage, orchestration, telemetry, and volume. For Arno, it was decided to focus on smoke tests. .. _`tempest installation guide using Rally`: https://www.mirantis.com/blog/rally-openstack-tempest-testing-made-simpler/ -OpenDaylight -============ -ODL wiki page describes system preparation and running tests. See `Integration Group CSIT`_. -.. _`Integration Group CSIT`: https://wiki.opendaylight.org/view/CrossProject:Integration_Group:CSIT +.. _manualtest: +-------------- +Test results +-------------- vPing ===== +vPing result is displayed in the console:: + + Functest: run vPing + 2015-09-13 22:11:49,502 - vPing- INFO - Glance image found 'functest-img' + 2015-09-13 22:11:49,502 - vPing- INFO - Creating neutron network functest-net... + 2015-09-13 22:11:50,275 - vPing- INFO - Flavor found 'm1.small' + 2015-09-13 22:11:50,318 - vPing- INFO - vPing Start Time:'2015-09-13 22:11:50' + 2015-09-13 22:11:50,470 - vPing- INFO - Creating instance 'opnfv-vping-1' with IP 192.168.120.30... + 2015-09-13 22:11:58,803 - vPing- INFO - Instance 'opnfv-vping-1' is ACTIVE. + 2015-09-13 22:11:58,981 - vPing- INFO - Creating instance 'opnfv-vping-2' with IP 192.168.120.40... + 2015-09-13 22:12:09,169 - vPing- INFO - Instance 'opnfv-vping-2' is ACTIVE. + 2015-09-13 22:12:09,169 - vPing- INFO - Waiting for ping... + 2015-09-13 22:13:11,329 - vPing- INFO - vPing detected! + 2015-09-13 22:13:11,329 - vPing- INFO - vPing duration:'81.0' + 2015-09-13 22:13:11,329 - vPing- INFO - Cleaning up... + 2015-09-13 22:13:18,727 - vPing- INFO - Deleting network 'functest-net'... + 015-09-13 22:13:19,470 - vPing- INFO - vPing OK + +A json file is produced and pushed into the test result database. -By default, the script’s is configured as follow:: +OpenDaylight +============ +.. _`functest wiki (ODL section)`: https://wiki.opnfv.org/r1_odl_suite + + +The results of ODL tests can be seen in the console:: + + ============================================================================== + Basic + ============================================================================== + Basic.010 Restconf OK :: Test suite to verify Restconf is OK + ============================================================================== + Get Controller Modules :: Get the controller modules via Restconf | PASS | + ------------------------------------------------------------------------------ + Basic.010 Restconf OK :: Test suite to verify Restconf is OK | PASS | + 1 critical test, 1 passed, 0 failed + 1 test total, 1 passed, 0 failed + ============================================================================== + Basic | PASS | + 1 critical test, 1 passed, 0 failed + 1 test total, 1 passed, 0 failed + ============================================================================== + Output: /home/jenkins-ci/workspace/functest-opnfv-jump-2/output.xml + Log: /home/jenkins-ci/workspace/functest-opnfv-jump-2/log.html + Report: /home/jenkins-ci/workspace/functest-opnfv-jump-2/report.html + + .............................................................................. + + Neutron.Delete Networks :: Checking Network deleted in OpenStack a... | FAIL | + 2 critical tests, 1 passed, 1 failed + 2 tests total, 1 passed, 1 failed + ============================================================================== + Neutron :: Test suite for Neutron Plugin | FAIL | + 18 critical tests, 15 passed, 3 failed + 18 tests total, 15 passed, 3 failed + ============================================================================== + Output: /home/jenkins-ci/workspace/functest-opnfv-jump-2/output.xml + Log: /home/jenkins-ci/workspace/functest-opnfv-jump-2/log.html + Report: /home/jenkins-ci/workspace/functest-opnfv-jump-2/report.html + +3 result files are generated: + * output.xml + * log.html + * report.html + + ODL result page + +.. figure:: ./images/functestODL.png + :width: 170mm + :align: center + :alt: ODL suite result page + + +Known issues +------------ + +Tests are expected to fail now: + * Check port deleted in OpenDaylight + * Check subnet deleted in OpenDaylight + * Check Network deleted in OpenDaylight + +These failures to delete objects in OpenDaylight (when removed via OpenStack Neutron) are due to the following bug: https://bugs.opendaylight.org/show_bug.cgi?id=3052. + +More details on `functest wiki (ODL section)`_ - * OS_USERNAME: admin - * OS_PASSWORD: test - * OS_AUTH_URL: http://192.168.20.71:5000/v2.0 - * OS_TENANT_NAME: invisible_to_admin - * Name of VM: opnfv-vping-1 , opnfv-vping-2 - * Flavor: m1.small - * Image: Ubuntu 14.04 (amd64) - * Network: private +Rally bench suite +================= -The script needs to be tuned to your specific system configuration +.. _`functest wiki (Rally section)`: https://wiki.opnfv.org/r1_rally_bench -vIMS -==== +Results are available in the result folder through a html page and a json file. +It generates a result page per module and can be described as follow. +.. figure:: ./images/functestRally2.png + :align: center + :alt: Example of Rally keystone test results -.. _manualtest: --------------- -Test results --------------- +.. figure:: ./images/functestRally1.png + :scale: 50 % + :align: center + :alt: Details on Glance test from Rally bench suite -Rally bench suite -================= -Results are available in the result folder through a html page and a json file. +Known issues +------------ +- some tests of Cinder suite may be failed due to time-out (timer could probably be extended in the configuration file) +- some test of Nova & Neutron suite may fail due to network issues (previously created network not properly cleaned and/or quota exceeded because of created ressources that have not be properly cleaned) or ODL bugs (see `ODL bug lists`_). + +More details on `functest wiki (Rally section)`_. Tempest suite ============= @@ -415,32 +674,74 @@ You can get the results of tempest by typing:: # rally verify list +You shall see the results as follow:: + Total results of verification: + +--------------------------------------+--------------------------------------+----------+-------+----------+----------------------------+----------------+----------+ + | UUID | Deployment UUID | Set name | Tests | Failures | Created at | Duration | Status | + +--------------------------------------+--------------------------------------+----------+-------+----------+----------------------------+----------------+----------+ + | 546c678a-19c4-4b2e-8f24-6f8c5ff20635 | 9c13dbbe-7a80-43db-8d6c-c4a61f257c7f | smoke | 111 | 15 | 2015-09-14 06:18:54.896224 | 0:00:51.804504 | finished | + +--------------------------------------+--------------------------------------+----------+-------+----------+----------------------------+----------------+----------+ -OpenDaylight -============ +If you run this test several times, you will see as many lines as test attempts. -Tests can be executed with script *start_test.sh* from directory *functest/testcases/Controllers/ODL/CI*. For usage example see:: +You can get more details on the test by typing:: - # bash start_test.sh -h + # rally verify show --uuid <UUID of the test> + # rally verify detailed --uuid <UUID of the test> -vPing -===== -The test can be executed with command:: +"show" will show you all the restults including the time needed to execute the test. +"detailed" will display additional elements (errors) - #python vPing.py +Example of test result display:: -vIMS -==== + +------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------+--------+ + | name | time | status | + +------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------+--------+ + | tempest.api.network.test_routers.RoutersTest.test_create_show_list_update_delete_router[id-f64403e2-8483-4b34-8ccd-b09a87bcc68c,smoke] | 0.011466 | FAIL | + | tempest.api.network.test_security_groups.SecGroupIPv6Test.test_create_list_update_show_delete_security_group[id-bfd128e5-3c92-44b6-9d66-7fe29d22c802,smoke]| 1.234566 | OK | + | tempest.api.network.test_security_groups.SecGroupIPv6Test.test_create_show_delete_security_group_rule[id-cfb99e0e-7410-4a3d-8a0c-959a63ee77e9,smoke] | 1.060221 | OK | + | tempest.api.network.test_security_groups.SecGroupIPv6Test.test_list_security_groups[id-e30abd17-fef9-4739-8617-dc26da88e686,smoke] | 0.060797 | OK | + | tempest.api.network.test_security_groups.SecGroupTest.test_create_list_update_show_delete_security_group[id-bfd128e5-3c92-44b6-9d66-7fe29d22c802,smoke] | 0.685149 | OK | + | tempest.api.network.test_security_groups.SecGroupTest.test_create_show_delete_security_group_rule[id-cfb99e0e-7410-4a3d-8a0c-959a63ee77e9,smoke] | 0.730561 | OK | + | tempest.api.network.test_security_groups.SecGroupTest.test_list_security_groups[id-e30abd17-fef9-4739-8617-dc26da88e686,smoke] | 0.116862 | OK | + | tempest.api.object_storage.test_account_quotas.AccountQuotasTest | 0.0 | SKIP | + | ... | ... | ... | +Known issues +------------ + +.. _`Rally patch`: https://review.openstack.org/#/c/187481/ +.. _`automatically generated tempest.conf`: https://github.com/openstack/rally/blob/master/rally/verification/tempest/config.py +.. _`functest wiki (Tempest section)`: https://wiki.opnfv.org/r1_tempest +.. _`ODL bug lists`: https://bugs.opendaylight.org/buglist.cgi?component=General&product=neutron&resolution=--- + +Several tests are declared as failed. They can be divided in 2 main categories: + * Multiple possible networks found, use a Network ID to be more specific. + * Network errors + +The Multiple possible netwok error occurs several times and may have different origins. It indicates that the test needs a network context to be run properly. A change in the `automatically generated tempest.conf`_ file could allow to precise the network ID. + +The network errors are various and dealing with all the aspects of networking: create/update/delete network/subnet/port/router. Some may be due to (possible) bug in tempest when it tries to delete networks which should not be there for the following tests. Some may be caused by the ODL bugs, several bugs related to tempest are already reported in `ODL bug lists`_. + +The follow-up of these tests can be found on the `functest wiki (Tempest section)`_. + .. _automatictest: ------------------ Testing Automation ------------------ +For Arno, the CI job performs the following actions: + * clean and prepare functest environment + * run vPing + * run ODL tests + * run Rally Bench + * run Tempest + * clean functest environment + Connection of your platform =========================== @@ -469,3 +770,7 @@ IRC support chan: #opnfv-testperf .. _opnfvmain: http://www.opnfv.org .. _opnfvfunctest: https://wiki.opnfv.org/opnfv_functional_testing +.. _`OpenRC`: http://docs.openstack.org/user-guide/common/cli_set_environment_variables_using_openstack_rc.html +.. _`Rally installation procedure`: https://rally.readthedocs.org/en/latest/tutorial/step_0_installation.html +.. _`config_test.py` : https://git.opnfv.org/cgit/functest/tree/testcases/config_functest.py +.. _`config_functest.yaml` : https://git.opnfv.org/cgit/functest/tree/testcases/config_functest.yaml diff --git a/docs/images/clearwater-architecture.png b/docs/images/clearwater-architecture.png Binary files differnew file mode 100644 index 000000000..987362ac6 --- /dev/null +++ b/docs/images/clearwater-architecture.png diff --git a/docs/images/functestODL.png b/docs/images/functestODL.png Binary files differnew file mode 100644 index 000000000..6bf7580ee --- /dev/null +++ b/docs/images/functestODL.png diff --git a/docs/images/functestRally1.png b/docs/images/functestRally1.png Binary files differnew file mode 100644 index 000000000..3bfac09a7 --- /dev/null +++ b/docs/images/functestRally1.png diff --git a/docs/images/functestRally2.png b/docs/images/functestRally2.png Binary files differnew file mode 100644 index 000000000..dcd408b5b --- /dev/null +++ b/docs/images/functestRally2.png diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst new file mode 100644 index 000000000..0229e703f --- /dev/null +++ b/docs/userguide/index.rst @@ -0,0 +1,540 @@ +************************* +OPNFV FUNCTEST user guide +************************* + +.. toctree:: + :numbered: + :maxdepth: 2 + + +============ +Introduction +============ + +The goal of this document consists in describing the Functest test cases for Brahmaputra. +A presentation has been created for the first OPNFV Summit: `[4]` + +This guide will detail how to launch the different tests assuming that Functest container has been properly installed `[1]`_. + + +============================= +Description of the test cases +============================= + +Functest is an OPNFV project dedicated to functional testing. +In the continuous integration, it is launched after a fresh installation of an OPNFV solution to verify the basic functions. + +Functest includes several test suites that usually include several test cases. +Some are developped within the Functest project, some in dedicated feature projects. + +The current list of test suites can be distributed in 3 main domains: + ++--------------+----------------+---------------------------------------------------------+ +| Component | Testcase | Comments | ++--------------+----------------+---------------------------------------------------------+ +| | vPing | NFV Hello World | +| +----------------+---------------------------------------------------------+ +| VIM | Tempest | OpenStack reference test suite `[2]`_ | +| +----------------+---------------------------------------------------------+ +| | Rally scenario | OpenStack testing tool testing OpenStack modules `[3]`_ | ++--------------+----------------+---------------------------------------------------------+ +| | odl | | +| +----------------+---------------------------------------------------------+ +| Controllers | onos | | +| +----------------+---------------------------------------------------------+ +| | opencontrail | | ++--------------+----------------+---------------------------------------------------------+ +| Features | vIMS | Show the capability to deploy a real NFV testcase | +| +----------------+---------------------------------------------------------+ +| | X | | ++--------------+----------------+---------------------------------------------------------+ + + +Most of the test suites are developped upstream, Functest is in charge of the integration in OPNFV. +Tempest `[2]`_, for example, is the OpenStack reference test suite. + +In Functest we customized the list of tests within Tempest but do not created our own test cases. +Some OPNFV feature projects (.e.g. SDNVPN) may create tempest scenario upstream that are integrated in our Tempest through our configuration. + +The test results are pushed into a test result database (when possible) in order to build a test dashboard. + +There is no real notion of Test domain or Test coverage yet, we tried to cover basic components such as VIM and controllers and integrate the tests of the feature projects. + +The vIMS test case was also integrated to demonstrate the capability to deploy a relatively complex NFV scenario on top of the OPNFV infrastructure. + +Functest considers OPNFV as a black box. OPNFV, since Brahmaputra, offers lots of possible combination (3 controllers, 4 installers). + +However most of the tests (except obviously those dedicated to a specific controller) shall be runnable on any configuration. + +The different scenarios are described in the section hereafter. + +VIM +=== + +vPing +----- + +The goal of this test can be described as follow:: + + vPing test case + +-------------+ +-------------+ + | | | | + | | | | + | | Boot VM1 | | + | +------------------>| | + | | | | + | | Get IP VM1 | | + | +------------------>| | + | Tester | | System | + | | Boot VM2 | Under | + | +------------------>| Test | + | | VM2 pings VM1 | | + | | | | + | | Check console log | | + | | If ping: | | + | | exit OK | | + | | else (timeout) | | + | | exit KO | | + | | | | + | | | | + +-------------+ +-------------+ + + +This example, using OpenStack Python clients can be considered as an "Hello World" example and may be modified for future use. +It is the first basic example, it must work on any configuration. + +Tempest +------- + +Tempest `[2]`_ is the reference OpenStack Integration test suite. It is a set of integration tests to be run against a live OpenStack cluster. +Tempest has batteries of tests for OpenStack API validation, Scenarios, and other specific tests useful in validating an OpenStack deployment. + +We use Rally `[3]`_ to run Tempest suite. +The tempest.conf configuration file is automatically generated by Rally then the Tempest suite is run, each test duration is measured. + +We considered the smoke test suite for Arno. For Brahmaputra, we decided to customize the list of test cases using the --tests-file option introduced in Rally in version 0.1.2. + +The custom list is available on the Functest repo `[4]`_ and contains more than 200 test cases. +This list contains tempest test cases chosen for Functest deployment. +It consists of two main parts: + + 1) Set of tempest smoke test cases + 2) Set of test cases from DefCore list (https://wiki.openstack.org/wiki/Governance/DefCoreCommittee) + +The goal of this test is to check the basic OpenStack functionalities on an OPNFV fresh installation. + + +Rally bench test suites +----------------------- + +Rally `[3]`_ is a benchmarking tool that answers the question: “How does OpenStack work at scale?â€. + +The goal of this test suite is to test the different modules of OpenStack and get significant figures that could help us to define telco Cloud KPI. + +The OPNFV scenarios are based on the collection of the existing Rally scenarios: + * authenticate + * cinder + * glance + * heat + * keystone + * neutron + * nova + * quotas + * requests + * vm + +For Brahmaputra, we integrated the rally certification feature introduced in Rally 0.1.1. + +SLA + + +SDN Controllers +=============== + +Brahmaputra introduces new SDN controllers in addition of odl already integrated in Arno. +There are currently 3 possible controllers: + + * odl + * onos + * opencontrail + +OpenDaylight +------------ + +The ODL suite consists in a set of basic tests inherited from ODL project. +The suite tests the creation and deletion of network, subnet, port though OpenDaylight and Neutron. + +The list of tests can be described as follow:: + + * Restconf.basic: Get the controller modules via Restconf + * Neutron.Networks + + * Check OpenStack Networks :: Checking OpenStack Neutron for known networks + * Check OpenDaylight Networks :: Checking OpenDaylight Neutron API + * Create Network :: Create new network in OpenStack + * Check Network :: Check Network created in OpenDaylight + * Neutron.Networks :: Checking Network created in OpenStack are pushed + + * Neutron.Subnets + + * Check OpenStack Subnets :: Checking OpenStack Neutron for known Subnets + * Check OpenDaylight subnets :: Checking OpenDaylight Neutron API + * Create New subnet :: Create new subnet in OpenStack + * Check New subnet :: Check new subnet created in OpenDaylight + * Neutron.Subnets :: Checking Subnets created in OpenStack are pushed + + * Neutron.Ports + + * Check OpenStack ports :: Checking OpenStack Neutron for known ports + * Check OpenDaylight ports :: Checking OpenDaylight Neutron API + * Create New Port :: Create new port in OpenStack + * Check New Port :: Check new subnet created in OpenDaylight + * Neutron.Ports :: Checking Port created in OpenStack are pushed + + * Delete Ports + + * Delete previously created subnet in OpenStack + * Check subnet deleted in OpenDaylight + * Check subnet deleted in OpenStack + + * Delete network + + * Delete previously created network in OpenStack + * Check network deleted in OpenDaylight + * Check network deleted in OpenStack + + +ONOS +---- +TODO + +OpenContrail +------------ +TODO + + + +Features +======== + +vIMS +---- +The goal of this test suite consists in: + * deploying a VNF orchestrator (cloudify) + * deploy a Clearwater vIMS (IP Multimedia Subsystem) VNF from this orchestrator based on a TOSCA blueprint defined in `[5]`_ + * run suite of signaling tests on top of this VNF + +The Clearwater architecture may be described as follow: + +.. figure:: ../images/clearwater-architecture.png + :align: center + :alt: vIMS architecture + +The duration of each step (orchestion deployment, VNF deployment and test), as well as test results, are stored and, in CI, pushed into the test collection database. + +X +-- + +TODO + + +============== +Manual testing +============== + +Once you have installed Functest docker file `[1]`_, and configured the system (though /home/opnfv/repos/functest/docker/prepare_env.sh script), you are ready to run the tests. + +The script run_tests.sh has several options:: + + ./run_tests.sh -h + Script to trigger the tests automatically. + + usage: + bash run_tests.sh [--offline] [-h|--help] [-t <test_name>] + + where: + -o|--offline optional offline mode (experimental) + -h|--help show this help text + -r|--report push results to database (false by default) + -t|--test run specific set of tests + <test_name> one or more of the following: vping,odl,rally,tempest,vims. Separated by comma. + + examples: + run_tests.sh + run_tests.sh --test vping,odl + run_tests.sh --offline -t tempest,rally + +The -o option can be used to run the container offline (in case you are in a summit where there is no Internet connection...). It is an experimental option. + +The -r option is used by the Continuous Integration in order to push the test results into a test collection database, see in next section for details. In manual mode, you must not use it, your try will be anyway probably rejected as your POD must be declared in the database to collect the data. + +The -t option can be used to specify the list of test you want to launch, by default Functest will try to launch all its test suites in the following order vPing, odl, Tempest, vIMS, Rally. You may launch only one single test by using -t <the test you want to launch> + +Please note that Functest includes cleaning mechanism to remove everything except what was present after a fresh install. If you create VM, tenants, networks then launch Functest, there is a risk to remove elements. Be carefull or comment the cleaning phase in run_test.sh (comment call to clean_openstack.py). However, be aware that Tempest and rally triggers the creation of lots of components that are not always properly cleaned, this function has been set to keep the system as clean as possible after a full Functest run. + +You may also add you own test by adding a section into the function run_test() + + +================= +Automated testing +================= + +As mentioned in `[1]`, the prepare-env.sh and run_test.sh can be executed within the container from jenkins. 2 jobs have been created, one to run all the test and one that allows testing test suite by test suite. You thus just have to launch the acurate jenkins job on the target lab, all the tests shall be automatically run. + + +============ +Test results +============ + +VIM +=== + +vPing +----- + +vPing result is displayed in the console:: + + 2016-01-06 16:06:20,550 - vPing- INFO - Creating neutron network vping-net... + 2016-01-06 16:06:23,867 - vPing- INFO - Flavor found 'm1.small' + 2016-01-06 16:06:24,457 - vPing- INFO - vPing Start Time:'2016-01-06 16:06:24' + 2016-01-06 16:06:24,626 - vPing- INFO - Creating instance 'opnfv-vping-1' with IP 192.168.130.30... + 2016-01-06 16:06:39,351 - vPing- INFO - Instance 'opnfv-vping-1' is ACTIVE. + 2016-01-06 16:06:39,650 - vPing- INFO - Creating instance 'opnfv-vping-2' with IP 192.168.130.40... + 2016-01-06 16:06:53,330 - vPing- INFO - Instance 'opnfv-vping-2' is ACTIVE. + 2016-01-06 16:06:53,330 - vPing- INFO - Waiting for ping... + 2016-01-06 16:06:58,669 - vPing- INFO - vPing detected! + 2016-01-06 16:06:58,669 - vPing- INFO - vPing duration:'34.2' + 2016-01-06 16:06:58,670 - vPing- INFO - Cleaning up... + 2016-01-06 16:07:12,661 - vPing- INFO - Deleting network 'vping-net'... + 2016-01-06 16:07:14,748 - vPing- INFO - vPing OK + +A json file is produced and pushed into the test result database. + + +Tempest +------- + +The Tempest results are displayed in the console:: + + FUNCTEST.info: Running Tempest tests... + 2016-01-06 16:07:32,271 - run_tempest - INFO - Creating tenant and user for Tempest suite + 2016-01-06 16:07:38,864 - run_tempest - INFO - Starting Tempest test suite: '--tests-file /home/opnfv/repos/functest/testcases/VIM/OpenStack/CI/custom_tests/test_list.txt'. + + {23} tempest.api.compute.flavors.test_flavors.FlavorsV2TestJSON.test_get_flavor [0.131741s] ... ok + {13} tempest.api.compute.images.test_list_images.ListImagesTestJSON.test_get_image [0.367465s] ... ok + {23} tempest.api.compute.flavors.test_flavors.FlavorsV2TestJSON.test_list_flavors [0.089323s] ... ok + {13} tempest.api.compute.images.test_list_images.ListImagesTestJSON.test_list_images [0.245090s] ... ok + {13} tempest.api.compute.images.test_list_images.ListImagesTestJSON.test_list_images_with_detail [0.434553s] ... ok + {7} setUpClass (tempest.api.identity.admin.v3.test_services.ServicesTestJSON) [0.000000s] ... FAILED + {5} setUpClass (tempest.api.identity.admin.v3.test_groups.GroupsV3TestJSON) [0.000000s] ... FAILED + {4} setUpClass (tempest.api.network.test_floating_ips.FloatingIPTestJSON) [0.000000s] ... FAILED + {10} setUpClass (tempest.api.identity.admin.v3.test_policies.PoliciesTestJSON) [0.000000s] ... FAILED + {3} tempest.api.compute.servers.test_servers.ServersTestJSON.test_create_server_with_admin_password [3.107954s] ... ok + {9} tempest.api.compute.security_groups.test_security_groups.SecurityGroupsTestJSON.test_security_groups_create_list_delete [2.933169s] ... ok + ....... + {1} tempest.api.network.test_networks.BulkNetworkOpsIpV6TestJSON.test_bulk_create_delete_network [1.002445s] ... ok + {1} tempest.api.network.test_networks.BulkNetworkOpsIpV6TestJSON.test_bulk_create_delete_port [1.553398s] ... ok + {1} tempest.api.network.test_networks.BulkNetworkOpsIpV6TestJSON.test_bulk_create_delete_subnet [3.082247s] ... ok + {3} tempest.scenario.test_network_basic_ops.TestNetworkBasicOps.test_network_basic_ops [48.295630s] ... ok + {6} tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_rebuild_server [78.782038s] ... ok + {6} tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_resize_server_confirm [15.597440s] ... ok + {6} tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_resize_server_revert [19.248253s] ... ok + {6} tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_stop_start_server [7.078850s] ... ok + {6} tempest.api.compute.volumes.test_attach_volume.AttachVolumeTestJSON.test_attach_detach_volume [40.311720s] ... ok + {6} tempest.api.volume.test_volumes_actions.VolumesV1ActionsTest.test_attach_detach_volume_to_instance [1.159194s] ... ok + ....... + ====== + Totals + ====== + Ran: 199 tests in 241.0000 sec. + - Passed: 182 + - Skipped: 3 + - Expected Fail: 0 + - Unexpected Success: 0 + - Failed: 14 + Sum of execute time for each test: 481.0934 sec. + + +Rally +----- + TODO + +Controllers +=========== + +odl +--- + +The results of ODL tests can be seen in the console:: + + ============================================================================== + Basic + ============================================================================== + Basic.010 Restconf OK :: Test suite to verify Restconf is OK + ============================================================================== + Get Controller Modules :: Get the controller modules via Restconf | PASS | + ------------------------------------------------------------------------------ + Basic.010 Restconf OK :: Test suite to verify Restconf is OK | PASS | + 1 critical test, 1 passed, 0 failed + 1 test total, 1 passed, 0 failed + ============================================================================== + Basic | PASS | + 1 critical test, 1 passed, 0 failed + 1 test total, 1 passed, 0 failed + ============================================================================== + Output: /home/jenkins-ci/workspace/functest-opnfv-jump-2/output.xml + Log: /home/jenkins-ci/workspace/functest-opnfv-jump-2/log.html + Report: /home/jenkins-ci/workspace/functest-opnfv-jump-2/report.html + + .............................................................................. + + Neutron.Delete Networks :: Checking Network deleted in OpenStack a... | FAIL | + 2 critical tests, 1 passed, 1 failed + 2 tests total, 1 passed, 1 failed + ============================================================================== + Neutron :: Test suite for Neutron Plugin | FAIL | + 18 critical tests, 15 passed, 3 failed + 18 tests total, 15 passed, 3 failed + ============================================================================== + Output: /home/jenkins-ci/workspace/functest-opnfv-jump-2/output.xml + Log: /home/jenkins-ci/workspace/functest-opnfv-jump-2/log.html + Report: /home/jenkins-ci/workspace/functest-opnfv-jump-2/report.html + +3 result files are generated: + * output.xml + * log.html + * report.html + + ODL result page + +.. figure:: ./images/functestODL.png + :width: 170mm + :align: center + :alt: ODL suite result page + + +Known issues +------------ + +Tests are expected to fail now: + * Check port deleted in OpenDaylight + * Check subnet deleted in OpenDaylight + * Check Network deleted in OpenDaylight + +These failures to delete objects in OpenDaylight (when removed via OpenStack Neutron) are due to the following bug: https://bugs.opendaylight.org/show_bug.cgi?id=3052. + +onos +---- + +TODO + +opencontrail +------------ + +TODO + + +Feature +======= + +vIMS +---- + +The results in the console are very verbose:: + + FUNCTEST.info: Running vIMS test... + 2016-01-07 12:30:24,107 - vIMS - INFO - Prepare OpenStack plateform (create tenant and user) + 2016-01-07 12:30:24,484 - vIMS - INFO - Update OpenStack creds informations + 2016-01-07 12:30:24,484 - vIMS - INFO - Upload some OS images if it doesn't exist + 2016-01-07 12:30:24,917 - vIMS - INFO - centos_7 image doesn't exist on glance repository. + Try downloading this image and upload on glance ! + 2016-01-07 12:31:01,268 - vIMS - INFO - ubuntu_14.04 image doesn't exist on glance repository. + Try downloading this image and upload on glance ! + 2016-01-07 12:31:28,670 - vIMS - INFO - Update security group quota for this tenant + 2016-01-07 12:31:28,903 - vIMS - INFO - Update cinder quota for this tenant + 2016-01-07 12:31:29,355 - vIMS - INFO - Collect flavor id for cloudify manager server + 2016-01-07 12:31:30,453 - vIMS - INFO - Prepare virtualenv for cloudify-cli + 2016-01-07 12:31:30,453 - vIMS - DEBUG - Executing command : chmod +x /home/opnfv/repos/functest/testcases/vIMS/CI/create_venv.sh + 2016-01-07 12:31:30,460 - vIMS - DEBUG - Executing command : /home/opnfv/repos/functest/testcases/vIMS/CI/create_venv.sh /home/opnfv/functest/data/vIMS/ + 2016-01-07 12:31:30,469 - vIMS - INFO - Downloading the cloudify manager server blueprint + 2016-01-07 12:31:46,028 - vIMS - INFO - Cloudify deployment Start Time:'2016-01-07 12:31:46' + 2016-01-07 12:31:46,029 - vIMS - INFO - Writing the inputs file + 2016-01-07 12:31:46,032 - vIMS - INFO - Launching the cloudify-manager deployment + ......................................... + 2016-01-07 12:36:51 LOG <manager> [rabbitmq_3c04e.create] INFO: preparing fabric environment... + 2016-01-07 12:36:51 LOG <manager> [rabbitmq_3c04e.create] INFO: environment prepared successfully + ......................................... + 2016-01-07 12:42:51,982 - vIMS - INFO - Cloudify-manager server is UP ! + 2016-01-07 12:42:51,983 - vIMS - INFO - Cloudify deployment duration:'666.0' + 2016-01-07 12:42:51,983 - vIMS - INFO - Collect flavor id for all clearwater vm + 2016-01-07 12:42:53,330 - vIMS - INFO - vIMS VNF deployment Start Time:'2016-01-07 12:42:53' + 2016-01-07 12:42:53,330 - vIMS - INFO - Downloading the openstack-blueprint.yaml blueprint + 2016-01-07 12:43:05,798 - vIMS - INFO - Writing the inputs file + 2016-01-07 12:43:05,801 - vIMS - INFO - Launching the clearwater deployment + 2016-01-07 12:43:05,801 - vIMS - DEBUG - Executing command : /bin/bash -c 'source /home/opnfv/functest/data/vIMS/venv_cloudify/bin/activate; cd /home/opnfv/functest/data/vIMS/opnfv-cloudify-clearwater; cfy blueprints upload -b clearwater -p openstack-blueprint.yaml; cfy deployments create -b clearwater -d clearwater-opnfv --inputs inputs.yaml; cfy executions start -w install -d clearwater-opnfv --timeout 1800; ' + 2016-01-07 13:01:50,577 - vIMS - DEBUG - Validating openstack-blueprint.yaml + Blueprint validated successfully + Uploading blueprint openstack-blueprint.yaml to management server 172.30.10.165 + Uploaded blueprint, blueprint's id is: clearwater + Creating new deployment from blueprint clearwater at management server 172.30.10.165 + Deployment created, deployment's id is: clearwater-opnfv + ......................................... + 2016-01-07 13:01:50,578 - vIMS - INFO - The deployment of clearwater-opnfv is ended + 2016-01-07 13:01:50,578 - vIMS - INFO - vIMS VNF deployment duration:'1137.2' + 2016-01-07 13:04:50,591 - vIMS - DEBUG - Trying to get clearwater nameserver IP ... + 2016-01-07 13:04:55,176 - vIMS - INFO - vIMS functional test Start Time:'2016-01-07 13:04:55' + 2016-01-07 13:14:20,694 - vIMS - INFO - vIMS functional test duration:'565.5' + ......................................... + Basic Call - Rejected by remote endpoint (TCP) - (6505550603, 6505550969) Passed + Basic Call - Rejected by remote endpoint (UDP) - (6505550095, 6505550084) Passed + Basic Call - Messages - Pager model (TCP) - (6505550000, 6505550520) Passed + Basic Call - Messages - Pager model (UDP) - (6505550742, 6505550077) Passed + Basic Call - Pracks (TCP) - (6505550670, 6505550304) Passed + Basic Call - Pracks (UDP) - (6505550990, 6505550391) Passed + Basic Registration (TCP) - (6505550744) Passed + Basic Registration (UDP) - (6505550616) Passed + Multiple Identities (TCP) - (6505550957, 6505550949) Passed + Multiple Identities (UDP) - (6505550771, 6505550675) Passed + ......................................... + 2016-01-07 13:14:20,695 - vIMS - DEBUG - Trying to load test results + 2016-01-07 13:14:20,702 - vIMS - DEBUG - Push result into DB + 2016-01-07 13:14:20,702 - vIMS - DEBUG - Pushing results to DB.... + 2016-01-07 13:14:21,396 - vIMS - DEBUG - <Response [200]> + 2016-01-07 13:14:21,396 - vIMS - INFO - Launching the clearwater-opnfv undeployment + + +========================== +Functest in test Dashboard +========================== + +The OPNFV testing group created a test collection database to collect the test results from CI. +Any lab integrated in CI can push the results to this database. + +The idea is to centralize the resultes and created a dashboard to give a high level overview of the test activities. + +TODO + +========== +References +========== + +.. _`[1]`: Functest configuration guide URL +.. _`[2]`: http://docs.openstack.org/developer/tempest/overview.html +.. _`[3]`: https://rally.readthedocs.org/en/latest/index.html +.. _`[4]`: http://events.linuxfoundation.org/sites/events/files/slides/Functest%20in%20Depth_0.pdf +.. _`[5]`: https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater/blob/master/openstack-blueprint.yaml + + +OPNFV main site: opnfvmain_. + +OPNFV functional test page: opnfvfunctest_. + +IRC support chan: #opnfv-testperf + +.. _opnfvmain: http://www.opnfv.org +.. _opnfvfunctest: https://wiki.opnfv.org/opnfv_functional_testing +.. _`OpenRC`: http://docs.openstack.org/user-guide/common/cli_set_environment_variables_using_openstack_rc.html +.. _`Rally installation procedure`: https://rally.readthedocs.org/en/latest/tutorial/step_0_installation.html +.. _`config_test.py` : https://git.opnfv.org/cgit/functest/tree/testcases/config_functest.py +.. _`config_functest.yaml` : https://git.opnfv.org/cgit/functest/tree/testcases/config_functest.yaml + diff --git a/testcases/Controllers/ODL/CI/custom_tests/neutron/040__delete_ports.txt b/testcases/Controllers/ODL/CI/custom_tests/neutron/040__delete_ports.txt new file mode 100644 index 000000000..02c90c37c --- /dev/null +++ b/testcases/Controllers/ODL/CI/custom_tests/neutron/040__delete_ports.txt @@ -0,0 +1,37 @@ +*** Settings *** +Documentation Checking Port deleted in OpenStack are deleted also in OpenDaylight +Suite Setup Create Session OSSession http://${OPENSTACK}:9696 headers=${X-AUTH} +Suite Teardown Delete All Sessions +Library SSHLibrary +Library Collections +Library OperatingSystem +Library ../../../libraries/RequestsLibrary.py +Library ../../../libraries/Common.py +Variables ../../../variables/Variables.py + +*** Variables *** +${ODLREST} /controller/nb/v2/neutron/ports +${OSREST} /v2.0/ports/${PORTID} +${data} {"port":{"network_id":"${NETID}","admin_state_up": true}} + +*** Test Cases *** +Delete New Port + [Documentation] Delete previously created port in OpenStack + [Tags] Delete port OpenStack Neutron + Log ${data} + ${resp} delete OSSession ${OSREST} + Should be Equal As Strings ${resp.status_code} 204 + Log ${resp.content} + sleep 2 + +Check Port Deleted + [Documentation] Check port deleted in OpenDaylight + [Tags] Check port deleted OpenDaylight + Create Session ODLSession http://${CONTROLLER}:${PORT} headers=${HEADERS} auth=${AUTH} + ${resp} get ODLSession ${ODLREST} + Should be Equal As Strings ${resp.status_code} 200 + ${ODLResult} To Json ${resp.content} + Set Suite Variable ${ODLResult} + Log ${ODLResult} + ${resp} get ODLSession ${ODLREST}/${PORTID} + Should be Equal As Strings ${resp.status_code} 404 diff --git a/testcases/Controllers/ODL/CI/custom_tests/neutron/050__delete_subnets.txt b/testcases/Controllers/ODL/CI/custom_tests/neutron/050__delete_subnets.txt new file mode 100644 index 000000000..4121c98fe --- /dev/null +++ b/testcases/Controllers/ODL/CI/custom_tests/neutron/050__delete_subnets.txt @@ -0,0 +1,37 @@ +*** Settings *** +Documentation Checking Subnets deleted in OpenStack are deleted also in OpenDaylight +Suite Setup Create Session OSSession http://${OPENSTACK}:9696 headers=${X-AUTH} +Suite Teardown Delete All Sessions +Library SSHLibrary +Library Collections +Library OperatingSystem +Library ../../../libraries/RequestsLibrary.py +Library ../../../libraries/Common.py +Variables ../../../variables/Variables.py + +*** Variables *** +${ODLREST} /controller/nb/v2/neutron/subnets +${OSREST} /v2.0/subnets/${SUBNETID} +${data} {"subnet":{"network_id":"${NETID}","ip_version":4,"cidr":"172.16.64.0/24","allocation_pools":[{"start":"172.16.64.20","end":"172.16.64.120"}]}} + +*** Test Cases *** +Delete New subnet + [Documentation] Delete previously created subnet in OpenStack + [Tags] Delete Subnet OpenStack Neutron + Log ${data} + ${resp} delete OSSession ${OSREST} + Should be Equal As Strings ${resp.status_code} 204 + Log ${resp.content} + sleep 2 + +Check New subnet deleted + [Documentation] Check subnet deleted in OpenDaylight + [Tags] Check subnet deleted OpenDaylight + Create Session ODLSession http://${CONTROLLER}:${PORT} headers=${HEADERS} auth=${AUTH} + ${resp} get ODLSession ${ODLREST} + Should be Equal As Strings ${resp.status_code} 200 + ${ODLResult} To Json ${resp.content} + Set Suite Variable ${ODLResult} + Log ${ODLResult} + ${resp} get ODLSession ${ODLREST}/${SUBNETID} + Should be Equal As Strings ${resp.status_code} 404 diff --git a/testcases/Controllers/ODL/CI/custom_tests/neutron/060__delete_networks.txt b/testcases/Controllers/ODL/CI/custom_tests/neutron/060__delete_networks.txt new file mode 100644 index 000000000..fc823fa4b --- /dev/null +++ b/testcases/Controllers/ODL/CI/custom_tests/neutron/060__delete_networks.txt @@ -0,0 +1,37 @@ +*** Settings *** +Documentation Checking Network deleted in OpenStack are deleted also in OpenDaylight +Suite Setup Create Session OSSession http://${OPENSTACK}:9696 headers=${X-AUTH} +Suite Teardown Delete All Sessions +Library SSHLibrary +Library Collections +Library OperatingSystem +Library ../../../libraries/RequestsLibrary.py +Library ../../../libraries/Common.py +Variables ../../../variables/Variables.py + +*** Variables *** +${ODLREST} /controller/nb/v2/neutron/networks +${OSREST} /v2.0/networks/${NETID} +${postNet} {"network":{"name":"odl_network","admin_state_up":true}} + +*** Test Cases *** +Delete Network + [Documentation] Delete network in OpenStack + [Tags] Delete Network OpenStack Neutron + Log ${postNet} + ${resp} delete OSSession ${OSREST} + Should be Equal As Strings ${resp.status_code} 204 + Log ${resp.content} + sleep 2 + +Check Network deleted + [Documentation] Check Network deleted in OpenDaylight + [Tags] Check Network OpenDaylight + Create Session ODLSession http://${CONTROLLER}:${PORT} headers=${HEADERS} auth=${AUTH} + ${resp} get ODLSession ${ODLREST} + Should be Equal As Strings ${resp.status_code} 200 + ${ODLResult} To Json ${resp.content} + Set Suite Variable ${ODLResult} + Log ${ODLResult} + ${resp} get ODLSession ${ODLREST}/${NetID} + Should be Equal As Strings ${resp.status_code} 404 diff --git a/testcases/Controllers/ODL/CI/requirements.pip b/testcases/Controllers/ODL/CI/requirements.pip deleted file mode 100644 index 43845e251..000000000 --- a/testcases/Controllers/ODL/CI/requirements.pip +++ /dev/null @@ -1,4 +0,0 @@ -requests -robotframework -robotframework-requests -robotframework-sshlibrary diff --git a/testcases/Controllers/ODL/CI/start_tests.sh b/testcases/Controllers/ODL/CI/start_tests.sh index 367a075f7..5e87726b8 100644..100755 --- a/testcases/Controllers/ODL/CI/start_tests.sh +++ b/testcases/Controllers/ODL/CI/start_tests.sh @@ -1,9 +1,11 @@ #!/bin/bash -# Script requires that test environment is created already # it includes python2.7 virtual env with robot packages and git -# use create_env.sh script for creating python virtualenv BASEDIR=`dirname $0` +RESULTS_DIR='/home/opnfv/functest/results/odl/' +REPO_DIR='/home/opnfv/repos/odl_integration' +#TODO: read this form config_functest.yaml + # Colors green='\033[0;32m' light_green='\033[1;32m' @@ -17,11 +19,11 @@ usage: where: -h show this help text - var one of the following: OSTACK_IP, ODL_PORT, USR_NAME, USR_PASSWORD + var one of the following: ODL_IP, ODL_PORT, USR_NAME, PASS, NEUTRON_IP value new value for var example: - OSTACK_IP=oscontro1 ODL_PORT=8080 bash $(basename "$0")" + ODL_IP=oscontro1 ODL_PORT=8080 bash $(basename "$0")" while getopts ':h' option; do case "$option" in @@ -38,36 +40,30 @@ done echo -e "${green}Current environment parameters for ODL suite.${nc}" # Following vars might be also specified as CLI params set -x -OSTACK_IP=${OSTACK_IP:-'oscontrol'} +ODL_IP=${ODL_IP:-'192.168.1.5'} ODL_PORT=${ODL_PORT:-8081} -USR_NAME=${USR_NAME:-'admin'} -USR_PASSWORD=${USR_PASSWORD:-'octopus'} +USR_NAME=${USR_NAME:-'neutron'} +PASS=${PASS:-'octopus'} +NEUTRON_IP=${NEUTRON_IP:-192.168.0.68} set +x -echo -e "${green}Cloning ODL integration git repo.${nc}" -if [ -d integration ]; then - cd integration - git checkout -- . - git pull - cd - -else - git clone https://github.com/opendaylight/integration.git -fi # Change openstack password for admin tenant in neutron suite -sed -i "s/\"password\": \"admin\"/\"password\": \"${USR_PASSWORD}\"/" integration/test/csit/suites/openstack/neutron/__init__.robot +sed -i "s/\"password\": \".*\"/\"password\": \"${PASS}\"/" ${REPO_DIR}/test/csit/suites/openstack/neutron/__init__.robot + +# Add Start Suite and Teardown Suite +sed -i "/^Documentation.*/a Suite Teardown Stop Suite" ${REPO_DIR}/test/csit/suites/openstack/neutron/__init__.robot +sed -i "/^Documentation.*/a Suite Setup Start Suite" ${REPO_DIR}/test/csit/suites/openstack/neutron/__init__.robot + -if source $BASEDIR/venv/bin/activate; then - echo -e "${green}Python virtualenv activated.${nc}" -else - echo -e "${red}ERROR${nc}" - exit 1 -fi +# add custom tests to suite, if there are more custom tests needed this will be reworked +echo -e "${green}Copy custom tests to suite.${nc}" +cp -vf ${BASEDIR}/custom_tests/neutron/* ${REPO_DIR}/test/csit/suites/openstack/neutron/ # List of tests are specified in test_list.txt # those are relative paths to test directories from integartion suite echo -e "${green}Executing chosen tests.${nc}" -test_num=1 +test_num=0 while read line do # skip comments @@ -75,16 +71,19 @@ do # skip empty lines [[ -z "${line}" ]] && continue - echo -e "${light_green}Starting test: $line ${nc}" - pybot -v OPENSTACK:${OSTACK_IP} -v PORT:${ODL_PORT} -v CONTROLLER:${OSTACK_IP} $line - mkdir -p $BASEDIR/logs/${test_num} - mv log.html $BASEDIR/logs/${test_num}/ - mv report.html $BASEDIR/logs/${test_num}/ - mv output.xml $BASEDIR/logs/${test_num}/ ((test_num++)) -done < test_list.txt + echo -e "${light_green}Starting test: $line ${nc}" + pybot -v OPENSTACK:${NEUTRON_IP} -v PORT:${ODL_PORT} -v CONTROLLER:${ODL_IP} ${REPO_DIR}/$line + mkdir -p $RESULTS_DIR/logs/${test_num} + mv log.html $RESULTS_DIR/logs/${test_num}/ + mv report.html $RESULTS_DIR/logs/${test_num}/ + mv output.xml $RESULTS_DIR/logs/${test_num}/ +done < ${BASEDIR}/test_list.txt -echo -e "${green}Deactivate venv.${nc}" -deactivate +# create final report which includes all partial test reports +for i in $(seq $test_num); do + rebot_params="$rebot_params $RESULTS_DIR/logs/$i/output.xml" +done -# Now we can copy output.xml, log.html and report.xml files generated by robot. +echo -e "${green}Final report is located:${nc}" +rebot $rebot_params diff --git a/testcases/Controllers/ODL/CI/test_list.txt b/testcases/Controllers/ODL/CI/test_list.txt index e5e52129b..ad791e553 100644 --- a/testcases/Controllers/ODL/CI/test_list.txt +++ b/testcases/Controllers/ODL/CI/test_list.txt @@ -1,5 +1,5 @@ # List of tests` which will be executed by script start_test.sh # You can specify path to specific robot test file or directory (in that case all tests from directory will be executed) -integration/test/csit/suites/integration/basic/ -integration/test/csit/suites/openstack/neutron/ +test/csit/suites/integration/basic/ +test/csit/suites/openstack/neutron/ diff --git a/testcases/Controllers/ONOS/Teston/CI/Readme.txt b/testcases/Controllers/ONOS/Teston/CI/Readme.txt new file mode 100644 index 000000000..7393f59a1 --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/Readme.txt @@ -0,0 +1,5 @@ +1.This is a basic test run about onos,we will make them better and better +2.This test include two suites: +(1)Test northbound(network/subnet/ports create/update/delete) +(2)Ovsdb test,default configuration,openflow connection,vm go onlines. +3.Later we will make a framework to do this test
\ No newline at end of file diff --git a/testcases/Controllers/ONOS/Teston/CI/__init__.py b/testcases/Controllers/ONOS/Teston/CI/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/__init__.py diff --git a/testcases/Controllers/ONOS/Teston/CI/adapters/__init__.py b/testcases/Controllers/ONOS/Teston/CI/adapters/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/adapters/__init__.py diff --git a/testcases/Controllers/ONOS/Teston/CI/adapters/client.py b/testcases/Controllers/ONOS/Teston/CI/adapters/client.py new file mode 100644 index 000000000..535b71f85 --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/adapters/client.py @@ -0,0 +1,76 @@ +""" +Description: + This file is used to run testcase + lanqinglong@huawei.com +""" +from environment import environment +import os +import time +import pexpect +import re +import requests +import json + +class client( environment ): + + def __init__( self ): + environment.__init__( self ) + self.loginfo = environment() + self.testcase = '' + + def RunScript( self, handle, testname, timeout=300 ): + """ + Run ONOS Test Script + Parameters: + testname: ONOS Testcase Name + masterusername: The server username of running ONOS + masterpassword: The server password of running ONOS + """ + self.testcase = testname + self.ChangeTestCasePara( testname, self.masterusername, self.masterpassword ) + runhandle = handle + runtest = self.home + "/OnosSystemTest/TestON/bin/cli.py run " + testname + runhandle.sendline(runtest) + circletime = 0 + lastshowscreeninfo = '' + while True: + Result = runhandle.expect(["PEXPECT]#", pexpect.EOF, pexpect.TIMEOUT]) + curshowscreeninfo = runhandle.before + if (len(lastshowscreeninfo) != len(curshowscreeninfo)): + self.loginfo.log(str(curshowscreeninfo)[len(lastshowscreeninfo)::]) + lastshowscreeninfo = curshowscreeninfo + if Result == 0: + print "Done!" + return + time.sleep(1) + circletime += 1 + if circletime > timeout: + break + self.loginfo.log( "Timeout when running the test, please check!" ) + + def onosstart( self ): + #This is the compass run machine user&pass,you need to modify + + print "Test Begin....." + self.OnosConnectionSet() + masterhandle = self.SSHlogin(self.localhost, self.masterusername, + self.masterpassword) + self.OnosEnvSetup( masterhandle ) + return masterhandle + + def onosclean( self, handle ): + self.SSHRelease( handle ) + self.loginfo.log('Release onos handle Successful') + + def push_results_to_db( self, payload, pushornot = 1): + if pushornot != 1: + return 1 + url = self.Result_DB + "/results" + params = {"project_name": "functest", "case_name": "ONOS-" + self.testcase, + "pod_name": 'huawei-build-2', "details": payload} + headers = {'Content-Type': 'application/json'} + try: + r = requests.post(url, data=json.dumps(params), headers=headers) + self.loginfo.log(r) + except: + self.loginfo.log('Error pushing results into Database') diff --git a/testcases/Controllers/ONOS/Teston/CI/adapters/connection.py b/testcases/Controllers/ONOS/Teston/CI/adapters/connection.py new file mode 100644 index 000000000..c0eb464af --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/adapters/connection.py @@ -0,0 +1,190 @@ +""" +Description: + This file is used to make connections + Include ssh & exchange public-key to each other so that + it can run without password + + lanqinglong@huawei.com +""" +import os +import time +import pexpect +import re +import sys +from foundation import foundation + +class connection( foundation ): + + def __init__( self ): + foundation.__init__( self ) + self.loginfo = foundation() + + def AddKnownHost( self, handle, ipaddr, username, password ): + """ + Add an user to known host,so that onos can login in with onos $ipaddr. + parameters: + ipaddr: ip address + username: login user name + password: login password + """ + print( "Now Adding an user to known hosts " + ipaddr ) + login = handle + login.sendline( "ssh -l %s -p 8101 %s"%( username, ipaddr ) ) + index = 0 + while index != 2: + index = login.expect( ['assword:', 'yes/no', pexpect.EOF, \ + pexpect.TIMEOUT] ) + if index == 0: + login.sendline( password ) + login.sendline( "logout" ) + index = login.expect( ["closed", pexpect.EOF] ) + if index == 0: + self.loginfo.log( "Add SSH Known Host Success!" ) + break + else: + self.loginfo.log( "Add SSH Known Host Failed! Please Check!" ) + break + login.prompt( ) + + if index == 1: + login.sendline('yes') + + def GetEnvValue( self, handle, envname): + """ + os.getenv only returns current user value + GetEnvValue returns a environment value of + current handle + eg: GetEnvValue(handle,'HOME') + """ + envhandle = handle + envhandle.sendline( 'echo $' + envname ) + envhandle.prompt( ) + reg = envname + '\r\n(.*)\r' + envaluereg = re.compile( reg ) + envalue = envaluereg.search( envhandle.before ) + if envalue: + return envalue.groups()[0] + else: + return None + + def Gensshkey( self, handle ): + """ + Generate ssh keys, used for some server have no sshkey. + """ + print "Now Generating SSH keys..." + #Here file name may be id_rsa or id_ecdsa or others + #So here will have a judgement + keysub = handle + filepath = self.GetEnvValue( keysub, 'HOME' ) + '/.ssh' + filelist = os.listdir( filepath ) + for item in filelist: + if 'id' in item: + self.loginfo.log("SSH keys are exsit in ssh directory.") + return True + keysub.sendline("ssh-keygen -t rsa") + Result = 0 + while Result != 2: + Result = keysub.expect( ["Overwrite", "Enter", pexpect.EOF, \ + 'PEXPECT]#', pexpect.TIMEOUT]) + if Result == 0: + keysub.sendline("y") + if Result == 1 or Result == 2: + keysub.sendline("\n") + if Result == 3: + self.loginfo.log( "Generate SSH key success." ) + keysub.prompt() + break + if Result == 4: + self.loginfo.log("Generate SSH key failed.") + keysub.prompt() + break + + def GetRootAuth( self, password ): + """ + Get root user + parameters: + password: root login password + """ + print( "Now changing to user root" ) + login = pexpect.spawn( "su - root" ) + index = 0 + while index != 2: + index = login.expect( ['assword:', "failure", \ + pexpect.EOF, pexpect.TIMEOUT] ) + if index == 0: + login.sendline( password ) + if index == 1: + self.loginfo.log("Change user to root failed.") + + login.interact() + + def ReleaseRootAuth( self ): + """ + Exit root user. + """ + print( "Now Release user root" ) + login = pexpect.spawn( "exit" ) + index = login.expect( ['logout', \ + pexpect.EOF, pexpect.TIMEOUT] ) + if index == 0: + self.loginfo.log("Release root user success.") + if index == 1: + self.loginfo.log("Release root user failed.") + + login.interact() + + def AddEnvIntoBashrc( self, envalue ): + """ + Add Env var into /etc/profile. + parameters: + envalue: environment value to add + """ + print "Now Adding bash environment" + fileopen = open( "/etc/profile", 'r' ) + findContext = 1 + while findContext: + findContext = fileopen.readline( ) + result = findContext.find( envalue ) + if result != -1: + break + fileopen.close + if result == -1: + envAdd = open( "/etc/profile", 'a+' ) + envAdd.writelines( "\n" + envalue ) + envAdd.close( ) + self.loginfo.log( "Add env to bashrc success!" ) + + def OnosRootPathChange( self, onospath ): + """ + Change ONOS root path in file:bash_profile + onospath: path of onos root + """ + print "Now Changing ONOS Root Path" + filepath = onospath + 'onos/tools/dev/bash_profile' + line = open(filepath, 'r').readlines() + lenall = len(line) - 1 + for i in range(lenall): + if "export ONOS_ROOT" in line[i]: + line[i] = 'export ONOS_ROOT=' + onospath + 'onos\n' + NewFile = open(filepath, 'w') + NewFile.writelines(line) + NewFile.close + print "Done!" + + def OnosConnectionSet (self): + """ + Intergrate for ONOS connection setup + """ + if self.masterusername == 'root': + filepath = '/root/' + else : + filepath = '/home/' + self.masterusername + '/' + filepath = os.path.join( filepath, "onos/tools/dev/bash_profile" ) + self.AddEnvIntoBashrc("source " + filepath + "\n") + self.AddEnvIntoBashrc("export OCT=" + self.OCT) + self.AddEnvIntoBashrc("export OC1=" + self.OC1) + self.AddEnvIntoBashrc("export OC2=" + self.OC2) + self.AddEnvIntoBashrc("export OC3=" + self.OC3) + self.AddEnvIntoBashrc("export OCN=" + self.OCN) + self.AddEnvIntoBashrc("export OCN2=" + self.OCN2) + self.AddEnvIntoBashrc("export localhost=" + self.localhost) diff --git a/testcases/Controllers/ONOS/Teston/CI/adapters/environment.py b/testcases/Controllers/ONOS/Teston/CI/adapters/environment.py new file mode 100644 index 000000000..f0bafd760 --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/adapters/environment.py @@ -0,0 +1,268 @@ +""" +Description: + This file is used to setup the running environment + Include Download code,setup environment variable + Set onos running config + Set user name/password + Onos-push-keys and so on + lanqinglong@huawei.com +""" + +import os +import time +import pexpect +import re +import sys +import pxssh +from connection import connection + +class environment( connection ): + + def __init__( self ): + connection.__init__( self ) + self.loginfo = connection( ) + self.masterhandle = '' + self.home = '' + + def DownLoadCode( self, handle, codeurl ): + """ + Download Code use 'git clone' + parameters: + handle: current working handle + codeurl: clone code url + """ + print "Now loading test codes! Please wait in patient..." + originalfolder = sys.path[0] + print originalfolder + gitclone = handle + gitclone.sendline( "git clone " + codeurl ) + index = 0 + increment = 0 + while index != 1 or index != 4: + index = gitclone.expect ( ['already exists', 'esolving deltas: 100%', \ + 'eceiving objects', 'Already up-to-date', \ + 'npacking objects: 100%', pexpect.EOF] ) + + filefolder = self.home + '/' + codeurl.split('/')[-1].split('.')[0] + if index == 0 : + os.chdir( filefolder ) + os.system( 'git pull' ) + os.chdir( originalfolder ) + self.loginfo.log( 'Download code success!' ) + break + elif index == 1 or index == 4: + self.loginfo.log( 'Download code success!' ) + gitclone.sendline( "mkdir onos" ) + gitclone.prompt( ) + gitclone.sendline( "cp -rf " + filefolder+ "/tools onos/" ) + gitclone.prompt( ) + break + elif index == 2 : + os.write(1, gitclone.before) + sys.stdout.flush() + else : + self.loginfo.log( 'Download code failed!' ) + self.loginfo.log( 'Information before' + gitclone.before ) + break + gitclone.prompt( ) + + def InstallDefaultSoftware( self, handle ): + """ + Install default software + parameters: + handle(input): current working handle + """ + print "Now Cleaning test environment" + handle.sendline("sudo apt-get install -y mininet") + handle.prompt( ) + handle.sendline("sudo pip install configobj") + handle.prompt( ) + handle.sendline("sudo apt-get install -y sshpass") + handle.prompt( ) + handle.sendline("OnosSystemTest/TestON/bin/cleanup.sh") + handle.prompt( ) + time.sleep(5) + self.loginfo.log( 'Clean environment success!' ) + + def OnosPushKeys(self, handle, cmd, password): + """ + Using onos-push-keys to make ssh device without password + parameters: + handle(input): working handle + cmd(input): onos-push-keys xxx(xxx is device) + password(input): login in password + """ + print "Now Pushing Onos Keys:"+cmd + Pushkeys = handle + Pushkeys.sendline( cmd ) + Result = 0 + while Result != 2: + Result = Pushkeys.expect( ["(yes/no)", "assword:", "PEXPECT]#", \ + pexpect.EOF, pexpect.TIMEOUT]) + if ( Result == 0 ): + Pushkeys.sendline( "yes" ) + if ( Result == 1 ): + Pushkeys.sendline( password ) + if ( Result == 2 ): + self.loginfo.log( "ONOS Push keys Success!" ) + break + if ( Result == 3 ): + self.loginfo.log( "ONOS Push keys Error!" ) + break + time.sleep(2) + Pushkeys.prompt( ) + print "Done!" + + def SetOnosEnvVar( self, handle, masterpass, agentpass): + """ + Setup onos pushkeys to all devices(3+2) + parameters: + handle(input): current working handle + masterpass: scripts running server's password + agentpass: onos cluster&compute node password + """ + print "Now Setting test environment" + for host in self.hosts: + print "try to connect " + str(host) + result = self.CheckSshNoPasswd(host) + if not result: + print "ssh lgin failed,try to copy master publickey to agent " + str(host) + self.CopyPublicKey(host) + self.OnosPushKeys( handle, "onos-push-keys " + self.OCT, masterpass) + self.OnosPushKeys( handle, "onos-push-keys " + self.OC1, agentpass) + self.OnosPushKeys( handle, "onos-push-keys " + self.OC2, agentpass) + self.OnosPushKeys( handle, "onos-push-keys " + self.OC3, agentpass) + self.OnosPushKeys( handle, "onos-push-keys " + self.OCN, agentpass) + self.OnosPushKeys( handle, "onos-push-keys " + self.OCN2, agentpass) + + def CheckSshNoPasswd( self, host): + """ + Check master can connect agent with no password + """ + login = pexpect.spawn( "ssh " + str(host)) + index = 4 + while index == 4: + index = login.expect(['(yes/no)','>|#|\$', \ + pexpect.EOF, pexpect.TIMEOUT] ) + if index == 0: + login.sendline( "yes" ) + index = 4 + if index == 1: + self.loginfo.log("ssh connect to " + str(host) + " success,no need to copy ssh public key" ) + return True + login.interact() + return False + + def ChangeOnosName( self, user, password): + """ + Change onos name in envDefault file + Because some command depend on this + parameters: + user: onos&compute node user + password: onos&compute node password + """ + print "Now Changing ONOS name&password" + filepath = self.home + '/onos/tools/build/envDefaults' + line = open(filepath, 'r').readlines() + lenall = len(line) - 1 + for i in range(lenall): + if "ONOS_USER=" in line[i]: + line[i]=line[i].replace("sdn",user) + if "ONOS_GROUP" in line[i]: + line[i]=line[i].replace("sdn",user) + if "ONOS_PWD" in line[i]: + line[i]=line[i].replace("rocks",password) + NewFile = open(filepath, 'w') + NewFile.writelines(line) + NewFile.close + print "Done!" + + def ChangeTestCasePara(self, testcase, user, password): + """ + When running test script, there's something need \ + to change in every test folder's *.param & *.topo files + user: onos&compute node user + password: onos&compute node password + """ + print "Now Changing " + testcase + " name&password" + if self.masterusername == 'root': + filepath = '/root/' + else : + filepath = '/home/' + self.masterusername + '/' + filepath = filepath +"OnosSystemTest/TestON/tests/" + testcase + "/" + \ + testcase + ".topo" + line = open(filepath,'r').readlines() + lenall = len(line)-1 + for i in range(lenall-2): + if ("localhost" in line[i]) or ("OCT" in line[i]): + line[i+1]=re.sub(">\w+",">"+user,line[i+1]) + line[i+2]=re.sub(">\w+",">"+password,line[i+2]) + if "OC1" in line [i] \ + or "OC2" in line [i] \ + or "OC3" in line [i] \ + or "OCN" in line [i] \ + or "OCN2" in line[i]: + line[i+1]=re.sub(">\w+",">root",line[i+1]) + line[i+2]=re.sub(">\w+",">root",line[i+2]) + NewFile = open(filepath,'w') + NewFile.writelines(line) + NewFile.close + + def SSHlogin ( self, ipaddr, username, password ) : + """ + SSH login provide a connection to destination. + parameters: + ipaddr: ip address + username: login user name + password: login password + return: handle + """ + login = pxssh.pxssh( ) + login.login ( ipaddr, username, password, original_prompt='[$#>]') + #send command ls -l + login.sendline ('ls -l') + #match prompt + login.prompt() + print ("SSH login " + ipaddr + " success!") + return login + + def SSHRelease( self, handle ): + #Release ssh + handle.logout() + + def CopyOnostoTestbin( self ): + sourcefile = self.cipath + '/dependencies/onos' + destifile = self.home + '/onos/tools/test/bin/' + os.system( 'pwd' ) + runcommand = 'cp ' + sourcefile + ' ' + destifile + os.system( runcommand ) + + def CopyPublicKey( self, host ): + output = os.popen( 'cat /root/.ssh/id_rsa.pub' ) + publickey = output.read().strip('\n') + tmphandle = self.SSHlogin( self.installer_master, self.installer_master_username, self.installer_master_password ) + tmphandle.sendline("ssh "+ host + " -T \'echo " + str(publickey) + ">>/root/.ssh/authorized_keys\'" ) + tmphandle.prompt() + self.SSHRelease(tmphandle) + print "Add OCT PublicKey to " + host + " success" + + def OnosEnvSetup( self, handle ): + """ + Onos Environment Setup function + """ + self.Gensshkey( handle ) + self.home = self.GetEnvValue( handle, 'HOME' ) + self.AddKnownHost( handle, self.OC1, "karaf", "karaf" ) + self.AddKnownHost( handle, self.OC2, "karaf", "karaf" ) + self.AddKnownHost( handle, self.OC3, "karaf", "karaf" ) + self.DownLoadCode( handle, 'https://github.com/sunyulin/OnosSystemTest.git' ) + #self.DownLoadCode( handle, 'https://gerrit.onosproject.org/onos' ) + if self.masterusername == 'root': + filepath = '/root/' + else : + filepath = '/home/' + self.masterusername + '/' + self.OnosRootPathChange( filepath ) + self.CopyOnostoTestbin() + self.ChangeOnosName(self.agentusername,self.agentpassword) + self.InstallDefaultSoftware( handle ) + self.SetOnosEnvVar(handle, self.masterpassword,self.agentpassword) diff --git a/testcases/Controllers/ONOS/Teston/CI/adapters/foundation.py b/testcases/Controllers/ONOS/Teston/CI/adapters/foundation.py new file mode 100644 index 000000000..83cbcb242 --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/adapters/foundation.py @@ -0,0 +1,90 @@ +""" +Description: + This file include basis functions + lanqinglong@huawei.com +""" + +import logging +import os +import time +import yaml +import re +import datetime + +class foundation: + + def __init__(self): + + #currentpath = os.getcwd() + REPO_PATH = os.environ['repos_dir']+'/functest/' + currentpath = REPO_PATH + 'testcases/Controllers/ONOS/Teston/CI' + self.cipath = currentpath + self.logdir = os.path.join( currentpath, 'log' ) + self.workhome = currentpath[0:currentpath.rfind('testcases')-1] + self.Result_DB = '' + filename = time.strftime( '%Y-%m-%d-%H-%M-%S' ) + '.log' + self.logfilepath = os.path.join( self.logdir, filename ) + self.starttime = datetime.datetime.now() + + def log (self, loginfo): + """ + Record log in log directory for deploying test environment + parameters: + loginfo(input): record info + """ + logging.basicConfig( level=logging.INFO, + format = '%(asctime)s %(filename)s:%(message)s', + datefmt = '%d %b %Y %H:%M:%S', + filename = self.logfilepath, + filemode = 'w') + filelog = logging.FileHandler( self.logfilepath ) + logging.getLogger( 'Functest' ).addHandler( filelog ) + print loginfo + logging.info(loginfo) + + def getdefaultpara( self ): + """ + Get Default Parameters value + """ + with open(self.workhome + "/testcases/config_functest.yaml") as f: + functest_yaml = yaml.safe_load(f) + f.close() + + self.Result_DB = str(functest_yaml.get("results").get("test_db_url")) + self.masterusername = str(functest_yaml.get("ONOS").get("general").\ + get('onosbench_username')) + self.masterpassword = str(functest_yaml.get("ONOS").get("general").\ + get("onosbench_password")) + self.agentusername = str(functest_yaml.get("ONOS").get("general").\ + get("onoscli_username")) + self.agentpassword = str(functest_yaml.get("ONOS").get("general").\ + get("onoscli_password")) + self.runtimeout = functest_yaml.get("ONOS").get("general").get("runtimeout") + self.OCT = str(functest_yaml.get("ONOS").get("environment").get("OCT")) + self.OC1 = str(functest_yaml.get("ONOS").get("environment").get("OC1")) + self.OC2 = str(functest_yaml.get("ONOS").get("environment").get("OC2")) + self.OC3 = str(functest_yaml.get("ONOS").get("environment").get("OC3")) + self.OCN = str(functest_yaml.get("ONOS").get("environment").get("OCN")) + self.OCN2 = str(functest_yaml.get("ONOS").get("environment").get("OCN2")) + self.installer_master = str(functest_yaml.get("ONOS").get("environment").get("installer_master")) + self.installer_master_username = str(functest_yaml.get("ONOS").get("environment").get("installer_master_username")) + self.installer_master_password = str(functest_yaml.get("ONOS").get("environment").get("installer_master_password")) + self.hosts = [self.OC1, self.OCN, self.OCN2] + self.localhost = self.OCT + + def GetResult( self ): + cmd = "cat " + self.logfilepath + " | grep Fail" + Resultbuffer = os.popen(cmd).read() + duration = datetime.datetime.now() - self.starttime + time.sleep(2) + + if re.search("[1-9]+", Resultbuffer): + self.log("Testcase Fails\n" + Resultbuffer) + Result = "POK" + else: + self.log("Testcases Pass") + Result = "OK" + payload={'timestart': str(self.starttime), + 'duration': str(duration), + 'status': Result} + return payload diff --git a/testcases/Controllers/ONOS/Teston/CI/dependencies/onos b/testcases/Controllers/ONOS/Teston/CI/dependencies/onos new file mode 100644 index 000000000..d4d59e0f7 --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/dependencies/onos @@ -0,0 +1,23 @@ +#!/bin/bash +# ----------------------------------------------------------------------------- +# ONOS remote command-line client. +# ----------------------------------------------------------------------------- + +[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1 +. /root/.bashrc +. $ONOS_ROOT/tools/build/envDefaults +. $ONOS_ROOT/tools/test/bin/find-node.sh + +[ "$1" = "-w" ] && shift && onos-wait-for-start $1 + +[ -n "$1" ] && OCI=$(find_node $1) && shift + +if which client 1>/dev/null 2>&1 && [ -z "$ONOS_USE_SSH" ]; then + # Use Karaf client only if we can and are allowed to + unset KARAF_HOME + client -h $OCI -u karaf "$@" 2>/dev/null +else + # Otherwise use raw ssh; strict checking is off for dev environments only + #ssh -p 8101 -o StrictHostKeyChecking=no $OCI "$@" + sshpass -p karaf ssh -l karaf -p 8101 $OCI "$@" +fi diff --git a/testcases/Controllers/ONOS/Teston/CI/log/gitignore b/testcases/Controllers/ONOS/Teston/CI/log/gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/log/gitignore diff --git a/testcases/Controllers/ONOS/Teston/CI/onosfunctest.py b/testcases/Controllers/ONOS/Teston/CI/onosfunctest.py new file mode 100644 index 000000000..675b3fc68 --- /dev/null +++ b/testcases/Controllers/ONOS/Teston/CI/onosfunctest.py @@ -0,0 +1,24 @@ +""" +Description: This test is to run onos Teston VTN scripts + +List of test cases: +CASE1 - Northbound NBI test network/subnet/ports +CASE2 - Ovsdb test&Default configuration&Vm go online + +lanqinglong@huawei.com +""" +from adapters.client import client + +if __name__=="__main__": + + main = client() + main.getdefaultpara() + + #scripts to run + runhandle = main.onosstart() + main.RunScript(runhandle, "FUNCvirNetNB") +# main.RunScript(runhandle, "FUNCovsdbtest") + main.RunScript(runhandle, "FUNCvirNetNBL3") +# main.RunScript(runhandle, "FUNCovsdbtestL3") + main.onosclean( runhandle ) + main.push_results_to_db(main.GetResult()) diff --git a/testcases/VIM/OpenStack/CI/custom_tests/test_list.txt b/testcases/VIM/OpenStack/CI/custom_tests/test_list.txt new file mode 100644 index 000000000..ca6bf6be2 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/custom_tests/test_list.txt @@ -0,0 +1,227 @@ +# This list contains tempest test cases chosen for Functest deployment. +# It consists of two main parts: +# 1. Set of tempest smoke test cases +# 2. Set of test cases from DefCore list (https://wiki.openstack.org/wiki/Governance/DefCoreCommittee) +# +# Part 1 (smoke) +# +tempest.api.compute.flavors.test_flavors.FlavorsV2TestJSON.test_get_flavor[id-1f12046b-753d-40d2-abb6-d8eb8b30cb2f,smoke] +tempest.api.compute.flavors.test_flavors.FlavorsV2TestJSON.test_list_flavors[id-e36c0eaa-dff5-4082-ad1f-3f9a80aa3f59,smoke] +tempest.api.compute.security_groups.test_security_group_rules.SecurityGroupRulesTestJSON.test_security_group_rules_create[id-850795d7-d4d3-4e55-b527-a774c0123d3a,network,smoke] +tempest.api.compute.security_groups.test_security_group_rules.SecurityGroupRulesTestJSON.test_security_group_rules_list[id-a6154130-5a55-4850-8be4-5e9e796dbf17,network,smoke] +tempest.api.compute.security_groups.test_security_groups.SecurityGroupsTestJSON.test_security_groups_create_list_delete[id-eb2b087d-633d-4d0d-a7bd-9e6ba35b32de,network,smoke] +tempest.api.compute.servers.test_attach_interfaces.AttachInterfacesTestJSON.test_add_remove_fixed_ip[id-c7e0e60b-ee45-43d0-abeb-8596fd42a2f9,network,smoke] +tempest.api.compute.servers.test_create_server.ServersTestJSON.test_list_servers[id-9a438d88-10c6-4bcd-8b5b-5b6e25e1346f,smoke] +tempest.api.compute.servers.test_create_server.ServersTestJSON.test_verify_server_details[id-5de47127-9977-400a-936f-abcfbec1218f,smoke] +tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_list_servers[id-9a438d88-10c6-4bcd-8b5b-5b6e25e1346f,smoke] +tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_verify_server_details[id-5de47127-9977-400a-936f-abcfbec1218f,smoke] +tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_reboot_server_hard[id-2cb1baf6-ac8d-4429-bf0d-ba8a0ba53e32,smoke] +tempest.api.compute.servers.test_server_addresses.ServerAddressesTestJSON.test_list_server_addresses[id-6eb718c0-02d9-4d5e-acd1-4e0c269cef39,network,smoke] +tempest.api.compute.servers.test_server_addresses.ServerAddressesTestJSON.test_list_server_addresses_by_network[id-87bbc374-5538-4f64-b673-2b0e4443cc30,network,smoke] +tempest.api.identity.admin.v2.test_services.ServicesTestJSON.test_list_services[id-34ea6489-012d-4a86-9038-1287cadd5eca,smoke] +tempest.api.identity.admin.v2.test_users.UsersTestJSON.test_create_user[id-2d55a71e-da1d-4b43-9c03-d269fd93d905,smoke] +tempest.api.identity.admin.v3.test_credentials.CredentialsTestJSON.test_credentials_create_get_update_delete[id-7cd59bf9-bda4-4c72-9467-d21cab278355,smoke] +tempest.api.identity.admin.v3.test_domains.DefaultDomainTestJSON.test_default_domain_exists[id-17a5de24-e6a0-4e4a-a9ee-d85b6e5612b5,smoke] +tempest.api.identity.admin.v3.test_domains.DomainsTestJSON.test_create_update_delete_domain[id-f2f5b44a-82e8-4dad-8084-0661ea3b18cf,smoke] +tempest.api.identity.admin.v3.test_endpoints.EndPointsTestJSON.test_update_endpoint[id-37e8f15e-ee7c-4657-a1e7-f6b61e375eff,smoke] +tempest.api.identity.admin.v3.test_groups.GroupsV3TestJSON.test_group_users_add_list_delete[id-1598521a-2f36-4606-8df9-30772bd51339,smoke] +tempest.api.identity.admin.v3.test_policies.PoliciesTestJSON.test_create_update_delete_policy[id-e544703a-2f03-4cf2-9b0f-350782fdb0d3,smoke] +tempest.api.identity.admin.v3.test_regions.RegionsTestJSON.test_create_region_with_specific_id[id-2c12c5b5-efcf-4aa5-90c5-bff1ab0cdbe2,smoke] +tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_role_create_update_get_list[id-18afc6c0-46cf-4911-824e-9989cc056c3a,smoke] +tempest.api.identity.admin.v3.test_services.ServicesTestJSON.test_create_update_get_service[id-5193aad5-bcb7-411d-85b0-b3b61b96ef06,smoke] +tempest.api.identity.admin.v3.test_trusts.TrustsV3TestJSON.test_get_trusts_all[id-4773ebd5-ecbf-4255-b8d8-b63e6f72b65d,smoke] +tempest.api.identity.v2.test_api_discovery.TestApiDiscovery.test_api_media_types[id-007a0be0-78fe-4fdb-bbee-e9216cc17bb2,smoke] +tempest.api.identity.v2.test_api_discovery.TestApiDiscovery.test_api_version_resources[id-ea889a68-a15f-4166-bfb1-c12456eae853,smoke] +tempest.api.identity.v2.test_api_discovery.TestApiDiscovery.test_api_version_statuses[id-77fd6be0-8801-48e6-b9bf-38cdd2f253ec,smoke] +tempest.api.identity.v3.test_api_discovery.TestApiDiscovery.test_api_media_types[id-657c1970-4722-4189-8831-7325f3bc4265,smoke] +tempest.api.identity.v3.test_api_discovery.TestApiDiscovery.test_api_version_resources[id-b9232f5e-d9e5-4d97-b96c-28d3db4de1bd,smoke] +tempest.api.identity.v3.test_api_discovery.TestApiDiscovery.test_api_version_statuses[id-8879a470-abfb-47bb-bb8d-5a7fd279ad1e,smoke] +tempest.api.image.v2.test_images.BasicOperationsImagesTest.test_delete_image[id-f848bb94-1c6e-45a4-8726-39e3a5b23535,smoke] +tempest.api.image.v2.test_images.BasicOperationsImagesTest.test_register_upload_get_image_file[id-139b765e-7f3d-4b3d-8b37-3ca3876ee318,smoke] +tempest.api.image.v2.test_images.BasicOperationsImagesTest.test_update_image[id-f66891a7-a35c-41a8-b590-a065c2a1caa6,smoke] +tempest.api.network.test_extensions.ExtensionsTestJSON.test_list_show_extensions[id-ef28c7e6-e646-4979-9d67-deb207bc5564,smoke] +tempest.api.network.test_floating_ips.FloatingIPTestJSON.test_create_floating_ip_specifying_a_fixed_ip_address[id-36de4bd0-f09c-43e3-a8e1-1decc1ffd3a5,smoke] +tempest.api.network.test_floating_ips.FloatingIPTestJSON.test_create_list_show_update_delete_floating_ip[id-62595970-ab1c-4b7f-8fcc-fddfe55e8718,smoke] +tempest.api.network.test_networks.BulkNetworkOpsIpV6TestJSON.test_bulk_create_delete_network[id-d4f9024d-1e28-4fc1-a6b1-25dbc6fa11e2,smoke] +tempest.api.network.test_networks.BulkNetworkOpsIpV6TestJSON.test_bulk_create_delete_port[id-48037ff2-e889-4c3b-b86a-8e3f34d2d060,smoke] +tempest.api.network.test_networks.BulkNetworkOpsIpV6TestJSON.test_bulk_create_delete_subnet[id-8936533b-c0aa-4f29-8e53-6cc873aec489,smoke] +tempest.api.network.test_networks.BulkNetworkOpsTestJSON.test_bulk_create_delete_network[id-d4f9024d-1e28-4fc1-a6b1-25dbc6fa11e2,smoke] +tempest.api.network.test_networks.BulkNetworkOpsTestJSON.test_bulk_create_delete_port[id-48037ff2-e889-4c3b-b86a-8e3f34d2d060,smoke] +tempest.api.network.test_networks.BulkNetworkOpsTestJSON.test_bulk_create_delete_subnet[id-8936533b-c0aa-4f29-8e53-6cc873aec489,smoke] +tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_create_update_delete_network_subnet[id-0e269138-0da6-4efc-a46d-578161e7b221,smoke] +tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_external_network_visibility[id-af774677-42a9-4e4b-bb58-16fe6a5bc1ec,smoke] +tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_list_networks[id-f7ffdeda-e200-4a7a-bcbe-05716e86bf43,smoke] +tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_list_subnets[id-db68ba48-f4ea-49e9-81d1-e367f6d0b20a,smoke] +tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_show_network[id-2bf13842-c93f-4a69-83ed-717d2ec3b44e,smoke] +tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_show_subnet[id-bd635d81-6030-4dd1-b3b9-31ba0cfdf6cc,smoke] +tempest.api.network.test_networks.NetworksIpV6TestJSON.test_create_update_delete_network_subnet[id-0e269138-0da6-4efc-a46d-578161e7b221,smoke] +tempest.api.network.test_networks.NetworksIpV6TestJSON.test_external_network_visibility[id-af774677-42a9-4e4b-bb58-16fe6a5bc1ec,smoke] +tempest.api.network.test_networks.NetworksIpV6TestJSON.test_list_networks[id-f7ffdeda-e200-4a7a-bcbe-05716e86bf43,smoke] +tempest.api.network.test_networks.NetworksIpV6TestJSON.test_list_subnets[id-db68ba48-f4ea-49e9-81d1-e367f6d0b20a,smoke] +tempest.api.network.test_networks.NetworksIpV6TestJSON.test_show_network[id-2bf13842-c93f-4a69-83ed-717d2ec3b44e,smoke] +tempest.api.network.test_networks.NetworksIpV6TestJSON.test_show_subnet[id-bd635d81-6030-4dd1-b3b9-31ba0cfdf6cc,smoke] +tempest.api.network.test_networks.NetworksTestJSON.test_create_update_delete_network_subnet[id-0e269138-0da6-4efc-a46d-578161e7b221,smoke] +tempest.api.network.test_networks.NetworksTestJSON.test_external_network_visibility[id-af774677-42a9-4e4b-bb58-16fe6a5bc1ec,smoke] +tempest.api.network.test_networks.NetworksTestJSON.test_list_networks[id-f7ffdeda-e200-4a7a-bcbe-05716e86bf43,smoke] +tempest.api.network.test_networks.NetworksTestJSON.test_list_subnets[id-db68ba48-f4ea-49e9-81d1-e367f6d0b20a,smoke] +tempest.api.network.test_networks.NetworksTestJSON.test_show_network[id-2bf13842-c93f-4a69-83ed-717d2ec3b44e,smoke] +tempest.api.network.test_networks.NetworksTestJSON.test_show_subnet[id-bd635d81-6030-4dd1-b3b9-31ba0cfdf6cc,smoke] +tempest.api.network.test_ports.PortsIpV6TestJSON.test_create_port_in_allowed_allocation_pools[id-0435f278-40ae-48cb-a404-b8a087bc09b1,smoke] +tempest.api.network.test_ports.PortsIpV6TestJSON.test_create_port_with_no_securitygroups[id-4179dcb9-1382-4ced-84fe-1b91c54f5735,smoke] +tempest.api.network.test_ports.PortsIpV6TestJSON.test_create_update_delete_port[id-c72c1c0c-2193-4aca-aaa4-b1442640f51c,smoke] +tempest.api.network.test_ports.PortsIpV6TestJSON.test_list_ports[id-cf95b358-3e92-4a29-a148-52445e1ac50e,smoke] +tempest.api.network.test_ports.PortsIpV6TestJSON.test_show_port[id-c9a685bd-e83f-499c-939f-9f7863ca259f,smoke] +tempest.api.network.test_ports.PortsTestJSON.test_create_port_in_allowed_allocation_pools[id-0435f278-40ae-48cb-a404-b8a087bc09b1,smoke] +tempest.api.network.test_ports.PortsTestJSON.test_create_port_with_no_securitygroups[id-4179dcb9-1382-4ced-84fe-1b91c54f5735,smoke] +tempest.api.network.test_ports.PortsTestJSON.test_create_update_delete_port[id-c72c1c0c-2193-4aca-aaa4-b1442640f51c,smoke] +tempest.api.network.test_ports.PortsTestJSON.test_list_ports[id-cf95b358-3e92-4a29-a148-52445e1ac50e,smoke] +tempest.api.network.test_ports.PortsTestJSON.test_show_port[id-c9a685bd-e83f-499c-939f-9f7863ca259f,smoke] +tempest.api.network.test_routers.RoutersIpV6Test.test_add_multiple_router_interfaces[id-802c73c9-c937-4cef-824b-2191e24a6aab,smoke] +tempest.api.network.test_routers.RoutersIpV6Test.test_add_remove_router_interface_with_port_id[id-2b7d2f37-6748-4d78-92e5-1d590234f0d5,smoke] +tempest.api.network.test_routers.RoutersIpV6Test.test_add_remove_router_interface_with_subnet_id[id-b42e6e39-2e37-49cc-a6f4-8467e940900a,smoke] +tempest.api.network.test_routers.RoutersIpV6Test.test_create_show_list_update_delete_router[id-f64403e2-8483-4b34-8ccd-b09a87bcc68c,smoke] +tempest.api.network.test_routers.RoutersTest.test_add_multiple_router_interfaces[id-802c73c9-c937-4cef-824b-2191e24a6aab,smoke] +tempest.api.network.test_routers.RoutersTest.test_add_remove_router_interface_with_port_id[id-2b7d2f37-6748-4d78-92e5-1d590234f0d5,smoke] +tempest.api.network.test_routers.RoutersTest.test_add_remove_router_interface_with_subnet_id[id-b42e6e39-2e37-49cc-a6f4-8467e940900a,smoke] +tempest.api.network.test_routers.RoutersTest.test_create_show_list_update_delete_router[id-f64403e2-8483-4b34-8ccd-b09a87bcc68c,smoke] +tempest.api.network.test_security_groups.SecGroupIPv6Test.test_create_list_update_show_delete_security_group[id-bfd128e5-3c92-44b6-9d66-7fe29d22c802,smoke] +tempest.api.network.test_security_groups.SecGroupIPv6Test.test_create_show_delete_security_group_rule[id-cfb99e0e-7410-4a3d-8a0c-959a63ee77e9,smoke] +tempest.api.network.test_security_groups.SecGroupIPv6Test.test_list_security_groups[id-e30abd17-fef9-4739-8617-dc26da88e686,smoke] +tempest.api.network.test_security_groups.SecGroupTest.test_create_list_update_show_delete_security_group[id-bfd128e5-3c92-44b6-9d66-7fe29d22c802,smoke] +tempest.api.network.test_security_groups.SecGroupTest.test_create_show_delete_security_group_rule[id-cfb99e0e-7410-4a3d-8a0c-959a63ee77e9,smoke] +tempest.api.network.test_security_groups.SecGroupTest.test_list_security_groups[id-e30abd17-fef9-4739-8617-dc26da88e686,smoke] +tempest.api.orchestration.stacks.test_resource_types.ResourceTypesTest.test_resource_type_list[id-7123d082-3577-4a30-8f00-f805327c4ffd,smoke] +tempest.api.orchestration.stacks.test_resource_types.ResourceTypesTest.test_resource_type_show[id-0e85a483-828b-4a28-a0e3-f0a21809192b,smoke] +tempest.api.orchestration.stacks.test_resource_types.ResourceTypesTest.test_resource_type_template[id-8401821d-65fe-4d43-9fa3-57d5ce3a35c7,smoke] +tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_get_deployment_list[id-1275c835-c967-4a2c-8d5d-ad533447ed91,smoke] +tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_get_deployment_metadata[id-fe7cd9f9-54b1-429c-a3b7-7df8451db913,smoke] +tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_get_software_config[id-136162ed-9445-4b9c-b7fc-306af8b5da99,smoke] +tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_software_deployment_create_validate[id-f29d21f3-ed75-47cf-8cdc-ef1bdeb4c674,smoke] +tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_software_deployment_update_no_metadata_change[id-2ac43ab3-34f2-415d-be2e-eabb4d14ee32,smoke] +tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_software_deployment_update_with_metadata_change[id-92c48944-d79d-4595-a840-8e1a581c1a72,smoke] +tempest.api.orchestration.stacks.test_stacks.StacksTestJSON.test_stack_crud_no_resources[id-10498bd5-a83e-4b62-a817-ce24afe938fe,smoke] +tempest.api.orchestration.stacks.test_stacks.StacksTestJSON.test_stack_list_responds[id-d35d628c-07f6-4674-85a1-74db9919e986,smoke] +tempest.api.telemetry.test_telemetry_notification_api.TelemetryNotificationAPITestJSON.test_check_glance_v1_notifications[id-04b10bfe-a5dc-47af-b22f-0460426bf498,image,smoke] +tempest.api.telemetry.test_telemetry_notification_api.TelemetryNotificationAPITestJSON.test_check_glance_v2_notifications[id-c240457d-d943-439b-8aea-85e26d64fe8e,image,smoke] +tempest.api.volume.test_volumes_actions.VolumesV1ActionsTest.test_attach_detach_volume_to_instance[compute,id-fff42874-7db5-4487-a8e1-ddda5fb5288d,smoke,stress] +tempest.api.volume.test_volumes_actions.VolumesV2ActionsTest.test_attach_detach_volume_to_instance[compute,id-fff42874-7db5-4487-a8e1-ddda5fb5288d,smoke,stress] +tempest.api.volume.test_volumes_get.VolumesV1GetTest.test_volume_create_get_update_delete[id-27fb0e9f-fb64-41dd-8bdb-1ffa762f0d51,smoke] +tempest.api.volume.test_volumes_get.VolumesV1GetTest.test_volume_create_get_update_delete_from_image[id-54a01030-c7fc-447c-86ee-c1182beae638,image,smoke] +tempest.api.volume.test_volumes_get.VolumesV2GetTest.test_volume_create_get_update_delete[id-27fb0e9f-fb64-41dd-8bdb-1ffa762f0d51,smoke] +tempest.api.volume.test_volumes_get.VolumesV2GetTest.test_volume_create_get_update_delete_from_image[id-54a01030-c7fc-447c-86ee-c1182beae638,image,smoke] +tempest.api.volume.test_volumes_list.VolumesV1ListTestJSON.test_volume_list[id-0b6ddd39-b948-471f-8038-4787978747c4,smoke] +tempest.api.volume.test_volumes_list.VolumesV2ListTestJSON.test_volume_list[id-0b6ddd39-b948-471f-8038-4787978747c4,smoke] +tempest.scenario.test_network_basic_ops.TestNetworkBasicOps.test_network_basic_ops[compute,id-f323b3ba-82f8-4db7-8ea6-6a895869ec49,network,smoke] +tempest.scenario.test_server_basic_ops.TestServerBasicOps.test_server_basicops[compute,id-7fff3fb3-91d8-4fd0-bd7d-0204f1f180ba,network,smoke] +tempest.scenario.test_volume_boot_pattern.TestVolumeBootPattern.test_volume_boot_pattern[compute,id-557cd2c2-4eb8-4dce-98be-f86765ff311b,image,smoke,volume] +tempest.scenario.test_volume_boot_pattern.TestVolumeBootPatternV2.test_volume_boot_pattern[compute,id-557cd2c2-4eb8-4dce-98be-f86765ff311b,image,smoke,volume] +# +# Part 2 (DefCore) +# +tempest.api.compute.images.test_images.ImagesTestJSON.test_delete_saving_image[id-aa06b52b-2db5-4807-b218-9441f75d74e3] +tempest.api.compute.images.test_images_oneserver.ImagesOneServerTestJSON.test_create_delete_image[id-3731d080-d4c5-4872-b41a-64d0d0021314] +tempest.api.compute.images.test_images_oneserver.ImagesOneServerTestJSON.test_create_image_specify_multibyte_character_image_name[id-3b7c6fe4-dfe7-477c-9243-b06359db51e6] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_filter_by_changes_since[id-18bac3ae-da27-436c-92a9-b22474d13aab] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_filter_by_name[id-33163b73-79f5-4d07-a7ea-9213bcc468ff] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_filter_by_server_id[id-9f238683-c763-45aa-b848-232ec3ce3105] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_filter_by_server_ref[id-05a377b8-28cf-4734-a1e6-2ab5c38bf606] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_filter_by_status[id-a3f5b513-aeb3-42a9-b18e-f091ef73254d] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_filter_by_type[id-e3356918-4d3e-4756-81d5-abc4524ba29f] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_limit_results[id-3a484ca9-67ba-451e-b494-7fcf28d32d62] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_with_detail_filter_by_changes_since[id-7d439e18-ac2e-4827-b049-7e18004712c4] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_with_detail_filter_by_name[id-644ea267-9bd9-4f3b-af9f-dffa02396a17] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_with_detail_filter_by_server_ref[id-8c78f822-203b-4bf6-8bba-56ebd551cf84] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_with_detail_filter_by_status[id-9b0ea018-6185-4f71-948a-a123a107988e] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_with_detail_filter_by_type[id-888c0cc0-7223-43c5-9db0-b125fd0a393b] +tempest.api.compute.images.test_list_image_filters.ListImageFiltersTestJSON.test_list_images_with_detail_limit_results[id-ba2fa9a9-b672-47cc-b354-3b4c0600e2cb] +tempest.api.compute.images.test_list_images.ListImagesTestJSON.test_get_image[id-490d0898-e12a-463f-aef0-c50156b9f789] +tempest.api.compute.images.test_list_images.ListImagesTestJSON.test_list_images[id-fd51b7f4-d4a3-4331-9885-866658112a6f] +tempest.api.compute.images.test_list_images.ListImagesTestJSON.test_list_images_with_detail[id-9f94cb6b-7f10-48c5-b911-a0b84d7d4cd6] +tempest.api.compute.servers.test_create_server.ServersTestJSON.test_host_name_is_same_as_server_name[id-ac1ad47f-984b-4441-9274-c9079b7a0666] +tempest.api.compute.servers.test_create_server.ServersTestJSON.test_list_servers_with_detail[id-585e934c-448e-43c4-acbf-d06a9b899997] +tempest.api.compute.servers.test_create_server.ServersTestJSON.test_verify_created_server_vcpus[id-cbc0f52f-05aa-492b-bdc1-84b575ca294b] +tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_host_name_is_same_as_server_name[id-ac1ad47f-984b-4441-9274-c9079b7a0666] +tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_list_servers_with_detail[id-585e934c-448e-43c4-acbf-d06a9b899997] +tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_verify_created_server_vcpus[id-cbc0f52f-05aa-492b-bdc1-84b575ca294b] +tempest.api.compute.servers.test_instance_actions.InstanceActionsTestJSON.test_get_instance_action[id-aacc71ca-1d70-4aa5-bbf6-0ff71470e43c] +tempest.api.compute.servers.test_instance_actions.InstanceActionsTestJSON.test_list_instance_actions[id-77ca5cc5-9990-45e0-ab98-1de8fead201a] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_detailed_filter_by_flavor[id-80c574cc-0925-44ba-8602-299028357dd9] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_detailed_filter_by_image[id-b3304c3b-97df-46d2-8cd3-e2b6659724e7] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_detailed_filter_by_server_name[id-f9eb2b70-735f-416c-b260-9914ac6181e4] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_detailed_filter_by_server_status[id-de2612ab-b7dd-4044-b0b1-d2539601911f] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_detailed_limit_results[id-67aec2d0-35fe-4503-9f92-f13272b867ed] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_filter_by_flavor[id-573637f5-7325-47bb-9144-3476d0416908] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_filter_by_image[id-05e8a8e7-9659-459a-989d-92c2f501f4ba] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_filter_by_limit[id-614cdfc1-d557-4bac-915b-3e67b48eee76] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_filter_by_server_name[id-9b067a7b-7fee-4f6a-b29c-be43fe18fc5a] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_filter_by_server_status[id-ca78e20e-fddb-4ce6-b7f7-bcbf8605e66e] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_filtered_by_ip[id-43a1242e-7b31-48d1-88f2-3f72aa9f2077] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_filtered_by_ip_regex[id-a905e287-c35e-42f2-b132-d02b09f3654a] +tempest.api.compute.servers.test_list_server_filters.ListServerFiltersTestJSON.test_list_servers_filtered_by_name_wildcard[id-e9f624ee-92af-4562-8bec-437945a18dcb] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_by_changes_since_future_date[id-74745ad8-b346-45b5-b9b8-509d7447fc1f,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_by_changes_since_invalid_date[id-87d12517-e20a-4c9c-97b6-dd1628d6d6c9,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_by_limits[id-12c80a9f-2dec-480e-882b-98ba15757659] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_by_limits_greater_than_actual_count[id-d47c17fb-eebd-4287-8e95-f20a7e627b18,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_by_limits_pass_negative_value[id-62610dd9-4713-4ee0-8beb-fd2c1aa7f950,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_by_limits_pass_string[id-679bc053-5e70-4514-9800-3dfab1a380a6,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_by_non_existing_flavor[id-5913660b-223b-44d4-a651-a0fbfd44ca75,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_by_non_existing_image[id-ff01387d-c7ad-47b4-ae9e-64fa214638fe,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_by_non_existing_server_name[id-e2c77c4a-000a-4af3-a0bd-629a328bde7c,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_detail_server_is_deleted[id-93055106-2d34-46fe-af68-d9ddbf7ee570,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_status_non_existing[id-fcdf192d-0f74-4d89-911f-1ec002b822c4,negative] +tempest.api.compute.servers.test_list_servers_negative.ListServersNegativeTestJSON.test_list_servers_with_a_deleted_server[id-24a26f1a-1ddc-4eea-b0d7-a90cc874ad8f,negative] +tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_change_server_password[id-6158df09-4b82-4ab3-af6d-29cf36af858d] +tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_get_console_output[id-4b8867e6-fffa-4d54-b1d1-6fdda57be2f3] +tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_lock_unlock_server[id-80a8094c-211e-440a-ab88-9e59d556c7ee] +tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_reboot_server_soft[id-4640e3ef-a5df-482e-95a1-ceeeb0faa84d] +tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_rebuild_server[id-aaa6cdf3-55a7-461a-add9-1c8596b9a07c] +tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_resize_server_confirm[id-1499262a-9328-4eda-9068-db1ac57498d2] +tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_resize_server_revert[id-c03aab19-adb1-44f5-917d-c419577e9e68] +tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_stop_start_server[id-af8eafd4-38a7-4a4b-bdbc-75145a580560] +tempest.api.compute.servers.test_server_metadata.ServerMetadataTestJSON.test_delete_server_metadata_item[id-127642d6-4c7b-4486-b7cd-07265a378658] +tempest.api.compute.servers.test_server_metadata.ServerMetadataTestJSON.test_get_server_metadata_item[id-3043c57d-7e0e-49a6-9a96-ad569c265e6a] +tempest.api.compute.servers.test_server_metadata.ServerMetadataTestJSON.test_list_server_metadata[id-479da087-92b3-4dcf-aeb3-fd293b2d14ce] +tempest.api.compute.servers.test_server_metadata.ServerMetadataTestJSON.test_set_server_metadata[id-211021f6-21de-4657-a68f-908878cfe251] +tempest.api.compute.servers.test_server_metadata.ServerMetadataTestJSON.test_set_server_metadata_item[id-58c02d4f-5c67-40be-8744-d3fa5982eb1c] +tempest.api.compute.servers.test_server_metadata.ServerMetadataTestJSON.test_update_server_metadata[id-344d981e-0c33-4997-8a5d-6c1d803e4134] +tempest.api.compute.servers.test_servers.ServersTestJSON.test_create_server_with_admin_password[id-b92d5ec7-b1dd-44a2-87e4-45e888c46ef0] +tempest.api.compute.servers.test_servers.ServersTestJSON.test_create_specify_keypair[id-f9e15296-d7f9-4e62-b53f-a04e89160833] +tempest.api.compute.servers.test_servers.ServersTestJSON.test_create_with_existing_server_name[id-8fea6be7-065e-47cf-89b8-496e6f96c699] +tempest.api.compute.servers.test_servers.ServersTestJSON.test_update_access_server_address[id-89b90870-bc13-4b73-96af-f9d4f2b70077] +tempest.api.compute.servers.test_servers.ServersTestJSON.test_update_server_name[id-5e6ccff8-349d-4852-a8b3-055df7988dd2] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_create_numeric_server_name[id-fd57f159-68d6-4c2a-902b-03070828a87e,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_create_server_metadata_exceeds_length_limit[id-7fc74810-0bd2-4cd7-8244-4f33a9db865a,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_create_server_name_length_exceeds_256[id-c3e0fb12-07fc-4d76-a22e-37409887afe8,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_create_with_invalid_flavor[id-18f5227f-d155-4429-807c-ccb103887537,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_create_with_invalid_image[id-fcba1052-0a50-4cf3-b1ac-fae241edf02f,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_create_with_invalid_network_uuid[id-4e72dc2d-44c5-4336-9667-f7972e95c402,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_delete_a_server_of_another_tenant[id-5c75009d-3eea-423e-bea3-61b09fd25f9c,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_delete_server_pass_id_exceeding_length_limit[id-f4d7279b-5fd2-4bf2-9ba4-ae35df0d18c5,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_delete_server_pass_negative_id[id-75f79124-277c-45e6-a373-a1d6803f4cc4,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_get_non_existent_server[id-3436b02f-1b1e-4f03-881e-c6a602327439,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_invalid_ip_v6_address[id-5226dd80-1e9c-4d8a-b5f9-b26ca4763fd0,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server[id-d4c023a0-9c55-4747-9dd5-413b820143c7,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_rebuild_non_existent_server[id-d86141a7-906e-4731-b187-d64a2ea61422,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_rebuild_reboot_deleted_server[id-98fa0458-1485-440f-873b-fe7f0d714930,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_resize_server_with_non_existent_flavor[id-ced1a1d7-2ab6-45c9-b90f-b27d87b30efd,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_resize_server_with_null_flavor[id-45436a7d-a388-4a35-a9d8-3adc5d0d940b,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_server_name_blank[id-dbbfd247-c40c-449e-8f6c-d2aa7c7da7cf,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_stop_non_existent_server[id-a31460a9-49e1-42aa-82ee-06e0bb7c2d03,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_update_name_of_non_existent_server[id-aa8eed43-e2cb-4ebf-930b-da14f6a21d81,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_update_server_name_length_exceeds_256[id-5c8e244c-dada-4590-9944-749c455b431f,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_update_server_of_another_tenant[id-543d84c1-dd2e-4c6d-8cb2-b9da0efaa384,negative] +tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_update_server_set_empty_name[id-38204696-17c6-44da-9590-40f87fb5a899,negative] +tempest.api.compute.test_authorization.AuthorizationTestJSON.test_create_keypair_in_analt_user_tenant[id-f03d1ded-7fd4-4d29-bc13-e2391f29c625] +tempest.api.compute.test_authorization.AuthorizationTestJSON.test_create_server_fails_when_tenant_incorrect[id-acf8724b-142b-4044-82c3-78d31a533f24] +tempest.api.compute.test_authorization.AuthorizationTestJSON.test_create_server_with_unauthorized_image[id-95d445f6-babc-4f2e-aea3-aa24ec5e7f0d] +tempest.api.compute.test_authorization.AuthorizationTestJSON.test_get_keypair_of_alt_account_fails[id-85bcdd8f-56b4-4868-ae56-63fbf6f7e405] +tempest.api.compute.test_authorization.AuthorizationTestJSON.test_get_metadata_of_alt_account_server_fails[id-dea1936a-473d-49f2-92ad-97bb7aded22e] +tempest.api.compute.test_authorization.AuthorizationTestJSON.test_set_metadata_of_alt_account_server_fails[id-c5f52351-53d9-4fc9-83e5-917f7f5e3d71] +tempest.api.compute.test_quotas.QuotasTestJSON.test_get_default_quotas[id-9bfecac7-b966-4f47-913f-1a9e2c12134a] +tempest.api.compute.test_quotas.QuotasTestJSON.test_get_quotas[id-f1ef0a97-dbbb-4cca-adc5-c9fbc4f76107] +tempest.api.compute.volumes.test_attach_volume.AttachVolumeTestJSON.test_attach_detach_volume[id-52e9045a-e90d-4c0d-9087-79d657faffff] +tempest.api.compute.volumes.test_volumes_list.VolumesTestJSON.test_volume_list[id-bc2dd1a0-15af-48e5-9990-f2e75a48325d] +tempest.api.compute.volumes.test_volumes_list.VolumesTestJSON.test_volume_list_with_details[id-bad0567a-5a4f-420b-851e-780b55bb867c] +tempest.api.compute.volumes.test_volumes_negative.VolumesNegativeTest.test_get_invalid_volume_id[id-f01904f2-e975-4915-98ce-cb5fa27bde4f,negative] +tempest.api.compute.volumes.test_volumes_negative.VolumesNegativeTest.test_get_volume_without_passing_volume_id[id-62bab09a-4c03-4617-8cca-8572bc94af9b,negative] +tempest.api.image.v1.test_images.ListImagesTest.test_index_no_params[id-246178ab-3b33-4212-9a4b-a7fe8261794d] diff --git a/testcases/VIM/OpenStack/CI/libraries/check_os.sh b/testcases/VIM/OpenStack/CI/libraries/check_os.sh new file mode 100755 index 000000000..560205261 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/libraries/check_os.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# +# Simple script to check the basic OpenStack clients +# +# Author: +# jose.lausuch@ericsson.com +# + +verify_connectivity() { + for i in $(seq 0 10); do + if echo "test" | nc -v $1 $2 &>/dev/null; then + return 0 + fi + sleep 1 + done + return 1 +} + + +if [ -z $OS_AUTH_URL ];then + echo "ERROR: OS_AUTH_URL environment variable missing... Have you sourced the OpenStack credentials?" + exit 1 +fi + + +echo "Checking OpenStack endpoints:" +publicURL=$OS_AUTH_URL +publicIP=$(echo $publicURL|sed 's/^.*http\:\/\///'|sed 's/.[^:]*$//') +publicPort=$(echo $publicURL|sed 's/^.*://'|sed 's/.[^\/]*$//') +echo ">>Verifying connectivity to the public endpoint $publicIP:$publicPort..." +verify_connectivity $publicIP $publicPort +RETVAL=$? +if [ $RETVAL -ne 0 ]; then + echo "ERROR: Cannot talk to the public endpoint publicIP:$publicPort ." + echo "OS_AUTH_URL=$OS_AUTH_URL" + exit 1 +fi +echo " ...OK" + +adminURL=$(keystone catalog --service identity 2>/dev/null|grep adminURL|awk '{print $4}') +adminIP=$(echo $adminURL|sed 's/^.*http\:\/\///'|sed 's/.[^:]*$//') +adminPort=$(echo $adminURL|sed 's/^.*://'|sed 's/.[^\/]*$//') +echo ">>Verifying connectivity to the admin endpoint $adminIP:$adminPort..." +verify_connectivity $adminIP $adminPort +RETVAL=$? +if [ $RETVAL -ne 0 ]; then + echo "ERROR: Cannot talk to the admin endpoint adminIP:$adminPort ." + echo "adminURL" + exit 1 +fi +echo " ...OK" + + +echo "Checking OpenStack basic services:" +commands=('keystone endpoint-list' 'nova list' 'neutron net-list' \ + 'glance image-list' 'cinder list') +for cmd in "${commands[@]}" +do + service=$(echo $cmd | awk '{print $1}') + echo ">>Checking $service service..." + $cmd &>/dev/null + result=$? + if [ $result -ne 0 ]; + then + + echo "ERROR: Failed execution $cmd. The $service does not seem to be working." + exit 1 + else + echo " ...OK" + fi +done + +echo "OpenStack services are OK." + +echo "Checking External network..." +networks=($(neutron net-list | tail -n +4 | head -n -1 | awk '{print $2}')) +is_external=False +for net in "${networks[@]}" +do + is_external=$(neutron net-show $net|grep "router:external"|awk '{print $4}') + if [ $is_external == "True" ]; then + echo "External network found: $net" + break + fi +done +if [ $is_external == "False" ]; then + echo "ERROR: There are no external networks in the deployment." + exit 1 +fi + +exit 0 diff --git a/testcases/VIM/OpenStack/CI/libraries/clean_openstack.py b/testcases/VIM/OpenStack/CI/libraries/clean_openstack.py new file mode 100644 index 000000000..96bd172b9 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/libraries/clean_openstack.py @@ -0,0 +1,399 @@ +#!/usr/bin/env python +# +# Description: +# Cleans possible leftovers after running functest tests: +# - Nova instances +# - Glance images +# - Cinder volumes +# - Floating IPs +# - Neutron networks, subnets and ports +# - Routers +# - Users and tenants +# +# Author: +# jose.lausuch@ericsson.com +# + +import argparse +import logging +import os +import re +import sys +import time +import yaml + +from novaclient import client as novaclient +from neutronclient.v2_0 import client as neutronclient +from keystoneclient.v2_0 import client as keystoneclient +from cinderclient import client as cinderclient + +parser = argparse.ArgumentParser() +parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") +args = parser.parse_args() + + +""" logging configuration """ +logger = logging.getLogger('clean_openstack') +logger.setLevel(logging.DEBUG) + +ch = logging.StreamHandler() +if args.debug: + ch.setLevel(logging.DEBUG) +else: + ch.setLevel(logging.INFO) + +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + +REPO_PATH=os.environ['repos_dir']+'/functest/' +if not os.path.exists(REPO_PATH): + logger.error("Functest repository directory not found '%s'" % REPO_PATH) + exit(-1) +sys.path.append(REPO_PATH + "testcases/") +import functest_utils + +with open(REPO_PATH+"testcases/VIM/OpenStack/CI/libraries/os_defaults.yaml") as f: + defaults_yaml = yaml.safe_load(f) +f.close() + +installer = os.environ["INSTALLER_TYPE"] + +default_images = defaults_yaml.get(installer).get("images") +default_networks = defaults_yaml.get(installer).get("networks") +\ + defaults_yaml.get("common").get("networks") +default_routers = defaults_yaml.get(installer).get("routers") +\ + defaults_yaml.get("common").get("routers") +default_security_groups = defaults_yaml.get(installer).get("security_groups") +default_users = defaults_yaml.get(installer).get("users") +default_tenants = defaults_yaml.get(installer).get("tenants") + +def separator(): + logger.info("-------------------------------------------") + +def remove_instances(nova_client): + logger.info("Removing Nova instances...") + instances = functest_utils.get_instances(nova_client) + if instances is None or len(instances) == 0: + logger.debug("No instances found.") + return + + for instance in instances: + instance_name = getattr(instance, 'name') + instance_id = getattr(instance, 'id') + logger.debug("Removing instance '%s', ID=%s ..." % (instance_name,instance_id)) + if functest_utils.delete_instance(nova_client, instance_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "instance %s..." % instance_id) + + timeout = 50 + while timeout > 0: + instances = functest_utils.get_instances(nova_client) + if instances is None or len(instances) == 0: + break + else: + logger.debug("Waiting for instances to be terminated...") + timeout -= 1 + time.sleep(1) + + +def remove_images(nova_client): + logger.info("Removing Glance images...") + images = functest_utils.get_images(nova_client) + if images is None or len(images) == 0: + logger.debug("No images found.") + return + + for image in images: + image_name = getattr(image, 'name') + image_id = getattr(image, 'id') + logger.debug("'%s', ID=%s " %(image_name,image_id)) + if image_name not in default_images: + logger.debug("Removing image '%s', ID=%s ..." % (image_name,image_id)) + if functest_utils.delete_glance_image(nova_client, image_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the" + "image %s..." % image_id) + else: + logger.debug(" > this is a default image and will NOT be deleted.") + + +def remove_volumes(cinder_client): + logger.info("Removing Cinder volumes...") + volumes = functest_utils.get_volumes(cinder_client) + if volumes is None or len(volumes) == 0: + logger.debug("No volumes found.") + return + + for volume in volumes: + volume_id = getattr(volume, 'id') + logger.debug("Removing cinder volume %s ..." % volume_id) + if functest_utils.delete_volume(cinder_client, volume_id): + logger.debug(" > Done!") + else: + logger.debug("Trying forced removal...") + if functest_utils.delete_volume(cinder_client, + volume_id, + forced=True): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "volume %s..." % volume_id) + + +def remove_floatingips(nova_client): + logger.info("Removing floating IPs...") + floatingips = functest_utils.get_floating_ips(nova_client) + if floatingips is None or len(floatingips) == 0: + logger.debug("No floating IPs found.") + return + + for fip in floatingips: + fip_id = getattr(fip, 'id') + logger.debug("Removing floating IP %s ..." % fip_id) + if functest_utils.delete_floating_ip(nova_client, fip_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "floating IP %s..." % fip_id) + + timeout = 50 + while timeout > 0: + floatingips = functest_utils.get_floating_ips(nova_client) + if floatingips is None or len(floatingips) == 0: + break + else: + logger.debug("Waiting for floating ips to be released...") + timeout -= 1 + time.sleep(1) + + +def remove_networks(neutron_client): + logger.info("Removing Neutron objects") + network_ids = [] + networks = functest_utils.get_network_list(neutron_client) + if networks == None: + logger.debug("There are no networks in the deployment. ") + else: + logger.debug("Existing networks:") + for network in networks: + net_id = network['id'] + net_name = network['name'] + logger.debug(" '%s', ID=%s " %(net_name,net_id)) + if net_name in default_networks: + logger.debug(" > this is a default network and will NOT be deleted.") + elif network['router:external'] == True: + logger.debug(" > this is an external network and will NOT be deleted.") + else: + logger.debug(" > this network will be deleted.") + network_ids.append(net_id) + + #delete ports + ports = functest_utils.get_port_list(neutron_client) + if ports is None: + logger.debug("There are no ports in the deployment. ") + else: + remove_ports(neutron_client, ports, network_ids) + + #remove routers + routers = functest_utils.get_router_list(neutron_client) + if routers is None: + logger.debug("There are no routers in the deployment. ") + else: + remove_routers(neutron_client, routers) + + #remove networks + if network_ids != None: + for net_id in network_ids: + logger.debug("Removing network %s ..." % net_id) + if functest_utils.delete_neutron_net(neutron_client, net_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "network %s..." % net_id) + + +def remove_ports(neutron_client, ports, network_ids): + for port in ports: + if port['network_id'] in network_ids: + port_id = port['id'] + try: + subnet_id = port['fixed_ips'][0]['subnet_id'] + except: + logger.info(" > WARNING: Port %s does not contain 'fixed_ips'" % port_id) + print port + router_id = port['device_id'] + if len(port['fixed_ips']) == 0 and router_id == '': + logger.debug("Removing port %s ..." % port_id) + if functest_utils.delete_neutron_port(neutron_client, port_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "port %s ..." %port_id) + force_remove_port(neutron_client, port_id) + + elif port['device_owner'] == 'network:router_interface': + logger.debug("Detaching port %s (subnet %s) from router %s ..." + % (port_id,subnet_id,router_id)) + if functest_utils.remove_interface_router(neutron_client, + router_id, subnet_id): + time.sleep(5) # leave 5 seconds to detach before doing anything else + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "interface %s from router %s..." %(subnet_id,router_id)) + force_remove_port(neutron_client, port_id) + else: + force_remove_port(neutron_client, port_id) + + +def force_remove_port(neutron_client, port_id): + logger.debug("Clearing device_owner for port %s ..." % port_id) + functest_utils.update_neutron_port(neutron_client, + port_id, + device_owner='clear') + logger.debug("Removing port %s ..." % port_id) + if functest_utils.delete_neutron_port(neutron_client, port_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: Deleting port %s failed" % port_id) + + +def remove_routers(neutron_client, routers): + for router in routers: + router_id = router['id'] + router_name = router['name'] + if router_name not in default_routers: + logger.debug("Checking '%s' with ID=(%s) ..." % (router_name,router_id)) + if router['external_gateway_info'] != None: + logger.debug("Router has gateway to external network. Removing link...") + if functest_utils.remove_gateway_router(neutron_client, router_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing " + "the gateway...") + else: + logger.debug("Router is not connected to anything. Ready to remove...") + logger.debug("Removing router %s(%s) ..." % (router_name, router_id)) + if functest_utils.delete_neutron_router(neutron_client, router_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "router '%s'(%s)..." % (router_name, router_id)) + + +def remove_security_groups(neutron_client): + logger.info("Removing Security groups...") + secgroups = functest_utils.get_security_groups(neutron_client) + if secgroups is None or len(secgroups) == 0: + logger.debug("No security groups found.") + return + + for secgroup in secgroups: + secgroup_name = secgroup['name'] + secgroup_id = secgroup['id'] + logger.debug("'%s', ID=%s " %(secgroup_name,secgroup_id)) + if secgroup_name not in default_security_groups: + logger.debug(" Removing '%s'..." % secgroup_name) + if functest_utils.delete_security_group(neutron_client, secgroup_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "security group %s..." % secgroup_id) + else: + logger.debug(" > this is a default security group and will NOT " + "be deleted.") + + +def remove_users(keystone_client): + logger.info("Removing Users...") + users = functest_utils.get_users(keystone_client) + if users == None: + logger.debug("There are no users in the deployment. ") + return + + for user in users: + user_name = getattr(user, 'name') + user_id = getattr(user, 'id') + logger.debug("'%s', ID=%s " %(user_name,user_id)) + if user_name not in default_users: + logger.debug(" Removing '%s'..." % user_name) + if functest_utils.delete_user(keystone_client,user_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "user '%s'(%s)..." % (user_name,user_id)) + else: + logger.debug(" > this is a default user and will NOT be deleted.") + + +def remove_tenants(keystone_client): + logger.info("Removing Tenants...") + tenants = functest_utils.get_tenants(keystone_client) + if tenants == None: + logger.debug("There are no tenants in the deployment. ") + return + + for tenant in tenants: + tenant_name=getattr(tenant, 'name') + tenant_id = getattr(tenant, 'id') + logger.debug("'%s', ID=%s " %(tenant_name,tenant_id)) + if tenant_name not in default_tenants: + logger.debug(" Removing '%s'..." % tenant_name) + if functest_utils.delete_tenant(keystone_client,tenant_id): + logger.debug(" > Done!") + else: + logger.info(" > ERROR: There has been a problem removing the " + "tenant '%s'(%s)..." % (tenant_name,tenant_id)) + else: + logger.debug(" > this is a default tenant and will NOT be deleted.") + + + +def main(): + creds_nova = functest_utils.get_credentials("nova") + nova_client = novaclient.Client('2',**creds_nova) + + creds_neutron = functest_utils.get_credentials("neutron") + neutron_client = neutronclient.Client(**creds_neutron) + + creds_keystone = functest_utils.get_credentials("keystone") + keystone_client = keystoneclient.Client(**creds_keystone) + + creds_cinder = functest_utils.get_credentials("cinder") + #cinder_client = cinderclient.Client(**creds_cinder) + cinder_client = cinderclient.Client('1',creds_cinder['username'], + creds_cinder['api_key'], + creds_cinder['project_id'], + creds_cinder['auth_url'], + service_type="volume") + + if not functest_utils.check_credentials(): + logger.error("Please source the openrc credentials and run the script again.") + exit(-1) + + remove_instances(nova_client) + separator() + remove_images(nova_client) + separator() + remove_volumes(cinder_client) + separator() + remove_floatingips(nova_client) + separator() + remove_networks(neutron_client) + separator() + remove_security_groups(neutron_client) + separator() + remove_users(keystone_client) + separator() + remove_tenants(keystone_client) + separator() + + exit(0) + + +if __name__ == '__main__': + main() diff --git a/testcases/VIM/OpenStack/CI/libraries/os_defaults.yaml b/testcases/VIM/OpenStack/CI/libraries/os_defaults.yaml new file mode 100644 index 000000000..f792cda5d --- /dev/null +++ b/testcases/VIM/OpenStack/CI/libraries/os_defaults.yaml @@ -0,0 +1,31 @@ +fuel: + images: ['TestVM'] + networks: ['net04', 'net04_ext'] + routers: ['router04'] + security_groups: ['default'] + tenants: ['admin', 'services'] + users: ['heat', 'heat-cfn', 'cinder', 'nova', 'swift', 'glance', 'neutron', 'admin', 'fuel_stats_user'] +apex: + images: [] + networks: ['internal', 'external'] + routers: [] + security_groups: ['default'] + tenants: ['admin', 'services', 'service'] + users: ['heat', 'heat-cfn', 'cinder', 'nova', 'swift', 'glance', 'neutron', 'admin', 'ceilometer', 'cinderv2'] +compass: + images: [] + networks: ['ext-net'] + routers: [] + security_groups: ['default'] + tenants: ['admin', 'service', 'demo'] + users: ['heat', 'cinder', 'nova', 'glance', 'neutron', 'admin', 'ceilometer', 'demo', 'keystone'] +joid: + images: [] + networks: ['ext-net'] + routers: [] + security_groups: ['default'] + tenants: ['admin', 'services'] + users: ['admin', 'glance', 'nova', 'quantum_nova', 'quantum', 'heat-cfn_heat', 'ceilometer', 'cinder_cinderv2', 'swift'] +common: + networks: ['functest-net'] + routers: ['functest-router'] diff --git a/testcases/VIM/OpenStack/CI/libraries/run_rally-cert.py b/testcases/VIM/OpenStack/CI/libraries/run_rally-cert.py new file mode 100755 index 000000000..b5fcd7218 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/libraries/run_rally-cert.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python +# +# Copyright (c) 2015 Orange +# guyrodrigue.koffi@orange.com +# morgan.richomme@orange.com +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 0.1 (05/2015) initial commit +# 0.2 (28/09/2015) extract Tempest, format json result, add ceilometer suite +# 0.3 (19/10/2015) remove Tempest from run_rally +# and push result into test DB +# + +import re +import json +import os +import argparse +import logging +import yaml +import requests +import sys +from novaclient import client as novaclient +from glanceclient import client as glanceclient +from keystoneclient.v2_0 import client as keystoneclient +from neutronclient.v2_0 import client as neutronclient + +""" tests configuration """ +tests = ['authenticate', 'glance', 'cinder', 'heat', 'keystone', + 'neutron', 'nova', 'quotas', 'requests', 'vm', 'all'] +parser = argparse.ArgumentParser() +parser.add_argument("test_name", + help="Module name to be tested. " + "Possible values are : " + "[ {d[0]} | {d[1]} | {d[2]} | {d[3]} | {d[4]} | " + "{d[5]} | {d[6]} | {d[7]} | {d[8]} | {d[9]} | " + "{d[10]} ] " + "The 'all' value " + "performs all possible test scenarios" + .format(d=tests)) + +parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") +parser.add_argument("-r", "--report", + help="Create json result file", + action="store_true") +parser.add_argument("-s", "--smoke", + help="Smoke test mode", + action="store_true") + +args = parser.parse_args() + +client_dict = {} + +""" logging configuration """ +logger = logging.getLogger("run_rally") +logger.setLevel(logging.DEBUG) + +ch = logging.StreamHandler() +if args.debug: + ch.setLevel(logging.DEBUG) +else: + ch.setLevel(logging.INFO) + +formatter = logging.Formatter("%(asctime)s - %(name)s - " + "%(levelname)s - %(message)s") +ch.setFormatter(formatter) +logger.addHandler(ch) + +REPO_PATH=os.environ['repos_dir']+'/functest/' +if not os.path.exists(REPO_PATH): + logger.error("Functest repository directory not found '%s'" % REPO_PATH) + exit(-1) +sys.path.append(REPO_PATH + "testcases/") +import functest_utils + +with open("/home/opnfv/functest/conf/config_functest.yaml") as f: + functest_yaml = yaml.safe_load(f) +f.close() + +HOME = os.environ['HOME']+"/" +####todo: +#SCENARIOS_DIR = REPO_PATH + functest_yaml.get("general"). \ +# get("directories").get("dir_rally_scn") +SCENARIOS_DIR = REPO_PATH + "testcases/VIM/OpenStack/CI/rally_cert/" +### +TEMPLATE_DIR = SCENARIOS_DIR + "scenario/templates" +SUPPORT_DIR = SCENARIOS_DIR + "scenario/support" +###todo: +FLAVOR_NAME = "m1.tiny" +USERS_AMOUNT = 2 +TENANTS_AMOUNT = 3 +CONTROLLERS_AMOUNT = 2 +### +RESULTS_DIR = functest_yaml.get("general").get("directories"). \ + get("dir_rally_res") +TEST_DB = functest_yaml.get("results").get("test_db_url") +FLOATING_NETWORK = functest_yaml.get("general"). \ + get("openstack").get("neutron_public_net_name") +FLOATING_SUBNET_CIDR = functest_yaml.get("general"). \ + get("openstack").get("neutron_public_subnet_cidr") +PRIVATE_NETWORK = functest_yaml.get("general"). \ + get("openstack").get("neutron_private_net_name") + +GLANCE_IMAGE_NAME = functest_yaml.get("general"). \ + get("openstack").get("image_name") +GLANCE_IMAGE_FILENAME = functest_yaml.get("general"). \ + get("openstack").get("image_file_name") +GLANCE_IMAGE_FORMAT = functest_yaml.get("general"). \ + get("openstack").get("image_disk_format") +GLANCE_IMAGE_PATH = functest_yaml.get("general"). \ + get("directories").get("dir_functest_data") + "/" + GLANCE_IMAGE_FILENAME + + +def push_results_to_db(payload): + + url = TEST_DB + "/results" + installer = functest_utils.get_installer_type(logger) + git_version = functest_utils.get_git_branch(REPO_PATH) + pod_name = functest_utils.get_pod_name(logger) + # TODO pod_name hardcoded, info shall come from Jenkins + params = {"project_name": "functest", "case_name": "Rally", + "pod_name": pod_name, "installer": installer, + "version": git_version, "details": payload} + + headers = {'Content-Type': 'application/json'} + r = requests.post(url, data=json.dumps(params), headers=headers) + logger.debug(r) + + +def get_task_id(cmd_raw): + """ + get task id from command rally result + :param cmd_raw: + :return: task_id as string + """ + taskid_re = re.compile('^Task +(.*): started$') + for line in cmd_raw.splitlines(True): + line = line.strip() + match = taskid_re.match(line) + if match: + return match.group(1) + return None + + +def task_succeed(json_raw): + """ + Parse JSON from rally JSON results + :param json_raw: + :return: Bool + """ + rally_report = json.loads(json_raw) + rally_report = rally_report[0] + if rally_report is None: + return False + if rally_report.get('result') is None: + return False + + for result in rally_report.get('result'): + if len(result.get('error')) > 0: + return False + + return True + + +def build_task_args(test_file_name): + task_args = {'service_list': [test_file_name]} + task_args['smoke'] = args.smoke + task_args['image_name'] = GLANCE_IMAGE_NAME + task_args['flavor_name'] = FLAVOR_NAME + task_args['glance_image_location'] = GLANCE_IMAGE_PATH + task_args['floating_network'] = FLOATING_NETWORK + task_args['floating_subnet_cidr'] = FLOATING_SUBNET_CIDR + task_args['netid'] = functest_utils.get_network_id(client_dict['neutron'], + PRIVATE_NETWORK).encode('ascii', 'ignore') + task_args['tmpl_dir'] = TEMPLATE_DIR + task_args['sup_dir'] = SUPPORT_DIR + task_args['users_amount'] = USERS_AMOUNT + task_args['tenants_amount'] = TENANTS_AMOUNT + task_args['controllers_amount'] = CONTROLLERS_AMOUNT + + return task_args + + +def run_task(test_name): + # + # the "main" function of the script who launch rally for a task + # :param test_name: name for the rally test + # :return: void + # + + logger.info('starting {} test ...'.format(test_name)) + + task_file = '{}task.yaml'.format(SCENARIOS_DIR) + if not os.path.exists(task_file): + logger.error("Task file '%s' does not exist." % task_file) + exit(-1) + + test_file_name = '{}opnfv-{}.yaml'.format(SCENARIOS_DIR + "scenario/", test_name) + if not os.path.exists(test_file_name): + logger.error("The scenario '%s' does not exist." % test_file_name) + exit(-1) + + logger.debug('Scenario fetched from : {}'.format(test_file_name)) + + cmd_line = "rally task start --abort-on-sla-failure " + \ + "--task {} ".format(task_file) + \ + "--task-args \"{}\" ".format(build_task_args(test_name)) + logger.debug('running command line : {}'.format(cmd_line)) + cmd = os.popen(cmd_line) + task_id = get_task_id(cmd.read()) + logger.debug('task_id : {}'.format(task_id)) + + if task_id is None: + logger.error("failed to retrieve task_id") + exit(-1) + + # check for result directory and create it otherwise + if not os.path.exists(RESULTS_DIR): + logger.debug('does not exists, we create it'.format(RESULTS_DIR)) + os.makedirs(RESULTS_DIR) + + # write html report file + report_file_name = '{}opnfv-{}.html'.format(RESULTS_DIR, test_name) + cmd_line = "rally task report {} --out {}".format(task_id, + report_file_name) + + logger.debug('running command line : {}'.format(cmd_line)) + os.popen(cmd_line) + + # get and save rally operation JSON result + cmd_line = "rally task results %s" % task_id + logger.debug('running command line : {}'.format(cmd_line)) + cmd = os.popen(cmd_line) + json_results = cmd.read() + with open('{}opnfv-{}.json'.format(RESULTS_DIR, test_name), 'w') as f: + logger.debug('saving json file') + f.write(json_results) + + with open('{}opnfv-{}.json' + .format(RESULTS_DIR, test_name)) as json_file: + json_data = json.load(json_file) + + # Push results in payload of testcase + if args.report: + logger.debug("Push result into DB") + push_results_to_db(json_data) + + """ parse JSON operation result """ + if task_succeed(json_results): + print 'Test OK' + else: + print 'Test KO' + + +def main(): + # configure script + if not (args.test_name in tests): + logger.error('argument not valid') + exit(-1) + + creds_nova = functest_utils.get_credentials("nova") + nova_client = novaclient.Client('2',**creds_nova) + creds_neutron = functest_utils.get_credentials("neutron") + neutron_client = neutronclient.Client(**creds_neutron) + creds_keystone = functest_utils.get_credentials("keystone") + keystone_client = keystoneclient.Client(**creds_keystone) + glance_endpoint = keystone_client.service_catalog.url_for(service_type='image', + endpoint_type='publicURL') + glance_client = glanceclient.Client(1, glance_endpoint, + token=keystone_client.auth_token) + + client_dict['neutron'] = neutron_client + + logger.debug("Creating image '%s' from '%s'..." % (GLANCE_IMAGE_NAME, GLANCE_IMAGE_PATH)) + image_id = functest_utils.create_glance_image(glance_client, + GLANCE_IMAGE_NAME,GLANCE_IMAGE_PATH) + if not image_id: + logger.error("Failed to create a Glance image...") + exit(-1) + # Check if the given image exists + try: + nova_client.images.find(name=GLANCE_IMAGE_NAME) + logger.info("Glance image found '%s'" % GLANCE_IMAGE_NAME) + except: + logger.error("ERROR: Glance image '%s' not found." % GLANCE_IMAGE_NAME) + logger.info("Available images are: ") + exit(-1) + + if args.test_name == "all": + for test_name in tests: + if not (test_name == 'all' or + test_name == 'vm'): + print(test_name) + run_task(test_name) + else: + print(args.test_name) + run_task(args.test_name) + + logger.debug("Deleting image...") + if not functest_utils.delete_glance_image(nova_client, image_id): + logger.error("Error deleting the glance image") + +if __name__ == '__main__': + main() diff --git a/testcases/VIM/OpenStack/CI/libraries/run_rally.py b/testcases/VIM/OpenStack/CI/libraries/run_rally.py index 2bfb8127f..d5796c1b4 100644 --- a/testcases/VIM/OpenStack/CI/libraries/run_rally.py +++ b/testcases/VIM/OpenStack/CI/libraries/run_rally.py @@ -8,36 +8,48 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 # -import re, json, os, urllib2, argparse, logging, yaml - -with open('../functest.yaml') as f: - functest_yaml = yaml.safe_load(f) -f.close() +# 0.1 (05/2015) initial commit +# 0.2 (28/09/2015) extract Tempest, format json result, add ceilometer suite +# 0.3 (19/10/2015) remove Tempest from run_rally +# and push result into test DB +# -HOME = os.environ['HOME']+"/" -SCENARIOS_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_rally_scn") -RESULTS_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_rally_res") +import re +import json +import os +import argparse +import logging +import yaml +import requests +import sys +from novaclient import client as novaclient +from keystoneclient.v2_0 import client as keystoneclient +from glanceclient import client as glanceclient """ tests configuration """ -tests = ['authenticate', 'glance', 'cinder', 'heat', 'keystone', 'neutron', 'nova', 'quotas', 'requests', 'tempest', 'vm', 'all', 'smoke'] +tests = ['authenticate', 'glance', 'cinder', 'ceilometer', 'heat', 'keystone', + 'neutron', 'nova', 'quotas', 'requests', 'vm', 'all'] parser = argparse.ArgumentParser() -parser.add_argument("test_name", help="The name of the test you want to perform with rally. " - "Possible values are : " - "[ {d[0]} | {d[1]} | {d[2]} | {d[3]} | {d[4]} | {d[5]} | {d[6]} " - "| {d[7]} | {d[8]} | {d[9]} | {d[10]} | {d[11]} | {d[12]}]. The 'all' value performs all the tests scenarios " - "except 'tempest'".format(d=tests)) +parser.add_argument("test_name", + help="Module name to be tested" + "Possible values are : " + "[ {d[0]} | {d[1]} | {d[2]} | {d[3]} | {d[4]} | " + "{d[5]} | {d[6]} | {d[7]} | {d[8]} | {d[9]} | " + "{d[10]} | {d[11]}]. The 'all' value " + "performs all the possible tests scenarios" + .format(d=tests)) parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") -parser.add_argument("test_mode", help="Tempest test mode", nargs='?', default="smoke") +parser.add_argument("-r", "--report", + help="Create json result file", + action="store_true") + args = parser.parse_args() -test_mode=args.test_mode -if not args.test_name == "tempest": - if not args.test_mode == "smoke": - parser.error("test_mode is only used with tempest") + """ logging configuration """ -logger = logging.getLogger('run_rally') +logger = logging.getLogger("run_rally") logger.setLevel(logging.DEBUG) ch = logging.StreamHandler() @@ -46,25 +58,53 @@ if args.debug: else: ch.setLevel(logging.INFO) -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +formatter = logging.Formatter("%(asctime)s - %(name)s - " + "%(levelname)s - %(message)s") ch.setFormatter(formatter) logger.addHandler(ch) +REPO_PATH=os.environ['repos_dir']+'/functest/' +if not os.path.exists(REPO_PATH): + logger.error("Functest repository directory not found '%s'" % REPO_PATH) + exit(-1) +sys.path.append(REPO_PATH + "testcases/") +import functest_utils -def get_tempest_id(cmd_raw): - """ - get task id from command rally result - :param cmd_raw: - :return: task_id as string - """ - taskid_re = re.compile('^Verification UUID: (.*)$') - for line in cmd_raw.splitlines(True): - line = line.strip() - match = taskid_re.match(line) +with open("/home/opnfv/functest/conf/config_functest.yaml") as f: + functest_yaml = yaml.safe_load(f) +f.close() + +HOME = os.environ['HOME']+"/" +SCENARIOS_DIR = REPO_PATH + functest_yaml.get("general"). \ + get("directories").get("dir_rally_scn") +RESULTS_DIR = functest_yaml.get("general").get("directories"). \ + get("dir_rally_res") +TEST_DB = functest_yaml.get("results").get("test_db_url") + +GLANCE_IMAGE_NAME = "functest-img-rally" +GLANCE_IMAGE_FILENAME = functest_yaml.get("general"). \ + get("openstack").get("image_file_name") +GLANCE_IMAGE_FORMAT = functest_yaml.get("general"). \ + get("openstack").get("image_disk_format") +GLANCE_IMAGE_PATH = functest_yaml.get("general"). \ + get("directories").get("dir_functest_data") + "/" + GLANCE_IMAGE_FILENAME + + +def push_results_to_db(payload): + + url = TEST_DB + "/results" + installer = functest_utils.get_installer_type(logger) + git_version = functest_utils.get_git_branch(REPO_PATH) + pod_name = functest_utils.get_pod_name(logger) + # TODO pod_name hardcoded, info shall come from Jenkins + params = {"project_name": "functest", "case_name": "Rally", + "pod_name": pod_name, "installer": installer, + "version": git_version, "details": payload} + + headers = {'Content-Type': 'application/json'} + r = requests.post(url, data=json.dumps(params), headers=headers) + logger.debug(r) - if match: - return match.group(1) - return None def get_task_id(cmd_raw): """ @@ -81,6 +121,16 @@ def get_task_id(cmd_raw): return None +def create_glance_image(path, name, disk_format): + """ + Create a glance image given the absolute path of the image, its name and the disk format + """ + cmd = ("glance image-create --name " + name + " --visibility public " + "--disk-format " + disk_format + " --container-format bare --file " + path) + functest_utils.execute_command(cmd, logger) + return True + + def task_succeed(json_raw): """ Parse JSON from rally JSON results @@ -95,68 +145,33 @@ def task_succeed(json_raw): return False for result in rally_report.get('result'): - if len(result.get('errors')) > 0: + if len(result.get('error')) > 0: return False return True -def run_tempest(): - """ - the function dedicated to Tempest (functional tests for OpenStack) - :param test_mode: Tempest mode smoke (default), full, .. - :return: void - """ - logger.info('starting {} Tempest ...'.format(test_mode)) - - """ get the date """ - cmd = os.popen("date '+%d%m%Y_%H%M'") - test_date = cmd.read().rstrip() - - cmd_line = "rally verify start {}".format(test_mode) - logger.debug('running command line : {}'.format(cmd_line)) - cmd = os.popen(cmd_line) - task_id = get_tempest_id(cmd.read()) - logger.debug('task_id : {}'.format(task_id)) - - if task_id is None: - logger.error("failed to retrieve task_id") - exit(-1) - - """ check for result directory and create it otherwise """ - if not os.path.exists(RESULTS_DIR): - logger.debug('does not exists, we create it'.format(RESULTS_DIR)) - os.makedirs(RESULTS_DIR) - - """ write log report file """ - report_file_name = '{}opnfv-tempest-{}.log'.format(RESULTS_DIR, test_date) - cmd_line = "rally verify detailed {} > {} ".format(task_id, report_file_name) - logger.debug('running command line : {}'.format(cmd_line)) - os.popen(cmd_line) - def run_task(test_name): - """ - the "main" function of the script who lunch rally for a task - :param test_name: name for the rally test - :return: void - """ - logger.info('starting {} test ...'.format(test_name)) + # + # the "main" function of the script who lunch rally for a task + # :param test_name: name for the rally test + # :return: void + # - """ get the date """ - cmd = os.popen("date '+%d%m%Y_%H%M'") - test_date = cmd.read().rstrip() + logger.info('starting {} test ...'.format(test_name)) - """ check directory for scenarios test files or retrieve from git otherwise""" + # check directory for scenarios test files or retrieve from git otherwise proceed_test = True test_file_name = '{}opnfv-{}.json'.format(SCENARIOS_DIR, test_name) + if not os.path.exists(test_file_name): - logger.debug('{} does not exists'.format(test_file_name)) - proceed_test = retrieve_test_cases_file(test_name, SCENARIOS_DIR) + logger.error("The scenario '%s' does not exist." % test_file_name) + exit(-1) - """ we do the test only if we have a scenario test file """ + # we do the test only if we have a scenario test file if proceed_test: logger.debug('Scenario fetched from : {}'.format(test_file_name)) - cmd_line = "rally task start --abort-on-sla-failure %s" % test_file_name + cmd_line = "rally task start --abort-on-sla-failure {}".format(test_file_name) logger.debug('running command line : {}'.format(cmd_line)) cmd = os.popen(cmd_line) task_id = get_task_id(cmd.read()) @@ -166,26 +181,36 @@ def run_task(test_name): logger.error("failed to retrieve task_id") exit(-1) - """ check for result directory and create it otherwise """ + # check for result directory and create it otherwise if not os.path.exists(RESULTS_DIR): logger.debug('does not exists, we create it'.format(RESULTS_DIR)) os.makedirs(RESULTS_DIR) - """ write html report file """ - report_file_name = '{}opnfv-{}-{}.html'.format(RESULTS_DIR, test_name, test_date) - cmd_line = "rally task report %s --out %s" % (task_id, report_file_name) + # write html report file + report_file_name = '{}opnfv-{}.html'.format(RESULTS_DIR, test_name) + cmd_line = "rally task report {} --out {}".format(task_id, + report_file_name) + logger.debug('running command line : {}'.format(cmd_line)) os.popen(cmd_line) - """ get and save rally operation JSON result """ + # get and save rally operation JSON result cmd_line = "rally task results %s" % task_id logger.debug('running command line : {}'.format(cmd_line)) cmd = os.popen(cmd_line) json_results = cmd.read() - with open('{}opnfv-{}-{}.json'.format(RESULTS_DIR, test_name, test_date), 'w') as f: + with open('{}opnfv-{}.json'.format(RESULTS_DIR, test_name), 'w') as f: logger.debug('saving json file') f.write(json_results) - logger.debug('saving json file2') + + with open('{}opnfv-{}.json' + .format(RESULTS_DIR, test_name)) as json_file: + json_data = json.load(json_file) + + # Push results in payload of testcase + if args.report: + logger.debug("Push result into DB") + push_results_to_db(json_data) """ parse JSON operation result """ if task_succeed(json_results): @@ -193,53 +218,55 @@ def run_task(test_name): else: print 'Test KO' else: - logger.error('{} test failed, unable to fetch a scenario test file'.format(test_name)) - - -def retrieve_test_cases_file(test_name, tests_path): - """ - Retrieve from github the sample test files - :return: Boolean that indicates the retrieval status - """ - - """ do not add the "/" at the end """ - url_base = "https://git.opnfv.org/cgit/functest/plain/testcases/VIM/OpenStack/CI/suites" - - test_file_name = 'opnfv-{}.json'.format(test_name) - logger.info('fetching {}/{} ...'.format(url_base, test_file_name)) - - try: - response = urllib2.urlopen('{}/{}'.format(url_base, test_file_name)) - except (urllib2.HTTPError, urllib2.URLError): - return False - file_raw = response.read() - - """ check if the test path exist otherwise we create it """ - if not os.path.exists(tests_path): - os.makedirs(tests_path) - - with open('{}/{}'.format(tests_path, test_file_name), 'w') as f: - f.write(file_raw) - return True + logger.error('{} test failed, unable to fetch a scenario test file' + .format(test_name)) def main(): - """ configure script """ + # configure script if not (args.test_name in tests): logger.error('argument not valid') exit(-1) + creds_nova = functest_utils.get_credentials("nova") + nova_client = novaclient.Client('2',**creds_nova) + creds_keystone = functest_utils.get_credentials("keystone") + keystone_client = keystoneclient.Client(**creds_keystone) + glance_endpoint = keystone_client.service_catalog.url_for(service_type='image', + endpoint_type='publicURL') + glance_client = glanceclient.Client(1, glance_endpoint, + token=keystone_client.auth_token) + + logger.debug("Creating image '%s' from '%s'..." % (GLANCE_IMAGE_NAME, GLANCE_IMAGE_PATH)) + image_id = functest_utils.create_glance_image(glance_client, + GLANCE_IMAGE_NAME,GLANCE_IMAGE_PATH) + if not image_id: + logger.error("Failed to create a Glance image...") + exit(-1) + # Check if the given image exists + try: + nova_client.images.find(name=GLANCE_IMAGE_NAME) + logger.info("Glance image found '%s'" % GLANCE_IMAGE_NAME) + except: + logger.error("ERROR: Glance image '%s' not found." % GLANCE_IMAGE_NAME) + logger.info("Available images are: ") + exit(-1) + if args.test_name == "all": for test_name in tests: - if not (test_name == 'all' or test_name == 'tempest'): + if not (test_name == 'all' or + test_name == 'heat' or + test_name == 'ceilometer' or + test_name == 'smoke' or + test_name == 'vm'): print(test_name) run_task(test_name) else: print(args.test_name) - if args.test_name == 'tempest': - run_tempest() - else: - run_task(args.test_name) + run_task(args.test_name) + + if not functest_utils.delete_glance_image(nova_client, image_id): + logger.error("Error deleting the glance image") if __name__ == '__main__': main() diff --git a/testcases/VIM/OpenStack/CI/libraries/run_tempest.py b/testcases/VIM/OpenStack/CI/libraries/run_tempest.py new file mode 100644 index 000000000..e24697c76 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/libraries/run_tempest.py @@ -0,0 +1,260 @@ +#!/usr/bin/env python +# +# Description: +# Runs tempest and pushes the results to the DB +# +# Authors: +# morgan.richomme@orange.com +# jose.lausuch@ericsson.com +# + +import argparse +import json +import logging +import os +import re +import requests +import subprocess +import sys +import yaml +import keystoneclient.v2_0.client as ksclient +from neutronclient.v2_0 import client as neutronclient + +modes = ['full', 'smoke', 'baremetal', 'compute', 'data_processing', + 'identity', 'image', 'network', 'object_storage', 'orchestration', + 'telemetry', 'volume', 'custom'] + +""" tests configuration """ +parser = argparse.ArgumentParser() +parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") +parser.add_argument("-m", "--mode", help="Tempest test mode [smoke, all]", + default="smoke") +parser.add_argument("-r", "--report", + help="Create json result file", + action="store_true") + +args = parser.parse_args() + +""" logging configuration """ +logger = logging.getLogger('run_tempest') +logger.setLevel(logging.DEBUG) + +ch = logging.StreamHandler() +if args.debug: + ch.setLevel(logging.DEBUG) +else: + ch.setLevel(logging.INFO) + +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + +REPO_PATH=os.environ['repos_dir']+'/functest/' +if not os.path.exists(REPO_PATH): + logger.error("Functest repository directory not found '%s'" % REPO_PATH) + exit(-1) +sys.path.append(REPO_PATH + "testcases/") +import functest_utils + +with open("/home/opnfv/functest/conf/config_functest.yaml") as f: + functest_yaml = yaml.safe_load(f) +f.close() +TEST_DB = functest_yaml.get("results").get("test_db_url") + +MODE = "smoke" +TENANT_NAME = functest_yaml.get("tempest").get("identity").get("tenant_name") +TENANT_DESCRIPTION = functest_yaml.get("tempest").get("identity").get("tenant_description") +USER_NAME = functest_yaml.get("tempest").get("identity").get("user_name") +USER_PASSWORD = functest_yaml.get("tempest").get("identity").get("user_password") +DEPLOYMENT_MAME = functest_yaml.get("rally").get("deployment_name") +RALLY_INSTALLATION_DIR = functest_yaml.get("general").get("directories").get("dir_rally_inst") + + +def get_info(file_result): + test_run = "" + duration = "" + test_failed = "" + + p = subprocess.Popen('cat tempest.log', + shell=True, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + for line in p.stdout.readlines(): + # print line, + if (len(test_run) < 1): + test_run = re.findall("[0-9]*\.[0-9]*s", line) + if (len(duration) < 1): + duration = re.findall("[0-9]*\ tests", line) + regexp = r"(failures=[0-9]+)" + if (len(test_failed) < 1): + test_failed = re.findall(regexp, line) + + retval = p.wait() + + logger.debug("test_run:"+test_run) + logger.debug("duration:"+duration) + + +def push_results_to_db(payload, module, pod_name): + + # TODO move DB creds into config file + url = TEST_DB + "/results" + installer = functest_utils.get_installer_type(logger) + git_version = functest_utils.get_git_branch(REPO_PATH) + logger.info("Pushing results to DB: '%s'." % url) + + params = {"project_name": "functest", "case_name": "Tempest", + "pod_name": str(pod_name), 'installer': installer, + "version": git_version, 'details': payload} + headers = {'Content-Type': 'application/json'} + + r = requests.post(url, data=json.dumps(params), headers=headers) + logger.debug(r) + + +def create_tempest_resources(): + ks_creds = functest_utils.get_credentials("keystone") + logger.info("Creating tenant and user for Tempest suite") + keystone = ksclient.Client(**ks_creds) + tenant_id = functest_utils.create_tenant(keystone, TENANT_NAME, TENANT_DESCRIPTION) + if tenant_id == '': + logger.error("Error : Failed to create %s tenant" %TENANT_NAME) + + user_id = functest_utils.create_user(keystone, USER_NAME, USER_PASSWORD, None, tenant_id) + if user_id == '': + logger.error("Error : Failed to create %s user" %USER_NAME) + + +def free_tempest_resources(): + ks_creds = functest_utils.get_credentials("keystone") + logger.info("Deleting tenant and user for Tempest suite)") + keystone = ksclient.Client(**ks_creds) + + user_id = functest_utils.get_user_id(keystone, USER_NAME) + if user_id == '': + logger.error("Error : Failed to get id of %s user" % USER_NAME) + else: + if not functest_utils.delete_user(keystone, user_id): + logger.error("Error : Failed to delete %s user" % USER_NAME) + + tenant_id = functest_utils.get_tenant_id(keystone, TENANT_NAME) + if tenant_id == '': + logger.error("Error : Failed to get id of %s tenant" % TENANT_NAME) + else: + if not functest_utils.delete_tenant(keystone, tenant_id): + logger.error("Error : Failed to delete %s tenant" % TENANT_NAME) + + +def configure_tempest(): + """ + Add/update needed parameters into tempest.conf file generated by Rally + """ + + logger.debug("Generating tempest.conf file...") + cmd = "rally verify genconfig" + functest_utils.execute_command(cmd,logger) + + logger.debug("Resolving deployment UUID...") + cmd = "rally deployment list | awk '/"+DEPLOYMENT_MAME+"/ {print $2}'" + p = subprocess.Popen(cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT); + deployment_uuid = p.stdout.readline().rstrip() + if deployment_uuid == "": + logger.debug(" Rally deployment NOT found") + return False + + logger.debug("Finding tempest.conf file...") + tempest_conf_file = RALLY_INSTALLATION_DIR+"/tempest/for-deployment-" \ + +deployment_uuid+"/tempest.conf" + if tempest_conf_file == "": + logger.debug(" Tempest configuration file NOT found") + return False + + logger.debug(" Updating fixed_network_name...") + private_net_name = "" + creds_neutron = functest_utils.get_credentials("neutron") + neutron_client = neutronclient.Client(**creds_neutron) + private_net = functest_utils.get_private_net(neutron_client) + if private_net is None: + logger.error("No shared private networks found.") + else: + private_net_name = private_net['name'] + cmd = "crudini --set "+tempest_conf_file+" compute fixed_network_name " \ + +private_net_name + functest_utils.execute_command(cmd,logger) + + logger.debug(" Updating non-admin credentials...") + cmd = "crudini --set "+tempest_conf_file+" identity tenant_name " \ + +TENANT_NAME + functest_utils.execute_command(cmd,logger) + cmd = "crudini --set "+tempest_conf_file+" identity username " \ + +USER_NAME + functest_utils.execute_command(cmd,logger) + cmd = "crudini --set "+tempest_conf_file+" identity password " \ + +USER_PASSWORD + functest_utils.execute_command(cmd,logger) + + return True + + +def run_tempest(OPTION): + # + # the "main" function of the script which launches Rally to run Tempest + # :param option: tempest option (smoke, ..) + # :return: void + # + logger.info("Starting Tempest test suite: '%s'." % OPTION) + cmd_line = "rally verify start "+OPTION + logger.debug('Executing command : {}'.format(cmd_line)) + subprocess.call(cmd_line, shell=True, stderr=subprocess.STDOUT) + + cmd_line = "rally verify list" + logger.debug('Executing command : {}'.format(cmd_line)) + cmd = os.popen(cmd_line) + output = (((cmd.read()).splitlines()[3]).replace(" ", "")).split("|") + # Format: + # | UUID | Deployment UUID | smoke | tests | failures | Created at | + # Duration | Status | + num_tests = output[4] + num_failures = output[5] + time_start = output[6] + duration = output[7] + # Compute duration (lets assume it does not take more than 60 min) + dur_min=int(duration.split(':')[1]) + dur_sec_float=float(duration.split(':')[2]) + dur_sec_int=int(round(dur_sec_float,0)) + dur_sec_int = dur_sec_int + 60 * dur_min + + # Generate json results for DB + json_results = {"timestart": time_start, "duration": dur_sec_int, + "tests": int(num_tests), "failures": int(num_failures)} + logger.info("Results: "+str(json_results)) + pod_name = functest_utils.get_pod_name(logger) + + # Push results in payload of testcase + if args.report: + logger.debug("Push result into DB") + push_results_to_db(json_results, MODE, pod_name) + + +def main(): + global MODE + if not (args.mode): + MODE = "smoke" + elif not (args.mode in modes): + logger.error("Tempest mode not valid. Possible values are:\n" + + str(modes)) + exit(-1) + elif (args.mode == 'custom'): + MODE = "--tests-file "+REPO_PATH+"testcases/VIM/OpenStack/CI/custom_tests/test_list.txt" + else: + MODE = "--set "+args.mode + + create_tempest_resources() + configure_tempest() + run_tempest(MODE) + free_tempest_resources() + + +if __name__ == '__main__': + main() diff --git a/testcases/VIM/OpenStack/CI/libraries/test_openstack.sh b/testcases/VIM/OpenStack/CI/libraries/test_openstack.sh new file mode 100755 index 000000000..7225796c5 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/libraries/test_openstack.sh @@ -0,0 +1,111 @@ +# +# Script to test clean_openstack.py +# +# Author: +# jose.lausuch@ericsson.com +# + +if [ -z $OS_AUTH_URL ]; then + echo "Source credentials first" + exit 1 +fi + +echo "Using following credentials:" +env | grep OS + +################################# +echo "Creating keystone stuff.." +################################# +keystone tenant-create --name tenant_test1 +keystone tenant-create --name tenant_test2 +tenant1_id=$(keystone tenant-list | grep tenant_test1 | awk '{print $2}') +tenant2_id=$(keystone tenant-list | grep tenant_test2 | awk '{print $2}') +keystone user-create --name user_test11 --tenant $tenant1_id +keystone user-create --name user_test12 --tenant $tenant1_id +keystone user-create --name user_test13 --tenant $tenant1_id +keystone user-create --name user_test21 --tenant $tenant2_id +keystone user-create --name user_test22 --tenant $tenant2_id + + +################################# +echo "Creating glance stuff.." +################################# +wget http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img +glance image-create --name image_test1 --disk-format qcow2 --container-format bare < cirros-0.3.4-x86_64-disk.img +glance image-create --name image_test2 --disk-format qcow2 --container-format bare < cirros-0.3.4-x86_64-disk.img +#glance image-create --name test --visibility public --disk-format qcow2 --container-format bare --file cirros-0.3.4-x86_64-disk.img + + +################################# +echo "Creating cinder stuff.." +################################# +cinder create --display_name volume-test1 1 +cinder create --display_name volume-test2 2 + + +################################# +echo "Creating NEUTRON stuff.." +################################# +echo "1. Create Networks." +neutron net-create net-test1 +neutron net-create net-test2 + +echo "2. Create subnets." +neutron subnet-create --name subnet-test11 --allocation-pool start=10.7.0.2,end=10.7.0.253 --gateway 10.7.0.254 net-test1 10.7.0.0/24 +neutron subnet-create --name subnet-test21 --allocation-pool start=10.6.0.2,end=10.6.0.253 --gateway 10.6.0.254 net-test2 10.6.0.0/24 + +echo "3. Create Ports." +neutron port-create --name port-test11 --fixed-ip ip_address=10.7.0.10 net-test1 +neutron port-create --name port-test21 --fixed-ip ip_address=10.6.0.60 net-test2 + + +echo "4. Create Routers." +neutron router-create router-test1 +neutron router-create router-test2 +router1_id=$(neutron router-list | grep router-test1 | awk '{print $2}') +router1_id=$(neutron router-list | grep router-test2 | awk '{print $2}') + +neutron router-gateway-set router-test1 net04_ext +neutron router-gateway-set router-test2 net04_ext + +neutron router-interface-add router-test1 subnet-test11 +neutron router-interface-add router-test2 subnet-test21 + +echo "5. Floating IPs." +neutron floatingip-create net04_ext +neutron floatingip-create net04_ext +neutron floatingip-create net04_ext +neutron floatingip-create net04_ext + +floating_ip1_id=$(neutron floatingip-list | awk 'FNR == 4 {print}' | awk '{print $2}') +floating_ip2_id=$(neutron floatingip-list | awk 'FNR == 5 {print}' | awk '{print $2}') +floating_ip3_id=$(neutron floatingip-list | awk 'FNR == 6 {print}' | awk '{print $2}') +floating_ip4_id=$(neutron floatingip-list | awk 'FNR == 7 {print}' | awk '{print $2}') + +floating_ip1=$(neutron floatingip-list | awk 'FNR == 4 {print}' | awk '{print $5}') +floating_ip2=$(neutron floatingip-list | awk 'FNR == 5 {print}' | awk '{print $5}') +floating_ip3=$(neutron floatingip-list | awk 'FNR == 6 {print}' | awk '{print $5}') +floating_ip4=$(neutron floatingip-list | awk 'FNR == 7 {print}' | awk '{print $5}') + +################################# +echo "Creating NOVA stuff.." +################################# +net1_id=$(neutron net-list | grep net-test1 | awk '{print $2}') +net2_id=$(neutron net-list | grep net-test2 | awk '{print $2}') + +nova boot --flavor 2 --image image_test1 --nic net-id=$net1_id nova-test11 +nova boot --flavor 2 --image image_test1 --nic net-id=$net1_id nova-test12 +nova boot --flavor 2 --image image_test2 --nic net-id=$net2_id nova-test21 +nova boot --flavor 2 --image image_test2 --nic net-id=$net2_id nova-test22 + +vm1_id=$(nova list | grep nova-test11 | awk '{print $2}') +vm2_id=$(nova list | grep nova-test12 | awk '{print $2}') +vm3_id=$(nova list | grep nova-test21 | awk '{print $2}') +vm4_id=$(nova list | grep nova-test22 | awk '{print $2}') + +nova floating-ip-associate $vm1_id $floating_ip1 +nova floating-ip-associate $vm2_id $floating_ip2 +nova floating-ip-associate $vm3_id $floating_ip3 +nova floating-ip-associate $vm4_id $floating_ip4 + +#neutron floatingip-associate --fixed-ip-address $floating_ip2 <PORT> diff --git a/testcases/VIM/OpenStack/CI/rally_cert/macro/macro.yaml b/testcases/VIM/OpenStack/CI/rally_cert/macro/macro.yaml new file mode 100644 index 000000000..48c0333e9 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/macro/macro.yaml @@ -0,0 +1,97 @@ +{%- macro user_context(tenants,users_per_tenant, use_existing_users) -%} +{%- if use_existing_users and caller is not defined -%} {} +{%- else %} + {%- if not use_existing_users %} + users: + tenants: {{ tenants }} + users_per_tenant: {{ users_per_tenant }} + {%- endif %} + {%- if caller is defined %} + {{ caller() }} + {%- endif %} +{%- endif %} +{%- endmacro %} + +{%- macro vm_params(image=none, flavor=none, size=none) %} +{%- if flavor is not none %} + flavor: + name: {{ flavor }} +{%- endif %} +{%- if image is not none %} + image: + name: {{ image }} +{%- endif %} +{%- if size is not none %} + size: {{ size }} +{%- endif %} +{%- endmacro %} + +{%- macro unlimited_volumes() %} + cinder: + gigabytes: -1 + snapshots: -1 + volumes: -1 +{%- endmacro %} + +{%- macro constant_runner(concurrency=1, times=1, is_smoke=True) %} + type: "constant" + {%- if is_smoke %} + concurrency: 1 + times: 1 + {%- else %} + concurrency: {{ concurrency }} + times: {{ times }} + {%- endif %} +{%- endmacro %} + +{%- macro rps_runner(rps=1, times=1, is_smoke=True) %} + type: rps + {%- if is_smoke %} + rps: 1 + times: 1 + {%- else %} + rps: {{ rps }} + times: {{ times }} + {%- endif %} +{%- endmacro %} + +{%- macro no_failures_sla() %} + failure_rate: + max: 0 +{%- endmacro %} + +{%- macro volumes(size=1, volumes_per_tenant=1) %} + volumes: + size: {{ size }} + volumes_per_tenant: {{ volumes_per_tenant }} +{%- endmacro %} + +{%- macro unlimited_nova(keypairs=false) %} + nova: + cores: -1 + floating_ips: -1 + instances: -1 + {%- if keypairs %} + key_pairs: -1 + {%- endif %} + ram: -1 + security_group_rules: -1 + security_groups: -1 +{%- endmacro %} + +{%- macro unlimited_neutron(secgroups=false) %} + neutron: + network: -1 + port: -1 + subnet: -1 + {%- if secgroups %} + security_group: -1 + security_group_rule: -1 + {%- endif %} +{%- endmacro %} + +{%- macro glance_args(location, container="bare", type="qcow2") %} + container_format: {{ container }} + disk_format: {{ type }} + image_location: {{ location }} +{%- endmacro %} diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-authenticate.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-authenticate.yaml new file mode 100644 index 000000000..8d7f0e7cb --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-authenticate.yaml @@ -0,0 +1,63 @@ + Authenticate.keystone: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + Authenticate.validate_cinder: + - + args: + repetitions: 2 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + Authenticate.validate_glance: + - + args: + repetitions: 2 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + Authenticate.validate_heat: + - + args: + repetitions: 2 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + Authenticate.validate_neutron: + - + args: + repetitions: 2 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + Authenticate.validate_nova: + - + args: + repetitions: 2 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-cinder.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-cinder.yaml new file mode 100644 index 000000000..723db65ff --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-cinder.yaml @@ -0,0 +1,266 @@ + CinderVolumes.create_and_attach_volume: + - + args: + {{ vm_params(image_name,flavor_name,1) }} + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_and_delete_snapshot: + - + args: + force: false + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {{ volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_and_delete_volume: + - + args: + size: + max: 1 + min: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + {{ vm_params(image_name,none,1) }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + size: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_and_extend_volume: + - + args: + new_size: 2 + size: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_and_list_snapshots: + - + args: + detailed: true + force: false + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {{ volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_and_list_volume: + - + args: + detailed: true + {{ vm_params(image_name,none,1) }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + detailed: true + size: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_and_upload_volume_to_image: + - + args: + container_format: "bare" + disk_format: "raw" + do_delete: true + force: false + size: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_from_volume_and_delete_volume: + - + args: + size: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {{ volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_nested_snapshots_and_attach_volume: + - + args: + nested_level: 1 + size: + max: 1 + min: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + servers: + {{ vm_params(image_name,flavor_name,none)|indent(2,true) }} + servers_per_tenant: 1 + auto_assign_nic: true + network: {} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_snapshot_and_attach_volume: + - + args: + volume_type: false + size: + min: 1 + max: 5 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + servers: + {{ vm_params(image_name,flavor_name,none)|indent(2,true) }} + servers_per_tenant: 2 + auto_assign_nic: true + network: {} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + volume_type: true + size: + min: 1 + max: 5 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + servers: + {{ vm_params(image_name,flavor_name,none)|indent(2,true) }} + servers_per_tenant: 2 + auto_assign_nic: true + network: {} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.create_volume: + - + args: + size: 1 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + - + args: + size: + min: 1 + max: 5 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + CinderVolumes.list_volumes: + - + args: + detailed: True + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_volumes() }} + volumes: + size: 1 + volumes_per_tenant: 4 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-glance.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-glance.yaml new file mode 100644 index 000000000..b5eb7f3f5 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-glance.yaml @@ -0,0 +1,49 @@ + GlanceImages.create_and_delete_image: + - + args: + {{ glance_args(location=glance_image_location) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + GlanceImages.create_and_list_image: + - + args: + {{ glance_args(location=glance_image_location) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + GlanceImages.list_images: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + GlanceImages.create_image_and_boot_instances: + - + args: + {{ glance_args(location=glance_image_location) }} + flavor: + name: {{ flavor_name }} + number_instances: 2 + nics: + - net-id: {{ netid }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + quotas: + {{ unlimited_nova() }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-heat.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-heat.yaml new file mode 100644 index 000000000..6debb415a --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-heat.yaml @@ -0,0 +1,142 @@ + HeatStacks.create_and_delete_stack: + - + args: + template_path: "{{ tmpl_dir }}/default.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + template_path: "{{ tmpl_dir }}/server_with_ports.yaml.template" + parameters: + public_net: {{ floating_network }} + image: {{ image_name }} + flavor: {{ flavor_name }} + cidr: {{ floating_subnet_cidr }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + template_path: "{{ tmpl_dir }}/server_with_volume.yaml.template" + parameters: + image: {{ image_name }} + flavor: {{ flavor_name }} + network_id: {{ netid }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + HeatStacks.create_and_list_stack: + - + args: + template_path: "{{ tmpl_dir }}/default.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + HeatStacks.create_check_delete_stack: + - + args: + template_path: "{{ tmpl_dir }}/random_strings.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + HeatStacks.create_suspend_resume_delete_stack: + - + args: + template_path: "{{ tmpl_dir }}/random_strings.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + HeatStacks.create_update_delete_stack: + - + args: + template_path: "{{ tmpl_dir }}/random_strings.yaml.template" + updated_template_path: "{{ tmpl_dir }}/updated_random_strings_add.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + template_path: "{{ tmpl_dir }}/random_strings.yaml.template" + updated_template_path: "{{ tmpl_dir }}/updated_random_strings_delete.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + template_path: "{{ tmpl_dir }}/resource_group.yaml.template" + updated_template_path: "{{ tmpl_dir }}/updated_resource_group_increase.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + template_path: "{{ tmpl_dir }}/autoscaling_policy.yaml.template" + updated_template_path: "{{ tmpl_dir }}/updated_autoscaling_policy_inplace.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + template_path: "{{ tmpl_dir }}/resource_group.yaml.template" + updated_template_path: "{{ tmpl_dir }}/updated_resource_group_reduce.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + - + args: + template_path: "{{ tmpl_dir }}/random_strings.yaml.template" + updated_template_path: "{{ tmpl_dir }}/updated_random_strings_replace.yaml.template" + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + HeatStacks.list_stacks_and_resources: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-keystone.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-keystone.yaml new file mode 100644 index 000000000..50cbecff2 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-keystone.yaml @@ -0,0 +1,92 @@ + KeystoneBasic.add_and_remove_user_role: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.create_add_and_list_user_roles: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.create_and_list_tenants: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.create_and_delete_role: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.create_and_delete_service: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.get_entities: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.create_update_and_delete_tenant: + - + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.create_user: + - + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.create_tenant: + - + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.create_and_list_users: + - + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + KeystoneBasic.create_tenant_with_users: + - + args: + users_per_tenant: 10 + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-neutron.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-neutron.yaml new file mode 100644 index 000000000..152c748b3 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-neutron.yaml @@ -0,0 +1,240 @@ + NeutronNetworks.create_and_delete_networks: + - + args: + network_create_args: {} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + neutron: + network: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_delete_ports: + - + args: + network_create_args: {} + port_create_args: {} + ports_per_network: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + quotas: + neutron: + network: -1 + port: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_delete_routers: + - + args: + network_create_args: {} + router_create_args: {} + subnet_cidr_start: "1.1.0.0/30" + subnet_create_args: {} + subnets_per_network: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + quotas: + neutron: + network: -1 + subnet: -1 + port: -1 + router: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_delete_subnets: + - + args: + network_create_args: {} + subnet_cidr_start: "1.1.0.0/30" + subnet_create_args: {} + subnets_per_network: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + quotas: + neutron: + network: -1 + subnet: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_list_networks: + - + args: + network_create_args: {} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + neutron: + network: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_list_ports: + - + args: + network_create_args: {} + port_create_args: {} + ports_per_network: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + quotas: + neutron: + network: -1 + port: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_list_routers: + - + args: + network_create_args: {} + router_create_args: {} + subnet_cidr_start: "1.1.0.0/30" + subnet_create_args: {} + subnets_per_network: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + quotas: + neutron: + network: -1 + subnet: -1 + router: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_list_subnets: + - + args: + network_create_args: {} + subnet_cidr_start: "1.1.0.0/30" + subnet_create_args: {} + subnets_per_network: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + quotas: + neutron: + network: -1 + subnet: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_update_networks: + - + args: + network_create_args: {} + network_update_args: + admin_state_up: false + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + neutron: + network: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_update_ports: + - + args: + network_create_args: {} + port_create_args: {} + port_update_args: + admin_state_up: false + device_id: "dummy_id" + device_owner: "dummy_owner" + ports_per_network: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + quotas: + neutron: + network: -1 + port: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_update_routers: + - + args: + network_create_args: {} + router_create_args: {} + router_update_args: + admin_state_up: false + subnet_cidr_start: "1.1.0.0/30" + subnet_create_args: {} + subnets_per_network: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + quotas: + neutron: + network: -1 + subnet: -1 + port: -1 + router: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NeutronNetworks.create_and_update_subnets: + - + args: + network_create_args: {} + subnet_cidr_start: "1.4.0.0/16" + subnet_create_args: {} + subnet_update_args: + enable_dhcp: false + subnets_per_network: 1 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + quotas: + neutron: + network: -1 + subnet: -1 + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-nova.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-nova.yaml new file mode 100644 index 000000000..d4bddbd89 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-nova.yaml @@ -0,0 +1,369 @@ + NovaKeypair.boot_and_delete_server_with_keypair: + - + args: + {{ vm_params(image_name, flavor_name) }} + server_kwargs: + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: + networks_per_tenant: 1 + start_cidr: "100.1.0.0/25" + quotas: + {{ unlimited_neutron() }} + {{ unlimited_nova(keypairs=true) }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaKeypair.create_and_delete_keypair: + - + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_nova(keypairs=true) }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaKeypair.create_and_list_keypairs: + - + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_nova(keypairs=true) }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_and_bounce_server: + - + args: + actions: + - + hard_reboot: 1 + - + soft_reboot: 1 + - + stop_start: 1 + - + rescue_unrescue: 1 + {{ vm_params(image_name, flavor_name) }} + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: + networks_per_tenant: 1 + start_cidr: "100.1.0.0/25" + quotas: + {{ unlimited_neutron() }} + {{ unlimited_nova() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_and_delete_server: + - + args: + {{ vm_params(image_name, flavor_name) }} + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: + networks_per_tenant: 1 + start_cidr: "100.1.0.0/25" + quotas: + {{ unlimited_neutron() }} + {{ unlimited_nova() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_and_list_server: + - + args: + detailed: true + {{ vm_params(image_name, flavor_name) }} + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: + networks_per_tenant: 1 + start_cidr: "100.1.0.0/25" + quotas: + {{ unlimited_neutron() }} + {{ unlimited_nova() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_and_rebuild_server: + - + args: + {{ vm_params(flavor=flavor_name) }} + from_image: + name: {{ image_name }} + to_image: + name: {{ image_name }} + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: + networks_per_tenant: 1 + start_cidr: "100.1.0.0/25" + quotas: + {{ unlimited_neutron() }} + {{ unlimited_nova() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_server_from_volume_and_delete: + - + args: + {{ vm_params(image_name, flavor_name) }} + volume_size: 5 + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: + networks_per_tenant: 1 + start_cidr: "100.1.0.0/25" + quotas: + {{ unlimited_volumes() }} + {{ unlimited_neutron() }} + {{ unlimited_nova() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.pause_and_unpause_server: + - + args: + {{ vm_params(image_name, flavor_name) }} + force_delete: false + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: + networks_per_tenant: 1 + start_cidr: "100.1.0.0/25" + quotas: + {{ unlimited_neutron() }} + {{ unlimited_nova() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.snapshot_server: + - + args: + {{ vm_params(image_name, flavor_name) }} + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: + networks_per_tenant: 1 + start_cidr: "100.1.0.0/25" + quotas: + {{ unlimited_neutron() }} + {{ unlimited_nova() }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaSecGroup.boot_and_delete_server_with_secgroups: + - + args: + {{ vm_params(image_name, flavor_name) }} + security_group_count: 10 + rules_per_security_group: 10 + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: + start_cidr: "100.1.0.0/25" + quotas: + {{ unlimited_nova() }} + {{ unlimited_neutron(secgroups=true) }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_and_live_migrate_server: + - args: + {{ vm_params(image_name, flavor_name) }} + block_migration: false + nics: + - net-id: {{ netid }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_and_migrate_server: + - args: + {{ vm_params(image_name, flavor_name) }} + nics: + - net-id: {{ netid }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_server_from_volume: + - + args: + {{ vm_params(image_name, flavor_name) }} + volume_size: 10 + nics: + - net-id: {{ netid }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_server: + - + args: + {{ vm_params(image_name, flavor_name) }} + nics: + - net-id: {{ netid }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_server_attach_created_volume_and_live_migrate: + - + args: + {{ vm_params(image_name, flavor_name) }} + size: 10 + block_migration: false + boot_server_kwargs: + nics: + - net-id: {{ netid }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.boot_server_from_volume_and_live_migrate: + - args: + {{ vm_params(image_name, flavor_name) }} + block_migration: false + volume_size: 10 + force_delete: false + nics: + - net-id: {{ netid }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaSecGroup.create_and_delete_secgroups: + - + args: + security_group_count: 10 + rules_per_security_group: 10 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_neutron(secgroups=true) }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaSecGroup.create_and_list_secgroups: + - + args: + security_group_count: 10 + rules_per_security_group: 10 + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + quotas: + {{ unlimited_neutron(secgroups=true) }} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.list_servers: + - + args: + detailed: True + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + servers: + {{ vm_params(image_name,flavor_name,none)|indent(2,true) }} + servers_per_tenant: 2 + auto_assign_nic: true + network: {} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + NovaServers.resize_server: + - + args: + {{ vm_params(image_name, flavor_name) }} + to_flavor: + name: "m1.small" + confirm: true + force_delete: false + nics: + - net-id: {{ netid }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-quotas.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-quotas.yaml new file mode 100644 index 000000000..66fd2039d --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-quotas.yaml @@ -0,0 +1,54 @@ + Quotas.cinder_update_and_delete: + - + args: + max_quota: 1024 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + Quotas.cinder_update: + - + args: + max_quota: 1024 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + Quotas.neutron_update: + - + args: + max_quota: 1024 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + Quotas.nova_update_and_delete: + - + args: + max_quota: 1024 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + Quotas.nova_update: + - + args: + max_quota: 1024 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount,times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-requests.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-requests.yaml new file mode 100644 index 000000000..b7d2033f2 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-requests.yaml @@ -0,0 +1,28 @@ + HttpRequests.check_random_request: + - + args: + requests: + - + url: "http://www.example.com" + method: "GET" + status_code: 200 + - + url: "http://www.openstack.org" + method: "GET" + status_code: 200 + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + HttpRequests.check_request: + - + args: + url: "http://www.example.com" + method: "GET" + status_code: 200 + allow_redirects: False + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-smoke.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-smoke.yaml new file mode 100644 index 000000000..f102edb2b --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-smoke.yaml @@ -0,0 +1,268 @@ + TempestScenario.list_of_tests: + - + args: + tempest_conf: /etc/tempest/tempest.conf + test_names: + - tempest.api.compute.flavors.test_flavors.FlavorsV2TestJSON.test_get_flavor + - tempest.api.compute.flavors.test_flavors.FlavorsV2TestJSON.test_list_flavors + - tempest.api.compute.flavors.test_flavors.FlavorsV2TestJSON.test_list_flavors_with_detail + - tempest.api.compute.images.test_images_oneserver.ImagesOneServerTestJSON.test_create_delete_image + - tempest.api.compute.images.test_list_images.ListImagesTestJSON.test_get_image + - tempest.api.compute.images.test_list_images.ListImagesTestJSON.test_list_images + - tempest.api.compute.images.test_list_images.ListImagesTestJSON.test_list_images_with_detail + - tempest.api.compute.security_groups.test_security_group_rules.SecurityGroupRulesTestJSON.test_security_group_rules_create + - tempest.api.compute.security_groups.test_security_group_rules.SecurityGroupRulesTestJSON.test_security_group_rules_create_with_optional_cidr + - tempest.api.compute.security_groups.test_security_group_rules.SecurityGroupRulesTestJSON.test_security_group_rules_create_with_optional_group_id + - tempest.api.compute.security_groups.test_security_group_rules.SecurityGroupRulesTestJSON.test_security_group_rules_delete_when_peer_group_deleted + - tempest.api.compute.security_groups.test_security_group_rules.SecurityGroupRulesTestJSON.test_security_group_rules_list + - tempest.api.compute.security_groups.test_security_groups.SecurityGroupsTestJSON.test_security_group_create_get_delete + - tempest.api.compute.security_groups.test_security_groups.SecurityGroupsTestJSON.test_security_groups_create_list_delete + - tempest.api.compute.security_groups.test_security_groups.SecurityGroupsTestJSON.test_server_security_groups + - tempest.api.compute.security_groups.test_security_groups.SecurityGroupsTestJSON.test_update_security_groups + - tempest.api.compute.servers.test_attach_interfaces.AttachInterfacesTestJSON.test_add_remove_fixed_ip + - tempest.api.compute.servers.test_attach_interfaces.AttachInterfacesTestJSON.test_create_list_show_delete_interfaces + - tempest.api.compute.servers.test_create_server.ServersTestJSON.test_list_servers + - tempest.api.compute.servers.test_create_server.ServersTestJSON.test_list_servers_with_detail + - tempest.api.compute.servers.test_create_server.ServersTestJSON.test_verify_server_details + - tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_list_servers + - tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_list_servers_with_detail + - tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_verify_server_details + - tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_reboot_server_hard + - tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_reboot_server_soft + - tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_rebuild_server + - tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_resize_server_confirm + - tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_resize_server_confirm_from_stopped + - tempest.api.compute.servers.test_server_addresses.ServerAddressesTestJSON.test_list_server_addresses + - tempest.api.compute.servers.test_server_addresses.ServerAddressesTestJSON.test_list_server_addresses_by_network + - tempest.api.compute.servers.test_server_rescue.ServerRescueTestJSON.test_rescue_unrescue_instance + - tempest.api.compute.test_quotas.QuotasTestJSON.test_compare_tenant_quotas_with_default_quotas + - tempest.api.compute.test_quotas.QuotasTestJSON.test_get_default_quotas + - tempest.api.compute.test_quotas.QuotasTestJSON.test_get_quotas + - tempest.api.compute.volumes.test_volumes_get.VolumesGetTestJSON.test_volume_create_get_delete + - tempest.api.data_processing.test_cluster_templates.ClusterTemplateTest.test_cluster_template_create + - tempest.api.data_processing.test_cluster_templates.ClusterTemplateTest.test_cluster_template_delete + - tempest.api.data_processing.test_cluster_templates.ClusterTemplateTest.test_cluster_template_get + - tempest.api.data_processing.test_cluster_templates.ClusterTemplateTest.test_cluster_template_list + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_external_hdfs_data_source_create + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_external_hdfs_data_source_delete + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_external_hdfs_data_source_get + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_external_hdfs_data_source_list + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_local_hdfs_data_source_create + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_local_hdfs_data_source_delete + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_local_hdfs_data_source_get + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_local_hdfs_data_source_list + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_swift_data_source_create + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_swift_data_source_delete + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_swift_data_source_get + - tempest.api.data_processing.test_data_sources.DataSourceTest.test_swift_data_source_list + - tempest.api.data_processing.test_job_binaries.JobBinaryTest.test_internal_db_job_binary_create + - tempest.api.data_processing.test_job_binaries.JobBinaryTest.test_internal_db_job_binary_delete + - tempest.api.data_processing.test_job_binaries.JobBinaryTest.test_internal_db_job_binary_get + - tempest.api.data_processing.test_job_binaries.JobBinaryTest.test_internal_db_job_binary_list + - tempest.api.data_processing.test_job_binaries.JobBinaryTest.test_job_binary_get_data + - tempest.api.data_processing.test_job_binaries.JobBinaryTest.test_swift_job_binary_create + - tempest.api.data_processing.test_job_binaries.JobBinaryTest.test_swift_job_binary_delete + - tempest.api.data_processing.test_job_binaries.JobBinaryTest.test_swift_job_binary_get + - tempest.api.data_processing.test_job_binaries.JobBinaryTest.test_swift_job_binary_list + - tempest.api.data_processing.test_job_binary_internals.JobBinaryInternalTest.test_job_binary_internal_create + - tempest.api.data_processing.test_job_binary_internals.JobBinaryInternalTest.test_job_binary_internal_delete + - tempest.api.data_processing.test_job_binary_internals.JobBinaryInternalTest.test_job_binary_internal_get + - tempest.api.data_processing.test_job_binary_internals.JobBinaryInternalTest.test_job_binary_internal_get_data + - tempest.api.data_processing.test_job_binary_internals.JobBinaryInternalTest.test_job_binary_internal_list + - tempest.api.data_processing.test_jobs.JobTest.test_job_create + - tempest.api.data_processing.test_jobs.JobTest.test_job_delete + - tempest.api.data_processing.test_jobs.JobTest.test_job_get + - tempest.api.data_processing.test_jobs.JobTest.test_job_list + - tempest.api.data_processing.test_node_group_templates.NodeGroupTemplateTest.test_node_group_template_create + - tempest.api.data_processing.test_node_group_templates.NodeGroupTemplateTest.test_node_group_template_delete + - tempest.api.data_processing.test_node_group_templates.NodeGroupTemplateTest.test_node_group_template_get + - tempest.api.data_processing.test_node_group_templates.NodeGroupTemplateTest.test_node_group_template_list + - tempest.api.data_processing.test_plugins.PluginsTest.test_plugin_get + - tempest.api.data_processing.test_plugins.PluginsTest.test_plugin_list + - tempest.api.database.flavors.test_flavors.DatabaseFlavorsTest.test_compare_db_flavors_with_os + - tempest.api.database.flavors.test_flavors.DatabaseFlavorsTest.test_get_db_flavor + - tempest.api.database.flavors.test_flavors.DatabaseFlavorsTest.test_list_db_flavors + - tempest.api.database.limits.test_limits.DatabaseLimitsTest.test_absolute_limits + - tempest.api.database.versions.test_versions.DatabaseVersionsTest.test_list_db_versions + - tempest.api.identity.admin.v2.test_services.ServicesTestJSON.test_list_services + - tempest.api.identity.admin.v2.test_users.UsersTestJSON.test_create_user + - tempest.api.identity.admin.v3.test_credentials.CredentialsTestJSON.test_credentials_create_get_update_delete + - tempest.api.identity.admin.v3.test_domains.DomainsTestJSON.test_create_update_delete_domain + - tempest.api.identity.admin.v3.test_endpoints.EndPointsTestJSON.test_update_endpoint + - tempest.api.identity.admin.v3.test_groups.GroupsV3TestJSON.test_group_users_add_list_delete + - tempest.api.identity.admin.v3.test_policies.PoliciesTestJSON.test_create_update_delete_policy + - tempest.api.identity.admin.v3.test_regions.RegionsTestJSON.test_create_region_with_specific_id + - tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_role_create_update_get_list + - tempest.api.identity.admin.v3.test_services.ServicesTestJSON.test_create_update_get_service + - tempest.api.identity.admin.v3.test_trusts.TrustsV3TestJSON.test_get_trusts_all + - tempest.api.messaging.test_claims.TestClaims.test_post_claim + - tempest.api.messaging.test_claims.TestClaims.test_query_claim + - tempest.api.messaging.test_claims.TestClaims.test_release_claim + - tempest.api.messaging.test_claims.TestClaims.test_update_claim + - tempest.api.messaging.test_messages.TestMessages.test_delete_multiple_messages + - tempest.api.messaging.test_messages.TestMessages.test_delete_single_message + - tempest.api.messaging.test_messages.TestMessages.test_get_message + - tempest.api.messaging.test_messages.TestMessages.test_get_multiple_messages + - tempest.api.messaging.test_messages.TestMessages.test_list_messages + - tempest.api.messaging.test_messages.TestMessages.test_post_messages + - tempest.api.messaging.test_queues.TestManageQueue.test_check_queue_existence + - tempest.api.messaging.test_queues.TestManageQueue.test_check_queue_head + - tempest.api.messaging.test_queues.TestManageQueue.test_get_queue_stats + - tempest.api.messaging.test_queues.TestManageQueue.test_list_queues + - tempest.api.messaging.test_queues.TestManageQueue.test_set_and_get_queue_metadata + - tempest.api.messaging.test_queues.TestQueues.test_create_delete_queue + - tempest.api.network.test_extensions.ExtensionsTestJSON.test_list_show_extensions + - tempest.api.network.test_floating_ips.FloatingIPTestJSON.test_create_floating_ip_specifying_a_fixed_ip_address + - tempest.api.network.test_floating_ips.FloatingIPTestJSON.test_create_list_show_update_delete_floating_ip + - tempest.api.network.test_networks.BulkNetworkOpsIpV6TestJSON.test_bulk_create_delete_network + - tempest.api.network.test_networks.BulkNetworkOpsIpV6TestJSON.test_bulk_create_delete_port + - tempest.api.network.test_networks.BulkNetworkOpsIpV6TestJSON.test_bulk_create_delete_subnet + - tempest.api.network.test_networks.BulkNetworkOpsTestJSON.test_bulk_create_delete_network + - tempest.api.network.test_networks.BulkNetworkOpsTestJSON.test_bulk_create_delete_port + - tempest.api.network.test_networks.BulkNetworkOpsTestJSON.test_bulk_create_delete_subnet + - tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_create_update_delete_network_subnet + - tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_external_network_visibility + - tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_list_networks + - tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_list_subnets + - tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_show_network + - tempest.api.network.test_networks.NetworksIpV6TestAttrs.test_show_subnet + - tempest.api.network.test_networks.NetworksIpV6TestJSON.test_create_update_delete_network_subnet + - tempest.api.network.test_networks.NetworksIpV6TestJSON.test_external_network_visibility + - tempest.api.network.test_networks.NetworksIpV6TestJSON.test_list_networks + - tempest.api.network.test_networks.NetworksIpV6TestJSON.test_list_subnets + - tempest.api.network.test_networks.NetworksIpV6TestJSON.test_show_network + - tempest.api.network.test_networks.NetworksIpV6TestJSON.test_show_subnet + - tempest.api.network.test_networks.NetworksTestJSON.test_create_update_delete_network_subnet + - tempest.api.network.test_networks.NetworksTestJSON.test_external_network_visibility + - tempest.api.network.test_networks.NetworksTestJSON.test_list_networks + - tempest.api.network.test_networks.NetworksTestJSON.test_list_subnets + - tempest.api.network.test_networks.NetworksTestJSON.test_show_network + - tempest.api.network.test_networks.NetworksTestJSON.test_show_subnet + - tempest.api.network.test_ports.PortsIpV6TestJSON.test_create_port_in_allowed_allocation_pools + - tempest.api.network.test_ports.PortsIpV6TestJSON.test_create_port_with_no_securitygroups + - tempest.api.network.test_ports.PortsIpV6TestJSON.test_create_update_delete_port + - tempest.api.network.test_ports.PortsIpV6TestJSON.test_list_ports + - tempest.api.network.test_ports.PortsIpV6TestJSON.test_show_port + - tempest.api.network.test_ports.PortsTestJSON.test_create_port_in_allowed_allocation_pools + - tempest.api.network.test_ports.PortsTestJSON.test_create_port_with_no_securitygroups + - tempest.api.network.test_ports.PortsTestJSON.test_create_update_delete_port + - tempest.api.network.test_ports.PortsTestJSON.test_list_ports + - tempest.api.network.test_ports.PortsTestJSON.test_show_port + - tempest.api.network.test_routers.RoutersIpV6Test.test_add_multiple_router_interfaces + - tempest.api.network.test_routers.RoutersIpV6Test.test_add_remove_router_interface_with_port_id + - tempest.api.network.test_routers.RoutersIpV6Test.test_add_remove_router_interface_with_subnet_id + - tempest.api.network.test_routers.RoutersIpV6Test.test_create_show_list_update_delete_router + - tempest.api.network.test_routers.RoutersTest.test_add_multiple_router_interfaces + - tempest.api.network.test_routers.RoutersTest.test_add_remove_router_interface_with_port_id + - tempest.api.network.test_routers.RoutersTest.test_add_remove_router_interface_with_subnet_id + - tempest.api.network.test_routers.RoutersTest.test_create_show_list_update_delete_router + - tempest.api.network.test_security_groups.SecGroupIPv6Test.test_create_list_update_show_delete_security_group + - tempest.api.network.test_security_groups.SecGroupIPv6Test.test_create_show_delete_security_group_rule + - tempest.api.network.test_security_groups.SecGroupIPv6Test.test_list_security_groups + - tempest.api.network.test_security_groups.SecGroupTest.test_create_list_update_show_delete_security_group + - tempest.api.network.test_security_groups.SecGroupTest.test_create_show_delete_security_group_rule + - tempest.api.network.test_security_groups.SecGroupTest.test_list_security_groups + - tempest.api.object_storage.test_account_quotas.AccountQuotasTest.test_admin_modify_quota + - tempest.api.object_storage.test_account_quotas.AccountQuotasTest.test_upload_valid_object + - tempest.api.object_storage.test_account_services.AccountTest.test_list_account_metadata + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers_with_end_marker + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers_with_format_json + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers_with_format_xml + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers_with_limit + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers_with_limit_and_end_marker + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers_with_limit_and_marker + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers_with_limit_and_marker_and_end_marker + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers_with_marker + - tempest.api.object_storage.test_account_services.AccountTest.test_list_containers_with_marker_and_end_marker + - tempest.api.object_storage.test_account_services.AccountTest.test_list_extensions + - tempest.api.object_storage.test_account_services.AccountTest.test_list_no_account_metadata + - tempest.api.object_storage.test_account_services.AccountTest.test_list_no_containers + - tempest.api.object_storage.test_account_services.AccountTest.test_update_account_metadata_with_create_and_delete_metadata + - tempest.api.object_storage.test_account_services.AccountTest.test_update_account_metadata_with_create_matadata_key + - tempest.api.object_storage.test_account_services.AccountTest.test_update_account_metadata_with_create_metadata + - tempest.api.object_storage.test_account_services.AccountTest.test_update_account_metadata_with_delete_matadata + - tempest.api.object_storage.test_account_services.AccountTest.test_update_account_metadata_with_delete_matadata_key + - tempest.api.object_storage.test_container_acl.ObjectTestACLs.test_read_object_with_rights + - tempest.api.object_storage.test_container_acl.ObjectTestACLs.test_write_object_with_rights + - tempest.api.object_storage.test_container_quotas.ContainerQuotasTest.test_upload_large_object + - tempest.api.object_storage.test_container_quotas.ContainerQuotasTest.test_upload_too_many_objects + - tempest.api.object_storage.test_container_quotas.ContainerQuotasTest.test_upload_valid_object + - tempest.api.object_storage.test_container_services.ContainerTest.test_create_container + - tempest.api.object_storage.test_container_services.ContainerTest.test_create_container_overwrite + - tempest.api.object_storage.test_container_services.ContainerTest.test_create_container_with_metadata_key + - tempest.api.object_storage.test_container_services.ContainerTest.test_create_container_with_metadata_value + - tempest.api.object_storage.test_container_services.ContainerTest.test_create_container_with_remove_metadata_key + - tempest.api.object_storage.test_container_services.ContainerTest.test_create_container_with_remove_metadata_value + - tempest.api.object_storage.test_container_services.ContainerTest.test_delete_container + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents_with_delimiter + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents_with_end_marker + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents_with_format_json + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents_with_format_xml + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents_with_limit + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents_with_marker + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents_with_no_object + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents_with_path + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_contents_with_prefix + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_container_metadata + - tempest.api.object_storage.test_container_services.ContainerTest.test_list_no_container_metadata + - tempest.api.object_storage.test_container_services.ContainerTest.test_update_container_metadata_with_create_and_delete_matadata + - tempest.api.object_storage.test_container_services.ContainerTest.test_update_container_metadata_with_create_matadata_key + - tempest.api.object_storage.test_container_services.ContainerTest.test_update_container_metadata_with_create_metadata + - tempest.api.object_storage.test_container_services.ContainerTest.test_update_container_metadata_with_delete_metadata + - tempest.api.object_storage.test_container_services.ContainerTest.test_update_container_metadata_with_delete_metadata_key + - tempest.api.object_storage.test_object_services.ObjectTest.test_copy_object_2d_way + - tempest.api.object_storage.test_object_services.ObjectTest.test_copy_object_across_containers + - tempest.api.object_storage.test_object_services.ObjectTest.test_copy_object_in_same_container + - tempest.api.object_storage.test_object_services.ObjectTest.test_copy_object_to_itself + - tempest.api.object_storage.test_object_services.ObjectTest.test_copy_object_with_x_fresh_metadata + - tempest.api.object_storage.test_object_services.ObjectTest.test_copy_object_with_x_object_meta + - tempest.api.object_storage.test_object_services.ObjectTest.test_copy_object_with_x_object_metakey + - tempest.api.object_storage.test_object_services.ObjectTest.test_get_object + - tempest.api.object_storage.test_object_services.ObjectTest.test_get_object_with_if_match + - tempest.api.object_storage.test_object_services.ObjectTest.test_get_object_with_if_modified_since + - tempest.api.object_storage.test_object_services.ObjectTest.test_get_object_with_if_unmodified_since + - tempest.api.object_storage.test_object_services.ObjectTest.test_get_object_with_metadata + - tempest.api.object_storage.test_object_services.ObjectTest.test_get_object_with_range + - tempest.api.object_storage.test_object_services.ObjectTest.test_get_object_with_x_newest + - tempest.api.object_storage.test_object_services.ObjectTest.test_get_object_with_x_object_manifest + - tempest.api.object_storage.test_object_services.ObjectTest.test_list_no_object_metadata + - tempest.api.object_storage.test_object_services.ObjectTest.test_list_object_metadata + - tempest.api.object_storage.test_object_services.ObjectTest.test_list_object_metadata_with_x_object_manifest + - tempest.api.object_storage.test_object_services.ObjectTest.test_update_object_metadata + - tempest.api.object_storage.test_object_services.ObjectTest.test_update_object_metadata_with_create_and_remove_metadata + - tempest.api.object_storage.test_object_services.ObjectTest.test_update_object_metadata_with_x_object_manifest + - tempest.api.object_storage.test_object_services.ObjectTest.test_update_object_metadata_with_x_remove_object_metakey + - tempest.api.object_storage.test_object_services.PublicObjectTest.test_access_public_container_object_without_using_creds + - tempest.api.object_storage.test_object_services.PublicObjectTest.test_access_public_object_with_another_user_creds + - tempest.api.object_storage.test_object_version.ContainerTest.test_versioned_container + - tempest.api.orchestration.stacks.test_resource_types.ResourceTypesTest.test_resource_type_list + - tempest.api.orchestration.stacks.test_resource_types.ResourceTypesTest.test_resource_type_show + - tempest.api.orchestration.stacks.test_resource_types.ResourceTypesTest.test_resource_type_template + - tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_get_deployment_list + - tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_get_deployment_metadata + - tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_get_software_config + - tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_software_deployment_create_validate + - tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_software_deployment_update_no_metadata_change + - tempest.api.orchestration.stacks.test_soft_conf.TestSoftwareConfig.test_software_deployment_update_with_metadata_change + - tempest.api.orchestration.stacks.test_stacks.StacksTestJSON.test_stack_crud_no_resources + - tempest.api.orchestration.stacks.test_stacks.StacksTestJSON.test_stack_list_responds + - tempest.api.telemetry.test_telemetry_notification_api.TelemetryNotificationAPITestJSON.test_check_glance_v1_notifications + - tempest.api.telemetry.test_telemetry_notification_api.TelemetryNotificationAPITestJSON.test_check_glance_v2_notifications + - tempest.api.volume.test_volumes_actions.VolumesV1ActionsTest.test_attach_detach_volume_to_instance + - tempest.api.volume.test_volumes_actions.VolumesV2ActionsTest.test_attach_detach_volume_to_instance + - tempest.api.volume.test_volumes_get.VolumesV1GetTest.test_volume_create_get_update_delete + - tempest.api.volume.test_volumes_get.VolumesV1GetTest.test_volume_create_get_update_delete_from_image + - tempest.api.volume.test_volumes_get.VolumesV2GetTest.test_volume_create_get_update_delete + - tempest.api.volume.test_volumes_get.VolumesV2GetTest.test_volume_create_get_update_delete_from_image + - tempest.api.volume.test_volumes_list.VolumesV1ListTestJSON.test_volume_list + - tempest.api.volume.test_volumes_list.VolumesV2ListTestJSON.test_volume_list + runner: + concurrency: 1 + times: 1 + type: serial + sla: + failure_rate: + max: 0 + diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-vm.yaml b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-vm.yaml new file mode 100644 index 000000000..17ce20ce1 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/opnfv-vm.yaml @@ -0,0 +1,42 @@ + VMTasks.boot_runcommand_delete: + - + args: + {{ vm_params(image_name, flavor_name) }} + floating_network: {{ floating_network }} + force_delete: false + command: + interpreter: /bin/sh + script_file: {{ sup_dir }}/instance_dd_test.sh + username: cirros + nics: + - net-id: {{ netid }} + context: + {% call user_context(tenants_amount, users_amount, use_existing_users) %} + network: {} + {% endcall %} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} + + - + args: + {{ vm_params(image_name, flavor_name) }} + fixed_network: private + floating_network: {{ floating_network }} + force_delete: false + command: + interpreter: /bin/sh + script_file: {{ sup_dir }}/instance_dd_test.sh + use_floatingip: true + username: cirros + nics: + - net-id: {{ netid }} + volume_args: + size: 2 + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + runner: + {{ constant_runner(concurrency=2*controllers_amount, times=10*controllers_amount, is_smoke=smoke) }} + sla: + {{ no_failures_sla() }} diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/support/instance_dd_test.sh b/testcases/VIM/OpenStack/CI/rally_cert/scenario/support/instance_dd_test.sh new file mode 100644 index 000000000..e3bf23405 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/support/instance_dd_test.sh @@ -0,0 +1,13 @@ +#!/bin/sh +time_seconds(){ (time -p $1 ) 2>&1 |awk '/real/{print $2}'; } +file=/tmp/test.img +c=${1:-$SIZE} +c=${c:-1000} #default is 1GB +write_seq=$(time_seconds "dd if=/dev/zero of=$file bs=1M count=$c") +read_seq=$(time_seconds "dd if=$file of=/dev/null bs=1M count=$c") +[ -f $file ] && rm $file + +echo "{ + \"write_seq_${c}m\": $write_seq, + \"read_seq_${c}m\": $read_seq + }" diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/autoscaling_policy.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/autoscaling_policy.yaml.template new file mode 100644 index 000000000..a22487e33 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/autoscaling_policy.yaml.template @@ -0,0 +1,17 @@ +heat_template_version: 2013-05-23 + +resources: + test_group: + type: OS::Heat::AutoScalingGroup + properties: + desired_capacity: 0 + max_size: 0 + min_size: 0 + resource: + type: OS::Heat::RandomString + test_policy: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: { get_resource: test_group } + scaling_adjustment: 1
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/default.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/default.yaml.template new file mode 100644 index 000000000..eb4f2f2dd --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/default.yaml.template @@ -0,0 +1 @@ +heat_template_version: 2014-10-16
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/random_strings.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/random_strings.yaml.template new file mode 100644 index 000000000..2dd676c11 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/random_strings.yaml.template @@ -0,0 +1,13 @@ +heat_template_version: 2014-10-16 + +description: Test template for rally create-update-delete scenario + +resources: + test_string_one: + type: OS::Heat::RandomString + properties: + length: 20 + test_string_two: + type: OS::Heat::RandomString + properties: + length: 20
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/resource_group.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/resource_group.yaml.template new file mode 100644 index 000000000..b3f505fa6 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/resource_group.yaml.template @@ -0,0 +1,13 @@ +heat_template_version: 2014-10-16 + +description: Test template for rally create-update-delete scenario + +resources: + test_group: + type: OS::Heat::ResourceGroup + properties: + count: 2 + resource_def: + type: OS::Heat::RandomString + properties: + length: 20
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/server_with_ports.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/server_with_ports.yaml.template new file mode 100644 index 000000000..909f45d21 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/server_with_ports.yaml.template @@ -0,0 +1,64 @@ +heat_template_version: 2013-05-23 + +parameters: + # set all correct defaults for parameters before launch test + public_net: + type: string + default: public + image: + type: string + default: cirros-0.3.4-x86_64-uec + flavor: + type: string + default: m1.tiny + cidr: + type: string + default: 11.11.11.0/24 + +resources: + server: + type: OS::Nova::Server + properties: + image: {get_param: image} + flavor: {get_param: flavor} + networks: + - port: { get_resource: server_port } + + router: + type: OS::Neutron::Router + properties: + external_gateway_info: + network: {get_param: public_net} + + router_interface: + type: OS::Neutron::RouterInterface + properties: + router_id: { get_resource: router } + subnet_id: { get_resource: private_subnet } + + private_net: + type: OS::Neutron::Net + + private_subnet: + type: OS::Neutron::Subnet + properties: + network: { get_resource: private_net } + cidr: {get_param: cidr} + + port_security_group: + type: OS::Neutron::SecurityGroup + properties: + name: default_port_security_group + description: > + Default security group assigned to port. The neutron default group is not + used because neutron creates several groups with the same name=default and + nova cannot chooses which one should it use. + + server_port: + type: OS::Neutron::Port + properties: + network: {get_resource: private_net} + fixed_ips: + - subnet: { get_resource: private_subnet } + security_groups: + - { get_resource: port_security_group } diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/server_with_volume.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/server_with_volume.yaml.template new file mode 100644 index 000000000..826ca9dae --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/server_with_volume.yaml.template @@ -0,0 +1,43 @@ +heat_template_version: 2013-05-23 + +parameters: + # set all correct defaults for parameters before launch test + image: + type: string + default: cirros-0.3.4-x86_64-uec + flavor: + type: string + default: m1.tiny + availability_zone: + type: string + description: The Availability Zone to launch the instance. + default: nova + volume_size: + type: number + description: Size of the volume to be created. + default: 1 + constraints: + - range: { min: 1, max: 1024 } + description: must be between 1 and 1024 Gb. + network_id: + type: string + +resources: + server: + type: OS::Nova::Server + properties: + image: {get_param: image} + flavor: {get_param: flavor} + networks: + - network: { get_param: network_id } + cinder_volume: + type: OS::Cinder::Volume + properties: + size: { get_param: volume_size } + availability_zone: { get_param: availability_zone } + volume_attachment: + type: OS::Cinder::VolumeAttachment + properties: + volume_id: { get_resource: cinder_volume } + instance_uuid: { get_resource: server} + mountpoint: /dev/vdc diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_autoscaling_policy_inplace.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_autoscaling_policy_inplace.yaml.template new file mode 100644 index 000000000..cf34879ca --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_autoscaling_policy_inplace.yaml.template @@ -0,0 +1,23 @@ +heat_template_version: 2013-05-23 + +description: > + Test template for create-update-delete-stack scenario in rally. + The template updates resource parameters without resource re-creation(replacement) + in the stack defined by autoscaling_policy.yaml.template. It allows to measure + performance of "pure" resource update operation only. + +resources: + test_group: + type: OS::Heat::AutoScalingGroup + properties: + desired_capacity: 0 + max_size: 0 + min_size: 0 + resource: + type: OS::Heat::RandomString + test_policy: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: { get_resource: test_group } + scaling_adjustment: -1
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_random_strings_add.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_random_strings_add.yaml.template new file mode 100644 index 000000000..e06d42e01 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_random_strings_add.yaml.template @@ -0,0 +1,19 @@ +heat_template_version: 2014-10-16 + +description: > + Test template for create-update-delete-stack scenario in rally. + The template updates the stack defined by random_strings.yaml.template with additional resource. + +resources: + test_string_one: + type: OS::Heat::RandomString + properties: + length: 20 + test_string_two: + type: OS::Heat::RandomString + properties: + length: 20 + test_string_three: + type: OS::Heat::RandomString + properties: + length: 20
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_random_strings_delete.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_random_strings_delete.yaml.template new file mode 100644 index 000000000..d02593e3b --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_random_strings_delete.yaml.template @@ -0,0 +1,11 @@ +heat_template_version: 2014-10-16 + +description: > + Test template for create-update-delete-stack scenario in rally. + The template deletes one resource from the stack defined by random_strings.yaml.template. + +resources: + test_string_one: + type: OS::Heat::RandomString + properties: + length: 20
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_random_strings_replace.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_random_strings_replace.yaml.template new file mode 100644 index 000000000..46d8bff4c --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_random_strings_replace.yaml.template @@ -0,0 +1,19 @@ +heat_template_version: 2014-10-16 + +description: > + Test template for create-update-delete-stack scenario in rally. + The template deletes one resource from the stack defined by + random_strings.yaml.template and re-creates it with the updated parameters + (so-called update-replace). That happens because some parameters cannot be + changed without resource re-creation. The template allows to measure performance + of update-replace operation. + +resources: + test_string_one: + type: OS::Heat::RandomString + properties: + length: 20 + test_string_two: + type: OS::Heat::RandomString + properties: + length: 40
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_resource_group_increase.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_resource_group_increase.yaml.template new file mode 100644 index 000000000..891074ebc --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_resource_group_increase.yaml.template @@ -0,0 +1,16 @@ +heat_template_version: 2014-10-16 + +description: > + Test template for create-update-delete-stack scenario in rally. + The template updates one resource from the stack defined by resource_group.yaml.template + and adds children resources to that resource. + +resources: + test_group: + type: OS::Heat::ResourceGroup + properties: + count: 3 + resource_def: + type: OS::Heat::RandomString + properties: + length: 20
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_resource_group_reduce.yaml.template b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_resource_group_reduce.yaml.template new file mode 100644 index 000000000..b4d1d1730 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/scenario/templates/updated_resource_group_reduce.yaml.template @@ -0,0 +1,16 @@ +heat_template_version: 2014-10-16 + +description: > + Test template for create-update-delete-stack scenario in rally. + The template updates one resource from the stack defined by resource_group.yaml.template + and deletes children resources from that resource. + +resources: + test_group: + type: OS::Heat::ResourceGroup + properties: + count: 1 + resource_def: + type: OS::Heat::RandomString + properties: + length: 20
\ No newline at end of file diff --git a/testcases/VIM/OpenStack/CI/rally_cert/task.yaml b/testcases/VIM/OpenStack/CI/rally_cert/task.yaml new file mode 100644 index 000000000..299421ac5 --- /dev/null +++ b/testcases/VIM/OpenStack/CI/rally_cert/task.yaml @@ -0,0 +1,59 @@ +{%- set glance_image_location = glance_image_location|default("http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img") %} +{%- set image_name = image_name|default("functest-img-rally") %} +{%- set flavor_name = flavor_name|default("m1.tiny") %} +{%- set use_existing_users = use_existing_users|default(false) %} +{%- set service_list = service_list|default(["authenticate", "cinder", "keystone", "nova", "glance", "neutron", "quotas", "requests", "heat", "vm"]) %} +{%- set smoke = smoke|default(true) %} +{%- set floating_network = floating_network|default("net04_ext") %} +{%- set controllers_amount = controllers_amount|default(1) %} +{%- if smoke %} +{%- set users_amount = 1 %} +{%- set tenants_amount = 1 %} +{%- else %} +{%- set users_amount = users_amount|default(1) %} +{%- set tenants_amount = tenants_amount|default(1) %} +{%- endif %} + +{%- from "macro/macro.yaml" import user_context, vm_params, unlimited_volumes, constant_runner, rps_runner, no_failures_sla -%} +{%- from "macro/macro.yaml" import volumes, unlimited_nova, unlimited_neutron, glance_args -%} + +--- +{% if "authenticate" in service_list %} +{%- include "scenario/opnfv-authenticate.yaml"-%} +{% endif %} + +{% if "cinder" in service_list %} +{%- include "scenario/opnfv-cinder.yaml"-%} +{% endif %} + +{% if "keystone" in service_list %} +{%- include "scenario/opnfv-keystone.yaml"-%} +{% endif %} + +{% if "nova" in service_list %} +{%- include "scenario/opnfv-nova.yaml"-%} +{% endif %} + +{% if "glance" in service_list %} +{%- include "scenario/opnfv-glance.yaml"-%} +{% endif %} + +{% if "neutron" in service_list %} +{%- include "scenario/opnfv-neutron.yaml"-%} +{% endif %} + +{% if "quotas" in service_list %} +{%- include "scenario/opnfv-quotas.yaml"-%} +{% endif %} + +{% if "requests" in service_list %} +{%- include "scenario/opnfv-requests.yaml"-%} +{% endif %} + +{% if "heat" in service_list %} +{%- include "scenario/opnfv-heat.yaml"-%} +{% endif %} + +{% if "vm" in service_list %} +{%- include "scenario/opnfv-vm.yaml"-%} +{% endif %} diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-authenticate.json b/testcases/VIM/OpenStack/CI/suites/opnfv-authenticate.json index 3ded19963..8bb589524 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-authenticate.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-authenticate.json @@ -11,6 +11,9 @@ "tenants": 3, "users_per_tenant": 50 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -29,6 +32,9 @@ "tenants": 3, "users_per_tenant": 5 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -47,6 +53,9 @@ "tenants": 3, "users_per_tenant": 5 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -65,6 +74,9 @@ "tenants": 3, "users_per_tenant": 5 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -83,6 +95,9 @@ "tenants": 3, "users_per_tenant": 5 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -101,6 +116,9 @@ "tenants": 3, "users_per_tenant": 5 } + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-cinder.json b/testcases/VIM/OpenStack/CI/suites/opnfv-cinder.json index 958055186..bada44733 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-cinder.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-cinder.json @@ -4,7 +4,7 @@ "args": { "size": 10, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "flavor": { "name": "m1.tiny" @@ -20,6 +20,9 @@ "tenants": 2, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -41,6 +44,9 @@ "volumes": { "size": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -59,6 +65,9 @@ "tenants": 2, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -78,6 +87,9 @@ "tenants": 1, "users_per_tenant": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -100,6 +112,9 @@ "volumes": { "size": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -119,6 +134,9 @@ "tenants": 1, "users_per_tenant": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -141,6 +159,9 @@ "tenants": 2, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -149,7 +170,7 @@ "args": { "size": 1, "image": { - "name": "^TestVM*" + "name": "^functest-img*" } }, "runner": { @@ -162,6 +183,9 @@ "tenants": 2, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -183,6 +207,9 @@ "volumes": { "size": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -210,13 +237,16 @@ }, "servers": { "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "flavor": { "name": "m1.tiny" }, "servers_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -241,13 +271,16 @@ }, "servers": { "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "flavor": { "name": "m1.tiny" }, "servers_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -266,6 +299,9 @@ "tenants": 2, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -288,8 +324,10 @@ "size": 1, "volumes_per_tenant": 4 } + }, + "sla": { + "failure_rate": {"max": 0} } } ] } - diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-glance.json b/testcases/VIM/OpenStack/CI/suites/opnfv-glance.json index 1359fff56..e905ccaba 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-glance.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-glance.json @@ -1,4 +1,28 @@ { + "GlanceImages.list_images": [ + { + "runner": { + "type": "constant", + "times": 10, + "concurrency": 1 + }, + "context": { + "users": { + "tenants": 2, + "users_per_tenant": 2 + }, + "images": { + "image_url": "http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-disk.img", + "image_type": "qcow2", + "image_container": "bare", + "images_per_tenant": 4 + } + }, + "sla": { + "failure_rate": {"max": 0} + } + } + ], "GlanceImages.create_and_delete_image": [ { "args": { @@ -16,6 +40,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -36,6 +63,9 @@ "tenants": 1, "users_per_tenant": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -46,7 +76,7 @@ "container_format": "bare", "disk_format": "qcow2", "flavor": { - "name": "m1.nano" + "name": "m1.small" }, "number_instances": 2 }, @@ -60,27 +90,9 @@ "tenants": 3, "users_per_tenant": 5 } - } - } - ], - "GlanceImages.list_images": [ - { - "runner": { - "type": "constant", - "times": 10, - "concurrency": 1 }, - "context": { - "users": { - "tenants": 2, - "users_per_tenant": 2 - }, - "images": { - "image_url": "http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-disk.img", - "image_type": "qcow2", - "image_container": "bare", - "images_per_tenant": 4 - } + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-heat.json b/testcases/VIM/OpenStack/CI/suites/opnfv-heat.json index 2fbb70fba..a712afefe 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-heat.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-heat.json @@ -11,6 +11,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -29,6 +32,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -47,6 +53,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -62,6 +71,9 @@ "tenants": 1, "users_per_tenant": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -80,6 +92,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -98,6 +113,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -117,6 +135,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -136,6 +157,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -155,6 +179,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -174,6 +201,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -193,6 +223,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -212,6 +245,9 @@ "tenants": 2, "users_per_tenant": 3 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -231,6 +267,9 @@ "stacks_per_tenant": 2, "resources_per_stack": 10 } + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-keystone.json b/testcases/VIM/OpenStack/CI/suites/opnfv-keystone.json index 390a1ae13..f7291ed59 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-keystone.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-keystone.json @@ -8,6 +8,9 @@ "type": "constant", "times": 100, "concurrency": 10 + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -20,6 +23,9 @@ "type": "constant", "times": 10, "concurrency": 1 + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -32,6 +38,9 @@ "type": "constant", "times": 100, "concurrency": 10 + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -44,6 +53,9 @@ "type": "constant", "times": 100, "concurrency": 10 + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -56,6 +68,9 @@ "type": "constant", "times": 100, "concurrency": 10 + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -69,6 +84,9 @@ "type": "constant", "times": 10, "concurrency": 10 + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-neutron.json b/testcases/VIM/OpenStack/CI/suites/opnfv-neutron.json index 5d176ca0d..9fcdf583d 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-neutron.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-neutron.json @@ -19,6 +19,9 @@ "network": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -45,6 +48,9 @@ "port": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -74,6 +80,9 @@ "router": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -101,6 +110,9 @@ "subnet": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -124,6 +136,9 @@ "network": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -150,6 +165,9 @@ "port": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -179,6 +197,9 @@ "router": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -206,6 +227,9 @@ "subnet": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -233,6 +257,9 @@ "network": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -265,6 +292,9 @@ "port": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -298,6 +328,9 @@ "router": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -329,6 +362,9 @@ "subnet": -1 } } + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-nova.json b/testcases/VIM/OpenStack/CI/suites/opnfv-nova.json index 2c56777dc..e32fd57ec 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-nova.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-nova.json @@ -6,7 +6,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "force_delete": false }, @@ -20,6 +20,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -30,7 +33,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" } }, "runner": { @@ -46,6 +49,9 @@ "network": { "start_cidr": "100.1.0.0/26" } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -56,7 +62,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "security_group_count": 10, "rules_per_security_group": 10 @@ -74,6 +80,9 @@ "network": { "start_cidr": "100.1.0.0/26" } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -84,7 +93,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "detailed": true }, @@ -98,6 +107,9 @@ "tenants": 1, "users_per_tenant": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -108,7 +120,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "block_migration": false }, @@ -122,6 +134,9 @@ "tenants": 1, "users_per_tenant": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -132,7 +147,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" } }, "runner": { @@ -145,6 +160,9 @@ "tenants": 1, "users_per_tenant": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -155,7 +173,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "force_delete": false, "actions": [ @@ -175,6 +193,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -185,7 +206,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "volume_size": 10, "force_delete": false @@ -200,6 +221,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -210,7 +234,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "volume_size": 10 }, @@ -224,6 +248,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -234,7 +261,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" } }, "runner": { @@ -247,6 +274,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -256,7 +286,7 @@ "size": 10, "block_migration": false, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "flavor": { "name": "m1.small" @@ -272,6 +302,9 @@ "tenants": 2, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -282,7 +315,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "block_migration": false, "volume_size": 10, @@ -298,6 +331,9 @@ "tenants": 1, "users_per_tenant": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -308,7 +344,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "force_delete": false }, @@ -322,6 +358,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -337,6 +376,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -356,6 +398,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -371,6 +416,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -390,6 +438,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -413,10 +464,13 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "servers_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -427,7 +481,7 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "to_flavor": { "name": "m1.small" @@ -445,6 +499,9 @@ "tenants": 1, "users_per_tenant": 1 } + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-quotas.json b/testcases/VIM/OpenStack/CI/suites/opnfv-quotas.json index 1778a8dd0..1cc1855e7 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-quotas.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-quotas.json @@ -14,6 +14,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -32,6 +35,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -50,6 +56,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -68,6 +77,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -86,6 +98,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-requests.json b/testcases/VIM/OpenStack/CI/suites/opnfv-requests.json index 9936e2fd5..4468d60a3 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-requests.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-requests.json @@ -1,16 +1,38 @@ { - "Requests.check_response": [ + "HttpRequests.check_random_request": [ { "args": { - "url": "http://www.google.com", - "response": 302 + "requests": [{"url": "http://www.example.com", "method": "GET", + "status_code": 200}, + {"url": "http://www.openstack.org", "method": "GET"}], + "status_code": 200 }, "runner": { "type": "constant", "times": 20, "concurrency": 5 + }, + "sla": { + "failure_rate": {"max": 0} + } + } + ], + "HttpRequests.check_request": [ + { + "args": { + "url": "http://www.example.com", + "method": "GET", + "status_code": 200, + "allow_redirects": false + }, + "runner": { + "type": "constant", + "times": 20, + "concurrency": 5 + }, + "sla": { + "failure_rate": {"max": 0} } } ] } - diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-smoke-green.json b/testcases/VIM/OpenStack/CI/suites/opnfv-smoke-green.json index a7eb345b7..b327b53e5 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-smoke-green.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-smoke-green.json @@ -230,6 +230,9 @@ "type": "serial", "times": 1, "concurrency": 1 + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-smoke.json b/testcases/VIM/OpenStack/CI/suites/opnfv-smoke.json index 8c40fab1d..31514d274 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-smoke.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-smoke.json @@ -265,6 +265,9 @@ "type": "serial", "times": 1, "concurrency": 1 + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-tempest.json b/testcases/VIM/OpenStack/CI/suites/opnfv-tempest.json index 0b63070a0..b94de47e4 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-tempest.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-tempest.json @@ -6,6 +6,9 @@ "type": "constant", "times": 1, "concurrency": 1 + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/CI/suites/opnfv-vm.json b/testcases/VIM/OpenStack/CI/suites/opnfv-vm.json index f197ef6ba..382f40251 100644 --- a/testcases/VIM/OpenStack/CI/suites/opnfv-vm.json +++ b/testcases/VIM/OpenStack/CI/suites/opnfv-vm.json @@ -6,13 +6,13 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, - "floating_network": "public", + "floating_network": "net04_ext", "force_delete": false, - "script": "samples/tasks/support/instance_dd_test.sh", + "script": "../Rally_repo/samples/tasks/support/instance_dd_test.sh", "interpreter": "/bin/sh", - "username": "cirros" + "username": "admin" }, "runner": { "type": "constant", @@ -26,6 +26,9 @@ }, "network": { } + }, + "sla": { + "failure_rate": {"max": 0} } } ], @@ -36,18 +39,18 @@ "name": "m1.small" }, "image": { - "name": "^TestVM*" + "name": "^functest-img*" }, "volume_args": { "size": 2 }, "fixed_network": "private", - "floating_network": "public", + "floating_network": "net04_ext", "use_floatingip": true, "force_delete": false, - "script": "samples/tasks/support/instance_dd_test.sh", + "script": "../Rally_repo/samples/tasks/support/instance_dd_test.sh", "interpreter": "/bin/sh", - "username": "cirros" + "username": "admin" }, "runner": { "type": "constant", @@ -59,6 +62,9 @@ "tenants": 3, "users_per_tenant": 2 } + }, + "sla": { + "failure_rate": {"max": 0} } } ] diff --git a/testcases/VIM/OpenStack/OpenStack.md b/testcases/VIM/OpenStack/OpenStack.md deleted file mode 100644 index e1a85c305..000000000 --- a/testcases/VIM/OpenStack/OpenStack.md +++ /dev/null @@ -1,218 +0,0 @@ -# Rally tests for OpenStack - -Original Rally testsuites can be found here: https://github.com/stackforge/rally - ---- -## Intro -In order to perform functional and performance testing, we use Rally (see https://wiki.openstack.org/wiki/Rally for details). -Rally must be installed as jenkins user on the jumphost machine of the OPNFV solution. - -## Installation & Configuration - -### Rally - -* Log on jumphost machine as jenkins user -* Create the file existing.json, adapt it to your OpenStack (until agreement on default passwords) -```bash -{ - "type": "ExistingCloud", - "auth_url": "http://example.net:5000/v2.0/", - "region_name": "RegionOne", - "endpoint_type": "public", - "admin": { - "username": "admin", - "password": "myadminpass", - "tenant_name": "demo" - }, - "https_insecure": False, - "https_cacert": "", -} -``` -* Install Rally (ref https://rally.readthedocs.org/en/latest/tutorial/step_0_installation.html) - -```bash -git clone https://git.openstack.org/stackforge/rally -./rally/install_rally.sh -v -rally deployment create --file=existing.json --name=existing -``` -* you can check the available OpenStack services -```bash -# rally deployment check -keystone endpoints are valid and following service are available: -+-------------+-----------+------------+ -| Services | Type | Status | -+-----------+-------------+------------+ -| cinder | volume | Available | -| cinderv2 | volumev2 | Available | -| glance | image | Available | -| keystone | identity | Available | -| neutron | network | Available | -| nova | compute | Available | -| nova_ec2 | compute_ec2 | Available | -| novav3 | computev3 | Available | -+-----------+-------------+------------+ -``` -* You can start Rally scenario manually, follow https://rally.readthedocs.org/en/latest/tutorial/step_1_setting_up_env_and_running_benchmark_from_samples.html -```bash -# rally task start ./samples/tasks/scenarios/nova/my-boot-and-delete.json --------------------------------------------------------------------------------- - Preparing input task --------------------------------------------------------------------------------- - -Input task is: -{ - "NovaServers.boot_and_delete_server": [ - { - "args": { - "flavor": { - "name": "m1.small" - }, - "image": { - "name": "^ubuntu-14.10-64b" - }, - "force_delete": false - }, - "runner": { - "type": "constant", - "times": 10, - "concurrency": 2 - }, - "context": { - "users": { - "tenants": 3, - "users_per_tenant": 2 - } - } - } - ] -} - --------------------------------------------------------------------------------- - Task f42c8aed-00a6-4715-9951-945b4fb97c32: started --------------------------------------------------------------------------------- - -Benchmarking... This can take a while... - -To track task status use: - - rally task status - or - rally task detailed - --------------------------------------------------------------------------------- -Task f42c8aed-00a6-4715-9951-945b4fb97c32: finished --------------------------------------------------------------------------------- - -test scenario NovaServers.boot_and_delete_server -args position 0 -args values: -OrderedDict([(u'runner', OrderedDict([(u'type', u'constant'), (u'concurrency', 2), (u'times', 10)])), (u'args', OrderedDict([(u'force_delete', False), (u'flavor', OrderedDict([(u'name', u'm1.small')])), (u'image', OrderedDict([(u'name', u'^ubuntu-14.10-64b')]))])), (u'context', OrderedDict([(u'users', OrderedDict([(u'project_domain', u'default'), (u'users_per_tenant', 2), (u'tenants', 3), (u'resource_management_workers', 30), (u'user_domain', u'default')]))]))]) -+--------------------+-----------+-----------+-----------+---------------+---------------+---------+-------+ -| action | min (sec) | avg (sec) | max (sec) | 90 percentile | 95 percentile | success | count | -+--------------------+-----------+-----------+-----------+---------------+---------------+---------+-------+ -| nova.boot_server | 4.675 | 5.554 | 6.357 | 6.289 | 6.323 | 100.0% | 10 | -| nova.delete_server | 2.365 | 3.301 | 4.728 | 4.553 | 4.64 | 100.0% | 10 | -| total | 7.303 | 8.857 | 10.789 | 10.543 | 10.666 | 100.0% | 10 | -+--------------------+-----------+-----------+-----------+---------------+---------------+---------+-------+ -Load duration: 45.7972288132 -Full duration: 58.912060976 - -HINTS: -* To plot HTML graphics with this data, run: - rally task report f42c8aed-00a6-4715-9951-945b4fb97c32 --out output.html - -* To get raw JSON output of task results, run: - rally task results f42c8aed-00a6-4715-9951-945b4fb97c32 - -Using task: f42c8aed-00a6-4715-9951-945b4fb97c32 - -``` -* For Tempest, you can run the test manually by following the instructions https://www.mirantis.com/blog/rally-openstack-tempest-testing-made-simpler - -```bash -root@rally:~/rally# rally verify start -[...] -tempest.api.volume.test_volumes_negative.VolumesV2NegativeTest - test_attach_volumes_with_nonexistent_volume_id[compute,gate,id-f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6,negative]FAIL - test_create_volume_with_invalid_size[gate,id-1ed83a8a-682d-4dfb-a30e-ee63ffd6c049,negative]OK 0.02 - test_create_volume_with_nonexistent_snapshot_id[gate,id-0c36f6ae-4604-4017-b0a9-34fdc63096f9,negative]OK 0.04 - test_create_volume_with_nonexistent_source_volid[gate,id-47c73e08-4be8-45bb-bfdf-0c4e79b88344,negative]OK 0.05 - test_create_volume_with_nonexistent_volume_type[gate,id-10254ed8-3849-454e-862e-3ab8e6aa01d2,negative]OK 0.02 - test_create_volume_with_out_passing_size[gate,id-9387686f-334f-4d31-a439-33494b9e2683,negative]OK 0.02 - test_create_volume_with_size_negative[gate,id-8b472729-9eba-446e-a83b-916bdb34bef7,negative]OK 0.02 -[...] -Ran 933 tests in 1020.200s - -FAILED (failures=186) -Test set 'full' has been finished with error. Check log for details - -``` - -It is possible to get a better view on the result -```bash -# rally verify list -+--------------------------------------+--------------------------------------+----------+-------+----------+----------------------------+----------------+----------+ -| UUID | Deployment UUID | Set name | Tests | Failures | Created at | Duration | Status | -+--------------------------------------+--------------------------------------+----------+-------+----------+----------------------------+----------------+----------+ -| b1de3608-dbee-40e7-84c4-1c756ca0347c | e7d70ddf-9be0-4681-9456-aa8dce515e0e | None | 0 | 0 | 2015-03-11 08:48:04.416793 | 0:00:00.102275 | running | -| ff0d9285-184f-47d5-9474-7475135ae8cf | e7d70ddf-9be0-4681-9456-aa8dce515e0e | full | 933 | 186 | 2015-03-11 09:57:01.836611 | 0:18:08.360204 | finished | -| fec2fd0a-a4ef-4064-a292-95e9da68025c | e7d70ddf-9be0-4681-9456-aa8dce515e0e | full | 933 | 186 | 2015-03-12 09:46:40.818691 | 0:17:02.316443 | finished | -+--------------------------------------+--------------------------------------+----------+-------+----------+----------------------------+----------------+----------+ - -rally verify show fec2fd0a-a4ef-4064-a292-95e9da68025c -Total results of verification: - -+--------------------------------------+--------------------------------------+----------+-------+----------+----------------------------+----------+ -| UUID | Deployment UUID | Set name | Tests | Failures | Created at | Status | -+--------------------------------------+--------------------------------------+----------+-------+----------+----------------------------+----------+ -| fec2fd0a-a4ef-4064-a292-95e9da68025c | e7d70ddf-9be0-4681-9456-aa8dce515e0e | full | 933 | 186 | 2015-03-12 09:46:40.818691 | finished | -+--------------------------------------+--------------------------------------+----------+-------+----------+----------------------------+----------+ - -Tests: - -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------+--------+ -| name | time | status | -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------+--------+ -| tearDownClass (tempest.api.image.v1.test_images.CreateRegisterImagesTest) | 0.0 | FAIL | -| tearDownClass (tempest.api.image.v1.test_images.UpdateImageMetaTest) | 0.0 | FAIL | -[...] -| tempest.cli.simple_read_only.volume.test_cinder.SimpleReadOnlyCinderClientTest.test_cinder_quota_show[id-18166673-ffa8-4df3-b60c-6375532288bc] | 1.309555 | OK | -| tempest.cli.simple_read_only.volume.test_cinder.SimpleReadOnlyCinderClientTest.test_cinder_rate_limits[id-b2c66ed9-ca96-4dc4-94cc-8083e664e516] | 1.277704 | OK | -| tempest.cli.simple_read_only.volume.test_cinder.SimpleReadOnlyCinderClientTest.test_cinder_region_list[id-95a2850c-35b4-4159-bb93-51647a5ad232] | 1.105877 | FAIL | -| tempest.cli.simple_read_only.volume.test_cinder.SimpleReadOnlyCinderClientTest.test_cinder_retries_list[id-6d97fcd2-5dd1-429d-af70-030c949d86cd] | 1.306407 | OK | -| tempest.cli.simple_read_only.volume.test_cinder.SimpleReadOnlyCinderClientTest.test_cinder_service_list[id-301b5ae1-9591-4e9f-999c-d525a9bdf822] | 1.24909 | OK | -| tempest.cli.simple_read_only.volume.test_cinder.SimpleReadOnlyCinderClientTest.test_cinder_snapshot_list[id-7a19955b-807c-481a-a2ee-9d76733eac28] | 1.270242 | OK | -[...] -| tempest.thirdparty.boto.test_s3_ec2_images.S3ImagesTest | 0.0 | SKIP | -| tempest.thirdparty.boto.test_s3_objects.S3BucketsTest.test_create_get_delete_object[id-4eea567a-b46a-405b-a475-6097e1faebde] | 0.239222 | FAIL | -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------+--------+ - -``` -Rally includes a reporting tool -https://rally.readthedocs.org/en/latest/tutorial/step_1_setting_up_env_and_running_benchmark_from_samples.html - -## Test description - -### Rally - -By default, the different Rally Scenarios are: -```bash - -ls samples/tasks/scenarios/ -authenticate cinder dummy heat mistral nova README.rst sahara vm -ceilometer designate glance keystone neutron quotas requests tempest-do-not-run-against-production zaqar - -``` - -tempest tests can be retrieved at https://github.com/openstack/tempest - -tests have been grouped and are available in https://git.opnfv.org/cgit/functest/tree/testcases/VIM/OpenStack/CI/suites - - -## Automation - -For automation, 2 job-templates have been created in https://git.opnfv.org/cgit/releng/tree/jjb/functest/functest.yml - -* functest-vim_bench-test: this template runs automatically a python script that runs the different rally scenario (except Tempest) -* functest-vim_tempest-test: this template runs the rally command rally verify start - diff --git a/testcases/__init__.py b/testcases/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/testcases/__init__.py diff --git a/testcases/config_functest.py b/testcases/config_functest.py index 05376be29..199fadfde 100644..100755 --- a/testcases/config_functest.py +++ b/testcases/config_functest.py @@ -8,18 +8,18 @@ # http://www.apache.org/licenses/LICENSE-2.0 # -import re, json, os, urllib2, argparse, logging, shutil, subprocess, yaml +import re, json, os, urllib2, argparse, logging, shutil, subprocess, yaml, sys, getpass +import functest_utils from git import Repo - -from neutronclient.v2_0 import client +from os import stat +from pwd import getpwuid +from neutronclient.v2_0 import client as neutronclient actions = ['start', 'check', 'clean'] - - - parser = argparse.ArgumentParser() parser.add_argument("action", help="Possible actions are: '{d[0]}|{d[1]}|{d[2]}' ".format(d=actions)) parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") +parser.add_argument("-f", "--force", help="Force", action="store_true") args = parser.parse_args() @@ -37,142 +37,124 @@ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(messag ch.setFormatter(formatter) logger.addHandler(ch) +REPO_PATH=os.environ['repos_dir']+'/functest/' +if not os.path.exists(REPO_PATH): + logger.error("Functest repository directory not found '%s'" % REPO_PATH) + exit(-1) +sys.path.append(REPO_PATH + "testcases/") - -yaml_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/functest.yaml' -name = yaml_url.rsplit('/')[-1] -dest = "./" + name -if not os.path.exists(dest): - logger.info("Downloading functest.yaml...") - try: - response = urllib2.urlopen(yaml_url) - except (urllib2.HTTPError, urllib2.URLError): - logger.error("Error in fetching %s" %yaml_url) - exit(-1) - with open(dest, 'wb') as f: - f.write(response.read()) - logger.info("functest.yaml stored in %s" % dest) -else: - logger.info("functest.yaml found in %s" % dest) - - -with open('./functest.yaml') as f: +with open("/home/opnfv/functest/conf/config_functest.yaml") as f: functest_yaml = yaml.safe_load(f) f.close() """ global variables """ -HOME = os.environ['HOME']+"/" -FUNCTEST_BASE_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_functest") -RALLY_REPO_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_rally_repo") -RALLY_TEST_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_rally") -RALLY_INSTALLATION_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_rally_inst") -BENCH_TESTS_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_rally_scn") -VPING_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_vping") -ODL_DIR = HOME + functest_yaml.get("general").get("directories").get("dir_odl") -NEUTRON_PUBLIC_NAME = functest_yaml.get("general").get("openstack").get("neutron_public_net_name") -NEUTRON_NET_NAME = functest_yaml.get("general").get("openstack").get("neutron_net_name") -NEUTRON_SUBNET_NAME = functest_yaml.get("general").get("openstack").get("neutron_subnet_name") -NEUTRON_RANGE = functest_yaml.get("general").get("openstack").get("neutron_subnet_range") -ROUTER_NAME = functest_yaml.get("general").get("openstack").get("neutron_router_name") - -IMAGE_URL = functest_yaml.get("general").get("openstack").get("image_url") -IMAGE_DISK_FORMAT = functest_yaml.get("general").get("openstack").get("image_disk_format") -IMAGE_NAME = functest_yaml.get("general").get("openstack").get("image_name") -IMAGE_FILE_NAME = IMAGE_URL.rsplit('/')[-1] -IMAGE_DOWNLOAD_PATH = FUNCTEST_BASE_DIR + IMAGE_FILE_NAME - - -def config_functest_start(): +# Directories +RALLY_DIR = REPO_PATH + functest_yaml.get("general").get("directories").get("dir_rally") +RALLY_REPO_DIR = functest_yaml.get("general").get("directories").get("dir_repo_rally") +RALLY_INSTALLATION_DIR = functest_yaml.get("general").get("directories").get("dir_rally_inst") +RALLY_RESULT_DIR = functest_yaml.get("general").get("directories").get("dir_rally_res") +VPING_DIR = REPO_PATH + functest_yaml.get("general").get("directories").get("dir_vping") +VIMS_TEST_DIR = functest_yaml.get("general").get("directories").get("dir_repo_vims_test") +ODL_DIR = REPO_PATH + functest_yaml.get("general").get("directories").get("dir_odl") +DATA_DIR = functest_yaml.get("general").get("directories").get("dir_functest_data") + +# Tempest/Rally configuration details +DEPLOYMENT_MAME = functest_yaml.get("rally").get("deployment_name") +RALLY_COMMIT = functest_yaml.get("general").get("repositories").get("rally_commit") + +#Image (cirros) +IMAGE_FILE_NAME = functest_yaml.get("general").get("openstack").get("image_file_name") +IMAGE_PATH = DATA_DIR + "/" + IMAGE_FILE_NAME + +# NEUTRON Private Network parameters +NEUTRON_PRIVATE_NET_NAME = functest_yaml.get("general"). \ + get("openstack").get("neutron_private_net_name") +NEUTRON_PRIVATE_SUBNET_NAME = functest_yaml.get("general"). \ + get("openstack").get("neutron_private_subnet_name") +NEUTRON_PRIVATE_SUBNET_CIDR = functest_yaml.get("general"). \ + get("openstack").get("neutron_private_subnet_cidr") +NEUTRON_ROUTER_NAME = functest_yaml.get("general"). \ + get("openstack").get("neutron_router_name") + +creds_neutron = functest_utils.get_credentials("neutron") +neutron_client = neutronclient.Client(**creds_neutron) + +def action_start(): """ Start the functest environment installation """ - #if config_functest_check(): - # logger.info("Functest environment already installed in %s. Nothing to do." %FUNCTEST_BASE_DIR) - # exit(0) - if not check_internet_connectivity(): + if not functest_utils.check_internet_connectivity(): logger.error("There is no Internet connectivity. Please check the network configuration.") exit(-1) - elif not check_credentials(): - logger.error("Please source the openrc credentials and run the script again.") - #TODO: source the credentials in this script - exit(-1) - elif not check_neutron_net(NEUTRON_PUBLIC_NAME): - #The public network is normally created by default, no need to create a new one - logger.debug("Public network '%s' not found." % NEUTRON_PUBLIC_NAME) - logger.error("A public Neutron network is needed for the environment. Please create one.") - #TODO: source the credentials in this script - exit(-1) - else: - # Clean in case there are left overs - config_functest_clean() - logger.info("Starting installationg of functest environment in %s" % FUNCTEST_BASE_DIR) - os.makedirs(FUNCTEST_BASE_DIR) - if not os.path.exists(FUNCTEST_BASE_DIR): - logger.error("There has been a problem while creating the environment directory.") - exit(-1) + if action_check(): + logger.info("Functest environment already installed. Nothing to do.") + exit(0) - logger.info("Donwloading test scripts and scenarios...") - if not download_tests(): - logger.error("There has been a problem while downloading the test scripts and scenarios.") - config_functest_clean() - exit(-1) + else: + # Clean in case there are left overs + logger.debug("Cleaning possible functest environment leftovers.") + action_clean() + logger.info("Starting installation of functest environment") + + private_net = functest_utils.get_private_net(neutron_client) + if private_net is None: + # If there is no private network in the deployment we create one + if not create_private_neutron_net(neutron_client): + logger.error("There has been a problem while creating the functest network.") + action_clean() + exit(-1) + else: + logger.info("Private network '%s' already existing in the deployment." + % private_net['name']) logger.info("Installing Rally...") if not install_rally(): logger.error("There has been a problem while installing Rally.") - config_functest_clean() - exit(-1) - - logger.info("Installing ODL environment...") - if not install_odl(): - logger.error("There has been a problem while installing Robot.") - config_functest_clean() + action_clean() exit(-1) - logger.info("Creating a private Neutron network...") - logger.debug("Checking if private network '%s' exists..." % NEUTRON_NET_NAME) - #Now: if exists we don't create it again (the clean command does not clean the neutron network) - #TODO: this check will not be needed when cleaning the neutron is implemented - if check_neutron_net(NEUTRON_NET_NAME): - logger.info("Private network '%s' found. No need to create another one." % NEUTRON_NET_NAME) + logger.info("Installing Ruby libraries for vIMS testcase...") + # Install ruby libraries for vims test-case + script = 'source /etc/profile.d/rvm.sh; ' + script += 'cd ' + VIMS_TEST_DIR + '; ' + script += 'rvm autolibs enable ;' + script += 'rvm install 1.9.3; ' + script += 'rvm use 1.9.3;' + script += 'bundle install' + + cmd = "/bin/bash -c '" + script + "'" + if os.environ.get("CI_DEBUG") == "false": + functest_utils.execute_command(cmd) else: - logger.info("Private network '%s' not found. Creating..." % NEUTRON_NET_NAME) - if not create_neutron_net(): - logger.error("There has been a problem while creating the Neutron network.") - #config_functest_clean() - exit(-1) - + functest_utils.execute_command(cmd,logger) - logger.info("Donwloading image...") - if not download_url_with_progress(IMAGE_URL, FUNCTEST_BASE_DIR): - logger.error("There has been a problem while downloading the image.") - config_functest_clean() - exit(-1) + # Create result folder under functest if necessary + if not os.path.exists(RALLY_RESULT_DIR): + os.makedirs(RALLY_RESULT_DIR) - logger.info("Creating Glance image: %s ..." %IMAGE_NAME) - if not create_glance_image(IMAGE_DOWNLOAD_PATH,IMAGE_NAME,IMAGE_DISK_FORMAT): - logger.error("There has been a problem while creating the Glance image.") - config_functest_clean() - exit(-1) + try: + logger.info("CI: Generate the list of executable tests.") + runnable_test = functest_utils.generateTestcaseList(functest_yaml) + logger.info("List of runnable tests generated: %s" % runnable_test) + except: + logger.error("Impossible to generate the list of runnable tests") exit(0) - -def config_functest_check(): +def action_check(): """ Check if the functest environment is properly installed """ errors_all = False - + errors = False logger.info("Checking current functest configuration...") + logger.debug("Checking script directories...") - logger.debug("Checking directories...") - errors = False - dirs = [FUNCTEST_BASE_DIR, RALLY_INSTALLATION_DIR, RALLY_REPO_DIR, RALLY_TEST_DIR, BENCH_TESTS_DIR, VPING_DIR, ODL_DIR] + dirs = [RALLY_DIR, RALLY_INSTALLATION_DIR, VPING_DIR, ODL_DIR] for dir in dirs: if not os.path.exists(dir): logger.debug("The directory '%s' does NOT exist." % dir) @@ -188,56 +170,21 @@ def config_functest_check(): logger.debug("Checking Rally deployment...") if not check_rally(): - logger.debug("Rally deployment NOT found.") + logger.debug(" Rally deployment NOT installed.") errors_all = True logger.debug("...FAIL") else: logger.debug("...OK") - - logger.debug("Checking Neutron...") - errors = False - if not check_neutron_net(NEUTRON_NET_NAME): - logger.debug(" Private network '%s' NOT found." % NEUTRON_NET_NAME) - errors = True - errors_all = True - else: - logger.debug(" Private network '%s' found." % NEUTRON_NET_NAME) - - if not check_neutron_net(NEUTRON_PUBLIC_NAME): - logger.debug(" Public network '%s' NOT found." % NEUTRON_PUBLIC_NAME) - errors = True - errors_all = True - else: - logger.debug(" Public network '%s' found." % NEUTRON_PUBLIC_NAME) - - if not errors: - logger.debug("...OK") - else: - logger.debug("...FAIL") - - logger.debug("Checking Image...") errors = False - if not os.path.isfile(IMAGE_DOWNLOAD_PATH): - logger.debug(" Image file '%s' NOT found." % IMAGE_DOWNLOAD_PATH) + if not os.path.isfile(IMAGE_PATH): + logger.debug(" Image file '%s' NOT found." % IMAGE_PATH) errors = True errors_all = True else: - logger.debug(" Image file found in %s" % IMAGE_DOWNLOAD_PATH) - - cmd="glance image-list | grep " + IMAGE_NAME - FNULL = open(os.devnull, 'w'); - logger.debug(' Executing command : {}'.format(cmd)) - p=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=FNULL); - #if the command does not exist or there is no glance image - line = p.stdout.readline() - if line == "": - logger.debug(" Glance image NOT found.") - errors = True - errors_all = True - else: - logger.debug(" Glance image found.") + logger.debug(" Image file found in %s" % IMAGE_PATH) + if not errors: logger.debug("...OK") @@ -245,44 +192,28 @@ def config_functest_check(): logger.debug("...FAIL") #TODO: check OLD environment setup - if errors_all: - return False - else: - return True + return not errors_all - -def config_functest_clean(): +def action_clean(): """ Clean the existing functest environment """ logger.info("Removing current functest environment...") if os.path.exists(RALLY_INSTALLATION_DIR): - logger.debug("Removing rally installation directory %s" % RALLY_INSTALLATION_DIR) + logger.debug("Removing Rally installation directory %s" % RALLY_INSTALLATION_DIR) shutil.rmtree(RALLY_INSTALLATION_DIR,ignore_errors=True) - if os.path.exists(FUNCTEST_BASE_DIR): - logger.debug("Removing functest directory %s" % FUNCTEST_BASE_DIR) - cmd = "sudo rm -rf " + FUNCTEST_BASE_DIR #need to be sudo, not possible with rmtree - execute_command(cmd) - - #logger.debug("Deleting Neutron network %s" % NEUTRON_NET_NAME) - #if not delete_neutron_net() : - # logger.error("Error deleting the network. Remove it manually.") - - logger.debug("Deleting glance images") - cmd = "glance image-list | grep "+IMAGE_NAME+" | cut -c3-38" - p = os.popen(cmd,"r") - - #while image_id = p.readline() - for image_id in p.readlines(): - cmd = "glance image-delete " + image_id - execute_command(cmd) - - return True - + if os.path.exists(RALLY_RESULT_DIR): + logger.debug("Removing Result directory") + shutil.rmtree(RALLY_RESULT_DIR,ignore_errors=True) + logger.debug("Cleaning up the OpenStack deployment...") + cmd='python ' + REPO_PATH + \ + '/testcases/VIM/OpenStack/CI/libraries/clean_openstack.py' + functest_utils.execute_command(cmd,logger) + logger.info("Functest environment clean!") @@ -290,38 +221,35 @@ def install_rally(): if check_rally(): logger.info("Rally is already installed.") else: - logger.debug("Cloning repository...") - url = "https://git.openstack.org/openstack/rally" - Repo.clone_from(url, RALLY_REPO_DIR) - - logger.debug("Executing %s./install_rally.sh..." %RALLY_REPO_DIR) - install_script = RALLY_REPO_DIR + "install_rally.sh" + logger.debug("Executing %s/install_rally.sh..." %RALLY_REPO_DIR) + install_script = RALLY_REPO_DIR + "/install_rally.sh --yes" cmd = 'sudo ' + install_script - execute_command(cmd) - #subprocess.call(['sudo', install_script]) + if os.environ.get("CI_DEBUG") == "false": + functest_utils.execute_command(cmd) + else: + functest_utils.execute_command(cmd,logger) logger.debug("Creating Rally environment...") - cmd = "rally deployment create --fromenv --name=opnfv-arno-rally" - execute_command(cmd) + cmd = "rally deployment create --fromenv --name="+DEPLOYMENT_MAME + functest_utils.execute_command(cmd,logger) logger.debug("Installing tempest...") - cmd = "rally-manage tempest install" - execute_command(cmd) + cmd = "rally verify install" + functest_utils.execute_command(cmd,logger) cmd = "rally deployment check" - execute_command(cmd) + functest_utils.execute_command(cmd,logger) #TODO: check that everything is 'Available' and warn if not cmd = "rally show images" - execute_command(cmd) + functest_utils.execute_command(cmd,logger) cmd = "rally show flavors" - execute_command(cmd) + functest_utils.execute_command(cmd,logger) return True - def check_rally(): """ Check if Rally is installed and properly configured @@ -329,326 +257,102 @@ def check_rally(): if os.path.exists(RALLY_INSTALLATION_DIR): logger.debug(" Rally installation directory found in %s" % RALLY_INSTALLATION_DIR) FNULL = open(os.devnull, 'w'); - cmd="rally deployment list | grep opnfv"; + cmd="rally deployment list | grep "+DEPLOYMENT_MAME logger.debug(' Executing command : {}'.format(cmd)) p=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=FNULL); #if the command does not exist or there is no deployment line = p.stdout.readline() if line == "": - logger.debug(" Rally deployment not found") + logger.debug(" Rally deployment NOT found") return False logger.debug(" Rally deployment found") return True else: - logger.debug(" Rally installation directory not found") return False -def install_odl(): - cmd = "chmod +x " + ODL_DIR + "create_venv.sh" - execute_command(cmd) - cmd = ODL_DIR + "create_venv.sh" - execute_command(cmd) - return True - +def create_private_neutron_net(neutron): + neutron.format = 'json' + logger.info('Creating neutron network %s...' % NEUTRON_PRIVATE_NET_NAME) + network_id = functest_utils. \ + create_neutron_net(neutron, NEUTRON_PRIVATE_NET_NAME) -def check_credentials(): - """ - Check if the OpenStack credentials (openrc) are sourced - """ - #TODO: there must be a short way to do this, doing if os.environ["something"] == "" throws an error - try: - os.environ['OS_AUTH_URL'] - except KeyError: - return False - try: - os.environ['OS_USERNAME'] - except KeyError: + if not network_id: return False - try: - os.environ['OS_PASSWORD'] - except KeyError: - return False - try: - os.environ['OS_TENANT_NAME'] - except KeyError: - return False - try: - os.environ['OS_REGION_NAME'] - except KeyError: - return False - return True + logger.debug("Network '%s' created successfully" % network_id) - -def get_credentials(): - d = {} - d['username'] = os.environ['OS_USERNAME'] - d['password'] = os.environ['OS_PASSWORD'] - d['auth_url'] = os.environ['OS_AUTH_URL'] - d['tenant_name'] = os.environ['OS_TENANT_NAME'] - return d - -def get_nova_credentials(): - d = {} - d['username'] = os.environ['OS_USERNAME'] - d['api_key'] = os.environ['OS_PASSWORD'] - d['auth_url'] = os.environ['OS_AUTH_URL'] - d['project_id'] = os.environ['OS_TENANT_NAME'] - return d - - -def download_tests(): - os.makedirs(VPING_DIR) - os.makedirs(ODL_DIR) - os.makedirs(BENCH_TESTS_DIR) - - logger.info("Downloading functest.yaml...") - yaml_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/functest.yaml' - if not download_url(yaml_url,FUNCTEST_BASE_DIR): - logger.error("Unable to download the configuration file functest.yaml") - return False - - logger.info("Downloading vPing test...") - vPing_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/vPing/CI/libraries/vPing.py' - if not download_url(vPing_url,VPING_DIR): + logger.info('Updating neutron network %s...' % NEUTRON_PRIVATE_NET_NAME) + if functest_utils.update_neutron_net(neutron, network_id, shared=True): + logger.debug("Network '%s' updated successfully" % network_id) + else: + logger.info('Updating neutron network %s failed' % network_id) + + logger.debug('Creating Subnet....') + subnet_id = functest_utils. \ + create_neutron_subnet(neutron, + NEUTRON_PRIVATE_SUBNET_NAME, + NEUTRON_PRIVATE_SUBNET_CIDR, + network_id) + if not subnet_id: return False + logger.debug("Subnet '%s' created successfully" % subnet_id) + logger.debug('Creating Router...') + router_id = functest_utils. \ + create_neutron_router(neutron, NEUTRON_ROUTER_NAME) - - logger.info("Downloading Rally bench tests...") - run_rally_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/VIM/OpenStack/CI/libraries/run_rally.py' - if not download_url(run_rally_url,RALLY_TEST_DIR): + if not router_id: return False - rally_bench_base_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/VIM/OpenStack/CI/suites/' - bench_tests = ['authenticate', 'cinder', 'glance', 'heat', 'keystone', 'neutron', 'nova', 'quotas', 'requests', 'tempest', 'vm'] - for i in bench_tests: - rally_bench_url = rally_bench_base_url + "opnfv-" + i + ".json" - logger.debug("Downloading %s" %rally_bench_url) - if not download_url(rally_bench_url,BENCH_TESTS_DIR): - return False + logger.debug("Router '%s' created successfully" % router_id) + logger.debug('Adding router to subnet...') - logger.info("Downloading OLD tests...") - odl_base_url = 'https://git.opnfv.org/cgit/functest/plain/testcases/Controllers/ODL/CI/' - odl_tests = ['create_venv.sh', 'requirements.pip', 'start_tests.sh', 'test_list.txt'] - for i in odl_tests: - odl_url = odl_base_url + i - logger.debug("Downloading %s" %odl_url) - if not download_url(odl_url,ODL_DIR): - return False + result = functest_utils.add_interface_router(neutron, router_id, subnet_id) - return True - - -def create_neutron_net(): - credentials = get_credentials() - neutron = client.Client(**credentials) - try: - neutron.format = 'json' - logger.debug('Creating Neutron network %s...' % NEUTRON_NET_NAME) - json_body = {'network': {'name': NEUTRON_NET_NAME, - 'admin_state_up': True}} - netw = neutron.create_network(body=json_body) - net_dict = netw['network'] - network_id = net_dict['id'] - logger.debug("Network '%s' created successfully" % network_id) - - logger.debug('Creating Subnet....') - json_body = {'subnets': [{'cidr': NEUTRON_RANGE, - 'ip_version': 4, 'network_id': network_id}]} - subnet = neutron.create_subnet(body=json_body) - logger.debug("Subnet '%s' created successfully" % subnet) - - logger.debug('Creating Router...') - json_body = {'router': {'name': ROUTER_NAME, 'admin_state_up': True}} - router = neutron.create_router(json_body) - logger.debug("Router '%s' created successfully" % router) - router_id = router['router']['id'] - - logger.debug('Creating Port') - json_body = {'port': { - 'admin_state_up': True, - 'device_id': router_id, - 'name': 'port1', - 'network_id': network_id, - }} - response = neutron.create_port(body=json_body) - logger.debug("Port created successfully.") - - logger.debug('Setting up gateway...') - public_network_id = get_network_id(neutron,NEUTRON_PUBLIC_NAME) - json_body = {'network_id': public_network_id, 'enable_snat' : True} - gateway = neutron.add_gateway_router(router_id,body=json_body) - logger.debug("Gateway '%s' added successfully" % gateway) - except: - logger.error("There has been a problem when creating the Neutron network.") + if not result: return False - finally: - logger.info("Neutron network created successfully.") - return True - - return False - -def get_network_id(neutron_client, network_name): - networks = neutron_client.list_networks()['networks'] - id = '' - for n in networks: - if n['name'] == network_name: - id = n['id'] - break - return id - -def check_neutron_net(net_name): - credentials = get_credentials() - neutron = client.Client(**credentials) - for network in neutron.list_networks()['networks']: - if network['name'] == net_name : - for subnet in network['subnets']: - return True - return False - -def delete_neutron_net(): - #TODO: remove router, ports - credentials = get_credentials() - neutron = client.Client(**credentials) - try: - #https://github.com/isginf/openstack_tools/blob/master/openstack_remove_tenant.py - for network in neutron.list_networks()['networks']: - if network['name'] == NEUTRON_NET_NAME : - for subnet in network['subnets']: - print "Deleting subnet " + subnet - neutron.delete_subnet(subnet) - print "Deleting network " + network['name'] - neutron.delete_neutron_net(network['id']) - finally: - return True - return False - - - - -def create_glance_image(path,name,disk_format): - """ - Create a glance image given the absolute path of the image, its name and the disk format - """ - cmd = "glance image-create --name "+name+" --is-public true --disk-format "+disk_format+" --container-format bare --file "+path - execute_command(cmd) + logger.debug("Interface added successfully.") + network_dic = {'net_id': network_id, + 'subnet_id': subnet_id, + 'router_id': router_id} return True - - - -def download_url(url, dest_path): - """ - Download a file to a destination path given a URL - """ - name = url.rsplit('/')[-1] - dest = dest_path + name - try: - response = urllib2.urlopen(url) - except (urllib2.HTTPError, urllib2.URLError): - logger.error("Error in fetching %s" %url) - return False - - with open(dest, 'wb') as f: - f.write(response.read()) - return True - - -def download_url_with_progress(url, dest_path): - """ - Download a file to a destination path given a URL showing the progress - """ - name = url.rsplit('/')[-1] - dest = dest_path + name - try: - response = urllib2.urlopen(url) - except (urllib2.HTTPError, urllib2.URLError): - logger.error("Error in fetching %s" %url) - return False - - f = open(dest, 'wb') - meta = response.info() - file_size = int(meta.getheaders("Content-Length")[0]) - logger.info("Downloading: %s Bytes: %s" %(dest, file_size)) - - file_size_dl = 0 - block_sz = 8192 - while True: - buffer = response.read(block_sz) - if not buffer: - break - - file_size_dl += len(buffer) - f.write(buffer) - status = r"%10d [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size) - status = status + chr(8)*(len(status)+1) - print status, - - f.close() - print("\n") - return True - - -def check_internet_connectivity(url='http://www.google.com/'): - """ - Check if there is access to the internet - """ - try: - urllib2.urlopen(url, timeout=5) - return True - except urllib.request.URLError: - return False - -def execute_command(cmd): - """ - Execute Linux command - """ - logger.debug('Executing command : {}'.format(cmd)) - #p = os.popen(cmd,"r") - #logger.debug(p.read()) - output_file = "/tmp/output.txt" - f = open(output_file, 'w+') - p = subprocess.call(cmd,shell=True, stdout=f, stderr=subprocess.STDOUT) - f.close() - f = open(output_file, 'r') - logger.debug(f.read()) - #p = subprocess.call(cmd,shell=True); - if p == 0 : - return True - else: - logger.error("Error when executing command %s" %cmd) - exit(-1) - - - - def main(): if not (args.action in actions): logger.error('argument not valid') exit(-1) + + if not functest_utils.check_credentials(): + logger.error("Please source the openrc credentials and run the script again.") + #TODO: source the credentials in this script + exit(-1) + + if args.action == "start": - config_functest_start() + action_start() if args.action == "check": - if config_functest_check(): + if action_check(): logger.info("Functest environment correctly installed") else: logger.info("Functest environment not found or faulty") if args.action == "clean": - while True: - print("Are you sure? [y|n]") - answer = raw_input("") - if answer == "y": - config_functest_clean() - break - elif answer == "n": - break - else: - print("Invalid option.") + if args.force : + action_clean() + else : + while True: + print("Are you sure? [y|n]") + answer = raw_input("") + if answer == "y": + action_clean() + break + elif answer == "n": + break + else: + print("Invalid option.") exit(0) diff --git a/testcases/config_functest.yaml b/testcases/config_functest.yaml new file mode 100644 index 000000000..7c1e79d36 --- /dev/null +++ b/testcases/config_functest.yaml @@ -0,0 +1,243 @@ +general: + directories: + # Relative to the path where the repo is cloned: + dir_vping: testcases/vPing/CI/libraries/ + dir_odl: testcases/Controllers/ODL/CI/ + dir_rally: testcases/VIM/OpenStack/CI/libraries/ + dir_rally_scn: testcases/VIM/OpenStack/CI/suites/ + dir_vIMS: testcases/vIMS/CI/ + dir_onos: testcases/Controllers/ONOS/Teston/CI/ + + # Absolute path + dir_repos: /home/opnfv/repos + dir_repo_functest: /home/opnfv/repos/functest + dir_repo_rally: /home/opnfv/repos/rally + dir_repo_releng: /home/opnfv/repos/releng + dir_repo_vims_test: /home/opnfv/repos/vims-test + dir_repo_bgpvpn: /home/opnfv/repos/bgpvpn + dir_repo_onos: /home/opnfv/repos/onos + dir_repo_promise: /home/opnfv/repos/promise + dir_repo_doctor: /home/opnfv/repos/doctor + dir_functest: /home/opnfv/functest + dir_results: /home/opnfv/functest/results + dir_functest_conf: /home/opnfv/functest/conf + dir_rally_res: /home/opnfv/functest/results/rally/ + dir_functest_data: /home/opnfv/functest/data + dir_vIMS_data: /home/opnfv/functest/data/vIMS + dir_rally_inst: ~/.rally + + repositories: + # branch and commit ID to which the repos will be reset (HEAD) + releng_branch: master + releng_commit: latest + rally_branch: master + rally_commit: 57efc5327530a34d139b5a1fd1f480195de0aadb + vims_test_branch: stable + vims_test_commit: latest + bgpvpn_branch: master + bgpvpn_commit: latest + onos_branch: master + onos_commit: latest + promise_branch: master + promise_commit: latest + + openstack: + image_name: functest-img + image_file_name: cirros-0.3.4-x86_64-disk.img + image_disk_format: qcow2 + + #Public network. Optional + neutron_public_net_name: net04_ext + neutron_public_subnet_name: net04_ext__subnet + neutron_public_subnet_cidr: 172.16.9.0/24 + neutron_public_subnet_start: 172.16.9.130 + neutron_public_subnet_end: 172.16.9.254 + #Private network for functest. Will be created by config_functest.py + neutron_private_net_name: functest-net + neutron_private_subnet_name: functest-subnet + neutron_private_subnet_cidr: 192.168.120.0/24 + neutron_private_subnet_start: 192.168.120.2 + neutron_private_subnet_end: 192.168.120.254 + neutron_private_subnet_gateway: 192.168.120.254 + neutron_router_name: functest-router + +vping: + ping_timeout: 200 + vm_flavor: m1.small #adapt to your environment + vm_name_1: opnfv-vping-1 + vm_name_2: opnfv-vping-2 + vping_private_net_name: vping-net + vping_private_subnet_name: vping-subnet + vping_private_subnet_cidr: 192.168.130.0/24 + vping_router_name: vping-router + ip_1: 192.168.130.30 + ip_2: 192.168.130.40 + +tempest: + identity: + tenant_name: tempest + tenant_description: Tenant for Tempest test suite + user_name: tempest + user_password: tempest + +rally: + deployment_name: opnfv-rally + +vIMS: + general: + tenant_name: vIMS + tenant_description: vIMS Functionality Testing + images: + ubuntu: + image_url: 'http://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img' + image_name: ubuntu_14.04 + centos: + image_url: 'http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1510.qcow2' + image_name: centos_7 + cloudify: + blueprint: + url: https://github.com/boucherv-orange/cloudify-manager-blueprints.git + branch: "3.3-build" + requierments: + ram_min: 3000 + os_image: centos_7 + inputs: + keystone_username: "" + keystone_password: "" + keystone_tenant_name: "" + keystone_url: "" + manager_public_key_name: 'manager-kp' + agent_public_key_name: 'agent-kp' + image_id: "" + flavor_id: "3" + external_network_name: "" + ssh_user: centos + agents_user: ubuntu + clearwater: + blueprint: + file_name: 'openstack-blueprint.yaml' + name: "clearwater-opnfv" + destination_folder: "opnfv-cloudify-clearwater" + url: 'https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater.git' + branch: "stable" + deployment-name: 'clearwater-opnfv' + requierments: + ram_min: 1700 + os_image: ubuntu_14.04 + inputs: + image_id: '' + flavor_id: '' + agent_user: 'ubuntu' + external_network_name: '' + public_domain: clearwater.opnfv +ONOS: + general: + onosbench_username: 'root' + onosbench_password: 'root' + onoscli_username: 'root' + onoscli_password: 'root' + runtimeout: 300 + environment: + OCT: '10.20.0.1' + OC1: '10.20.0.7' + OC2: '10.20.0.7' + OC3: '10.20.0.7' + OCN: '10.20.0.4' + OCN2: '10.20.0.5' + installer_master: '10.20.0.2' + installer_master_username: 'root' + installer_master_password: 'r00tme' +results: + test_db_url: http://213.77.62.197 + +# to be maintained... +# the execution order is important as some tests may be more destructive than others +# and if vPing is failing is usually not needed to continue... +test_exec_priority: + 1: vping + 2: tempest + 3: odl + 4: onos + #5: ovno + #6: doctor + 7: promise + #8: policy-test + #9: odl-vpn_service-tests + #10: opnfv-yardstick-tc026-sdnvpn + #11: openstack-neutron-bgpvpn-api-extension-tests + 12: vims + 13: rally + + +######################################################################## +# This part lists the dependencies of the tests +# +# it is used to manage the complexity of the possible combinations +# +# 17 projects have been declared for Brahmaputra (D Milestone) +# 89 testcases are associated with these 17 projects +# +# in B-Release, Functest deals with 6 companion projects: +# - congress +# - doctor +# - ovno +# - policyTest +# - promise +# - sdnvpn +# +# constraints may be declared at the testcase or the test project level +# +# By default we consider that all the tests can be run on any configuration +# +# we defined 2 constraints +# - installer (e.g. my test can be run only with installer Compass) +# possible values: apex, compass, fuel, joid +# +# - the scenario: it described a specif installation +# os-<controller>-<nfvfeature>-<mode>[-<extrastuff>] +# With parameters: +# controller=(nosdn|odl_l3|odl_l2|onos|ocl) +# No odl_l3 today +# nfvfeature=(kvm|ovs|dpdk|nofeature) +# '_' list separated. +# mode=(ha|noha) +# extrastuff=(none) +# Optional field - Not used today# +# +# ref:https://gerrit.opnfv.org/gerrit/#/c/6323/7/jjb/joid/joid-deploy.sh (L72-82) +# e.g my test is only possible with OVS 2.3.2 on odl +# +# in functest, we indicate the regex pattern to be checked towards the scenario +# e.g. odl-vpn_service-tests can be run if and only if +# - installer is fuel +# - scenario contains the name ovs and odl +# +####################################################################### +test-dependencies: + doctor: + installer: '(apex)|(fuel)' + functest: + vims: + vping: + tempest: + rally: + odl: + scenario: 'odl' + onos: + scenario: 'onos' + promise: + installer: '(fuel)|(joid)' + ovno: + scenario: 'ocl' + policy-test: + scenario: 'odl' + sdnvpn: + opnfv-yardstick-tc026-sdnvpn: + installer: 'fuel' + scenario: '(ovs)*(nosdn)' + odl-vpn_service-tests: + installer: 'fuel' + scenario: '(ovs)*(odl)' + openstack-neutron-bgpvpn-api-extension-tests: + installer: 'fuel' + scenario: '(ovs)*(nosdn)' diff --git a/testcases/features/doctor.py b/testcases/features/doctor.py new file mode 100644 index 000000000..a68c31cd0 --- /dev/null +++ b/testcases/features/doctor.py @@ -0,0 +1,64 @@ +#!/usr/bin/python +# +# Copyright (c) 2015 All rights reserved +# This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 0.1: This script boots the VM1 and allocates IP address from Nova +# Later, the VM2 boots then execute cloud-init to ping VM1. +# After successful ping, both the VMs are deleted. +# 0.2: measure test duration and publish results under json format +# +# + +import os +import time +import sys +import yaml + + +with open('/home/opnfv/functest/conf/config_functest.yaml') as f: + functest_yaml = yaml.safe_load(f) + +dirs = functest_yaml.get('general').get('directories') +FUNCTEST_REPO = dirs.get('dir_repo_functest') +DOCTOR_REPO = dirs.get('dir_repo_doctor') +TEST_DB_URL = functest_yaml.get('results').get('test_db_url') + +sys.path.append('%s/testcases' % FUNCTEST_REPO) +import functest_utils + + +def main(): + cmd = 'cd %s/tests && ./run.sh' % DOCTOR_REPO + start_time_ts = time.time() + + ret = functest_utils.execute_command(cmd, exit_on_error=False) + + end_time_ts = time.time() + duration = round(end_time_ts - start_time_ts, 1) + if ret: + test_status = 'OK' + else: + test_status = 'NOK' + + details = { + 'timestart': start_time_ts, + 'duration': duration, + 'status': test_status, + } + pod_name = functest_utils.get_pod_name() + git_version = functest_utils.get_git_branch(DOCTOR_REPO) + functest_utils.push_results_to_db(TEST_DB_URL, + 'doctor-notification', + None, + pod_name, + git_version, + details) + + +if __name__ == '__main__': + main() diff --git a/testcases/functest.yaml b/testcases/functest.yaml deleted file mode 100644 index 2f3494997..000000000 --- a/testcases/functest.yaml +++ /dev/null @@ -1,30 +0,0 @@ ---- -general: - directories: - dir_functest: .functest/ #DONT CHANGE - dir_rally_repo: .functest/Rally_repo/ - dir_rally: .functest/Rally_test/ - dir_rally_scn: .functest/Rally_test/scenarios/ - dir_rally_res: .functest/Rally_test/results/ - dir_vping: .functest/vPing/ - dir_odl: .functest/ODL/ - dir_rally_inst: .rally/ - openstack: - image_name: Ubuntu14.04 - image_url: https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img - image_disk_format: raw - #Public network. Must exist already. - neutron_public_net_name: net04_ext - #Private network for functest. Will be created by config_functest.py - neutron_net_name: functest-net - neutron_subnet_name: functest-subnet - neutron_subnet_range: 192.168.120.0/24 - neutron_subnet_start: 192.168.120.2 - neutron_subnet_end: 192.168.120.254 - neutron_subnet_gateway: 192.168.120.254 - neutron_router_name: functest-router -vping: - ping_timeout: 200 - vm_flavor: m1.small #adapt to your environment - vm_name_1: opnfv-vping-1 - vm_name_2: opnfv-vping-2 diff --git a/testcases/functest_utils.py b/testcases/functest_utils.py new file mode 100644 index 000000000..baab415d9 --- /dev/null +++ b/testcases/functest_utils.py @@ -0,0 +1,766 @@ +#!/usr/bin/env python +# +# jose.lausuch@ericsson.com +# valentin.boucher@orange.com +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# + + +import os +import os.path +import urllib2 +import subprocess +import sys +import requests +import json +import shutil +import re +import yaml +from git import Repo + + +# ############ CREDENTIALS OPENSTACK ############# +def check_credentials(): + """ + Check if the OpenStack credentials (openrc) are sourced + """ + env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD', 'OS_TENANT_NAME'] + return all(map(lambda v: v in os.environ and os.environ[v], env_vars)) + + +def get_credentials(service): + """Returns a creds dictionary filled with the following keys: + * username + * password/api_key (depending on the service) + * tenant_name/project_id (depending on the service) + * auth_url + :param service: a string indicating the name of the service + requesting the credentials. + """ + creds = {} + # Unfortunately, each of the OpenStack client will request slightly + # different entries in their credentials dict. + if service.lower() in ("nova", "cinder"): + password = "api_key" + tenant = "project_id" + else: + password = "password" + tenant = "tenant_name" + + # The most common way to pass these info to the script is to do it through + # environment variables. + creds.update({ + "username": os.environ.get('OS_USERNAME', "admin"), + password: os.environ.get("OS_PASSWORD", 'admin'), + "auth_url": os.environ.get("OS_AUTH_URL", + "http://192.168.20.71:5000/v2.0"), + tenant: os.environ.get("OS_TENANT_NAME", "admin"), + }) + + return creds + + +# ################ NOVA ################# +def get_instances(nova_client): + try: + instances = nova_client.servers.list(search_opts={'all_tenants': 1}) + return instances + except: + return None + + +def get_instance_status(nova_client, instance): + try: + instance = nova_client.servers.get(instance.id) + return instance.status + except: + return None + + +def get_instance_by_name(nova_client, instance_name): + try: + instance = nova_client.servers.find(name=instance_name) + return instance + except: + return None + + +def get_flavor_id(nova_client, flavor_name): + flavors = nova_client.flavors.list(detailed=True) + id = '' + for f in flavors: + if f.name == flavor_name: + id = f.id + break + return id + + +def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram): + flavors = nova_client.flavors.list(detailed=True) + id = '' + for f in flavors: + if min_ram <= f.ram and f.ram <= max_ram: + id = f.id + break + return id + + +def delete_instance(nova_client, instance_id): + try: + nova_client.servers.force_delete(instance_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def get_floating_ips(nova_client): + try: + floating_ips = nova_client.floating_ips.list() + return floating_ips + except: + return None + + +def delete_floating_ip(nova_client, floatingip_id): + try: + nova_client.floating_ips.delete(floatingip_id) + return True + except: + print "Error:", sys.exc_info()[0] + return None + + +# ################ NEUTRON ################# +def create_neutron_net(neutron_client, name): + json_body = {'network': {'name': name, + 'admin_state_up': True}} + try: + network = neutron_client.create_network(body=json_body) + network_dict = network['network'] + return network_dict['id'] + except: + print "Error:", sys.exc_info()[0] + return False + + +def update_neutron_net(neutron_client, network_id, shared=False): + json_body = {'network': {'shared': shared}} + try: + neutron_client.update_network(network_id, body=json_body) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def delete_neutron_net(neutron_client, network_id): + try: + neutron_client.delete_network(network_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def create_neutron_subnet(neutron_client, name, cidr, net_id): + json_body = {'subnets': [{'name': name, 'cidr': cidr, + 'ip_version': 4, 'network_id': net_id}]} + try: + subnet = neutron_client.create_subnet(body=json_body) + return subnet['subnets'][0]['id'] + except: + print "Error:", sys.exc_info()[0] + return False + + +def delete_neutron_subnet(neutron_client, subnet_id): + try: + neutron_client.delete_subnet(subnet_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def create_neutron_router(neutron_client, name): + json_body = {'router': {'name': name, 'admin_state_up': True}} + try: + router = neutron_client.create_router(json_body) + return router['router']['id'] + except: + print "Error:", sys.exc_info()[0] + return False + + +def delete_neutron_router(neutron_client, router_id): + json_body = {'router': {'id': router_id}} + try: + neutron_client.delete_router(router=router_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def add_interface_router(neutron_client, router_id, subnet_id): + json_body = {"subnet_id": subnet_id} + try: + neutron_client.add_interface_router(router=router_id, body=json_body) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def remove_interface_router(neutron_client, router_id, subnet_id): + json_body = {"subnet_id": subnet_id} + try: + neutron_client.remove_interface_router(router=router_id, + body=json_body) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def remove_gateway_router(neutron_client, router_id): + try: + neutron_client.remove_gateway_router(router_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def create_neutron_port(neutron_client, name, network_id, ip): + json_body = {'port': { + 'admin_state_up': True, + 'name': name, + 'network_id': network_id, + 'fixed_ips': [{"ip_address": ip}] + }} + try: + port = neutron_client.create_port(body=json_body) + return port['port']['id'] + except: + print "Error:", sys.exc_info()[0] + return False + + +def update_neutron_port(neutron_client, port_id, device_owner): + json_body = {'port': { + 'device_owner': device_owner, + }} + try: + port = neutron_client.update_port(port=port_id, + body=json_body) + return port['port']['id'] + except: + print "Error:", sys.exc_info()[0] + return False + + +def delete_neutron_port(neutron_client, port_id): + try: + neutron_client.delete_port(port_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def get_network_id(neutron_client, network_name): + networks = neutron_client.list_networks()['networks'] + id = '' + for n in networks: + if n['name'] == network_name: + id = n['id'] + break + return id + + +def check_neutron_net(neutron_client, net_name): + for network in neutron_client.list_networks()['networks']: + if network['name'] == net_name: + for subnet in network['subnets']: + return True + return False + + +def get_network_list(neutron_client): + network_list = neutron_client.list_networks()['networks'] + if len(network_list) == 0: + return None + else: + return network_list + + +def get_router_list(neutron_client): + router_list = neutron_client.list_routers()['routers'] + if len(router_list) == 0: + return None + else: + return router_list + + +def get_port_list(neutron_client): + port_list = neutron_client.list_ports()['ports'] + if len(port_list) == 0: + return None + else: + return port_list + + +def get_external_net(neutron_client): + for network in neutron_client.list_networks()['networks']: + if network['router:external']: + return network['name'] + return False + + +def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota): + json_body = {"quota": { + "security_group": sg_quota, + "security_group_rule": sg_rule_quota + }} + + try: + quota = neutron_client.update_quota(tenant_id=tenant_id, + body=json_body) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def update_cinder_quota(cinder_client, tenant_id, vols_quota, + snapshots_quota, gigabytes_quota): + quotas_values = {"volumes": vols_quota, + "snapshots": snapshots_quota, + "gigabytes": gigabytes_quota} + + try: + quotas_default = cinder_client.quotas.update(tenant_id, + **quotas_values) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def get_private_net(neutron_client): + # Checks if there is an existing shared private network + networks = neutron_client.list_networks()['networks'] + if len(networks) == 0: + return None + for net in networks: + if (net['router:external'] is False) and (net['shared'] is True): + return net + return None + + +# ################ GLANCE ################# +def get_images(nova_client): + try: + images = nova_client.images.list() + return images + except: + return None + + +def get_image_id(glance_client, image_name): + images = glance_client.images.list() + id = '' + for i in images: + if i.name == image_name: + id = i.id + break + return id + + +def create_glance_image(glance_client, image_name, file_path, public=True): + if not os.path.isfile(file_path): + print "Error: file " + file_path + " does not exist." + return False + try: + with open(file_path) as fimage: + image = glance_client.images.create(name=image_name, + is_public=public, + disk_format="qcow2", + container_format="bare", + data=fimage) + return image.id + except: + print "Error:", sys.exc_info()[0] + return False + + +def delete_glance_image(nova_client, image_id): + try: + nova_client.images.delete(image_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +# ################ CINDER ################# +def get_volumes(cinder_client): + try: + volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1}) + return volumes + except: + return None + + +def delete_volume(cinder_client, volume_id, forced=False): + try: + if forced: + try: + cinder_client.volumes.detach(volume_id) + except: + print "Error:", sys.exc_info()[0] + cinder_client.volumes.force_delete(volume_id) + else: + cinder_client.volumes.delete(volume_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +# ################ CINDER ################# +def get_security_groups(neutron_client): + try: + security_groups = neutron_client.list_security_groups()[ + 'security_groups'] + return security_groups + except: + return None + + +def delete_security_group(neutron_client, secgroup_id): + try: + neutron_client.delete_security_group(secgroup_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +# ################ KEYSTONE ################# +def get_tenants(keystone_client): + try: + tenants = keystone_client.tenants.list() + return tenants + except: + return None + + +def get_tenant_id(keystone_client, tenant_name): + tenants = keystone_client.tenants.list() + id = '' + for t in tenants: + if t.name == tenant_name: + id = t.id + break + return id + + +def get_users(keystone_client): + try: + users = keystone_client.users.list() + return users + except: + return None + + +def get_role_id(keystone_client, role_name): + roles = keystone_client.roles.list() + id = '' + for r in roles: + if r.name == role_name: + id = r.id + break + return id + + +def get_user_id(keystone_client, user_name): + users = keystone_client.users.list() + id = '' + for u in users: + if u.name == user_name: + id = u.id + break + return id + + +def create_tenant(keystone_client, tenant_name, tenant_description): + try: + tenant = keystone_client.tenants.create(tenant_name, + tenant_description, + enabled=True) + return tenant.id + except: + print "Error:", sys.exc_info()[0] + return False + + +def delete_tenant(keystone_client, tenant_id): + try: + tenant = keystone_client.tenants.delete(tenant_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def create_user(keystone_client, user_name, user_password, + user_email, tenant_id): + try: + user = keystone_client.users.create(user_name, user_password, + user_email, tenant_id, + enabled=True) + return user.id + except: + print "Error:", sys.exc_info()[0] + return False + + +def delete_user(keystone_client, user_id): + try: + tenant = keystone_client.users.delete(user_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def add_role_user(keystone_client, user_id, role_id, tenant_id): + try: + keystone_client.roles.add_user_role(user_id, role_id, tenant_id) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +# ################ UTILS ################# +def check_internet_connectivity(url='http://www.opnfv.org/'): + """ + Check if there is access to the internet + """ + try: + urllib2.urlopen(url, timeout=5) + return True + except urllib2.URLError: + return False + + +def download_url(url, dest_path): + """ + Download a file to a destination path given a URL + """ + name = url.rsplit('/')[-1] + dest = dest_path + "/" + name + try: + response = urllib2.urlopen(url) + except (urllib2.HTTPError, urllib2.URLError): + return False + + with open(dest, 'wb') as f: + shutil.copyfileobj(response, f) + return True + + +def execute_command(cmd, logger=None, exit_on_error=True): + """ + Execute Linux command + """ + if logger: + logger.debug('Executing command : {}'.format(cmd)) + output_file = "output.txt" + f = open(output_file, 'w+') + p = subprocess.call(cmd, shell=True, stdout=f, stderr=subprocess.STDOUT) + f.close() + f = open(output_file, 'r') + result = f.read() + if result != "" and logger: + logger.debug(result) + if p == 0: + return True + else: + if logger: + logger.error("Error when executing command %s" % cmd) + if exit_on_error: + exit(-1) + return False + + +def get_git_branch(repo_path): + """ + Get git branch name + """ + repo = Repo(repo_path) + branch = repo.active_branch + return branch.name + + +def get_installer_type(logger=None): + """ + Get installer type (fuel, apex, joid, compass) + """ + try: + installer = os.environ['INSTALLER_TYPE'] + except KeyError: + if logger: + logger.error("Impossible to retrieve the installer type") + installer = "Unkown" + + return installer + + +def get_pod_name(logger=None): + """ + Get PoD Name from env variable NODE_NAME + """ + try: + return os.environ['NODE_NAME'] + except KeyError: + if logger: + logger.error( + "Unable to retrieve the POD name from environment.Using pod name 'unknown-pod'") + return "unknown-pod" + + +def push_results_to_db(db_url, case_name, logger, pod_name, + git_version, payload): + url = db_url + "/results" + installer = get_installer_type(logger) + params = {"project_name": "functest", "case_name": case_name, + "pod_name": pod_name, "installer": installer, + "version": git_version, "details": payload} + + headers = {'Content-Type': 'application/json'} + try: + r = requests.post(url, data=json.dumps(params), headers=headers) + if logger: + logger.debug(r) + return True + except: + print "Error:", sys.exc_info()[0] + return False + + +def get_resolvconf_ns(): + nameservers = [] + rconf = open("/etc/resolv.conf", "r") + line = rconf.readline() + while line: + ip = re.search(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", line) + if ip: + nameservers.append(ip.group()) + line = rconf.readline() + return nameservers + +def getTestEnv(test, functest_yaml): + # get the config of the testcase based on functest_config.yaml + # 2 options + # - test = test project e.g; ovno + # - test = testcase e.g. functest/odl + # look for the / to see if it is a test project or a testcase + try: + TEST_ENV = functest_yaml.get("test-dependencies") + + if test.find("/") < 0: + config_test = TEST_ENV[test] + else: + test_split = test.split("/") + testproject = test_split[0] + testcase = test_split[1] + config_test = TEST_ENV[testproject][testcase] + except KeyError: + # if not defined in dependencies => no dependencies + config_test = "" + except: + print "Error getTestEnv:", sys.exc_info()[0] + + return config_test + + +def get_ci_envvars(): + """ + Get the CI env variables + """ + ci_env_var = { + "installer": os.environ.get('INSTALLER_TYPE'), + "scenario": os.environ.get('DEPLOY_SCENARIO')} + return ci_env_var + + +def isTestRunnable(test, functest_yaml): + # By default we assume that all the tests are always runnable... + is_runnable = True + # Retrieve CI environment + ci_env = get_ci_envvars() + # Retrieve test environement from config file + test_env = getTestEnv(test, functest_yaml) + + # if test_env not empty => dependencies to be checked + if test_env is not None and len(test_env) > 0: + # possible criteria = ["installer", "scenario"] + # consider test criteria from config file + # compare towards CI env through CI en variable + for criteria in test_env: + if re.search(test_env[criteria], ci_env[criteria]) is None: + # print "Test "+ test + " cannot be run on the environment" + is_runnable = False + return is_runnable + + +def generateTestcaseList(functest_yaml): + test_list = "" + # get testcases + testcase_list = functest_yaml.get("test-dependencies") + projects = testcase_list.keys() + + for project in projects: + testcases = testcase_list[project] + # 1 or 2 levels for testcases project[/case] + # if only project name without controller or scenario + # => shall be runnable on any controller/scenario + if testcases is None: + test_list += project + " " + else: + for testcase in testcases: + if testcase == "installer" or testcase == "scenario": + # project (1 level) + if isTestRunnable(project, functest_yaml): + test_list += project + " " + else: + # project/testcase (2 levels) + thetest = project + "/" + testcase + if isTestRunnable(thetest, functest_yaml): + test_list += testcase + " " + + # sort the list to execute the test in the right order + test_order_list = functest_yaml.get("test_exec_priority") + test_sorted_list = "" + for test in test_order_list: + if test_order_list[test] in test_list: + test_sorted_list += test_order_list[test] + " " + + # create a file that could be consumed by run-test.sh + # this method is used only for CI + # so it can be run only in container + # reuse default conf directory to store the list of runnable tests + file = open("/home/opnfv/functest/conf/testcase-list.txt", 'w') + file.write(test_sorted_list) + file.close() + + return test_sorted_list + diff --git a/testcases/tests/TestFunctestUtils.py b/testcases/tests/TestFunctestUtils.py new file mode 100644 index 000000000..6f12e603d --- /dev/null +++ b/testcases/tests/TestFunctestUtils.py @@ -0,0 +1,111 @@ +import unittest +import os +import sys +import yaml + +sys.path.append("../") +from functest_utils import getTestEnv, isTestRunnable, generateTestcaseList + + +class TestFunctestUtils(unittest.TestCase): + + def setUp(self): + os.environ["INSTALLER_TYPE"] = "fuel" + os.environ["DEPLOY_SCENARIO"] = "os-odl_l3-ovs-ha" + + global functest_yaml + + with open("../config_functest.yaml") as f: + functest_yaml = yaml.safe_load(f) + f.close() + + def test_getTestEnv(self): + + env_test = getTestEnv('ovno', functest_yaml) + self.assertEqual(env_test, {'scenario': 'ocl'}) + + env_test = getTestEnv('doctor', functest_yaml) + self.assertEqual(env_test, {'installer': 'fuel'}) + + env_test = getTestEnv('promise', functest_yaml) + self.assertEqual(env_test, {'installer': '(fuel)|(joid)'}) + + env_test = getTestEnv('functest/tempest', functest_yaml) + self.assertEqual(env_test, None) + + env_test = getTestEnv('functest/vims', functest_yaml) + self.assertEqual(env_test, None) + + env_test = getTestEnv('functest/odl', functest_yaml) + self.assertEqual(env_test, {'scenario': 'odl'}) + + env_test = getTestEnv('functest/onos', functest_yaml) + self.assertEqual(env_test, {'scenario': 'onos'}) + + env_test = getTestEnv('policy-test', functest_yaml) + self.assertEqual(env_test, {'scenario': 'odl'}) + + env_test = getTestEnv('sdnvpn/odl-vpn_service-tests', functest_yaml) + self.assertEqual(env_test, + {'installer': 'fuel', 'scenario': '(ovs)*(odl)'}) + + env_test = getTestEnv('sdnvpn/opnfv-yardstick-tc026-sdnvpn', + functest_yaml) + self.assertEqual(env_test, + {'installer': 'fuel', 'scenario': '(ovs)*(nosdn)'}) + + env_test = getTestEnv('foo', functest_yaml) + self.assertEqual(env_test, '') + + def test_isTestRunnable(self): + + test = isTestRunnable('ovno', functest_yaml) + self.assertFalse(test) + + test = isTestRunnable('doctor', functest_yaml) + self.assertTrue(test) + + test = isTestRunnable('promise', functest_yaml) + self.assertTrue(test) + + test = isTestRunnable('functest/onos', functest_yaml) + self.assertFalse(test) + + test = isTestRunnable('functest/odl', functest_yaml) + self.assertTrue(test) + + test = isTestRunnable('functest/vping', functest_yaml) + self.assertTrue(test) + + test = isTestRunnable('functest/tempest', functest_yaml) + self.assertTrue(test) + + test = isTestRunnable('functest/rally', functest_yaml) + self.assertTrue(test) + + test = isTestRunnable('functest/vims', functest_yaml) + self.assertTrue(test) + + test = isTestRunnable('sdnvpn/odl-vpn_service-tests', + functest_yaml) + self.assertTrue(test) + + test = isTestRunnable('sdnvpn/opnfv-yardstick-tc026-sdnvpn', + functest_yaml) + self.assertFalse(test) + + def test_generateTestcaseList(self): + + test = generateTestcaseList(functest_yaml) + + expected_list = "vping tempest odl doctor promise policy-test odl-vpn_service-tests vims rally " + self.assertEqual(test, expected_list) + + def tearDown(self): + os.environ["INSTALLER_TYPE"] = "" + os.environ["DEPLOY_SCENARIO"] = "" + + +if __name__ == '__main__': + unittest.main() + diff --git a/testcases/vIMS/CI/clearwater.py b/testcases/vIMS/CI/clearwater.py new file mode 100644 index 000000000..d2d189f60 --- /dev/null +++ b/testcases/vIMS/CI/clearwater.py @@ -0,0 +1,63 @@ +#!/usr/bin/python +# coding: utf8 +####################################################################### +# +# Copyright (c) 2015 Orange +# valentin.boucher@orange.com +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +######################################################################## +import sys +import subprocess + + +class clearwater: + + def __init__(self, inputs={}, orchestrator=None, logger=None): + self.config = inputs + self.orchestrator = orchestrator + self.logger = logger + self.deploy = False + + def set_orchestrator(self, orchestrator): + self.orchestrator = orchestrator + + def set_flavor_id(self, flavor_id): + self.config['flavor_id'] = flavor_id + + def set_image_id(self, image_id): + self.config['image_id'] = image_id + + def set_agent_user(self, agent_user): + self.config['agent_user'] = agent_user + + def set_external_network_name(self, external_network_name): + self.config['external_network_name'] = external_network_name + + def set_public_domain(self, public_domain): + self.config['public_domain'] = public_domain + + def deploy_vnf(self, blueprint, bp_name='clearwater', dep_name='clearwater-opnfv'): + if self.orchestrator: + self.dep_name = dep_name + self.orchestrator.download_upload_and_deploy_blueprint( + blueprint, self.config, bp_name, dep_name) + self.deploy = True + else: + if self.logger: + logger.error("Cloudify manager is down or not provide...") + + def undeploy_vnf(self): + if self.orchestrator: + if self.deploy: + self.deploy = False + self.orchestrator.undeploy_deployment(self.dep_name) + else: + if self.logger: + logger.error("Clearwater isn't already deploy...") + else: + if self.logger: + logger.error("Cloudify manager is down or not provide...") diff --git a/testcases/Controllers/ODL/CI/create_venv.sh b/testcases/vIMS/CI/create_venv.sh index 5d0733a5a..15294f77b 100644..100755 --- a/testcases/Controllers/ODL/CI/create_venv.sh +++ b/testcases/vIMS/CI/create_venv.sh @@ -4,7 +4,8 @@ # It requires python2.7 and virtualenv packages installed BASEDIR=`dirname $0` - +VENV_PATH=$1 +VENV_NAME="venv_cloudify" function venv_install() { if command -v virtualenv-2.7; then virtualenv-2.7 $1 @@ -13,22 +14,22 @@ function venv_install() { elif command -v virtualenv; then virtualenv $1 else - echo Please make sure virtualenv package is installed. + echo Cannot find virtualenv command. return 1 fi } # exit when something goes wrong during venv install set -e -if [ ! -d "$BASEDIR/venv" ]; then - venv_install $BASEDIR/venv - echo "Virtualenv created." +if [ ! -d "$VENV_PATH/$VENV_NAME" ]; then + venv_install $VENV_PATH/$VENV_NAME + echo "Virtualenv" + $VENV_NAME + "created." fi -if [ ! -f "$BASEDIR/venv/updated" -o $BASEDIR/requirements.pip -nt $BASEDIR/venv/updated ]; then - source $BASEDIR/venv/bin/activate +if [ ! -f "$VENV_PATH/$VENV_NAME/updated" -o $BASEDIR/requirements.pip -nt $VENV_PATH/$VENV_NAME/updated ]; then + source $VENV_PATH/$VENV_NAME/bin/activate pip install -r $BASEDIR/requirements.pip - touch $BASEDIR/venv/updated + touch $VENV_PATH/$VENV_NAME/updated echo "Requirements installed." deactivate fi diff --git a/testcases/vIMS/CI/orchestrator.py b/testcases/vIMS/CI/orchestrator.py new file mode 100644 index 000000000..382fbd139 --- /dev/null +++ b/testcases/vIMS/CI/orchestrator.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# coding: utf8 +####################################################################### +# +# Copyright (c) 2015 Orange +# valentin.boucher@orange.com +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +######################################################################## +import sys +import subprocess +import os +import shutil +import yaml +from git import Repo + + +class orchestrator: + + def __init__(self, testcase_dir, inputs={}, logger=None): + self.testcase_dir = testcase_dir + self.blueprint_dir = testcase_dir + 'cloudify-manager-blueprint/' + self.input_file = 'inputs.yaml' + self.manager_blueprint = False + self.config = inputs + self.logger = logger + self.manager_up = False + + def set_credentials(self, username, password, tenant_name, auth_url): + self.config['keystone_username'] = username + self.config['keystone_password'] = password + self.config['keystone_url'] = auth_url + self.config['keystone_tenant_name'] = tenant_name + + def set_flavor_id(self, flavor_id): + self.config['flavor_id'] = flavor_id + + def set_image_id(self, image_id): + self.config['image_id'] = image_id + + def set_external_network_name(self, external_network_name): + self.config['external_network_name'] = external_network_name + + def set_ssh_user(self, ssh_user): + self.config['ssh_user'] = ssh_user + + def set_nameservers(self, nameservers): + if 0 < len(nameservers): + self.config['dns_subnet_1'] = nameservers[0] + if 1 < len(nameservers): + self.config['dns_subnet_2'] = nameservers[1] + + def set_logger(self, logger): + self.logger = logger + + def download_manager_blueprint(self, manager_blueprint_url, manager_blueprint_branch): + if self.manager_blueprint: + if self.logger: + self.logger.info( + "cloudify manager server blueprint is already downloaded !") + else: + if self.logger: + self.logger.info( + "Downloading the cloudify manager server blueprint") + download_result = download_blueprints( + manager_blueprint_url, manager_blueprint_branch, self.blueprint_dir) + + if not download_result: + if self.logger: + self.logger.error("Failed to download manager blueprint") + exit(-1) + else: + self.manager_blueprint = True + + def manager_up(self): + return manager_up + + def deploy_manager(self): + if self.manager_blueprint: + if self.logger: + self.logger.info("Writing the inputs file") + with open(self.blueprint_dir + "inputs.yaml", "w") as f: + f.write(yaml.dump(self.config, default_style='"')) + f.close() + + # Ensure no ssh key file already exists + key_files = ["/.ssh/cloudify-manager-kp.pem", + "/.ssh/cloudify-agent-kp.pem"] + home = os.path.expanduser("~") + + for key_file in key_files: + if os.path.isfile(home + key_file): + os.remove(home + key_file) + + if self.logger: + self.logger.info("Launching the cloudify-manager deployment") + script = "set -e; " + script += "source " + self.testcase_dir + "venv_cloudify/bin/activate; " + script += "cd " + self.testcase_dir + "; " + script += "cfy init -r; " + script += "cd cloudify-manager-blueprint; " + script += "cfy local create-requirements -o requirements.txt -p openstack-manager-blueprint.yaml; " + script += "pip install -r requirements.txt; " + script += "timeout 1800 cfy bootstrap --install-plugins -p openstack-manager-blueprint.yaml -i inputs.yaml; " + cmd = "/bin/bash -c '" + script + "'" + execute_command(cmd, self.logger) + + if self.logger: + self.logger.info("Cloudify-manager server is UP !") + + self.manager_up = True + + def undeploy_manager(self): + if self.logger: + self.logger.info("Launching the cloudify-manager undeployment") + + self.manager_up = False + + script = "source " + self.testcase_dir + "venv_cloudify/bin/activate; " + script += "cd " + self.testcase_dir + "; " + script += "cfy teardown -f --ignore-deployments; " + cmd = "/bin/bash -c '" + script + "'" + execute_command(cmd, self.logger) + + if self.logger: + self.logger.info( + "Cloudify-manager server has been successfully removed!") + + def download_upload_and_deploy_blueprint(self, blueprint, config, bp_name, dep_name): + if self.logger: + self.logger.info("Downloading the {0} blueprint".format( + blueprint['file_name'])) + download_result = download_blueprints(blueprint['url'], blueprint['branch'], + self.testcase_dir + blueprint['destination_folder']) + + if not download_result: + if self.logger: + self.logger.error( + "Failed to download blueprint {0}".format(blueprint['file_name'])) + exit(-1) + + if self.logger: + self.logger.info("Writing the inputs file") + with open(self.testcase_dir + blueprint['destination_folder'] + "/inputs.yaml", "w") as f: + f.write(yaml.dump(config, default_style='"')) + f.close() + + if self.logger: + self.logger.info("Launching the {0} deployment".format(bp_name)) + script = "source " + self.testcase_dir + "venv_cloudify/bin/activate; " + script += "cd " + self.testcase_dir + \ + blueprint['destination_folder'] + "; " + script += "cfy blueprints upload -b " + \ + bp_name + " -p openstack-blueprint.yaml; " + script += "cfy deployments create -b " + bp_name + \ + " -d " + dep_name + " --inputs inputs.yaml; " + script += "cfy executions start -w install -d " + dep_name + " --timeout 1800; " + + cmd = "/bin/bash -c '" + script + "'" + execute_command(cmd, self.logger) + + if self.logger: + self.logger.info("The deployment of {0} is ended".format(dep_name)) + + def undeploy_deployment(self, dep_name): + if self.logger: + self.logger.info("Launching the {0} undeployment".format(dep_name)) + script = "source " + self.testcase_dir + "venv_cloudify/bin/activate; " + script += "cd " + self.testcase_dir + "; " + script += "cfy executions start -w uninstall -d " + dep_name + " --timeout 1800 ; " + script += "cfy deployments delete -d " + dep_name + "; " + + cmd = "/bin/bash -c '" + script + "'" + try: + execute_command(cmd, self.logger) + except: + if self.logger: + self.logger.error("Clearwater undeployment failed") + + +def execute_command(cmd, logger): + """ + Execute Linux command + """ + if logger: + logger.debug('Executing command : {}'.format(cmd)) + output_file = "output.txt" + f = open(output_file, 'w+') + p = subprocess.call(cmd, shell=True, stdout=f, stderr=subprocess.STDOUT) + f.close() + f = open(output_file, 'r') + result = f.read() + if result != "" and logger: + logger.debug(result) + if p == 0: + return True + else: + if logger: + logger.error("Error when executing command %s" % cmd) + exit(-1) + + +def download_blueprints(blueprint_url, branch, dest_path): + if os.path.exists(dest_path): + shutil.rmtree(dest_path) + try: + Repo.clone_from(blueprint_url, dest_path, branch=branch) + return True + except: + return False diff --git a/testcases/vIMS/CI/requirements.pip b/testcases/vIMS/CI/requirements.pip new file mode 100644 index 000000000..9b9d0ba53 --- /dev/null +++ b/testcases/vIMS/CI/requirements.pip @@ -0,0 +1 @@ +cloudify==3.3
\ No newline at end of file diff --git a/testcases/vIMS/CI/vIMS.py b/testcases/vIMS/CI/vIMS.py new file mode 100644 index 000000000..eae821ad4 --- /dev/null +++ b/testcases/vIMS/CI/vIMS.py @@ -0,0 +1,480 @@ +#!/usr/bin/python +# coding: utf8 +####################################################################### +# +# Copyright (c) 2015 Orange +# valentin.boucher@orange.com +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +######################################################################## + +import os +import time +import subprocess +import logging +import argparse +import yaml +import pprint +import sys +import shutil +import json +import datetime +from git import Repo +import keystoneclient.v2_0.client as ksclient +import glanceclient.client as glclient +import novaclient.client as nvclient +from neutronclient.v2_0 import client as ntclient + +from orchestrator import * +from clearwater import * + +import urllib +pp = pprint.PrettyPrinter(indent=4) + + +parser = argparse.ArgumentParser() +parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") +parser.add_argument("-r", "--report", + help="Create json result file", + action="store_true") +args = parser.parse_args() + +""" logging configuration """ +logger = logging.getLogger('vIMS') +logger.setLevel(logging.DEBUG) + +ch = logging.StreamHandler() +if args.debug: + ch.setLevel(logging.DEBUG) +else: + ch.setLevel(logging.INFO) +formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + +REPO_PATH = os.environ['repos_dir'] + '/functest/' +if not os.path.exists(REPO_PATH): + logger.error("Functest repository directory not found '%s'" % REPO_PATH) + exit(-1) +sys.path.append(REPO_PATH + "testcases/") +import functest_utils + +with open("/home/opnfv/functest/conf/config_functest.yaml") as f: + functest_yaml = yaml.safe_load(f) +f.close() + +# Cloudify parameters +VIMS_DIR = REPO_PATH + \ + functest_yaml.get("general").get("directories").get("dir_vIMS") +VIMS_DATA_DIR = functest_yaml.get("general").get( + "directories").get("dir_vIMS_data") + "/" +VIMS_TEST_DIR = functest_yaml.get("general").get( + "directories").get("dir_repo_vims_test") + "/" +TEST_DB = functest_yaml.get("results").get("test_db_url") + +TENANT_NAME = functest_yaml.get("vIMS").get("general").get("tenant_name") +TENANT_DESCRIPTION = functest_yaml.get("vIMS").get( + "general").get("tenant_description") +IMAGES = functest_yaml.get("vIMS").get("general").get("images") + +CFY_MANAGER_BLUEPRINT = functest_yaml.get( + "vIMS").get("cloudify").get("blueprint") +CFY_MANAGER_REQUIERMENTS = functest_yaml.get( + "vIMS").get("cloudify").get("requierments") +CFY_INPUTS = functest_yaml.get("vIMS").get("cloudify").get("inputs") + +CW_BLUEPRINT = functest_yaml.get("vIMS").get("clearwater").get("blueprint") +CW_DEPLOYMENT_NAME = functest_yaml.get("vIMS").get( + "clearwater").get("deployment-name") +CW_INPUTS = functest_yaml.get("vIMS").get("clearwater").get("inputs") +CW_REQUIERMENTS = functest_yaml.get("vIMS").get( + "clearwater").get("requierments") + +CFY_DEPLOYMENT_DURATION = 0 +CW_DEPLOYMENT_DURATION = 0 + + +def download_and_add_image_on_glance(glance, image_name, image_url): + dest_path = VIMS_DATA_DIR + "tmp/" + if not os.path.exists(dest_path): + os.makedirs(dest_path) + file_name = image_url.rsplit('/')[-1] + if not functest_utils.download_url(image_url, dest_path): + logger.error("Failed to download image %s" % file_name) + return False + + image = functest_utils.create_glance_image( + glance, image_name, dest_path + file_name) + if not image: + logger.error("Failed to upload image on glance") + return False + + return image + + +def test_clearwater(): + + time.sleep(180) + + script = "source " + VIMS_DATA_DIR + "venv_cloudify/bin/activate; " + script += "cd " + VIMS_DATA_DIR + "; " + script += "cfy deployments outputs -d " + CW_DEPLOYMENT_NAME + \ + " | grep Value: | sed \"s/ *Value: //g\";" + cmd = "/bin/bash -c '" + script + "'" + + try: + logger.debug("Trying to get clearwater nameserver IP ... ") + dns_ip = os.popen(cmd).read() + dns_ip = dns_ip.splitlines()[0] + except: + logger.error("Unable to retrieve the IP of the DNS server !") + + start_time_ts = time.time() + end_time_ts = start_time_ts + logger.info("vIMS functional test Start Time:'%s'" % ( + datetime.datetime.fromtimestamp(start_time_ts).strftime( + '%Y-%m-%d %H:%M:%S'))) + nameservers = functest_utils.get_resolvconf_ns() + resolvconf = "" + for ns in nameservers: + resolvconf += "\nnameserver " + ns + + if dns_ip != "": + script = 'echo -e "nameserver ' + dns_ip + resolvconf + '" > /etc/resolv.conf; ' + script += 'source /etc/profile.d/rvm.sh; ' + script += 'cd ' + VIMS_TEST_DIR + '; ' + script += 'rake test[' + \ + CW_INPUTS["public_domain"] + '] SIGNUP_CODE="secret"' + + cmd = "/bin/bash -c '" + script + "'" + output_file = "output.txt" + f = open(output_file, 'w+') + p = subprocess.call(cmd, shell=True, stdout=f, + stderr=subprocess.STDOUT) + f.close() + end_time_ts = time.time() + duration = round(end_time_ts - start_time_ts, 1) + logger.info("vIMS functional test duration:'%s'" % duration) + f = open(output_file, 'r') + result = f.read() + if result != "" and logger: + logger.debug(result) + + vims_test_result = "" + try: + logger.debug("Trying to load test results") + with open(VIMS_TEST_DIR + "temp.json") as f: + vims_test_result = json.load(f) + f.close() + except: + logger.error("Unable to retrieve test results") + + if vims_test_result != "": + if args.report: + logger.debug("Push result into DB") + logger.debug("Pushing results to DB....") + git_version = functest_utils.get_git_branch(REPO_PATH) + functest_utils.push_results_to_db(db_url=TEST_DB, case_name="vIMS", + logger=logger, pod_name=functest_utils.get_pod_name(logger), git_version=git_version, + payload={'orchestrator': {'duration': CFY_DEPLOYMENT_DURATION, + 'result': ""}, + 'vIMS': {'duration': CW_DEPLOYMENT_DURATION, + 'result': ""}, + 'sig_test': {'duration': duration, + 'result': vims_test_result}}) + try: + os.remove(VIMS_TEST_DIR + "temp.json") + except: + logger.error("Deleting file failed") + + +def main(): + + ################Â GENERAL INITIALISATION ################ + + if not os.path.exists(VIMS_DATA_DIR): + os.makedirs(VIMS_DATA_DIR) + + ks_creds = functest_utils.get_credentials("keystone") + nv_creds = functest_utils.get_credentials("nova") + nt_creds = functest_utils.get_credentials("neutron") + + logger.info("Prepare OpenStack plateform (create tenant and user)") + keystone = ksclient.Client(**ks_creds) + + user_id = functest_utils.get_user_id(keystone, ks_creds['username']) + if user_id == '': + logger.error("Error : Failed to get id of %s user" % + ks_creds['username']) + exit(-1) + + tenant_id = functest_utils.create_tenant( + keystone, TENANT_NAME, TENANT_DESCRIPTION) + if tenant_id == '': + logger.error("Error : Failed to create %s tenant" % TENANT_NAME) + exit(-1) + + roles_name = ["admin", "Admin"] + role_id = '' + for role_name in roles_name: + if role_id == '': + role_id = functest_utils.get_role_id(keystone, role_name) + + if role_id == '': + logger.error("Error : Failed to get id for %s role" % role_name) + + if not functest_utils.add_role_user(keystone, user_id, role_id, tenant_id): + logger.error("Error : Failed to add %s on tenant" % + ks_creds['username']) + + user_id = functest_utils.create_user( + keystone, TENANT_NAME, TENANT_NAME, None, tenant_id) + if user_id == '': + logger.error("Error : Failed to create %s user" % TENANT_NAME) + + logger.info("Update OpenStack creds informations") + ks_creds.update({ + "username": TENANT_NAME, + "password": TENANT_NAME, + "tenant_name": TENANT_NAME, + }) + + nt_creds.update({ + "tenant_name": TENANT_NAME, + }) + + nv_creds.update({ + "project_id": TENANT_NAME, + }) + + logger.info("Upload some OS images if it doesn't exist") + glance_endpoint = keystone.service_catalog.url_for(service_type='image', + endpoint_type='publicURL') + glance = glclient.Client(1, glance_endpoint, token=keystone.auth_token) + + for img in IMAGES.keys(): + image_name = IMAGES[img]['image_name'] + image_url = IMAGES[img]['image_url'] + + image_id = functest_utils.get_image_id(glance, image_name) + + if image_id == '': + logger.info("""%s image doesn't exist on glance repository. + Try downloading this image and upload on glance !""" % image_name) + image_id = download_and_add_image_on_glance( + glance, image_name, image_url) + + if image_id == '': + logger.error( + "Error : Failed to find or upload required OS image for this deployment") + exit(-1) + + nova = nvclient.Client("2", **nv_creds) + + logger.info("Update security group quota for this tenant") + neutron = ntclient.Client(**nt_creds) + if not functest_utils.update_sg_quota(neutron, tenant_id, 50, 100): + logger.error( + "Failed to update security group quota for tenant %s" % TENANT_NAME) + exit(-1) + + logger.info("Update cinder quota for this tenant") + from cinderclient import client as cinderclient + + creds_cinder = functest_utils.get_credentials("cinder") + cinder_client = cinderclient.Client('1', creds_cinder['username'], + creds_cinder['api_key'], + creds_cinder['project_id'], + creds_cinder['auth_url'], + service_type="volume") + if not functest_utils.update_cinder_quota(cinder_client, tenant_id, 20, 10, 150): + logger.error("Failed to update cinder quota for tenant %s" % + TENANT_NAME) + exit(-1) + + ################Â CLOUDIFY INITIALISATION ################ + + cfy = orchestrator(VIMS_DATA_DIR, CFY_INPUTS, logger) + + cfy.set_credentials(username=ks_creds['username'], password=ks_creds[ + 'password'], tenant_name=ks_creds['tenant_name'], auth_url=ks_creds['auth_url']) + + logger.info("Collect flavor id for cloudify manager server") + nova = nvclient.Client("2", **nv_creds) + + flavor_name = "m1.medium" + flavor_id = functest_utils.get_flavor_id(nova, flavor_name) + for requirement in CFY_MANAGER_REQUIERMENTS: + if requirement == 'ram_min': + flavor_id = functest_utils.get_flavor_id_by_ram_range( + nova, CFY_MANAGER_REQUIERMENTS['ram_min'], 8196) + + if flavor_id == '': + logger.error( + "Failed to find %s flavor. Try with ram range default requirement !" % flavor_name) + flavor_id = functest_utils.get_flavor_id_by_ram_range(nova, 4000, 8196) + + if flavor_id == '': + logger.error( + "Failed to find required flavor for this deployment" % flavor_name) + exit(-1) + + cfy.set_flavor_id(flavor_id) + + image_name = "centos_7" + image_id = functest_utils.get_image_id(glance, image_name) + for requirement in CFY_MANAGER_REQUIERMENTS: + if requirement == 'os_image': + image_id = functest_utils.get_image_id( + glance, CFY_MANAGER_REQUIERMENTS['os_image']) + + if image_id == '': + logger.error( + "Error : Failed to find required OS image for cloudify manager") + exit(-1) + + cfy.set_image_id(image_id) + + ext_net = functest_utils.get_external_net(neutron) + if not ext_net: + logger.error("Failed to get external network") + exit(-1) + + cfy.set_external_network_name(ext_net) + + ns = functest_utils.get_resolvconf_ns() + if ns: + cfy.set_nameservers(ns) + + logger.info("Prepare virtualenv for cloudify-cli") + cmd = "chmod +x " + VIMS_DIR + "create_venv.sh" + functest_utils.execute_command(cmd, logger) + cmd = VIMS_DIR + "create_venv.sh " + VIMS_DATA_DIR + functest_utils.execute_command(cmd, logger) + + cfy.download_manager_blueprint( + CFY_MANAGER_BLUEPRINT['url'], CFY_MANAGER_BLUEPRINT['branch']) + + ################Â CLOUDIFY DEPLOYMENT ################ + start_time_ts = time.time() + end_time_ts = start_time_ts + logger.info("Cloudify deployment Start Time:'%s'" % ( + datetime.datetime.fromtimestamp(start_time_ts).strftime( + '%Y-%m-%d %H:%M:%S'))) + + cfy.deploy_manager() + + global CFY_DEPLOYMENT_DURATION + end_time_ts = time.time() + CFY_DEPLOYMENT_DURATION = round(end_time_ts - start_time_ts, 1) + logger.info("Cloudify deployment duration:'%s'" % CFY_DEPLOYMENT_DURATION) + + ################Â CLEARWATER INITIALISATION ################ + + cw = clearwater(CW_INPUTS, cfy, logger) + + logger.info("Collect flavor id for all clearwater vm") + nova = nvclient.Client("2", **nv_creds) + + flavor_name = "m1.small" + flavor_id = functest_utils.get_flavor_id(nova, flavor_name) + for requirement in CW_REQUIERMENTS: + if requirement == 'ram_min': + flavor_id = functest_utils.get_flavor_id_by_ram_range( + nova, CW_REQUIERMENTS['ram_min'], 8196) + + if flavor_id == '': + logger.error( + "Failed to find %s flavor. Try with ram range default requirement !" % flavor_name) + flavor_id = functest_utils.get_flavor_id_by_ram_range(nova, 4000, 8196) + + if flavor_id == '': + logger.error( + "Failed to find required flavor for this deployment" % flavor_name) + exit(-1) + + cw.set_flavor_id(flavor_id) + + image_name = "ubuntu_14.04" + image_id = functest_utils.get_image_id(glance, image_name) + for requirement in CW_REQUIERMENTS: + if requirement == 'os_image': + image_id = functest_utils.get_image_id( + glance, CW_REQUIERMENTS['os_image']) + + if image_id == '': + logger.error( + "Error : Failed to find required OS image for cloudify manager") + exit(-1) + + cw.set_image_id(image_id) + + ext_net = functest_utils.get_external_net(neutron) + if not ext_net: + logger.error("Failed to get external network") + exit(-1) + + cw.set_external_network_name(ext_net) + + ################Â CLEARWATER DEPLOYMENT ################ + + start_time_ts = time.time() + end_time_ts = start_time_ts + logger.info("vIMS VNF deployment Start Time:'%s'" % ( + datetime.datetime.fromtimestamp(start_time_ts).strftime( + '%Y-%m-%d %H:%M:%S'))) + + cw.deploy_vnf(CW_BLUEPRINT) + + global CW_DEPLOYMENT_DURATION + end_time_ts = time.time() + CW_DEPLOYMENT_DURATION = round(end_time_ts - start_time_ts, 1) + logger.info("vIMS VNF deployment duration:'%s'" % CW_DEPLOYMENT_DURATION) + + ################Â CLEARWATER TEST ################ + + test_clearwater() + + ###########Â CLEARWATER UNDEPLOYMENT ############ + + cw.undeploy_vnf() + + ############Â CLOUDIFY UNDEPLOYMENT ############# + + cfy.undeploy_manager() + + ############### GENERAL CLEANUP ################ + + ks_creds = functest_utils.get_credentials("keystone") + + keystone = ksclient.Client(**ks_creds) + + logger.info("Removing %s tenant .." % CFY_INPUTS['keystone_tenant_name']) + tenant_id = functest_utils.get_tenant_id( + keystone, CFY_INPUTS['keystone_tenant_name']) + if tenant_id == '': + logger.error("Error : Failed to get id of %s tenant" % + CFY_INPUTS['keystone_tenant_name']) + else: + if not functest_utils.delete_tenant(keystone, tenant_id): + logger.error("Error : Failed to remove %s tenant" % + CFY_INPUTS['keystone_tenant_name']) + + logger.info("Removing %s user .." % CFY_INPUTS['keystone_username']) + user_id = functest_utils.get_user_id( + keystone, CFY_INPUTS['keystone_username']) + if user_id == '': + logger.error("Error : Failed to get id of %s user" % + CFY_INPUTS['keystone_username']) + else: + if not functest_utils.delete_user(keystone, user_id): + logger.error("Error : Failed to remove %s user" % + CFY_INPUTS['keystone_username']) + + +if __name__ == '__main__': + main() diff --git a/testcases/vIMS/vIMS.md b/testcases/vIMS/vIMS.md new file mode 100644 index 000000000..68f86d9fa --- /dev/null +++ b/testcases/vIMS/vIMS.md @@ -0,0 +1,3 @@ +# vIMS README + + diff --git a/testcases/vPing/CI/libraries/vPing.py b/testcases/vPing/CI/libraries/vPing.py index b81ebb881..be0d2341a 100644 --- a/testcases/vPing/CI/libraries/vPing.py +++ b/testcases/vPing/CI/libraries/vPing.py @@ -1,277 +1,482 @@ #!/usr/bin/python # -# Copyright (c) 2015 All rights reserved. This program and the accompanying materials +# Copyright (c) 2015 All rights reserved +# This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# This script boots the VM1 and allocates IP address from Nova +# 0.1: This script boots the VM1 and allocates IP address from Nova # Later, the VM2 boots then execute cloud-init to ping VM1. # After successful ping, both the VMs are deleted. +# 0.2: measure test duration and publish results under json format # -# Note: this is script works only with Ubuntu image, not with Cirros image # -import os, time, subprocess, logging, argparse, yaml +import os +import time +import argparse import pprint -import novaclient.v2.client as novaclient -import neutronclient.client as neutronclient -#import novaclient.v1_1.client as novaclient -import cinderclient.v1.client as cinderclient -pp = pprint.PrettyPrinter(indent=4) +import sys +import logging +import yaml +import datetime +from novaclient import client as novaclient +from neutronclient.v2_0 import client as neutronclient +from keystoneclient.v2_0 import client as keystoneclient +from glanceclient import client as glanceclient -EXIT_CODE = -1 -HOME = os.environ['HOME']+"/" -with open(HOME+'.functest/functest.yaml') as f: - functest_yaml = yaml.safe_load(f) -f.close() +pp = pprint.PrettyPrinter(indent=4) -PING_TIMEOUT = functest_yaml.get("vping").get("ping_timeout") -NAME_VM_1 = functest_yaml.get("vping").get("vm_name_1") -NAME_VM_2 = functest_yaml.get("vping").get("vm_name_2") -GLANCE_IMAGE_NAME = functest_yaml.get("general").get("openstack").get("image_name") -NEUTRON_NET_NAME = functest_yaml.get("general").get("openstack").get("neutron_net_name") -FLAVOR = functest_yaml.get("vping").get("vm_flavor") +parser = argparse.ArgumentParser() +parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") +parser.add_argument("-r", "--report", + help="Create json result file", + action="store_true") -parser = argparse.ArgumentParser() -parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") args = parser.parse_args() """ logging configuration """ + logger = logging.getLogger('vPing') logger.setLevel(logging.DEBUG) ch = logging.StreamHandler() + if args.debug: ch.setLevel(logging.DEBUG) else: ch.setLevel(logging.INFO) -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + +formatter = logging.Formatter('%(asctime)s - %(name)s' + '- %(levelname)s - %(message)s') + ch.setFormatter(formatter) logger.addHandler(ch) +REPO_PATH=os.environ['repos_dir']+'/functest/' +if not os.path.exists(REPO_PATH): + logger.error("Functest repository directory not found '%s'" % REPO_PATH) + exit(-1) +sys.path.append(REPO_PATH + "testcases/") +import functest_utils + +with open("/home/opnfv/functest/conf/config_functest.yaml") as f: + functest_yaml = yaml.safe_load(f) +f.close() + +HOME = os.environ['HOME'] + "/" +# vPing parameters +VM_BOOT_TIMEOUT = 180 +VM_DELETE_TIMEOUT = 100 +PING_TIMEOUT = functest_yaml.get("vping").get("ping_timeout") +TEST_DB = functest_yaml.get("results").get("test_db_url") +NAME_VM_1 = functest_yaml.get("vping").get("vm_name_1") +NAME_VM_2 = functest_yaml.get("vping").get("vm_name_2") +IP_1 = functest_yaml.get("vping").get("ip_1") +IP_2 = functest_yaml.get("vping").get("ip_2") +# GLANCE_IMAGE_NAME = functest_yaml.get("general"). \ +# get("openstack").get("image_name") +GLANCE_IMAGE_NAME = "functest-vping" +GLANCE_IMAGE_FILENAME = functest_yaml.get("general"). \ + get("openstack").get("image_file_name") +GLANCE_IMAGE_FORMAT = functest_yaml.get("general"). \ + get("openstack").get("image_disk_format") +GLANCE_IMAGE_PATH = functest_yaml.get("general"). \ + get("directories").get("dir_functest_data") + "/" + GLANCE_IMAGE_FILENAME + + +FLAVOR = functest_yaml.get("vping").get("vm_flavor") + +# NEUTRON Private Network parameters + +NEUTRON_PRIVATE_NET_NAME = functest_yaml.get("vping"). \ + get("vping_private_net_name") + +NEUTRON_PRIVATE_SUBNET_NAME = functest_yaml.get("vping"). \ + get("vping_private_subnet_name") + +NEUTRON_PRIVATE_SUBNET_CIDR = functest_yaml.get("vping"). \ + get("vping_private_subnet_cidr") + +NEUTRON_ROUTER_NAME = functest_yaml.get("vping"). \ + get("vping_router_name") def pMsg(value): + """pretty printing""" pp.pprint(value) -def print_title(title): - """Print titles""" - print "\n"+"#"*40+"\n# "+title+"\n"+"#"*40+"\n" - -def get_credentials(service): - """Returns a creds dictionary filled with the following keys: - * username - * password/api_key (depending on the service) - * tenant_name/project_id (depending on the service) - * auth_url - :param service: a string indicating the name of the service - requesting the credentials. - """ - #TODO: get credentials from the openrc file - creds = {} - # Unfortunately, each of the OpenStack client will request slightly - # different entries in their credentials dict. - if service.lower() in ("nova", "cinder"): - password = "api_key" - tenant = "project_id" - else: - password = "password" - tenant = "tenant_name" - # The most common way to pass these info to the script is to do it through - # environment variables. - creds.update({ - "username": os.environ.get('OS_USERNAME', "admin"), # add your cloud username details - password: os.environ.get("OS_PASSWORD", 'admin'), # add password - "auth_url": os.environ.get("OS_AUTH_URL","http://192.168.20.71:5000/v2.0"), # Auth URL - tenant: os.environ.get("OS_TENANT_NAME", "admin"), - }) +def waitVmActive(nova, vm): - return creds + # sleep and wait for VM status change + sleep_time = 3 + count = VM_BOOT_TIMEOUT / sleep_time + while True: + status = functest_utils.get_instance_status(nova, vm) + logger.debug("Status: %s" % status) + if status == "ACTIVE": + return True + if status == "ERROR" or status == "error": + return False + if count == 0: + logger.debug("Booting a VM timed out...") + return False + count -= 1 + time.sleep(sleep_time) + return False + + +def waitVmDeleted(nova, vm): + + # sleep and wait for VM status change + sleep_time = 3 + count = VM_DELETE_TIMEOUT / sleep_time + while True: + status = functest_utils.get_instance_status(nova, vm) + if not status: + return True + elif count == 0: + logger.debug("Timeout") + return False + else: + # return False + count -= 1 + time.sleep(sleep_time) + return False -def get_server(creds, servername): - nova = novaclient.Client(**creds) - return nova.servers.find(name=servername) +def create_private_neutron_net(neutron): + neutron.format = 'json' + logger.info('Creating neutron network %s...' % NEUTRON_PRIVATE_NET_NAME) + network_id = functest_utils. \ + create_neutron_net(neutron, NEUTRON_PRIVATE_NET_NAME) -def waitVmActive(nova,vm): - # sleep and wait for VM status change - while get_status(nova,vm) != "ACTIVE": - time.sleep(3) - logger.debug("Status: %s" % vm.status) - logger.debug("Status: %s" % vm.status) + if not network_id: + return False + logger.debug("Network '%s' created successfully" % network_id) + logger.debug('Creating Subnet....') + subnet_id = functest_utils. \ + create_neutron_subnet(neutron, + NEUTRON_PRIVATE_SUBNET_NAME, + NEUTRON_PRIVATE_SUBNET_CIDR, + network_id) + if not subnet_id: + return False + logger.debug("Subnet '%s' created successfully" % subnet_id) + logger.debug('Creating Router...') + router_id = functest_utils. \ + create_neutron_router(neutron, NEUTRON_ROUTER_NAME) -def get_status(nova,vm): - vm = nova.servers.get(vm.id) - return vm.status + if not router_id: + return False + + logger.debug("Router '%s' created successfully" % router_id) + logger.debug('Adding router to subnet...') + + result = functest_utils.add_interface_router(neutron, router_id, subnet_id) + + if not result: + return False + + logger.debug("Interface added successfully.") + network_dic = {'net_id': network_id, + 'subnet_id': subnet_id, + 'router_id': router_id} + return network_dic + + +def cleanup(nova, neutron, image_id, network_dic, port_id1, port_id2): + + # delete both VMs + logger.info("Cleaning up...") + logger.debug("Deleting image...") + if not functest_utils.delete_glance_image(nova, image_id): + logger.error("Error deleting the glance image") + + vm1 = functest_utils.get_instance_by_name(nova, NAME_VM_1) + if vm1: + logger.debug("Deleting '%s'..." % NAME_VM_1) + nova.servers.delete(vm1) + # wait until VMs are deleted + if not waitVmDeleted(nova, vm1): + logger.error( + "Instance '%s' with cannot be deleted. Status is '%s'" % ( + NAME_VM_1, functest_utils.get_instance_status(nova, vm1))) + else: + logger.debug("Instance %s terminated." % NAME_VM_1) + + vm2 = functest_utils.get_instance_by_name(nova, NAME_VM_2) + + if vm2: + logger.debug("Deleting '%s'..." % NAME_VM_2) + vm2 = nova.servers.find(name=NAME_VM_2) + nova.servers.delete(vm2) + + if not waitVmDeleted(nova, vm2): + logger.error( + "Instance '%s' with cannot be deleted. Status is '%s'" % ( + NAME_VM_2, functest_utils.get_instance_status(nova, vm2))) + else: + logger.debug("Instance %s terminated." % NAME_VM_2) + + # delete created network + logger.info("Deleting network '%s'..." % NEUTRON_PRIVATE_NET_NAME) + net_id = network_dic["net_id"] + subnet_id = network_dic["subnet_id"] + router_id = network_dic["router_id"] + + if not functest_utils.delete_neutron_port(neutron, port_id1): + logger.error("Unable to remove port '%s'" % port_id1) + return False + logger.debug("Port '%s' removed successfully" % port_id1) + + if not functest_utils.delete_neutron_port(neutron, port_id2): + logger.error("Unable to remove port '%s'" % port_id2) + return False + logger.debug("Port '%s' removed successfully" % port_id2) + + if not functest_utils.remove_interface_router(neutron, router_id, + subnet_id): + logger.error("Unable to remove subnet '%s' from router '%s'" % ( + subnet_id, router_id)) + return False + + logger.debug("Interface removed successfully") + if not functest_utils.delete_neutron_router(neutron, router_id): + logger.error("Unable to delete router '%s'" % router_id) + return False + + logger.debug("Router deleted successfully") + + if not functest_utils.delete_neutron_subnet(neutron, subnet_id): + logger.error("Unable to delete subnet '%s'" % subnet_id) + return False + + logger.debug( + "Subnet '%s' deleted successfully" % NEUTRON_PRIVATE_SUBNET_NAME) + + if not functest_utils.delete_neutron_net(neutron, net_id): + logger.error("Unable to delete network '%s'" % net_id) + return False + + logger.debug( + "Network '%s' deleted successfully" % NEUTRON_PRIVATE_NET_NAME) + + return True def main(): - creds = get_credentials("nova") - nova = novaclient.Client(**creds) - cinder = cinderclient.Client(**creds) - - """ - # print images and server resources - # print nova_images - print_title("images list") - pMsg(nova.images.list()) - print_title("servers list") - pMsg(nova.servers.list()) - """ - # Check if the given image is created - images=nova.images.list() - image_found = False - for image in images: - if image.name == GLANCE_IMAGE_NAME: - logger.info("Glance image found '%s'" %image.name) - image_found = True - if not image_found: - logger.error("ERROR: Glance image %s not found." % GLANCE_IMAGE_NAME) + + creds_nova = functest_utils.get_credentials("nova") + nova_client = novaclient.Client('2',**creds_nova) + creds_neutron = functest_utils.get_credentials("neutron") + neutron_client = neutronclient.Client(**creds_neutron) + creds_keystone = functest_utils.get_credentials("keystone") + keystone_client = keystoneclient.Client(**creds_keystone) + glance_endpoint = keystone_client.service_catalog.url_for(service_type='image', + endpoint_type='publicURL') + glance_client = glanceclient.Client(1, glance_endpoint, + token=keystone_client.auth_token) + EXIT_CODE = -1 + + image = None + flavor = None + + logger.debug("Creating image '%s' from '%s'..." % (GLANCE_IMAGE_NAME, + GLANCE_IMAGE_PATH)) + image_id = functest_utils.create_glance_image(glance_client, + GLANCE_IMAGE_NAME,GLANCE_IMAGE_PATH) + if not image_id: + logger.error("Failed to create a Glance image...") + exit(-1) + + # Check if the given image exists + image = functest_utils.get_image_id(glance_client, GLANCE_IMAGE_NAME) + if image == '': + logger.error("ERROR: Glance image '%s' not found." % GLANCE_IMAGE_NAME) logger.info("Available images are: ") - pMsg(nova.images.list()) + pMsg(nova_client.images.list()) + exit(-1) + + network_dic = create_private_neutron_net(neutron_client) + + if not network_dic: + logger.error( + "There has been a problem when creating the neutron network") exit(-1) - # Check if the given neutron network is created - networks=nova.networks.list() - network_found = False - for net in networks: - if net.human_id == NEUTRON_NET_NAME: - logger.info("Network found '%s'" %net.human_id) - network_found = True - if not network_found: - logger.error("Neutron network %s not found." % NEUTRON_NET_NAME) - logger.info("Available networks are: ") - pMsg(nova.networks.list()) + network_id = network_dic["net_id"] + + # Check if the given flavor exists + + try: + flavor = nova_client.flavors.find(name=FLAVOR) + logger.info("Flavor found '%s'" % FLAVOR) + except: + logger.error("Flavor '%s' not found." % FLAVOR) + logger.info("Available flavors are: ") + pMsg(nova_client.flavor.list()) exit(-1) - servers=nova.servers.list() + # Deleting instances if they exist + + servers = nova_client.servers.list() for server in servers: if server.name == NAME_VM_1 or server.name == NAME_VM_2: - logger.info("Instance %s found. Deleting..." %server.name) + logger.info("Instance %s found. Deleting..." % server.name) server.delete() - - # boot VM 1 # basic boot - # tune (e.g. flavor, images, network) to your specific openstack configuration here - m = NAME_VM_1 - f = nova.flavors.find(name = FLAVOR) - i = nova.images.find(name = GLANCE_IMAGE_NAME) - n = nova.networks.find(label = NEUTRON_NET_NAME) - u = "#cloud-config\npassword: opnfv\nchpasswd: { expire: False }\nssh_pwauth: True" - #k = "demo-key" + # tune (e.g. flavor, images, network) to your specific + # openstack configuration here + # we consider start time at VM1 booting + start_time_ts = time.time() + end_time_ts = start_time_ts + logger.info("vPing Start Time:'%s'" % ( + datetime.datetime.fromtimestamp(start_time_ts).strftime( + '%Y-%m-%d %H:%M:%S'))) # create VM - logger.info("Creating instance '%s'..." %m) - logger.debug("Configuration:\n name=%s \n flavor=%s \n image=%s \n network=%s \n userdata= \n%s" %(m,f,i,n,u)) - vm1 = nova.servers.create( - name = m, - flavor = f, - image = i, - nics = [{"net-id": n.id}], - #key_name = k, - userdata = u, - ) + logger.debug("Creating port 'vping-port-1' with IP %s..." % IP_1) + port_id1 = functest_utils.create_neutron_port(neutron_client, + "vping-port-1", network_id, + IP_1) + if not port_id1: + logger.error("Unable to create port.") + exit(-1) - #pMsg(vm1) + logger.info("Creating instance '%s' with IP %s..." % (NAME_VM_1, IP_1)) + logger.debug( + "Configuration:\n name=%s \n flavor=%s \n image=%s \n " + "network=%s \n" % (NAME_VM_1, flavor, image, network_id)) + vm1 = nova_client.servers.create( + name=NAME_VM_1, + flavor=flavor, + image=image, + # nics = [{"net-id": network_id, "v4-fixed-ip": IP_1}] + nics=[{"port-id": port_id1}] + ) + # wait until VM status is active + if not waitVmActive(nova_client, vm1): - #wait until VM status is active - waitVmActive(nova,vm1) + logger.error("Instance '%s' cannot be booted. Status is '%s'" % ( + NAME_VM_1, functest_utils.get_instance_status(nova_client, vm1))) + cleanup(nova_client, neutron_client, image_id, network_dic, port_id1) + return (EXIT_CODE) + else: + logger.info("Instance '%s' is ACTIVE." % NAME_VM_1) - #retrieve IP of first VM - logger.debug("Fetching IP...") - server = get_server(creds, m) - #pMsg(server.networks) - # theoretically there is only one IP address so we take the first element of the table + # Retrieve IP of first VM + # logger.debug("Fetching IP...") + # server = functest_utils.get_instance_by_name(nova_client, NAME_VM_1) + # theoretically there is only one IP address so we take the + # first element of the table # Dangerous! To be improved! - test_ip = server.networks.get(NEUTRON_NET_NAME)[0] - logger.debug("Instance '%s' got %s" %(m,test_ip)) - test_cmd = '/tmp/vping.sh %s'%test_ip - + # test_ip = server.networks.get(NEUTRON_PRIVATE_NET_NAME)[0] + test_ip = IP_1 + logger.debug("Instance '%s' got %s" % (NAME_VM_1, test_ip)) # boot VM 2 # we will boot then execute a ping script with cloud-init # the long chain corresponds to the ping procedure converted with base 64 - # tune (e.g. flavor, images, network) to your specific openstack configuration here - m = NAME_VM_2 - f = nova.flavors.find(name = FLAVOR) - i = nova.images.find(name = GLANCE_IMAGE_NAME) - n = nova.networks.find(label = NEUTRON_NET_NAME) - # use base 64 format becaus bad surprises with sh script with cloud-init but script is just pinging - #k = "demo-key" - u = "#cloud-config\npassword: opnfv\nchpasswd: { expire: False }\nssh_pwauth: True\nwrite_files:\n- encoding: b64\n path: /tmp/vping.sh\n permissions: '0777'\n owner: root:root\n content: IyEvYmluL2Jhc2gKCndoaWxlIHRydWU7IGRvCiBwaW5nIC1jIDEgJDEgMj4mMSA+L2Rldi9udWxsCiBSRVM9JD8KIGlmIFsgIlokUkVTIiA9ICJaMCIgXSA7IHRoZW4KICBlY2hvICJ2UGluZyBPSyIKICBzbGVlcCAxMAogIHN1ZG8gc2h1dGRvd24gLWggbm93CiAgYnJlYWsKIGVsc2UKICBlY2hvICJ2UGluZyBLTyIKIGZpCiBzbGVlcCAxCmRvbmUK\nruncmd:\n - [ sh, -c, %s]"%test_cmd + # tune (e.g. flavor, images, network) to your specific openstack + # configuration here + u = "#!/bin/sh\n\nwhile true; do\n ping -c 1 %s 2>&1 >/dev/null\n " \ + "RES=$?\n if [ \"Z$RES\" = \"Z0\" ] ; then\n echo 'vPing OK'\n " \ + "break\n else\n echo 'vPing KO'\n fi\n sleep 1\ndone\n" % test_ip + # create VM - logger.info("Creating instance '%s'..." %m) - logger.debug("Configuration:\n name=%s \n flavor=%s \n image=%s \n network=%s \n userdata= \n%s" %(m,f,i,n,u)) - vm2 = nova.servers.create( - name = m, - flavor = f, - image = i, - nics = [{"net-id": n.id}], - #key_name = k, - userdata = u, - #security_groups = s, - #config_drive = v.id - ) - # The injected script will shutdown the VM2 when the ping works - # The console-log method is more consistent but doesn't work yet + logger.debug("Creating port 'vping-port-2' with IP %s..." % IP_2) + port_id2 = functest_utils.create_neutron_port(neutron_client, + "vping-port-2", network_id, + IP_2) - waitVmActive(nova,vm2) + if not port_id2: + logger.error("Unable to create port.") + exit(-1) + logger.info("Creating instance '%s' with IP %s..." % (NAME_VM_2, IP_2)) + logger.debug( + "Configuration:\n name=%s \n flavor=%s \n image=%s \n network=%s " + "\n userdata= \n%s" % ( + NAME_VM_2, flavor, image, network_id, u)) + vm2 = nova_client.servers.create( + name=NAME_VM_2, + flavor=flavor, + image=image, + # nics = [{"net-id": network_id, "v4-fixed-ip": IP_2}], + nics=[{"port-id": port_id2}], + userdata=u + ) - logger.info("Waiting for ping, timeout is %d sec..." % PING_TIMEOUT) - sec = 0 - while True: - status = get_status(nova, vm2) - #print status - if status == "SHUTOFF" : - EXIT_CODE = 0 - logger.info("vPing SUCCESSFUL after %d sec" % sec) - break - if sec == PING_TIMEOUT: - logger.info("Timeout. vPing UNSUCCESSFUL.") - break - time.sleep(1) - sec+=1 + if not waitVmActive(nova_client, vm2): + logger.error("Instance '%s' cannot be booted. Status is '%s'" % ( + NAME_VM_2, functest_utils.get_instance_status(nova_client, vm2))) + cleanup(nova_client, neutron_client, image_id, network_dic, port_id1, port_id2) + return (EXIT_CODE) + else: + logger.info("Instance '%s' is ACTIVE." % NAME_VM_2) - """ - # I leave this here until we fix the console-log output + logger.info("Waiting for ping...") sec = 0 console_log = vm2.get_console_output() - while not ("vPing" in console_log): + + while True: time.sleep(1) console_log = vm2.get_console_output() - print "--"+console_log - + # print "--"+console_log # report if the test is failed - if "vPing" in console_log: - pMsg("vPing is OK") + if "vPing OK" in console_log: + logger.info("vPing detected!") + + # we consider start time at VM1 booting + end_time_ts = time.time() + duration = round(end_time_ts - start_time_ts, 1) + logger.info("vPing duration:'%s'" % duration) + EXIT_CODE = 0 break - else: - pMsg("no vPing detected....") - sec+=1 - if sec == PING_TIMEOUT: + elif sec == PING_TIMEOUT: + logger.info("Timeout reached.") break - """ + else: + logger.debug("No vPing detected...") + sec += 1 - # delete both VMs - logger.debug("Deleting Instances...") - nova.servers.delete(vm1) - logger.debug("Instance %s terminated." % NAME_VM_1) - nova.servers.delete(vm2) - logger.debug("Instance %s terminated." % NAME_VM_2) + cleanup(nova_client, neutron_client, image_id, network_dic, port_id1, port_id2) + test_status = "NOK" + if EXIT_CODE == 0: + logger.info("vPing OK") + test_status = "OK" + else: + logger.error("vPing FAILED") + + try: + if args.report: + logger.debug("Push result into DB") + # TODO check path result for the file + git_version = functest_utils.get_git_branch(REPO_PATH) + pod_name = functest_utils.get_pod_name(logger) + functest_utils.push_results_to_db(TEST_DB, + "vPing", + logger, pod_name, git_version, + payload={'timestart': start_time_ts, + 'duration': duration, + 'status': test_status}) + # with open("vPing-result.json", "w") as outfile: + # json.dump({'timestart': start_time_ts, 'duration': duration, + # 'status': test_status}, outfile, indent=4) + except: + logger.error("Error pushing results into Database") - logger.debug("EXIT_CODE=%s" % EXIT_CODE) exit(EXIT_CODE) - if __name__ == '__main__': main() |