diff options
Diffstat (limited to 'functest')
31 files changed, 573 insertions, 1037 deletions
diff --git a/functest/ci/config_functest.yaml b/functest/ci/config_functest.yaml index f6cb14cb..d0442cf9 100755 --- a/functest/ci/config_functest.yaml +++ b/functest/ci/config_functest.yaml @@ -5,7 +5,6 @@ general: dir_odl: functest/opnfv_tests/sdn/odl rally: functest/opnfv_tests/openstack/rally tempest_cases: functest/opnfv_tests/openstack/tempest/custom_tests - dir_vIMS: functest/opnfv_tests/vnf/ims dir_onos: functest/opnfv_tests/sdn/onos/teston dir_onos_sfc: functest/opnfv_tests/sdn/onos/sfc @@ -27,13 +26,14 @@ general: repo_parser: /home/opnfv/repos/parser repo_domino: /home/opnfv/repos/domino repo_snaps: /home/opnfv/repos/snaps + repo_securityscan: /home/opnfv/repos/securityscanning functest: /home/opnfv/functest functest_test: /home/opnfv/repos/functest/functest/opnfv_tests results: /home/opnfv/functest/results functest_logging_cfg: /home/opnfv/repos/functest/functest/ci/logging.json functest_conf: /home/opnfv/functest/conf functest_data: /home/opnfv/functest/data - dir_vIMS_data: /home/opnfv/functest/data/vIMS/ + ims_data: /home/opnfv/functest/data/ims/ rally_inst: /home/opnfv/.rally openstack: @@ -125,45 +125,7 @@ vnf: cloudify_ims: tenant_name: cloudify_ims tenant_description: vIMS - tenant_images: - ubuntu_14.04: http://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img - centos_7: http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1510.qcow2 - cloudify: - blueprint: - url: https://github.com/boucherv-orange/cloudify-manager-blueprints.git - branch: "3.3.1-build" - requierments: - ram_min: 3000 - os_image: centos_7 - inputs: - keystone_username: "" - keystone_password: "" - keystone_tenant_name: "" - keystone_url: "" - manager_public_key_name: 'manager-kp' - agent_public_key_name: 'agent-kp' - image_id: "" - flavor_id: "3" - external_network_name: "" - ssh_user: centos - agents_user: ubuntu - clearwater: - blueprint: - file_name: 'openstack-blueprint.yaml' - name: "clearwater-opnfv" - destination_folder: "opnfv-cloudify-clearwater" - url: https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater.git - branch: "stable" - deployment_name: 'clearwater-opnfv' - requirements: - ram_min: 1700 - os_image: ubuntu_14.04 - inputs: - image_id: '' - flavor_id: '' - agent_user: 'ubuntu' - external_network_name: '' - public_domain: clearwater.opnfv + config: cloudify_ims.yaml orchestra_ims: tenant_name: orchestra_ims tenant_description: ims deployed with openbaton diff --git a/functest/ci/exec_test.sh b/functest/ci/exec_test.sh index 6a2b55a2..aa0cfaf7 100755 --- a/functest/ci/exec_test.sh +++ b/functest/ci/exec_test.sh @@ -105,14 +105,6 @@ function run_test(){ # no need to run anything until refactoring done # ${REPOS_DIR}/ovno/Testcases/RunTests.sh ;; - "security_scan") - echo "Sourcing Credentials ${FUNCTEST_CONF_DIR}/stackrc for undercloud .." - source ${FUNCTEST_CONF_DIR}/stackrc - python ${FUNCTEST_TEST_DIR}/security_scan/security_scan.py --config ${FUNCTEST_TEST_DIR}/security_scan/config.ini - ;; - "moon") - python ${REPOS_DIR}/moon/tests/run_tests.py $report - ;; *) echo "The test case '${test_name}' does not exist." exit 1 diff --git a/functest/ci/prepare_env.py b/functest/ci/prepare_env.py index b3e59020..6b24fe08 100755 --- a/functest/ci/prepare_env.py +++ b/functest/ci/prepare_env.py @@ -47,7 +47,8 @@ class PrepareEnvParser(): def __init__(self): self.parser = argparse.ArgumentParser() self.parser.add_argument("action", help="Possible actions are: " - "'{d[0]}|{d[1]}' ".format(d=actions)) + "'{d[0]}|{d[1]}' ".format(d=actions), + choices=actions) self.parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") @@ -140,14 +141,14 @@ def source_rc_file(): if CONST.INSTALLER_IP is None: logger.error("The env variable CI_INSTALLER_IP must be provided in" " order to fetch the credentials from the installer.") - sys.exit("Missing CI_INSTALLER_IP.") + raise Exception("Missing CI_INSTALLER_IP.") if CONST.INSTALLER_TYPE not in opnfv_constants.INSTALLERS: logger.error("Cannot fetch credentials. INSTALLER_TYPE=%s is " "not a valid OPNFV installer. Available " "installers are : %s." % (CONST.INSTALLER_TYPE, opnfv_constants.INSTALLERS)) - sys.exit("Wrong INSTALLER_TYPE.") + raise Exception("Wrong INSTALLER_TYPE.") cmd = ("/home/opnfv/repos/releng/utils/fetch_os_creds.sh " "-d %s -i %s -a %s" @@ -159,23 +160,18 @@ def source_rc_file(): output = p.communicate()[0] logger.debug("\n%s" % output) if p.returncode != 0: - logger.error("Failed to fetch credentials from installer.") - sys.exit(1) + raise Exception("Failed to fetch credentials from installer.") else: logger.info("RC file provided in %s." % CONST.openstack_creds) if os.path.getsize(CONST.openstack_creds) == 0: - logger.error("The file %s is empty." - % CONST.openstack_creds) - sys.exit(1) + raise Exception("The file %s is empty." % CONST.openstack_creds) logger.info("Sourcing the OpenStack RC file...") - creds = os_utils.source_credentials( + os_utils.source_credentials( CONST.openstack_creds) - str = "" - for key, value in creds.iteritems(): + for key, value in os.environ.iteritems(): if re.search("OS_", key): - str += "\n\t\t\t\t\t\t " + key + "=" + value if key == 'OS_AUTH_URL': CONST.OS_AUTH_URL = value elif key == 'OS_USERNAME': @@ -213,7 +209,7 @@ def verify_deployment(): line = p.stdout.readline().rstrip() if "ERROR" in line: logger.error(line) - sys.exit("Problem while running 'check_os.sh'.") + raise Exception("Problem while running 'check_os.sh'.") logger.info(line) @@ -272,46 +268,43 @@ def create_flavor(): def check_environment(): msg_not_active = "The Functest environment is not installed." if not os.path.isfile(CONST.env_active): - logger.error(msg_not_active) - sys.exit(1) + raise Exception(msg_not_active) with open(CONST.env_active, "r") as env_file: s = env_file.read() if not re.search("1", s): - logger.error(msg_not_active) - sys.exit(1) + raise Exception(msg_not_active) logger.info("Functest environment is installed.") def main(**kwargs): - if not (kwargs['action'] in actions): - logger.error('Argument not valid.') - sys.exit() - - if kwargs['action'] == "start": - logger.info("######### Preparing Functest environment #########\n") - check_env_variables() - create_directories() - source_rc_file() - patch_config_file() - verify_deployment() - install_rally() - install_tempest() - create_flavor() - - with open(CONST.env_active, "w") as env_file: - env_file.write("1") - - check_environment() - - if kwargs['action'] == "check": - check_environment() - - exit(0) + try: + if not (kwargs['action'] in actions): + logger.error('Argument not valid.') + return -1 + elif kwargs['action'] == "start": + logger.info("######### Preparing Functest environment #########\n") + check_env_variables() + create_directories() + source_rc_file() + patch_config_file() + verify_deployment() + install_rally() + install_tempest() + create_flavor() + with open(CONST.env_active, "w") as env_file: + env_file.write("1") + check_environment() + elif kwargs['action'] == "check": + check_environment() + except Exception as e: + logger.error(e) + return -1 + return 0 if __name__ == '__main__': parser = PrepareEnvParser() args = parser.parse_args(sys.argv[1:]) - main(**args) + sys.exit(main(**args)) diff --git a/functest/ci/run_tests.py b/functest/ci/run_tests.py index 320102dd..93518de0 100755 --- a/functest/ci/run_tests.py +++ b/functest/ci/run_tests.py @@ -10,6 +10,7 @@ import argparse import datetime +import enum import importlib import os import re @@ -35,7 +36,16 @@ logger = ft_logger.Logger("run_tests").getLogger() 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 -1 +# this variable will change to Result.EX_ERROR + + +class Result(enum.Enum): + EX_OK = os.EX_OK + EX_ERROR = -1 + + +class BlockingTestFailed(Exception): + pass class RunTestsParser(): @@ -60,7 +70,7 @@ class RunTestsParser(): class GlobalVariables: EXECUTED_TEST_CASES = [] - OVERALL_RESULT = 0 + OVERALL_RESULT = Result.EX_OK CLEAN_FLAG = True REPORT_FLAG = False @@ -75,11 +85,10 @@ def print_separator(str, count=45): def source_rc_file(): rc_file = CONST.openstack_creds if not os.path.isfile(rc_file): - logger.error("RC file %s does not exist..." % rc_file) - sys.exit(1) + raise Exception("RC file %s does not exist..." % rc_file) logger.debug("Sourcing the OpenStack RC file...") - creds = os_utils.source_credentials(rc_file) - for key, value in creds.iteritems(): + os_utils.source_credentials(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 @@ -155,7 +164,7 @@ def run_test(test, tier_name, testcases=None): result = test_case.run() if result == testcase_base.TestcaseBase.EX_OK: if GlobalVariables.REPORT_FLAG: - test_case.publish_report() + test_case.push_to_db() result = test_case.check_criteria() except ImportError: logger.exception("Cannot import module {}".format( @@ -179,19 +188,16 @@ def run_test(test, tier_name, testcases=None): if result != 0: logger.error("The test case '%s' failed. " % test_name) - GlobalVariables.OVERALL_RESULT = -1 + GlobalVariables.OVERALL_RESULT = Result.EX_ERROR result_str = "FAIL" if test.is_blocking(): if not testcases or testcases == "all": - logger.info("This test case is blocking. Aborting overall " - "execution.") # if it is a single test we don't print the whole results table update_test_info(test_name, result_str, duration_str) generate_report.main(GlobalVariables.EXECUTED_TEST_CASES) - logger.info("Execution exit value: %s" % - GlobalVariables.OVERALL_RESULT) - sys.exit(GlobalVariables.OVERALL_RESULT) + raise BlockingTestFailed("The test case {} failed and is blocking" + .format(test.get_name())) update_test_info(test_name, result_str, duration_str) @@ -246,33 +252,37 @@ def main(**kwargs): if kwargs['report']: GlobalVariables.REPORT_FLAG = True - if kwargs['test']: - source_rc_file() - if _tiers.get_tier(kwargs['test']): - run_tier(_tiers.get_tier(kwargs['test'])) - - elif _tiers.get_test(kwargs['test']): - run_test(_tiers.get_test(kwargs['test']), - _tiers.get_tier(kwargs['test']), - kwargs['test']) - - elif kwargs['test'] == "all": - run_all(_tiers) - + try: + if kwargs['test']: + source_rc_file() + if _tiers.get_tier(kwargs['test']): + GlobalVariables.EXECUTED_TEST_CASES = generate_report.init( + [_tiers.get_tier(kwargs['test'])]) + run_tier(_tiers.get_tier(kwargs['test'])) + elif _tiers.get_test(kwargs['test']): + run_test(_tiers.get_test(kwargs['test']), + _tiers.get_tier(kwargs['test']), + kwargs['test']) + elif kwargs['test'] == "all": + run_all(_tiers) + else: + logger.error("Unknown test case or tier '%s', " + "or not supported by " + "the given scenario '%s'." + % (kwargs['test'], CI_SCENARIO)) + logger.debug("Available tiers are:\n\n%s" + % _tiers) + return Result.EX_ERROR else: - logger.error("Unknown test case or tier '%s', or not supported by " - "the given scenario '%s'." - % (kwargs['test'], CI_SCENARIO)) - logger.debug("Available tiers are:\n\n%s" - % _tiers) - else: - run_all(_tiers) - + run_all(_tiers) + except Exception as e: + logger.error(e) + GlobalVariables.OVERALL_RESULT = Result.EX_ERROR logger.info("Execution exit value: %s" % GlobalVariables.OVERALL_RESULT) - sys.exit(GlobalVariables.OVERALL_RESULT) + return GlobalVariables.OVERALL_RESULT if __name__ == '__main__': parser = RunTestsParser() args = parser.parse_args(sys.argv[1:]) - main(**args) + sys.exit(main(**args).value) diff --git a/functest/ci/testcases.yaml b/functest/ci/testcases.yaml index 6397f764..4d02fe78 100755 --- a/functest/ci/testcases.yaml +++ b/functest/ci/testcases.yaml @@ -19,6 +19,22 @@ tiers: installer: '' scenario: '^((?!lxd).)*$' - + name: snaps_health_check + criteria: 'status == "PASS"' + blocking: 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: connection_check criteria: 'status == "PASS"' blocking: true @@ -124,9 +140,9 @@ tiers: criteria: 'success_rate == 100%' blocking: true description: >- - Test Suite for the OpenDaylight SDN Controller. It integrates - some test suites from upstream using Robot as the test - framework. + Test Suite for the OpenDaylight SDN Controller. It + integrates some test suites from upstream using + Robot as the test framework. dependencies: installer: '' scenario: 'odl' @@ -139,6 +155,27 @@ tiers: - /home/opnfv/repos/odl_test/csit/suites/openstack/neutron - + name: odl_netvirt + criteria: 'success_rate == 100%' + blocking: true + 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' + run: + module: 'functest.opnfv_tests.sdn.odl.odl' + class: 'ODLTests' + args: + suites: + - /home/opnfv/repos/odl_test/csit/suites/integration/basic + - /home/opnfv/repos/odl_test/csit/suites/openstack/neutron + - /home/opnfv/repos/odl_test/csit/suites/openstack/connectivity + + - name: onos criteria: 'status == "PASS"' blocking: true @@ -223,10 +260,13 @@ tiers: criteria: 'status == "PASS"' blocking: false description: >- - Simple security Scan + Simple Security Scan dependencies: installer: 'apex' scenario: '^((?!fdio).)*$' + run: + module: 'functest.opnfv_tests.features.security_scan' + class: 'SecurityScan' # - # name: copper # criteria: 'status == "PASS"' @@ -240,15 +280,6 @@ tiers: # module: 'functest.opnfv_tests.features.copper' # class: 'Copper' - - name: moon - criteria: 'status == "PASS"' - blocking: false - description: >- - Security management system for OPNFV - dependencies: - installer: 'compass' - scenario: '(odl)*(moon)' - - name: multisite criteria: 'success_rate == 100%' blocking: false diff --git a/functest/core/feature_base.py b/functest/core/feature_base.py index 873e21da..fe9a9998 100644 --- a/functest/core/feature_base.py +++ b/functest/core/feature_base.py @@ -24,6 +24,7 @@ class FeatureBase(base.TestcaseBase): self.post() self.parse_results(ret) self.log_results() + self.logger.info("Test result is stored in '%s'" % self.result_file) return base.TestcaseBase.EX_OK def prepare(self, **kwargs): diff --git a/functest/core/testcase_base.py b/functest/core/testcase_base.py index ec46bc64..838b6398 100644 --- a/functest/core/testcase_base.py +++ b/functest/core/testcase_base.py @@ -9,7 +9,6 @@ import os -from functest.utils.constants import CONST import functest.utils.functest_logger as ft_logger import functest.utils.functest_utils as ft_utils @@ -18,7 +17,7 @@ class TestcaseBase(object): EX_OK = os.EX_OK EX_RUN_ERROR = os.EX_SOFTWARE - EX_PUBLISH_RESULT_FAILED = os.EX_SOFTWARE - 1 + EX_PUSH_TO_DB_ERROR = os.EX_SOFTWARE - 1 EX_TESTCASE_FAILED = os.EX_SOFTWARE - 2 logger = ft_logger.Logger(__name__).getLogger() @@ -44,45 +43,21 @@ class TestcaseBase(object): self.logger.error("Run must be implemented") return TestcaseBase.EX_RUN_ERROR - def publish_report(self): - if "RESULTS_STORE" in os.environ: - CONST.results_test_db_url = os.environ['RESULTS_STORE'] - + def push_to_db(self): try: assert self.project_name assert self.case_name assert self.criteria assert self.start_time assert self.stop_time - if CONST.results_test_db_url.lower().startswith( - ("http://", "https://")): - self.push_to_db() - elif CONST.results_test_db_url.lower().startswith("file://"): - self.write_to_file() + if ft_utils.push_results_to_db( + self.project_name, self.case_name, self.start_time, + self.stop_time, self.criteria, self.details): + self.logger.info("The results were successfully pushed to DB") + return TestcaseBase.EX_OK else: - self.logger.error("Please check parameter test_db_url and " - "OS environ variable RESTULTS_STORE") - return TestcaseBase.EX_PUBLISH_RESULT_FAILED + self.logger.error("The results cannot be pushed to DB") + return TestcaseBase.EX_PUSH_TO_DB_ERROR except Exception: - self.logger.exception("The results cannot be stored") - return TestcaseBase.EX_PUBLISH_RESULT_FAILED - - def write_to_file(self): - if ft_utils.write_results_to_file( - self.project_name, self.case_name, self.start_time, - self.stop_time, self.criteria, self.details): - self.logger.info("The results were successfully written to a file") - return TestcaseBase.EX_OK - else: - self.logger.error("write results to a file failed") - return TestcaseBase.EX_PUBLISH_RESULT_FAILED - - def push_to_db(self): - if ft_utils.push_results_to_db( - self.project_name, self.case_name, self.start_time, - self.stop_time, self.criteria, self.details): - self.logger.info("The results were successfully pushed to DB") - return TestcaseBase.EX_OK - else: - self.logger.error("The results cannot be pushed to DB") - return TestcaseBase.EX_PUBLISH_RESULT_FAILED + self.logger.exception("The results cannot be pushed to DB") + return TestcaseBase.EX_PUSH_TO_DB_ERROR diff --git a/functest/core/vnf_base.py b/functest/core/vnf_base.py index 4d019858..44b4ae04 100644 --- a/functest/core/vnf_base.py +++ b/functest/core/vnf_base.py @@ -7,12 +7,10 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 -import os import time import inspect - import functest.utils.functest_logger as ft_logger import functest.utils.openstack_utils as os_utils import functest.utils.functest_utils as ft_utils @@ -161,30 +159,6 @@ class VnfOnBoardingBase(base.TestcaseBase): "username": self.tenant_name, "password": self.tenant_name, }) - self.glance_client = os_utils.get_glance_client(self.creds) - 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(): - image_id = os_utils.get_image_id(self.glance_client, image_name) - - if image_id == '': - self.logger.info("""%s image doesn't exist on glance repository. Try - downloading this image and upload on glance !""" % image_name) - image_id = os_utils.download_and_add_image_on_glance( - self.glance_client, image_name, image_url, temp_dir) - - if image_id == '': - self.step_failure( - "Failed to find or upload required OS " - "image for this deployment") - - self.logger.info("Update security group quota for this tenant") - - if not os_utils.update_sg_quota(self.neutron_client, - tenant_id, 50, 100): - self.step_failure("Failed to update security group quota" + - " for tenant " + self.tenant_name) # orchestrator is not mandatory to dpeloy and test VNF def deploy_orchestrator(self, **kwargs): diff --git a/functest/opnfv_tests/features/multisite.py b/functest/opnfv_tests/features/multisite.py deleted file mode 100755 index 15cfe2a4..00000000 --- a/functest/opnfv_tests/features/multisite.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2015 All rights reserved -# This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Execute Multisite Tempest test cases -# -import functest.utils.functest_logger as ft_logger - -logger = ft_logger.Logger("multisite").getLogger() - - -def main(): - logger.info("multisite OK") - - -if __name__ == '__main__': - main() diff --git a/functest/opnfv_tests/features/security_scan.py b/functest/opnfv_tests/features/security_scan.py new file mode 100755 index 00000000..bcae516b --- /dev/null +++ b/functest/opnfv_tests/features/security_scan.py @@ -0,0 +1,24 @@ +#!/usr/bin/python +# +# Copyright (c) 2015 All rights reserved +# This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +import functest.core.feature_base as base +from functest.utils.constants import CONST + + +class SecurityScan(base.FeatureBase): + def __init__(self): + super(SecurityScan, self).__init__(project='security_scan', + case='security_scan', + repo='dir_repo_securityscan') + self.cmd = ('bash {0} && ' + 'cd {1} && ' + 'python security_scan.py --config config.ini && ' + 'cd -'.format(CONST.openstack_creds, + self.repo)) diff --git a/functest/opnfv_tests/openstack/rally/rally.py b/functest/opnfv_tests/openstack/rally/rally.py index 16a872fc..46d6a570 100644 --- a/functest/opnfv_tests/openstack/rally/rally.py +++ b/functest/opnfv_tests/openstack/rally/rally.py @@ -526,14 +526,13 @@ class RallyBase(testcase_base.TestcaseBase): self._run_tests() self._generate_report() self._clean_up() + res = testcase_base.TestcaseBase.EX_OK except Exception as e: logger.error('Error with run: %s' % e) - return testcase_base.TestcaseBase.EX_RUN_ERROR - self.stop_time = time.time() + res = testcase_base.TestcaseBase.EX_RUN_ERROR - # If we are here, it means that the test case was successfully executed - # criteria is managed by the criteria Field - return testcase_base.TestcaseBase.EX_OK + self.stop_time = time.time() + return res class RallySanity(RallyBase): diff --git a/functest/opnfv_tests/openstack/snaps/health_check.py b/functest/opnfv_tests/openstack/snaps/health_check.py new file mode 100644 index 00000000..993c1000 --- /dev/null +++ b/functest/opnfv_tests/openstack/snaps/health_check.py @@ -0,0 +1,34 @@ +# 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 + +import unittest + +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): + """ + 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(HealthCheck, self).__init__() + + self.suite = unittest.TestSuite() + self.case_name = "snaps_health_check" + ext_net_name = snaps_utils.get_ext_net_name() + + self.suite.addTest( + OSIntegrationTestCase.parameterize( + SimpleHealthCheck, CONST.openstack_creds, ext_net_name, + use_keystone=CONST.snaps_use_keystone)) diff --git a/functest/opnfv_tests/openstack/tempest/conf_utils.py b/functest/opnfv_tests/openstack/tempest/conf_utils.py index 91a5bb4b..028b085c 100644 --- a/functest/opnfv_tests/openstack/tempest/conf_utils.py +++ b/functest/opnfv_tests/openstack/tempest/conf_utils.py @@ -13,8 +13,6 @@ import re import shutil import subprocess -import opnfv.utils.constants as releng_constants - from functest.utils.constants import CONST import functest.utils.functest_logger as ft_logger import functest.utils.functest_utils as ft_utils @@ -110,24 +108,19 @@ def get_verifier_deployment_dir(verifier_id, deployment_id): def configure_tempest(deployment_dir, IMAGE_ID=None, FLAVOR_ID=None): """ - Add/update needed parameters into tempest.conf file generated by Rally + Calls rally verify and updates the generated tempest.conf with + given parameters """ - tempest_conf_file = os.path.join(deployment_dir, "tempest.conf") - if os.path.isfile(tempest_conf_file): - logger.debug("Verifier is already configured.") - logger.debug("Reconfiguring the current verifier...") - cmd = "rally verify configure-verifier --reconfigure" - else: - logger.info("Configuring the verifier...") - cmd = "rally verify configure-verifier" - ft_utils.execute_command(cmd) + conf_file = configure_verifier(deployment_dir) + configure_tempest_update_params(conf_file, + IMAGE_ID, FLAVOR_ID) - logger.debug("Looking for tempest.conf file...") - if not os.path.isfile(tempest_conf_file): - logger.error("Tempest configuration file %s NOT found." - % tempest_conf_file) - return releng_constants.EXIT_RUN_ERROR +def configure_tempest_update_params(tempest_conf_file, + IMAGE_ID=None, FLAVOR_ID=None): + """ + Add/update needed parameters into tempest.conf file + """ logger.debug("Updating selected tempest.conf parameters...") config = ConfigParser.RawConfigParser() config.read(tempest_conf_file) @@ -178,7 +171,29 @@ def configure_tempest(deployment_dir, IMAGE_ID=None, FLAVOR_ID=None): shutil.copyfile(tempest_conf_file, os.path.join(TEMPEST_RESULTS_DIR, 'tempest.conf')) - return releng_constants.EXIT_OK + +def configure_verifier(deployment_dir): + """ + Execute rally verify configure-verifier, which generates tempest.conf + """ + tempest_conf_file = os.path.join(deployment_dir, "tempest.conf") + if os.path.isfile(tempest_conf_file): + logger.debug("Verifier is already configured.") + logger.debug("Reconfiguring the current verifier...") + cmd = "rally verify configure-verifier --reconfigure" + else: + logger.info("Configuring the verifier...") + cmd = "rally verify configure-verifier" + ft_utils.execute_command(cmd) + + logger.debug("Looking for tempest.conf file...") + if not os.path.isfile(tempest_conf_file): + logger.error("Tempest configuration file %s NOT found." + % tempest_conf_file) + raise Exception("Tempest configuration file %s NOT found." + % tempest_conf_file) + else: + return tempest_conf_file def configure_tempest_multisite(deployment_dir): @@ -191,9 +206,8 @@ def configure_tempest_multisite(deployment_dir): logger.debug("Finding tempest.conf file...") tempest_conf_old = os.path.join(deployment_dir, 'tempest.conf') if not os.path.isfile(tempest_conf_old): - logger.error("Tempest configuration file %s NOT found." - % tempest_conf_old) - return releng_constants.EXIT_RUN_ERROR + raise Exception("Tempest configuration file %s NOT found." + % tempest_conf_old) # Copy tempest.conf to /home/opnfv/functest/results/tempest/ cur_path = os.path.split(os.path.realpath(__file__))[0] @@ -265,5 +279,3 @@ def configure_tempest_multisite(deployment_dir): config.set('kingbird', 'api_version', kingbird_api_version) with open(tempest_conf_file, 'wb') as config_file: config.write(config_file) - - return releng_constants.EXIT_OK diff --git a/functest/opnfv_tests/openstack/tempest/tempest.py b/functest/opnfv_tests/openstack/tempest/tempest.py index e1a223a7..13d9e4e6 100644 --- a/functest/opnfv_tests/openstack/tempest/tempest.py +++ b/functest/opnfv_tests/openstack/tempest/tempest.py @@ -57,7 +57,7 @@ class TempestCommon(testcase_base.TestcaseBase): CONST.tempest_identity_tenant_name, CONST.tempest_identity_tenant_description) if not tenant_id: - logger.error("Error : Failed to create %s tenant" + logger.error("Failed to create %s tenant" % CONST.tempest_identity_tenant_name) user_id = os_utils.create_user(keystone_client, @@ -65,7 +65,7 @@ class TempestCommon(testcase_base.TestcaseBase): CONST.tempest_identity_user_password, None, tenant_id) if not user_id: - logger.error("Error : Failed to create %s user" % + logger.error("Failed to create %s user" % CONST.tempest_identity_user_name) logger.debug("Creating private network for Tempest suite") @@ -74,8 +74,8 @@ class TempestCommon(testcase_base.TestcaseBase): CONST.tempest_private_subnet_name, CONST.tempest_router_name, CONST.tempest_private_subnet_cidr) - if not network_dic: - return testcase_base.TestcaseBase.EX_RUN_ERROR + if network_dic is None: + raise Exception('Failed to create private network') if CONST.tempest_use_custom_images: # adding alternative image should be trivial should we need it @@ -83,8 +83,8 @@ class TempestCommon(testcase_base.TestcaseBase): _, self.IMAGE_ID = os_utils.get_or_create_image( CONST.openstack_image_name, conf_utils.GLANCE_IMAGE_PATH, CONST.openstack_image_disk_format) - if not self.IMAGE_ID: - return testcase_base.TestcaseBase.EX_RUN_ERROR + if self.IMAGE_ID is None: + raise Exception('Failed to create image') if CONST.tempest_use_custom_flavors: # adding alternative flavor should be trivial should we need it @@ -94,10 +94,8 @@ class TempestCommon(testcase_base.TestcaseBase): CONST.openstack_flavor_ram, CONST.openstack_flavor_disk, CONST.openstack_flavor_vcpus) - if not self.FLAVOR_ID: - return testcase_base.TestcaseBase.EX_RUN_ERROR - - return testcase_base.TestcaseBase.EX_OK + if self.FLAVOR_ID is None: + raise Exception('Failed to create flavor') def generate_test_list(self, verifier_repo_dir): logger.debug("Generating test case list...") @@ -109,9 +107,8 @@ class TempestCommon(testcase_base.TestcaseBase): shutil.copyfile( conf_utils.TEMPEST_CUSTOM, conf_utils.TEMPEST_RAW_LIST) else: - logger.error("Tempest test list file %s NOT found." - % conf_utils.TEMPEST_CUSTOM) - return testcase_base.TestcaseBase.EX_RUN_ERROR + raise Exception("Tempest test list file %s NOT found." + % conf_utils.TEMPEST_CUSTOM) else: if self.MODE == 'smoke': testr_mode = "smoke" @@ -128,8 +125,6 @@ class TempestCommon(testcase_base.TestcaseBase): conf_utils.TEMPEST_RAW_LIST)) ft_utils.execute_command(cmd) - return testcase_base.TestcaseBase.EX_OK - def apply_tempest_blacklist(self): logger.debug("Applying tempest blacklist...") cases_file = self.read_file(conf_utils.TEMPEST_RAW_LIST) @@ -164,7 +159,6 @@ class TempestCommon(testcase_base.TestcaseBase): else: result_file.write(str(cases_line) + '\n') result_file.close() - return testcase_base.TestcaseBase.EX_OK def _parse_verification_id(line): first_pos = line.index("UUID=") + len("UUID=") @@ -217,7 +211,7 @@ class TempestCommon(testcase_base.TestcaseBase): f_env.close() def parse_verifier_result(self): - if not self.VERIFICATION_ID: + if self.VERIFICATION_ID is None: raise Exception('Verification UUID not found') cmd_line = "rally verify show --uuid {}".format(self.VERIFICATION_ID) @@ -274,33 +268,22 @@ class TempestCommon(testcase_base.TestcaseBase): if not os.path.exists(conf_utils.TEMPEST_RESULTS_DIR): os.makedirs(conf_utils.TEMPEST_RESULTS_DIR) - # Pre-configuration - res = self.create_tempest_resources() - if res != testcase_base.TestcaseBase.EX_OK: - return res - - res = conf_utils.configure_tempest(self.DEPLOYMENT_DIR, - self.IMAGE_ID, - self.FLAVOR_ID) - if res != testcase_base.TestcaseBase.EX_OK: - return res - - res = self.generate_test_list(self.VERIFIER_REPO_DIR) - if res != testcase_base.TestcaseBase.EX_OK: - return res - - res = self.apply_tempest_blacklist() - if res != testcase_base.TestcaseBase.EX_OK: - return res - - self.run_verifier_tests() - self.parse_verifier_result() + try: + self.create_tempest_resources() + conf_utils.configure_tempest(self.DEPLOYMENT_DIR, + self.IMAGE_ID, + self.FLAVOR_ID) + self.generate_test_list(self.VERIFIER_REPO_DIR) + self.apply_tempest_blacklist() + self.run_verifier_tests() + self.parse_verifier_result() + 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() - - # If we are here, it means that the test case was successfully executed - # criteria is managed by the criteria Field - return testcase_base.TestcaseBase.EX_OK + return res class TempestSmokeSerial(TempestCommon): diff --git a/functest/opnfv_tests/openstack/vping/vping_base.py b/functest/opnfv_tests/openstack/vping/vping_base.py index 8285d93f..a5309bd4 100644 --- a/functest/opnfv_tests/openstack/vping/vping_base.py +++ b/functest/opnfv_tests/openstack/vping/vping_base.py @@ -289,6 +289,6 @@ class VPingMain(object): if result != VPingBase.EX_OK: return result if kwargs['report']: - return self.vping.publish_report() + return self.vping.push_to_db() except Exception: return VPingBase.EX_RUN_ERROR diff --git a/functest/opnfv_tests/sdn/odl/odl.py b/functest/opnfv_tests/sdn/odl/odl.py index 25075957..9bff324f 100755 --- a/functest/opnfv_tests/sdn/odl/odl.py +++ b/functest/opnfv_tests/sdn/odl/odl.py @@ -237,6 +237,6 @@ if __name__ == '__main__': if result != testcase_base.TestcaseBase.EX_OK: sys.exit(result) if args['pushtodb']: - sys.exit(odl.publish_report()) + sys.exit(odl.push_to_db()) except Exception: sys.exit(testcase_base.TestcaseBase.EX_RUN_ERROR) diff --git a/functest/opnfv_tests/security_scan/config.ini b/functest/opnfv_tests/security_scan/config.ini deleted file mode 100644 index b97de80f..00000000 --- a/functest/opnfv_tests/security_scan/config.ini +++ /dev/null @@ -1,29 +0,0 @@ -[undercloud] -port = 22 -user = stack -remotekey = /home/stack/.ssh/id_rsa -localkey = /root/.ssh/overCloudKey - -[controller] -port = 22 -user = heat-admin -scantype = xccdf -secpolicy = /usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml -cpe = /usr/share/xml/scap/ssg/content/ssg-rhel7-cpe-dictionary.xml -profile = stig-rhel7-server-upstream -report = report.html -results = results.xml -reports_dir=/home/opnfv/functest/results/security_scan/ -clean = True - -[compute] -port = 22 -user = heat-admin -scantype = xccdf -secpolicy = /usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml -cpe = /usr/share/xml/scap/ssg/content/ssg-rhel7-cpe-dictionary.xml -profile = sstig-rhel7-server-upstream -report = report.html -results = results.xml -reports_dir=/home/opnfv/functest/results/security_scan/ -clean = True diff --git a/functest/opnfv_tests/security_scan/connect.py b/functest/opnfv_tests/security_scan/connect.py deleted file mode 100644 index 3d5456c5..00000000 --- a/functest/opnfv_tests/security_scan/connect.py +++ /dev/null @@ -1,245 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2016 Red Hat -# Luke Hinds (lhinds@redhat.com) -# This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# 0.1: OpenSCAP paramiko connection functions - -import os -import socket -import paramiko - -import functest.utils.functest_logger as ft_logger -import functest.utils.functest_constants as ft_constants - -# add installer IP from env -INSTALLER_IP = ft_constants.CI_INSTALLER_IP - -# Set up loggers -logger = ft_logger.Logger("security_scan").getLogger() -paramiko.util.log_to_file("/var/log/paramiko.log") - - -class SetUp: - def __init__(self, *args): - self.args = args - - def keystonepass(self): - com = self.args[0] - client = paramiko.SSHClient() - privatekeyfile = os.path.expanduser('/root/.ssh/id_rsa') - selectedkey = paramiko.RSAKey.from_private_key_file(privatekeyfile) - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - try: - client.connect(INSTALLER_IP, port=22, username='stack', - pkey=selectedkey) - except paramiko.SSHException: - logger.error("Password is invalid for " - "undercloud host: {0}".format(INSTALLER_IP)) - except paramiko.AuthenticationException: - logger.error("Authentication failed for " - "undercloud host: {0}".format(INSTALLER_IP)) - except socket.error: - logger.error("Socker Connection failed for " - "undercloud host: {0}".format(INSTALLER_IP)) - stdin, stdout, stderr = client.exec_command(com) - return stdout.read() - client.close() - - def getockey(self): - remotekey = self.args[0] - localkey = self.args[1] - privatekeyfile = os.path.expanduser('/root/.ssh/id_rsa') - selectedkey = paramiko.RSAKey.from_private_key_file(privatekeyfile) - transport = paramiko.Transport((INSTALLER_IP, 22)) - transport.connect(username='stack', pkey=selectedkey) - try: - sftp = paramiko.SFTPClient.from_transport(transport) - except paramiko.SSHException: - logger.error("Authentication failed for " - "host: {0}".format(INSTALLER_IP)) - except paramiko.AuthenticationException: - logger.error("Authentication failed for " - "host: {0}".format(INSTALLER_IP)) - except socket.error: - logger.error("Socker Connection failed for " - "undercloud host: {0}".format(INSTALLER_IP)) - sftp.get(remotekey, localkey) - sftp.close() - transport.close() - - -class ConnectionManager: - def __init__(self, host, port, user, localkey, *args): - self.host = host - self.port = port - self.user = user - self.localkey = localkey - self.args = args - - def remotescript(self): - localpath = self.args[0] - remotepath = self.args[1] - com = self.args[2] - - client = paramiko.SSHClient() - privatekeyfile = os.path.expanduser('/root/.ssh/id_rsa') - selectedkey = paramiko.RSAKey.from_private_key_file(privatekeyfile) - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - # Connection to undercloud - try: - client.connect(INSTALLER_IP, port=22, username='stack', - pkey=selectedkey) - except paramiko.SSHException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except paramiko.AuthenticationException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except socket.error: - logger.error("Socker Connection failed for " - "undercloud host: {0}".format(self.host)) - - transport = client.get_transport() - local_addr = ('127.0.0.1', 0) - channel = transport.open_channel("direct-tcpip", - (self.host, int(self.port)), - (local_addr)) - remote_client = paramiko.SSHClient() - remote_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - # Tunnel to overcloud - try: - remote_client.connect('127.0.0.1', port=22, username=self.user, - key_filename=self.localkey, sock=channel) - sftp = remote_client.open_sftp() - sftp.put(localpath, remotepath) - except paramiko.SSHException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except paramiko.AuthenticationException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except socket.error: - logger.error("Socker Connection failed for " - "undercloud host: {0}".format(self.host)) - - output = "" - stdin, stdout, stderr = remote_client.exec_command(com) - stdout = stdout.readlines() - # remove script - sftp.remove(remotepath) - remote_client.close() - client.close() - # Pipe back stout - for line in stdout: - output = output + line - if output != "": - return output - - def remotecmd(self): - com = self.args[0] - - client = paramiko.SSHClient() - privatekeyfile = os.path.expanduser('/root/.ssh/id_rsa') - selectedkey = paramiko.RSAKey.from_private_key_file(privatekeyfile) - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - # Connection to undercloud - try: - client.connect(INSTALLER_IP, port=22, username='stack', - pkey=selectedkey) - except paramiko.SSHException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except paramiko.AuthenticationException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except socket.error: - logger.error("Socker Connection failed for " - "undercloud host: {0}".format(self.host)) - - transport = client.get_transport() - local_addr = ('127.0.0.1', 0) # 0 denotes choose random port - channel = transport.open_channel("direct-tcpip", - (self.host, int(self.port)), - (local_addr)) - remote_client = paramiko.SSHClient() - remote_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - # Tunnel to overcloud - try: - remote_client.connect('127.0.0.1', port=22, username=self.user, - key_filename=self.localkey, sock=channel) - except paramiko.SSHException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except paramiko.AuthenticationException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except socket.error: - logger.error("Socker Connection failed for " - "undercloud host: {0}".format(self.host)) - - chan = remote_client.get_transport().open_session() - chan.get_pty() - feed = chan.makefile() - chan.exec_command(com) - print feed.read() - - remote_client.close() - client.close() - - def download_reports(self): - dl_folder = self.args[0] - reportfile = self.args[1] - reportname = self.args[2] - resultsname = self.args[3] - client = paramiko.SSHClient() - privatekeyfile = os.path.expanduser('/root/.ssh/id_rsa') - selectedkey = paramiko.RSAKey.from_private_key_file(privatekeyfile) - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - # Connection to overcloud - try: - client.connect(INSTALLER_IP, port=22, username='stack', - pkey=selectedkey) - except paramiko.SSHException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except paramiko.AuthenticationException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except socket.error: - logger.error("Socker Connection failed for " - "undercloud host: {0}".format(self.host)) - - transport = client.get_transport() - local_addr = ('127.0.0.1', 0) # 0 denotes choose random port - channel = transport.open_channel("direct-tcpip", - (self.host, int(self.port)), - (local_addr)) - remote_client = paramiko.SSHClient() - remote_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - # Tunnel to overcloud - try: - remote_client.connect('127.0.0.1', port=22, username=self.user, - key_filename=self.localkey, sock=channel) - except paramiko.SSHException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except paramiko.AuthenticationException: - logger.error("Authentication failed for " - "host: {0}".format(self.host)) - except socket.error: - logger.error("Socker Connection failed for " - "undercloud host: {0}".format(self.host)) - # Download the reports - sftp = remote_client.open_sftp() - logger.info("Downloading \"{0}\"...".format(reportname)) - sftp.get(reportfile, ('{0}/{1}'.format(dl_folder, reportname))) - logger.info("Downloading \"{0}\"...".format(resultsname)) - sftp.get(reportfile, ('{0}/{1}'.format(dl_folder, resultsname))) - sftp.close() - transport.close() diff --git a/functest/opnfv_tests/security_scan/examples/xccdf-rhel7-server-upstream.ini b/functest/opnfv_tests/security_scan/examples/xccdf-rhel7-server-upstream.ini deleted file mode 100644 index 43b2e82d..00000000 --- a/functest/opnfv_tests/security_scan/examples/xccdf-rhel7-server-upstream.ini +++ /dev/null @@ -1,29 +0,0 @@ -[undercloud] -port = 22 -user = stack -remotekey = /home/stack/.ssh/id_rsa -localkey = /root/.ssh/overCloudKey - -[controller] -port = 22 -user = heat-admin -scantype = xccdf -secpolicy = /usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml -cpe = /usr/share/xml/scap/ssg/content/ssg-rhel7-cpe-dictionary.xml -profile = stig-rhel7-server-upstream -report = report.hmtl -results = results.xml -reports_dir=/home/opnfv/functest/results/security_scan/ -clean = True - -[compute] -port = 22 -user = heat-admin -scantype = xccdf -secpolicy = /usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml -cpe = /usr/share/xml/scap/ssg/content/ssg-rhel7-cpe-dictionary.xml -profile = stig-rhel7-server-upstream -report = report.hmtl -results = results.xml -reports_dir=/home/opnfv/functest/results/security_scan/ -clean = True diff --git a/functest/opnfv_tests/security_scan/examples/xccdf-standard.ini b/functest/opnfv_tests/security_scan/examples/xccdf-standard.ini deleted file mode 100644 index bfbcf82d..00000000 --- a/functest/opnfv_tests/security_scan/examples/xccdf-standard.ini +++ /dev/null @@ -1,29 +0,0 @@ -[undercloud] -port = 22 -user = stack -remotekey = /home/stack/.ssh/id_rsa -localkey = /root/.ssh/overCloudKey - -[controller] -port = 22 -user = heat-admin -scantype = xccdf -secpolicy = /usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml -cpe = /usr/share/xml/scap/ssg/content/ssg-rhel7-cpe-dictionary.xml -profile = standard -report = report.hmtl -results = results.xml -reports_dir=/home/opnfv/functest/results/security_scan/ -clean = True - -[compute] -port = 22 -user = heat-admin -scantype = xccdf -secpolicy = /usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml -cpe = /usr/share/xml/scap/ssg/content/ssg-rhel7-cpe-dictionary.xml -profile = standard -report = report.hmtl -results = results.xml -reports_dir=/home/opnfv/functest/results/security_scan/ -clean = True diff --git a/functest/opnfv_tests/security_scan/scripts/createfiles.py b/functest/opnfv_tests/security_scan/scripts/createfiles.py deleted file mode 100644 index b828901a..00000000 --- a/functest/opnfv_tests/security_scan/scripts/createfiles.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2016 Red Hat -# Luke Hinds (lhinds@redhat.com) -# This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# 0.1: This script creates the needed local files into a tmp directory. Should -# '--clean' be passed, all files will be removed, post scan. - - -import os -import tempfile - -files = ['results.xml', 'report.html', 'syschar.xml'] - - -directory_name = tempfile.mkdtemp() - -for i in files: - os.system("touch %s/%s" % (directory_name, i)) - -print directory_name diff --git a/functest/opnfv_tests/security_scan/scripts/internet_check.py b/functest/opnfv_tests/security_scan/scripts/internet_check.py deleted file mode 100644 index d417d174..00000000 --- a/functest/opnfv_tests/security_scan/scripts/internet_check.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2016 Red Hat -# Luke Hinds (lhinds@redhat.com) -# 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 -# -# Performs simple connection check, falls to default timeout of 10 seconds - -import socket - -TEST_HOST = "google.com" - - -def is_connected(): - try: - host = socket.gethostbyname(TEST_HOST) - socket.create_connection((host, 80), 2) - return True - except: - return False - - -print is_connected() diff --git a/functest/opnfv_tests/security_scan/security_scan.py b/functest/opnfv_tests/security_scan/security_scan.py deleted file mode 100755 index f0673924..00000000 --- a/functest/opnfv_tests/security_scan/security_scan.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2016 Red Hat -# Luke Hinds (lhinds@redhat.com) -# This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# 0.1: This script installs OpenSCAP on the remote host, and scans the -# nominated node. Post scan a report is downloaded and if '--clean' is passed -# all trace of the scan is removed from the remote system. - - -import datetime -import os -import sys -from ConfigParser import SafeConfigParser - -import argparse -from keystoneclient import session -from keystoneclient.auth.identity import v2 -from novaclient import client - -import connect -import functest.utils.functest_constants as ft_constants - -__version__ = 0.1 -__author__ = 'Luke Hinds (lhinds@redhat.com)' -__url__ = 'https://wiki.opnfv.org/display/functest/Functest+Security' - -# Global vars -INSTALLER_IP = ft_constants.CI_INSTALLER_IP -oscapbin = 'sudo /bin/oscap' -functest_dir = '%s/security_scan/' % ft_constants.FUNCTEST_TEST_DIR - -# Apex Spefic var needed to query Undercloud -if ft_constants.OS_AUTH_URL is None: - connect.logger.error(" Enviroment variable OS_AUTH_URL is not set") - sys.exit(0) -else: - OS_AUTH_URL = ft_constants.OS_AUTH_URL - -# args -parser = argparse.ArgumentParser(description='OPNFV OpenSCAP Scanner') -parser.add_argument('--config', action='store', dest='cfgfile', - help='Config file', required=True) -args = parser.parse_args() - -# Config Parser -cfgparse = SafeConfigParser() -cfgparse.read(args.cfgfile) - -# Grab Undercloud key -remotekey = cfgparse.get('undercloud', 'remotekey') -localkey = cfgparse.get('undercloud', 'localkey') -setup = connect.SetUp(remotekey, localkey) -setup.getockey() - - -# Configure Nova Credentials -com = 'sudo /usr/bin/hiera admin_password' -setup = connect.SetUp(com) -keypass = setup.keystonepass() -auth = v2.Password(auth_url=OS_AUTH_URL, - username='admin', - password=str(keypass).rstrip(), - tenant_name='admin') -sess = session.Session(auth=auth) -nova = client.Client(2, session=sess) - - -class GlobalVariables: - tmpdir = "" - - -def run_tests(host, nodetype): - user = cfgparse.get(nodetype, 'user') - port = cfgparse.get(nodetype, 'port') - connect.logger.info("Host: {0} Selected Profile: {1}".format(host, - nodetype)) - connect.logger.info("Checking internet for package installation...") - if internet_check(host, nodetype): - connect.logger.info("Internet Connection OK.") - connect.logger.info("Creating temp file structure..") - createfiles(host, port, user, localkey) - connect.logger.debug("Installing OpenSCAP...") - install_pkg(host, port, user, localkey) - connect.logger.debug("Running scan...") - run_scanner(host, port, user, localkey, nodetype) - clean = cfgparse.get(nodetype, 'clean') - connect.logger.info("Post installation tasks....") - post_tasks(host, port, user, localkey, nodetype) - if clean: - connect.logger.info("Cleaning down environment....") - connect.logger.debug("Removing OpenSCAP....") - removepkg(host, port, user, localkey, nodetype) - connect.logger.info("Deleting tmp file and reports (remote)...") - cleandir(host, port, user, localkey, nodetype) - else: - connect.logger.error("Internet timeout. Moving on to next node..") - pass - - -def nova_iterate(): - # Find compute nodes, active with network on ctlplane - for server in nova.servers.list(): - if server.status == 'ACTIVE' and 'compute' in server.name: - networks = server.networks - nodetype = 'compute' - for host in networks['ctlplane']: - run_tests(host, nodetype) - # Find controller nodes, active with network on ctlplane - elif server.status == 'ACTIVE' and 'controller' in server.name: - networks = server.networks - nodetype = 'controller' - for host in networks['ctlplane']: - run_tests(host, nodetype) - - -def internet_check(host, nodetype): - import connect - user = cfgparse.get(nodetype, 'user') - port = cfgparse.get(nodetype, 'port') - localpath = functest_dir + 'scripts/internet_check.py' - remotepath = '/tmp/internet_check.py' - com = 'python /tmp/internet_check.py' - testconnect = connect.ConnectionManager(host, port, user, localkey, - localpath, remotepath, com) - connectionresult = testconnect.remotescript() - if connectionresult.rstrip() == 'True': - return True - else: - return False - - -def createfiles(host, port, user, localkey): - import connect - localpath = functest_dir + 'scripts/createfiles.py' - remotepath = '/tmp/createfiles.py' - com = 'python /tmp/createfiles.py' - connect = connect.ConnectionManager(host, port, user, localkey, - localpath, remotepath, com) - GlobalVariables.tmpdir = connect.remotescript() - - -def install_pkg(host, port, user, localkey): - import connect - com = 'sudo yum -y install openscap-scanner scap-security-guide' - connect = connect.ConnectionManager(host, port, user, localkey, com) - connect.remotecmd() - - -def run_scanner(host, port, user, localkey, nodetype): - import connect - scantype = cfgparse.get(nodetype, 'scantype') - profile = cfgparse.get(nodetype, 'profile') - results = cfgparse.get(nodetype, 'results') - report = cfgparse.get(nodetype, 'report') - secpolicy = cfgparse.get(nodetype, 'secpolicy') - # Here is where we contruct the actual scan command - if scantype == 'xccdf': - cpe = cfgparse.get(nodetype, 'cpe') - com = '{0} xccdf eval --profile {1} --results {2}/{3}' \ - ' --report {2}/{4}' \ - ' --cpe {5} {6}'.format(oscapbin, - profile, - GlobalVariables.tmpdir.rstrip(), - results, - report, - cpe, - secpolicy) - connect = connect.ConnectionManager(host, port, user, localkey, com) - connect.remotecmd() - elif scantype == 'oval': - com = '{0} oval eval --results {1}/{2} ' - '--report {1}/{3} {4}'.format(oscapbin, - GlobalVariables.tmpdir.rstrip(), - results, report, secpolicy) - connect = connect.ConnectionManager(host, port, user, localkey, com) - connect.remotecmd() - else: - com = '{0} oval-collect '.format(oscapbin) - connect = connect.ConnectionManager(host, port, user, localkey, com) - connect.remotecmd() - - -def post_tasks(host, port, user, localkey, nodetype): - import connect - # Create the download folder for functest dashboard and download reports - reports_dir = cfgparse.get(nodetype, 'reports_dir') - dl_folder = os.path.join(reports_dir, host + "_" + - datetime.datetime. - now().strftime('%Y-%m-%d_%H-%M-%S')) - os.makedirs(dl_folder, 0755) - report = cfgparse.get(nodetype, 'report') - results = cfgparse.get(nodetype, 'results') - reportfile = '{0}/{1}'.format(GlobalVariables.tmpdir.rstrip(), report) - connect = connect.ConnectionManager(host, port, user, localkey, dl_folder, - reportfile, report, results) - connect.download_reports() - - -def removepkg(host, port, user, localkey, nodetype): - import connect - com = 'sudo yum -y remove openscap-scanner scap-security-guide' - connect = connect.ConnectionManager(host, port, user, localkey, com) - connect.remotecmd() - - -def cleandir(host, port, user, localkey, nodetype): - import connect - com = 'sudo rm -r {0}'.format(GlobalVariables.tmpdir.rstrip()) - connect = connect.ConnectionManager(host, port, user, localkey, com) - connect.remotecmd() - - -if __name__ == '__main__': - nova_iterate() diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims.py b/functest/opnfv_tests/vnf/ims/cloudify_ims.py index 13a5af4f..e2508c22 100644 --- a/functest/opnfv_tests/vnf/ims/cloudify_ims.py +++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.py @@ -11,7 +11,9 @@ import json import os import requests import subprocess +import sys import time +import yaml import functest.core.vnf_base as vnf_base import functest.utils.functest_logger as ft_logger @@ -29,57 +31,127 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): repo='', cmd=''): super(ImsVnf, self).__init__(project, case, repo, cmd) self.logger = ft_logger.Logger("vIMS").getLogger() - self.case_dir = os.path.join(CONST.functest_test, 'vnf/ims/') - self.data_dir = CONST.dir_vIMS_data + self.case_dir = os.path.join(CONST.dir_functest_test, 'vnf/ims/') + self.data_dir = CONST.dir_ims_data self.test_dir = CONST.dir_repo_vims_test + # Retrieve the configuration + try: + self.config = CONST.__getattribute__( + 'vnf_{}_config'.format(self.case_name)) + except: + raise Exception("VNF config file not found") + + config_file = self.case_dir + self.config self.orchestrator = dict( - requirements=CONST.cloudify_requirements, - blueprint=CONST.cloudify_blueprint, - inputs=CONST.cloudify_inputs + requirements=get_config("cloudify.requirements", config_file), + blueprint=get_config("cloudify.blueprint", config_file), + inputs=get_config("cloudify.inputs", config_file) ) - + self.logger.debug("Orchestrator configuration: %s" % self.orchestrator) self.vnf = dict( - blueprint=CONST.clearwater_blueprint, - deployment_name=CONST.clearwater_deployment_name, - inputs=CONST.clearwater_inputs, - requirements=CONST.clearwater_requirements + blueprint=get_config("clearwater.blueprint", config_file), + deployment_name=get_config("clearwater.deployment_name", + config_file), + inputs=get_config("clearwater.inputs", config_file), + requirements=get_config("clearwater.requirements", config_file) ) + self.logger.debug("VNF configuration: %s" % self.vnf) + + self.images = get_config("tenant_images", config_file) + self.logger.info("Images needed for vIMS: %s" % self.images) # vIMS Data directory creation if not os.path.exists(self.data_dir): os.makedirs(self.data_dir) def deploy_orchestrator(self, **kwargs): + + self.logger.info("Additional pre-configuration steps") + self.neutron_client = os_utils.get_neutron_client(self.creds) + self.glance_client = os_utils.get_glance_client(self.creds) + self.keystone_client = os_utils.get_keystone_client(self.creds) + self.nova_client = os_utils.get_nova_client(self.creds) + + # 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(): + self.logger.info("image: %s, url: %s" % (image_name, image_url)) + try: + image_id = os_utils.get_image_id(self.glance_client, + image_name) + self.logger.debug("image_id: %s" % image_id) + except: + self.logger.error("Unexpected error: %s" % sys.exc_info()[0]) + + if image_id == '': + self.logger.info("""%s image doesn't exist on glance repository. Try + downloading this image and upload on glance !""" % image_name) + image_id = download_and_add_image_on_glance(self.glance_client, + image_name, + image_url, + temp_dir) + if image_id == '': + self.step_failure( + "Failed to find or upload required OS " + "image for this deployment") + # Need to extend quota + self.logger.info("Update security group quota for this tenant") + tenant_id = os_utils.get_tenant_id(self.keystone_client, + self.tenant_name) + self.logger.debug("Tenant id found %s" % tenant_id) + if not os_utils.update_sg_quota(self.neutron_client, + tenant_id, 50, 100): + self.step_failure("Failed to update security group quota" + + " for tenant " + self.tenant_name) + self.logger.debug("group quota extended") + + # start the deployment of cloudify public_auth_url = os_utils.get_endpoint('identity') - cfy = Orchestrator(self.data_dir, self.orchestrator.inputs) - self.orchestrator.object = cfy + self.logger.debug("CFY inputs: %s" % self.orchestrator['inputs']) + cfy = Orchestrator(self.data_dir, self.orchestrator['inputs']) + self.orchestrator['object'] = cfy + self.logger.debug("Orchestrator object created") - if 'tenant_name' in self.creds.keys(): - tenant_name = self.creds['tenant_name'] - elif 'project_name' in self.creds.keys(): - tenant_name = self.creds['project_name'] + self.logger.debug("Tenant name: %s" % self.tenant_name) - cfy.set_credentials(username=self.creds['username'], - password=self.creds['password'], - tenant_name=tenant_name, + cfy.set_credentials(username=self.tenant_name, + password=self.tenant_name, + tenant_name=self.tenant_name, auth_url=public_auth_url) + self.logger.info("Credentials set in CFY") # orchestrator VM flavor - flavor_id = self.get_flavor("m1.large", self.orchestrator.requirements) + self.logger.info("Check Flavor is available, if not create one") + self.logger.debug("Flavor details %s " % + self.orchestrator['requirements']['ram_min']) + flavor_exist, flavor_id = os_utils.get_or_create_flavor( + "m1.large", + self.orchestrator['requirements']['ram_min'], + '1', + '1', + public=True) + self.logger.debug("Flavor id: %s" % flavor_id) + if not flavor_id: self.logger.info("Available flavors are: ") - self.pMsg(self.nova_client.flavor.list()) + self.logger.info(self.nova_client.flavor.list()) self.step_failure("Failed to find required flavor" "for this deployment") cfy.set_flavor_id(flavor_id) + self.logger.debug("Flavor OK") # orchestrator VM image - if 'os_image' in self.orchestrator.requirements.keys(): + self.logger.debug("Orchestrator image") + if 'os_image' in self.orchestrator['requirements'].keys(): image_id = os_utils.get_image_id( - self.glance_client, self.orchestrator.requirements['os_image']) + self.glance_client, + self.orchestrator['requirements']['os_image']) + self.logger.debug("Orchestrator image id: %s" % image_id) if image_id == '': + self.logger.error("CFY image not found") self.step_failure("Failed to find required OS image" " for cloudify manager") else: @@ -87,16 +159,22 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): " for cloudify manager") cfy.set_image_id(image_id) + self.logger.debug("Orchestrator image set") + self.logger.debug("Get External network") ext_net = os_utils.get_external_net(self.neutron_client) + self.logger.debug("External network: %s" % ext_net) if not ext_net: self.step_failure("Failed to get external network") cfy.set_external_network_name(ext_net) + self.logger.debug("CFY External network set") + self.logger.debug("get resolvconf") ns = ft_utils.get_resolvconf_ns() if ns: cfy.set_nameservers(ns) + self.logger.debug("Resolvconf set") if 'compute' in self.nova_client.client.services_url: cfy.set_nova_url(self.nova_client.client.services_url['compute']) @@ -110,8 +188,9 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): cmd = self.case_dir + "create_venv.sh " + self.data_dir ft_utils.execute_command(cmd) - cfy.download_manager_blueprint(self.orchestrator.blueprint['url'], - self.orchestrator.blueprint['branch']) + cfy.download_manager_blueprint( + self.orchestrator['blueprint']['url'], + self.orchestrator['blueprint']['branch']) cfy.deploy_manager() return {'status': 'PASS', 'result': ''} @@ -121,10 +200,16 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): self.vnf.object = cw self.logger.info("Collect flavor id for all clearwater vm") - flavor_id = self.get_flavor("m1.small", self.vnf.requirements) + flavor_exist, flavor_id = os_utils.get_or_create_flavor( + "m1.small", + self.vnf['requirements']['ram_min'], + '1', + '1', + public=True) + self.logger.debug("Flavor id: %s" % flavor_id) if not flavor_id: self.logger.info("Available flavors are: ") - self.pMsg(self.nova_client.flavor.list()) + self.logger.info(self.nova_client.flavor.list()) self.step_failure("Failed to find required flavor" " for this deployment") @@ -133,7 +218,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): # VMs image if 'os_image' in self.vnf.requirements.keys(): image_id = os_utils.get_image_id( - self.glance_client, self.vnf.requirements['os_image']) + self.glance_client, self.vnf['requirements']['os_image']) if image_id == '': self.step_failure("Failed to find required OS image" " for clearwater VMs") @@ -256,23 +341,54 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): self.orchestrator.object.undeploy_manager() super(ImsVnf, self).clean() - def get_flavor(self, flavor_name, requirements): - try: - flavor_id = os_utils.get_flavor_id(self.nova_client, flavor_name) - if 'ram_min' in requirements.keys(): - flavor_id = os_utils.get_flavor_id_by_ram_range( - self.nova_client, requirements['ram_min'], 7500) - - if flavor_id == '': - self.logger.error( - "Failed to find %s flavor. " - "Try with ram range default requirement !" % flavor_name) - flavor_id = os_utils.get_flavor_id_by_ram_range( - self.nova_client, - 4000, 10000) - return flavor_id - except: - self.logger.error("Flavor '%s' not found." % self.flavor_name) - self.logger.info("Available flavors are: ") - self.pMsg(self.nova_client.flavor.list()) - return None + def main(self, **kwargs): + self.logger.info("Cloudify IMS VNF onboarding test starting") + self.execute() + self.logger.info("Cloudify IMS VNF onboarding test executed") + if self.criteria is "PASS": + return self.EX_OK + else: + return self.EX_RUN_ERROR + + def run(self): + kwargs = {} + return self.main(**kwargs) + + +# ---------------------------------------------------------- +# +# YAML 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/cloudify_ims.yaml b/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml new file mode 100644 index 00000000..c5918087 --- /dev/null +++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml @@ -0,0 +1,39 @@ +tenant_images: + ubuntu_14.04: http://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img + centos_7: http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1510.qcow2 +cloudify: + blueprint: + url: https://github.com/boucherv-orange/cloudify-manager-blueprints.git + branch: '3.3.1-build' + requirements: + ram_min: 3000 + os_image: centos_7 + inputs: + keystone_username: "" + keystone_password: "" + keystone_tenant_name: "" + keystone_url: "" + manager_public_key_name: 'manager-kp' + agent_public_key_name: 'agent-kp' + image_id: "" + flavor_id: "3" + external_network_name: "" + ssh_user: centos + agents_user: ubuntu +clearwater: + blueprint: + file_name: openstack-blueprint.yaml + name: clearwater-opnfv + destination_folder: opnfv-cloudify-clearwater + url: https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater.git + branch: stable + deployment_name: clearwater-opnfv + requirements: + ram_min: 1700 + os_image: ubuntu_14.04 + inputs: + image_id: '' + flavor_id: '' + agent_user: ubuntu + external_network_name: '' + public_domain: clearwaterfv diff --git a/functest/tests/unit/core/test_testcase_base.py b/functest/tests/unit/core/test_testcase_base.py index 94d2e966..b7c81d87 100755..100644 --- a/functest/tests/unit/core/test_testcase_base.py +++ b/functest/tests/unit/core/test_testcase_base.py @@ -9,7 +9,6 @@ import logging import mock -import os import unittest from functest.core import testcase_base @@ -32,12 +31,11 @@ class TestcaseBaseTesting(unittest.TestCase): self.assertEqual(self.test.run(), testcase_base.TestcaseBase.EX_RUN_ERROR) - @mock.patch.dict(os.environ, {}) @mock.patch('functest.utils.functest_utils.push_results_to_db', return_value=False) def _test_missing_attribute(self, mock_function): - self.assertEqual(self.test.publish_report(), - testcase_base.TestcaseBase.EX_PUBLISH_RESULT_FAILED) + self.assertEqual(self.test.push_to_db(), + testcase_base.TestcaseBase.EX_PUSH_TO_DB_ERROR) mock_function.assert_not_called() def test_missing_case_name(self): @@ -70,7 +68,7 @@ class TestcaseBaseTesting(unittest.TestCase): return_value=False) def test_push_to_db_failed(self, mock_function): self.assertEqual(self.test.push_to_db(), - testcase_base.TestcaseBase.EX_PUBLISH_RESULT_FAILED) + testcase_base.TestcaseBase.EX_PUSH_TO_DB_ERROR) mock_function.assert_called_once_with( self.test.project, self.test.case_name, self.test.start_time, self.test.stop_time, self.test.criteria, self.test.details) diff --git a/functest/tests/unit/utils/test_openstack_utils.py b/functest/tests/unit/utils/test_openstack_utils.py index 0f510414..447271fc 100644 --- a/functest/tests/unit/utils/test_openstack_utils.py +++ b/functest/tests/unit/utils/test_openstack_utils.py @@ -7,6 +7,7 @@ import copy import logging +import os import unittest import mock @@ -353,18 +354,34 @@ class OSUtilsTesting(unittest.TestCase): def test_get_credentials_missing_endpoint_type(self): self._get_credentials_missing_env('OS_ENDPOINT_TYPE') + def _test_source_credentials(self, msg, key='OS_TENANT_NAME', + value='admin'): + try: + del os.environ[key] + except: + pass + f = 'rc_file' + with mock.patch('__builtin__.open', mock.mock_open(read_data=msg), + create=True) as m: + m.return_value.__iter__ = lambda self: iter(self.readline, '') + openstack_utils.source_credentials(f) + m.assert_called_once_with(f, 'r') + self.assertEqual(os.environ[key], value) + def test_source_credentials(self): - with mock.patch('functest.utils.openstack_utils.subprocess.Popen') \ - as mock_subproc_popen, \ - mock.patch('functest.utils.openstack_utils.os.environ'): - process_mock = mock.Mock() - attrs = {'communicate.return_value': ('OS_USER_NAME=test_name', - 'success')} - process_mock.configure_mock(**attrs) - mock_subproc_popen.return_value = process_mock - - self.assertDictEqual(openstack_utils.source_credentials('rc_file'), - {'OS_USER_NAME': 'test_name'}) + self._test_source_credentials('OS_TENANT_NAME=admin') + self._test_source_credentials('OS_TENANT_NAME= admin') + self._test_source_credentials('OS_TENANT_NAME = admin') + self._test_source_credentials('OS_TENANT_NAME = "admin"') + self._test_source_credentials('export OS_TENANT_NAME=admin') + self._test_source_credentials('export OS_TENANT_NAME =admin') + self._test_source_credentials('export OS_TENANT_NAME = admin') + self._test_source_credentials('export OS_TENANT_NAME = "admin"') + self._test_source_credentials('OS_TENANT_NAME', value='') + self._test_source_credentials('export OS_TENANT_NAME', value='') + # This test will fail as soon as rc_file is fixed + self._test_source_credentials( + 'export "\'OS_TENANT_NAME\'" = "\'admin\'"') @mock.patch('functest.utils.openstack_utils.os.getenv', return_value=None) diff --git a/functest/utils/decorators.py b/functest/utils/decorators.py new file mode 100644 index 00000000..99bcef3e --- /dev/null +++ b/functest/utils/decorators.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +import mock +import requests.sessions +import urlparse + + +def can_dump_request_to_file(method): + + def dump_preparedrequest(request, **kwargs): + parseresult = urlparse.urlparse(request.url) + if parseresult.scheme == "file": + with open(parseresult.path.replace('/results', ''), 'a') as f: + headers = "" + for key in request.headers: + headers += key + " " + request.headers[key] + "\n" + message = "{} {}\n{}\n{}\n\n\n".format( + request.method, request.url, headers, request.body) + f.write(message) + return mock.Mock() + + def patch_request(method, url, **kwargs): + with requests.sessions.Session() as session: + parseresult = urlparse.urlparse(url) + if parseresult.scheme == "file": + with mock.patch.object( + session, 'send', side_effect=dump_preparedrequest): + return session.request(method=method, url=url, **kwargs) + else: + return session.request(method=method, url=url, **kwargs) + + def hook(*args, **kwargs): + with mock.patch('requests.api.request', side_effect=patch_request): + return method(*args, **kwargs) + + return hook diff --git a/functest/utils/functest_logger.py b/functest/utils/functest_logger.py index f09f56be..0cba8c52 100755 --- a/functest/utils/functest_logger.py +++ b/functest/utils/functest_logger.py @@ -28,42 +28,36 @@ import json from functest.utils.constants import CONST -logger = logging.getLogger(__name__) - - -def is_debug(): - if CONST.CI_DEBUG and CONST.CI_DEBUG.lower() == "true": - return True - return False - - -def setup_logging(default_path=CONST.dir_functest_logging_cfg, - default_level=logging.INFO, - env_key='LOG_CFG'): - path = default_path - value = os.getenv(env_key, None) - if value: - path = value - if os.path.exists(path): - with open(path, 'rt') as f: - config = json.load(f) - if (config['handlers'] and - config['handlers']['console']): - stream_level = logging.INFO - if is_debug(): - stream_level = logging.DEBUG - config['handlers']['console']['level'] = stream_level - logging.config.dictConfig(config) - else: - logging.basicConfig(level=default_level) - - -setup_logging() - class Logger: def __init__(self, logger_name): + self.setup_logging() self.logger = logging.getLogger(logger_name) def getLogger(self): return self.logger + + def is_debug(self): + if CONST.CI_DEBUG and CONST.CI_DEBUG.lower() == "true": + return True + return False + + def setup_logging(self, default_path=CONST.dir_functest_logging_cfg, + default_level=logging.INFO, + env_key='LOG_CFG'): + path = default_path + value = os.getenv(env_key, None) + if value: + path = value + if os.path.exists(path): + with open(path, 'rt') as f: + config = json.load(f) + if (config['handlers'] and + config['handlers']['console']): + stream_level = logging.INFO + if self.is_debug(): + stream_level = logging.DEBUG + config['handlers']['console']['level'] = stream_level + logging.config.dictConfig(config) + else: + logging.basicConfig(level=default_level) diff --git a/functest/utils/functest_utils.py b/functest/utils/functest_utils.py index 04055464..12d8e902 100644 --- a/functest/utils/functest_utils.py +++ b/functest/utils/functest_utils.py @@ -23,10 +23,9 @@ import requests import yaml from git import Repo -from functest.utils.constants import CONST +from functest.utils import decorators import functest.utils.functest_logger as ft_logger - logger = ft_logger.Logger("functest_utils").getLogger() @@ -184,43 +183,14 @@ def logger_test_results(project, case_name, status, details): 'd': details}) -def write_results_to_file(project, case_name, start_date, - stop_date, criteria, details): - file_path = re.split(r'://', CONST.results_test_db_url)[1] - - try: - installer = os.environ['INSTALLER_TYPE'] - scenario = os.environ['DEPLOY_SCENARIO'] - pod_name = os.environ['NODE_NAME'] - except KeyError as e: - logger.error("Please set env var: " + str(e)) - return False - - test_start = dt.fromtimestamp(start_date).strftime('%Y-%m-%d %H:%M:%S') - test_stop = dt.fromtimestamp(stop_date).strftime('%Y-%m-%d %H:%M:%S') - - params = {"project_name": project, "case_name": case_name, - "pod_name": pod_name, "installer": installer, - "scenario": scenario, "criteria": criteria, - "start_date": test_start, "stop_date": test_stop, - "details": details} - try: - with open(file_path, "a+w") as outfile: - json.dump(params, outfile) - outfile.write("\n") - return True - except Exception as e: - logger.error("write result data into a file failed: %s" % e) - return False - - +@decorators.can_dump_request_to_file def push_results_to_db(project, case_name, start_date, stop_date, criteria, details): """ POST results to the Result target DB """ # Retrieve params from CI and conf - url = CONST.results_test_db_url + "/results" + url = get_db_url() + "/results" try: installer = os.environ['INSTALLER_TYPE'] diff --git a/functest/utils/openstack_utils.py b/functest/utils/openstack_utils.py index 64f18504..3093cb55 100755 --- a/functest/utils/openstack_utils.py +++ b/functest/utils/openstack_utils.py @@ -10,7 +10,7 @@ import os import os.path -import subprocess +import re import sys import time @@ -112,12 +112,15 @@ def get_credentials(other_creds={}): def source_credentials(rc_file): - pipe = subprocess.Popen(". %s; env" % rc_file, stdout=subprocess.PIPE, - shell=True) - output = pipe.communicate()[0] - env = dict((line.split("=", 1) for line in output.splitlines())) - os.environ.update(env) - return env + with open(rc_file, "r") as f: + for line in f: + var = line.rstrip('"\n').replace('export ', '').split("=") + # The two next lines should be modified as soon as rc_file + # conforms with common rules. Be aware that it could induce + # issues if value starts with ' + key = re.sub(r'^["\' ]*|[ \'"]*$', '', var[0]) + value = re.sub(r'^["\' ]*|[ \'"]*$', '', "".join(var[1:])) + os.environ[key] = value def get_credentials_for_rally(): |