From 9c13968cdb32806da738dc520d45270e019f0ad3 Mon Sep 17 00:00:00 2001 From: "jose.lausuch" Date: Mon, 25 Apr 2016 18:08:22 +0200 Subject: Create prepare_env.py from prepare_env.sh and config_functest.py JIRA: FUNCTEST-227 Change-Id: I1aa890b9f91ec524c766ba3c460666ed227f2126 Signed-off-by: jose.lausuch --- CI/__init__.py | 0 CI/testcases.yaml | 196 --------- CI/tier_builder.py | 61 --- CI/tier_handler.py | 75 ---- ci/__init__.py | 0 ci/check_os.sh | 90 +++++ ci/prepare_env.py | 301 ++++++++++++++ ci/testcases.yaml | 196 +++++++++ ci/tier_builder.py | 61 +++ ci/tier_handler.py | 75 ++++ testcases/VIM/OpenStack/CI/libraries/check_os.sh | 27 +- .../VIM/OpenStack/CI/libraries/clean_openstack.py | 442 --------------------- .../OpenStack/CI/libraries/generate_defaults.py | 205 ---------- utils/clean_openstack.py | 442 +++++++++++++++++++++ utils/functest_logger.py | 6 +- utils/generate_defaults.py | 185 +++++++++ utils/openstack_utils.py | 10 + 17 files changed, 1365 insertions(+), 1007 deletions(-) delete mode 100644 CI/__init__.py delete mode 100644 CI/testcases.yaml delete mode 100644 CI/tier_builder.py delete mode 100644 CI/tier_handler.py create mode 100644 ci/__init__.py create mode 100755 ci/check_os.sh create mode 100644 ci/prepare_env.py create mode 100644 ci/testcases.yaml create mode 100644 ci/tier_builder.py create mode 100644 ci/tier_handler.py delete mode 100644 testcases/VIM/OpenStack/CI/libraries/clean_openstack.py delete mode 100644 testcases/VIM/OpenStack/CI/libraries/generate_defaults.py create mode 100644 utils/clean_openstack.py create mode 100644 utils/generate_defaults.py diff --git a/CI/__init__.py b/CI/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/CI/testcases.yaml b/CI/testcases.yaml deleted file mode 100644 index 42458bbef..000000000 --- a/CI/testcases.yaml +++ /dev/null @@ -1,196 +0,0 @@ -tiers: - - - name: healthcheck - order: 0 - ci: daily - description : >- - This is the first tier to be executed to verify the basic - operations in the VIM. - testcases: - - - name: healthcheck - description: >- - This test case verifies the basic OpenStack services like - Keystone, Glance, Cinder, Neutron and Nova. - - dependencies: - installer: '' - scenario: '' - - - - name: smoke - order: 1 - ci: daily - description : >- - This is the second tier in Functest and consist of a set of basic - Functional tests to validate the OpenStack deployment. - testcases: - - - name: vping_ssh - description: |- - This test case verifies: - ····1) SSH to an instance using floating IPs over the public network. - ····2) Connectivity between 2 instances over a private network. - dependencies: - installer: '' - scenario: '^((?!bgpvpn).)*$' - - - - name: vping_userdata - description: |- - This test case verifies: - ····1) Boot a VM with given userdata. - ····2) Connectivity between 2 instances over a private network. - dependencies: - installer: '' - scenario: '' - - - - name: tempest_smoke_serial - description: >- - This test case runs the smoke subset of the OpenStack - Tempest suite. The list of test cases is generated by - Tempest automatically and depend on the parameters of - the OpenStack deplopyment. - dependencies: - installer: '' - scenario: '' - - - - name: rally_sanity - description: >- - This test case runs a sub group of tests of the OpenStack - Rally suite in smoke mode. - dependencies: - installer: '' - scenario: '' - - - - name: security_groups - description: >- - This test case verifies the functionality of the OpenStack - security groups and that the port rules created are - fullfilled. - dependencies: - installer: '' - scenario: '' - - - - name: sdn_suites - order: 2 - ci: daily - description : >- - This tier contains the test suites corresponding to the different - SDN Controllers existing in OPNFV. - testcases: - - - name: odl - description: >- - Test Suite for the OpenDaylight SDN Controller. It integrates - some test suites from upstream using Robot as the test - framework. - dependencies: - installer: '' - scenario: 'odl' - - - - name: onos - description: >- - Test Suite for the ONOS SDN Controller. It integrates - some test suites from upstream using TestON as the test - framework. - dependencies: - installer: '' - scenario: 'onos' - - - - name: ovno - description: >- - Test Suite for the Open Contrail SDN Controller. - framework. - dependencies: - installer: '' - scenario: 'ocl' - - - - name: features - order: 3 - ci: daily - description : >- - This tier contains the test suites from feature projects - integrated in functest - testcases: - - - name: promise - description: >- - Test suite from Promise project. - dependencies: - installer: '(fuel)|(joid)' - scenario: '' - - - - name: doctor - description: >- - Test suite from Dcotor project. - dependencies: - installer: 'apex' - scenario: '' - - - - name: sdnvpn - description: >- - Test suite from SDNVPN project. - dependencies: - installer: '(fuel)|(apex)' - scenario: 'bgpvpn' - - - - name: tempest - order: 4 - ci: weekly - description : >- - This tier contains the test suites from feature projects - integrated in functest - testcases: - - - name: tempest_full_parallel - description: >- - This test case runs the full set of the OpenStack - Tempest suite. The list of test cases is generated by - Tempest automatically and depend on the parameters of - the OpenStack deplopyment. - dependencies: - installer: '' - scenario: '' - - - - name: rally - order: 5 - ci: weekly - description : >- - This tier contains the Rally suite from the OpenStack community. - testcases: - - - name: rally_full - description: >- - This test case runs the full suite of scenarios of the OpenStack - Rally suite using several threads and iterations. - dependencies: - installer: '' - scenario: '' - - - - name: vnf - order: 6 - ci: weekly - description : >- - This tier contains a collection of VNF test cases. - testcases: - - - name: vims - description: >- - This test case deploys an OpenSource vIMS solution from Clearwater - using the Cloudify orchestrator. It also runs some signaling traffic. - dependencies: - installer: '' - scenario: '(ocl)|(nosdn)|^(os-odl)((?!bgpvpn).)*$' diff --git a/CI/tier_builder.py b/CI/tier_builder.py deleted file mode 100644 index e66e97a38..000000000 --- a/CI/tier_builder.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -# -# jose.lausuch@ericsson.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 yaml - -import tier_handler as th - - -class TierBuilder: - def __init__(self, ci_installer, ci_scenario, testcases_file): - self.ci_installer = ci_installer - self.ci_scenario = ci_scenario - self.testcases_file = testcases_file - self.dic_tier_array = None - self.tier_objects = [] - self.testcases_yaml = None - self.generate_tiers() - - def read_test_yaml(self): - with open(self.testcases_file) as f: - self.testcases_yaml = yaml.safe_load(f) - - self.dic_tier_array = [] - for tier in self.testcases_yaml.get("tiers"): - self.dic_tier_array.append(tier) - - def generate_tiers(self): - if self.dic_tier_array is None: - self.read_test_yaml() - - del self.tier_objects[:] - for dic_tier in self.dic_tier_array: - tier = th.Tier(name=dic_tier['name'], - order=dic_tier['order'], - ci=dic_tier['ci'], - description=dic_tier['description']) - - for dic_testcase in dic_tier['testcases']: - installer = dic_testcase['dependencies']['installer'] - scenario = dic_testcase['dependencies']['scenario'] - dep = th.Dependency(installer, scenario) - - testcase = th.TestCase(name=dic_testcase['name'], - dependency=dep, - description=dic_testcase['description']) - if testcase.is_compatible(self.ci_installer, self.ci_scenario): - tier.add_test(testcase) - - self.tier_objects.append(tier) - - def __str__(self): - output = "" - for i in range(0, len(self.tier_objects)): - output += str(self.tier_objects[i]) + "\n" - return output diff --git a/CI/tier_handler.py b/CI/tier_handler.py deleted file mode 100644 index 0b7559498..000000000 --- a/CI/tier_handler.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python -# -# jose.lausuch@ericsson.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 re - - -class Tier: - def __init__(self, name, order, ci, description=""): - self.tests_array = [] - self.name = name - self.order = order - self.ci = ci - self.description = description - - def add_test(self, testcase): - self.tests_array.append(testcase) - - def get_tests(self): - array_str = [] - for test in self.tests_array: - array_str.append(test.name) - return array_str - - def __str__(self): - return ("Tier info:\n" - " Name: " + self.name + "\n" - " Description: " + self.description + "\n" - " Order: " + str(self.order) + "\n" - " Test cases: " + str(self.get_tests()) + "\n") - - -class TestCase: - def __init__(self, name, dependency, description=""): - self.name = name - self.dependency = dependency - self.description = description - - def is_compatible(self, ci_installer, ci_scenario): - if re.search(self.dependency.get_installer(), ci_installer) is None: - return False - - if re.search(self.dependency.get_scenario(), ci_scenario) is None: - return False - - return True - - def __str__(self): - return ("Testcase info:\n" - " Name: " + self.name + "\n" - " Description: " + self.description + "\n" - " " + str(self.dependency) + "\n") - - -class Dependency: - def __init__(self, installer, scenario): - self.installer = installer - self.scenario = scenario - - def get_installer(self): - return self.installer - - def get_scenario(self): - return self.scenario - - def __str__(self): - return ("Dependency info:\n" - " installer: " + self.installer + "\n" - " scenario: " + self.scenario + "\n") diff --git a/ci/__init__.py b/ci/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ci/check_os.sh b/ci/check_os.sh new file mode 100755 index 000000000..bb1335306 --- /dev/null +++ b/ci/check_os.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# +# Simple script to check the basic OpenStack clients +# +# Author: +# jose.lausuch@ericsson.com +# + +verify_connectivity() { + for i in $(seq 0 9); do + if echo "test" | nc -v -w 10 $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=$(openstack catalog show identity |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=('openstack 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/ci/prepare_env.py b/ci/prepare_env.py new file mode 100644 index 000000000..710a767e5 --- /dev/null +++ b/ci/prepare_env.py @@ -0,0 +1,301 @@ +#!/bin/bash +# +# Author: Jose Lausuch (jose.lausuch@ericsson.com) +# +# Installs the Functest framework within the Docker container +# and run the tests automatically +# +# +# 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 argparse +import os +import re +import subprocess +import sys +import yaml + +import functest.ci.tier_builder as tb +import functest.utils.functest_logger as ft_logger +import functest.utils.functest_utils as ft_utils +import functest.utils.generate_defaults as gen_def +import functest.utils.openstack_utils as os_utils + + +""" arguments """ +actions = ['start', 'check'] +parser = argparse.ArgumentParser() +parser.add_argument("action", help="Possible actions are: " + "'{d[0]}|{d[1]}' ".format(d=actions)) +parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") +args = parser.parse_args() + + +""" logging configuration """ +logger = ft_logger.Logger("prepare_env").getLogger() + + +""" global variables """ +INSTALLERS = ['fuel', 'compass', 'apex', 'joid'] +CI_INSTALLER_TYPE = "" +CI_INSTALLER_IP = "" +CI_SCENARIO = "" +CI_DEBUG = False +REPOS_DIR = os.getenv('repos_dir') +FUNCTEST_REPO = REPOS_DIR + '/functest/' + +with open("/home/opnfv/repos/functest/testcases/config_functest.yaml") as f: + functest_yaml = yaml.safe_load(f) + +FUNCTEST_CONF_DIR = functest_yaml.get("general").get( + "directories").get("dir_functest_conf") + +FUNCTEST_DATA_DIR = functest_yaml.get("general").get( + "directories").get("dir_functest_data") +FUNCTEST_RESULTS_DIR = functest_yaml.get("general").get( + "directories").get("dir_results") +DEPLOYMENT_MAME = functest_yaml.get("rally").get("deployment_name") +TEMPEST_REPO_DIR = functest_yaml.get("general").get( + "directories").get("dir_repo_tempest") + +ENV_FILE = FUNCTEST_CONF_DIR + "/env_active" + + +def print_separator(): + logger.info("==============================================") + + +def check_env_variables(): + print_separator() + logger.info("Checking environment variables...") + global CI_INSTALLER_TYPE + global CI_INSTALLER_IP + global CI_DEBUG + global CI_SCENARIO + CI_INSTALLER_TYPE = os.getenv('INSTALLER_TYPE') + CI_INSTALLER_IP = os.getenv('INSTALLER_IP') + CI_SCENARIO = os.getenv('DEPLOY_SCENARIO') + CI_NODE = os.getenv('NODE_NAME') + CI_BUILD_TAG = os.getenv('BUILD_TAG') + CI_DEBUG = os.getenv('CI_DEBUG') + + if CI_INSTALLER_TYPE is None: + logger.warning("The env variable 'INSTALLER_TYPE' is not defined.") + CI_INSTALLER_TYPE = "undefined" + else: + if os.getenv('INSTALLER_TYPE') not in INSTALLERS: + logger.warning("INSTALLER_TYPE=%s is not a valid OPNFV installer. " + "Available OPNFV Installers are : %s." + "Setting INSTALLER_TYPE=undefined." % INSTALLERS) + CI_INSTALLER_TYPE = "undefined" + else: + logger.info(" INSTALLER_TYPE=%s" % CI_INSTALLER_TYPE) + + if CI_INSTALLER_IP is None: + logger.warning("The env variable 'INSTALLER_IP' is not defined. " + "It is needed to fetch the OpenStack credentials. " + "If the credentials are not provided to the " + "container as a volume, please add this env variable " + "to the 'docker run' command.") + else: + logger.info(" INSTALLER_IP=%s" % CI_INSTALLER_IP) + + if CI_SCENARIO is None: + logger.warning("The env variable 'DEPLOY_SCENARIO' is not defined. " + "Setting CE_SCENARIO=undefined.") + CI_SCENARIO = "undefined" + else: + logger.info(" DEPLOY_SCENARIO=%s" % CI_SCENARIO) + if CI_DEBUG: + logger.info(" CI_DEBUG=%s" % CI_DEBUG) + + if CI_NODE: + logger.info(" NODE_NAME=%s" % CI_NODE) + + if CI_BUILD_TAG: + logger.info(" BUILD_TAG=%s" % CI_BUILD_TAG) + + +def create_directories(): + print_separator() + logger.info("Creating needed directories...") + if not os.path.exists(FUNCTEST_CONF_DIR): + os.makedirs(FUNCTEST_CONF_DIR) + logger.info(" %s created." % FUNCTEST_CONF_DIR) + else: + logger.debug(" %s already exists." % FUNCTEST_CONF_DIR) + + if not os.path.exists(FUNCTEST_DATA_DIR): + os.makedirs(FUNCTEST_DATA_DIR) + logger.info(" %s created." % FUNCTEST_DATA_DIR) + else: + logger.debug(" %s already exists." % FUNCTEST_DATA_DIR) + + ODL_RESULTS_DIR = FUNCTEST_RESULTS_DIR + "/ODL/" + if not os.path.exists(ODL_RESULTS_DIR): + os.makedirs(ODL_RESULTS_DIR) + logger.info(" %s created." % ODL_RESULTS_DIR) + else: + logger.debug(" %s already exists." % ODL_RESULTS_DIR) + + +def source_rc_file(): + print_separator() + logger.info("Fetching RC file...") + rc_file = os.getenv('creds') + if rc_file is None: + logger.warning("The environment variable 'creds' must be set and" + "pointing to the local RC file. Using default: " + "/home/opnfv/functest/conf/openstack.creds ...") + rc_file = "/home/opnfv/functest/conf/openstack.creds ..." + + if not os.path.isfile(rc_file): + logger.info("RC file not provided. " + "Fetching it from the installer...") + if CI_INSTALLER_IP is None: + logger.error("The env variable CI_INSTALLER_IP must be provided in" + " order to fetch the credentials from the installer.") + sys.exit("Missing CI_INSTALLER_IP.") + if CI_INSTALLER_TYPE not in INSTALLERS: + logger.error("Cannot fetch credentials. INSTALLER_TYPE=%s is " + "not a valid OPNFV installer. Available " + "installers are : %s." % INSTALLERS) + sys.exit("Wrong INSTALLER_TYPE.") + + cmd = ("/home/opnfv/repos/releng/utils/fetch_os_creds.sh " + "-d %s -i %s -a %s" + % (rc_file, CI_INSTALLER_TYPE, CI_INSTALLER_IP)) + logger.debug("Executing command: %s" % cmd) + p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) + output = p.communicate()[0] + logger.debug(output) + if p.returncode != 0: + logger.error("Failed to fetch credentials from installer.") + sys.exit(1) + else: + logger.info("RC file provided in %s." % rc_file) + if os.path.getsize(rc_file) == 0: + logger.error("The file %s is empty." % rc_file) + sys.exit(1) + + logger.info("Sourcing the OpenStack RC file...") + creds = os_utils.source_credentials(rc_file) + str = "" + for key, value in creds.iteritems(): + if re.search("OS_", key): + str += "\n\t\t\t\t\t\t " + key + "=" + value + logger.debug("Used credentials: %s" % str) + + +def verify_deployment(): + print_separator() + logger.info("Verifying OpenStack services...") + cmd = ("%s/ci/check_os.sh" % FUNCTEST_REPO) + + logger.debug("Executing command: %s" % cmd) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + + while p.poll() is None: + line = p.stdout.readline().rstrip() + if "ERROR" in line: + logger.error(line) + sys.exit("Problem while running 'check_os.sh'.") + logger.debug(line) + + +def install_rally(): + print_separator() + logger.info("Creating Rally environment...") + + cmd = "rally deployment destroy opnfv-rally" + ft_utils.execute_command(cmd, logger=None, exit_on_error=False) + + cmd = "rally deployment create --fromenv --name=" + DEPLOYMENT_MAME + if not ft_utils.execute_command(cmd, logger): + logger.error("Problem while creating Rally deployment.") + sys.exit(cmd) + + logger.info("Installing tempest from existing repo...") + cmd = ("rally verify install --source " + TEMPEST_REPO_DIR + + " --system-wide") + if not ft_utils.execute_command(cmd, logger): + logger.error("Problem while installing Tempest.") + sys.exit(cmd) + + cmd = "rally deployment check" + if not ft_utils.execute_command(cmd, logger): + logger.error("OpenStack not responding or faulty Rally deployment.") + sys.exit(cmd) + + cmd = "rally show images" + if not ft_utils.execute_command(cmd, logger): + logger.error("Problem while listing OpenStack images.") + sys.exit(cmd) + + cmd = "rally show flavors" + if not ft_utils.execute_command(cmd, logger): + logger.error("Problem while showing OpenStack flavors.") + sys.exit(cmd) + + +def generate_os_defaults(): + print_separator() + logger.info("Generating OpenStack defaults...") + gen_def.main() + + +def generate_tiers(): + print_separator() + logger.info("Generating Tiers and test cases...") + file = FUNCTEST_REPO + "/ci/testcases.yaml" + + t = tb.TierBuilder(CI_INSTALLER_TYPE, CI_SCENARIO, file) + logger.info("Tiers and tests to be executed:\n\n%s" % t) + + +def check_environment(): + msg_not_active = "The Functest environment is not installed." + if not os.path.isfile(ENV_FILE): + logger.error(msg_not_active) + sys.exit(1) + + with open(ENV_FILE, "r") as env_file: + s = env_file.read() + if not re.search("1", s): + logger.error(msg_not_active) + sys.exit(1) + + logger.info("Functest environment installed.") + + +def main(): + if not (args.action in actions): + logger.error('Argument not valid.') + sys.exit() + + if args.action == "start": + print ("\n######### Preparing Functest environment #########\n") + check_env_variables() + create_directories() + source_rc_file() + verify_deployment() + install_rally() + generate_os_defaults() + generate_tiers() + + with open(ENV_FILE, "w") as env_file: + env_file.write("1") + + check_environment() + + if args.action == "check": + check_environment() + + exit(0) + +if __name__ == '__main__': + main() diff --git a/ci/testcases.yaml b/ci/testcases.yaml new file mode 100644 index 000000000..42458bbef --- /dev/null +++ b/ci/testcases.yaml @@ -0,0 +1,196 @@ +tiers: + - + name: healthcheck + order: 0 + ci: daily + description : >- + This is the first tier to be executed to verify the basic + operations in the VIM. + testcases: + - + name: healthcheck + description: >- + This test case verifies the basic OpenStack services like + Keystone, Glance, Cinder, Neutron and Nova. + + dependencies: + installer: '' + scenario: '' + + - + name: smoke + order: 1 + ci: daily + description : >- + This is the second tier in Functest and consist of a set of basic + Functional tests to validate the OpenStack deployment. + testcases: + - + name: vping_ssh + description: |- + This test case verifies: + ····1) SSH to an instance using floating IPs over the public network. + ····2) Connectivity between 2 instances over a private network. + dependencies: + installer: '' + scenario: '^((?!bgpvpn).)*$' + + - + name: vping_userdata + description: |- + This test case verifies: + ····1) Boot a VM with given userdata. + ····2) Connectivity between 2 instances over a private network. + dependencies: + installer: '' + scenario: '' + + - + name: tempest_smoke_serial + description: >- + This test case runs the smoke subset of the OpenStack + Tempest suite. The list of test cases is generated by + Tempest automatically and depend on the parameters of + the OpenStack deplopyment. + dependencies: + installer: '' + scenario: '' + + - + name: rally_sanity + description: >- + This test case runs a sub group of tests of the OpenStack + Rally suite in smoke mode. + dependencies: + installer: '' + scenario: '' + + - + name: security_groups + description: >- + This test case verifies the functionality of the OpenStack + security groups and that the port rules created are + fullfilled. + dependencies: + installer: '' + scenario: '' + + - + name: sdn_suites + order: 2 + ci: daily + description : >- + This tier contains the test suites corresponding to the different + SDN Controllers existing in OPNFV. + testcases: + - + name: odl + description: >- + Test Suite for the OpenDaylight SDN Controller. It integrates + some test suites from upstream using Robot as the test + framework. + dependencies: + installer: '' + scenario: 'odl' + + - + name: onos + description: >- + Test Suite for the ONOS SDN Controller. It integrates + some test suites from upstream using TestON as the test + framework. + dependencies: + installer: '' + scenario: 'onos' + + - + name: ovno + description: >- + Test Suite for the Open Contrail SDN Controller. + framework. + dependencies: + installer: '' + scenario: 'ocl' + + - + name: features + order: 3 + ci: daily + description : >- + This tier contains the test suites from feature projects + integrated in functest + testcases: + - + name: promise + description: >- + Test suite from Promise project. + dependencies: + installer: '(fuel)|(joid)' + scenario: '' + + - + name: doctor + description: >- + Test suite from Dcotor project. + dependencies: + installer: 'apex' + scenario: '' + + - + name: sdnvpn + description: >- + Test suite from SDNVPN project. + dependencies: + installer: '(fuel)|(apex)' + scenario: 'bgpvpn' + + - + name: tempest + order: 4 + ci: weekly + description : >- + This tier contains the test suites from feature projects + integrated in functest + testcases: + - + name: tempest_full_parallel + description: >- + This test case runs the full set of the OpenStack + Tempest suite. The list of test cases is generated by + Tempest automatically and depend on the parameters of + the OpenStack deplopyment. + dependencies: + installer: '' + scenario: '' + + - + name: rally + order: 5 + ci: weekly + description : >- + This tier contains the Rally suite from the OpenStack community. + testcases: + - + name: rally_full + description: >- + This test case runs the full suite of scenarios of the OpenStack + Rally suite using several threads and iterations. + dependencies: + installer: '' + scenario: '' + + - + name: vnf + order: 6 + ci: weekly + description : >- + This tier contains a collection of VNF test cases. + testcases: + - + name: vims + description: >- + This test case deploys an OpenSource vIMS solution from Clearwater + using the Cloudify orchestrator. It also runs some signaling traffic. + dependencies: + installer: '' + scenario: '(ocl)|(nosdn)|^(os-odl)((?!bgpvpn).)*$' diff --git a/ci/tier_builder.py b/ci/tier_builder.py new file mode 100644 index 000000000..e66e97a38 --- /dev/null +++ b/ci/tier_builder.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# +# jose.lausuch@ericsson.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 yaml + +import tier_handler as th + + +class TierBuilder: + def __init__(self, ci_installer, ci_scenario, testcases_file): + self.ci_installer = ci_installer + self.ci_scenario = ci_scenario + self.testcases_file = testcases_file + self.dic_tier_array = None + self.tier_objects = [] + self.testcases_yaml = None + self.generate_tiers() + + def read_test_yaml(self): + with open(self.testcases_file) as f: + self.testcases_yaml = yaml.safe_load(f) + + self.dic_tier_array = [] + for tier in self.testcases_yaml.get("tiers"): + self.dic_tier_array.append(tier) + + def generate_tiers(self): + if self.dic_tier_array is None: + self.read_test_yaml() + + del self.tier_objects[:] + for dic_tier in self.dic_tier_array: + tier = th.Tier(name=dic_tier['name'], + order=dic_tier['order'], + ci=dic_tier['ci'], + description=dic_tier['description']) + + for dic_testcase in dic_tier['testcases']: + installer = dic_testcase['dependencies']['installer'] + scenario = dic_testcase['dependencies']['scenario'] + dep = th.Dependency(installer, scenario) + + testcase = th.TestCase(name=dic_testcase['name'], + dependency=dep, + description=dic_testcase['description']) + if testcase.is_compatible(self.ci_installer, self.ci_scenario): + tier.add_test(testcase) + + self.tier_objects.append(tier) + + def __str__(self): + output = "" + for i in range(0, len(self.tier_objects)): + output += str(self.tier_objects[i]) + "\n" + return output diff --git a/ci/tier_handler.py b/ci/tier_handler.py new file mode 100644 index 000000000..0b7559498 --- /dev/null +++ b/ci/tier_handler.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# +# jose.lausuch@ericsson.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 re + + +class Tier: + def __init__(self, name, order, ci, description=""): + self.tests_array = [] + self.name = name + self.order = order + self.ci = ci + self.description = description + + def add_test(self, testcase): + self.tests_array.append(testcase) + + def get_tests(self): + array_str = [] + for test in self.tests_array: + array_str.append(test.name) + return array_str + + def __str__(self): + return ("Tier info:\n" + " Name: " + self.name + "\n" + " Description: " + self.description + "\n" + " Order: " + str(self.order) + "\n" + " Test cases: " + str(self.get_tests()) + "\n") + + +class TestCase: + def __init__(self, name, dependency, description=""): + self.name = name + self.dependency = dependency + self.description = description + + def is_compatible(self, ci_installer, ci_scenario): + if re.search(self.dependency.get_installer(), ci_installer) is None: + return False + + if re.search(self.dependency.get_scenario(), ci_scenario) is None: + return False + + return True + + def __str__(self): + return ("Testcase info:\n" + " Name: " + self.name + "\n" + " Description: " + self.description + "\n" + " " + str(self.dependency) + "\n") + + +class Dependency: + def __init__(self, installer, scenario): + self.installer = installer + self.scenario = scenario + + def get_installer(self): + return self.installer + + def get_scenario(self): + return self.scenario + + def __str__(self): + return ("Dependency info:\n" + " installer: " + self.installer + "\n" + " scenario: " + self.scenario + "\n") diff --git a/testcases/VIM/OpenStack/CI/libraries/check_os.sh b/testcases/VIM/OpenStack/CI/libraries/check_os.sh index 98b8605cd..c247d5ae2 100755 --- a/testcases/VIM/OpenStack/CI/libraries/check_os.sh +++ b/testcases/VIM/OpenStack/CI/libraries/check_os.sh @@ -7,8 +7,8 @@ # verify_connectivity() { - for i in $(seq 0 10); do - if echo "test" | nc -v $1 $2 &>/dev/null; then + for i in $(seq 0 9); do + if echo "test" | nc -v -w 10 $1 $2 &>/dev/null; then return 0 fi sleep 1 @@ -88,27 +88,4 @@ if [ $is_external == "False" ]; then exit 1 fi - -# Temporary output information -# To see the initial OpenStack defaults -# in case we delete something later on. -# This is to be removed for the release -if [[ "${CI_DEBUG,,}" == "true" ]];then - echo "nova list:" - nova list - echo "cinder list" - cinder list - echo "nova floating-ip-list:" - nova floating-ip-list - echo "neutron net-list:" - neutron net-list - echo "neutron router-list:" - neutron router-list - echo "neutron security-group-list:" - neutron security-group-list - echo "openstack project list:" - openstack project list - echo "openstack user list:" - openstack user list -fi exit 0 diff --git a/testcases/VIM/OpenStack/CI/libraries/clean_openstack.py b/testcases/VIM/OpenStack/CI/libraries/clean_openstack.py deleted file mode 100644 index 838927faa..000000000 --- a/testcases/VIM/OpenStack/CI/libraries/clean_openstack.py +++ /dev/null @@ -1,442 +0,0 @@ -#!/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 -# -# -# 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 argparse -import logging -import os -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 - -import openstack_utils - -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/' - -DEFAULTS_FILE = '/home/opnfv/functest/conf/os_defaults.yaml' - -try: - with open(DEFAULTS_FILE) as f: - defaults_yaml = yaml.safe_load(f) -except Exception, e: - logger.info("The file %s does not exist. Please run generate_defaults.py " - "to create the OpenStack defaults. " - "Aborting cleanup..." % DEFAULTS_FILE) - exit(0) - -default_images = defaults_yaml.get('images') -default_instances = defaults_yaml.get('instances') -default_volumes = defaults_yaml.get('volumes') -default_networks = defaults_yaml.get('networks') -default_routers = defaults_yaml.get('routers') -default_security_groups = defaults_yaml.get('secgroups') -default_floatingips = defaults_yaml.get('floatingips') -default_users = defaults_yaml.get('users') -default_tenants = defaults_yaml.get('tenants') - - -def separator(): - logger.info("-------------------------------------------") - - -def remove_instances(nova_client): - logger.info("Removing Nova instances...") - instances = openstack_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 openstack_utils.delete_instance(nova_client, instance_id): - logger.debug(" > Done!") - else: - logger.error("There has been a problem removing the " - "instance %s..." % instance_id) - - timeout = 50 - while timeout > 0: - instances = openstack_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 = openstack_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_id not in default_images: - logger.debug("Removing image '%s', ID=%s ..." - % (image_name, image_id)) - if openstack_utils.delete_glance_image(nova_client, image_id): - logger.debug(" > Done!") - else: - logger.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 = openstack_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') - volume_name = getattr(volume, 'display_name') - logger.debug("'%s', ID=%s " % (volume_name, volume_id)) - if volume_id not in default_volumes: - logger.debug("Removing cinder volume %s ..." % volume_id) - if openstack_utils.delete_volume(cinder_client, volume_id): - logger.debug(" > Done!") - else: - logger.debug("Trying forced removal...") - if openstack_utils.delete_volume(cinder_client, - volume_id, - forced=True): - logger.debug(" > Done!") - else: - logger.error("There has been a problem removing the " - "volume %s..." % volume_id) - else: - logger.debug(" > this is a default volume and will " - "NOT be deleted.") - - -def remove_floatingips(nova_client): - logger.info("Removing floating IPs...") - floatingips = openstack_utils.get_floating_ips(nova_client) - if floatingips is None or len(floatingips) == 0: - logger.debug("No floating IPs found.") - return - - init_len = len(floatingips) - deleted = 0 - for fip in floatingips: - fip_id = getattr(fip, 'id') - fip_ip = getattr(fip, 'ip') - logger.debug("'%s', ID=%s " % (fip_ip, fip_id)) - if fip_id not in default_floatingips: - logger.debug("Removing floating IP %s ..." % fip_id) - if openstack_utils.delete_floating_ip(nova_client, fip_id): - logger.debug(" > Done!") - deleted += 1 - else: - logger.error("There has been a problem removing the " - "floating IP %s..." % fip_id) - else: - logger.debug(" > this is a default floating IP and will " - "NOT be deleted.") - - timeout = 50 - while timeout > 0: - floatingips = openstack_utils.get_floating_ips(nova_client) - if floatingips is None or len(floatingips) == (init_len - deleted): - 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 = openstack_utils.get_network_list(neutron_client) - if networks is 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_id in default_networks: - logger.debug(" > this is a default network and will " - "NOT be deleted.") - elif network['router:external'] is 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 = openstack_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 = openstack_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 is not None: - for net_id in network_ids: - logger.debug("Removing network %s ..." % net_id) - if openstack_utils.delete_neutron_net(neutron_client, net_id): - logger.debug(" > Done!") - else: - logger.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 (openstack_utils.delete_neutron_port(neutron_client, - port_id)): - logger.debug(" > Done!") - else: - logger.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 openstack_utils.remove_interface_router( - neutron_client, router_id, subnet_id): - time.sleep(5) # leave 5 seconds to detach - logger.debug(" > Done!") - else: - logger.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) - openstack_utils.update_neutron_port(neutron_client, - port_id, - device_owner='clear') - logger.debug("Removing port %s ..." % port_id) - if openstack_utils.delete_neutron_port(neutron_client, port_id): - logger.debug(" > Done!") - else: - logger.error("There has been a problem removing the port %s..." - % port_id) - - -def remove_routers(neutron_client, routers): - for router in routers: - router_id = router['id'] - router_name = router['name'] - if router_id not in default_routers: - logger.debug("Checking '%s' with ID=(%s) ..." % (router_name, - router_id)) - if router['external_gateway_info'] is not None: - logger.debug("Router has gateway to external network." - "Removing link...") - if openstack_utils.remove_gateway_router(neutron_client, - router_id): - logger.debug(" > Done!") - else: - logger.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 openstack_utils.delete_neutron_router(neutron_client, - router_id): - logger.debug(" > Done!") - else: - logger.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 = openstack_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_id not in default_security_groups: - logger.debug(" Removing '%s'..." % secgroup_name) - if openstack_utils.delete_security_group(neutron_client, - secgroup_id): - logger.debug(" > Done!") - else: - logger.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 = openstack_utils.get_users(keystone_client) - if users is 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_id not in default_users: - logger.debug(" Removing '%s'..." % user_name) - if openstack_utils.delete_user(keystone_client, user_id): - logger.debug(" > Done!") - else: - logger.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 = openstack_utils.get_tenants(keystone_client) - if tenants is 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_id not in default_tenants: - logger.debug(" Removing '%s'..." % tenant_name) - if openstack_utils.delete_tenant(keystone_client, tenant_id): - logger.debug(" > Done!") - else: - logger.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 = openstack_utils.get_credentials("nova") - nova_client = novaclient.Client('2', **creds_nova) - - creds_neutron = openstack_utils.get_credentials("neutron") - neutron_client = neutronclient.Client(**creds_neutron) - - creds_keystone = openstack_utils.get_credentials("keystone") - keystone_client = keystoneclient.Client(**creds_keystone) - - creds_cinder = openstack_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 openstack_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/generate_defaults.py b/testcases/VIM/OpenStack/CI/libraries/generate_defaults.py deleted file mode 100644 index 5e799e4c9..000000000 --- a/testcases/VIM/OpenStack/CI/libraries/generate_defaults.py +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/env python -# -# Description: -# Generates a list of the current Openstack objects in the deployment: -# - Nova instances -# - Glance images -# - Cinder volumes -# - Floating IPs -# - Neutron networks, subnets and ports -# - Routers -# - Users and tenants -# -# Author: -# jose.lausuch@ericsson.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 argparse -import logging -import os -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 - -import openstack_utils - -parser = argparse.ArgumentParser() -parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") -args = parser.parse_args() - - -""" logging configuration """ -logger = logging.getLogger('generate_defaults') -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) - - -DEFAULTS_FILE = '/home/opnfv/functest/conf/os_defaults.yaml' - - -def separator(): - logger.info("-------------------------------------------") - - -def get_instances(nova_client): - logger.debug("Getting instances...") - dic_instances = {} - instances = openstack_utils.get_instances(nova_client) - if not (instances is None or len(instances) == 0): - for instance in instances: - dic_instances.update({getattr(instance, 'id'): getattr(instance, - 'name')}) - return {'instances': dic_instances} - - -def get_images(nova_client): - logger.debug("Getting images...") - dic_images = {} - images = openstack_utils.get_images(nova_client) - if not (images is None or len(images) == 0): - for image in images: - dic_images.update({getattr(image, 'id'): getattr(image, 'name')}) - return {'images': dic_images} - - -def get_volumes(cinder_client): - logger.debug("Getting volumes...") - dic_volumes = {} - volumes = openstack_utils.get_volumes(cinder_client) - if volumes is not None: - for volume in volumes: - dic_volumes.update({volume.id: volume.display_name}) - return {'volumes': dic_volumes} - - -def get_networks(neutron_client): - logger.debug("Getting networks") - dic_networks = {} - networks = openstack_utils.get_network_list(neutron_client) - if networks is not None: - for network in networks: - dic_networks.update({network['id']: network['name']}) - return {'networks': dic_networks} - - -def get_routers(neutron_client): - logger.debug("Getting routers") - dic_routers = {} - routers = openstack_utils.get_router_list(neutron_client) - if routers is not None: - for router in routers: - dic_routers.update({router['id']: router['name']}) - return {'routers': dic_routers} - - -def get_security_groups(neutron_client): - logger.debug("Getting Security groups...") - dic_secgroups = {} - secgroups = openstack_utils.get_security_groups(neutron_client) - if not (secgroups is None or len(secgroups) == 0): - for secgroup in secgroups: - dic_secgroups.update({secgroup['id']: secgroup['name']}) - return {'secgroups': dic_secgroups} - - -def get_floatinips(nova_client): - logger.debug("Getting Floating IPs...") - dic_floatingips = {} - floatingips = openstack_utils.get_floating_ips(nova_client) - if not (floatingips is None or len(floatingips) == 0): - for floatingip in floatingips: - dic_floatingips.update({floatingip.id: floatingip.ip}) - return {'floatingips': dic_floatingips} - - -def get_users(keystone_client): - logger.debug("Getting users...") - dic_users = {} - users = openstack_utils.get_users(keystone_client) - if not (users is None or len(users) == 0): - for user in users: - dic_users.update({getattr(user, 'id'): getattr(user, 'name')}) - return {'users': dic_users} - - -def get_tenants(keystone_client): - logger.debug("Getting users...") - dic_tenants = {} - tenants = openstack_utils.get_tenants(keystone_client) - if not (tenants is None or len(tenants) == 0): - for tenant in tenants: - dic_tenants.update({getattr(tenant, 'id'): - getattr(tenant, 'name')}) - return {'tenants': dic_tenants} - - -def main(): - creds_nova = openstack_utils.get_credentials("nova") - nova_client = novaclient.Client('2', **creds_nova) - - creds_neutron = openstack_utils.get_credentials("neutron") - neutron_client = neutronclient.Client(**creds_neutron) - - creds_keystone = openstack_utils.get_credentials("keystone") - keystone_client = keystoneclient.Client(**creds_keystone) - - creds_cinder = openstack_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 openstack_utils.check_credentials(): - logger.error("Please source the openrc credentials and run the" + - "script again.") - exit(-1) - - defaults = {} - defaults.update(get_instances(nova_client)) - defaults.update(get_images(nova_client)) - defaults.update(get_volumes(cinder_client)) - defaults.update(get_networks(neutron_client)) - defaults.update(get_routers(neutron_client)) - defaults.update(get_security_groups(neutron_client)) - defaults.update(get_floatinips(nova_client)) - defaults.update(get_users(keystone_client)) - defaults.update(get_tenants(keystone_client)) - - with open(DEFAULTS_FILE, 'w+') as yaml_file: - yaml_file.write(yaml.safe_dump(defaults, default_flow_style=False)) - yaml_file.seek(0) - logger.info("Openstack Defaults found in the deployment:") - print yaml_file.read() - logger.debug("NOTE: These objects will NOT be deleted after " + - "running the tests.") - - exit(0) - - -if __name__ == '__main__': - main() diff --git a/utils/clean_openstack.py b/utils/clean_openstack.py new file mode 100644 index 000000000..838927faa --- /dev/null +++ b/utils/clean_openstack.py @@ -0,0 +1,442 @@ +#!/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 +# +# +# 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 argparse +import logging +import os +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 + +import openstack_utils + +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/' + +DEFAULTS_FILE = '/home/opnfv/functest/conf/os_defaults.yaml' + +try: + with open(DEFAULTS_FILE) as f: + defaults_yaml = yaml.safe_load(f) +except Exception, e: + logger.info("The file %s does not exist. Please run generate_defaults.py " + "to create the OpenStack defaults. " + "Aborting cleanup..." % DEFAULTS_FILE) + exit(0) + +default_images = defaults_yaml.get('images') +default_instances = defaults_yaml.get('instances') +default_volumes = defaults_yaml.get('volumes') +default_networks = defaults_yaml.get('networks') +default_routers = defaults_yaml.get('routers') +default_security_groups = defaults_yaml.get('secgroups') +default_floatingips = defaults_yaml.get('floatingips') +default_users = defaults_yaml.get('users') +default_tenants = defaults_yaml.get('tenants') + + +def separator(): + logger.info("-------------------------------------------") + + +def remove_instances(nova_client): + logger.info("Removing Nova instances...") + instances = openstack_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 openstack_utils.delete_instance(nova_client, instance_id): + logger.debug(" > Done!") + else: + logger.error("There has been a problem removing the " + "instance %s..." % instance_id) + + timeout = 50 + while timeout > 0: + instances = openstack_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 = openstack_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_id not in default_images: + logger.debug("Removing image '%s', ID=%s ..." + % (image_name, image_id)) + if openstack_utils.delete_glance_image(nova_client, image_id): + logger.debug(" > Done!") + else: + logger.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 = openstack_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') + volume_name = getattr(volume, 'display_name') + logger.debug("'%s', ID=%s " % (volume_name, volume_id)) + if volume_id not in default_volumes: + logger.debug("Removing cinder volume %s ..." % volume_id) + if openstack_utils.delete_volume(cinder_client, volume_id): + logger.debug(" > Done!") + else: + logger.debug("Trying forced removal...") + if openstack_utils.delete_volume(cinder_client, + volume_id, + forced=True): + logger.debug(" > Done!") + else: + logger.error("There has been a problem removing the " + "volume %s..." % volume_id) + else: + logger.debug(" > this is a default volume and will " + "NOT be deleted.") + + +def remove_floatingips(nova_client): + logger.info("Removing floating IPs...") + floatingips = openstack_utils.get_floating_ips(nova_client) + if floatingips is None or len(floatingips) == 0: + logger.debug("No floating IPs found.") + return + + init_len = len(floatingips) + deleted = 0 + for fip in floatingips: + fip_id = getattr(fip, 'id') + fip_ip = getattr(fip, 'ip') + logger.debug("'%s', ID=%s " % (fip_ip, fip_id)) + if fip_id not in default_floatingips: + logger.debug("Removing floating IP %s ..." % fip_id) + if openstack_utils.delete_floating_ip(nova_client, fip_id): + logger.debug(" > Done!") + deleted += 1 + else: + logger.error("There has been a problem removing the " + "floating IP %s..." % fip_id) + else: + logger.debug(" > this is a default floating IP and will " + "NOT be deleted.") + + timeout = 50 + while timeout > 0: + floatingips = openstack_utils.get_floating_ips(nova_client) + if floatingips is None or len(floatingips) == (init_len - deleted): + 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 = openstack_utils.get_network_list(neutron_client) + if networks is 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_id in default_networks: + logger.debug(" > this is a default network and will " + "NOT be deleted.") + elif network['router:external'] is 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 = openstack_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 = openstack_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 is not None: + for net_id in network_ids: + logger.debug("Removing network %s ..." % net_id) + if openstack_utils.delete_neutron_net(neutron_client, net_id): + logger.debug(" > Done!") + else: + logger.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 (openstack_utils.delete_neutron_port(neutron_client, + port_id)): + logger.debug(" > Done!") + else: + logger.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 openstack_utils.remove_interface_router( + neutron_client, router_id, subnet_id): + time.sleep(5) # leave 5 seconds to detach + logger.debug(" > Done!") + else: + logger.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) + openstack_utils.update_neutron_port(neutron_client, + port_id, + device_owner='clear') + logger.debug("Removing port %s ..." % port_id) + if openstack_utils.delete_neutron_port(neutron_client, port_id): + logger.debug(" > Done!") + else: + logger.error("There has been a problem removing the port %s..." + % port_id) + + +def remove_routers(neutron_client, routers): + for router in routers: + router_id = router['id'] + router_name = router['name'] + if router_id not in default_routers: + logger.debug("Checking '%s' with ID=(%s) ..." % (router_name, + router_id)) + if router['external_gateway_info'] is not None: + logger.debug("Router has gateway to external network." + "Removing link...") + if openstack_utils.remove_gateway_router(neutron_client, + router_id): + logger.debug(" > Done!") + else: + logger.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 openstack_utils.delete_neutron_router(neutron_client, + router_id): + logger.debug(" > Done!") + else: + logger.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 = openstack_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_id not in default_security_groups: + logger.debug(" Removing '%s'..." % secgroup_name) + if openstack_utils.delete_security_group(neutron_client, + secgroup_id): + logger.debug(" > Done!") + else: + logger.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 = openstack_utils.get_users(keystone_client) + if users is 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_id not in default_users: + logger.debug(" Removing '%s'..." % user_name) + if openstack_utils.delete_user(keystone_client, user_id): + logger.debug(" > Done!") + else: + logger.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 = openstack_utils.get_tenants(keystone_client) + if tenants is 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_id not in default_tenants: + logger.debug(" Removing '%s'..." % tenant_name) + if openstack_utils.delete_tenant(keystone_client, tenant_id): + logger.debug(" > Done!") + else: + logger.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 = openstack_utils.get_credentials("nova") + nova_client = novaclient.Client('2', **creds_nova) + + creds_neutron = openstack_utils.get_credentials("neutron") + neutron_client = neutronclient.Client(**creds_neutron) + + creds_keystone = openstack_utils.get_credentials("keystone") + keystone_client = keystoneclient.Client(**creds_keystone) + + creds_cinder = openstack_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 openstack_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/utils/functest_logger.py b/utils/functest_logger.py index 5639ed809..b9b308710 100644 --- a/utils/functest_logger.py +++ b/utils/functest_logger.py @@ -38,10 +38,10 @@ class Logger: CI_DEBUG = os.getenv('CI_DEBUG') - if CI_DEBUG.lower() == "true": + ch.setLevel(logging.INFO) + + if CI_DEBUG is not None and CI_DEBUG.lower() == "true": ch.setLevel(logging.DEBUG) - else: - ch.setLevel(logging.INFO) self.logger.addHandler(ch) diff --git a/utils/generate_defaults.py b/utils/generate_defaults.py new file mode 100644 index 000000000..4c2065e4a --- /dev/null +++ b/utils/generate_defaults.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python +# +# Description: +# Generates a list of the current Openstack objects in the deployment: +# - Nova instances +# - Glance images +# - Cinder volumes +# - Floating IPs +# - Neutron networks, subnets and ports +# - Routers +# - Users and tenants +# +# Author: +# jose.lausuch@ericsson.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 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 + +import functest.utils.openstack_utils as openstack_utils +import functest.utils.functest_logger as ft_logger + +""" logging configuration """ +logger = ft_logger.Logger("generate_defaults").getLogger() + +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) + + +DEFAULTS_FILE = '/home/opnfv/functest/conf/os_defaults.yaml' + + +def separator(): + logger.info("-------------------------------------------") + + +def get_instances(nova_client): + logger.debug("Getting instances...") + dic_instances = {} + instances = openstack_utils.get_instances(nova_client) + if not (instances is None or len(instances) == 0): + for instance in instances: + dic_instances.update({getattr(instance, 'id'): getattr(instance, + 'name')}) + return {'instances': dic_instances} + + +def get_images(nova_client): + logger.debug("Getting images...") + dic_images = {} + images = openstack_utils.get_images(nova_client) + if not (images is None or len(images) == 0): + for image in images: + dic_images.update({getattr(image, 'id'): getattr(image, 'name')}) + return {'images': dic_images} + + +def get_volumes(cinder_client): + logger.debug("Getting volumes...") + dic_volumes = {} + volumes = openstack_utils.get_volumes(cinder_client) + if volumes is not None: + for volume in volumes: + dic_volumes.update({volume.id: volume.display_name}) + return {'volumes': dic_volumes} + + +def get_networks(neutron_client): + logger.debug("Getting networks") + dic_networks = {} + networks = openstack_utils.get_network_list(neutron_client) + if networks is not None: + for network in networks: + dic_networks.update({network['id']: network['name']}) + return {'networks': dic_networks} + + +def get_routers(neutron_client): + logger.debug("Getting routers") + dic_routers = {} + routers = openstack_utils.get_router_list(neutron_client) + if routers is not None: + for router in routers: + dic_routers.update({router['id']: router['name']}) + return {'routers': dic_routers} + + +def get_security_groups(neutron_client): + logger.debug("Getting Security groups...") + dic_secgroups = {} + secgroups = openstack_utils.get_security_groups(neutron_client) + if not (secgroups is None or len(secgroups) == 0): + for secgroup in secgroups: + dic_secgroups.update({secgroup['id']: secgroup['name']}) + return {'secgroups': dic_secgroups} + + +def get_floatinips(nova_client): + logger.debug("Getting Floating IPs...") + dic_floatingips = {} + floatingips = openstack_utils.get_floating_ips(nova_client) + if not (floatingips is None or len(floatingips) == 0): + for floatingip in floatingips: + dic_floatingips.update({floatingip.id: floatingip.ip}) + return {'floatingips': dic_floatingips} + + +def get_users(keystone_client): + logger.debug("Getting users...") + dic_users = {} + users = openstack_utils.get_users(keystone_client) + if not (users is None or len(users) == 0): + for user in users: + dic_users.update({getattr(user, 'id'): getattr(user, 'name')}) + return {'users': dic_users} + + +def get_tenants(keystone_client): + logger.debug("Getting users...") + dic_tenants = {} + tenants = openstack_utils.get_tenants(keystone_client) + if not (tenants is None or len(tenants) == 0): + for tenant in tenants: + dic_tenants.update({getattr(tenant, 'id'): + getattr(tenant, 'name')}) + return {'tenants': dic_tenants} + + +def main(): + creds_nova = openstack_utils.get_credentials("nova") + nova_client = novaclient.Client('2', **creds_nova) + + creds_neutron = openstack_utils.get_credentials("neutron") + neutron_client = neutronclient.Client(**creds_neutron) + + creds_keystone = openstack_utils.get_credentials("keystone") + keystone_client = keystoneclient.Client(**creds_keystone) + + creds_cinder = openstack_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 openstack_utils.check_credentials(): + logger.error("Please source the openrc credentials and run the" + + "script again.") + exit(-1) + + defaults = {} + defaults.update(get_instances(nova_client)) + defaults.update(get_images(nova_client)) + defaults.update(get_volumes(cinder_client)) + defaults.update(get_networks(neutron_client)) + defaults.update(get_routers(neutron_client)) + defaults.update(get_security_groups(neutron_client)) + defaults.update(get_floatinips(nova_client)) + defaults.update(get_users(keystone_client)) + defaults.update(get_tenants(keystone_client)) + + with open(DEFAULTS_FILE, 'w+') as yaml_file: + yaml_file.write(yaml.safe_dump(defaults, default_flow_style=False)) + yaml_file.seek(0) + logger.debug("Openstack Defaults found in the deployment:") + print yaml_file.read() + logger.debug("NOTE: These objects will NOT be deleted after " + + "running the tests.") + + +if __name__ == '__main__': + main() diff --git a/utils/openstack_utils.py b/utils/openstack_utils.py index ff3968d67..2ae2842d4 100644 --- a/utils/openstack_utils.py +++ b/utils/openstack_utils.py @@ -10,6 +10,7 @@ import os import os.path +import subprocess import sys # ---------------------------------------------------------- @@ -73,6 +74,15 @@ def get_credentials(service): return creds +def source_credentials(rc_file): + pipe = subprocess.Popen(". %s; env" % rc_file, stdout=subprocess.PIPE, + shell=True) + output = pipe.communicate()[0] + env = dict((line.split("=", 1) for line in output.splitlines())) + os.environ.update(env) + return env + + # ********************************************* # NOVA # ********************************************* -- cgit 1.2.3-korg