diff options
Diffstat (limited to 'functest')
-rwxr-xr-x | functest/ci/config_functest.yaml | 12 | ||||
-rwxr-xr-x | functest/ci/config_patch.yaml | 6 | ||||
-rwxr-xr-x | functest/ci/exec_test.sh | 6 | ||||
-rwxr-xr-x | functest/ci/prepare_env.py | 58 | ||||
-rwxr-xr-x | functest/ci/testcases.yaml | 27 | ||||
-rw-r--r-- | functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template | 2 | ||||
-rw-r--r-- | functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template | 2 | ||||
-rw-r--r-- | functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt | 19 | ||||
-rw-r--r-- | functest/opnfv_tests/openstack/tempest/custom_tests/test_list.txt | 4 | ||||
-rw-r--r-- | functest/opnfv_tests/openstack/tempest/tempest.py | 6 | ||||
-rw-r--r-- | functest/opnfv_tests/sdn/onos/__init__.py | 0 | ||||
-rw-r--r-- | functest/opnfv_tests/sdn/onos/onos.py | 225 | ||||
-rwxr-xr-x | functest/opnfv_tests/sdn/onos/teston/onos.py | 261 | ||||
-rw-r--r-- | functest/tests/unit/utils/test_openstack_utils.py | 58 | ||||
-rwxr-xr-x[-rw-r--r--] | functest/utils/config.py | 20 | ||||
-rw-r--r-- | functest/utils/functest_constants.py | 9 | ||||
-rwxr-xr-x | functest/utils/openstack_utils.py | 87 |
17 files changed, 430 insertions, 372 deletions
diff --git a/functest/ci/config_functest.yaml b/functest/ci/config_functest.yaml index 489c395f..402e2999 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 @@ -43,8 +43,8 @@ general: 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 +67,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 index aa0cfaf7..6f776101 100755 --- a/functest/ci/exec_test.sh +++ b/functest/ci/exec_test.sh @@ -94,12 +94,6 @@ function run_test(){ --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 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/testcases.yaml b/functest/ci/testcases.yaml index f8bbe9b7..722e8796 100755 --- a/functest/ci/testcases.yaml +++ b/functest/ci/testcases.yaml @@ -78,7 +78,7 @@ tiers: over a private network. dependencies: installer: '' - scenario: '^((?!bgpvpn|odl_l3).)*$' + scenario: '^((?!odl_l3).)*$' run: module: 'functest.opnfv_tests.openstack.vping.vping_ssh' class: 'VPingSSH' @@ -125,7 +125,7 @@ tiers: Rally suite in smoke mode. dependencies: installer: '' - scenario: '^((?!bgpvpn).)*$' + scenario: '' run: module: 'functest.opnfv_tests.openstack.rally.rally' class: 'RallySanity' @@ -184,7 +184,9 @@ tiers: dependencies: installer: '' scenario: 'onos' - + run: + module: 'functest.opnfv_tests.sdn.onos.onos' + class: 'Onos' - name: snaps_smoke @@ -319,6 +321,9 @@ tiers: dependencies: installer: '' scenario: 'onos-sfc' + run: + module: 'functest.opnfv_tests.sdn.onos.onos' + class: 'OnosSfc' - name: parser criteria: 'ret == 0' @@ -423,6 +428,22 @@ tiers: run: module: 'functest.opnfv_tests.openstack.tempest.tempest' class: 'TempestDefcore' + - + name: tempest_custom + criteria: 'success_rate == 100%' + blocking: false + description: >- + The test case allows running a customized list of tempest + test cases defined in a file under + <dir_functest_repo>/functest/opnfv_tests/openstack/ + /tempest/custom_tests/test_list.txt + The file is empty and can be customized with the desired tests. + dependencies: + installer: 'unknown' + scenario: 'unknown' + run: + module: 'functest.opnfv_tests.openstack.tempest.tempest' + class: 'TempestCustom' # - # name: rally_full # criteria: 'success_rate >= 90%' 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/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/custom_tests/test_list.txt b/functest/opnfv_tests/openstack/tempest/custom_tests/test_list.txt new file mode 100644 index 00000000..ac4e3728 --- /dev/null +++ b/functest/opnfv_tests/openstack/tempest/custom_tests/test_list.txt @@ -0,0 +1,4 @@ +# This is an empty file to be filled up with the desired tempest test cases +# Examples: +#tempest.scenario.test_server_basic_ops.TestServerBasicOps.test_server_basic_ops +#tempest.scenario.test_network_basic_ops.TestNetworkBasicOps.test_network_basic_ops
\ No newline at end of file diff --git a/functest/opnfv_tests/openstack/tempest/tempest.py b/functest/opnfv_tests/openstack/tempest/tempest.py index 37b5c0ee..4c96500d 100644 --- a/functest/opnfv_tests/openstack/tempest/tempest.py +++ b/functest/opnfv_tests/openstack/tempest/tempest.py @@ -324,11 +324,11 @@ class TempestMultisite(TempestCommon): class TempestCustom(TempestCommon): - def __init__(self, mode, option): + def __init__(self): TempestCommon.__init__(self) self.case_name = "tempest_custom" - self.MODE = mode - self.OPTION = option + self.MODE = "custom" + self.OPTION = "--concurrency 1" class TempestDefcore(TempestCommon): 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/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/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/config.py b/functest/utils/config.py index 84166c1d..b5b84501 100644..100755 --- a/functest/utils/config.py +++ b/functest/utils/config.py @@ -2,26 +2,25 @@ import os import yaml +import env + class Config(object): def __init__(self): - if 'CONFIG_FUNCTEST_YAML' not in os.environ: - raise Exception('CONFIG_FUNCTEST_YAML not configed') - self.config_functest = os.environ['CONFIG_FUNCTEST_YAML'] try: - with open(self.config_functest) as f: + with open(env.ENV.CONFIG_FUNCTEST_YAML) as f: self.functest_yaml = yaml.safe_load(f) self._parse(None, self.functest_yaml) - except: - raise Exception('Parse {} failed'.format(self.config_functest)) + except Exception as error: + raise Exception('Parse config failed: {}'.format(str(error))) self._set_others() def _parse(self, attr_now, left_parametes): for param_n, param_v in left_parametes.iteritems(): attr_further = self._get_attr_further(attr_now, param_n) - if not isinstance(param_v, dict): + if attr_further: self.__setattr__(attr_further, param_v) - else: + if isinstance(param_v, dict): self._parse(attr_further, param_v) def _get_attr_further(self, attr_now, next): @@ -33,3 +32,8 @@ class Config(object): CONF = Config() + +if __name__ == "__main__": + print CONF.vnf_cloudify_ims + print CONF.vnf_cloudify_ims_tenant_images + print CONF.vnf_cloudify_ims_tenant_images_centos_7 diff --git a/functest/utils/functest_constants.py b/functest/utils/functest_constants.py index 0a9a03b1..9fae9a9c 100644 --- a/functest/utils/functest_constants.py +++ b/functest/utils/functest_constants.py @@ -94,15 +94,6 @@ 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', 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 |