diff options
Diffstat (limited to 'functest')
37 files changed, 1142 insertions, 946 deletions
diff --git a/functest/ci/config_aarch64_patch.yaml b/functest/ci/config_aarch64_patch.yaml index 9a345e3f..b43b5a76 100644 --- a/functest/ci/config_aarch64_patch.yaml +++ b/functest/ci/config_aarch64_patch.yaml @@ -5,10 +5,10 @@ os: image_file_name: cirros-d161201-aarch64-disk.img image_password: gocubsgo - snaps_simple_healthcheck: - disk_image: /home/opnfv/functest/data/cirros-d161201-aarch64-disk.img - kernel_image: /home/opnfv/functest/data/cirros-d161201-aarch64-kernel - ramdisk_image: /home/opnfv/functest/data/cirros-d161201-aarch64-initramfs + snaps_health_check: + disk_url: http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-disk.img + kernel_url: http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-kernel + ramdisk_url: http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-initramfs extra_properties: os_command_line: root=/dev/vdb1 rw rootwait console=tty0 console=ttyS0 console=ttyAMA0 hw_video_model: vga diff --git a/functest/ci/config_functest.yaml b/functest/ci/config_functest.yaml index 489c395f..b358a332 100755 --- a/functest/ci/config_functest.yaml +++ b/functest/ci/config_functest.yaml @@ -5,8 +5,8 @@ general: dir_odl: functest/opnfv_tests/sdn/odl rally: functest/opnfv_tests/openstack/rally tempest_cases: functest/opnfv_tests/openstack/tempest/custom_tests - dir_onos: functest/opnfv_tests/sdn/onos/teston - dir_onos_sfc: functest/opnfv_tests/sdn/onos/sfc + onos: functest/opnfv_tests/sdn/onos/teston + onos_sfc: functest/opnfv_tests/sdn/onos/sfc # Absolute path home: /home/opnfv @@ -18,7 +18,7 @@ general: repo_vims_test: /home/opnfv/repos/vnfs/vims-test repo_sdnvpn: /home/opnfv/repos/sdnvpn repo_sfc: /home/opnfv/repos/sfc - dir_repo_onos: /home/opnfv/repos/onos + repo_onos: /home/opnfv/repos/onos repo_promise: /home/opnfv/repos/promise repo_netready: /home/opnfv/repos/netready repo_barometer: /home/opnfv/repos/barometer @@ -28,8 +28,9 @@ general: repo_parser: /home/opnfv/repos/parser repo_domino: /home/opnfv/repos/domino repo_snaps: /home/opnfv/repos/snaps + repo_fds: /home/opnfv/repos/fds repo_securityscan: /home/opnfv/repos/securityscanning - repo_vrouter: /home/opnfv/repos/vrouter + repo_vrouter: /home/opnfv/repos/vnfs/vrouter functest: /home/opnfv/functest functest_test: /home/opnfv/repos/functest/functest/opnfv_tests results: /home/opnfv/functest/results @@ -38,13 +39,14 @@ general: functest_data: /home/opnfv/functest/data ims_data: /home/opnfv/functest/data/ims/ rally_inst: /home/opnfv/.rally + repo_kingbird: /home/opnfv/repos/kingbird openstack: creds: /home/opnfv/functest/conf/openstack.creds snapshot_file: /home/opnfv/functest/conf/openstack_snapshot.yaml - image_name: Cirros-0.3.4 - image_file_name: cirros-0.3.4-x86_64-disk.img + image_name: Cirros-0.3.5 + image_file_name: cirros-0.3.5-x86_64-disk.img image_disk_format: qcow2 image_username: cirros image_password: cubswin:) @@ -67,7 +69,7 @@ general: testcases_yaml: /home/opnfv/repos/functest/functest/ci/testcases.yaml healthcheck: - disk_image: /home/opnfv/functest/data/cirros-0.3.4-x86_64-disk.img + disk_image: /home/opnfv/functest/data/cirros-0.3.5-x86_64-disk.img disk_format: qcow2 wait_time: 60 diff --git a/functest/ci/config_patch.yaml b/functest/ci/config_patch.yaml index 46064a07..d984a3f4 100755 --- a/functest/ci/config_patch.yaml +++ b/functest/ci/config_patch.yaml @@ -1,12 +1,12 @@ lxd: general: openstack: - image_name: Cirros-0.3.4 - image_file_name: cirros-0.3.4-x86_64-lxc.tar.gz + image_name: Cirros-0.3.5 + image_file_name: cirros-0.3.5-x86_64-lxc.tar.gz image_disk_format: raw healthcheck: - disk_image: /home/opnfv/functest/data/cirros-0.3.4-x86_64-lxc.tar.gz + disk_image: /home/opnfv/functest/data/cirros-0.3.5-x86_64-lxc.tar.gz disk_format: raw fdio: general: diff --git a/functest/ci/exec_test.sh b/functest/ci/exec_test.sh deleted file mode 100755 index aa0cfaf7..00000000 --- a/functest/ci/exec_test.sh +++ /dev/null @@ -1,154 +0,0 @@ -#!/bin/bash - -# -# Author: Jose Lausuch (jose.lausuch@ericsson.com) -# Morgan Richomme (morgan.richomme@orange.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 -# - -usage="Script to trigger the tests automatically. - -usage: - bash $(basename "$0") [-h|--help] [-t <test_name>] - -where: - -h|--help show this help text - -r|--report push results to database (false by default) - -s|--serial run Tempest tests in one thread - -t|--test run specific test case - <test_name>" - - -report="" -serial=false - -# Get the list of runnable tests -# Check if we are in CI mode -debug="" -if [[ "${CI_DEBUG,,}" == "true" ]];then - debug="--debug" -fi - -FUNCTEST_REPO_DIR=${REPOS_DIR}/functest -FUNCTEST_TEST_DIR=${REPOS_DIR}/functest/functest/opnfv_tests -FUNCTEST_CONF_DIR=/home/opnfv/functest/conf - -export PYTHONUNBUFFERED=1 - -function odl_tests(){ - keystone_ip=$(openstack catalog show identity |grep publicURL| cut -f3 -d"/" | cut -f1 -d":") - neutron_ip=$(openstack catalog show network | grep publicURL | cut -f3 -d"/" | cut -f1 -d":") - odl_ip=${neutron_ip} - odl_port=8080 - odl_restport=8181 - if [ "$INSTALLER_TYPE" == "fuel" ]; then - odl_port=8282 - elif [ "$INSTALLER_TYPE" == "apex" ]; then - odl_ip=$SDN_CONTROLLER_IP - odl_port=8081 - odl_restport=8081 - elif [ "$INSTALLER_TYPE" == "netvirt" ]; then - odl_ip=$SDN_CONTROLLER_IP - odl_port=8081 - odl_restport=8081 - elif [ "$INSTALLER_TYPE" == "joid" ]; then - odl_ip=$SDN_CONTROLLER - elif [ "$INSTALLER_TYPE" == "compass" ]; then - odl_port=8181 - else - odl_ip=$SDN_CONTROLLER_IP - fi -} - - - -function run_test(){ - test_name=$1 - serial_flag="" - if [ $serial == "true" ]; then - serial_flag="-s" - fi - - case $test_name in - "healthcheck") - ${FUNCTEST_TEST_DIR}/openstack/healthcheck/healthcheck.sh - ;; - "odl") - odl_tests - [[ "$report" == "-r" ]] && args=-p - ${FUNCTEST_TEST_DIR}/sdn/odl/odl.py \ - --keystoneip $keystone_ip \ - --neutronip $neutron_ip \ - --odlip $odl_ip \ - --odlrestconfport $odl_restport \ - --odlwebport $odl_port \ - --ospassword ${OS_PASSWORD} \ - --ostenantname ${OS_TENANT_NAME} \ - --osusername ${OS_USERNAME} \ - ${args} - ;; - "onos") - python ${FUNCTEST_TEST_DIR}/sdn/onos/teston/onos.py - ;; - "onos_sfc") - python ${FUNCTEST_TEST_DIR}/sdn/onos/teston/onos.py -t sfc - ;; - "ovno") - # suite under rewritting for colorado - # no need to run anything until refactoring done - # ${REPOS_DIR}/ovno/Testcases/RunTests.sh - ;; - *) - echo "The test case '${test_name}' does not exist." - exit 1 - esac - - if [[ $? != 0 ]]; then exit 1 - else exit 0 - fi -} - - -# Parse parameters -while [[ $# > 0 ]] - do - key="$1" - case $key in - -h|--help) - echo "$usage" - exit 0 - shift - ;; - -r|--report) - report="-r" - ;; - -s|--serial) - serial=true - ;; - -t|--test|--tests) - TEST="$2" - shift - ;; - *) - echo "unknown option $1 $2" - exit 1 - ;; - esac - shift # past argument or value -done - - -# Source credentials -echo "Sourcing Credentials ${creds} to run the test.." -source ${creds} - - -# Run test -run_test $TEST diff --git a/functest/ci/prepare_env.py b/functest/ci/prepare_env.py index f5bae6a0..724ea14d 100755 --- a/functest/ci/prepare_env.py +++ b/functest/ci/prepare_env.py @@ -31,6 +31,7 @@ logger = ft_logger.Logger("prepare_env").getLogger() handler = None # set the architecture to default pod_arch = None +arch_filter = ['aarch64'] CONFIG_FUNCTEST_PATH = CONST.CONFIG_FUNCTEST_YAML CONFIG_PATCH_PATH = os.path.join(os.path.dirname( @@ -115,24 +116,28 @@ def get_deployment_handler(): 'functest/ci/installer_params.yaml') if (CONST.INSTALLER_IP and CONST.INSTALLER_TYPE and CONST.INSTALLER_TYPE in opnfv_constants.INSTALLERS): - installer_params = ft_utils.get_parameter_from_yaml( - CONST.INSTALLER_TYPE, installer_params_yaml) - - user = installer_params.get('user', None) - password = installer_params.get('password', None) - pkey = installer_params.get('pkey', None) - try: - handler = factory.Factory.get_handler( - installer=CONST.INSTALLER_TYPE, - installer_ip=CONST.INSTALLER_IP, - installer_user=user, - installer_pwd=password, - pkey_file=pkey) - if handler: - pod_arch = handler.get_arch() - except Exception as e: - logger.debug("Cannot get deployment information. %s" % e) + installer_params = ft_utils.get_parameter_from_yaml( + CONST.INSTALLER_TYPE, installer_params_yaml) + except ValueError as e: + logger.debug('Printing deployment info is not supported for %s' % + CONST.INSTALLER_TYPE) + logger.debug(e) + else: + user = installer_params.get('user', None) + password = installer_params.get('password', None) + pkey = installer_params.get('pkey', None) + try: + handler = factory.Factory.get_handler( + installer=CONST.INSTALLER_TYPE, + installer_ip=CONST.INSTALLER_IP, + installer_user=user, + installer_pwd=password, + pkey_file=pkey) + if handler: + pod_arch = handler.get_arch() + except Exception as e: + logger.debug("Cannot get deployment information. %s" % e) def create_directories(): @@ -196,8 +201,7 @@ def source_rc_file(): raise Exception("The file %s is empty." % CONST.openstack_creds) logger.info("Sourcing the OpenStack RC file...") - os_utils.source_credentials( - CONST.openstack_creds) + os_utils.source_credentials(CONST.openstack_creds) for key, value in os.environ.iteritems(): if re.search("OS_", key): if key == 'OS_AUTH_URL': @@ -210,10 +214,15 @@ def source_rc_file(): CONST.OS_PASSWORD = value -def patch_config_file(patch_file_path, arch_filter=None): - if arch_filter and pod_arch not in arch_filter: - return +def patch_config_file(): + patch_file(CONFIG_PATCH_PATH) + + if pod_arch and pod_arch in arch_filter: + patch_file(CONFIG_AARCH64_PATCH_PATH) + +def patch_file(patch_file_path): + logger.debug('Updating file: %s', patch_file_path) with open(patch_file_path) as f: patch_file = yaml.safe_load(f) @@ -250,7 +259,7 @@ def verify_deployment(): def install_rally(): print_separator() - if 'aarch64' in pod_arch: + if pod_arch and pod_arch in arch_filter: logger.info("Apply aarch64 specific to rally config...") with open(RALLY_AARCH64_PATCH_PATH, "r") as f: rally_patch_conf = f.read() @@ -350,8 +359,7 @@ def main(**kwargs): get_deployment_handler() create_directories() source_rc_file() - patch_config_file(CONFIG_PATCH_PATH) - patch_config_file(CONFIG_AARCH64_PATCH_PATH, 'aarch64') + patch_config_file() verify_deployment() install_rally() install_tempest() diff --git a/functest/ci/run_tests.py b/functest/ci/run_tests.py index f920e70d..4a47ba57 100755 --- a/functest/ci/run_tests.py +++ b/functest/ci/run_tests.py @@ -19,7 +19,6 @@ import sys import functest.ci.generate_report as generate_report import functest.ci.tier_builder as tb import functest.core.testcase_base as testcase_base -import functest.utils.functest_constants as ft_constants import functest.utils.functest_logger as ft_logger import functest.utils.functest_utils as ft_utils import functest.utils.openstack_clean as os_clean @@ -32,13 +31,6 @@ from functest.utils.constants import CONST logger = ft_logger.Logger("run_tests").getLogger() -""" global variables """ -EXEC_SCRIPT = ("%s/functest/ci/exec_test.sh" % CONST.dir_repo_functest) - -# This will be the return code of this script. If any of the tests fails, -# this variable will change to Result.EX_ERROR - - class Result(enum.Enum): EX_OK = os.EX_OK EX_ERROR = -1 @@ -91,16 +83,12 @@ def source_rc_file(): for key, value in os.environ.iteritems(): if re.search("OS_", key): if key == 'OS_AUTH_URL': - ft_constants.OS_AUTH_URL = value CONST.OS_AUTH_URL = value elif key == 'OS_USERNAME': - ft_constants.OS_USERNAME = value CONST.OS_USERNAME = value elif key == 'OS_TENANT_NAME': - ft_constants.OS_TENANT_NAME = value CONST.OS_TENANT_NAME = value elif key == 'OS_PASSWORD': - ft_constants.OS_PASSWORD = value CONST.OS_PASSWORD = value @@ -119,7 +107,7 @@ def update_test_info(test_name, result, duration): "duration": duration}) -def get_run_dict_if_defined(testname): +def get_run_dict(testname): try: dict = ft_utils.get_dict_by_test(testname) if not dict: @@ -143,7 +131,7 @@ def run_test(test, tier_name, testcases=None): logger.debug("\n%s" % test) source_rc_file() - if GlobalVariables.CLEAN_FLAG: + if test.needs_clean() and GlobalVariables.CLEAN_FLAG: generate_os_snapshot() flags = (" -t %s" % (test_name)) @@ -151,12 +139,13 @@ def run_test(test, tier_name, testcases=None): flags += " -r" result = testcase_base.TestcaseBase.EX_RUN_ERROR - run_dict = get_run_dict_if_defined(test_name) + run_dict = get_run_dict(test_name) if run_dict: try: module = importlib.import_module(run_dict['module']) cls = getattr(module, run_dict['class']) test_case = cls() + try: kwargs = run_dict['args'] result = test_case.run(**kwargs) @@ -173,14 +162,11 @@ def run_test(test, tier_name, testcases=None): logger.exception("Cannot get class {}".format( run_dict['class'])) else: - cmd = ("%s%s" % (EXEC_SCRIPT, flags)) - logger.info("Executing command {} because {} " - "doesn't implement the new framework".format( - cmd, test_name)) - result = ft_utils.execute_command(cmd) + raise Exception("Cannot import the class for the test case.") - if GlobalVariables.CLEAN_FLAG: + if test.needs_clean() and GlobalVariables.CLEAN_FLAG: cleanup() + end = datetime.datetime.now() duration = (end - start).seconds duration_str = ("%02d:%02d" % divmod(duration, 60)) diff --git a/functest/ci/testcases.yaml b/functest/ci/testcases.yaml index ed3a0b84..767380fc 100755 --- a/functest/ci/testcases.yaml +++ b/functest/ci/testcases.yaml @@ -8,24 +8,10 @@ tiers: operations in the VIM. testcases: - - name: snaps_health_check - criteria: 'status == "PASS"' - blocking: true - description: >- - This test case creates executes the SimpleHealthCheck - Python test class which creates an, image, flavor, network, - and Cirros VM instance and observes the console output to - validate the single port obtains the correct IP address. - dependencies: - installer: '' - scenario: '^((?!lxd).)*$' - run: - module: 'functest.opnfv_tests.openstack.snaps.health_check' - class: 'HealthCheck' - - name: connection_check criteria: 'status == "PASS"' blocking: true + clean_flag: false description: >- This test case verifies the retrieval of OpenStack clients: Keystone, Glance, Neutron and Nova and may perform some @@ -44,6 +30,7 @@ tiers: name: api_check criteria: 'status == "PASS"' blocking: true + clean_flag: false description: >- This test case verifies the retrieval of OpenStack clients: Keystone, Glance, Neutron and Nova and may perform some @@ -57,6 +44,22 @@ tiers: run: module: 'functest.opnfv_tests.openstack.snaps.api_check' class: 'ApiCheck' + - + name: snaps_health_check + criteria: 'status == "PASS"' + blocking: true + clean_flag: false + description: >- + This test case creates executes the SimpleHealthCheck + Python test class which creates an, image, flavor, network, + and Cirros VM instance and observes the console output to + validate the single port obtains the correct IP address. + dependencies: + installer: '' + scenario: '^((?!lxd).)*$' + run: + module: 'functest.opnfv_tests.openstack.snaps.health_check' + class: 'HealthCheck' - name: smoke order: 1 @@ -68,13 +71,14 @@ tiers: name: vping_ssh criteria: 'status == "PASS"' blocking: true + clean_flag: true 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|odl_l3).)*$' + scenario: '^((?!odl_l3).)*$' run: module: 'functest.opnfv_tests.openstack.vping.vping_ssh' class: 'VPingSSH' @@ -83,6 +87,7 @@ tiers: name: vping_userdata criteria: 'status == "PASS"' blocking: true + clean_flag: true description: >- This test case verifies: 1) Boot a VM with given userdata. 2) Connectivity between 2 instances over a private network. @@ -97,6 +102,7 @@ tiers: name: tempest_smoke_serial criteria: 'success_rate == 100%' blocking: false + clean_flag: false description: >- This test case runs the smoke subset of the OpenStack Tempest suite. The list of test cases is generated by @@ -113,12 +119,13 @@ tiers: name: rally_sanity criteria: 'success_rate == 100%' blocking: false + clean_flag: false description: >- This test case runs a sub group of tests of the OpenStack Rally suite in smoke mode. dependencies: installer: '' - scenario: '^((?!bgpvpn).)*$' + scenario: '' run: module: 'functest.opnfv_tests.openstack.rally.rally' class: 'RallySanity' @@ -127,6 +134,7 @@ tiers: name: odl criteria: 'success_rate == 100%' blocking: true + clean_flag: false description: >- Test Suite for the OpenDaylight SDN Controller. It integrates some test suites from upstream using @@ -146,14 +154,15 @@ tiers: name: odl_netvirt criteria: 'success_rate == 100%' blocking: true + clean_flag: false description: >- Test Suite for the OpenDaylight SDN Controller when the NetVirt features are installed. It integrates some test suites from upstream using Robot as the test framework. dependencies: - installer: '' - scenario: 'netvirt' + installer: 'apex' + scenario: 'os-odl_l3-nofeature' run: module: 'functest.opnfv_tests.sdn.odl.odl' class: 'ODLTests' @@ -164,9 +173,29 @@ tiers: - /home/opnfv/repos/odl_test/csit/suites/openstack/connectivity - + name: fds + criteria: 'success_rate == 100%' + blocking: false + clean_flag: false + description: >- + Test Suite for the OpenDaylight SDN Controller when GBP features are + installed. It integrates some test suites from upstream using + Robot as the test framework. + dependencies: + installer: 'apex' + scenario: 'odl_l2-fdio' + run: + module: 'functest.opnfv_tests.sdn.odl.odl' + class: 'ODLTests' + args: + suites: + - /home/opnfv/repos/fds/testing/robot + + - name: onos criteria: 'status == "PASS"' blocking: true + clean_flag: true description: >- Test Suite for the ONOS SDN Controller. It integrates some test suites from upstream using TestON as the test @@ -174,12 +203,15 @@ tiers: dependencies: installer: '' scenario: 'onos' - + run: + module: 'functest.opnfv_tests.sdn.onos.onos' + class: 'Onos' - name: snaps_smoke criteria: 'status == "PASS"' blocking: false + clean_flag: false description: >- This test case contains tests that setup and destroy environments with VMs with and without Floating IPs @@ -191,7 +223,7 @@ tiers: dependencies: installer: '^((?!netvirt).)*$' - scenario: '' + scenario: '^((?!lxd).)*$' run: module: 'functest.opnfv_tests.openstack.snaps.smoke' class: 'SnapsSmoke' @@ -208,6 +240,7 @@ tiers: name: promise criteria: 'success_rate == 100%' blocking: false + clean_flag: true description: >- Test suite from Promise project. dependencies: @@ -221,6 +254,7 @@ tiers: name: doctor criteria: 'status == "PASS"' blocking: false + clean_flag: true description: >- Test suite from Doctor project. dependencies: @@ -234,6 +268,7 @@ tiers: name: bgpvpn criteria: 'status == "PASS"' blocking: false + clean_flag: true description: >- Test suite from SDNVPN project. dependencies: @@ -247,6 +282,7 @@ tiers: name: security_scan criteria: 'status == "PASS"' blocking: false + clean_flag: true description: >- Simple Security Scan dependencies: @@ -259,6 +295,7 @@ tiers: # name: copper # criteria: 'status == "PASS"' # blocking: false +# clean_flag: true # description: >- # Test suite for policy management based on OpenStack Congress # dependencies: @@ -271,6 +308,7 @@ tiers: name: multisite criteria: 'success_rate == 100%' blocking: false + clean_flag: false description: >- Test suite from kingbird dependencies: @@ -283,6 +321,7 @@ tiers: name: odl-sfc criteria: 'status == "PASS"' blocking: false + clean_flag: true description: >- Test suite for odl-sfc to test two chains and two SFs dependencies: @@ -295,15 +334,20 @@ tiers: name: onos_sfc criteria: 'status == "PASS"' blocking: true + clean_flag: true description: >- Test Suite for onos-sfc to test sfc function. dependencies: installer: '' scenario: 'onos-sfc' + run: + module: 'functest.opnfv_tests.sdn.onos.onos' + class: 'OnosSfc' - name: parser criteria: 'ret == 0' blocking: false + clean_flag: true description: >- Test suite from Parser project. dependencies: @@ -316,6 +360,7 @@ tiers: name: domino criteria: 'status == "PASS"' blocking: false + clean_flag: true description: >- Test suite from Domino project. dependencies: @@ -325,21 +370,10 @@ tiers: module: 'functest.opnfv_tests.features.domino' class: 'Domino' - - name: orchestra - criteria: 'ret == 0' - blocking: false - description: >- - Test OpenBaton (Orchestra) stack - dependencies: - installer: 'joid' - scenario: 'unknown' - run: - module: 'functest.opnfv_tests.features.orchestrator.orchestra' - class: 'OpenbatonOrchestrator' - - name: netready criteria: 'status == "PASS"' blocking: false + clean_flag: true description: >- Test suite from Netready project. dependencies: @@ -352,6 +386,7 @@ tiers: name: barometer criteria: 'status == "PASS"' blocking: false + clean_flag: true description: >- Test suite for the Barometer project. Separate tests verify the proper configuration and functionality of the following @@ -374,6 +409,7 @@ tiers: # name: tempest_full_parallel # criteria: 'success_rate >= 80%' # blocking: false +# clean_flag: false # description: >- # The list of test cases is generated by # Tempest automatically and depends on the parameters of @@ -388,6 +424,7 @@ tiers: name: tempest_defcore criteria: 'success_rate == 100%' blocking: false + clean_flag: false description: >- This is the set of Tempest test cases created by OpenStack Interop Working Group for certification purposes. @@ -401,6 +438,7 @@ tiers: name: tempest_custom criteria: 'success_rate == 100%' blocking: false + clean_flag: false description: >- The test case allows running a customized list of tempest test cases defined in a file under @@ -417,6 +455,7 @@ tiers: # name: rally_full # criteria: 'success_rate >= 90%' # blocking: false +# clean_flag: false # description: >- # This test case runs the full suite of scenarios of the OpenStack # Rally suite using several threads and iterations. @@ -438,6 +477,7 @@ tiers: name: cloudify_ims criteria: 'status == "PASS"' blocking: false + clean_flag: true description: >- This test case deploys an OpenSource vIMS solution from Clearwater using the Cloudify orchestrator. It also runs some signaling traffic. @@ -447,36 +487,24 @@ tiers: run: module: 'functest.opnfv_tests.vnf.ims.cloudify_ims' class: 'ImsVnf' - - - name: aaa - criteria: 'ret == 0' - blocking: false - description: >- - Test suite from Parser project. - dependencies: - installer: '' - scenario: '' - run: - module: 'functest.opnfv_tests.vnf.aaa.aaa' - class: 'AaaVnf' - - - - name: juju_epc - criteria: 'ret == 0' - blocking: false - description: >- - Test suite from OAI project, vEPC deployed with Juju. - dependencies: - installer: 'unknown' - scenario: 'unknown' - run: - module: 'functest.opnfv_tests.vnf.epc.epc' - class: 'EpcVnf' - +# - +# name: aaa +# criteria: 'ret == 0' +# blocking: false +# clean_flag: true +# description: >- +# Test suite from Parser project. +# dependencies: +# installer: '' +# scenario: '' +# run: +# module: 'functest.opnfv_tests.vnf.aaa.aaa' +# class: 'AaaVnf' - name: orchestra_ims criteria: 'ret == 0' blocking: false + clean_flag: true description: >- VNF deployment with OpenBaton (Orchestra) dependencies: @@ -490,6 +518,7 @@ tiers: name: opera_ims criteria: 'ret == 0' blocking: false + clean_flag: true description: >- Evolution of vIMS dependencies: @@ -503,6 +532,7 @@ tiers: name: vyos_vrouter criteria: 'status == "PASS"' blocking: false + clean_flag: true description: >- This test case is vRouter testing. dependencies: diff --git a/functest/ci/tier_builder.py b/functest/ci/tier_builder.py index dae7c73e..f4c6f70f 100755 --- a/functest/ci/tier_builder.py +++ b/functest/ci/tier_builder.py @@ -50,6 +50,7 @@ class TierBuilder(object): dependency=dep, criteria=dic_testcase['criteria'], blocking=dic_testcase['blocking'], + clean_flag=dic_testcase['clean_flag'], description=dic_testcase['description']) if testcase.is_compatible(self.ci_installer, self.ci_scenario): tier.add_test(testcase) diff --git a/functest/ci/tier_handler.py b/functest/ci/tier_handler.py index 127986bf..6b4864b5 100755 --- a/functest/ci/tier_handler.py +++ b/functest/ci/tier_handler.py @@ -104,12 +104,18 @@ class Tier(object): class TestCase(object): - def __init__(self, name, dependency, criteria, blocking, description=""): + def __init__(self, name, + dependency, + criteria, + blocking, + clean_flag, + description=""): self.name = name self.dependency = dependency - self.description = description self.criteria = criteria self.blocking = blocking + self.clean_flag = clean_flag + self.description = description @staticmethod def is_none(item): @@ -138,6 +144,9 @@ class TestCase(object): def is_blocking(self): return self.blocking + def needs_clean(self): + return self.clean_flag + def __str__(self): lines = split_text(self.description, LINE_LENGTH - 6) diff --git a/functest/core/pytest_suite_runner.py b/functest/core/pytest_suite_runner.py index c168d7d9..f0ae265a 100644 --- a/functest/core/pytest_suite_runner.py +++ b/functest/core/pytest_suite_runner.py @@ -1,5 +1,3 @@ -#!/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 diff --git a/functest/core/vnf_base.py b/functest/core/vnf_base.py index 9438dca1..daf8b806 100644 --- a/functest/core/vnf_base.py +++ b/functest/core/vnf_base.py @@ -79,7 +79,8 @@ class VnfOnBoardingBase(base.TestcaseBase): self.details['vnf']['result'] = res_deploy_vnf['result'] self.details['vnf']['duration'] = round( vnf_ready_time - orchestrator_ready_time, 1) - except: + except Exception: + self.logger.error("Error during VNF deployment", exc_info=True) raise Exception("Error during VNF deployment") # Test VNF @@ -91,7 +92,8 @@ class VnfOnBoardingBase(base.TestcaseBase): self.details['test_vnf']['result'] = res_test_vnf['result'] self.details['test_vnf']['duration'] = round( test_vnf_done_time - vnf_ready_time, 1) - except: + except Exception: + self.logger.error("Error when running VNF tests", exc_info=True) raise Exception("Error when running VNF tests") # Clean the system diff --git a/functest/opnfv_tests/features/barometer.py b/functest/opnfv_tests/features/barometer.py index aec2bce5..32067284 100644 --- a/functest/opnfv_tests/features/barometer.py +++ b/functest/opnfv_tests/features/barometer.py @@ -6,11 +6,9 @@ # # http://www.apache.org/licenses/LICENSE-2.0 +from baro_tests import collectd import functest.core.feature_base as base -import functest.utils.functest_logger as ft_logger - -from baro_tests import collectd class BarometerCollectd(base.FeatureBase): @@ -22,7 +20,6 @@ class BarometerCollectd(base.FeatureBase): super(BarometerCollectd, self).__init__(project='barometer', case='barometercollectd', repo='dir_repo_barometer') - self.logger = ft_logger.Logger("BarometerCollectd").getLogger() def execute(self): return collectd.main(self.logger) diff --git a/functest/opnfv_tests/features/security_scan.py b/functest/opnfv_tests/features/security_scan.py index 2db44175..58f0ec74 100755 --- a/functest/opnfv_tests/features/security_scan.py +++ b/functest/opnfv_tests/features/security_scan.py @@ -17,8 +17,8 @@ class SecurityScan(base.FeatureBase): super(SecurityScan, self).__init__(project='securityscanning', case='security_scan', repo='dir_repo_securityscan') - self.cmd = ('bash {0} && ' + self.cmd = ('. {0}/stackrc && ' 'cd {1} && ' 'python security_scan.py --config config.ini && ' - 'cd -'.format(CONST.openstack_creds, + 'cd -'.format(CONST.dir_functest_conf, self.repo)) diff --git a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template index 909f45d2..ed5e61fe 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template +++ b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template @@ -7,7 +7,7 @@ parameters: default: public image: type: string - default: cirros-0.3.4-x86_64-uec + default: cirros-0.3.5-x86_64-uec flavor: type: string default: m1.tiny diff --git a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template index 826ca9da..116b5bb6 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template +++ b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template @@ -4,7 +4,7 @@ parameters: # set all correct defaults for parameters before launch test image: type: string - default: cirros-0.3.4-x86_64-uec + default: cirros-0.3.5-x86_64-uec flavor: type: string default: m1.tiny diff --git a/functest/opnfv_tests/openstack/snaps/api_check.py b/functest/opnfv_tests/openstack/snaps/api_check.py index 17d05b92..ad77d9be 100644 --- a/functest/opnfv_tests/openstack/snaps/api_check.py +++ b/functest/opnfv_tests/openstack/snaps/api_check.py @@ -9,12 +9,12 @@ import unittest from snaps import test_suite_builder -from functest.core.pytest_suite_runner import PyTestSuiteRunner -from functest.opnfv_tests.openstack.snaps import snaps_utils +from functest.opnfv_tests.openstack.snaps.snaps_test_runner import \ + SnapsTestRunner from functest.utils.constants import CONST -class ApiCheck(PyTestSuiteRunner): +class ApiCheck(SnapsTestRunner): """ This test executes the Python Tests included with the SNAPS libraries that exercise many of the OpenStack APIs within Keystone, Glance, Neutron, @@ -25,10 +25,9 @@ class ApiCheck(PyTestSuiteRunner): self.suite = unittest.TestSuite() self.case_name = "api_check" - ext_net_name = snaps_utils.get_ext_net_name() test_suite_builder.add_openstack_api_tests( self.suite, CONST.openstack_creds, - ext_net_name, + self.ext_net_name, use_keystone=CONST.snaps_use_keystone) diff --git a/functest/opnfv_tests/openstack/snaps/connection_check.py b/functest/opnfv_tests/openstack/snaps/connection_check.py index 11f8ad07..0637bcfb 100644 --- a/functest/opnfv_tests/openstack/snaps/connection_check.py +++ b/functest/opnfv_tests/openstack/snaps/connection_check.py @@ -9,12 +9,12 @@ import unittest from snaps import test_suite_builder -from functest.core.pytest_suite_runner import PyTestSuiteRunner -from functest.opnfv_tests.openstack.snaps import snaps_utils +from functest.opnfv_tests.openstack.snaps.snaps_test_runner import \ + SnapsTestRunner from functest.utils.constants import CONST -class ConnectionCheck(PyTestSuiteRunner): +class ConnectionCheck(SnapsTestRunner): """ This test executes the Python Tests included with the SNAPS libraries that simply obtain the different OpenStack clients and may perform @@ -25,10 +25,9 @@ class ConnectionCheck(PyTestSuiteRunner): self.suite = unittest.TestSuite() self.case_name = "connection_check" - ext_net_name = snaps_utils.get_ext_net_name() test_suite_builder.add_openstack_client_tests( self.suite, CONST.openstack_creds, - ext_net_name, + self.ext_net_name, use_keystone=CONST.snaps_use_keystone) diff --git a/functest/opnfv_tests/openstack/snaps/health_check.py b/functest/opnfv_tests/openstack/snaps/health_check.py index 993c1000..8fece746 100644 --- a/functest/opnfv_tests/openstack/snaps/health_check.py +++ b/functest/opnfv_tests/openstack/snaps/health_check.py @@ -7,15 +7,15 @@ import unittest +from functest.opnfv_tests.openstack.snaps.snaps_test_runner import \ + SnapsTestRunner +from functest.utils.constants import CONST + from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase from snaps.openstack.tests.create_instance_tests import SimpleHealthCheck -from functest.core.pytest_suite_runner import PyTestSuiteRunner -from functest.opnfv_tests.openstack.snaps import snaps_utils -from functest.utils.constants import CONST - -class HealthCheck(PyTestSuiteRunner): +class HealthCheck(SnapsTestRunner): """ This test executes the SNAPS Python Test case SimpleHealthCheck which creates a VM with a single port with an IPv4 address that is assigned by @@ -26,9 +26,14 @@ class HealthCheck(PyTestSuiteRunner): self.suite = unittest.TestSuite() self.case_name = "snaps_health_check" - ext_net_name = snaps_utils.get_ext_net_name() + + image_custom_config = None + if hasattr(CONST, 'snaps_health_check'): + image_custom_config = CONST.snaps_health_check self.suite.addTest( OSIntegrationTestCase.parameterize( - SimpleHealthCheck, CONST.openstack_creds, ext_net_name, - use_keystone=CONST.snaps_use_keystone)) + SimpleHealthCheck, CONST.openstack_creds, self.ext_net_name, + use_keystone=CONST.snaps_use_keystone, + flavor_metadata=self.flavor_metadata, + image_metadata=image_custom_config)) diff --git a/functest/opnfv_tests/openstack/snaps/smoke.py b/functest/opnfv_tests/openstack/snaps/smoke.py index 83eb6600..864bca5e 100644 --- a/functest/opnfv_tests/openstack/snaps/smoke.py +++ b/functest/opnfv_tests/openstack/snaps/smoke.py @@ -10,12 +10,12 @@ import unittest from snaps import test_suite_builder -from functest.core.pytest_suite_runner import PyTestSuiteRunner -from functest.opnfv_tests.openstack.snaps import snaps_utils +from functest.opnfv_tests.openstack.snaps.snaps_test_runner import \ + SnapsTestRunner from functest.utils.constants import CONST -class SnapsSmoke(PyTestSuiteRunner): +class SnapsSmoke(SnapsTestRunner): """ This test executes the Python Tests included with the SNAPS libraries that exercise many of the OpenStack APIs within Keystone, Glance, Neutron, @@ -27,7 +27,12 @@ class SnapsSmoke(PyTestSuiteRunner): self.suite = unittest.TestSuite() self.case_name = "snaps_smoke" use_fip = CONST.snaps_use_floating_ips - ext_net_name = snaps_utils.get_ext_net_name() + + # The snaps smoke test uses the same config as the + # snaps_health_check suite, so reuse it here + image_custom_config = None + if hasattr(CONST, 'snaps_health_check'): + image_custom_config = CONST.snaps_health_check # Tests requiring floating IPs leverage files contained within the # SNAPS repository and are found relative to that path @@ -38,6 +43,7 @@ class SnapsSmoke(PyTestSuiteRunner): test_suite_builder.add_openstack_integration_tests( self.suite, CONST.openstack_creds, - ext_net_name, + self.ext_net_name, use_keystone=CONST.snaps_use_keystone, + image_metadata=image_custom_config, use_floating_ips=use_fip) diff --git a/functest/opnfv_tests/openstack/snaps/snaps_test_runner.py b/functest/opnfv_tests/openstack/snaps/snaps_test_runner.py new file mode 100644 index 00000000..67cd9415 --- /dev/null +++ b/functest/opnfv_tests/openstack/snaps/snaps_test_runner.py @@ -0,0 +1,30 @@ +# 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 + +from functest.core.pytest_suite_runner import PyTestSuiteRunner +from functest.opnfv_tests.openstack.snaps import snaps_utils +from functest.utils import functest_utils + +from snaps.openstack import create_flavor + + +class SnapsTestRunner(PyTestSuiteRunner): + """ + This test executes the SNAPS Python Test case SimpleHealthCheck which + creates a VM with a single port with an IPv4 address that is assigned by + DHCP. This test then validates the expected IP with the actual + """ + def __init__(self): + super(SnapsTestRunner, self).__init__() + + self.ext_net_name = snaps_utils.get_ext_net_name() + + scenario = functest_utils.get_scenario() + + self.flavor_metadata = create_flavor.MEM_PAGE_SIZE_ANY + if 'ovs' in scenario or 'fdio' in scenario: + self.flavor_metadata = create_flavor.MEM_PAGE_SIZE_LARGE diff --git a/functest/opnfv_tests/openstack/tempest/conf_utils.py b/functest/opnfv_tests/openstack/tempest/conf_utils.py index 893fff8c..2c113367 100644 --- a/functest/opnfv_tests/openstack/tempest/conf_utils.py +++ b/functest/opnfv_tests/openstack/tempest/conf_utils.py @@ -106,6 +106,17 @@ def get_verifier_deployment_dir(verifier_id, deployment_id): 'for-deployment-{}'.format(deployment_id)) +def get_repo_tag(repo): + """ + Returns last tag of current branch + """ + cmd = ("git -C {0} describe --abbrev=0 HEAD".format(repo)) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + tag = p.stdout.readline().rstrip() + + return str(tag) + + def backup_tempest_config(conf_file): """ Copy config file to tempest results directory @@ -276,3 +287,16 @@ def configure_tempest_multisite_params(tempest_conf_file): config.write(config_file) backup_tempest_config(tempest_conf_file) + + +def install_verifier_ext(path): + """ + Install extension to active verifier + """ + logger.info("Installing verifier from existing repo...") + tag = get_repo_tag(path) + cmd = ("rally verify add-verifier-ext --source {0} " + "--version {1}" + .format(path, tag)) + error_msg = ("Problem while adding verifier extension from %s" % path) + ft_utils.execute_command_raise(cmd, error_msg=error_msg) diff --git a/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt b/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt index 0a4256ce..fcdfe225 100644 --- a/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt +++ b/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt @@ -1,22 +1,3 @@ -- - scenarios: - - os-odl_l2-bgpvpn-ha - - os-odl_l2-bgpvpn-noha - installers: - - fuel - - apex - tests: - - tempest.api.compute.servers.test_create_server.ServersTestJSON.test_list_servers - - 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_verify_server_details - - tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_reboot_server_hard - - tempest.api.network.test_floating_ips.FloatingIPTestJSON.test_create_list_show_update_delete_floating_ip - - tempest.api.network.test_floating_ips.FloatingIPTestJSON.test_create_floating_ip_specifying_a_fixed_ip_address - - tempest.scenario.test_network_basic_ops.TestNetworkBasicOps.test_network_basic_ops - - tempest.scenario.test_server_basic_ops.TestServerBasicOps.test_server_basic_ops - - tempest.scenario.test_volume_boot_pattern.TestVolumeBootPattern.test_volume_boot_pattern - - tempest.scenario.test_volume_boot_pattern.TestVolumeBootPatternV2.test_volume_boot_pattern - scenarios: diff --git a/functest/opnfv_tests/openstack/tempest/tempest.py b/functest/opnfv_tests/openstack/tempest/tempest.py index ae4eed09..a6ce4ee6 100644 --- a/functest/opnfv_tests/openstack/tempest/tempest.py +++ b/functest/opnfv_tests/openstack/tempest/tempest.py @@ -161,7 +161,8 @@ class TempestCommon(testcase_base.TestcaseBase): result_file.close() def run_verifier_tests(self): - self.OPTION += (" --load-list {}".format(conf_utils.TEMPEST_LIST)) + self.OPTION += (" --load-list {} --detailed" + .format(conf_utils.TEMPEST_LIST)) cmd_line = "rally verify start " + self.OPTION logger.info("Starting Tempest test suite: '%s'." % cmd_line) @@ -315,6 +316,7 @@ class TempestMultisite(TempestCommon): self.case_name = "multisite" self.MODE = "feature_multisite" self.OPTION = "--concurrency 1" + conf_utils.install_verifier_ext(CONST.dir_repo_kingbird) class TempestCustom(TempestCommon): diff --git a/functest/opnfv_tests/sdn/odl/odl.py b/functest/opnfv_tests/sdn/odl/odl.py index 69818f5a..c8e9c492 100755 --- a/functest/opnfv_tests/sdn/odl/odl.py +++ b/functest/opnfv_tests/sdn/odl/odl.py @@ -94,8 +94,11 @@ class ODLTests(testcase_base.TestcaseBase): try: odlusername = kwargs['odlusername'] odlpassword = kwargs['odlpassword'] - variables = ['KEYSTONE:' + kwargs['keystoneip'], + osauthurl = kwargs['osauthurl'] + keystoneip = urlparse.urlparse(osauthurl).hostname + variables = ['KEYSTONE:' + keystoneip, 'NEUTRON:' + kwargs['neutronip'], + 'OS_AUTH_URL:"' + osauthurl + '"', 'OSUSERNAME:"' + kwargs['osusername'] + '"', 'OSTENANTNAME:"' + kwargs['ostenantname'] + '"', 'OSPASSWORD:"' + kwargs['ospassword'] + '"', @@ -147,10 +150,8 @@ class ODLTests(testcase_base.TestcaseBase): suites = kwargs["suites"] except KeyError: pass - keystone_url = op_utils.get_endpoint(service_type='identity') neutron_url = op_utils.get_endpoint(service_type='network') - kwargs = {'keystoneip': urlparse.urlparse(keystone_url).hostname} - kwargs['neutronip'] = urlparse.urlparse(neutron_url).hostname + kwargs = {'neutronip': urlparse.urlparse(neutron_url).hostname} kwargs['odlip'] = kwargs['neutronip'] kwargs['odlwebport'] = '8080' kwargs['odlrestconfport'] = '8181' @@ -161,6 +162,7 @@ class ODLTests(testcase_base.TestcaseBase): installer_type = os.environ['INSTALLER_TYPE'] kwargs['osusername'] = os.environ['OS_USERNAME'] kwargs['ostenantname'] = os.environ['OS_TENANT_NAME'] + kwargs['osauthurl'] = os.environ['OS_AUTH_URL'] kwargs['ospassword'] = os.environ['OS_PASSWORD'] if installer_type == 'fuel': kwargs['odlwebport'] = '8282' @@ -191,12 +193,12 @@ class ODLParser(object): def __init__(self): self.parser = argparse.ArgumentParser() self.parser.add_argument( - '-k', '--keystoneip', help='Keystone IP', - default='127.0.0.1') - self.parser.add_argument( '-n', '--neutronip', help='Neutron IP', default='127.0.0.1') self.parser.add_argument( + '-k', '--osauthurl', help='OS_AUTH_URL as defined by OpenStack', + default='http://127.0.0.1:5000/v2.0') + self.parser.add_argument( '-a', '--osusername', help='Username for OpenStack', default='admin') self.parser.add_argument( diff --git a/functest/opnfv_tests/sdn/onos/__init__.py b/functest/opnfv_tests/sdn/onos/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/functest/opnfv_tests/sdn/onos/__init__.py diff --git a/functest/opnfv_tests/sdn/onos/onos.py b/functest/opnfv_tests/sdn/onos/onos.py new file mode 100644 index 00000000..8bc73832 --- /dev/null +++ b/functest/opnfv_tests/sdn/onos/onos.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python + +# Copyright (c) 2017 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# 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 re +import subprocess +import shutil +import time +import urlparse + +from functest.core import testcase_base +from functest.utils.constants import CONST +import functest.utils.functest_logger as ft_logger +import functest.utils.functest_utils as ft_utils +import functest.utils.openstack_utils as openstack_utils + + +logger = ft_logger.Logger(__name__).getLogger() + + +class OnosBase(testcase_base.TestcaseBase): + onos_repo_path = CONST.dir_repo_onos + onos_sfc_image_name = CONST.onos_sfc_image_name + onos_sfc_image_path = os.path.join(CONST.dir_functest_data, + CONST.onos_sfc_image_file_name) + onos_sfc_path = os.path.join(CONST.dir_repo_functest, + CONST.dir_onos_sfc) + + def __init__(self): + super(OnosBase, self).__init__() + + def run(self): + self.start_time = time.time() + try: + self._run() + res = testcase_base.TestcaseBase.EX_OK + except Exception as e: + logger.error('Error with run: %s', e) + res = testcase_base.TestcaseBase.EX_RUN_ERROR + + self.stop_time = time.time() + return res + + def _run(self): + raise NotImplementedError('_run is not implemented') + + +class Onos(OnosBase): + def __init__(self): + super(Onos, self).__init__() + self.case_name = 'onos' + self.log_path = os.path.join(self.onos_repo_path, 'TestON/logs') + + def set_onos_ip(self): + if (CONST.INSTALLER_TYPE and + CONST.INSTALLER_TYPE.lower() == 'joid'): + sdn_controller_env = os.getenv('SDN_CONTROLLER') + OC1 = re.search(r"\d+\.\d+\.\d+\.\d+", sdn_controller_env).group() + else: + neutron_url = openstack_utils.get_endpoint(service_type='network') + OC1 = urlparse.urlparse(neutron_url).hostname + os.environ['OC1'] = OC1 + logger.debug("ONOS IP is %s" % OC1) + + def run_onos_script(self, testname): + cli_dir = os.path.join(self.onos_repo_path, 'TestON/bin/cli.py') + cmd = '{0} run {1}'.format(cli_dir, testname) + logger.debug("Run script: %s" % testname) + ft_utils.execute_command_raise( + cmd, + error_msg=('Error when running ONOS script: %s' + % (testname))) + + def clean_existing_logs(self): + log_dir = [f for f in os.listdir(self.log_path)] + for log in log_dir: + try: + if os.path.isdir(log): + shutil.rmtree(log) + elif os.path.isfile(log): + os.remove(log) + except OSError as e: + logger.error('Error with deleting file %s: %s', + log, e.strerror) + + def get_result(self): + cmd = 'grep -rnh Fail {0}'.format(self.log_path) + p = subprocess.Popen(cmd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + for line in p.stdout: + logger.debug(line) + if re.search("\s+[1-9]+\s+", line): + logger.debug("Testcase Fails\n" + line) + + cmd = "grep -rnh 'Execution Time' {0}".format(self.log_path) + result_buffer = os.popen(cmd).read() + time1 = result_buffer[114:128] + time2 = result_buffer[28:42] + cmd = "grep -rnh 'Success Percentage' {0}".format( + os.path.join(self.log_path, "FUNCvirNetNB_*")) + result_buffer = os.popen(cmd).read() + if result_buffer.find('100%') >= 0: + result1 = 'Success' + else: + result1 = 'Failed' + cmd = "grep -rnh 'Success Percentage' {0}".format( + os.path.join(self.log_path, "FUNCvirNetNBL3*")) + result_buffer = os.popen(cmd).read() + if result_buffer.find('100%') >= 0: + result2 = 'Success' + else: + result2 = 'Failed' + status1 = [] + status2 = [] + cmd = "grep -rnh 'h3' {0}".format( + os.path.join(self.log_path, "FUNCvirNetNB_*")) + result_buffer = os.popen(cmd).read() + pattern = re.compile("<h3>([^-]+) - ([^-]+) - (\S*)</h3>") + # res = pattern.search(result_buffer).groups() + res = pattern.findall(result_buffer) + i = 0 + for index in range(len(res)): + status1.append({'Case name:': res[i][0] + res[i][1], + 'Case result': res[i][2]}) + i = i + 1 + cmd = "grep -rnh 'h3' {0}".format( + os.path.join(self.log_path, "FUNCvirNetNBL3*")) + result_buffer = os.popen(cmd).read() + pattern = re.compile("<h3>([^-]+) - ([^-]+) - (\S*)</h3>") + res = pattern.findall(result_buffer) + i = 0 + for index in range(len(res)): + status2.append({'Case name:': res[i][0] + res[i][1], + 'Case result': res[i][2]}) + i = i + 1 + payload = {'FUNCvirNet': {'duration': time1, + 'result': result1, + 'status': status1}, + 'FUNCvirNetL3': {'duration': time2, + 'result': result2, + 'status': status2}} + return payload + + def parse_result(self): + result = self.get_result() + status = "FAIL" + try: + if (result['FUNCvirNet']['result'] == "Success" and + result['FUNCvirNetL3']['result'] == "Success"): + status = "PASS" + except: + logger.error("Unable to set ONOS criteria") + + self.criteria = status + self.details = result + + def _run(self): + self.clean_existing_logs() + self.set_onos_ip() + self.run_onos_script('FUNCvirNetNB') + self.run_onos_script('FUNCvirNetNBL3') + self.parse_result() + + +class OnosSfc(OnosBase): + def __init__(self): + super(OnosSfc, self).__init__() + self.case_name = 'onos_sfc' + + def get_ip(type): + url = openstack_utils.get_endpoint(service_type=type) + logger.debug('get_ip for %s: %s' % (type, url)) + return urlparse.urlparse(url).hostname + + def update_sfc_onos_file(self, before, after): + file_dir = os.path.join(self.onos_sfc_path, "sfc_onos.py") + cmd = "sed -i 's/{0}/{1}/g' {2}".format(before, + after, + file_dir) + ft_utils.execute_command_raise( + cmd, + error_msg=('Error with replacing %s with %s' + % (before, after))) + + def create_image(self): + glance_client = openstack_utils.get_glance_client() + image_id = openstack_utils.create_glance_image( + glance_client, + self.onos_sfc_image_name, + self.onos_sfc_image_path) + if image_id is None: + raise Exception('Failed to create image') + + logger.debug("Image '%s' with ID=%s is created successfully." + % (self.onos_sfc_image_name, image_id)) + + def set_sfc_conf(self): + self.update_sfc_onos_file("keystone_ip", self.get_ip("keystone")) + self.update_sfc_onos_file("neutron_ip", self.get_ip("neutron")) + self.update_sfc_onos_file("nova_ip", self.get_ip("nova")) + self.update_sfc_onos_file("glance_ip", self.get_ip("glance")) + self.update_sfc_onos_file("console", CONST.OS_PASSWORD) + neutron_client = openstack_utils.get_neutron_client() + ext_net = openstack_utils.get_external_net(neutron_client) + self.update_sfc_onos_file("admin_floating_net", ext_net) + logger.debug("SFC configuration is modified") + + def sfc_test(self): + cmd = 'python {0}'.format(os.path.join(self.onos_sfc_path, 'sfc.py')) + ft_utils.execute_command_raise(cmd, + error_msg='Error with testing SFC') + + def _run(self): + self.create_image() + self.set_sfc_conf() + self.sfc_test() diff --git a/functest/opnfv_tests/sdn/onos/teston/adapters/foundation.py b/functest/opnfv_tests/sdn/onos/teston/adapters/foundation.py index 2bef5cc6..25421d40 100644 --- a/functest/opnfv_tests/sdn/onos/teston/adapters/foundation.py +++ b/functest/opnfv_tests/sdn/onos/teston/adapters/foundation.py @@ -17,7 +17,7 @@ import os import re import time -import functest.utils.functest_constants as ft_constants +from functest.utils.constants import CONST import functest.utils.functest_utils as ft_utils @@ -26,7 +26,7 @@ class Foundation(object): def __init__(self): # currentpath = os.getcwd() - currentpath = '%s/sdn/onos/teston/ci' % ft_constants.FUNCTEST_TEST_DIR + currentpath = '%s/sdn/onos/teston/ci' % CONST.dir_functest_data self.cipath = currentpath self.logdir = os.path.join(currentpath, 'log') self.workhome = currentpath[0: currentpath.rfind('opnfv_tests') - 1] @@ -54,23 +54,23 @@ class Foundation(object): """ Get Default Parameters value """ - self.Result_DB = str(ft_utils.get_db_url()) - self.masterusername = str(ft_constants.ONOSBENCH_USERNAME) - self.masterpassword = str(ft_constants.ONOSBENCH_PASSWORD) - self.agentusername = str(ft_constants.ONOSCLI_USERNAME) - self.agentpassword = str(ft_constants.ONOSCLI_PASSWORD) - self.runtimeout = ft_constants.ONOS_RUNTIMEOUT - self.OCT = str(ft_constants.ONOS_OCT) - self.OC1 = str(ft_constants.ONOS_OC1) - self.OC2 = str(ft_constants.ONOS_OC2) - self.OC3 = str(ft_constants.ONOS_OC3) - self.OCN = str(ft_constants.ONOS_OCN) - self.OCN2 = str(ft_constants.ONOS_OCN2) - self.installer_master = str(ft_constants.ONOS_INSTALLER_MASTER) - self.installer_master_username = \ - str(ft_constants.ONOS_INSTALLER_MASTER_USERNAME) - self.installer_master_password = \ - ft_constants.ONOS_INSTALLER_MASTER_PASSWORD + self.Result_DB = ft_utils.get_db_url() + self.masterusername = CONST.ONOS_onosbench_username + self.masterpassword = CONST.ONOS_onosbench_password + self.agentusername = CONST.ONOS_onoscli_username + self.agentpassword = CONST.ONOS_onoscli_password + self.runtimeout = CONST.ONOS_runtimeout + self.OCT = CONST.ONOS_environment_OCT + self.OC1 = CONST.ONOS_environment_OC1 + self.OC2 = CONST.ONOS_environment_OC2 + self.OC3 = CONST.ONOS_environment_OC3 + self.OCN = CONST.ONOS_environment_OCN + self.OCN2 = CONST.ONOS_environment_OCN2 + self.installer_master = CONST.ONOS_environment_installer_master + self.installer_master_username = ( + CONST.ONOS_environment_installer_master_username) + self.installer_master_password = ( + CONST.ONOS_environment_installer_master_password) self.hosts = [self.OC1, self.OCN, self.OCN2] self.localhost = self.OCT diff --git a/functest/opnfv_tests/sdn/onos/teston/onos.py b/functest/opnfv_tests/sdn/onos/teston/onos.py deleted file mode 100755 index 2537e18d..00000000 --- a/functest/opnfv_tests/sdn/onos/teston/onos.py +++ /dev/null @@ -1,261 +0,0 @@ -""" -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 -# -# 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 datetime -import os -import re -import time -import urlparse - -import argparse -from neutronclient.v2_0 import client as neutronclient - -import functest.utils.functest_constants as ft_constants -import functest.utils.functest_logger as ft_logger -import functest.utils.functest_utils as ft_utils -import functest.utils.openstack_utils as openstack_utils - - -parser = argparse.ArgumentParser() -parser.add_argument("-t", "--testcase", help="Testcase name") -args = parser.parse_args() - - -""" logging configuration """ -logger = ft_logger.Logger("onos").getLogger() - -# onos parameters -ONOSCI_PATH = ft_constants.REPOS_DIR + "/" -starttime = datetime.datetime.now() - -INSTALLER_TYPE = ft_constants.CI_INSTALLER_TYPE -ONOS_SFC_IMAGE_NAME = ft_constants.ONOS_SFC_IMAGE_NAME -ONOS_SFC_IMAGE_PATH = os.path.join(ft_constants.FUNCTEST_DATA_DIR, - ft_constants.ONOS_SFC_IMAGE_FILENAME) -ONOS_SFC_PATH = os.path.join(ft_constants.FUNCTEST_REPO_DIR, - ft_constants.ONOS_SFC_RELATIVE_PATH) - - -def RunScript(testname): - """ - Run ONOS Test Script - Parameters: - testname: ONOS Testcase Name - """ - runtest = ONOSCI_PATH + "onos/TestON/bin/cli.py run " + testname - logger.debug("Run script " + testname) - os.system(runtest) - - -def DownloadCodes(url="https://github.com/wuwenbin2/OnosSystemTest.git"): - """ - Download Onos Teston codes - Parameters: - url: github url - """ - downloadcode = "git clone " + url + " " + ONOSCI_PATH + "OnosSystemTest" - logger.debug("Download Onos Teston codes " + url) - os.system(downloadcode) - - -def GetResult(): - LOGPATH = ONOSCI_PATH + "onos/TestON/logs" - cmd = "grep -rnh " + "Fail" + " " + LOGPATH - Resultbuffer = os.popen(cmd).read() - # duration = datetime.datetime.now() - starttime - time.sleep(2) - - if re.search("\s+[1-9]+\s+", Resultbuffer): - logger.debug("Testcase Fails\n" + Resultbuffer) - # Result = "Failed" - else: - logger.debug("Testcases Success") - # Result = "Success" - # payload={'timestart': str(starttime), - # 'duration': str(duration), - # 'status': Result} - cmd = "grep -rnh 'Execution Time' " + LOGPATH - Resultbuffer = os.popen(cmd).read() - time1 = Resultbuffer[114:128] - time2 = Resultbuffer[28:42] - cmd = "grep -rnh 'Success Percentage' " + LOGPATH + "/FUNCvirNetNB_*" - Resultbuffer = os.popen(cmd).read() - if Resultbuffer.find('100%') >= 0: - result1 = 'Success' - else: - result1 = 'Failed' - cmd = "grep -rnh 'Success Percentage' " + LOGPATH + "/FUNCvirNetNBL3*" - Resultbuffer = os.popen(cmd).read() - if Resultbuffer.find('100%') >= 0: - result2 = 'Success' - else: - result2 = 'Failed' - status1 = [] - status2 = [] - cmd = "grep -rnh 'h3' " + LOGPATH + "/FUNCvirNetNB_*" - Resultbuffer = os.popen(cmd).read() - pattern = re.compile("<h3>([^-]+) - ([^-]+) - (\S*)</h3>") - # res = pattern.search(Resultbuffer).groups() - res = pattern.findall(Resultbuffer) - i = 0 - for index in range(len(res)): - status1.append({'Case name:': res[i][0] + res[i][1], - 'Case result': res[i][2]}) - i = i + 1 - cmd = "grep -rnh 'h3' " + LOGPATH + "/FUNCvirNetNBL3*" - Resultbuffer = os.popen(cmd).read() - pattern = re.compile("<h3>([^-]+) - ([^-]+) - (\S*)</h3>") - # res = pattern.search(Resultbuffer).groups() - res = pattern.findall(Resultbuffer) - i = 0 - for index in range(len(res)): - status2.append({'Case name:': res[i][0] + res[i][1], - 'Case result': res[i][2]}) - i = i + 1 - payload = {'timestart': str(starttime), - 'FUNCvirNet': {'duration': time1, - 'result': result1, - 'status': status1}, - 'FUNCvirNetL3': {'duration': time2, - 'result': result2, - 'status': status2}} - return payload - - -def SetOnosIp(): - # cmd = "openstack catalog show network | grep publicURL" - neutron_url = openstack_utils.get_endpoint(service_type='network') - OC1 = urlparse.urlparse(neutron_url).hostname - os.environ['OC1'] = OC1 - time.sleep(2) - logger.debug("ONOS IP is " + OC1) - - -def SetOnosIpForJoid(): - cmd = "env | grep SDN_CONTROLLER" - cmd_output = os.popen(cmd).read() - OC1 = re.search(r"\d+\.\d+\.\d+\.\d+", cmd_output).group() - os.environ['OC1'] = OC1 - time.sleep(2) - logger.debug("ONOS IP is " + OC1) - - -def CleanOnosTest(): - TESTONPATH = ONOSCI_PATH + "onos/" - cmd = "rm -rf " + TESTONPATH - os.system(cmd) - time.sleep(2) - logger.debug("Clean ONOS Teston") - - -def CreateImage(): - glance_client = openstack_utils.get_glance_client() - image_id = openstack_utils.create_glance_image(glance_client, - ONOS_SFC_IMAGE_NAME, - ONOS_SFC_IMAGE_PATH) - EXIT_CODE = -1 - if not image_id: - logger.error("Failed to create a Glance image...") - return(EXIT_CODE) - logger.debug("Image '%s' with ID=%s created successfully." - % (ONOS_SFC_IMAGE_NAME, image_id)) - - -def SfcTest(): - cmd = "python " + ONOS_SFC_PATH + "/sfc.py" - logger.debug("Run sfc tests") - os.system(cmd) - - -def GetIp(type): - # cmd = "openstack catalog show " + type + " | grep publicURL" - url = openstack_utils.get_endpoint(service_type=type) - return urlparse.urlparse(url).hostname - - -def Replace(before, after): - file = "/sfc_onos.py" - cmd = "sed -i 's/" + before + "/" + after + "/g' " + ONOS_SFC_PATH + file - os.system(cmd) - - -def SetSfcConf(): - Replace("keystone_ip", GetIp("keystone")) - Replace("neutron_ip", GetIp("neutron")) - Replace("nova_ip", GetIp("nova")) - Replace("glance_ip", GetIp("glance")) - pwd = ft_constants.OS_PASSWORD - Replace("console", pwd) - creds_neutron = openstack_utils.get_credentials() - neutron_client = neutronclient.Client(**creds_neutron) - ext_net = openstack_utils.get_external_net(neutron_client) - Replace("admin_floating_net", ext_net) - logger.info("Modify configuration for SFC") - - -def OnosTest(): - start_time = time.time() - stop_time = start_time - if INSTALLER_TYPE == "joid": - logger.debug("Installer is Joid") - SetOnosIpForJoid() - else: - SetOnosIp() - RunScript("FUNCvirNetNB") - RunScript("FUNCvirNetNBL3") - try: - logger.debug("Push ONOS results into DB") - # TODO check path result for the file - result = GetResult() - stop_time = time.time() - - # ONOS success criteria = all tests OK - # i.e. FUNCvirNet & FUNCvirNetL3 - status = "FAIL" - try: - if (result['FUNCvirNet']['result'] == "Success" and - result['FUNCvirNetL3']['result'] == "Success"): - status = "PASS" - except: - logger.error("Unable to set ONOS criteria") - - ft_utils.push_results_to_db("functest", - "onos", - start_time, - stop_time, - status, - result) - - except: - logger.error("Error pushing results into Database") - - if status == "FAIL": - EXIT_CODE = -1 - exit(EXIT_CODE) - - -def main(): - - if args.testcase == "sfc": - CreateImage() - SetSfcConf() - SfcTest() - else: - OnosTest() - - -if __name__ == '__main__': - main() diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims.py b/functest/opnfv_tests/vnf/ims/cloudify_ims.py index c2c251ad..e2401d0f 100644 --- a/functest/opnfv_tests/vnf/ims/cloudify_ims.py +++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.py @@ -234,7 +234,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): cw.set_external_network_name(ext_net) - error = cw.deploy_vnf() + error = cw.deploy_vnf(self.vnf['blueprint']) if error: self.logger.error(error) return {'status': 'FAIL', 'result': error} diff --git a/functest/opnfv_tests/vnf/ims/orchestra_ims.py b/functest/opnfv_tests/vnf/ims/orchestra_ims.py index 352b609b..42b218e6 100644 --- a/functest/opnfv_tests/vnf/ims/orchestra_ims.py +++ b/functest/opnfv_tests/vnf/ims/orchestra_ims.py @@ -23,6 +23,45 @@ from functest.utils.constants import CONST from org.openbaton.cli.agents.agents import MainAgent from org.openbaton.cli.errors.errors import NfvoException +# ---------------------------------------------------------- +# +# UTILS +# +# ----------------------------------------------------------- + + +def get_config(parameter, file): + """ + Returns the value of a given parameter in file.yaml + parameter must be given in string format with dots + Example: general.openstack.image_name + """ + with open(file) as f: + file_yaml = yaml.safe_load(f) + f.close() + value = file_yaml + for element in parameter.split("."): + value = value.get(element) + if value is None: + raise ValueError("The parameter %s is not defined in" + " %s" % (parameter, file)) + return value + + +def download_and_add_image_on_glance(glance, image_name, + image_url, data_dir): + dest_path = data_dir + if not os.path.exists(dest_path): + os.makedirs(dest_path) + file_name = image_url.rsplit('/')[-1] + if not ft_utils.download_url(image_url, dest_path): + return False + image = os_utils.create_glance_image( + glance, image_name, dest_path + file_name) + if not image: + return False + return image + def servertest(host, port): args = socket.getaddrinfo(host, port, socket.AF_INET, socket.SOCK_STREAM) @@ -38,6 +77,7 @@ def servertest(host, port): class ImsVnf(vnf_base.VnfOnBoardingBase): + def __init__(self, project='functest', case='orchestra_ims', repo='', cmd=''): super(ImsVnf, self).__init__(project, case, repo, cmd) @@ -54,6 +94,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): self.ob_projectid = "" self.keystone_client = os_utils.get_keystone_client() self.ob_nsr_id = "" + self.nsr = None self.main_agent = None # vIMS Data directory creation if not os.path.exists(self.data_dir): @@ -66,9 +107,14 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): raise Exception("Orchestra VNF config file not found") config_file = self.case_dir + self.config self.imagename = get_config("openbaton.imagename", config_file) + self.bootstrap_link = get_config("openbaton.bootstrap_link", + config_file) + self.bootstrap_config_link = get_config( + "openbaton.bootstrap_config_link", config_file) self.market_link = get_config("openbaton.marketplace_link", config_file) self.images = get_config("tenant_images", config_file) + self.ims_conf = get_config("vIMS", config_file) def deploy_orchestrator(self, **kwargs): self.logger.info("Additional pre-configuration steps") @@ -77,6 +123,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): glance_client = os_utils.get_glance_client() # Import images if needed + # needs some images self.logger.info("Upload some OS images if it doesn't exist") temp_dir = os.path.join(self.data_dir, "tmp/") for image_name, image_url in self.images.iteritems(): @@ -106,9 +153,9 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): "192.168.100.0/24") # orchestrator VM flavor - self.logger.info("Check medium Flavor is available, if not create one") + self.logger.info("Check if Flavor is available, if not create one") flavor_exist, flavor_id = os_utils.get_or_create_flavor( - "m1.medium", + "orchestra", "4096", '20', '2', @@ -129,13 +176,14 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): self.logger.error("Cannot create floating IP.") userdata = "#!/bin/bash\n" + userdata += "echo \"Executing userdata...\"\n" userdata += "set -x\n" userdata += "set -e\n" + userdata += "echo \"Set nameserver to '8.8.8.8'...\"\n" userdata += "echo \"nameserver 8.8.8.8\" >> /etc/resolv.conf\n" + userdata += "echo \"Install curl...\"\n" userdata += "apt-get install curl\n" - userdata += ("echo \"rabbitmq_broker_ip=%s\" > ./config_file\n" - % floatip) - userdata += "echo \"mysql=no\" >> ./config_file\n" + userdata += "echo \"Inject public key...\"\n" userdata += ("echo \"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuPXrV3" "geeHc6QUdyUr/1Z+yQiqLcOskiEGBiXr4z76MK4abiFmDZ18OMQlc" "fl0p3kS0WynVgyaOHwZkgy/DIoIplONVr2CKBKHtPK+Qcme2PVnCtv" @@ -145,17 +193,30 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): "7YAdalAnyD/jwCHuwIrUw/lxo7UdNCmaUxeobEYyyFA1YVXzpNFZya" "XPGAAYIJwEq/ openbaton@opnfv\" >> /home/ubuntu/.ssh/aut" "horized_keys\n") - userdata += "cat ./config_file\n" - userdata += ("curl -s http://get.openbaton.org/bootstrap " - "> ./bootstrap\n") + userdata += "echo \"Download bootstrap...\"\n" + userdata += ("curl -s %s " + "> ./bootstrap\n" % self.bootstrap_link) + userdata += ("curl -s %s" + "> ./config_file\n" % self.bootstrap_config_link) + userdata += ("echo \"Disable usage of mysql...\"\n") + userdata += "sed -i s/mysql=.*/mysql=no/g /config_file\n" + userdata += ("echo \"Setting 'rabbitmq_broker_ip' to '%s'\"\n" + % floatip) + userdata += ("sed -i s/rabbitmq_broker_ip=localhost/rabbitmq_broker_ip" + "=%s/g /config_file\n" % floatip) + userdata += "echo \"Set autostart of components to 'false'\"\n" userdata += "export OPENBATON_COMPONENT_AUTOSTART=false\n" + userdata += "echo \"Execute bootstrap...\"\n" bootstrap = "sh ./bootstrap release -configFile=./config_file" userdata += bootstrap + "\n" - + userdata += "echo \"Setting 'nfvo.plugin.timeout' to '300000'\"\n" userdata += ("echo \"nfvo.plugin.timeout=300000\" >> " "/etc/openbaton/openbaton-nfvo.properties\n") + userdata += "echo \"Starting NFVO\"\n" userdata += "service openbaton-nfvo restart\n" + userdata += "echo \"Starting Generic VNFM\"\n" userdata += "service openbaton-vnfm-generic restart\n" + userdata += "echo \"...end of userdata...\"\n" sg_id = os_utils.create_security_group_full(neutron_client, "orchestra-sec-group", @@ -200,22 +261,22 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): self.logger.info("Associating floating ip: '%s' to VM '%s' " % (floatip, "orchestra-openbaton")) if not os_utils.add_floating_ip(nova_client, instance.id, floatip): - self.logger.error("Cannot associate floating IP to VM.") self.step_failure("Cannot associate floating IP to VM.") - self.logger.info("Waiting for nfvo to be up and running...") + self.logger.info("Waiting for Open Baton NFVO to be up and running...") x = 0 while x < 100: if servertest(floatip, "8080"): break else: - self.logger.debug("openbaton is not started yet") + self.logger.debug( + "Open Baton NFVO is not started yet (%ss)" % + (x * 5)) time.sleep(5) x += 1 if x == 100: - self.logger.error("Openbaton is not started correctly") - self.step_failure("Openbaton is not started correctly") + self.step_failure("Open Baton is not started correctly") self.ob_ip = floatip self.ob_password = "openbaton" @@ -223,10 +284,10 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): self.ob_https = False self.ob_port = "8080" - self.logger.info("Deploy orchestrator: OK") + self.logger.info("Deploy Open Baton NFVO: OK") def deploy_vnf(self): - self.logger.info("vIMS Deployment") + self.logger.info("Starting vIMS Deployment...") self.main_agent = MainAgent(nfvo_ip=self.ob_ip, nfvo_port=self.ob_port, @@ -235,15 +296,16 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): username=self.ob_username, password=self.ob_password) + self.logger.info("Getting project 'default'...") project_agent = self.main_agent.get_agent("project", self.ob_projectid) for p in json.loads(project_agent.find()): if p.get("name") == "default": self.ob_projectid = p.get("id") + self.logger.info("Found project 'default': %s" % p) break self.logger.debug("project id: %s" % self.ob_projectid) if self.ob_projectid == "": - self.logger.error("Default project id was not found!") self.step_failure("Default project id was not found!") vim_json = { @@ -252,9 +314,6 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): "tenant": os_utils.get_credentials().get("tenant_name"), "username": os_utils.get_credentials().get("username"), "password": os_utils.get_credentials().get("password"), - "keyPair": "opnfv", - # TODO change the keypair to correct value - # or upload a correct one or remove it "securityGroups": [ "default", "orchestra-sec-group" @@ -267,7 +326,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): } } - self.logger.debug("vim: %s" % vim_json) + self.logger.debug("Registering VIM: %s" % vim_json) self.main_agent.get_agent( "vim", @@ -280,7 +339,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): try: self.logger.info("sending: %s" % self.market_link) nsd = market_agent.create(entity=self.market_link) - self.logger.info("Onboarded nsd: " + nsd.get("name")) + self.logger.info("Onboarded NSD: " + nsd.get("name")) except NfvoException as e: self.step_failure(e.message) @@ -290,34 +349,77 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): if nsd_id is None: self.step_failure("NSD not onboarded correctly") - nsr = None try: - nsr = nsr_agent.create(nsd_id) + self.nsr = nsr_agent.create(nsd_id) except NfvoException as e: self.step_failure(e.message) - if nsr is None: - self.step_failure("NSR not deployed correctly") + if self.nsr.get('code') is not None: + self.logger.error( + "vIMS cannot be deployed: %s -> %s" % + (self.nsr.get('code'), self.nsr.get('message'))) + self.step_failure("vIMS cannot be deployed") i = 0 - self.logger.info("waiting NSR to go to active...") - while nsr.get("status") != 'ACTIVE': + self.logger.info("Waiting for NSR to go to ACTIVE...") + while self.nsr.get("status") != 'ACTIVE' and self.nsr.get( + "status") != 'ERROR': i += 1 - if i == 100: - self.step_failure("After %s sec the nsr did not go to active.." - % 5 * 100) + if i == 150: + self.step_failure("After %s sec the NSR did not go to ACTIVE.." + % 5 * i) time.sleep(5) - nsr = json.loads(nsr_agent.find(nsr.get('id'))) + self.nsr = json.loads(nsr_agent.find(self.nsr.get('id'))) - deploy_vnf = {'status': "PASS", 'result': nsr} - self.ob_nsr_id = nsr.get("id") - self.logger.info("Deploy VNF: OK") + if self.nsr.get("status") == 'ACTIVE': + deploy_vnf = {'status': "PASS", 'result': self.nsr} + self.logger.info("Deploy VNF: OK") + else: + deploy_vnf = {'status': "FAIL", 'result': self.nsr} + self.step_failure("Deploy VNF: ERROR") + self.ob_nsr_id = self.nsr.get("id") + self.logger.info( + "Sleep for 60s to ensure that all services are up and running...") + time.sleep(60) return deploy_vnf def test_vnf(self): # Adaptations probably needed # code used for cloudify_ims # ruby client on jumphost calling the vIMS on the SUT + self.logger.info( + "Testing if %s works properly..." % + self.nsr.get('name')) + for vnfr in self.nsr.get('vnfr'): + self.logger.info( + "Checking ports %s of VNF %s" % + (self.ims_conf.get( + vnfr.get('name')).get('ports'), + vnfr.get('name'))) + for vdu in vnfr.get('vdu'): + for vnfci in vdu.get('vnfc_instance'): + self.logger.debug( + "Checking ports of VNFC instance %s" % + vnfci.get('hostname')) + for floatingIp in vnfci.get('floatingIps'): + self.logger.debug( + "Testing %s:%s" % + (vnfci.get('hostname'), floatingIp.get('ip'))) + for port in self.ims_conf.get( + vnfr.get('name')).get('ports'): + if servertest(floatingIp.get('ip'), port): + self.logger.info( + "VNFC instance %s is reachable at %s:%s" % + (vnfci.get('hostname'), + floatingIp.get('ip'), + port)) + else: + self.logger.error( + "VNFC instance %s is not reachable " + "at %s:%s" % (vnfci.get('hostname'), + floatingIp.get('ip'), port)) + self.step_failure("Test VNF: ERROR") + self.logger.info("Test VNF: OK") return def clean(self): @@ -349,42 +451,5 @@ if __name__ == '__main__': test = ImsVnf() test.deploy_orchestrator() test.deploy_vnf() + test.test_vnf() test.clean() - - -# ---------------------------------------------------------- -# -# UTILS -# -# ----------------------------------------------------------- -def get_config(parameter, file): - """ - Returns the value of a given parameter in file.yaml - parameter must be given in string format with dots - Example: general.openstack.image_name - """ - with open(file) as f: - file_yaml = yaml.safe_load(f) - f.close() - value = file_yaml - for element in parameter.split("."): - value = value.get(element) - if value is None: - raise ValueError("The parameter %s is not defined in" - " reporting.yaml" % parameter) - return value - - -def download_and_add_image_on_glance(glance, image_name, - image_url, data_dir): - dest_path = data_dir - if not os.path.exists(dest_path): - os.makedirs(dest_path) - file_name = image_url.rsplit('/')[-1] - if not ft_utils.download_url(image_url, dest_path): - return False - image = os_utils.create_glance_image( - glance, image_name, dest_path + file_name) - if not image: - return False - return image diff --git a/functest/opnfv_tests/vnf/ims/orchestra_ims.yaml b/functest/opnfv_tests/vnf/ims/orchestra_ims.yaml index 2fb33df5..86d6e604 100644 --- a/functest/opnfv_tests/vnf/ims/orchestra_ims.yaml +++ b/functest/opnfv_tests/vnf/ims/orchestra_ims.yaml @@ -2,6 +2,18 @@ tenant_images: ubuntu_14.04: http://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img openims: http://marketplace.openbaton.org:8082/api/v1/images/52e2ccc0-1dce-4663-894d-28aab49323aa/img openbaton: - bootstrap: sh <(curl -s http://get.openbaton.org/bootstrap) release -configFile= + bootstrap_link: http://get.openbaton.org/bootstrap + bootstrap_config_link: http://get.openbaton.org/bootstrap-config-file marketplace_link: http://marketplace.openbaton.org:8082/api/v1/nsds/fokus/OpenImsCore/3.2.0/json imagename: ubuntu_14.04 +vIMS: + scscf: + ports: [3870, 6060] + pcscf: + ports: [4060] + icscf: + ports: [3869, 5060] + fhoss: + ports: [3868] + bind9: + ports: []
\ No newline at end of file diff --git a/functest/tests/unit/ci/__init__.py b/functest/tests/unit/ci/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/functest/tests/unit/ci/__init__.py diff --git a/functest/tests/unit/ci/test_prepare_env.py b/functest/tests/unit/ci/test_prepare_env.py new file mode 100644 index 00000000..540501ff --- /dev/null +++ b/functest/tests/unit/ci/test_prepare_env.py @@ -0,0 +1,347 @@ +#!/usr/bin/env python + +# 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 logging +import unittest + +import mock + +from functest.ci import prepare_env +from functest.tests.unit import test_utils +from functest.utils.constants import CONST +from opnfv.utils import constants as opnfv_constants + + +class PrepareEnvTesting(unittest.TestCase): + + logging.disable(logging.CRITICAL) + + @mock.patch('functest.ci.prepare_env.logger.info') + def test_print_separator(self, mock_logger_info): + str = "==============================================" + prepare_env.print_separator() + mock_logger_info.assert_called_once_with(str) + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_check_env_variables_missing_inst_type(self, mock_logger_warn, + mock_logger_info): + CONST.INSTALLER_TYPE = None + prepare_env.check_env_variables() + mock_logger_info.assert_any_call("Checking environment variables" + "...") + mock_logger_warn.assert_any_call("The env variable 'INSTALLER_TYPE'" + " is not defined.") + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_check_env_variables_missing_inst_ip(self, mock_logger_warn, + mock_logger_info): + CONST.INSTALLER_IP = None + prepare_env.check_env_variables() + mock_logger_info.assert_any_call("Checking environment variables" + "...") + mock_logger_warn.assert_any_call("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.") + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_check_env_variables_with_inst_ip(self, mock_logger_warn, + mock_logger_info): + CONST.INSTALLER_IP = mock.Mock() + prepare_env.check_env_variables() + mock_logger_info.assert_any_call("Checking environment variables" + "...") + mock_logger_info.assert_any_call(test_utils. + SubstrMatch(" INSTALLER_IP=")) + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_check_env_variables_missing_scenario(self, mock_logger_warn, + mock_logger_info): + CONST.DEPLOY_SCENARIO = None + prepare_env.check_env_variables() + mock_logger_info.assert_any_call("Checking environment variables" + "...") + mock_logger_warn.assert_any_call("The env variable" + " 'DEPLOY_SCENARIO' is not defined" + ". Setting CI_SCENARIO=undefined.") + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_check_env_variables_with_scenario(self, mock_logger_warn, + mock_logger_info): + CONST.DEPLOY_SCENARIO = mock.Mock() + prepare_env.check_env_variables() + mock_logger_info.assert_any_call("Checking environment variables" + "...") + mock_logger_info.assert_any_call(test_utils. + SubstrMatch("DEPLOY_SCENARIO=")) + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_check_env_variables_with_ci_debug(self, mock_logger_warn, + mock_logger_info): + CONST.CI_DEBUG = mock.Mock() + prepare_env.check_env_variables() + mock_logger_info.assert_any_call("Checking environment variables" + "...") + mock_logger_info.assert_any_call(test_utils. + SubstrMatch(" CI_DEBUG=")) + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_check_env_variables_with_node(self, mock_logger_warn, + mock_logger_info): + CONST.NODE_NAME = mock.Mock() + prepare_env.check_env_variables() + mock_logger_info.assert_any_call("Checking environment variables" + "...") + mock_logger_info.assert_any_call(test_utils. + SubstrMatch(" NODE_NAME=")) + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_check_env_variables_with_build_tag(self, mock_logger_warn, + mock_logger_info): + CONST.BUILD_TAG = mock.Mock() + prepare_env.check_env_variables() + mock_logger_info.assert_any_call("Checking environment variables" + "...") + + mock_logger_info.assert_any_call(test_utils. + SubstrMatch(" BUILD_TAG=")) + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_check_env_variables_with_is_ci_run(self, mock_logger_warn, + mock_logger_info): + CONST.IS_CI_RUN = mock.Mock() + prepare_env.check_env_variables() + mock_logger_info.assert_any_call("Checking environment variables" + "...") + + mock_logger_info.assert_any_call(test_utils. + SubstrMatch(" IS_CI_RUN=")) + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.debug') + def test_create_directories_missing_dir(self, mock_logger_debug, + mock_logger_info): + with mock.patch('functest.ci.prepare_env.os.path.exists', + return_value=False), \ + mock.patch('functest.ci.prepare_env.os.makedirs') \ + as mock_method: + prepare_env.create_directories() + mock_logger_info.assert_any_call("Creating needed directories...") + mock_method.assert_any_call(CONST.dir_functest_conf) + mock_method.assert_any_call(CONST.dir_functest_data) + mock_logger_info.assert_any_call(" %s created." % + CONST.dir_functest_conf) + mock_logger_info.assert_any_call(" %s created." % + CONST.dir_functest_data) + + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.debug') + def test_create_directories_with_dir(self, mock_logger_debug, + mock_logger_info): + with mock.patch('functest.ci.prepare_env.os.path.exists', + return_value=True): + prepare_env.create_directories() + mock_logger_info.assert_any_call("Creating needed directories...") + mock_logger_debug.assert_any_call(" %s already exists." % + CONST.dir_functest_conf) + mock_logger_debug.assert_any_call(" %s already exists." % + CONST.dir_functest_data) + + def _get_env_cred_dict(self, os_prefix=''): + return {'OS_USERNAME': os_prefix + 'username', + 'OS_PASSWORD': os_prefix + 'password', + 'OS_AUTH_URL': 'http://test_ip:test_port/v2.0', + 'OS_TENANT_NAME': os_prefix + 'tenant_name', + 'OS_USER_DOMAIN_NAME': os_prefix + 'user_domain_name', + 'OS_PROJECT_DOMAIN_NAME': os_prefix + 'project_domain_name', + 'OS_PROJECT_NAME': os_prefix + 'project_name', + 'OS_ENDPOINT_TYPE': os_prefix + 'endpoint_type', + 'OS_REGION_NAME': os_prefix + 'region_name'} + + @mock.patch('functest.ci.prepare_env.logger.error') + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.logger.warning') + def test_source_rc_missing_rc_file(self, mock_logger_warn, + mock_logger_info, + mock_logger_error): + with mock.patch('functest.ci.prepare_env.os.path.isfile', + return_value=True), \ + mock.patch('functest.ci.prepare_env.os.path.getsize', + return_value=0), \ + self.assertRaises(Exception): + CONST.openstack_creds = 'test_creds' + prepare_env.source_rc_file() + + def test_source_rc_missing_installer_ip(self): + with mock.patch('functest.ci.prepare_env.os.path.isfile', + return_value=False), \ + self.assertRaises(Exception): + CONST.INSTALLER_IP = None + CONST.openstack_creds = 'test_creds' + prepare_env.source_rc_file() + + def test_source_rc_missing_installer_type(self): + with mock.patch('functest.ci.prepare_env.os.path.isfile', + return_value=False), \ + self.assertRaises(Exception): + CONST.INSTALLER_IP = 'test_ip' + CONST.openstack_creds = 'test_creds' + CONST.INSTALLER_TYPE = 'test_type' + opnfv_constants.INSTALLERS = [] + prepare_env.source_rc_file() + + def test_source_rc_missing_os_credfile_ci_inst(self): + with mock.patch('functest.ci.prepare_env.os.path.isfile', + return_value=False), \ + mock.patch('functest.ci.prepare_env.os.path.getsize'), \ + mock.patch('functest.ci.prepare_env.os.path.join'), \ + mock.patch('functest.ci.prepare_env.subprocess.Popen') \ + as mock_subproc_popen, \ + self.assertRaises(Exception): + CONST.openstack_creds = 'test_creds' + CONST.INSTALLER_IP = None + CONST.INSTALLER_TYPE = 'test_type' + opnfv_constants.INSTALLERS = ['test_type'] + + process_mock = mock.Mock() + attrs = {'communicate.return_value': ('output', 'error'), + 'return_code': 1} + process_mock.configure_mock(**attrs) + mock_subproc_popen.return_value = process_mock + + prepare_env.source_rc_file() + + def _get_rally_creds(self): + return {"type": "ExistingCloud", + "admin": {"username": 'test_user_name', + "password": 'test_password', + "tenant": 'test_tenant'}} + + @mock.patch('functest.ci.prepare_env.os_utils.get_credentials_for_rally') + @mock.patch('functest.ci.prepare_env.logger.info') + @mock.patch('functest.ci.prepare_env.ft_utils.execute_command_raise') + @mock.patch('functest.ci.prepare_env.ft_utils.execute_command') + def test_install_rally(self, mock_exec, mock_exec_raise, mock_logger_info, + mock_os_utils): + + mock_os_utils.return_value = self._get_rally_creds() + + prepare_env.install_rally() + + cmd = "rally deployment destroy opnfv-rally" + error_msg = "Deployment %s does not exist." % \ + CONST.rally_deployment_name + mock_logger_info.assert_any_call("Creating Rally environment...") + mock_exec.assert_any_call(cmd, error_msg=error_msg, verbose=False) + + cmd = "rally deployment create --file=rally_conf.json --name=" + cmd += CONST.rally_deployment_name + error_msg = "Problem while creating Rally deployment" + mock_exec_raise.assert_any_call(cmd, error_msg=error_msg) + + cmd = "rally deployment check" + error_msg = ("OpenStack not responding or " + "faulty Rally deployment.") + mock_exec_raise.assert_any_call(cmd, error_msg=error_msg) + + cmd = "rally deployment list" + error_msg = ("Problem while listing " + "Rally deployment.") + mock_exec.assert_any_call(cmd, error_msg=error_msg) + + cmd = "rally plugin list | head -5" + error_msg = ("Problem while showing " + "Rally plugins.") + mock_exec.assert_any_call(cmd, error_msg=error_msg) + + @mock.patch('functest.ci.prepare_env.sys.exit') + @mock.patch('functest.ci.prepare_env.logger.error') + def test_check_environment_missing_file(self, mock_logger_error, + mock_sys_exit): + with mock.patch('functest.ci.prepare_env.os.path.isfile', + return_value=False), \ + self.assertRaises(Exception): + prepare_env.check_environment() + + @mock.patch('functest.ci.prepare_env.sys.exit') + @mock.patch('functest.ci.prepare_env.logger.error') + def test_check_environment_with_error(self, mock_logger_error, + mock_sys_exit): + with mock.patch('functest.ci.prepare_env.os.path.isfile', + return_value=True), \ + mock.patch("__builtin__.open", mock.mock_open(read_data='0')), \ + self.assertRaises(Exception): + prepare_env.check_environment() + + @mock.patch('functest.ci.prepare_env.logger.info') + def test_check_environment_default(self, mock_logger_info): + with mock.patch('functest.ci.prepare_env.os.path.isfile', + return_value=True): + with mock.patch("__builtin__.open", mock.mock_open(read_data='1')): + prepare_env.check_environment() + mock_logger_info.assert_any_call("Functest environment" + " is installed.") + + @mock.patch('functest.ci.prepare_env.check_environment') + @mock.patch('functest.ci.prepare_env.create_flavor') + @mock.patch('functest.ci.prepare_env.install_tempest') + @mock.patch('functest.ci.prepare_env.install_rally') + @mock.patch('functest.ci.prepare_env.verify_deployment') + @mock.patch('functest.ci.prepare_env.patch_config_file') + @mock.patch('functest.ci.prepare_env.source_rc_file') + @mock.patch('functest.ci.prepare_env.create_directories') + @mock.patch('functest.ci.prepare_env.check_env_variables') + @mock.patch('functest.ci.prepare_env.logger.info') + def test_main_start(self, mock_logger_info, mock_env_var, + mock_create_dir, mock_source_rc, mock_patch_config, + mock_verify_depl, mock_install_rally, + mock_install_temp, mock_create_flavor, + mock_check_env): + with mock.patch("__builtin__.open", mock.mock_open()) as m: + args = {'action': 'start'} + self.assertEqual(prepare_env.main(**args), 0) + mock_logger_info.assert_any_call("######### Preparing Functest " + "environment #########\n") + self.assertTrue(mock_env_var.called) + self.assertTrue(mock_create_dir.called) + self.assertTrue(mock_source_rc.called) + self.assertTrue(mock_patch_config.called) + self.assertTrue(mock_verify_depl.called) + self.assertTrue(mock_install_rally.called) + self.assertTrue(mock_install_temp.called) + self.assertTrue(mock_create_flavor.called) + m.assert_called_once_with(CONST.env_active, "w") + self.assertTrue(mock_check_env.called) + + @mock.patch('functest.ci.prepare_env.check_environment') + def test_main_check(self, mock_check_env): + args = {'action': 'check'} + self.assertEqual(prepare_env.main(**args), 0) + self.assertTrue(mock_check_env.called) + + @mock.patch('functest.ci.prepare_env.logger.error') + def test_main_no_arg(self, mock_logger_error): + args = {'action': 'not_valid'} + self.assertEqual(prepare_env.main(**args), -1) + mock_logger_error.assert_called_once_with('Argument not valid.') + + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/functest/tests/unit/odl/test_odl.py b/functest/tests/unit/odl/test_odl.py index 8f2a5d7e..5961940f 100644 --- a/functest/tests/unit/odl/test_odl.py +++ b/functest/tests/unit/odl/test_odl.py @@ -30,6 +30,7 @@ class ODLTesting(unittest.TestCase): _keystone_ip = "127.0.0.1" _neutron_ip = "127.0.0.2" _sdn_controller_ip = "127.0.0.3" + _os_auth_url = "http://{}:5000/v2.0".format(_keystone_ip) _os_tenantname = "admin" _os_username = "admin" _os_password = "admin" @@ -42,14 +43,15 @@ class ODLTesting(unittest.TestCase): for var in ("INSTALLER_TYPE", "SDN_CONTROLLER", "SDN_CONTROLLER_IP"): if var in os.environ: del os.environ[var] + os.environ["OS_AUTH_URL"] = self._os_auth_url os.environ["OS_USERNAME"] = self._os_username os.environ["OS_PASSWORD"] = self._os_password os.environ["OS_TENANT_NAME"] = self._os_tenantname self.test = odl.ODLTests() self.defaultargs = {'odlusername': self._odl_username, 'odlpassword': self._odl_password, - 'keystoneip': self._keystone_ip, 'neutronip': self._keystone_ip, + 'osauthurl': self._os_auth_url, 'osusername': self._os_username, 'ostenantname': self._os_tenantname, 'ospassword': self._os_password, @@ -157,8 +159,8 @@ class ODLTesting(unittest.TestCase): def _get_main_kwargs(self, key=None): kwargs = {'odlusername': self._odl_username, 'odlpassword': self._odl_password, - 'keystoneip': self._keystone_ip, 'neutronip': self._neutron_ip, + 'osauthurl': self._os_auth_url, 'osusername': self._os_username, 'ostenantname': self._os_tenantname, 'ospassword': self._os_password, @@ -178,6 +180,7 @@ class ODLTesting(unittest.TestCase): if len(args) > 1: variable = ['KEYSTONE:{}'.format(self._keystone_ip), 'NEUTRON:{}'.format(self._neutron_ip), + 'OS_AUTH_URL:"{}"'.format(self._os_auth_url), 'OSUSERNAME:"{}"'.format(self._os_username), 'OSTENANTNAME:"{}"'.format(self._os_tenantname), 'OSPASSWORD:"{}"'.format(self._os_password), @@ -207,12 +210,12 @@ class ODLTesting(unittest.TestCase): def test_main_missing_odlpassword(self): self._test_main_missing_keyword('odlpassword') - def test_main_missing_keystoneip(self): - self._test_main_missing_keyword('keystoneip') - def test_main_missing_neutronip(self): self._test_main_missing_keyword('neutronip') + def test_main_missing_osauthurl(self): + self._test_main_missing_keyword('osauthurl') + def test_main_missing_osusername(self): self._test_main_missing_keyword('osusername') @@ -347,10 +350,11 @@ class ODLTesting(unittest.TestCase): self.assertEqual(self.test.run(), status) self.test.main.assert_called_once_with( odl.ODLTests.default_suites, - keystoneip=self._keystone_ip, neutronip=self._neutron_ip, + neutronip=self._neutron_ip, odlip=odlip, odlpassword=self._odl_password, odlrestconfport=odlrestconfport, odlusername=self._odl_username, odlwebport=odlwebport, + osauthurl=self._os_auth_url, ospassword=self._os_password, ostenantname=self._os_tenantname, osusername=self._os_username) @@ -368,10 +372,11 @@ class ODLTesting(unittest.TestCase): self.assertEqual(self.test.run(suites=suites), status) self.test.main.assert_called_once_with( suites, - keystoneip=self._keystone_ip, neutronip=self._neutron_ip, + neutronip=self._neutron_ip, odlip=odlip, odlpassword=self._odl_password, odlrestconfport=odlrestconfport, odlusername=self._odl_username, odlwebport=odlwebport, + osauthurl=self._os_auth_url, ospassword=self._os_password, ostenantname=self._os_tenantname, osusername=self._os_username) @@ -381,6 +386,9 @@ class ODLTesting(unittest.TestCase): self.assertEqual(self.test.run(), testcase_base.TestcaseBase.EX_RUN_ERROR) + def test_run_missing_os_auth_url(self): + self._test_run_missing_env_var("OS_AUTH_URL") + def test_run_missing_os_username(self): self._test_run_missing_env_var("OS_USERNAME") @@ -507,8 +515,8 @@ class ODLTesting(unittest.TestCase): def test_argparser_odlpassword(self): self._test_argparser('odlpassword', 'foo') - def test_argparser_keystoneip(self): - self._test_argparser('keystoneip', '127.0.0.4') + def test_argparser_osauthurl(self): + self._test_argparser('osauthurl', 'http://127.0.0.4:5000/v2') def test_argparser_neutronip(self): self._test_argparser('neutronip', '127.0.0.4') diff --git a/functest/tests/unit/utils/test_openstack_utils.py b/functest/tests/unit/utils/test_openstack_utils.py index 447271fc..ef3764cc 100644 --- a/functest/tests/unit/utils/test_openstack_utils.py +++ b/functest/tests/unit/utils/test_openstack_utils.py @@ -104,7 +104,6 @@ class OSUtilsTesting(unittest.TestCase): 'servers.create.return_value': self.instance, 'flavors.list.return_value': [self.flavor], 'flavors.find.return_value': self.flavor, - 'flavors.list.return_value': [self.flavor], 'servers.add_floating_ip.return_value': mock.Mock(), 'servers.force_delete.return_value': mock.Mock(), 'aggregates.list.return_value': [self.aggregate], @@ -162,6 +161,15 @@ class OSUtilsTesting(unittest.TestCase): } self.cinder_client.configure_mock(**attrs) + self.resource = mock.Mock() + attrs = {'id': 'resource_test_id', + 'name': 'resource_test_name' + } + + self.heat_client = mock.Mock() + attrs = {'resources.get.return_value': self.resource} + self.heat_client.configure_mock(**attrs) + mock_obj = mock.Mock() attrs = {'id': 'tenant_id', 'name': 'test_tenant'} @@ -543,6 +551,36 @@ class OSUtilsTesting(unittest.TestCase): mock_glan_client.assert_called_once_with('3', session=mock_session_obj) + @mock.patch('functest.utils.openstack_utils.os.getenv', + return_value=None) + def test_get_heat_client_version_missing_env(self, mock_os_getenv): + self.assertEqual(openstack_utils.get_heat_client_version(), + openstack_utils.DEFAULT_HEAT_API_VERSION) + + @mock.patch('functest.utils.openstack_utils.logger.info') + @mock.patch('functest.utils.openstack_utils.os.getenv', return_value='1') + def test_get_heat_client_version_default(self, mock_os_getenv, + mock_logger_info): + self.assertEqual(openstack_utils.get_heat_client_version(), '1') + mock_logger_info.assert_called_once_with( + "OS_ORCHESTRATION_API_VERSION is set in env as '%s'", '1') + + def test_get_heat_client(self): + mock_heat_obj = mock.Mock() + mock_session_obj = mock.Mock() + with mock.patch('functest.utils.openstack_utils' + '.get_heat_client_version', return_value='1'), \ + mock.patch('functest.utils.openstack_utils' + '.heatclient.Client', + return_value=mock_heat_obj) \ + as mock_heat_client, \ + mock.patch('functest.utils.openstack_utils.get_session', + return_value=mock_session_obj): + self.assertEqual(openstack_utils.get_heat_client(), + mock_heat_obj) + mock_heat_client.assert_called_once_with('1', + session=mock_session_obj) + def test_get_instances_default(self): self.assertEqual(openstack_utils.get_instances(self.nova_client), [self.instance]) @@ -1700,6 +1738,24 @@ class OSUtilsTesting(unittest.TestCase): 'user_id')) self.assertTrue(mock_logger_error.called) + def test_get_resource_default(self): + with mock.patch('functest.utils.openstack_utils.' + 'is_keystone_v3', return_value=True): + self.assertEqual(openstack_utils. + get_resource(self.heat_client, + 'stack_id', + 'resource'), + self.resource) + + @mock.patch('functest.utils.openstack_utils.logger.error') + def test_get_resource_exception(self, mock_logger_error): + self.assertEqual(openstack_utils. + get_resource(Exception, + 'stack_id', + 'resource'), + None) + self.assertTrue(mock_logger_error.called) + if __name__ == "__main__": unittest.main(verbosity=2) diff --git a/functest/utils/functest_constants.py b/functest/utils/functest_constants.py deleted file mode 100644 index 0a9a03b1..00000000 --- a/functest/utils/functest_constants.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/env python -# -# yaohelan@huawei.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 functest.utils.functest_logger as ft_logger -import functest.utils.functest_utils as ft_utils - -logger = ft_logger.Logger("functest_constants").getLogger() - - -""" global variables """ -INSTALLERS = ['fuel', 'compass', 'apex', 'joid'] -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') -CI_LOOP = os.getenv('CI_LOOP') -OS_AUTH_URL = os.getenv('OS_AUTH_URL') -OS_USERNAME = os.getenv('OS_USERNAME') -OS_TENANT_NAME = os.getenv('OS_TENANT_NAME') -OS_PASSWORD = os.getenv('OS_PASSWORD') -OS_ENDPOINT_TYPE = os.getenv('OS_ENDPOINT_TYPE') -OS_REGION_NAME = os.getenv('OS_REGION_NAME') -OS_CACERT = os.getenv('OS_CACERT') -FUEL_ENV = os.getenv('FUEL_ENV') -SDN_CONTROLLER_IP = os.getenv('SDN_CONTROLLER_IP') -SDN_CONTROLLER = os.getenv('SDN_CONTROLLER') - -if CI_BUILD_TAG is not None: - IS_CI_RUN = True -else: - IS_CI_RUN = False - -CONFIG_FUNCTEST_YAML = os.getenv("CONFIG_FUNCTEST_YAML") - - -def get_value(functest_config_key, env_variable): - try: - constant = ft_utils.get_functest_config(functest_config_key) - # logger.debug("%s is defined in config_functest.yaml as [%s]" - # % (env_variable, constant)) - return constant - except ValueError: - logger.warning("%s is not defined in config_functest.yaml" - % functest_config_key) - constant = os.getenv(env_variable) - if constant is None: - raise ValueError("%s is neither defined in config_functest.yaml" - " nor environment variable" % env_variable) - else: - logger.debug("%s is defined as environment variable as [%s]" - % (env_variable, constant)) - return constant - - -HOME = get_value('general.dir.home', 'HOME') -REPOS_DIR = get_value('general.dir.repos', 'REPOS_DIR') -FUNCTEST_BASE_DIR = get_value('general.dir.functest', - 'FUNCTEST_BASE_DIR') -FUNCTEST_REPO_DIR = get_value('general.dir.repo_functest', - 'FUNCTEST_REPO_DIR') -FUNCTEST_TEST_DIR = get_value('general.dir.functest_test', - 'FUNCTEST_TEST_DIR') -FUNCTEST_CONF_DIR = get_value('general.dir.functest_conf', - 'FUNCTEST_CONF_DIR') -FUNCTEST_DATA_DIR = get_value('general.dir.functest_data', - 'FUNCTEST_DATA_DIR') -FUNCTEST_RESULTS_DIR = get_value('general.dir.results', - 'FUNCTEST_RESULTS_DIR') -FUNCTEST_TESTCASES_YAML = get_value('general.functest.testcases_yaml', - 'FUNCTEST_TESTCASES_YAML') -RALLY_DEPLOYMENT_NAME = get_value('rally.deployment_name', - 'RALLY_DEPLOYMENT_NAME') -TEMPEST_REPO_DIR = get_value('general.dir.repo_tempest', - 'TEMPEST_REPO_DIR') - -ENV_FILE = os.path.join(FUNCTEST_CONF_DIR, "env_active") - -OPENSTACK_CREDS = get_value('general.openstack.creds', 'creds') -OPENSTACK_SNAPSHOT_FILE = get_value('general.openstack.snapshot_file', - 'OPENSTACK_SNAPSHOT_FILE') - -DOMINO_REPO_DIR = get_value('general.dir.repo_domino', - 'DOMINO_REPO_DIR') -SDNVPN_REPO_DIR = get_value('general.dir.repo_sdnvpn', - 'SDNVPN_REPO_DIR') -SFC_REPO_DIR = get_value('general.dir.repo_sfc', - 'SFC_REPO_DIR') - -ONOS_SFC_IMAGE_NAME = get_value('onos_sfc.image_name', - 'ONOS_SFC_IMAGE_NAME') -ONOS_SFC_IMAGE_FILENAME = get_value('onos_sfc.image_file_name', - 'ONOS_SFC_IMAGE_FILENAME') -ONOS_SFC_RELATIVE_PATH = get_value('general.dir.dir_onos_sfc', - 'ONOS_SFC_RELATIVE_PATH') -ONOS_SFC_IMAGE_BASE_URL = get_value('onos_sfc.image_base_url', - 'ONOS_SFC_IMAGE_BASE_URL') -RALLY_RELATIVE_PATH = get_value('general.dir.rally', - 'RALLY_RELATIVE_PATH') -RALLY_PRIVATE_NET_NAME = get_value('rally.network_name', - 'RALLY_PRIVATE_NET_NAME') -RALLY_PRIVATE_SUBNET_NAME = get_value('rally.subnet_name', - 'RALLY_PRIVATE_SUBNET_NAME') -RALLY_PRIVATE_SUBNET_CIDR = get_value('rally.subnet_cidr', - 'RALLY_PRIVATE_SUBNET_CIDR') -RALLY_ROUTER_NAME = get_value('rally.router_name', 'RALLY_ROUTER_NAME') -RALLY_INSTALLATION_DIR = get_value('general.dir.rally_inst', - 'RALLY_INSTALLATION_DIR') -GLANCE_IMAGE_NAME = get_value('general.openstack.image_name', - 'GLANCE_IMAGE_NAME') -GLANCE_IMAGE_FILENAME = get_value('general.openstack.image_file_name', - 'GLANCE_IMAGE_FILENAME') -GLANCE_IMAGE_FORMAT = get_value('general.openstack.image_disk_format', - 'GLANCE_IMAGE_FORMAT') -FLAVOR_NAME = get_value('general.openstack.flavor_name', - 'FLAVOR_NAME') -FLAVOR_RAM = get_value('general.openstack.flavor_ram', - 'FLAVOR_RAM') -FLAVOR_DISK = get_value('general.openstack.flavor_disk', - 'FLAVOR_DISK') -FLAVOR_VCPUS = get_value('general.openstack.flavor_vcpus', - 'FLAVOR_VCPUS') -TEMPEST_PRIVATE_NET_NAME = get_value('tempest.private_net_name', - 'TEMPEST_PRIVATE_NET_NAME') -TEMPEST_PRIVATE_SUBNET_NAME = get_value('tempest.private_subnet_name', - 'TEMPEST_PRIVATE_SUBNET_NAME') -TEMPEST_PRIVATE_SUBNET_CIDR = get_value('tempest.private_subnet_cidr', - 'TEMPEST_PRIVATE_SUBNET_CIDR') -TEMPEST_ROUTER_NAME = get_value('tempest.router_name', - 'TEMPEST_ROUTER_NAME') -TEMPEST_TENANT_NAME = get_value('tempest.identity.tenant_name', - 'TEMPEST_TENANT_NAME') -TEMPEST_TENANT_DESCRIPTION = get_value('tempest.identity.tenant_description', - 'TEMPEST_TENANT_DESCRIPTION') -TEMPEST_USER_NAME = get_value('tempest.identity.user_name', - 'TEMPEST_USER_NAME') -TEMPEST_USER_PASSWORD = get_value('tempest.identity.user_password', - 'TEMPEST_USER_PASSWORD') -TEMPEST_SSH_TIMEOUT = get_value('tempest.validation.ssh_timeout', - 'TEMPEST_SSH_TIMEOUT') -TEMPEST_OPERATOR_ROLE = get_value('tempest.object_storage.operator_role', - 'TEMPEST_OPERATOR_ROLE') -TEMPEST_USE_CUSTOM_IMAGES = get_value('tempest.use_custom_images', - 'TEMPEST_USE_CUSTOM_IMAGES') -TEMPEST_USE_CUSTOM_FLAVORS = get_value('tempest.use_custom_flavors', - 'TEMPEST_USE_CUSTOM_FLAVORS') -TEMPEST_TEST_LIST_DIR = get_value('general.dir.tempest_cases', - 'TEMPEST_TEST_LIST_DIR') -NAME_VM_1 = get_value('vping.vm_name_1', 'NAME_VM_1') -NAME_VM_2 = get_value('vping.vm_name_2', 'NAME_VM_2') -PING_TIMEOUT = get_value('vping.ping_timeout', 'PING_TIMEOUT') -VPING__IMAGE_NAME = get_value('vping.image_name', 'VPING__IMAGE_NAME') -VPING_VM_FLAVOR = get_value('vping.vm_flavor', 'VPING_VM_FLAVOR') -VPING_PRIVATE_NET_NAME = get_value('vping.private_net_name', - 'VPING_PRIVATE_NET_NAME') -VPING_PRIVATE_SUBNET_NAME = get_value('vping.private_subnet_name', - 'VPING_PRIVATE_SUBNET_NAME') -VPING_PRIVATE_SUBNET_CIDR = get_value('vping.private_subnet_cidr', - 'VPING_PRIVATE_SUBNET_CIDR') -VPING_ROUTER_NAME = get_value('vping.router_name', - 'VPING_ROUTER_NAME') -VPING_SECGROUP_NAME = get_value('vping.sg_name', - 'VPING_SECGROUP_NAME') -VPING_SECGROUP_DESCR = get_value('vping.sg_desc', - 'VPING_SECGROUP_DESCR') -ONOSBENCH_USERNAME = get_value('ONOS.general.onosbench_username', - 'ONOSBENCH_USERNAME') -ONOSBENCH_PASSWORD = get_value('ONOS.general.onosbench_password', - 'ONOSBENCH_PASSWORD') -ONOSCLI_USERNAME = get_value('ONOS.general.onoscli_username', - 'ONOSCLI_USERNAME') -ONOSCLI_PASSWORD = get_value('ONOS.general.onoscli_password', - 'ONOSCLI_PASSWORD') -ONOS_RUNTIMEOUT = get_value('ONOS.general.runtimeout', - 'ONOS_RUNTIMEOUT') -ONOS_OCT = get_value('ONOS.environment.OCT', 'ONOS_OCT') -ONOS_OC1 = get_value('ONOS.environment.OC1', 'ONOS_OC1') -ONOS_OC2 = get_value('ONOS.environment.OC2', 'ONOS_OC2') -ONOS_OC3 = get_value('ONOS.environment.OC3', 'ONOS_OC3') -ONOS_OCN = get_value('ONOS.environment.OCN', 'ONOS_OCN') -ONOS_OCN2 = get_value('ONOS.environment.OCN2', 'ONOS_OCN2') -ONOS_INSTALLER_MASTER = get_value('ONOS.environment.installer_master', - 'ONOS_INSTALLER_MASTER') -ONOS_INSTALLER_MASTER_USERNAME = get_value( - 'ONOS.environment.installer_master_username', - 'ONOS_INSTALLER_MASTER_USERNAME') -ONOS_INSTALLER_MASTER_PASSWORD = get_value( - 'ONOS.environment.installer_master_password', - 'ONOS_INSTALLER_MASTER_PASSWORD') -EXAMPLE_INSTANCE_NAME = get_value('example.vm_name', - 'EXAMPLE_INSTANCE_NAME') -EXAMPLE_FLAVOR = get_value('example.flavor', 'EXAMPLE_FLAVOR') -EXAMPLE_IMAGE_NAME = get_value('example.image_name', - 'EXAMPLE_IMAGE_NAME') -EXAMPLE_PRIVATE_NET_NAME = get_value('example.private_net_name', - 'EXAMPLE_PRIVATE_NET_NAME') -EXAMPLE_PRIVATE_SUBNET_NAME = get_value( - 'example.private_subnet_name', - 'EXAMPLE_PRIVATE_SUBNET_NAME') -EXAMPLE_PRIVATE_SUBNET_CIDR = get_value( - 'example.private_subnet_cidr', - 'EXAMPLE_PRIVATE_SUBNET_CIDR') -EXAMPLE_ROUTER_NAME = get_value('example.router_name', - 'EXAMPLE_ROUTER_NAME') -EXAMPLE_SECGROUP_NAME = get_value('example.sg_name', - 'EXAMPLE_SECGROUP_NAME') -EXAMPLE_SECGROUP_DESCR = get_value('example.sg_desc', - 'EXAMPLE_SECGROUP_DESCR') -PARSER_REPO_DIR = get_value('general.dir.repo_parser', - 'PARSER_REPO_DIR') diff --git a/functest/utils/openstack_utils.py b/functest/utils/openstack_utils.py index 3093cb55..e33af63b 100755 --- a/functest/utils/openstack_utils.py +++ b/functest/utils/openstack_utils.py @@ -18,6 +18,7 @@ from keystoneauth1 import loading from keystoneauth1 import session from cinderclient import client as cinderclient from glanceclient import client as glanceclient +from heatclient import client as heatclient from novaclient import client as novaclient from keystoneclient import client as keystoneclient from neutronclient.neutron import client as neutronclient @@ -28,6 +29,7 @@ import functest.utils.functest_utils as ft_utils logger = ft_logger.Logger("openstack_utils").getLogger() DEFAULT_API_VERSION = '2' +DEFAULT_HEAT_API_VERSION = '1' # ********************************************* @@ -241,6 +243,20 @@ def get_glance_client(other_creds={}): return glanceclient.Client(get_glance_client_version(), session=sess) +def get_heat_client_version(): + api_version = os.getenv('OS_ORCHESTRATION_API_VERSION') + if api_version is not None: + logger.info("OS_ORCHESTRATION_API_VERSION is set in env as '%s'", + api_version) + return api_version + return DEFAULT_HEAT_API_VERSION + + +def get_heat_client(other_creds={}): + sess = get_session(other_creds) + return heatclient.Client(get_heat_client_version(), session=sess) + + # ********************************************* # NOVA # ********************************************* @@ -985,36 +1001,43 @@ def create_security_group(neutron_client, sg_name, sg_description): def create_secgroup_rule(neutron_client, sg_id, direction, protocol, port_range_min=None, port_range_max=None): - if port_range_min is None and port_range_max is None: - json_body = {'security_group_rule': {'direction': direction, - 'security_group_id': sg_id, - 'protocol': protocol}} - elif port_range_min is not None and port_range_max is not None: - json_body = {'security_group_rule': {'direction': direction, - 'security_group_id': sg_id, - 'port_range_min': port_range_min, - 'port_range_max': port_range_max, - 'protocol': protocol}} + # We create a security group in 2 steps + # 1 - we check the format and set the json body accordingly + # 2 - we call neturon client to create the security group + + # Format check + json_body = {'security_group_rule': {'direction': direction, + 'security_group_id': sg_id, + 'protocol': protocol}} + # parameters may be + # - both None => we do nothing + # - both Not None => we add them to the json description + # but one cannot be None is the other is not None + if (port_range_min is not None and port_range_max is not None): + # add port_range in json description + json_body['security_group_rule']['port_range_min'] = port_range_min + json_body['security_group_rule']['port_range_max'] = port_range_max + logger.debug("Security_group format set (port range included)") else: - logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', " - "'%s', '%s', '%s', '%s')]:" % (neutron_client, - sg_id, direction, - port_range_min, - port_range_max, - protocol), - " Invalid values for port_range_min, port_range_max") - return False + # either both port range are set to None => do nothing + # or one is set but not the other => log it and return False + if port_range_min is None and port_range_max is None: + logger.debug("Security_group format set (no port range mentioned)") + else: + logger.error("Bad security group format." + "One of the port range is not properly set:" + "range min: {}," + "range max: {}".format(port_range_min, + port_range_max)) + return False + + # Create security group using neutron client try: neutron_client.create_security_group_rule(json_body) return True - except Exception, e: - logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', " - "'%s', '%s', '%s', '%s')]: %s" % (neutron_client, - sg_id, - direction, - port_range_min, - port_range_max, - protocol, e)) + except: + logger.exception("Impossible to create_security_group_rule," + "security group rule probably already exists") return False @@ -1383,3 +1406,15 @@ def delete_user(keystone_client, user_id): logger.error("Error [delete_user(keystone_client, '%s')]: %s" % (user_id, e)) return False + + +# ********************************************* +# HEAT +# ********************************************* +def get_resource(heat_client, stack_id, resource): + try: + resources = heat_client.resources.get(stack_id, resource) + return resources + except Exception, e: + logger.error("Error [get_resource]: %s" % e) + return None |