diff options
34 files changed, 486 insertions, 426 deletions
diff --git a/docs/com/pres/Summit/Berlin-2016/summit-Berlin.html b/docs/com/pres/Summit/Berlin-2016/summit-Berlin.html index 4173a86ac..8369443f7 100755 --- a/docs/com/pres/Summit/Berlin-2016/summit-Berlin.html +++ b/docs/com/pres/Summit/Berlin-2016/summit-Berlin.html @@ -230,7 +230,7 @@ ## What's new? * Slicing of the tests (healthcheck / Smoke / SDN controllers / Features / Components / VNFs) * Better Test duration management - * Refactoring (repo, case management, test API) + * Refactoring (repo, case management, TestAPI) * Automatic reporting * Dashboard evolution to ELK * CLI diff --git a/docs/com/pres/Summit/Berlin-2016/testapi.html b/docs/com/pres/Summit/Berlin-2016/testapi.html index 7035d71df..16f97c44d 100755 --- a/docs/com/pres/Summit/Berlin-2016/testapi.html +++ b/docs/com/pres/Summit/Berlin-2016/testapi.html @@ -6,7 +6,7 @@ <title>OPNFV presentation</title> - <meta name="description" content="Test API"> + <meta name="description" content="TestAPI"> <meta name="author" content="Serena Feng"> <meta name="apple-mobile-web-app-capable" content="yes" /> @@ -42,7 +42,7 @@ <section data-background="../../../img/title-bg-berlin.png" data-background-transition="none"> <br><br><br><br><br> - <h1>Test API</h1> + <h1>TestAPI</h1> <h3>Clean, Easy, Complete</h3> <br> <h4>OPNFV testing community</h4> @@ -52,7 +52,7 @@ <section data-markdown> # Agenda - * testAPI: what for? + * TestAPI: what for? * API overview * API evolution * Roadmap @@ -60,7 +60,7 @@ <section> <section data-markdown> - # test API: what for? + # TestAPI: what for? </section> <section data-markdown> ## Consistant view for @@ -78,12 +78,12 @@ </section> <section data-markdown> <script type='text/template'> - ## Achieve using testAPI - * Uniform API: testAPI + ## Achieve using TestAPI + * Uniform API: TestAPI * Uniform format: JSON * Universal Location: http://testresults.opnfv.org <aside class='notes'> - By using testAPI, we hope to provide a uniform way of collection and saving test results to a universal location + By using TestAPI, we hope to provide a uniform way of collection and saving test results to a universal location </aside> </script> </section> @@ -101,11 +101,11 @@ </section> <section data-markdown> ## Storage structure - ![testapi](https://wiki.opnfv.org/download/attachments/2926452/results_collection_structure.png?version=1&modificationDate=1459196347000&api=v2 "OPNFV API page") + ![TestAPI](https://wiki.opnfv.org/download/attachments/2926452/results_collection_structure.png?version=1&modificationDate=1459196347000&api=v2 "OPNFV API page") </section> <section data-markdown> ## API in Brahmaputra - ![testapi](../../../img/testapi0.png) + ![TestAPI](../../../img/testapi0.png) https://wiki.opnfv.org/display/functest/Collection+Of+Test+Results </section> @@ -137,7 +137,7 @@ <aside class='notes'> So you can discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection, - and also you can interact with the testAPI directly through swagger website. + and also you can interact with the TestAPI directly through swagger website. </aside> </ul> <p class="fragment fade-up"><b>All done in Colorado!</b></p> @@ -152,7 +152,7 @@ <section> <h2> URI changes...</h2> <div style="text-align:left""> - <p> testresults.opnfv.org/<span style="color:lightblue">testapi</span> => <br>testresults.opnfv.org/<span style="color:yellow">test/api/v1</span> </p> + <p> testresults.opnfv.org/<span style="color:lightblue">TestAPI</span> => <br>testresults.opnfv.org/<span style="color:yellow">test/api/v1</span> </p> <p> /test/api/v1/<b>pods</b></p> <p> /test/api/v1/<b>projects</b></p> @@ -195,7 +195,7 @@ </section> <section data-markdown> http://testresults.opnfv.org/test/swagger/spec.html - ![alt text](../../../img/testapi1.png "Test API swagger interface") + ![alt text](../../../img/testapi1.png "TestAPI swagger interface") </section> <section> <h2>unit tests</h2> @@ -223,8 +223,8 @@ OK </section> <section data-markdown> ## Roadmap - * Dockerize testAPI - * Automatic update of testAPI + * Dockerize TestAPI + * Automatic update of TestAPI * Command Line Interface * Automatic update for pods/projects/testcases </section> diff --git a/docs/release-notes/functest-release.rst b/docs/release/release-notes/functest-release.rst index 07389bb5b..ce03047f6 100644 --- a/docs/release-notes/functest-release.rst +++ b/docs/release/release-notes/functest-release.rst @@ -32,7 +32,7 @@ Version history +------------+----------+------------------+------------------------+ OPNFV Colorado Release -========================= +====================== Functest deals with functional testing of the OPNFV solution. It includes test cases developed within the project and test cases developed in @@ -99,7 +99,7 @@ Software - The Functest Docker image: https://hub.docker.com/r/opnfv/functest (tag: colorado.1.0) - - The testapi Docker image: https://hub.docker.com/r/opnfv/testapi (tag:colorado.1.0) + - The TestAPI Docker image: https://hub.docker.com/r/opnfv/testapi (tag:colorado.1.0) Documents @@ -120,7 +120,7 @@ Feature evolution - refactoring of ODL functional tests (with upstream modifications) - - refactoring of testapi (update, swagger documentation, dockerization) + - refactoring of TestAPI (update, swagger documentation, dockerization) - jenkins logs improvement diff --git a/docs/release-notes/index.rst b/docs/release/release-notes/index.rst index 6c6d18109..6c6d18109 100644 --- a/docs/release-notes/index.rst +++ b/docs/release/release-notes/index.rst diff --git a/docs/devguide/index.rst b/docs/testing/developer/devguide/index.rst index eee013678..11ca241b2 100644 --- a/docs/devguide/index.rst +++ b/docs/testing/developer/devguide/index.rst @@ -14,7 +14,7 @@ Introduction Functest is a project dealing with functional testing. Functest produces its own internal test cases but can also be considered as a framework to support feature and VNF onboarding project testing. -Functest developed a test API and defined a test collection framework +Functest developed a TestAPI and defined a test collection framework that can be used by any OPNFV project. Therefore there are many ways to contribute to Functest. You can: @@ -260,9 +260,9 @@ The Test result management can be summarized as follows:: | | +----------------------+ -Test API description --------------------- -The Test API is used to declare pods, projects, test cases and test +TestAPI description +------------------- +The TestAPI is used to declare pods, projects, test cases and test results. Pods are the pods used to run the tests. The results pushed in the database are related to pods, projects and cases. If you try to push results of test done on non referenced pod, @@ -500,21 +500,21 @@ Scenarios: The code of the API is hosted in the releng repository `[6]`_. The static documentation of the API can be found at `[17]`_. -The test API has been dockerized and may be installed locally in your +The TestAPI has been dockerized and may be installed locally in your lab. See `[15]`_ for details. -The deployment of the test API has been automated. +The deployment of the TestAPI has been automated. A jenkins job manages: - * the unit tests of the test api + * the unit tests of the TestAPI * the creation of a new docker file - * the deployment of the new test api - * the archive of the old test api + * the deployment of the new TestAPI + * the archive of the old TestAPI * the backup of the Mongo DB -Test API Authorization -~~~~~~~~~~~~~~~~~~~~~~ +TestAPI Authorization +~~~~~~~~~~~~~~~~~~~~~ -PUT/DELETE/POST operations of the testapi now require token based authorization. The token needs +PUT/DELETE/POST operations of the TestAPI now require token based authorization. The token needs to be added in the request using a header 'X-Auth-Token' for access to the database. e.g:: @@ -627,7 +627,7 @@ script can be found in `[16]`_. For next versions, it was decided to integrated bitergia dashboard. Bitergia already provides a dashboard for code and infrastructure. A new Test tab will be added. The dataset will be built by consuming -the test API. +the TestAPI. ======= diff --git a/docs/internship/security_group/index.rst b/docs/testing/developer/internship/security_group/index.rst index d1cdbdd8f..d1cdbdd8f 100644 --- a/docs/internship/security_group/index.rst +++ b/docs/testing/developer/internship/security_group/index.rst diff --git a/docs/internship/testapi_evolution/index.rst b/docs/testing/developer/internship/testapi_evolution/index.rst index 9cca9ebce..3038d0ac6 100644 --- a/docs/internship/testapi_evolution/index.rst +++ b/docs/testing/developer/internship/testapi_evolution/index.rst @@ -7,9 +7,9 @@ International License. You should have received a copy of the license along with this. If not, see <http://creativecommons.org/licenses/by/4.0/>. -================== -Test API evolution -================== +================= +TestAPI evolution +================= Author: Sakala Venkata Krishna Rohit Mentors: S. Feng, J.Lausuch, M.Richomme @@ -17,10 +17,10 @@ Mentors: S. Feng, J.Lausuch, M.Richomme Abstract ======== -The testapi is used by all the test opnfv projects to report results. +The TestAPI is used by all the test opnfv projects to report results. It is also used to declare projects, test cases and labs. A major refactoring -has been done in Colorado with the introduction of swagger. The testapi is defined in Functest -developer guide. The purpose of this project is to add more features to the testapi that automate +has been done in Colorado with the introduction of swagger. The TestAPI is defined in Functest +developer guide. The purpose of this project is to add more features to the TestAPI that automate the tasks that are done manually now, though there are tasks other than automation. Version history @@ -48,33 +48,33 @@ documentation is as follows. Problem Statement: ------------------ -The problem statement could be divided into pending features that needed to be added into testapi +The problem statement could be divided into pending features that needed to be added into TestAPI repo. The following were to be accomplished within the internship time frame. -* **Add verification jenkins job for the testapi code** +* **Add verification jenkins job for the TestAPI code** The purpose of this job is to verify whehter the unit tests are successful or not with the inclusion of the patchset submitted. * **Automatic update of opnfv/testapi docker image** - The docker image of testapi is hosted in the opnfv docker hub. To ensure that the testapi image + The docker image of TestAPI is hosted in the opnfv docker hub. To ensure that the TestAPI image is always updated with the repository, automatic updation of the image is necessary and a job is triggered whenever a new patch gets merged. * **Automation deployment of testresults.opnfv.org/test/ website** - In the same manner as the docker image of testapi is updated, the testapi website needs to be + In the same manner as the docker image of TestAPI is updated, the TestAPI website needs to be in sync with the repository code. So, a job has been added to the opnfv jenkins ci for the updation of the testresults website. -* **Generate static documentation of testapi calls** - The purpose of this is to give an static/offline view of testapi. If someone wants to have a - look at the Restful apis of testapi, he/she does't need to go to the website, he can download +* **Generate static documentation of TestAPI calls** + The purpose of this is to give an static/offline view of TestAPI. If someone wants to have a + look at the Restful APIs of TestAPI, he/she does't need to go to the website, he can download a html page and view it anytime. -* **Backup MongoDB of testapi** +* **Backup MongoDB of TestAPI** The mongoDB needs to be backed up every week. Till now it was done manually, but due to this internship, it is now automated using a jenkins job. -* **Add token based authorization to the testapi calls** +* **Add token based authorization to the TestAPI calls** The token based authorization was implemented to ensure that only ci_pods could access the database. Authentication has been added to only delete/put/post requests. @@ -82,7 +82,7 @@ Curation Phase: --------------- The curation phase was the first 3 to 4 weeks of the internship. This phase was to get familiar -with the testapi code and functionality and propose the solutions/tools for the tasks mentioned +with the TestAPI code and functionality and propose the solutions/tools for the tasks mentioned above. Swagger codegen was choosen out of the four tools proposed `[3]`_ for generating static documentaion. @@ -107,7 +107,7 @@ The progress and completion of the tasks is described in the below table. | **Date** | **Comment** | | | | +--------------------------+------------------------------------------+ -| Nov 14th - Dec 31st | Understand Testapi code and the | +| Nov 14th - Dec 31st | Understand TestAPI code and the | | | requirements. | +--------------------------+------------------------------------------+ | Jan 1st - Jan 7th | Add jenkins job to create static | @@ -134,8 +134,8 @@ the internship. This section may help other developers in solving any errors cas code written as a part of this internship. -Test Api --------- +TestAPI +------- What is the difference between defining data_file as "/etc/.." and "etc/.." in setup.cfg ? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -216,7 +216,7 @@ defined. What job style should be used when there is a situation like one build should trigger other builds ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ or when different build scripts need to be run on different machines ? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MultiJob style should be used as it has phases where each phase can be taken as a build scipt and can have its own parameters by which one can define the SLAVE_LABEL parameter. @@ -234,4 +234,4 @@ _`[4]` : http://artifacts.opnfv.org/testapibackup.html _`[5]` : http://artifacts.opnfv.org/releng/docs/testapi.html -_`[6]` : http://artifacts.opnfv.org/functest/review/26047/devguide/index.html#test-api-authorization +_`[6]` : http://artifacts.opnfv.org/functest/docs/devguide/index.html#test-api-authorization diff --git a/docs/internship/unit_tests/index.rst b/docs/testing/developer/internship/unit_tests/index.rst index f969aa72d..f969aa72d 100644 --- a/docs/internship/unit_tests/index.rst +++ b/docs/testing/developer/internship/unit_tests/index.rst diff --git a/docs/internship/vnf_catalog/index.rst b/docs/testing/developer/internship/vnf_catalog/index.rst index df7633391..df7633391 100644 --- a/docs/internship/vnf_catalog/index.rst +++ b/docs/testing/developer/internship/vnf_catalog/index.rst diff --git a/docs/configguide/configguide.rst b/docs/testing/user/configguide/configguide.rst index 08e089c2b..08e089c2b 100644 --- a/docs/configguide/configguide.rst +++ b/docs/testing/user/configguide/configguide.rst diff --git a/docs/configguide/index.rst b/docs/testing/user/configguide/index.rst index f12739e31..f12739e31 100644 --- a/docs/configguide/index.rst +++ b/docs/testing/user/configguide/index.rst diff --git a/docs/userguide/index.rst b/docs/testing/user/userguide/index.rst index 9436de2b9..9436de2b9 100644 --- a/docs/userguide/index.rst +++ b/docs/testing/user/userguide/index.rst diff --git a/docs/userguide/introduction.rst b/docs/testing/user/userguide/introduction.rst index 4dfe79375..4dfe79375 100644 --- a/docs/userguide/introduction.rst +++ b/docs/testing/user/userguide/introduction.rst diff --git a/docs/userguide/runfunctest.rst b/docs/testing/user/userguide/runfunctest.rst index b5c7191ca..e7ab84b26 100644 --- a/docs/userguide/runfunctest.rst +++ b/docs/testing/user/userguide/runfunctest.rst @@ -174,7 +174,7 @@ To execute a Test Tier or Test Case, the 'run' command is used:: 2016-06-30 11:50:31,865 - run_tests - INFO - ============================================ 2016-06-30 11:50:31,865 - run_tests - INFO - Running test case 'vping_ssh'... 2016-06-30 11:50:31,865 - run_tests - INFO - ============================================ - 2016-06-30 11:50:32,977 - vping_ssh - INFO - Creating image 'functest-vping' from '/home/opnfv/functest/data/cirros-0.3.4-x86_64-disk.img'... + 2016-06-30 11:50:32,977 - vping_ssh - INFO - Creating image 'functest-vping' from '/home/opnfv/functest/data/cirros-0.3.5-x86_64-disk.img'... 2016-06-30 11:50:45,470 - vping_ssh - INFO - Creating neutron network vping-net... 2016-06-30 11:50:47,645 - vping_ssh - INFO - Creating security group 'vPing-sg'... 2016-06-30 11:50:48,843 - vping_ssh - INFO - Using existing Flavor 'm1.small'... diff --git a/docs/userguide/troubleshooting.rst b/docs/testing/user/userguide/troubleshooting.rst index 1b7bf9b38..845501916 100644 --- a/docs/userguide/troubleshooting.rst +++ b/docs/testing/user/userguide/troubleshooting.rst @@ -100,7 +100,7 @@ In this case, proceed to create it manually. These are some hints:: --protocol tcp --port-range-min 80 --port-range-max 80 --remote-ip-prefix 0.0.0.0/0 The next step is to create the instances. The image used is located in -*/home/opnfv/functest/data/cirros-0.3.4-x86_64-disk.img* and a Glance image is created +*/home/opnfv/functest/data/cirros-0.3.5-x86_64-disk.img* and a Glance image is created with the name **functest-vping**. If booting the instances fails (i.e. the status is not **ACTIVE**), you can check why it failed by doing:: diff --git a/functest/ci/config_functest.yaml b/functest/ci/config_functest.yaml index 489c395ff..402e29999 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 46064a07f..d984a3f47 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 aa0cfaf7e..6f776101d 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 f5bae6a04..724ea14df 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 f8bbe9b74..722e8796d 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 909f45d21..ed5e61fe0 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 826ca9dae..116b5bb6c 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 0a4256ce6..fcdfe225b 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 000000000..ac4e37289 --- /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 37b5c0ee7..4c96500db 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 000000000..e69de29bb --- /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 000000000..8bc738325 --- /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 2537e18de..000000000 --- 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 447271fc6..ef3764cc5 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 84166c1d3..b5b845010 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 0a9a03b18..9fae9a9c0 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 3093cb558..e33af63b4 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 diff --git a/requirements.txt b/requirements.txt index 68b889b35..ee629eab8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ pyyaml==3.10 gitpython==1.0.1 python-openstackclient==2.3.0 python-ceilometerclient==2.6.2 +python-heatclient==1.7.0 python-keystoneclient==3.5.0 python-neutronclient==6.0.0 python-novaclient==6.0.0 diff --git a/test-requirements.txt b/test-requirements.txt index 16466b8a3..471e9c30a 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -14,6 +14,7 @@ mock==1.3.0 nose==1.3.7 python-ceilometerclient==2.6.2 python-congressclient==1.5.0 +python-heatclient==1.7.0 python-keystoneclient==3.5.0 python-neutronclient==6.0.0 python-openstackclient==2.3.0 |