diff options
126 files changed, 3052 insertions, 463 deletions
diff --git a/ansible/roles/convert_openrc/tasks/main.yml b/ansible/roles/convert_openrc/tasks/main.yml index be621f0af..00aa13615 100644 --- a/ansible/roles/convert_openrc/tasks/main.yml +++ b/ansible/roles/convert_openrc/tasks/main.yml @@ -18,7 +18,7 @@ - debug: var=openrc - set_fact: - yardstick_url_ip: "{{ openrc.OS_AUTH_URL|urlsplit|attr('hostname') }}" + yardstick_url_ip: "{{ openrc.OS_AUTH_URL|urlsplit('hostname') }}" - debug: var=yardstick_url_ip diff --git a/ansible/roles/download_l2fwd/defaults/main.yml b/ansible/roles/download_l2fwd/defaults/main.yml new file mode 100644 index 000000000..1bc76ef3e --- /dev/null +++ b/ansible/roles/download_l2fwd/defaults/main.yml @@ -0,0 +1,4 @@ +--- +l2fwd_url: "http://artifacts.opnfv.org/yardstick/third-party/l2fwd.tar" +l2fwd_file: "l2fwd.tar" +l2fwd_dest: "/home" diff --git a/ansible/roles/download_l2fwd/tasks/main.yml b/ansible/roles/download_l2fwd/tasks/main.yml new file mode 100644 index 000000000..7f2ea25c4 --- /dev/null +++ b/ansible/roles/download_l2fwd/tasks/main.yml @@ -0,0 +1,28 @@ +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +--- +- file: + path: "{{ l2fwd_dest }}" + state: directory + +- name: fetch dpdk + get_url: + url: "{{ l2fwd_url }}" + dest: "{{ l2fwd_dest }}" + +- unarchive: + src: "{{ l2fwd_dest }}/{{ l2fwd_file }}" + dest: "{{ l2fwd_dest }}/" + copy: no + mode: 0777 diff --git a/ansible/roles/infra_check_requirements/tasks/main.yml b/ansible/roles/infra_check_requirements/tasks/main.yml index 8d05bbdb7..a11bc56a1 100644 --- a/ansible/roles/infra_check_requirements/tasks/main.yml +++ b/ansible/roles/infra_check_requirements/tasks/main.yml @@ -34,6 +34,22 @@ msg: "Failed, not enough CPU, required: {{ vcpu_t }}, available {{ ansible_processor_vcpus }}" when: ansible_processor_vcpus < vcpu_t|int +- name: Define default network counter + set_fact: + num_default_network_detected: 0 + +- name: Increment counter for every default network detected + set_fact: + num_default_network_detected: "{{ num_default_network_detected|int + 1 }}" + when: + - item.default_gateway is defined + - item.default_gateway == True + with_items: "{{infra_deploy_vars.networks}}" + +- name: Fail if more than 1 or 0 default networks + fail: + msg: "Failed, there must be 1 default network: {{ num_default_network_detected }} detected" + when: num_default_network_detected|int != 1 - name: Fail if not enough Disk space set_fact: diff --git a/ansible/roles/infra_create_network/tasks/create_xml.yaml b/ansible/roles/infra_create_network/tasks/create_xml.yml index a01c7974a..1632e591c 100644 --- a/ansible/roles/infra_create_network/tasks/create_xml.yaml +++ b/ansible/roles/infra_create_network/tasks/create_xml.yml @@ -40,10 +40,30 @@ xpath: /network add_children: - name: "{{ item.name }}" + - forward: + mode: nat - bridge - ip pretty_print: yes +- name: Add new children nodes to "forward" node + xml: + path: "{{ xml_file }}" + xpath: /network/forward + add_children: + - nat + pretty_print: yes + +- name: Add new children nodes to "nat" node + xml: + path: "{{ xml_file }}" + xpath: /network/forward/nat + add_children: + - port: + start: "1024" + end: "65535" + pretty_print: yes + - name: Add "name" attribute to "bridge" node xml: path: "{{ xml_file }}" diff --git a/ansible/roles/infra_create_network/tasks/main.yml b/ansible/roles/infra_create_network/tasks/main.yml index eba4a3a49..025a775a1 100644 --- a/ansible/roles/infra_create_network/tasks/main.yml +++ b/ansible/roles/infra_create_network/tasks/main.yml @@ -18,5 +18,5 @@ name: infra_deploy_vars - name: Create XML file - include_tasks: create_xml.yaml + include_tasks: create_xml.yml with_items: "{{ infra_deploy_vars.networks }}" diff --git a/ansible/roles/infra_create_vms/tasks/configure_vm.yml b/ansible/roles/infra_create_vms/tasks/configure_vm.yml index 10201cf2a..c20a0b175 100644 --- a/ansible/roles/infra_create_vms/tasks/configure_vm.yml +++ b/ansible/roles/infra_create_vms/tasks/configure_vm.yml @@ -222,6 +222,10 @@ - console: type: pty tty: '/dev/pts/14' + - graphics: + type: vnc + port: '-1' + autoport: 'yes' pretty_print: yes - name: Add new children nodes to "disk" node @@ -241,6 +245,16 @@ name: virtio-disk0 pretty_print: yes +- name: Add new children nodes to "graphics" node + xml: + path: "{{ xml_file }}" + xpath: /domain/devices/graphics + add_children: + - listen: + type: address + address: 0.0.0.0 + pretty_print: yes + - name: Add new children nodes to "devices" node xml: path: "{{ xml_file }}" @@ -305,7 +319,7 @@ - name: Populate network-config and add interface to xml file include_tasks: create_interfaces.yml - extra_vars: "{{ network_config, xml_file , slot_address, mac_address_counter }}" + extra_vars: "{{ network_config xml_file slot_address mac_address_counter }}" loop_control: loop_var: interface_item with_items: "{{ node_item.interfaces }}" @@ -326,9 +340,9 @@ shell: > qemu-img convert -O qcow2 {{ node_item.image }} {{ image_dir+node_item.hostname+'.qcow2' }} -- name: Copy and convert the ubuntu image +- name: Resize image shell: > - qemu-img resize {{ image_dir+node_item.hostname+'.qcow2' }} {{ node_item.disk }}MB + qemu-img resize {{ image_dir+node_item.hostname+'.qcow2' }} {{ node_item.disk }}M - name: Define the VMs virt: diff --git a/ansible/roles/infra_create_vms/tasks/create_interfaces.yml b/ansible/roles/infra_create_vms/tasks/create_interfaces.yml index 124421b56..34bfd1b71 100644 --- a/ansible/roles/infra_create_vms/tasks/create_interfaces.yml +++ b/ansible/roles/infra_create_vms/tasks/create_interfaces.yml @@ -24,6 +24,16 @@ addresses: - {{ interface_item.ip }}/{{ interface_item.netmask }} +- name: Add default gateway + blockinfile: + path: "{{ network_config }}" + insertafter: "{{ interface_item.ip }}" + marker: "MARKER" + block: |2 + gateway4: {{ default_bridge.host_ip }} + when: + - default_bridge is defined + - default_bridge.name == interface_item.network - name: Remove the marker introduced in network-data lineinfile: diff --git a/ansible/roles/infra_create_vms/tasks/main.yml b/ansible/roles/infra_create_vms/tasks/main.yml index 62a023e7e..4d47f44ff 100644 --- a/ansible/roles/infra_create_vms/tasks/main.yml +++ b/ansible/roles/infra_create_vms/tasks/main.yml @@ -20,9 +20,15 @@ - set_fact: mac_address_counter: 0 +- set_fact: + default_bridge: "{{ item }}" + when: + - item.default_gateway is defined + - item.default_gateway == True + with_items: "{{ infra_deploy_vars.networks }}" + - name: Create XML file include_tasks: configure_vm.yml - extra_vars: "{{ mac_address_counter }}" loop_control: loop_var: node_item with_items: "{{ infra_deploy_vars.nodes }}" diff --git a/ansible/ubuntu_server_cloudimg_modify.yml b/ansible/ubuntu_server_cloudimg_modify.yml index 099d5803f..90235cc81 100644 --- a/ansible/ubuntu_server_cloudimg_modify.yml +++ b/ansible/ubuntu_server_cloudimg_modify.yml @@ -27,6 +27,7 @@ - modify_cloud_config - role: set_package_installer_proxy when: proxy_env is defined and proxy_env + - download_l2fwd - install_image_dependencies - download_unixbench - install_unixbench diff --git a/api/database/v2/models.py b/api/database/v2/models.py index 59dab3ebc..0ee811698 100644 --- a/api/database/v2/models.py +++ b/api/database/v2/models.py @@ -92,6 +92,7 @@ class V2Task(Base): case_name = Column(String(30)) suite = Column(Boolean) content = Column(Text) + params = Column(Text) result = Column(Text) error = Column(Text) status = Column(Integer) diff --git a/api/resources/v2/environments.py b/api/resources/v2/environments.py index 158e98be7..7e587be85 100644 --- a/api/resources/v2/environments.py +++ b/api/resources/v2/environments.py @@ -11,6 +11,7 @@ import logging from oslo_serialization import jsonutils from docker import Client +from docker.errors import APIError from api import ApiResource from api.database.v2.handlers import V2EnvironmentHandler @@ -20,6 +21,7 @@ from api.database.v2.handlers import V2ContainerHandler from yardstick.common.utils import result_handler from yardstick.common.utils import change_obj_to_dict from yardstick.common import constants as consts +from yardstick.service.environment import Environment LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) @@ -124,10 +126,41 @@ class V2Environment(ApiResource): LOG.debug('container name: %s', container.name) try: client.remove_container(container.name, force=True) - except Exception: + except APIError: LOG.exception('remove container failed') container_handler.delete_by_uuid(v) environment_handler.delete_by_uuid(environment_id) return result_handler(consts.API_SUCCESS, {'environment': environment_id}) + + +class V2SUT(ApiResource): + + def get(self, environment_id): + try: + uuid.UUID(environment_id) + except ValueError: + return result_handler(consts.API_ERROR, 'invalid environment id') + + environment_handler = V2EnvironmentHandler() + try: + environment = environment_handler.get_by_uuid(environment_id) + except ValueError: + return result_handler(consts.API_ERROR, 'no such environment id') + + if not environment.pod_id: + return result_handler(consts.API_SUCCESS, {'sut': {}}) + + pod_handler = V2PodHandler() + try: + pod = pod_handler.get_by_uuid(environment.pod_id) + except ValueError: + return result_handler(consts.API_ERROR, 'no such pod id') + else: + pod_content = pod.content + + env = Environment(pod=pod_content) + sut_info = env.get_sut_info() + + return result_handler(consts.API_SUCCESS, {'sut': sut_info}) diff --git a/api/resources/v2/tasks.py b/api/resources/v2/tasks.py index 25a9cf109..17241ed63 100644 --- a/api/resources/v2/tasks.py +++ b/api/resources/v2/tasks.py @@ -38,6 +38,8 @@ class V2Tasks(ApiResource): for t in tasks: result = t['result'] t['result'] = jsonutils.loads(result) if result else None + params = t['params'] + t['params'] = jsonutils.loads(params) if params else None return result_handler(consts.API_SUCCESS, {'tasks': tasks}) @@ -94,6 +96,9 @@ class V2Task(ApiResource): result = task_info['result'] task_info['result'] = jsonutils.loads(result) if result else None + params = task_info['params'] + task_info['params'] = jsonutils.loads(params) if params else None + return result_handler(consts.API_SUCCESS, {'task': task_info}) def delete(self, task_id): @@ -127,7 +132,6 @@ class V2Task(ApiResource): return result_handler(consts.API_SUCCESS, {'task': task_id}) def put(self, task_id): - try: uuid.UUID(task_id) except ValueError: @@ -166,6 +170,21 @@ class V2Task(ApiResource): return result_handler(consts.API_SUCCESS, {'uuid': task_id}) + def add_params(self, args): + task_id = args['task_id'] + try: + params = args['params'] + except KeyError: + return result_handler(consts.API_ERROR, 'params must be provided') + + LOG.info('update params info in task') + + task_handler = V2TaskHandler() + task_update_data = {'params': jsonutils.dumps(params)} + task_handler.update_attr(task_id, task_update_data) + + return result_handler(consts.API_SUCCESS, {'uuid': task_id}) + def add_case(self, args): task_id = args['task_id'] try: @@ -243,7 +262,8 @@ class V2Task(ApiResource): data = { 'inputfile': ['/tmp/{}.yaml'.format(task.case_name)], - 'task_id': task_id + 'task_id': task_id, + 'task-args': task.params } if task.suite: data.update({'suite': True}) diff --git a/api/urls.py b/api/urls.py index 4b8e39e8f..9f0abcade 100644 --- a/api/urls.py +++ b/api/urls.py @@ -26,6 +26,7 @@ urlpatterns = [ Url('/api/v2/yardstick/environments', 'v2_environments'), Url('/api/v2/yardstick/environments/action', 'v2_environments'), Url('/api/v2/yardstick/environments/<environment_id>', 'v2_environment'), + Url('/api/v2/yardstick/environments/<environment_id>/sut', 'v2_sut'), Url('/api/v2/yardstick/openrcs', 'v2_openrcs'), Url('/api/v2/yardstick/openrcs/action', 'v2_openrcs'), diff --git a/docs/testing/developer/devguide/devguide_nsb_prox.rst b/docs/testing/developer/devguide/devguide_nsb_prox.rst index fc533b2cf..22628413b 100755 --- a/docs/testing/developer/devguide/devguide_nsb_prox.rst +++ b/docs/testing/developer/devguide/devguide_nsb_prox.rst @@ -251,9 +251,11 @@ Now let's examine the components of the file in detail In this case it is ``handle_l2fwd-2.cfg`` A number of additional parameters can be added. This example - is taken from VPE:: + is for VPE:: options: + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: ``configs/handle_vpe-4.cfg`` @@ -267,6 +269,12 @@ Now let's examine the components of the file in detail ``configs/vpe_rules.lua`` : ```` prox_generate_parameter: True + ``interface_speed_gbps`` - this specifies the speed of the interface + in Gigabits Per Second. This is used to calculate pps(packets per second). + If the interfaces are of different speeds, then this specifies the speed + of the slowest interface. This parameter is optional. If omitted the + interface speed defaults to 10Gbps. + ``prox_files`` - this specified that a number of addition files need to be provided for the test to run correctly. This files could provide routing information,hashing information or a diff --git a/docs/testing/user/userguide/08-api.rst b/docs/testing/user/userguide/08-api.rst index 92fa408c8..79f5d64be 100644 --- a/docs/testing/user/userguide/08-api.rst +++ b/docs/testing/user/userguide/08-api.rst @@ -35,7 +35,7 @@ Prepare Yardstick test environment Example:: { - 'action': 'prepareYardstickEnv' + 'action': 'prepare_env' } This is an asynchronous API. You need to call /yardstick/asynctask API to get the task result. @@ -45,7 +45,7 @@ Start and config an InfluxDB docker container Example:: { - 'action': 'createInfluxDBContainer' + 'action': 'create_influxdb' } This is an asynchronous API. You need to call /yardstick/asynctask API to get the task result. @@ -55,7 +55,7 @@ Start and config a Grafana docker container Example:: { - 'action': 'createGrafanaContainer' + 'action': 'create_grafana' } This is an asynchronous API. You need to call /yardstick/asynctask API to get the task result. @@ -73,10 +73,15 @@ Method: GET Get the status of asynchronous tasks Example:: - http://localhost:8888/yardstick/asynctask?task_id=3f3f5e03-972a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/yardstick/asynctask?task_id=3f3f5e03-972a-4847-a5f8-154f1b31db8c The returned status will be 0(running), 1(finished) and 2(failed). +NOTE:: + + <SERVER IP>: The ip of the host where you start your yardstick container + <PORT>: The outside port of port mapping which set when you start start yardstick container + /yardstick/testcases ^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +95,7 @@ Method: GET Get a list of released test cases Example:: - http://localhost:8888/yardstick/testcases + http://<SERVER IP>:<PORT>/yardstick/testcases /yardstick/testcases/release/action @@ -106,10 +111,10 @@ Run a released test case Example:: { - 'action': 'runTestCase', + 'action': 'run_test_case', 'args': { 'opts': {}, - 'testcase': 'tc002' + 'testcase': 'opnfv_yardstick_tc002' } } @@ -129,7 +134,7 @@ Run a sample test case Example:: { - 'action': 'runTestCase', + 'action': 'run_test_case', 'args': { 'opts': {}, 'testcase': 'ping' @@ -151,7 +156,7 @@ Method: GET Get the documentation of a certain test case Example:: - http://localhost:8888/yardstick/taskcases/opnfv_yardstick_tc002/docs + http://<SERVER IP>:<PORT>/yardstick/taskcases/opnfv_yardstick_tc002/docs /yardstick/testsuites/action @@ -167,10 +172,10 @@ Run a test suite Example:: { - 'action': 'runTestSuite', + 'action': 'run_test_suite', 'args': { 'opts': {}, - 'testcase': 'smoke' + 'testsuite': 'opnfv_smoke' } } @@ -178,6 +183,7 @@ This is an asynchronous API. You need to call /yardstick/results to get the resu /yardstick/tasks/<task_id>/log +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to get the real time log of test case execution. @@ -188,7 +194,7 @@ Method: GET Get real time of test case execution Example:: - http://localhost:8888/yardstick/tasks/14795be8-f144-4f54-81ce-43f4e3eab33f/log?index=0 + http://<SERVER IP>:<PORT>/yardstick/tasks/14795be8-f144-4f54-81ce-43f4e3eab33f/log?index=0 /yardstick/results @@ -203,17 +209,18 @@ Method: GET Get test results of one task Example:: - http://localhost:8888/yardstick/results?task_id=3f3f5e03-972a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/yardstick/results?task_id=3f3f5e03-972a-4847-a5f8-154f1b31db8c This API will return a list of test case result -/api/v2/yardstick/openrcs/action +/api/v2/yardstick/openrcs +^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API provides functionality of handling OpenStack credential file (openrc). For Euphrates, it supports: 1. Upload an openrc file for an OpenStack environment; -2. Update an openrc file; +2. Update an openrc; 3. Get openrc file information; 4. Delete an openrc file. @@ -260,12 +267,21 @@ Example:: } +/api/v2/yardstick/openrcs/<openrc_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API provides functionality of handling OpenStack credential file (openrc). For Euphrates, it supports: + +1. Get openrc file information; +2. Delete an openrc file. + + METHOD: GET Get openrc file information Example:: - http://localhost:8888/api/v2/yardstick/openrcs/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/openrcs/5g6g3e02-155a-4847-a5f8-154f1b31db8c METHOD: DELETE @@ -274,16 +290,15 @@ METHOD: DELETE Delete openrc file Example:: - http://localhost:8888/api/v2/yardstick/openrcs/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/openrcs/5g6g3e02-155a-4847-a5f8-154f1b31db8c -/api/v2/yardstick/pods/action +/api/v2/yardstick/pods +^^^^^^^^^^^^^^^^^^^^^^ Description: This API provides functionality of handling Yardstick pod file (pod.yaml). For Euphrates, it supports: 1. Upload a pod file; -2. Get pod file information; -3. Delete an openrc file. Which API to call will depend on the parameters. @@ -303,12 +318,20 @@ Example:: } +/api/v2/yardstick/pods/<pod_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API provides functionality of handling Yardstick pod file (pod.yaml). For Euphrates, it supports: + +1. Get pod file information; +2. Delete an openrc file. + METHOD: GET Get pod file information Example:: - http://localhost:8888/api/v2/yardstick/pods/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/pods/5g6g3e02-155a-4847-a5f8-154f1b31db8c METHOD: DELETE @@ -316,16 +339,15 @@ METHOD: DELETE Delete openrc file Example:: - http://localhost:8888/api/v2/yardstick/pods/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/pods/5g6g3e02-155a-4847-a5f8-154f1b31db8c -/api/v2/yardstick/images/action +/api/v2/yardstick/images +^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to Yardstick VM images. For Euphrates, it supports: 1. Load Yardstick VM images; -2. Get image's information; -3. Delete images. Which API to call will depend on the parameters. @@ -337,16 +359,27 @@ Load VM images Example:: { - 'action': 'load_images' + 'action': 'load_image', + 'args': { + 'name': 'yardstick-image' + } } +/api/v2/yardstick/images/<image_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to Yardstick VM images. For Euphrates, it supports: + +1. Get image's information; +2. Delete images + METHOD: GET Get image information Example:: - http://localhost:8888/api/v2/yardstick/images/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/images/5g6g3e02-155a-4847-a5f8-154f1b31db8c METHOD: DELETE @@ -354,19 +387,15 @@ METHOD: DELETE Delete images Example:: - http://localhost:8888/api/v2/yardstick/images/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/images/5g6g3e02-155a-4847-a5f8-154f1b31db8c -/api/v2/yardstick/tasks/action +/api/v2/yardstick/tasks +^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to yardstick tasks. For Euphrates, it supports: 1. Create a Yardstick task; -2. run a Yardstick task; -3. Add a test case to a task; -4. Add a test suite to a task; -5. Get a tasks' information; -6. Delete a task. Which API to call will depend on the parameters. @@ -386,20 +415,35 @@ Example:: } +/api/v2/yardstick/tasks/<task_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to yardstick tasks. For Euphrates, it supports: + +1. Add a environment to a task +2. Add a test case to a task; +3. Add a test suite to a task; +4. run a Yardstick task; +5. Get a tasks' information; +6. Delete a task. + + METHOD: PUT +Add a environment to a task -Run a task Example:: { - 'action': 'run' + 'action': 'add_environment', + 'args': { + 'environment_id': 'e3cadbbb-0419-4fed-96f1-a232daa0422a' + } } METHOD: PUT - Add a test case to a task Example:: @@ -412,8 +456,8 @@ Example:: } -METHOD: PUT +METHOD: PUT Add a test suite to a task Example:: @@ -427,29 +471,41 @@ Example:: } +METHOD: PUT + +Run a task + +Example:: + + { + 'action': 'run' + } + + + METHOD: GET Get a task's information Example:: - http://localhost:8888/api/v2/yardstick/tasks/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/tasks/5g6g3e02-155a-4847-a5f8-154f1b31db8c METHOD: DELETE Delete a task + Example:: - http://localhost:8888/api/v2/yardstick/tasks/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/tasks/5g6g3e02-155a-4847-a5f8-154f1b31db8c -/api/v2/yardstick/testcases/action +/api/v2/yardstick/testcases +^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to yardstick testcases. For Euphrates, it supports: 1. Upload a test case; 2. Get all released test cases' information; -3. Get a certain released test case's information; -4. Delete a test case. Which API to call will depend on the parameters. @@ -474,16 +530,24 @@ METHOD: GET Get all released test cases' information Example:: - http://localhost:8888/api/v2/yardstick/testcases + http://<SERVER IP>:<PORT>/api/v2/yardstick/testcases + + +/api/v2/yardstick/testcases/<case_name> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to yardstick testcases. For Euphrates, it supports: +1. Get certain released test case's information; +2. Delete a test case. METHOD: GET -Get a certain released test case's information +Get certain released test case's information Example:: - http://localhost:8888/api/v2/yardstick/testcases/opnfv_yardstick_tc002 + http://<SERVER IP>:<PORT>/api/v2/yardstick/testcases/opnfv_yardstick_tc002 METHOD: DELETE @@ -491,17 +555,16 @@ METHOD: DELETE Delete a certain test case Example:: - http://localhost:8888/api/v2/yardstick/testcases/opnfv_yardstick_tc002 + http://<SERVER IP>:<PORT>/api/v2/yardstick/testcases/opnfv_yardstick_tc002 -/api/v2/yardstick/testsuites/action +/api/v2/yardstick/testsuites +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to yardstick test suites. For Euphrates, it supports: 1. Create a test suite; -2. Get a certain test suite's information; -3. Get all test suites; -4. Delete a test case. +2. Get all test suites; Which API to call will depend on the parameters. @@ -526,19 +589,27 @@ Example:: METHOD: GET -Get a certain test suite's information +Get all test suite Example:: - http://localhost:8888/api/v2/yardstick/testsuites/<suite_name> + http://<SERVER IP>:<PORT>/api/v2/yardstick/testsuites + + +/api/v2/yardstick/testsuites +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to yardstick test suites. For Euphrates, it supports: +1. Get certain test suite's information; +2. Delete a test case. METHOD: GET -Get all test suite +Get certain test suite's information Example:: - http://localhost:8888/api/v2/yardstick/testsuites + http://<SERVER IP>:<PORT>/api/v2/yardstick/testsuites/<suite_name> METHOD: DELETE @@ -547,17 +618,16 @@ METHOD: DELETE Delete a certain test suite Example:: - http://localhost:8888/api/v2/yardstick/testsuites/<suite_name> + http://<SERVER IP>:<PORT>/api/v2/yardstick/testsuites/<suite_name> -/api/v2/yardstick/projects/action +/api/v2/yardstick/projects +^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to yardstick test projects. For Euphrates, it supports: 1. Create a Yardstick project; -2. Get a certain project's information; -3. Get all projects; -4. Delete a project. +2. Get all projects; Which API to call will depend on the parameters. @@ -579,19 +649,27 @@ Example:: METHOD: GET -Get a certain project's information +Get all projects' information Example:: - http://localhost:8888/api/v2/yardstick/projects/<project_id> + http://<SERVER IP>:<PORT>/api/v2/yardstick/projects + +/api/v2/yardstick/projects +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to yardstick test projects. For Euphrates, it supports: + +1. Get certain project's information; +2. Delete a project. METHOD: GET -Get all projects' information +Get certain project's information Example:: - http://localhost:8888/api/v2/yardstick/projects + http://<SERVER IP>:<PORT>/api/v2/yardstick/projects/<project_id> METHOD: DELETE @@ -600,17 +678,16 @@ METHOD: DELETE Delete a certain project Example:: - http://localhost:8888/api/v2/yardstick/projects/<project_id> + http://<SERVER IP>:<PORT>/api/v2/yardstick/projects/<project_id> -/api/v2/yardstick/containers/action +/api/v2/yardstick/containers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to Docker containers. For Euphrates, it supports: 1. Create a Grafana Docker container; 2. Create an InfluxDB Docker container; -3. Get a certain container's information; -4. Delete a container. Which API to call will depend on the parameters. @@ -643,13 +720,21 @@ Example:: } +/api/v2/yardstick/containers/<container_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to Docker containers. For Euphrates, it supports: + +1. Get certain container's information; +2. Delete a container. + METHOD: GET -Get a certain container's information +Get certain container's information Example:: - http://localhost:8888/api/v2/yardstick/containers/<container_id> + http://<SERVER IP>:<PORT>/api/v2/yardstick/containers/<container_id> METHOD: DELETE @@ -658,4 +743,4 @@ METHOD: DELETE Delete a certain container Example:: - http://localhost:8888/api/v2/yardstick/containers/<container_id> + http://<SERVER IP>:<PORT>/api/v2/yardstick/containers/<container_id> diff --git a/docs/testing/user/userguide/11-nsb-overview.rst b/docs/testing/user/userguide/11-nsb-overview.rst index 8ce90f65d..332dba47d 100644 --- a/docs/testing/user/userguide/11-nsb-overview.rst +++ b/docs/testing/user/userguide/11-nsb-overview.rst @@ -197,7 +197,9 @@ VNFs supported for chracterization: 1. CGNAPT - Carrier Grade Network Address and port Translation 2. vFW - Virtual Firewall 3. vACL - Access Control List -5. Prox - Packet pROcessing eXecution engine: - - VNF can act as Drop, Basic Forwarding (no touch), L2 Forwarding (change MAC), GRE encap/decap, Load balance based on packet fields, Symmetric load balancing, +4. Prox - Packet pROcessing eXecution engine: + - VNF can act as Drop, Basic Forwarding (no touch), + L2 Forwarding (change MAC), GRE encap/decap, Load balance based on + packet fields, Symmetric load balancing - QinQ encap/decap IPv4/IPv6, ARP, QoS, Routing, Unmpls, Policing, ACL -6. UDP_Replay +5. UDP_Replay diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc019.rst b/docs/testing/user/userguide/opnfv_yardstick_tc019.rst index 57e8ddf79..8d79e011a 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc019.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc019.rst @@ -125,7 +125,12 @@ Yardstick Test Case Description TC019 +--------------+--------------------------------------------------------------+ |post-action | It is the action when the test cases exist. It will check | | | the status of the specified process on the host, and restart | -| | the process if it is not running for next test cases | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc045.rst b/docs/testing/user/userguide/opnfv_yardstick_tc045.rst index 0b0993c34..378176090 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc045.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc045.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC045 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc046.rst b/docs/testing/user/userguide/opnfv_yardstick_tc046.rst index cce6c6884..5308c8e7b 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc046.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc046.rst @@ -127,9 +127,14 @@ Yardstick Test Case Description TC046 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc047.rst b/docs/testing/user/userguide/opnfv_yardstick_tc047.rst index 95158cfd6..bb8ffc6ab 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc047.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc047.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC047 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc048.rst b/docs/testing/user/userguide/opnfv_yardstick_tc048.rst index 21c00d1fe..1bf627282 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc048.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc048.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC048 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test case | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc049.rst b/docs/testing/user/userguide/opnfv_yardstick_tc049.rst index f58bb9989..12ed94b7d 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc049.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc049.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC049 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc053.rst b/docs/testing/user/userguide/opnfv_yardstick_tc053.rst index 3c6bbc628..7308babb8 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc053.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc053.rst @@ -135,6 +135,11 @@ Yardstick Test Case Description TC053 | | the status of the specified process on the host, and restart | | | the process if it is not running for next test cases. | | | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc056.rst b/docs/testing/user/userguide/opnfv_yardstick_tc056.rst index 09b866c34..cd8cc2f20 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc056.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc056.rst @@ -142,6 +142,11 @@ Yardstick Test Case Description TC056 | | the status of the specified process on the host, and restart | | | the process if it is not running for next test cases. | | | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc057.rst b/docs/testing/user/userguide/opnfv_yardstick_tc057.rst index bb42b2aae..1bb43c9e7 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc057.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc057.rst @@ -162,8 +162,14 @@ Yardstick Test Case Description TC057 |post-action | It is the action when the test cases exist. It will check | | | the status of the cluster messaging process(corosync) on the | | | host, and restart the process if it is not running for next | -| | test cases | +| | test cases. | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+------+----------------------------------+--------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | +| | | +--------------+--------------------------------------------------------------+ diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc058.rst b/docs/testing/user/userguide/opnfv_yardstick_tc058.rst index 7c323e913..9e8427b50 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc058.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc058.rst @@ -109,8 +109,9 @@ Yardstick Test Case Description TC058 |conditions | with cachestat included in the image. | | | | +--------------+--------------------------------------------------------------+ -|step 1 | Two host VMs are booted, these two hosts are in two different| -| | networks, the networks are connected by a virtual router | +|step 1 | Two host VMs are booted, these two hosts are in two | +| | different networks, the networks are connected by a virtual | +| | router. | | | | +--------------+--------------------------------------------------------------+ |step 1 | start monitors: | @@ -143,7 +144,13 @@ Yardstick Test Case Description TC058 | | Virtual machines and network created in the test case will | | | be destoryed. | | | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+------+----------------------------------+--------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | +| | | +--------------+--------------------------------------------------------------+ diff --git a/etc/infra/infra_deploy.yaml.sample b/etc/infra/infra_deploy.yaml.sample index bf07a01bc..8ed793622 100644 --- a/etc/infra/infra_deploy.yaml.sample +++ b/etc/infra/infra_deploy.yaml.sample @@ -31,5 +31,11 @@ nodes: networks: - name: management + default_gateway: True host_ip: 192.168.1.1 netmask: 255.255.255.0 + + - name: traffic + default_gateway: False # This parameter is not mandatory, default value: False + host_ip: 192.20.1.1 + netmask: 255.255.255.0 diff --git a/etc/yardstick/nodes/fuel_baremetal/pod.yaml b/etc/yardstick/nodes/fuel_baremetal/pod.yaml index 5ce555293..301433d50 100644 --- a/etc/yardstick/nodes/fuel_baremetal/pod.yaml +++ b/etc/yardstick/nodes/fuel_baremetal/pod.yaml @@ -49,3 +49,16 @@ nodes: ip: ip5 user: node_username key_filename: node_keyfile +- + name: node6 + role: Opendaylight + ip: ip6 + user: node_username + key_filename: node_keyfile +- + name: node7 + role: Gateway + ip: ip7 + user: node_username + key_filename: node_keyfile + diff --git a/gui/app/index.html b/gui/app/index.html index d959b14d2..2ea1cabe7 100644 --- a/gui/app/index.html +++ b/gui/app/index.html @@ -93,6 +93,7 @@ <script src="scripts/controllers/detail.controller.js"></script> <script src="scripts/controllers/image.controller.js"></script> <script src="scripts/controllers/pod.controller.js"></script> + <script src="scripts/controllers/sut.controller.js"></script> <script src="scripts/controllers/container.controller.js"></script> <script src="scripts/controllers/testcase.controller.js"></script> <script src="scripts/controllers/testcasedetail.controller.js"></script> diff --git a/gui/app/scripts/controllers/container.controller.js b/gui/app/scripts/controllers/container.controller.js index 3ad200a91..a7d5f0309 100644 --- a/gui/app/scripts/controllers/container.controller.js +++ b/gui/app/scripts/controllers/container.controller.js @@ -127,10 +127,15 @@ angular.module('yardStickGui2App') function chooseResult(name) { $scope.selectContainer = name; } + $scope.goBack = function goBack() { $state.go('app.projectList'); } + $scope.goNext = function goNext() { + $state.go('app.sut', {uuid: $scope.uuid}); + } + $scope.openDeleteEnv = function openDeleteEnv(id, name) { $scope.deleteName = name; $scope.deleteId = id; diff --git a/gui/app/scripts/controllers/content.controller.js b/gui/app/scripts/controllers/content.controller.js index 0288fa540..90a3f1433 100644 --- a/gui/app/scripts/controllers/content.controller.js +++ b/gui/app/scripts/controllers/content.controller.js @@ -49,6 +49,7 @@ angular.module('yardStickGui2App') $scope.gotoOpenrcPage = gotoOpenrcPage; $scope.gotoPodPage = gotoPodPage; $scope.gotoContainerPage = gotoContainerPage; + $scope.gotoSUTPage = gotoSUTPage; $scope.gotoTestcase = gotoTestcase; $scope.gotoEnviron = gotoEnviron; $scope.gotoSuite = gotoSuite; @@ -95,6 +96,12 @@ angular.module('yardStickGui2App') $state.go('app.container', { uuid: $scope.uuid }); } + function gotoSUTPage() { + $scope.path = $location.path(); + $scope.uuid = $scope.path.split('/').pop(); + $state.go('app.sut', { uuid: $scope.uuid }); + } + function gotoTestcase() { $state.go('app.testcase'); } diff --git a/gui/app/scripts/controllers/projectDetail.controller.js b/gui/app/scripts/controllers/projectDetail.controller.js index e8468045d..353e02bcf 100644 --- a/gui/app/scripts/controllers/projectDetail.controller.js +++ b/gui/app/scripts/controllers/projectDetail.controller.js @@ -439,15 +439,36 @@ angular.module('yardStickGui2App') $scope.displayTable = false; $scope.contentInfo = response.result.testcase; + $scope.optionalParams = response.result.args; } }, function(error) { - toaster.pop({ - type: 'error', - title: 'fail', - body: 'unknow error', - timeout: 3000 - }); + mainFactory.errorHandler2(error); + }) + } + + + function addParamsToTask(){ + var params = {} + angular.forEach($scope.optionalParams, function(value, name){ + if(value.value){ + params[name] = value.value; + } + }); + + mainFactory.taskAddParams().put({ + 'taskId': $scope.newUUID, + 'action': 'add_params', + 'args': { + 'params': params + } + }).$promise.then(function(resp) { + if (resp.status == 1) { + } else { + mainFactory.errorHandler1(resp); + } + }, function(error) { + mainFactory.errorHandler2(error); }) } @@ -530,6 +551,7 @@ angular.module('yardStickGui2App') function confirmAddCaseOrSuite(content) { if ($scope.selectType.name == "Test Case") { addCasetoTask(content); + addParamsToTask(); } else { addSuitetoTask(content); } diff --git a/gui/app/scripts/controllers/sut.controller.js b/gui/app/scripts/controllers/sut.controller.js new file mode 100644 index 000000000..092aabc41 --- /dev/null +++ b/gui/app/scripts/controllers/sut.controller.js @@ -0,0 +1,58 @@ +'use strict'; + +angular.module('yardStickGui2App') + .controller('SUTController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', '$location', 'ngDialog', + function($scope, $state, $stateParams, mainFactory, Upload, toaster, $location, ngDialog) { + + + init(); + $scope.showloading = false; + $scope.loadingOPENrc = false; + + function init() { + + + $scope.uuid = $stateParams.uuid; + $scope.sutInfo = {}; + getItemIdDetail(); + getSUTDetail(); + + } + + function getItemIdDetail() { + mainFactory.ItemDetail().get({ + 'envId': $scope.uuid + }).$promise.then(function(response) { + if (response.status == 1) { + $scope.envName = response.result.environment.name; + }else{ + mainFactory.errorHandler1(response); + } + }, function(error) { + mainFactory.errorHandler2(error); + }) + } + + function getSUTDetail(){ + mainFactory.SUTDetail().get({ + 'envId': $scope.uuid + }).$promise.then(function(resp){ + $scope.sutInfo = resp.result.sut; + console.log($scope.sutInfo); + }, function(error){ + }) + } + + $scope.goBack = function goBack() { + $state.go('app.projectList'); + } + + + $scope.goNext = function goNext() { + $scope.path = $location.path(); + $scope.uuid = $scope.path.split('/').pop(); + $state.go('app.container', { uuid: $scope.uuid }); + } + + } + ]); diff --git a/gui/app/scripts/controllers/taskModify.controller.js b/gui/app/scripts/controllers/taskModify.controller.js index 757d65866..c9672fea8 100644 --- a/gui/app/scripts/controllers/taskModify.controller.js +++ b/gui/app/scripts/controllers/taskModify.controller.js @@ -20,6 +20,7 @@ angular.module('yardStickGui2App') $scope.constructTestSuit = constructTestSuit; $scope.constructTestCase = constructTestCase; $scope.getTestDeatil = getTestDeatil; + $scope.getTestcaseArgs = getTestcaseArgs; $scope.confirmToServer = confirmToServer; $scope.addEnvToTask = addEnvToTask; } @@ -46,6 +47,8 @@ angular.module('yardStickGui2App') getItemIdDetail($scope.taskDetailData.environment_id); } + getTestcaseArgs(); + } }, function(error) { toaster.pop({ @@ -277,7 +280,6 @@ angular.module('yardStickGui2App') function getTestDeatil() { - if ($scope.selectType.name == 'Test Case') { getTestcaseDetail(); } else { @@ -307,6 +309,29 @@ angular.module('yardStickGui2App') } + function getTestcaseArgs(){ + mainFactory.getTestcaseDetail().get({ + 'testcasename': $scope.taskDetailData.case_name + }).$promise.then(function(resp){ + if(resp.status == 1){ + $scope.optionalParams = resp.result.args; + var params = $scope.taskDetailData.params; + if(params){ + angular.forEach($scope.optionalParams, function(value, name){ + if(name in params){ + value.value = params[name]; + } + }); + } + }else{ + mainFactory.errorHandler1(resp); + } + }, function(error){ + mainFactory.errorHandler2(error); + }); + } + + function getTestcaseDetail() { mainFactory.getTestcaseDetail().get({ 'testcasename': $scope.selectCase @@ -316,15 +341,13 @@ angular.module('yardStickGui2App') $scope.displayTable = false; $scope.contentInfo = response.result.testcase; + $scope.optionalParams = response.result.args; + }else{ + mainFactory.errorHandler1(response); } }, function(error) { - toaster.pop({ - type: 'error', - title: 'fail', - body: 'unknow error', - timeout: 3000 - }); + mainFactory.errorHandler2(error); }) } @@ -426,12 +449,38 @@ angular.module('yardStickGui2App') if ($scope.selectCase == 'Test Case' || $scope.taskDetailData.suite == false) { addCasetoTask(content); + addParamsToTask(); } else { addSuitetoTask(content); } } + function addParamsToTask(){ + var params = {} + angular.forEach($scope.optionalParams, function(value, name){ + if(value.value){ + params[name] = value.value; + } + }); + + mainFactory.taskAddParams().put({ + 'taskId': $stateParams.taskId, + 'action': 'add_params', + 'args': { + 'params': params + } + }).$promise.then(function(resp) { + if (resp.status == 1) { + } else { + mainFactory.errorHandler1(resp); + } + }, function(error) { + mainFactory.errorHandler2(error); + }) + } + + function addEnvToTask() { mainFactory.taskAddEnv().put({ diff --git a/gui/app/scripts/factory/main.factory.js b/gui/app/scripts/factory/main.factory.js index 7637a9ff3..f75369336 100644 --- a/gui/app/scripts/factory/main.factory.js +++ b/gui/app/scripts/factory/main.factory.js @@ -58,6 +58,13 @@ angular.module('yardStickGui2App') } }) }, + SUTDetail: function() { + return $resource(Base_URL + '/api/v2/yardstick/environments/:envId/sut', { envId: "@envId" }, { + 'get': { + method: 'GET' + } + }) + }, ImageDetail: function() { return $resource(Base_URL + '/api/v2/yardstick/images/:image_id', { image_id: "@image_id" }, { 'get': { @@ -214,6 +221,14 @@ angular.module('yardStickGui2App') } }) }, + + taskAddParams: function() { + return $resource(Base_URL + '/api/v2/yardstick/tasks/:taskId', { taskId: "@taskId" }, { + 'put': { + method: 'PUT' + } + }) + }, //delete operate deleteEnv: function() { return $resource(Base_URL + '/api/v2/yardstick/environments/:env_id', { env_id: '@env_id' }, { diff --git a/gui/app/scripts/router.config.js b/gui/app/scripts/router.config.js index da2eb086b..75d5372fb 100644 --- a/gui/app/scripts/router.config.js +++ b/gui/app/scripts/router.config.js @@ -116,6 +116,15 @@ angular.module('yardStickGui2App') label: 'Container Manage' } }) + .state('app.sut', { + url: '/envsut/:uuid', + templateUrl: 'views/sut.html', + controller: 'SUTController', + params: { uuid: null }, + ncyBreadcrumb: { + label: 'SUT Manage' + } + }) .state('app.projectList', { url: '/project', templateUrl: 'views/projectList.html', diff --git a/gui/app/views/container.html b/gui/app/views/container.html index b3d78bfb1..ea5902996 100644 --- a/gui/app/views/container.html +++ b/gui/app/views/container.html @@ -5,7 +5,7 @@ <div style="width:750px;"> <h3>{{envName}} -- Container - <!--<button class="btn btn-default" style="float:right">Go Next</button>--> + <button class="btn btn-default" ng-click="goNext()" style="float:right">Next</button> </h3> <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>--> diff --git a/gui/app/views/layout/sideNav.html b/gui/app/views/layout/sideNav.html index 6c4426307..2333d22d5 100644 --- a/gui/app/views/layout/sideNav.html +++ b/gui/app/views/layout/sideNav.html @@ -42,6 +42,9 @@ <div class="panel-body " style="border:none;text-align: right;cursor:pointer" ng-click="gotoContainerPage()" ng-class="{active:$state.includes('app.container')}"> Container </div> + <div class="panel-body " style="border:none;text-align: right;cursor:pointer" ng-click="gotoSUTPage()" ng-class="{active:$state.includes('app.sut')}"> + SUT + </div> <div class="panel-body " style="border:none;text-align: right;"> Others </div> @@ -151,4 +154,4 @@ .active.panel-body { background-color: #dfe3e4; } -</style>
\ No newline at end of file +</style> diff --git a/gui/app/views/modal/taskCreate.html b/gui/app/views/modal/taskCreate.html index 2d7f1dc3b..ab6ff0ca1 100644 --- a/gui/app/views/modal/taskCreate.html +++ b/gui/app/views/modal/taskCreate.html @@ -80,13 +80,20 @@ </div> </div> - <div ng-show="displayTable==false"> - <textarea ng-model="contentInfo" spellcheck="false"> - - - </textarea> - + <div ng-show="displayTable==false" style="display:flex;flex-direction:row;justify-content:space-between;margin-top:10px;"> + <textarea class="col-md-8" ng-model="contentInfo" style="margin-top:5px;" spellcheck="false"></textarea> + <div class="col-md-4" style="border:1px solid #e8e8e8;margin-top:5px;margin-left:10px;padding-top:30px;"> + <h4>Optional Paramters:</h4> + <form class="form-horizontal col-md-offset-2" style="margin-top:20px"> + <div ng-repeat="(name, value) in optionalParams" class="form-group"> + <label for="param{{$index}}" class="col-md-5" style="font-weight:normal;">{{ name }}:</label> + <div class="col-md-5"> + <input type="text" ng-model="value.value" class="form-control" id="param{{$index}}"> + </div> + </div> + </form> + </div> </div> diff --git a/gui/app/views/sut.html b/gui/app/views/sut.html new file mode 100644 index 000000000..8cf1fcd6c --- /dev/null +++ b/gui/app/views/sut.html @@ -0,0 +1,33 @@ +<!--sut management--> + +<div class="content"> + <div style="display:flex;flex-direction:row;"> + <div style="width:750px;"> + + <h3>{{envName}} -- SUT + <!--<button class="btn btn-default" style="float:right">Go Next</button>--> + + </h3> + + <h2>Hosts</h2> + <div ng-repeat="(host, info) in sutInfo"> + <hr/> + <div class="results-table" style="margin-top:30px;"> + <table class="table table-striped table-hover"> + <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"> + <tr ng-repeat="record in info"> + <td>{{ record[0] }}</td> + <td>{{ record[1] }}</td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </div> + +</div> +<toaster-container></toaster-container> + +<style> +</style> diff --git a/gui/app/views/taskmodify.html b/gui/app/views/taskmodify.html index d12df4ba2..24b3d945f 100644 --- a/gui/app/views/taskmodify.html +++ b/gui/app/views/taskmodify.html @@ -42,11 +42,20 @@ <button class="btn btn-default" style="float:right" ng-disabled="sourceShow==null" ng-click="confirmToServer(contentInfo,taskDetailData.content)">Confirm</button> </div> - - <textarea ng-model="taskDetailData.content" ng-show="sourceShow==false" style="margin-top:5px;" spellcheck="false"> - - - </textarea> + <div ng-show="sourceShow==false" style="display:flex;flex-direction:row;justify-content:space-between;margin-top:10px;"> + <textarea class="col-md-8" ng-model="taskDetailData.content" style="margin-top:5px;" spellcheck="false"></textarea> + <div class="col-md-4" style="border:1px solid #e8e8e8;margin-top:5px;margin-left:10px;padding-top:30px;"> + <h4>Optional Paramters:</h4> + <form class="form-horizontal col-md-offset-2" style="margin-top:20px"> + <div ng-repeat="(name, value) in optionalParams" class="form-group"> + <label for="param{{$index}}" class="col-md-5" style="font-weight:normal;">{{ name }}:</label> + <div class="col-md-5"> + <input type="text" ng-model="value.value" class="form-control" id="param{{$index}}"> + </div> + </div> + </form> + </div> + </div> <div ng-show="sourceShow==true"> <div style="display:flex;flex-direction:row"> @@ -102,9 +111,7 @@ <div ng-show="displayTable==false"> <textarea ng-model="contentInfo" spellcheck="false"> - </textarea> - - + </textarea> </div> </div> diff --git a/samples/MoongenL2fwd.yaml b/samples/MoongenL2fwd.yaml new file mode 100644 index 000000000..8c00bfec6 --- /dev/null +++ b/samples/MoongenL2fwd.yaml @@ -0,0 +1,96 @@ +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# VSPERF specific configuration file for execution of RFC2544 throughput +# traffic. Traffic executed by traffic generator is forwarded directly +# between interfaces connected to the traffic generator. So test will only +# benchmark the performance of OVS external bridge at controller node. +# Details about supported test options and test case execution can be +# found in VSPERF documentation: +# +# http://artifacts.opnfv.org/vswitchperf/docs/userguide/yardstick.html + +schema: "yardstick:task:0.1" + +scenarios: +{% for multistream in [1, 1000] %} +- + type: MoongenTestPMD + options: + multistream: {{multistream}} + frame_size: 1024 + testpmd_queue: 2 + trafficgen_port1: 'ens4' + trafficgen_port2: 'ens5' + moongen_host_user: 'root' + moongen_host_passwd: 'root' + moongen_host_ip: '192.168.37.2' + moongen_dir: '/home/lua-trafficgen' + moongen_runBidirec: 'true' + Package_Loss: 0 + SearchRuntime: 60 + moongen_port1_mac: '88:cf:98:2f:4d:ed' + moongen_port2_mac: '88:cf:98:2f:4d:ee' + forward_type: 'l2fwd' + + host: testpmd.demo + + runner: + type: Sequence + scenario_option_name: frame_size + sequence: + - 64 + + sla: + # The throughput SLA (or any other SLA) cannot be set to a meaningful + # value without knowledge of the server and networking environment, + # possibly including prior testing in that environment to establish + # a baseline SLA level under well-understood circumstances. + throughput_rx_mpps: 0.5 +{% endfor %} + +context: + name: demo + image: yardstick-image + flavor: + vcpus: 10 + ram: 20480 + disk: 6 + extra_specs: + hw:mem_page_size: "1GB" + hw:cpu_policy: "dedicated" + hw:vif_multiqueue_enabled: "true" + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + testpmd: + floating_ip: true + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' + test2: + cidr: '10.0.2.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + test3: + cidr: '10.0.3.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' diff --git a/samples/MoongenTestPMD.yaml b/samples/MoongenTestPMD.yaml new file mode 100644 index 000000000..b389a19bc --- /dev/null +++ b/samples/MoongenTestPMD.yaml @@ -0,0 +1,106 @@ +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# VSPERF specific configuration file for execution of RFC2544 throughput +# traffic. Traffic executed by traffic generator is forwarded directly +# between interfaces connected to the traffic generator. So test will only +# benchmark the performance of OVS external bridge at controller node. +# Details about supported test options and test case execution can be +# found in VSPERF documentation: +# +# http://artifacts.opnfv.org/vswitchperf/docs/userguide/yardstick.html + +schema: "yardstick:task:0.1" + +scenarios: +{% for multistream in [1, 1000] %} +- + type: MoongenTestPMD + options: + multistream: {{multistream}} + frame_size: 1024 + testpmd_queue: 2 + trafficgen_port1: 'ens5' + trafficgen_port2: 'ens6' + moongen_host_user: 'root' + moongen_host_passwd: 'root' + moongen_host_ip: '192.168.37.2' + moongen_dir: '/home/lua-trafficgen' + moongen_runBidirec: 'true' + Package_Loss: 0 + SearchRuntime: 60 + moongen_port1_mac: '88:cf:98:2f:4d:ed' + moongen_port2_mac: '88:cf:98:2f:4d:ee' + forward_type: 'testpmd' + + host: testpmd.demo + + runner: + type: Sequence + scenario_option_name: frame_size + sequence: + - 64 + + sla: + # The throughput SLA (or any other SLA) cannot be set to a meaningful + # value without knowledge of the server and networking environment, + # possibly including prior testing in that environment to establish + # a baseline SLA level under well-understood circumstances. + throughput_rx_mpps: 0.5 +{% endfor %} + +context: + name: demo + #image: yardstick-image + image: yardstick-nsb-image + flavor: + vcpus: 10 + ram: 20480 + disk: 6 + extra_specs: + hw:mem_page_size: "1GB" + hw:cpu_policy: "dedicated" + hw:vif_multiqueue_enabled: "true" + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + testpmd: + floating_ip: true + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' + provider: "sriov" + physical_network: "sriov2" + segmentation_id: "1063" + test2: + cidr: '10.0.2.0/24' + gateway_ip: 'null' + provider: "sriov" + physical_network: "sriov2" + segmentation_id: "1061" + #port_security_enabled: False + enable_dhcp: 'false' + test3: + cidr: '10.0.3.0/24' + provider: "sriov" + physical_network: "sriov2" + segmentation_id: "1062" + gateway_ip: 'null' + #port_security_enabled: False + enable_dhcp: 'false' diff --git a/samples/dummy.yaml b/samples/dummy.yaml index fde2907cd..2921f5d3f 100644 --- a/samples/dummy.yaml +++ b/samples/dummy.yaml @@ -22,4 +22,5 @@ scenarios: context: type: Dummy + name: Dummy diff --git a/samples/netperf_soak.yaml b/samples/netperf_soak.yaml new file mode 100644 index 000000000..a7344dae2 --- /dev/null +++ b/samples/netperf_soak.yaml @@ -0,0 +1,71 @@ +############################################################################## +# Copyright (c) 2018 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 +############################################################################## +--- +# Bottlenecks long duration test need Yardstick to create VM pairs and use netperf sending messages +# This yaml file for the above operations based on Netperf mode similiar as netperf.yaml +# UDP_STREAM is used and out_opt is customized + +schema: "yardstick:task:0.1" + +{% set tx_msg_size = tx_msg_size or "8K" %} +{% set rx_msg_size = rx_msg_size or "8K" %} +{% set test_time = test_time or "10" %} +{% set out_opt = out_opt or "THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY,LOCAL_CPU_UTIL,REMOTE_CPU_UTIL,LOCAL_BYTES_SENT,REMOTE_BYTES_RECVD" %} +{% set image_name = image_name or "yardstick-image" %} +{% set cpu_num = cpu_num or 1 %} +{% set ram_num = ram_num or 512 %} +{% set disk_num = disk_num or 7 %} + +scenarios: +- + type: Netperf + options: + testname: 'UDP_STREAM' + send_msg_size: {{tx_msg_size}} + recv_msg_size: {{rx_msg_size}} + duration: {{test_time}} + output_opt: {{out_opt}} + + host: netperf-host.demo + target: netperf-target.demo + + runner: + type: Iteration + iterations: 1 + interval: 1 + run_step: 'setup,run' + + sla: + mean_latency: 100 + action: monitor + +context: + name: demo + image: {{image_name}} + flavor: + vcpus: {{cpu_num}} + ram: {{ram_num}} + disk: {{disk_num}} + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + netperf-host: + floating_ip: true + placement: "pgrp1" + netperf-target: + floating_ip: false + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' diff --git a/samples/ping-mixed-network.yaml b/samples/ping-mixed-network.yaml new file mode 100644 index 000000000..76e05c9aa --- /dev/null +++ b/samples/ping-mixed-network.yaml @@ -0,0 +1,65 @@ +############################################################################## +## Copyright (c) 2018 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 +############################################################################### +--- +# Sample benchmark task config file +# measure network latency using ping +# This test case sample uses existing network to be public network, +# and also create the private network by heat like normal ping. + +schema: "yardstick:task:0.1" + +{% set public_net = public_net or 'public' %} +{% set public_subnet = public_subnet or 'public_subnet' %} +{% set provider = provider or none %} +{% set physical_network = physical_network or 'physnet1' %} +{% set segmentation_id = segmentation_id or none %} + +scenarios: +- + type: Ping + options: + packetsize: 200 + host: athena.demo + target: ares.demo + + runner: + type: Duration + duration: 60 + interval: 1 + + sla: + max_rtt: 10 + action: monitor + +context: + name: demo + image: yardstick-image + flavor: yardstick-flavor + user: ubuntu + + servers: + athena: + ares: + + networks: + test: + cidr: '10.0.1.0/24' + {% if provider == "vlan" %} + provider: {{provider}} + physical_network: {{physical_network}} + {% if segmentation_id %} + segmentation_id: {{segmentation_id}} + {% endif %} + {% endif %} + + {{ public_net }}: + net_flags: + is_existing: true + is_public: true + subnet: {{ public_subnet }} diff --git a/samples/ping-one-exising-network.yaml b/samples/ping-one-exising-network.yaml new file mode 100644 index 000000000..9e33148d6 --- /dev/null +++ b/samples/ping-one-exising-network.yaml @@ -0,0 +1,50 @@ +############################################################################## +## Copyright (c) 2018 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 +############################################################################### +--- +# Sample benchmark task config file +# measure network latency using ping +# This sample use one existing network as both public network and private network. + +schema: "yardstick:task:0.1" + +{% set public_net = public_net or 'public' %} +{% set public_subnet = public_subnet or 'public_subnet' %} + +scenarios: +- + type: Ping + options: + packetsize: 200 + host: athena.demo + target: ares.demo + + runner: + type: Duration + duration: 60 + interval: 1 + + sla: + max_rtt: 10 + action: monitor + +context: + name: demo + image: yardstick-image + flavor: yardstick-flavor + user: ubuntu + + servers: + athena: + ares: + + networks: + {{ public_net }}: + net_flags: + is_existing: true + subnet: {{ public_subnet }} diff --git a/samples/ping-two-exising-network.yaml b/samples/ping-two-exising-network.yaml new file mode 100644 index 000000000..adea43ef5 --- /dev/null +++ b/samples/ping-two-exising-network.yaml @@ -0,0 +1,58 @@ +############################################################################## +## Copyright (c) 2018 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 +############################################################################### +--- +# Sample benchmark task config file +# measure network latency using ping +# This sample use two existing network, one as public network to replace for +# floating ip, one as private network to ping between VMs. + +schema: "yardstick:task:0.1" + +{% set private_net = private_net or 'private' %} +{% set private_subnet = private_subnet or 'private_subnet' %} +{% set public_net = public_net or 'public' %} +{% set public_subnet = public_subnet or 'public_subnet' %} + +scenarios: +- + type: Ping + options: + packetsize: 200 + host: athena.demo + target: ares.demo + + runner: + type: Duration + duration: 60 + interval: 1 + + sla: + max_rtt: 10 + action: monitor + +context: + name: demo + image: yardstick-image + flavor: yardstick-flavor + user: ubuntu + + servers: + athena: + ares: + + networks: + {{ private_net }}: + net_flags: + is_existing: true + subnet: {{ private_subnet }} + {{ public_net }}: + net_flags: + is_existing: true + is_public: true + subnet: {{ public_subnet }} diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-2.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-2.yaml index b1fef6d45..69778ed8c 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-2.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-2.yaml @@ -26,6 +26,8 @@ scenarios: vnf__0: vnf_0.yardstick options: + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: "configs/handle_l2fwd-2.cfg" diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-4.yaml index e17c5c2a1..ab067a836 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-4.yaml @@ -26,6 +26,8 @@ scenarios: vnf__0: vnf_0.yardstick options: + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: "configs/handle_l2fwd-4.cfg" diff --git a/tests/ci/load_images.sh b/tests/ci/load_images.sh index caaba9e8b..d723823ee 100755 --- a/tests/ci/load_images.sh +++ b/tests/ci/load_images.sh @@ -67,6 +67,7 @@ build_yardstick_image() cd ${ANSIBLE_SCRIPTS} &&\ ansible-playbook \ -e img_property="normal" \ + -e YARD_IMG_ARCH=${YARD_IMG_ARCH} \ -vvv -i inventory.ini build_yardstick_image.yml if [ ! -f "${QCOW_IMAGE}" ]; then diff --git a/tests/ci/prepare_env.sh b/tests/ci/prepare_env.sh index 886e50e21..d7c60d48f 100755 --- a/tests/ci/prepare_env.sh +++ b/tests/ci/prepare_env.sh @@ -72,10 +72,12 @@ if [ "$INSTALLER_TYPE" == "fuel" ]; then # update "ip" according to the CI env ssh -l ubuntu "${INSTALLER_IP}" -i ${SSH_KEY} ${ssh_options} \ - "sudo salt -C 'ctl* or cmp*' grains.get fqdn_ip4 --out yaml">node_info + "sudo salt -C 'ctl* or cmp* or odl01* or gtw*' grains.get fqdn_ip4 --out yaml">node_info - controller_ips=($(awk '/ctl/{getline; print $2} < node_info')) - compute_ips=($(awk '/cmp/{getline; print $2} < node_info')) + controller_ips=($(awk '/ctl/{getline; print $2}' < node_info)) + compute_ips=($(awk '/cmp/{getline; print $2}' < node_info)) + odl_ip=($(awk '/odl01/{getline; print $2}' < node_info)) + gateway_ip=($(awk '/gtw/{getline; print $2}' < node_info)) if [[ ${controller_ips[0]} ]]; then sed -i "s|ip1|${controller_ips[0]}|" "${pod_yaml}" @@ -92,6 +94,12 @@ if [ "$INSTALLER_TYPE" == "fuel" ]; then if [[ ${compute_ips[1]} ]]; then sed -i "s|ip5|${compute_ips[1]}|" "${pod_yaml}" fi + if [[ ${odl_ip[0]} ]]; then + sed -i "s|ip6|${odl_ip[0]}|" "${pod_yaml}" + fi + if [[ ${gateway_ip[0]} ]]; then + sed -i "s|ip7|${gateway_ip[0]}|" "${pod_yaml}" + fi # update 'user' and 'key_filename' according to the CI env sed -i "s|node_username|${USER_NAME}|;s|node_keyfile|${SSH_KEY}|" "${pod_yaml}" diff --git a/tests/opnfv/test_suites/opnfv_k8-nosdn-lb_ceph-noha_daily.yaml b/tests/opnfv/test_suites/opnfv_k8-nosdn-lb_ceph-noha_daily.yaml new file mode 100644 index 000000000..ebb21b5c7 --- /dev/null +++ b/tests/opnfv/test_suites/opnfv_k8-nosdn-lb_ceph-noha_daily.yaml @@ -0,0 +1,18 @@ +############################################################################## +# 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 +############################################################################## +--- +# k8 nosdn lb ceph noha daily task suite + +schema: "yardstick:suite:0.1" + +name: "k8-nosdn-lb_ceph-noha" +test_cases_dir: "tests/opnfv/test_cases/" +test_cases: +- + file_name: opnfv_yardstick_tc080.yaml diff --git a/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py b/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py index faceeb695..bc48f994c 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py @@ -24,7 +24,7 @@ import unittest from tests.unit import STL_MOCKS from yardstick.common import utils from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper - +from yardstick.network_services import constants STLClient = mock.MagicMock() stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) @@ -46,7 +46,6 @@ if stl_patch: from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxVpeProfileHelper from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxlwAFTRProfileHelper - class TestCoreTuple(unittest.TestCase): def test___init__(self): core_tuple = CoreSocketTuple('core 5s6') @@ -1537,7 +1536,9 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.port_stats.return_value = list(range(10)) - data_helper = ProxDataHelper(vnfd_helper, sut, pkt_size, 25, None) + data_helper = ProxDataHelper( + vnfd_helper, sut, pkt_size, 25, None, + constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) self.assertEqual(data_helper.rx_total, 6) self.assertEqual(data_helper.tx_total, 7) @@ -1551,7 +1552,7 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.port_stats.return_value = list(range(10)) - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None) + data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None, None) expected = { 'xe1': { @@ -1574,13 +1575,15 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.port_stats.return_value = list(range(10)) - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, 5.4) + data_helper = ProxDataHelper(vnfd_helper, sut, None, None, + 5.4, constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) data_helper._totals_and_pps = 12, 32, 4.5 data_helper.tsc_hz = 9.8 data_helper.measured_stats = {'delta': TotStatsTuple(6.1, 6.2, 6.3, 6.4)} data_helper.latency = 7 self.assertIsNone(data_helper.result_tuple) + self.assertEqual(data_helper.line_speed, 10000000000) expected = ProxTestDataTuple(5.4, 9.8, 6.1, 6.2, 6.3, 7, 12, 32, 4.5) with data_helper: @@ -1595,7 +1598,7 @@ class TestProxDataHelper(unittest.TestCase): def test___enter___negative(self): vnfd_helper = mock.MagicMock() - data_helper = ProxDataHelper(vnfd_helper, None, None, None, None) + data_helper = ProxDataHelper(vnfd_helper, None, None, None, None, None) vnfd_helper.port_pairs.all_ports = [] with self.assertRaises(AssertionError): @@ -1617,7 +1620,7 @@ class TestProxDataHelper(unittest.TestCase): sut = ProxSocketHelper(mock.MagicMock()) sut.get_all_tot_stats = mock.MagicMock(side_effect=[start, end]) - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, 5.4) + data_helper = ProxDataHelper(vnfd_helper, sut, None, None, 5.4, None) self.assertIsNone(data_helper.measured_stats) @@ -1638,7 +1641,7 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.hz.return_value = '54.6' - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None) + data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None, None) self.assertIsNone(data_helper.tsc_hz) @@ -1935,7 +1938,8 @@ class TestProxProfileHelper(unittest.TestCase): helper = ProxProfileHelper(resource_helper) - helper.run_test(120, 5, 6.5) + helper.run_test(120, 5, 6.5, + constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) class TestProxMplsProfileHelper(unittest.TestCase): @@ -2081,8 +2085,12 @@ class TestProxBngProfileHelper(unittest.TestCase): helper = ProxBngProfileHelper(resource_helper) - helper.run_test(120, 5, 6.5) - helper.run_test(-1000, 5, 6.5) # negative pkt_size is the only way to make ratio > 1 + helper.run_test(120, 5, 6.5, + constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) + + # negative pkt_size is the only way to make ratio > 1 + helper.run_test(-1000, 5, 6.5, + constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) class TestProxVpeProfileHelper(unittest.TestCase): diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index 44078892b..0d1dfb86f 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -134,16 +134,6 @@ class HeatContext(Context): self.attrs = attrs - self.key_filename = ''.join( - [consts.YARDSTICK_ROOT_PATH, - 'yardstick/resources/files/yardstick_key-', - self.name]) - # Permissions may have changed since creation; this can be fixed. If we - # overwrite the file, we lose future access to VMs using this key. - # As long as the file exists, even if it is unreadable, keep it intact - if not os.path.exists(self.key_filename): - SSH.gen_keys(self.key_filename) - def check_environment(self): try: os.environ['OS_AUTH_URL'] @@ -185,6 +175,9 @@ class HeatContext(Context): template.add_security_group(self.secgroup_name) for network in self.networks.values(): + # Using existing network + if network.is_existing(): + continue template.add_network(network.stack_name, network.physical_network, network.provider, @@ -308,7 +301,7 @@ class HeatContext(Context): timeout=self.heat_timeout) except KeyboardInterrupt: raise y_exc.StackCreationInterrupt - except: + except Exception: LOG.exception("stack failed") # let the other failures happen, we want stack trace raise @@ -325,6 +318,16 @@ class HeatContext(Context): """deploys template into a stack using cloud""" LOG.info("Deploying context '%s' START", self.name) + self.key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.name]) + # Permissions may have changed since creation; this can be fixed. If we + # overwrite the file, we lose future access to VMs using this key. + # As long as the file exists, even if it is unreadable, keep it intact + if not os.path.exists(self.key_filename): + SSH.gen_keys(self.key_filename) + heat_template = HeatTemplate(self.name, self.template_file, self.heat_parameters) @@ -354,18 +357,35 @@ class HeatContext(Context): LOG.info("Deploying context '%s' DONE", self.name) + @staticmethod + def _port_net_is_existing(port_info): + net_flags = port_info.get('net_flags', {}) + return net_flags.get(consts.IS_EXISTING) + + @staticmethod + def _port_net_is_public(port_info): + net_flags = port_info.get('net_flags', {}) + return net_flags.get(consts.IS_PUBLIC) + def add_server_port(self, server): - # use private ip from first port in first network - try: - private_port = next(iter(server.ports.values()))[0] - except IndexError: - LOG.exception("Unable to find first private port in %s", server.ports) - raise - server.private_ip = self.stack.outputs[private_port["stack_name"]] + server_ports = server.ports.values() + for server_port in server_ports: + port_info = server_port[0] + port_ip = self.stack.outputs[port_info["stack_name"]] + port_net_is_existing = self._port_net_is_existing(port_info) + port_net_is_public = self._port_net_is_public(port_info) + if port_net_is_existing and (port_net_is_public or + len(server_ports) == 1): + server.public_ip = port_ip + if not server.private_ip or len(server_ports) == 1: + server.private_ip = port_ip + server.interfaces = {} for network_name, ports in server.ports.items(): for port in ports: # port['port'] is either port name from mapping or default network_name + if self._port_net_is_existing(port): + continue server.interfaces[port['port']] = self.make_interface_dict(network_name, port['port'], port['stack_name'], diff --git a/yardstick/benchmark/contexts/model.py b/yardstick/benchmark/contexts/model.py index ae56066ee..a55c11f79 100644 --- a/yardstick/benchmark/contexts/model.py +++ b/yardstick/benchmark/contexts/model.py @@ -18,6 +18,8 @@ import logging from collections import Mapping from six.moves import range +from yardstick.common import constants as consts + LOG = logging.getLogger(__name__) @@ -132,11 +134,28 @@ class Network(Object): if self.gateway_ip is None: self.gateway_ip = "null" - if "external_network" in attrs: - self.router = Router("router", self.name, - context, attrs["external_network"]) - - Network.list.append(self) + self.net_flags = attrs.get('net_flags', {}) + if self.is_existing(): + self.subnet = attrs.get('subnet') + if not self.subnet: + raise Warning('No subnet set in existing netwrok!') + else: + if "external_network" in attrs: + self.router = Router("router", self.name, + context, attrs["external_network"]) + Network.list.append(self) + + def is_existing(self): + net_is_existing = self.net_flags.get(consts.IS_EXISTING) + if net_is_existing and not isinstance(net_is_existing, bool): + raise SyntaxError('Network flags should be bool type!') + return net_is_existing + + def is_public(self): + net_is_public = self.net_flags.get(consts.IS_PUBLIC) + if net_is_public and not isinstance(net_is_public, bool): + raise SyntaxError('Network flags should be bool type!') + return net_is_public def has_route_to(self, network_name): """determines if this network has a route to the named network""" @@ -302,10 +321,13 @@ class Server(Object): # pragma: no cover # otherwise add a port for every network with port name as network name else: ports = [network.name] + net_flags = network.net_flags for port in ports: port_name = "{0}-{1}-port".format(server_name, port) - self.ports.setdefault(network.name, []).append( - {"stack_name": port_name, "port": port}) + port_info = {"stack_name": port_name, "port": port} + if net_flags: + port_info['net_flags'] = net_flags + self.ports.setdefault(network.name, []).append(port_info) # we can't use secgroups if port_security_enabled is False if network.port_security_enabled is False: sec_group_id = None @@ -314,11 +336,14 @@ class Server(Object): # pragma: no cover sec_group_id = self.secgroup_name # don't refactor to pass in network object, that causes JSON # circular ref encode errors - template.add_port(port_name, network.stack_name, network.subnet_stack_name, - network.vnic_type, sec_group_id=sec_group_id, + template.add_port(port_name, network, + sec_group_id=sec_group_id, provider=network.provider, allowed_address_pairs=network.allowed_address_pairs) - port_name_list.append(port_name) + if network.is_public(): + port_name_list.insert(0, port_name) + else: + port_name_list.append(port_name) if self.floating_ip: external_network = self.floating_ip["external_network"] diff --git a/yardstick/benchmark/core/report.py b/yardstick/benchmark/core/report.py index 997a125e7..199602444 100644 --- a/yardstick/benchmark/core/report.py +++ b/yardstick/benchmark/core/report.py @@ -45,7 +45,7 @@ class Report(object): self.task_id = "" def _validate(self, yaml_name, task_id): - if re.match("^[a-z0-9_-]+$", yaml_name): + if re.match(r"^[\w-]+$", yaml_name): self.yaml_name = yaml_name else: raise ValueError("invalid yaml_name", yaml_name) @@ -102,10 +102,12 @@ class Report(object): task_time = str(task_time, 'utf8') key = str(key, 'utf8') task_time = task_time[11:] - head, sep, tail = task_time.partition('.') + head, _, tail = task_time.partition('.') task_time = head + "." + tail[:6] self.Timestamp.append(task_time) - if isinstance(task[key], float) is True: + if task[key] is None: + values.append('') + elif isinstance(task[key], (int, float)) is True: values.append(task[key]) else: values.append(ast.literal_eval(task[key])) diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py index 7f6309a7e..e7acde696 100644 --- a/yardstick/benchmark/core/task.py +++ b/yardstick/benchmark/core/task.py @@ -149,7 +149,7 @@ class Task(object): # pragma: no cover total_end_time - total_start_time) LOG.info('To generate report, execute command "yardstick report ' - 'generate %(task_id)s <yaml_name>s"', self.task_id) + 'generate %s <YAML_NAME>"', self.task_id) LOG.info("Task ALL DONE, exiting") return result diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/add_server_to_existing_secgroup.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/add_server_to_existing_secgroup.bash new file mode 100644 index 000000000..3a50626f5 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/add_server_to_existing_secgroup.bash @@ -0,0 +1,26 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# add server to existing security group +# parameters: $1 - server name, $2 - security group name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +SECGROUPNAME="$(openstack ${SECURE} security group list -f value -c Name | grep $2)" + +openstack ${SECURE} server add security group $1 ${SECGROUPNAME} + diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_instance_from_image.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_instance_from_image.bash new file mode 100644 index 000000000..5e0b1ccf1 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_instance_from_image.bash @@ -0,0 +1,26 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# create nova server +# parameters: $1 - server name, $2 - image name, $3 - flavor name, $4 - network name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +NETNAME="$(openstack ${SECURE} network list -f value -c Name | grep $4)" + +openstack ${SECURE} server create $1 --image $2 --flavor $3 --network ${NETNAME} + diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_instance.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_instance.bash new file mode 100644 index 000000000..008e7f5ff --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_instance.bash @@ -0,0 +1,24 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# delete nova server +# parameters: $1 - server name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +openstack ${SECURE} server delete $1 + diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/get_server_privateip.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/get_server_privateip.bash new file mode 100644 index 000000000..7f2bad540 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/get_server_privateip.bash @@ -0,0 +1,24 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# get private ip of a server +# parameter: $1 - server name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +openstack ${SECURE} server list -f value -c Name -c Networks | grep $1 | awk '{print $2}' | sed -r 's/.*=([0-9\.\:]+)[;,]*/\1/' + diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/remove_server_from_secgroup.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/remove_server_from_secgroup.bash new file mode 100644 index 000000000..61d0a2b49 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/remove_server_from_secgroup.bash @@ -0,0 +1,25 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# remove server from existing security group +# parameters: $1 - server name, $2 - security group name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +SECGROUPNAME="$(openstack ${SECURE} security group list -f value -c Name | grep $2)" + +openstack ${SECURE} server remove security group $1 ${SECGROUPNAME} diff --git a/yardstick/benchmark/scenarios/availability/operation_conf.yaml b/yardstick/benchmark/scenarios/availability/operation_conf.yaml index dc5169196..5f3f6c91e 100644 --- a/yardstick/benchmark/scenarios/availability/operation_conf.yaml +++ b/yardstick/benchmark/scenarios/availability/operation_conf.yaml @@ -35,3 +35,14 @@ get-vip-host: action_script: ha_tools/pacemaker/get_vip_host.bash rollback_script: ha_tools/pacemaker/get_resource_status.bash +start-service: + action_script: ha_tools/start_service.bash + rollback_script: ha_tools/check_process_python.bash + +add-server-to-secgroup: + action_script: ha_tools/nova/add_server_to_existing_secgroup.bash + rollback_script: ha_tools/nova/remove_server_from_secgroup.bash + +get-privateip: + action_script: ha_tools/nova/get_server_privateip.bash + rollback_script: ha_tools/nova/list_servers.bash diff --git a/yardstick/benchmark/scenarios/lib/create_network.py b/yardstick/benchmark/scenarios/lib/create_network.py index cffff132a..734820519 100644 --- a/yardstick/benchmark/scenarios/lib/create_network.py +++ b/yardstick/benchmark/scenarios/lib/create_network.py @@ -7,13 +7,12 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import print_function -from __future__ import absolute_import - import logging from yardstick.benchmark.scenarios import base -import yardstick.common.openstack_utils as op_utils +from yardstick.common import openstack_utils +from yardstick.common import exceptions + LOG = logging.getLogger(__name__) @@ -28,9 +27,14 @@ class CreateNetwork(base.Scenario): self.context_cfg = context_cfg self.options = self.scenario_cfg['options'] - self.openstack = self.options.get("openstack_paras", None) + self.network_name = self.options["network_name"] + self.shared = self.options.get("shared", False) + self.admin_state_up = self.options.get("admin_state_up", True) + self.external = self.options.get("external", False) + self.provider = self.options.get("provider") + self.project_id = self.options.get("project_id") - self.neutron_client = op_utils.get_neutron_client() + self.shade_client = openstack_utils.get_shade_client() self.setup_done = False @@ -45,20 +49,17 @@ class CreateNetwork(base.Scenario): if not self.setup_done: self.setup() - openstack_paras = {'network': self.openstack} - network_id = op_utils.create_neutron_net(self.neutron_client, - openstack_paras) - if network_id: - result.update({"network_create": 1}) - LOG.info("Create network successful!") - else: + network_id = openstack_utils.create_neutron_net( + self.shade_client, self.network_name, shared=self.shared, + admin_state_up=self.admin_state_up, external=self.external, + provider=self.provider, project_id=self.project_id) + if not network_id: result.update({"network_create": 0}) LOG.error("Create network failed!") + raise exceptions.ScenarioCreateNetworkError - try: - keys = self.scenario_cfg.get('output', '').split() - except KeyError: - pass - else: - values = [network_id] - return self._push_to_outputs(keys, values) + result.update({"network_create": 1}) + LOG.info("Create network successful!") + keys = self.scenario_cfg.get('output', '').split() + values = [network_id] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/create_subnet.py b/yardstick/benchmark/scenarios/lib/create_subnet.py index c34af8a9e..e383c99de 100644 --- a/yardstick/benchmark/scenarios/lib/create_subnet.py +++ b/yardstick/benchmark/scenarios/lib/create_subnet.py @@ -7,13 +7,12 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import print_function -from __future__ import absolute_import - import logging from yardstick.benchmark.scenarios import base -import yardstick.common.openstack_utils as op_utils +from yardstick.common import openstack_utils +from yardstick.common import exceptions + LOG = logging.getLogger(__name__) @@ -28,9 +27,23 @@ class CreateSubnet(base.Scenario): self.context_cfg = context_cfg self.options = self.scenario_cfg['options'] - self.openstack = self.options.get("openstack_paras", None) - - self.neutron_client = op_utils.get_neutron_client() + self.network_name_or_id = self.options['network_name_or_id'] + self.cidr = self.options.get('cidr') + self.ip_version = self.options.get('ip_version', 4) + self.enable_dhcp = self.options.get('enable_dhcp', False) + self.subnet_name = self.options.get('subnet_name') + self.tenant_id = self.options.get('tenant_id') + self.allocation_pools = self.options.get('allocation_pools') + self.gateway_ip = self.options.get('gateway_ip') + self.disable_gateway_ip = self.options.get('disable_gateway_ip', False) + self.dns_nameservers = self.options.get('dns_nameservers') + self.host_routes = self.options.get('host_routes') + self.ipv6_ra_mode = self.options.get('ipv6_ra_mode') + self.ipv6_address_mode = self.options.get('ipv6_address_mode') + self.use_default_subnetpool = self.options.get( + 'use_default_subnetpool', False) + + self.shade_client = openstack_utils.get_shade_client() self.setup_done = False @@ -45,22 +58,23 @@ class CreateSubnet(base.Scenario): if not self.setup_done: self.setup() - openstack_paras = {'subnets': [self.openstack]} - subnet_id = op_utils.create_neutron_subnet(self.neutron_client, - openstack_paras) - if subnet_id: - result.update({"subnet_create": 1}) - LOG.info("Create subnet successful!") - else: + subnet_id = openstack_utils.create_neutron_subnet( + self.shade_client, self.network_name_or_id, cidr=self.cidr, + ip_version=self.ip_version, enable_dhcp=self.enable_dhcp, + subnet_name=self.subnet_name, tenant_id=self.tenant_id, + allocation_pools=self.allocation_pools, gateway_ip=self.gateway_ip, + disable_gateway_ip=self.disable_gateway_ip, + dns_nameservers=self.dns_nameservers, host_routes=self.host_routes, + ipv6_ra_mode=self.ipv6_ra_mode, + ipv6_address_mode=self.ipv6_address_mode, + use_default_subnetpool=self.use_default_subnetpool) + if not subnet_id: result.update({"subnet_create": 0}) LOG.error("Create subnet failed!") + raise exceptions.ScenarioCreateSubnetError - check_result = subnet_id - - try: - keys = self.scenario_cfg.get('output', '').split() - except KeyError: - pass - else: - values = [check_result] - return self._push_to_outputs(keys, values) + result.update({"subnet_create": 1}) + LOG.info("Create subnet successful!") + keys = self.scenario_cfg.get('output', '').split() + values = [subnet_id] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/delete_router.py b/yardstick/benchmark/scenarios/lib/delete_router.py index 358fd40cf..5e7467b2c 100644 --- a/yardstick/benchmark/scenarios/lib/delete_router.py +++ b/yardstick/benchmark/scenarios/lib/delete_router.py @@ -7,13 +7,12 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import print_function -from __future__ import absolute_import - import logging +from yardstick.common import openstack_utils +from yardstick.common import exceptions from yardstick.benchmark.scenarios import base -import yardstick.common.openstack_utils as op_utils + LOG = logging.getLogger(__name__) @@ -28,9 +27,9 @@ class DeleteRouter(base.Scenario): self.context_cfg = context_cfg self.options = self.scenario_cfg['options'] - self.router_id = self.options.get("router_id", None) + self.router_id = self.options["router_id"] - self.neutron_client = op_utils.get_neutron_client() + self.shade_client = openstack_utils.get_shade_client() self.setup_done = False @@ -45,11 +44,12 @@ class DeleteRouter(base.Scenario): if not self.setup_done: self.setup() - status = op_utils.delete_neutron_router(self.neutron_client, - router_id=self.router_id) - if status: - result.update({"delete_router": 1}) - LOG.info("Delete router successful!") - else: + status = openstack_utils.delete_neutron_router(self.shade_client, + self.router_id) + if not status: result.update({"delete_router": 0}) LOG.error("Delete router failed!") + raise exceptions.ScenarioDeleteRouterError + + result.update({"delete_router": 1}) + LOG.info("Delete router successful!") diff --git a/yardstick/benchmark/scenarios/networking/moongen_testpmd.bash b/yardstick/benchmark/scenarios/networking/moongen_testpmd.bash new file mode 100644 index 000000000..3e92cc900 --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/moongen_testpmd.bash @@ -0,0 +1,62 @@ +############################################################################## +# Copyright (c) 2018 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 +############################################################################## +#!/bin/bash + +set -e + +# Commandline arguments +MOONGEN_PORT1_MAC=$1 # MAC address of the peer port +MOONGEN_PORT2_MAC=$2 # MAC address of the peer port +TESTPMD_QUEUE=$3 + +BIND_ROOT='/opt/nsb_bin' +DRIVER_ROOT='/opt/tempT/dpdk-17.02/' + +load_modules() +{ + if ! lsmod | grep "uio" &> /dev/null; then + modprobe uio + fi + + if ! lsmod | grep "igb_uio" &> /dev/null; then + insmod ${DRIVER_ROOT}/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko + fi + + if ! lsmod | grep "rte_kni" &> /dev/null; then + insmod ${DRIVER_ROOT}/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko + fi +} + +change_permissions() +{ + chmod 777 /sys/bus/pci/drivers/virtio-pci/* + chmod 777 /sys/bus/pci/drivers/igb_uio/* +} + +add_interface_to_dpdk(){ + interfaces=$(lspci |grep Eth |tail -n +2 |awk '{print $1}') + ${BIND_ROOT}/dpdk_nic_bind.py --bind=igb_uio $interfaces &> /dev/null +} + +run_testpmd() +{ + blacklist=$(lspci |grep Eth |awk '{print $1}'|head -1) + cd ${DRIVER_ROOT} + sudo ./x86_64-native-linuxapp-gcc/app/testpmd -c 0x3f -n 4 -b $blacklist -- -a --nb-cores=4 --coremask=0x3c --burst=64 --txd=4096 --rxd=4096 --rxq=$TESTPMD_QUEUE --txq=$TESTPMD_QUEUE --rss-udp --eth-peer=0,$MOONGEN_PORT1_MAC --eth-peer=1,$MOONGEN_PORT2_MAC --forward-mode=mac +} + +main() +{ + load_modules + change_permissions + add_interface_to_dpdk + run_testpmd +} + +main diff --git a/yardstick/benchmark/scenarios/networking/moongen_testpmd.py b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py new file mode 100644 index 000000000..86173c9da --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py @@ -0,0 +1,378 @@ +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" VsperfDPDK specific scenario definition """ + +from __future__ import absolute_import +import pkg_resources +import logging +import subprocess +import time +import re +from oslo_serialization import jsonutils + +import yardstick.ssh as ssh +import yardstick.common.utils as utils +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class MoongenTestPMD(base.Scenario): + """Execute vsperf with defined parameters + + Parameters: + frame_size - a frame size for which test should be executed; + Multiple frame sizes can be tested by modification of sequence runner + section inside TC YAML definition. + type: string + default: "64" + multistream - the number of simulated streams + type: string + default: 0 (disabled) + testpmd_queue - specifies how many queues you will use the VM + only useful when forward_type is true. + type: int + default: 1(one queue) + trafficgen_port1 - specifies device name of 1st interface connected to + the trafficgen + type: string + default: NA + trafficgen_port2 - specifies device name of 2nd interface connected to + the trafficgen + type: string + default: NA + moongen_host_user - specifies moongen host ssh user name + type: string + default: root + moongen_host_passwd - specifies moongen host ssh user password + type: string + default: root + moongen_host_ip - specifies moongen host ssh ip address + type: string + default NA + moongen_dir - specifies where is the moongen installtion dir + type: string + default NA + moongen_runBidirec - specifies moongen will run in one traffic + or two traffic. + type: string + default true + Package_Loss - specifies the package_Loss number in moongen server. + type: int + default 0(0%) + SearchRuntime - specifies the SearchRuntime and validation time + on moongen server. + type: int + default 60(s) + moongen_port1_mac - moongen server port1 mac address. + type: string + default NA + moongen_port2_mac - moongen server port2 mac address. + type: string + default NA + forward_type - VM forward type is l2fwd or testpmd. + type: string + default: testpmd + """ + __scenario_type__ = "MoongenTestPMD" + + TESTPMD_SCRIPT = 'moongen_testpmd.bash' + VSPERF_CONFIG = '/tmp/opnfv-vsperf-cfg.lua' + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.forward_setup_done = False + self.options = scenario_cfg.get('options', {}) + self.moongen_host_user = \ + self.options.get('moongen_host_user', "root") + self.moongen_host_passwd = \ + self.options.get('moongen_host_passwd', "r00t") + self.moongen_dir = \ + self.options.get('moongen_dir', '~/moongen.py') + self.testpmd_queue = \ + self.options.get('testpmd_queue', 1) + self.moongen_host_ip = \ + self.options.get('moongen_host_ip', "127.0.0.1") + self.moongen_port1_mac = \ + self.options.get('moongen_port1_mac', None) + self.moongen_port2_mac = \ + self.options.get('moongen_port2_mac', None) + self.tg_port1 = \ + self.options.get('trafficgen_port1', "enp2s0f0") + self.tg_port2 = \ + self.options.get('trafficgen_port2', "enp2s0f1") + self.forward_type = \ + self.options.get('forward_type', 'testpmd') + self.tgen_port1_mac = None + self.tgen_port2_mac = None + + def setup(self): + """scenario setup""" + host = self.context_cfg['host'] + + task_id = self.scenario_cfg['task_id'] + context_number = task_id.split('-')[0] + self.tg_port1_nw = 'demo' + \ + "-" + context_number + "-" + \ + self.options.get('trafficgen_port1_nw', 'test2') + self.tg_port2_nw = 'demo' + \ + "-" + context_number + "-" + \ + self.options.get('trafficgen_port2_nw', 'test3') + + # copy vsperf conf to VM + self.client = ssh.SSH.from_node(host, defaults={"user": "ubuntu"}) + # traffic generation could last long + self.client.wait(timeout=1800) + + self.server = ssh.SSH( + self.moongen_host_user, + self.moongen_host_ip, + password=self.moongen_host_passwd + ) + # traffic generation could last long + self.server.wait(timeout=1800) + + self.setup_done = True + + def forward_setup(self): + """forward tool setup""" + + # setup forward loopback in VM + self.testpmd_script = pkg_resources.resource_filename( + 'yardstick.benchmark.scenarios.networking', + self.TESTPMD_SCRIPT) + + self.client._put_file_shell(self.testpmd_script, + '~/testpmd_vsperf.sh') + + # disable Address Space Layout Randomization (ASLR) + cmd = "echo 0 | sudo tee /proc/sys/kernel/randomize_va_space" + self.client.send_command(cmd) + + if not self._is_forward_setup(): + self.tgen_port1_ip = \ + utils.get_port_ip(self.client, self.tg_port1) + self.tgen_port1_mac = \ + utils.get_port_mac(self.client, self.tg_port1) + self.client.run("tee ~/.testpmd.ipaddr.port1 > /dev/null", + stdin=self.tgen_port1_ip) + self.client.run("tee ~/.testpmd.macaddr.port1 > /dev/null", + stdin=self.tgen_port1_mac) + self.tgen_port2_ip = \ + utils.get_port_ip(self.client, self.tg_port2) + self.tgen_port2_mac = \ + utils.get_port_mac(self.client, self.tg_port2) + self.client.run("tee ~/.testpmd.ipaddr.port2 > /dev/null", + stdin=self.tgen_port2_ip) + self.client.run("tee ~/.testpmd.macaddr.port2 > /dev/null", + stdin=self.tgen_port2_mac) + else: + cmd = "cat ~/.testpmd.macaddr.port1" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port1_mac = stdout + cmd = "cat ~/.testpmd.ipaddr.port1" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port1_ip = stdout + cmd = "cat ~/.testpmd.macaddr.port2" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port2_mac = stdout + cmd = "cat ~/.testpmd.ipaddr.port2" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port2_ip = stdout + + LOG.info("forward type is %s", self.forward_type) + if self.forward_type == 'testpmd': + cmd = "sudo ip link set %s down" % (self.tg_port1) + LOG.debug("Executing command: %s", cmd) + self.client.execute(cmd) + cmd = "sudo ip link set %s down" % (self.tg_port2) + LOG.debug("Executing command: %s", cmd) + self.client.execute(cmd) + cmd = "screen -d -m sudo -E bash ~/testpmd_vsperf.sh %s %s %d" % \ + (self.moongen_port1_mac, self.moongen_port2_mac, + self.testpmd_queue) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + + elif self.forward_type == 'l2fwd': + cmd = ('sed -i "s/static char *net1 = \\\"eth1\\\";' + '/static char *net1 = \\\"%s %s %s\\\";/g" /home/l2fwd/l2fwd.c' + % (self.tg_port1, self.tgen_port1_ip, self.moongen_port1_mac)) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + cmd = ('sed -i "s/static char *net2 = \\\"eth2\\\";' + '/static char *net2 = \\\"%s %s %s\\\";/g" /home/l2fwd/l2fwd.c' + % (self.tg_port2, self.tgen_port2_ip, self.moongen_port2_mac)) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + cmd = ('cd /home/l2fwd/;make;./gen_debian_package.sh;' + 'sudo dpkg -i *.deb;' + 'sudo modprobe l2fwd') + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + time.sleep(1) + + self.forward_setup_done = True + + def _is_forward_setup(self): + """Is forward already setup in the host?""" + if self.forward_type is 'testpmd': + is_run = True + cmd = "ip a | grep %s 2>/dev/null" % (self.tg_port1) + LOG.debug("Executing command: %s", cmd) + _, stdout, _ = self.client.execute(cmd) + if stdout: + is_run = False + return is_run + elif self.forward_type is 'l2fwd': + cmd = ('sudo lsmod |grep l2fwd') + LOG.debug("Executing command: %s", cmd) + _, stdout, _ = self.client.execute(cmd) + if stdout: + return True + else: + return False + + def generate_config_file(self, frame_size, multistream, + runBidirec, tg_port1_vlan, tg_port2_vlan, + SearchRuntime, Package_Loss): + out_text = """\ +VSPERF { +testType = 'throughput', +nrFlows = %d, +runBidirec = %s, +frameSize = %d, +srcMacs = {\'%s\', \'%s\'}, +dstMacs = {\'%s\', \'%s\'}, +vlanIds = {%d, %d}, +searchRunTime = %d, +validationRunTime = %d, +acceptableLossPct = %d, +ports = {0,1}, +} +""" % (multistream, runBidirec, frame_size, self.moongen_port1_mac, + self.moongen_port2_mac, self.tgen_port1_mac, self.tgen_port2_mac, + tg_port1_vlan, tg_port2_vlan, SearchRuntime, SearchRuntime, Package_Loss) + with open(self.VSPERF_CONFIG, "wt") as out_file: + out_file.write(out_text) + self.CONFIG_FILE = True + + def result_to_data(self, result): + search_pattern = re.compile( + r'\[REPORT\]\s+total\:\s+' + r'Tx\s+frames\:\s+(\d+)\s+' + r'Rx\s+Frames\:\s+(\d+)\s+' + r'frame\s+loss\:\s+(\d+)\,' + r'\s+(\d+\.\d+|\d+)%\s+' + r'Tx\s+Mpps\:\s+(\d+.\d+|\d+)\s+' + r'Rx\s+Mpps\:\s+(\d+\.\d+|\d+)', + re.IGNORECASE) + results_match = search_pattern.search(result) + if results_match: + rx_mpps = float(results_match.group(6)) + tx_mpps = float(results_match.group(5)) + else: + rx_mpps = 0 + tx_mpps = 0 + test_result = {"rx_mpps": rx_mpps, "tx_mpps": tx_mpps} + self.TO_DATA = True + return test_result + + def run(self, result): + """ execute the vsperf benchmark and return test results + within result dictionary + """ + + if not self.setup_done: + self.setup() + + # get vsperf options + multistream = self.options.get("multistream", 1) + + if not self.forward_setup_done: + self.forward_setup() + + if 'frame_size' in self.options: + frame_size = self.options.get("frame_size", 64) + Package_Loss = self.options.get("Package_Loss", 0) + runBidirec = self.options.get("moongen_runBidirec", + "true") + SearchRuntime = self.options.get("SearchRuntime", 10) + + cmd = "openstack network show %s --format json -c " \ + "provider:segmentation_id" % (self.tg_port1_nw) + LOG.debug("Executing command: %s", cmd) + output = subprocess.check_output(cmd, shell=True) + try: + tg_port1_vlan = jsonutils.loads(output).get("provider:segmentation_id", 1) + except TypeError: + tg_port1_vlan = 1 + + cmd = "openstack network show %s --format json -c " \ + "provider:segmentation_id" % (self.tg_port2_nw) + LOG.debug("Executing command: %s", cmd) + output = subprocess.check_output(cmd, shell=True) + try: + tg_port2_vlan = jsonutils.loads(output).get("provider:segmentation_id", 2) + except TypeError: + tg_port2_vlan = 2 + + self.generate_config_file(frame_size, multistream, + runBidirec, tg_port1_vlan, + tg_port2_vlan, SearchRuntime, Package_Loss) + + self.server.execute("rm -f -- %s/opnfv-vsperf-cfg.lua" % + (self.moongen_dir)) + self.server._put_file_shell(self.VSPERF_CONFIG, + "%s/opnfv-vsperf-cfg.lua" + % (self.moongen_dir)) + + # execute moongen + cmd = ("cd %s;./MoonGen/build/MoonGen ./trafficgen.lua" + % (self.moongen_dir)) + status, stdout, stderr = self.server.execute(cmd) + if status: + raise RuntimeError(stderr) + + moongen_result = self.result_to_data(stdout) + LOG.info(moongen_result) + result.update(moongen_result) + + if "sla" in self.scenario_cfg: + throughput_rx_mpps = int( + self.scenario_cfg["sla"]["throughput_rx_mpps"]) + + assert throughput_rx_mpps <= moongen_result["tx_mpps"], \ + "sla_throughput_rx_mpps %f > throughput_rx_mpps(%f); " % \ + (throughput_rx_mpps, moongen_result["tx_mpps"]) + + def teardown(self): + """cleanup after the test execution""" + + # execute external setup script + self.setup_done = False diff --git a/yardstick/benchmark/scenarios/networking/netperf.py b/yardstick/benchmark/scenarios/networking/netperf.py index a8d9010ed..33c02d409 100755 --- a/yardstick/benchmark/scenarios/networking/netperf.py +++ b/yardstick/benchmark/scenarios/networking/netperf.py @@ -104,7 +104,9 @@ class Netperf(base.Scenario): cmd_args = "-H %s -l %s -t %s" % (ipaddr, testlen, testname) # get test specific options - default_args = "-O 'THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY'" + output_opt = options.get( + "output_opt", "THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY") + default_args = "-O %s" % output_opt cmd_args += " -- %s" % default_args option_pair_list = [("send_msg_size", "-m"), ("recv_msg_size", "-M"), diff --git a/yardstick/benchmark/scenarios/storage/fio.py b/yardstick/benchmark/scenarios/storage/fio.py index 125bc7ed4..d3ed840d8 100644 --- a/yardstick/benchmark/scenarios/storage/fio.py +++ b/yardstick/benchmark/scenarios/storage/fio.py @@ -124,12 +124,16 @@ class Fio(base.Scenario): if mount_dir: LOG.debug("Formating volume...") - self.client.execute("sudo mkfs.ext4 /dev/vdb") - cmd = "sudo mkdir %s" % mount_dir - self.client.execute(cmd) - LOG.debug("Mounting volume at: %s", mount_dir) - cmd = "sudo mount /dev/vdb %s" % mount_dir - self.client.execute(cmd) + _, stdout, _ = self.client.execute( + "lsblk -dps | grep -m 1 disk | awk '{print $1}'") + block_device = stdout.strip() + if block_device: + self.client.execute("sudo mkfs.ext4 %s" % block_device) + cmd = "sudo mkdir %s" % mount_dir + self.client.execute(cmd) + LOG.debug("Mounting volume at: %s", mount_dir) + cmd = "sudo mount %s %s" % (block_device, mount_dir) + self.client.execute(cmd) self.setup_done = True diff --git a/yardstick/common/ansible_common.py b/yardstick/common/ansible_common.py index be262c215..38d2dd7c2 100644 --- a/yardstick/common/ansible_common.py +++ b/yardstick/common/ansible_common.py @@ -31,6 +31,7 @@ import six.moves.configparser as ConfigParser import yaml from six import StringIO from chainmap import ChainMap +from oslo_serialization import jsonutils from yardstick.common.utils import Timer from yardstick.common import constants as consts @@ -508,6 +509,58 @@ class AnsibleCommon(object): timeout = 1200.0 return timeout + def _generate_ansible_cfg(self, directory): + parser = ConfigParser.ConfigParser() + parser.add_section('defaults') + parser.set('defaults', 'host_key_checking', 'False') + + cfg_path = os.path.join(directory, 'setup.cfg') + with open(cfg_path, 'w') as f: + parser.write(f) + + def get_sut_info(self, directory, sut_dir='sut'): + if not os.path.isdir(directory): + raise OSError('No such directory: %s' % directory) + + self._generate_ansible_cfg(directory) + + prefix = 'tmp' + self.gen_inventory_ini_dict() + ini_file = self._gen_ansible_inventory_file(directory, prefix=prefix) + with ini_file as f: + inventory_path = str(f) + + self._exec_get_sut_info_cmd(directory, inventory_path, sut_dir) + + sut_dir = os.path.join(directory, sut_dir) + sut_info = self._gen_sut_info_dict(sut_dir) + + return sut_info + + def _exec_get_sut_info_cmd(self, directory, inventory_path, sut_dir): + cmd = ['ansible', 'all', '-m', 'setup', '-i', + inventory_path, '--tree', sut_dir] + + proc = Popen(cmd, stdout=PIPE, cwd=directory) + output, _ = proc.communicate() + retcode = proc.wait() + LOG.debug("exit status = %s", retcode) + if retcode != 0: + raise CalledProcessError(retcode, cmd, output) + + def _gen_sut_info_dict(self, sut_dir): + sut_info = {} + + if os.path.isdir(sut_dir): + root, _, files = next(os.walk(sut_dir)) + for filename in files: + abs_path = os.path.join(root, filename) + with open(abs_path) as f: + data = jsonutils.load(f) + sut_info[filename] = data + + return sut_info + def execute_ansible(self, playbooks, directory, timeout=None, extra_vars=None, ansible_check=False, prefix='tmp', verbose=False): diff --git a/yardstick/common/constants.py b/yardstick/common/constants.py index 43c2c19cb..153bd4bf4 100644 --- a/yardstick/common/constants.py +++ b/yardstick/common/constants.py @@ -145,6 +145,10 @@ BASE_URL = 'http://localhost:5000' ENV_ACTION_API = BASE_URL + '/yardstick/env/action' ASYNC_TASK_API = BASE_URL + '/yardstick/asynctask' +# flags +IS_EXISTING = 'is_existing' +IS_PUBLIC = 'is_public' + # general TESTCASE_PRE = 'opnfv_yardstick_' TESTSUITE_PRE = 'opnfv_' diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index 9946bf1cb..633b36f91 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -67,7 +67,7 @@ class YardstickBannedModuleImported(YardstickException): class HeatTemplateError(YardstickException): """Error in Heat during the stack deployment""" message = ('Error in Heat during the creation of the OpenStack stack ' - '"%(stack_name)"') + '"%(stack_name)s"') class IPv6RangeError(YardstickException): @@ -100,3 +100,23 @@ class TaskReadError(YardstickException): class TaskRenderError(YardstickException): message = 'Failed to render template:\n%(input_task)s' + + +class ScenarioCreateNetworkError(YardstickException): + message = 'Create Neutron Network Scenario failed' + + +class ScenarioCreateSubnetError(YardstickException): + message = 'Create Neutron Subnet Scenario failed' + + +class ScenarioDeleteRouterError(YardstickException): + message = 'Delete Neutron Router Scenario failed' + + +class MissingPodInfoError(YardstickException): + message = 'Missing pod args, please check' + + +class UnsupportedPodFormatError(YardstickException): + message = 'Failed to load pod info, unsupported format' diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py index e3f67baa5..84bfbbbb1 100644 --- a/yardstick/common/openstack_utils.py +++ b/yardstick/common/openstack_utils.py @@ -435,13 +435,29 @@ def get_network_id(shade_client, network_name): return networks[0]['id'] -def create_neutron_net(neutron_client, json_body): # pragma: no cover +def create_neutron_net(shade_client, network_name, shared=False, + admin_state_up=True, external=False, provider=None, + project_id=None): + """Create a neutron network. + + :param network_name:(string) name of the network being created. + :param shared:(bool) whether the network is shared. + :param admin_state_up:(bool) set the network administrative state. + :param external:(bool) whether this network is externally accessible. + :param provider:(dict) a dict of network provider options. + :param project_id:(string) specify the project ID this network + will be created on (admin-only). + :returns:(string) the network id. + """ try: - network = neutron_client.create_network(body=json_body) - return network['network']['id'] - except Exception: # pylint: disable=broad-except - log.error("Error [create_neutron_net(neutron_client)]") - raise Exception("operation error") + networks = shade_client.create_network( + name=network_name, shared=shared, admin_state_up=admin_state_up, + external=external, provider=provider, project_id=project_id) + return networks['id'] + except exc.OpenStackCloudException as o_exc: + log.error("Error [create_neutron_net(shade_client)]." + "Exception message, '%s'", o_exc.orig_message) + return None def delete_neutron_net(shade_client, network_id): @@ -452,13 +468,55 @@ def delete_neutron_net(shade_client, network_id): return False -def create_neutron_subnet(neutron_client, json_body): # pragma: no cover +def create_neutron_subnet(shade_client, network_name_or_id, cidr=None, + ip_version=4, enable_dhcp=False, subnet_name=None, + tenant_id=None, allocation_pools=None, + gateway_ip=None, disable_gateway_ip=False, + dns_nameservers=None, host_routes=None, + ipv6_ra_mode=None, ipv6_address_mode=None, + use_default_subnetpool=False): + """Create a subnet on a specified network. + + :param network_name_or_id:(string) the unique name or ID of the + attached network. If a non-unique name is + supplied, an exception is raised. + :param cidr:(string) the CIDR. + :param ip_version:(int) the IP version. + :param enable_dhcp:(bool) whether DHCP is enable. + :param subnet_name:(string) the name of the subnet. + :param tenant_id:(string) the ID of the tenant who owns the network. + :param allocation_pools: A list of dictionaries of the start and end + addresses for the allocation pools. + :param gateway_ip:(string) the gateway IP address. + :param disable_gateway_ip:(bool) whether gateway IP address is enabled. + :param dns_nameservers: A list of DNS name servers for the subnet. + :param host_routes: A list of host route dictionaries for the subnet. + :param ipv6_ra_mode:(string) IPv6 Router Advertisement mode. + Valid values are: 'dhcpv6-stateful', + 'dhcpv6-stateless', or 'slaac'. + :param ipv6_address_mode:(string) IPv6 address mode. + Valid values are: 'dhcpv6-stateful', + 'dhcpv6-stateless', or 'slaac'. + :param use_default_subnetpool:(bool) use the default subnetpool for + ``ip_version`` to obtain a CIDR. It is + required to pass ``None`` to the ``cidr`` + argument when enabling this option. + :returns:(string) the subnet id. + """ try: - subnet = neutron_client.create_subnet(body=json_body) - return subnet['subnets'][0]['id'] - except Exception: # pylint: disable=broad-except - log.error("Error [create_neutron_subnet") - raise Exception("operation error") + subnet = shade_client.create_subnet( + network_name_or_id, cidr=cidr, ip_version=ip_version, + enable_dhcp=enable_dhcp, subnet_name=subnet_name, + tenant_id=tenant_id, allocation_pools=allocation_pools, + gateway_ip=gateway_ip, disable_gateway_ip=disable_gateway_ip, + dns_nameservers=dns_nameservers, host_routes=host_routes, + ipv6_ra_mode=ipv6_ra_mode, ipv6_address_mode=ipv6_address_mode, + use_default_subnetpool=use_default_subnetpool) + return subnet['id'] + except exc.OpenStackCloudException as o_exc: + log.error("Error [create_neutron_subnet(shade_client)]. " + "Exception message: %s", o_exc.orig_message) + return None def create_neutron_router(neutron_client, json_body): # pragma: no cover @@ -470,13 +528,12 @@ def create_neutron_router(neutron_client, json_body): # pragma: no cover raise Exception("operation error") -def delete_neutron_router(neutron_client, router_id): # pragma: no cover +def delete_neutron_router(shade_client, router_id): try: - neutron_client.delete_router(router=router_id) - return True - except Exception: # pylint: disable=broad-except - log.error("Error [delete_neutron_router(neutron_client, '%s')]", - router_id) + return shade_client.delete_router(router_id) + except exc.OpenStackCloudException as o_exc: + log.error("Error [delete_neutron_router(shade_client, '%s')]. " + "Exception message: %s", router_id, o_exc.orig_message) return False diff --git a/yardstick/network_services/constants.py b/yardstick/network_services/constants.py index 79951e353..0064b4fc5 100644 --- a/yardstick/network_services/constants.py +++ b/yardstick/network_services/constants.py @@ -15,3 +15,5 @@ REMOTE_TMP = "/tmp" DEFAULT_VNF_TIMEOUT = 3600 PROCESS_JOIN_TIMEOUT = 3 +ONE_GIGABIT_IN_BITS = 1000000000 +NIC_GBPS_DEFAULT = 10 diff --git a/yardstick/network_services/traffic_profile/prox_binsearch.py b/yardstick/network_services/traffic_profile/prox_binsearch.py index 5700f98e5..c3277fb12 100644 --- a/yardstick/network_services/traffic_profile/prox_binsearch.py +++ b/yardstick/network_services/traffic_profile/prox_binsearch.py @@ -20,6 +20,7 @@ import datetime import time from yardstick.network_services.traffic_profile.prox_profile import ProxProfile +from yardstick.network_services import constants LOG = logging.getLogger(__name__) @@ -99,9 +100,13 @@ class ProxBinSearchProfile(ProxProfile): # throughput and packet loss from the most recent successful test successful_pkt_loss = 0.0 + line_speed = traffic_gen.scenario_helper.all_options.get( + "interface_speed_gbps", constants.NIC_GBPS_DEFAULT) * constants.ONE_GIGABIT_IN_BITS for test_value in self.bounds_iterator(LOG): result, port_samples = self._profile_helper.run_test(pkt_size, duration, - test_value, self.tolerated_loss) + test_value, + self.tolerated_loss, + line_speed) self.curr_time = time.time() diff_time = self.curr_time - self.prev_time self.prev_time = self.curr_time diff --git a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py index 29f9c7bba..e42431f94 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py @@ -35,6 +35,7 @@ from yardstick.common.utils import SocketTopology, join_non_strings, try_int from yardstick.network_services.helpers.iniparser import ConfigParser from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper +from yardstick.network_services import constants PROX_PORT = 8474 @@ -44,7 +45,6 @@ SECTION_CONTENTS = 1 LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) -TEN_GIGABIT = 1e10 BITS_PER_BYTE = 8 RETRY_SECONDS = 60 RETRY_INTERVAL = 1 @@ -466,13 +466,14 @@ class ProxSocketHelper(object): core_data['current'] = core_data[key1] + core_data[key2] self.set_speed(core_data['cores'], core_data['current']) - def set_pps(self, cores, pps, pkt_size): + def set_pps(self, cores, pps, pkt_size, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): """ set packets per second for specific cores on the remote instance """ msg = "Set packets per sec for core(s) %s to %g%% of line rate (packet size: %d)" LOG.debug(msg, cores, pps, pkt_size) # speed in percent of line-rate - speed = float(pps) * (pkt_size + 20) / TEN_GIGABIT / BITS_PER_BYTE + speed = float(pps) * (pkt_size + 20) / line_speed / BITS_PER_BYTE self._run_template_over_cores("speed {} 0 {}\n", cores, speed) def lat_stats(self, cores, task=0): @@ -967,12 +968,13 @@ class ProxResourceHelper(ClientResourceHelper): class ProxDataHelper(object): - def __init__(self, vnfd_helper, sut, pkt_size, value, tolerated_loss): + def __init__(self, vnfd_helper, sut, pkt_size, value, tolerated_loss, line_speed): super(ProxDataHelper, self).__init__() self.vnfd_helper = vnfd_helper self.sut = sut self.pkt_size = pkt_size self.value = value + self.line_speed = line_speed self.tolerated_loss = tolerated_loss self.port_count = len(self.vnfd_helper.port_pairs.all_ports) self.tsc_hz = None @@ -1058,9 +1060,7 @@ class ProxDataHelper(object): self.tsc_hz = float(self.sut.hz()) def line_rate_to_pps(self): - # NOTE: to fix, don't hardcode 10Gb/s - return self.port_count * TEN_GIGABIT / BITS_PER_BYTE / (self.pkt_size + 20) - + return self.port_count * self.line_speed / BITS_PER_BYTE / (self.pkt_size + 20) class ProxProfileHelper(object): @@ -1139,8 +1139,10 @@ class ProxProfileHelper(object): return cores - def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): - data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, + value, tolerated_loss, line_speed) with data_helper, self.traffic_context(pkt_size, value): with data_helper.measure_tot_stats(): @@ -1396,8 +1398,10 @@ class ProxBngProfileHelper(ProxProfileHelper): time.sleep(3) self.sut.stop(self.all_rx_cores) - def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): - data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, + value, tolerated_loss, line_speed) with data_helper, self.traffic_context(pkt_size, value): with data_helper.measure_tot_stats(): @@ -1583,8 +1587,10 @@ class ProxVpeProfileHelper(ProxProfileHelper): time.sleep(3) self.sut.stop(self.all_rx_cores) - def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): - data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, + value, tolerated_loss, line_speed) with data_helper, self.traffic_context(pkt_size, value): with data_helper.measure_tot_stats(): @@ -1772,8 +1778,10 @@ class ProxlwAFTRProfileHelper(ProxProfileHelper): time.sleep(3) self.sut.stop(self.all_rx_cores) - def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): - data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, + value, tolerated_loss, line_speed) with data_helper, self.traffic_context(pkt_size, value): with data_helper.measure_tot_stats(): diff --git a/yardstick/network_services/vnf_generic/vnf/prox_vnf.py b/yardstick/network_services/vnf_generic/vnf/prox_vnf.py index 2cdb3f904..285e08659 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_vnf.py @@ -22,7 +22,7 @@ from yardstick.common.process import check_if_process_failed from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxDpdkVnfSetupEnvHelper from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxResourceHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF -from yardstick.network_services.constants import PROCESS_JOIN_TIMEOUT +from yardstick.network_services import constants LOG = logging.getLogger(__name__) @@ -136,5 +136,5 @@ class ProxApproxVnf(SampleVNF): self._tear_down() if self._vnf_process is not None: LOG.debug("joining before terminate %s", self._vnf_process.name) - self._vnf_process.join(PROCESS_JOIN_TIMEOUT) + self._vnf_process.join(constants.PROCESS_JOIN_TIMEOUT) self._vnf_process.terminate() diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py index f16b4142d..addbd9aa4 100644 --- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py @@ -32,9 +32,7 @@ from yardstick.benchmark.contexts.base import Context from yardstick.common import exceptions as y_exceptions from yardstick.common.process import check_if_process_failed from yardstick.common import utils -from yardstick.network_services.constants import DEFAULT_VNF_TIMEOUT -from yardstick.network_services.constants import PROCESS_JOIN_TIMEOUT -from yardstick.network_services.constants import REMOTE_TMP +from yardstick.network_services import constants from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper, DpdkNode from yardstick.network_services.helpers.samplevnf_helper import MultiPortConfig from yardstick.network_services.helpers.samplevnf_helper import PortPairs @@ -51,8 +49,8 @@ LOG = logging.getLogger(__name__) class SetupEnvHelper(object): - CFG_CONFIG = os.path.join(REMOTE_TMP, "sample_config") - CFG_SCRIPT = os.path.join(REMOTE_TMP, "sample_script") + CFG_CONFIG = os.path.join(constants.REMOTE_TMP, "sample_config") + CFG_SCRIPT = os.path.join(constants.REMOTE_TMP, "sample_script") DEFAULT_CONFIG_TPL_CFG = "sample.cfg" PIPELINE_COMMAND = '' VNF_TYPE = "SAMPLE" @@ -371,7 +369,7 @@ class ClientResourceHelper(ResourceHelper): try: return self.client.get_stats(*args, **kwargs) except STLError: - LOG.exception("TRex client not connected") + LOG.error('TRex client not connected') return {} def generate_samples(self, ports, key=None, default=None): @@ -609,8 +607,10 @@ class ScenarioHelper(object): @property def timeout(self): - return self.options.get('timeout', DEFAULT_VNF_TIMEOUT) - + test_duration = self.scenario_cfg.get('runner', {}).get('duration', + self.options.get('timeout', constants.DEFAULT_VNF_TIMEOUT)) + test_timeout = self.options.get('timeout', constants.DEFAULT_VNF_TIMEOUT) + return test_duration if test_duration > test_timeout else test_timeout class SampleVNF(GenericVNF): """ Class providing file-like API for generic VNF implementation """ @@ -794,7 +794,7 @@ class SampleVNF(GenericVNF): if self._vnf_process is not None: # be proper and join first before we kill LOG.debug("joining before terminate %s", self._vnf_process.name) - self._vnf_process.join(PROCESS_JOIN_TIMEOUT) + self._vnf_process.join(constants.PROCESS_JOIN_TIMEOUT) self._vnf_process.terminate() # no terminate children here because we share processes with tg @@ -938,12 +938,12 @@ class SampleVNFTrafficGen(GenericTrafficGen): if self._traffic_process is not None: # be proper and try to join before terminating LOG.debug("joining before terminate %s", self._traffic_process.name) - self._traffic_process.join(PROCESS_JOIN_TIMEOUT) + self._traffic_process.join(constants.PROCESS_JOIN_TIMEOUT) self._traffic_process.terminate() if self._tg_process is not None: # be proper and try to join before terminating LOG.debug("joining before terminate %s", self._tg_process.name) - self._tg_process.join(PROCESS_JOIN_TIMEOUT) + self._tg_process.join(constants.PROCESS_JOIN_TIMEOUT) self._tg_process.terminate() # no terminate children here because we share processes with vnf diff --git a/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py b/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py index 8e02cf3ac..de6fd9329 100644 --- a/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py +++ b/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py @@ -17,7 +17,7 @@ import os from six.moves import StringIO -from yardstick.network_services.constants import REMOTE_TMP +from yardstick.network_services import constants from yardstick.ssh import AutoConnectSSH LOG = logging.getLogger(__name__) @@ -46,7 +46,7 @@ class VnfSshHelper(AutoConnectSSH): return self.get_class()(self.node, self.bin_path) def upload_config_file(self, prefix, content): - cfg_file = os.path.join(REMOTE_TMP, prefix) + cfg_file = os.path.join(constants.REMOTE_TMP, prefix) LOG.debug(content) file_obj = StringIO(content) self.put_file_obj(file_obj, cfg_file) diff --git a/yardstick/orchestrator/heat.py b/yardstick/orchestrator/heat.py index 20be89f57..d69f86044 100644 --- a/yardstick/orchestrator/heat.py +++ b/yardstick/orchestrator/heat.py @@ -26,6 +26,7 @@ import shade import yardstick.common.openstack_utils as op_utils from yardstick.common import exceptions from yardstick.common import template_format +from yardstick.common import constants as consts log = logging.getLogger(__name__) @@ -333,21 +334,24 @@ name (i.e. %s). } } - def add_port(self, name, network_name, subnet_name, vnic_type, sec_group_id=None, + def add_port(self, name, network, sec_group_id=None, provider=None, allowed_address_pairs=None): """add to the template a named Neutron Port """ - log.debug("adding Neutron::Port '%s', network:'%s', subnet:'%s', vnic_type:'%s', " - "secgroup:%s", name, network_name, subnet_name, vnic_type, sec_group_id) + net_is_existing = network.net_flags.get(consts.IS_EXISTING) + depends_on = [] if net_is_existing else [network.subnet_stack_name] + fixed_ips = [{'subnet': network.subnet}] if net_is_existing else [ + {'subnet': {'get_resource': network.subnet_stack_name}}] + network_ = network.name if net_is_existing else { + 'get_resource': network.stack_name} self.resources[name] = { 'type': 'OS::Neutron::Port', - 'depends_on': [subnet_name], + 'depends_on': depends_on, 'properties': { 'name': name, - 'binding:vnic_type': vnic_type, - 'fixed_ips': [{'subnet': {'get_resource': subnet_name}}], - 'network_id': {'get_resource': network_name}, - 'replacement_policy': 'AUTO', + 'binding:vnic_type': network.vnic_type, + 'fixed_ips': fixed_ips, + 'network': network_, } } @@ -364,6 +368,8 @@ name (i.e. %s). self.resources[name]['properties'][ 'allowed_address_pairs'] = allowed_address_pairs + log.debug("adding Neutron::Port %s", self.resources[name]) + self._template['outputs'][name] = { 'description': 'Address for interface %s' % name, 'value': {'get_attr': [name, 'fixed_ips', 0, 'ip_address']} diff --git a/yardstick/service/__init__.py b/yardstick/service/__init__.py new file mode 100644 index 000000000..1c3953de6 --- /dev/null +++ b/yardstick/service/__init__.py @@ -0,0 +1,12 @@ +############################################################################## +# Copyright (c) 2016 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 +############################################################################## + + +class Service(object): + pass diff --git a/yardstick/service/environment.py b/yardstick/service/environment.py new file mode 100644 index 000000000..324589f79 --- /dev/null +++ b/yardstick/service/environment.py @@ -0,0 +1,101 @@ +############################################################################## +# Copyright (c) 2016 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 tempfile +import logging +import collections + +from oslo_serialization import jsonutils + +from yardstick.service import Service +from yardstick.common.exceptions import MissingPodInfoError +from yardstick.common.exceptions import UnsupportedPodFormatError +from yardstick.common.ansible_common import AnsibleCommon + +LOG = logging.getLogger(__name__) + + +class Environment(Service): + def __init__(self, pod=None): + super(Environment, self).__init__() + # pod can be a dict or a json format string + self.pod = pod + + def get_sut_info(self): + temdir = tempfile.mkdtemp(prefix='sut') + + nodes = self._load_pod_info() + ansible = AnsibleCommon(nodes=nodes) + ansible.gen_inventory_ini_dict() + sut_info = ansible.get_sut_info(temdir) + + return self._format_sut_info(sut_info) + + def _load_pod_info(self): + if self.pod is None: + raise MissingPodInfoError + + if isinstance(self.pod, collections.Mapping): + try: + return self.pod['nodes'] + except KeyError: + raise UnsupportedPodFormatError + + try: + return jsonutils.loads(self.pod)['nodes'] + except (ValueError, KeyError): + raise UnsupportedPodFormatError + + def _format_sut_info(self, sut_info): + return {k: self._format_node_info(v) for k, v in sut_info.items()} + + def _format_node_info(self, node_info): + info = [] + facts = node_info.get('ansible_facts', {}) + + info.append(['hostname', facts.get('ansible_hostname')]) + + info.append(['product_name', facts.get('ansible_product_name')]) + info.append(['product_version', facts.get('ansible_product_version')]) + + processors = facts.get('ansible_processor', []) + try: + processor_type = '{} {}'.format(processors[0], processors[1]) + except IndexError: + LOG.exception('No Processor in SUT data') + processor_type = None + + info.append(['processor_type', processor_type]) + info.append(['architecture', facts.get('ansible_architecture')]) + info.append(['processor_cores', facts.get('ansible_processor_cores')]) + info.append(['processor_vcpus', facts.get('ansible_processor_vcpus')]) + + memory = facts.get('ansible_memtotal_mb') + memory = round(memory * 1.0 / 1024, 2) if memory else None + info.append(['memory', '{} GB'.format(memory)]) + + devices = facts.get('ansible_devices', {}) + info.extend([self._get_device_info(k, v) for k, v in devices.items()]) + + lsb_description = facts.get('ansible_lsb', {}).get('description') + info.append(['OS', lsb_description]) + + interfaces = facts.get('ansible_interfaces') + info.append(['interfaces', interfaces]) + if isinstance(interfaces, collections.Sequence): + info.extend([self._get_interface_info(facts, i) for i in interfaces]) + info = [i for i in info if i] + + return info + + def _get_interface_info(self, facts, name): + mac = facts.get('ansible_{}'.format(name), {}).get('macaddress') + return [name, mac] if mac else [] + + def _get_device_info(self, name, info): + return ['disk_{}'.format(name), info.get('size')] diff --git a/yardstick/tests/unit/benchmark/contexts/test_heat.py b/yardstick/tests/unit/benchmark/contexts/test_heat.py index f48d6f32c..625f97bf4 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_heat.py +++ b/yardstick/tests/unit/benchmark/contexts/test_heat.py @@ -10,17 +10,16 @@ from collections import OrderedDict from itertools import count import logging +import os import mock import unittest -import shade - from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts import heat from yardstick.benchmark.contexts import model +from yardstick.common import constants as consts from yardstick.common import exceptions as y_exc -from yardstick.orchestrator import heat as orch_heat from yardstick import ssh @@ -62,12 +61,11 @@ class HeatContextTestCase(unittest.TestCase): self.assertIsNone(self.test_context.heat_parameters) self.assertIsNone(self.test_context.key_filename) - @mock.patch.object(ssh.SSH, 'gen_keys') @mock.patch('yardstick.benchmark.contexts.heat.PlacementGroup') @mock.patch('yardstick.benchmark.contexts.heat.ServerGroup') @mock.patch('yardstick.benchmark.contexts.heat.Network') @mock.patch('yardstick.benchmark.contexts.heat.Server') - def test_init(self, mock_server, mock_network, mock_sg, mock_pg, mock_ssh_gen_keys): + def test_init(self, mock_server, mock_network, mock_sg, mock_pg): pgs = {'pgrp1': {'policy': 'availability'}} sgs = {'servergroup1': {'policy': 'affinity'}} @@ -105,8 +103,6 @@ class HeatContextTestCase(unittest.TestCase): servers['baz']) self.assertEqual(len(self.test_context.servers), 1) - mock_ssh_gen_keys.assert_called() - def test_init_no_name_or_task_id(self): attrs = {} self.assertRaises(KeyError, self.test_context.init, attrs) @@ -128,8 +124,7 @@ class HeatContextTestCase(unittest.TestCase): self.assertEqual(self.test_context.name, 'foo') self.assertEqual(self.test_context.assigned_name, 'foo') - @mock.patch('yardstick.ssh.SSH.gen_keys') - def test_init_no_setup_no_teardown(self, *args): + def test_init_no_setup_no_teardown(self): attrs = {'name': 'foo', 'task_id': '1234567890', @@ -222,9 +217,11 @@ class HeatContextTestCase(unittest.TestCase): self.test_context._create_new_stack, template) - @mock.patch.object(orch_heat.HeatTemplate, 'add_keypair') + @mock.patch.object(os.path, 'exists', return_value=True) + @mock.patch.object(heat.HeatContext, '_add_resources_to_template') @mock.patch.object(heat.HeatContext, '_create_new_stack') - def test_deploy_stack_creation_failed(self, mock_create, *args): + def test_deploy_stack_creation_failed(self, mock_create, + mock_resources_template, mock_path_exists): self.test_context._name = 'foo' self.test_context._task_id = '1234567890' self.test_context._name_task_id = 'foo-12345678' @@ -232,8 +229,13 @@ class HeatContextTestCase(unittest.TestCase): self.assertRaises(y_exc.HeatTemplateError, self.test_context.deploy) + mock_path_exists.assert_called_once() + mock_resources_template.assert_called_once() + + @mock.patch.object(os.path, 'exists', return_value=False) + @mock.patch.object(ssh.SSH, 'gen_keys') @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') - def test_deploy(self, mock_template): + def test_deploy(self, mock_template, mock_genkeys, mock_path_exists): self.test_context._name = 'foo' self.test_context._task_id = '1234567890' self.test_context._name_task_id = '{}-{}'.format( @@ -247,46 +249,98 @@ class HeatContextTestCase(unittest.TestCase): '/bar/baz/some-heat-file', {'image': 'cirros'}) self.assertIsNotNone(self.test_context.stack) + key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.test_context._name_task_id]) + mock_genkeys.assert_called_once_with(key_filename) + mock_path_exists.assert_called_once_with(key_filename) - # TODO: patch objects @mock.patch.object(heat, 'HeatTemplate') + @mock.patch.object(os.path, 'exists', return_value=False) + @mock.patch.object(ssh.SSH, 'gen_keys') @mock.patch.object(heat.HeatContext, '_retrieve_existing_stack') @mock.patch.object(heat.HeatContext, '_create_new_stack') - def test_deploy_no_setup(self, mock_create_new_stack, mock_retrieve_existing_stack, *args): + def test_deploy_no_setup(self, mock_create_new_stack, + mock_retrieve_existing_stack, mock_genkeys, mock_path_exists, + *args): self.test_context._name = 'foo' self.test_context._task_id = '1234567890' - # Might be able to get rid of these self.test_context.template_file = '/bar/baz/some-heat-file' self.test_context.heat_parameters = {'image': 'cirros'} self.test_context.get_neutron_info = mock.MagicMock() self.test_context._flags.no_setup = True self.test_context.deploy() - # check that heat client is called... mock_create_new_stack.assert_not_called() mock_retrieve_existing_stack.assert_called_with(self.test_context.name) self.assertIsNotNone(self.test_context.stack) + key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.test_context._name]) + mock_genkeys.assert_called_once_with(key_filename) + mock_path_exists.assert_called_once_with(key_filename) - @mock.patch.object(shade, 'openstack_cloud') - @mock.patch.object(heat.HeatTemplate, 'add_keypair') + @mock.patch.object(heat, 'HeatTemplate') + @mock.patch.object(os.path, 'exists', return_value=False) + @mock.patch.object(ssh.SSH, 'gen_keys') @mock.patch.object(heat.HeatContext, '_create_new_stack') - @mock.patch.object(heat.HeatStack, 'get') + @mock.patch.object(heat.HeatContext, '_retrieve_existing_stack', + return_value=None) def test_deploy_try_retrieve_context_does_not_exist(self, - mock_get_stack, - mock_create_new_stack, - *args): + mock_retrieve_stack, mock_create_new_stack, mock_genkeys, + mock_path_exists, *args): self.test_context._name = 'demo' self.test_context._task_id = '1234567890' self.test_context._flags.no_setup = True + self.test_context.template_file = '/bar/baz/some-heat-file' self.test_context.get_neutron_info = mock.MagicMock() - # TODo: Check is this the right value to return, should it be None instead? - mock_get_stack.return_value = [] - self.test_context.deploy() - mock_get_stack.assert_called() + mock_retrieve_stack.assert_called_once_with(self.test_context._name) mock_create_new_stack.assert_called() + key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.test_context._name]) + mock_genkeys.assert_called_once_with(key_filename) + mock_path_exists.assert_called_once_with(key_filename) + + @mock.patch.object(heat, 'HeatTemplate', return_value='heat_template') + @mock.patch.object(heat.HeatContext, '_add_resources_to_template') + @mock.patch.object(os.path, 'exists', return_value=False) + @mock.patch.object(ssh.SSH, 'gen_keys') + def test_deploy_ssh_key_before_adding_resources(self, mock_genkeys, + mock_path_exists, mock_add_resources, *args): + mock_manager = mock.Mock() + mock_manager.attach_mock(mock_add_resources, + '_add_resources_to_template') + mock_manager.attach_mock(mock_genkeys, 'gen_keys') + mock_manager.reset_mock() + self.test_context._name_task_id = 'demo-12345678' + self.test_context.get_neutron_info = mock.Mock() + with mock.patch.object(self.test_context, '_create_new_stack') as \ + mock_create_stack, \ + mock.patch.object(self.test_context, 'get_neutron_info') as \ + mock_neutron_info: + self.test_context.deploy() + + mock_neutron_info.assert_called_once() + mock_create_stack.assert_called_once() + key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.test_context._name_task_id]) + mock_genkeys.assert_called_once_with(key_filename) + mock_path_exists.assert_called_with(key_filename) + + mock_call_gen_keys = mock.call.gen_keys(key_filename) + mock_call_add_resources = ( + mock.call._add_resources_to_template('heat_template')) + self.assertTrue(mock_manager.mock_calls.index(mock_call_gen_keys) < + mock_manager.mock_calls.index(mock_call_add_resources)) def test_check_for_context(self): pass @@ -326,6 +380,7 @@ class HeatContextTestCase(unittest.TestCase): u'e-network_id': u'net987', } server = mock.MagicMock() + server.private_ip = None server.ports = OrderedDict([ ('a', [{'stack_name': 'b', 'port': 'port_a'}]), ('c', [{'stack_name': 'd', 'port': 'port_c'}, @@ -365,7 +420,7 @@ class HeatContextTestCase(unittest.TestCase): self.test_context.key_filename = 'foo/bar/foobar' self.test_context.undeploy() mock_delete_key.assert_called() - self.assertTrue(mock_template.delete.called) + mock_template.delete.assert_called_once() @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') def test_undeploy_no_teardown(self, mock_template): diff --git a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py index 22153e4e8..4dd9d40d1 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py +++ b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py @@ -58,10 +58,10 @@ class KubernetesTestCase(unittest.TestCase): mock_delete_services): self.k8s_context.undeploy() - self.assertTrue(mock_delete_ssh.called) - self.assertTrue(mock_delete_rcs.called) - self.assertTrue(mock_delete_pods.called) - self.assertTrue(mock_delete_services.called) + mock_delete_ssh.assert_called_once() + mock_delete_rcs.assert_called_once() + mock_delete_pods.assert_called_once() + mock_delete_services.assert_called_once() @mock.patch.object(kubernetes.KubernetesContext, '_create_services') @mock.patch.object(kubernetes.KubernetesContext, '_wait_until_running') @@ -77,11 +77,11 @@ class KubernetesTestCase(unittest.TestCase): with mock.patch("yardstick.benchmark.contexts.kubernetes.time"): self.k8s_context.deploy() - self.assertTrue(mock_set_ssh_key.called) - self.assertTrue(mock_create_rcs.called) - self.assertTrue(mock_create_services.called) - self.assertTrue(mock_get_rc_pods.called) - self.assertTrue(mock_wait_until_running.called) + mock_set_ssh_key.assert_called_once() + mock_create_rcs.assert_called_once() + mock_create_services.assert_called_once() + mock_get_rc_pods.assert_called_once() + mock_wait_until_running.assert_called_once() @mock.patch.object(kubernetes, 'paramiko', **{"resource_filename.return_value": ""}) @mock.patch.object(kubernetes, 'pkg_resources', **{"resource_filename.return_value": ""}) @@ -93,8 +93,8 @@ class KubernetesTestCase(unittest.TestCase): self.k8s_context._set_ssh_key() self.k8s_context._delete_ssh_key() - self.assertTrue(mock_create.called) - self.assertTrue(mock_delete.called) + mock_create.assert_called_once() + mock_delete.assert_called_once() @mock.patch.object(kubernetes.k8s_utils, 'read_pod_status') def test_wait_until_running(self, mock_read_pod_status): @@ -136,34 +136,34 @@ class KubernetesTestCase(unittest.TestCase): @mock.patch.object(kubernetes.KubernetesContext, '_create_rc') def test_create_rcs(self, mock_create_rc): self.k8s_context._create_rcs() - self.assertTrue(mock_create_rc.called) + mock_create_rc.assert_called() @mock.patch.object(kubernetes.k8s_utils, 'create_replication_controller') def test_create_rc(self, mock_create_replication_controller): self.k8s_context._create_rc({}) - self.assertTrue(mock_create_replication_controller.called) + mock_create_replication_controller.assert_called_once() @mock.patch.object(kubernetes.KubernetesContext, '_delete_rc') def test_delete_rcs(self, mock_delete_rc): self.k8s_context._delete_rcs() - self.assertTrue(mock_delete_rc.called) + mock_delete_rc.assert_called() @mock.patch.object(kubernetes.k8s_utils, 'delete_replication_controller') def test_delete_rc(self, mock_delete_replication_controller): self.k8s_context._delete_rc({}) - self.assertTrue(mock_delete_replication_controller.called) + mock_delete_replication_controller.assert_called_once() @mock.patch.object(kubernetes.k8s_utils, 'get_node_list') def test_get_node_ip(self, mock_get_node_list): self.k8s_context._get_node_ip() - self.assertTrue(mock_get_node_list.called) + mock_get_node_list.assert_called_once() @mock.patch('yardstick.orchestrator.kubernetes.ServiceObject.create') def test_create_services(self, mock_create): self.k8s_context._create_services() - self.assertTrue(mock_create.called) + mock_create.assert_called() @mock.patch('yardstick.orchestrator.kubernetes.ServiceObject.delete') def test_delete_services(self, mock_delete): self.k8s_context._delete_services() - self.assertTrue(mock_delete.called) + mock_delete.assert_called() diff --git a/yardstick/tests/unit/benchmark/contexts/test_model.py b/yardstick/tests/unit/benchmark/contexts/test_model.py index 76c4da533..20cc00b4e 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_model.py +++ b/yardstick/tests/unit/benchmark/contexts/test_model.py @@ -239,6 +239,7 @@ class ServerTestCase(unittest.TestCase): mock_network.vnic_type = 'normal' mock_network.subnet_stack_name = 'some-network-stack-subnet' mock_network.provider = 'sriov' + mock_network.net_flags = {} mock_network.external_network = 'ext_net' mock_network.router = model.Router('some-router', 'some-network', self.mock_context, 'ext_net') @@ -248,9 +249,7 @@ class ServerTestCase(unittest.TestCase): mock_template.add_port.assert_called_with( 'some-server-some-network-port', - mock_network.stack_name, - mock_network.subnet_stack_name, - mock_network.vnic_type, + mock_network, sec_group_id=self.mock_context.secgroup_name, provider=mock_network.provider, allowed_address_pairs=mock_network.allowed_address_pairs) @@ -511,6 +510,7 @@ class ServerTestCase(unittest.TestCase): mock_network = mock.Mock() mock_network.allowed_address_pairs = ["1", "2"] mock_network.vnic_type = 'normal' + mock_network.net_flags = {} mock_network.configure_mock(name='some-network', stack_name='some-network-stack', subnet_stack_name='some-network-stack-subnet', provider='some-provider') @@ -520,9 +520,7 @@ class ServerTestCase(unittest.TestCase): mock_template.add_port.assert_called_with( 'ServerFlavor-2-some-network-port', - mock_network.stack_name, - mock_network.subnet_stack_name, - mock_network.vnic_type, + mock_network, provider=mock_network.provider, sec_group_id=self.mock_context.secgroup_name, allowed_address_pairs=mock_network.allowed_address_pairs) @@ -554,6 +552,7 @@ class ServerTestCase(unittest.TestCase): mock_network.name = 'some-network' mock_network.stack_name = 'some-network-stack' mock_network.subnet_stack_name = 'some-network-stack-subnet' + mock_network.net_flags = {} test_server._add_instance(mock_template, 'ServerFlavor-3', [mock_network], 'hints') diff --git a/yardstick/tests/unit/benchmark/contexts/test_node.py b/yardstick/tests/unit/benchmark/contexts/test_node.py index 9761f6d53..8b232481b 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_node.py +++ b/yardstick/tests/unit/benchmark/contexts/test_node.py @@ -176,7 +176,7 @@ class NodeContextTestCase(unittest.TestCase): 'type': 'script' } obj.deploy() - self.assertTrue(dispatch_script_mock.called) + dispatch_script_mock.assert_called_once() @mock.patch('{}.NodeContext._dispatch_ansible'.format(PREFIX)) def test_deploy_anisible(self, dispatch_ansible_mock): @@ -186,7 +186,7 @@ class NodeContextTestCase(unittest.TestCase): 'type': 'ansible' } obj.deploy() - self.assertTrue(dispatch_ansible_mock.called) + dispatch_ansible_mock.assert_called_once() @mock.patch('{}.NodeContext._dispatch_script'.format(PREFIX)) def test_undeploy(self, dispatch_script_mock): @@ -195,7 +195,7 @@ class NodeContextTestCase(unittest.TestCase): 'type': 'script' } obj.undeploy() - self.assertTrue(dispatch_script_mock.called) + dispatch_script_mock.assert_called_once() @mock.patch('{}.NodeContext._dispatch_ansible'.format(PREFIX)) def test_undeploy_anisble(self, dispatch_ansible_mock): @@ -204,7 +204,7 @@ class NodeContextTestCase(unittest.TestCase): 'type': 'ansible' } obj.undeploy() - self.assertTrue(dispatch_ansible_mock.called) + dispatch_ansible_mock.assert_called_once() @mock.patch('{}.ssh.SSH._put_file_shell'.format(PREFIX)) @mock.patch('{}.ssh.SSH.execute'.format(PREFIX)) @@ -224,8 +224,8 @@ class NodeContextTestCase(unittest.TestCase): execute_mock.return_value = (0, '', '') obj._execute_remote_script('node5', info) - self.assertTrue(put_file_mock.called) - self.assertTrue(execute_mock.called) + put_file_mock.assert_called_once() + execute_mock.assert_called() @mock.patch('{}.NodeContext._execute_local_script'.format(PREFIX)) def test_execute_script_local(self, local_execute_mock): @@ -234,7 +234,7 @@ class NodeContextTestCase(unittest.TestCase): obj = node.NodeContext() self.addCleanup(obj._delete_context) obj._execute_script(node_name, info) - self.assertTrue(local_execute_mock.called) + local_execute_mock.assert_called_once() @mock.patch('{}.NodeContext._execute_remote_script'.format(PREFIX)) def test_execute_script_remote(self, remote_execute_mock): @@ -243,7 +243,7 @@ class NodeContextTestCase(unittest.TestCase): obj = node.NodeContext() self.addCleanup(obj._delete_context) obj._execute_script(node_name, info) - self.assertTrue(remote_execute_mock.called) + remote_execute_mock.assert_called_once() def test_get_script(self): script_args = 'hello.bash' @@ -276,7 +276,7 @@ class NodeContextTestCase(unittest.TestCase): 'pwd': 'ubuntu', }] obj._get_client(node_name_args) - self.assertTrue(wait_mock.called) + wait_mock.assert_called_once() def test_get_server(self): self.test_context.init(self.attrs) diff --git a/yardstick/tests/unit/benchmark/core/test_task.py b/yardstick/tests/unit/benchmark/core/test_task.py index 82a90b172..1ce30eacb 100644 --- a/yardstick/tests/unit/benchmark/core/test_task.py +++ b/yardstick/tests/unit/benchmark/core/test_task.py @@ -153,7 +153,7 @@ class TaskTestCase(unittest.TestCase): runner.get_result.return_value = [] mock_base_runner.Runner.get.return_value = runner t._run([scenario], False, "yardstick.out") - self.assertTrue(runner.run.called) + runner.run.assert_called_once() @mock.patch.object(os, 'environ') def test_check_precondition(self, mock_os_environ): diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py index 98d967f2b..af4f0c8ab 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py @@ -27,7 +27,7 @@ class AddMemoryLoadTestCase(unittest.TestCase): mock_from_node().execute.return_value = (0, '0 2048 512', '') obj = AddMemoryLoad(scenario_cfg, context_cfg) obj.run({}) - self.assertTrue(mock_from_node.called) + mock_from_node.assert_called() @mock.patch('yardstick.ssh.SSH.from_node') def test_add_memory_load_without_load(self, mock_from_node): @@ -41,7 +41,7 @@ class AddMemoryLoadTestCase(unittest.TestCase): } obj = AddMemoryLoad(scenario_cfg, context_cfg) obj.run({}) - self.assertTrue(mock_from_node.called) + mock_from_node.assert_called_once() @mock.patch('yardstick.ssh.SSH.from_node') def test_add_memory_load_without_args(self, mock_from_node): @@ -54,4 +54,4 @@ class AddMemoryLoadTestCase(unittest.TestCase): } obj = AddMemoryLoad(scenario_cfg, context_cfg) obj.run({}) - self.assertTrue(mock_from_node.called) + mock_from_node.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_attach_volume.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_attach_volume.py index a61195f66..2964ecc14 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_attach_volume.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_attach_volume.py @@ -23,4 +23,4 @@ class AttachVolumeTestCase(unittest.TestCase): args = {"options": options} obj = AttachVolume(args, {}) obj.run({}) - self.assertTrue(mock_attach_server_volume.called) + mock_attach_server_volume.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py index a50e752fa..270c9d3c9 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py @@ -19,7 +19,7 @@ class CheckNumaInfoTestCase(unittest.TestCase): scenario_cfg = {'info1': {}, 'info2': {}} obj = CheckNumaInfo(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_check_vm2.called) + mock_check_vm2.assert_called_once() def test_check_vm2_status_length_eq_1(self): info1 = { diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_flavor.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_flavor.py index 663ca5d5b..0b175fae8 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_flavor.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_flavor.py @@ -26,4 +26,4 @@ class CreateFlavorTestCase(unittest.TestCase): args = {"options": options} obj = CreateFlavor(args, {}) obj.run({}) - self.assertTrue(mock_create_flavor.called) + mock_create_flavor.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_network.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_network.py index ad4adeeb2..17a4ef2e1 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_network.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_network.py @@ -6,25 +6,52 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## + +from oslo_utils import uuidutils import unittest import mock -from yardstick.benchmark.scenarios.lib.create_network import CreateNetwork +from yardstick.common import openstack_utils +from yardstick.common import exceptions +from yardstick.benchmark.scenarios.lib import create_network class CreateNetworkTestCase(unittest.TestCase): - @mock.patch('yardstick.common.openstack_utils.get_neutron_client') - @mock.patch('yardstick.common.openstack_utils.create_neutron_net') - def test_create_network(self, mock_get_neutron_client, mock_create_neutron_net): - options = { - 'openstack_paras': { - 'name': 'yardstick_net', - 'admin_state_up': 'True' - } - } - args = {"options": options} - obj = CreateNetwork(args, {}) - obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_neutron_net.called) + def setUp(self): + + self._mock_create_neutron_net = mock.patch.object( + openstack_utils, 'create_neutron_net') + self.mock_create_neutron_net = self._mock_create_neutron_net.start() + self._mock_get_shade_client = mock.patch.object( + openstack_utils, 'get_shade_client') + self.mock_get_shade_client = self._mock_get_shade_client.start() + self._mock_log = mock.patch.object(create_network, 'LOG') + self.mock_log = self._mock_log.start() + self.args = {'options': {'network_name': 'yardstick_net'}} + self.result = {} + + self._cnet_obj = create_network.CreateNetwork(self.args, mock.ANY) + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_create_neutron_net.stop() + self._mock_get_shade_client.stop() + self._mock_log.stop() + + def test_run(self): + _uuid = uuidutils.generate_uuid() + self._cnet_obj.scenario_cfg = {'output': 'id'} + self.mock_create_neutron_net.return_value = _uuid + output = self._cnet_obj.run(self.result) + self.assertEqual({"network_create": 1}, self.result) + self.assertEqual({'id': _uuid}, output) + self.mock_log.info.asset_called_once_with('Create network successful!') + + def test_run_fail_exception(self): + self.mock_create_neutron_net.return_value = None + with self.assertRaises(exceptions.ScenarioCreateNetworkError): + self._cnet_obj.run(self.result) + self.assertEqual({"network_create": 0}, self.result) + self.mock_log.error.assert_called_once_with( + 'Create network failed!') diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_port.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_port.py index 9a1611c3d..bea02a630 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_port.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_port.py @@ -24,4 +24,4 @@ class CreatePortTestCase(unittest.TestCase): args = {"options": options} obj = CreatePort(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) + mock_get_neutron_client.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_router.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_router.py index 107921403..3469a2a06 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_router.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_router.py @@ -26,5 +26,5 @@ class CreateRouterTestCase(unittest.TestCase): args = {"options": options} obj = CreateRouter(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_neutron_router.called) + mock_get_neutron_client.assert_called_once() + mock_create_neutron_router.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py index b55767360..21158ab17 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py @@ -26,5 +26,5 @@ class CreateSecGroupTestCase(unittest.TestCase): args = {"options": options} obj = CreateSecgroup(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_security_group_full.called) + mock_get_neutron_client.assert_called_once() + mock_create_security_group_full.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_server.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_server.py index faee98fd1..9d6d8cb1b 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_server.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_server.py @@ -28,7 +28,7 @@ class CreateServerTestCase(unittest.TestCase): } obj = CreateServer(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_get_glance_client.called) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_instance_and_wait_for_active.called) + mock_get_nova_client.assert_called_once() + mock_get_glance_client.assert_called_once() + mock_get_neutron_client.assert_called_once() + mock_create_instance_and_wait_for_active.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py index 1536e83e0..856e985c4 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py @@ -6,27 +6,53 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## + +from oslo_utils import uuidutils import unittest import mock -from yardstick.benchmark.scenarios.lib.create_subnet import CreateSubnet +from yardstick.common import openstack_utils +from yardstick.common import exceptions +from yardstick.benchmark.scenarios.lib import create_subnet class CreateSubnetTestCase(unittest.TestCase): - @mock.patch('yardstick.common.openstack_utils.get_neutron_client') - @mock.patch('yardstick.common.openstack_utils.create_neutron_subnet') - def test_create_subnet(self, mock_get_neutron_client, mock_create_neutron_subnet): - options = { - 'openstack_paras': { - 'network_id': '123-123-123', - 'name': 'yardstick_subnet', - 'cidr': '10.10.10.0/24', - 'ip_version': '4' - } - } - args = {"options": options} - obj = CreateSubnet(args, {}) - obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_neutron_subnet.called) + def setUp(self): + + self._mock_create_neutron_subnet = mock.patch.object( + openstack_utils, 'create_neutron_subnet') + self.mock_create_neutron_subnet = ( + self._mock_create_neutron_subnet.start()) + self._mock_get_shade_client = mock.patch.object( + openstack_utils, 'get_shade_client') + self.mock_get_shade_client = self._mock_get_shade_client.start() + self._mock_log = mock.patch.object(create_subnet, 'LOG') + self.mock_log = self._mock_log.start() + self.args = {'options': {'network_name_or_id': 'yardstick_net'}} + self.result = {"subnet_create": 0} + + self._csubnet_obj = create_subnet.CreateSubnet(self.args, mock.ANY) + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_create_neutron_subnet.stop() + self._mock_get_shade_client.stop() + self._mock_log.stop() + + def test_run(self): + _uuid = uuidutils.generate_uuid() + self._csubnet_obj.scenario_cfg = {'output': 'id'} + self.mock_create_neutron_subnet.return_value = _uuid + output = self._csubnet_obj.run(self.result) + self.assertDictEqual({"subnet_create": 1}, self.result) + self.assertDictEqual({'id': _uuid}, output) + self.mock_log.info.asset_called_once_with('Create subnet successful!') + + def test_run_fail(self): + self._csubnet_obj.scenario_cfg = {'output': 'id'} + self.mock_create_neutron_subnet.return_value = None + with self.assertRaises(exceptions.ScenarioCreateSubnetError): + self._csubnet_obj.run(self.result) + self.assertDictEqual({"subnet_create": 0}, self.result) + self.mock_log.error.assert_called_once_with('Create subnet failed!') diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_volume.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_volume.py index 4bfec3252..30333dda8 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_volume.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_volume.py @@ -94,7 +94,7 @@ class CreateVolumeTestCase(unittest.TestCase): args = {"options": options} scenario = create_volume.CreateVolume(args, {}) scenario.run() - self.assertTrue(mock_create_volume.called) - self.assertTrue(mock_image_id.called) - self.assertTrue(mock_get_glance_client.called) - self.assertTrue(mock_get_cinder_client.called) + mock_create_volume.assert_called_once() + mock_image_id.assert_called_once() + mock_get_glance_client.assert_called_once() + mock_get_cinder_client.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py index e345afe3c..24dbf8a16 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py @@ -23,5 +23,5 @@ class DeleteFlavorTestCase(unittest.TestCase): args = {"options": options} obj = DeleteFlavor(args, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_delete_flavor.called) + mock_get_nova_client.assert_called_once() + mock_delete_flavor.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_floating_ip.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_floating_ip.py index be997199c..3185ec59f 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_floating_ip.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_floating_ip.py @@ -23,5 +23,5 @@ class DeleteFloatingIpTestCase(unittest.TestCase): args = {"options": options} obj = DeleteFloatingIp(args, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_delete_floating_ip.called) + mock_get_nova_client.assert_called_once() + mock_delete_floating_ip.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py index eb3f9fc85..e382d46fa 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py @@ -24,6 +24,6 @@ class DeleteImageTestCase(unittest.TestCase): args = {"options": options} obj = DeleteImage(args, {}) obj.run({}) - self.assertTrue(mock_delete_image.called) - self.assertTrue(mock_image_id.called) - self.assertTrue(mock_get_glance_client.called) + mock_delete_image.assert_called_once() + mock_image_id.assert_called_once() + mock_get_glance_client.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_keypair.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_keypair.py index 38cc929c0..6e790ba90 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_keypair.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_keypair.py @@ -23,5 +23,5 @@ class DeleteKeypairTestCase(unittest.TestCase): args = {"options": options} obj = DeleteKeypair(args, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_delete_keypair.called) + mock_get_nova_client.assert_called_once() + mock_delete_keypair.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_port.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_port.py index 008ed9168..9fd318580 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_port.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_port.py @@ -22,4 +22,4 @@ class DeletePortTestCase(unittest.TestCase): args = {"options": options} obj = DeletePort(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) + mock_get_neutron_client.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router.py index 9b31566ac..b76100f19 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router.py @@ -6,22 +6,49 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## + +from oslo_utils import uuidutils import unittest import mock -from yardstick.benchmark.scenarios.lib.delete_router import DeleteRouter +from yardstick.common import openstack_utils +from yardstick.common import exceptions +from yardstick.benchmark.scenarios.lib import delete_router class DeleteRouterTestCase(unittest.TestCase): - @mock.patch('yardstick.common.openstack_utils.get_neutron_client') - @mock.patch('yardstick.common.openstack_utils.delete_neutron_router') - def test_delete_router(self, mock_get_neutron_client, mock_delete_neutron_router): - options = { - 'router_id': '123-123-123' - } - args = {"options": options} - obj = DeleteRouter(args, {}) - obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_delete_neutron_router.called) + def setUp(self): + self._mock_delete_neutron_router = mock.patch.object( + openstack_utils, 'delete_neutron_router') + self.mock_delete_neutron_router = ( + self._mock_delete_neutron_router.start()) + self._mock_get_shade_client = mock.patch.object( + openstack_utils, 'get_shade_client') + self.mock_get_shade_client = self._mock_get_shade_client.start() + self._mock_log = mock.patch.object(delete_router, 'LOG') + self.mock_log = self._mock_log.start() + self.args = {'options': {'router_id': uuidutils.generate_uuid()}} + self.result = {"delete_router": 0} + + self._del_obj = delete_router.DeleteRouter(self.args, mock.ANY) + + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_delete_neutron_router.stop() + self._mock_get_shade_client.stop() + self._mock_log.stop() + + def test_run(self): + self.mock_delete_neutron_router.return_value = True + self.assertIsNone(self._del_obj.run(self.result)) + self.assertEqual({"delete_router": 1}, self.result) + self.mock_log.info.assert_called_once_with("Delete router successful!") + + def test_run_fail(self): + self.mock_delete_neutron_router.return_value = False + with self.assertRaises(exceptions.ScenarioDeleteRouterError): + self._del_obj.run(self.result) + self.assertEqual({"delete_router": 0}, self.result) + self.mock_log.error.assert_called_once_with("Delete router failed!") diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_gateway.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_gateway.py index e19c38d47..0c9cf7c17 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_gateway.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_gateway.py @@ -23,5 +23,5 @@ class DeleteRouterGatewayTestCase(unittest.TestCase): args = {"options": options} obj = DeleteRouterGateway(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_remove_gateway_router.called) + mock_get_neutron_client.assert_called_once() + mock_remove_gateway_router.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_interface.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_interface.py index 6c4fdd5e3..9e9c5a5b6 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_interface.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_interface.py @@ -24,5 +24,5 @@ class DeleteRouterInterfaceTestCase(unittest.TestCase): args = {"options": options} obj = DeleteRouterInterface(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_remove_interface_router.called) + mock_get_neutron_client.assert_called_once() + mock_remove_interface_router.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_server.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_server.py index dedce2d4a..eee565de7 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_server.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_server.py @@ -23,5 +23,5 @@ class DeleteServerTestCase(unittest.TestCase): args = {"options": options} obj = DeleteServer(args, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_delete_instance.called) + mock_get_nova_client.assert_called_once() + mock_delete_instance.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_volume.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_volume.py index 2ea82e2a4..93f76e819 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_volume.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_volume.py @@ -23,5 +23,5 @@ class DeleteVolumeTestCase(unittest.TestCase): args = {"options": options} obj = DeleteVolume(args, {}) obj.run({}) - self.assertTrue(mock_get_cinder_client.called) - self.assertTrue(mock_delete_volume.called) + mock_get_cinder_client.assert_called_once() + mock_delete_volume.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_detach_volume.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_detach_volume.py index 34fbac68c..9794d2129 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_detach_volume.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_detach_volume.py @@ -23,4 +23,4 @@ class DetachVolumeTestCase(unittest.TestCase): args = {"options": options} obj = DetachVolume(args, {}) obj.run({}) - self.assertTrue(mock_detach_volume.called) + mock_detach_volume.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_flavor.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_flavor.py index e9025f33f..15a6f7c8f 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_flavor.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_flavor.py @@ -22,4 +22,4 @@ class GetFlavorTestCase(unittest.TestCase): args = {"options": options} obj = GetFlavor(args, {}) obj.run({}) - self.assertTrue(mock_get_flavor_by_name.called) + mock_get_flavor_by_name.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py index aa9f63e26..879b2b988 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py @@ -25,9 +25,9 @@ class GetMigrateTargetHostTestCase(unittest.TestCase): mock_get_nova_client): obj = GetMigrateTargetHost({}, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_get_current_host_name.called) - self.assertTrue(mock_get_migrate_host.called) + mock_get_nova_client.assert_called_once() + mock_get_current_host_name.assert_called_once() + mock_get_migrate_host.assert_called_once() @mock.patch('{}.openstack_utils.get_nova_client'.format(BASE)) def test_get_migrate_host(self, mock_get_nova_client): @@ -39,5 +39,5 @@ class GetMigrateTargetHostTestCase(unittest.TestCase): mock_get_nova_client().hosts.list_all.return_value = [A('compute')] obj = GetMigrateTargetHost({}, {}) host = obj._get_migrate_host('host5') - self.assertTrue(mock_get_nova_client.called) + mock_get_nova_client.assert_called() self.assertEqual(host, 'host4') diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py index 4b2132c2c..bea978b8a 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py @@ -44,8 +44,8 @@ class GetNumaInfoTestCase(unittest.TestCase): } obj = GetNumaInfo(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_get_current_host_name.called) - self.assertTrue(mock_check_numa_node.called) + mock_get_current_host_name.assert_called_once() + mock_check_numa_node.assert_called_once() @mock.patch('yardstick.ssh.SSH.from_node') @mock.patch('{}.GetNumaInfo._get_current_host_name'.format(BASE)) diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server.py index 97b81ed60..83ec903bc 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server.py @@ -25,8 +25,8 @@ class GetServerTestCase(unittest.TestCase): } obj = GetServer(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_get_server_by_name.called) + mock_get_nova_client.assert_called_once() + mock_get_server_by_name.assert_called_once() @mock.patch('yardstick.common.openstack_utils.get_nova_client') def test_get_server_with_id(self, mock_get_nova_client): @@ -39,4 +39,4 @@ class GetServerTestCase(unittest.TestCase): mock_get_nova_client().servers.get.return_value = None obj = GetServer(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) + mock_get_nova_client.assert_called() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py index d6636383a..74144afd5 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py @@ -65,7 +65,7 @@ class IperfTestCase(unittest.TestCase): p.target = mock_ssh.SSH.from_node() p.teardown() - self.assertTrue(mock_ssh.SSH.from_node().close.called) + mock_ssh.SSH.from_node().close.assert_called() mock_ssh.SSH.from_node().execute.assert_called_with("pkill iperf3") def test_iperf_successful_no_sla(self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py new file mode 100644 index 000000000..620155c7e --- /dev/null +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python + +# Copyright 2017 Nokia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Unittest for yardstick.benchmark.scenarios.networking.MoongenTestPMD + +from __future__ import absolute_import +try: + from unittest import mock +except ImportError: + import mock +import unittest + +from yardstick.benchmark.scenarios.networking import moongen_testpmd + + +@mock.patch('yardstick.benchmark.scenarios.networking.moongen_testpmd.subprocess') +class MoongenTestPMDTestCase(unittest.TestCase): + + def setUp(self): + self.ctx = { + "host": { + "ip": "10.229.47.137", + "user": "ubuntu", + "password": "ubuntu", + }, + } + self.TestPMDargs = { + 'task_id': "1234-5678", + 'options': { + 'multistream': 1, + 'frame_size': 1024, + 'testpmd_queue': 2, + 'trafficgen_port1': 'ens5', + 'trafficgen_port2': 'ens6', + 'moongen_host_user': 'root', + 'moongen_host_passwd': 'root', + 'moongen_host_ip': '10.5.201.151', + 'moongen_dir': '/home/lua-trafficgen', + 'moongen_runBidirec': 'true', + 'Package_Loss': 0, + 'SearchRuntime': 60, + 'moongen_port1_mac': '88:cf:98:2f:4d:ed', + 'moongen_port2_mac': '88:cf:98:2f:4d:ee', + 'forward_type': 'testpmd', + }, + 'sla': { + 'metrics': 'throughput_rx_mpps', + 'throughput_rx_mpps': 0.5, + 'action': 'monitor', + } + } + self.L2fwdargs = { + 'task_id': "1234-5678", + 'options': { + 'multistream': 1, + 'frame_size': 1024, + 'testpmd_queue': 2, + 'trafficgen_port1': 'ens5', + 'trafficgen_port2': 'ens6', + 'moongen_host_user': 'root', + 'moongen_host_passwd': 'root', + 'moongen_host_ip': '10.5.201.151', + 'moongen_dir': '/home/lua-trafficgen', + 'moongen_runBidirec': 'true', + 'Package_Loss': 0, + 'SearchRuntime': 60, + 'moongen_port1_mac': '88:cf:98:2f:4d:ed', + 'moongen_port2_mac': '88:cf:98:2f:4d:ee', + 'forward_type': 'l2fwd', + }, + 'sla': { + 'metrics': 'throughput_rx_mpps', + 'throughput_rx_mpps': 0.5, + 'action': 'monitor', + } + } + + self._mock_ssh = mock.patch( + 'yardstick.benchmark.scenarios.networking.moongen_testpmd.ssh') + self.mock_ssh = self._mock_ssh.start() + + self.addCleanup(self._cleanup) + + def _cleanup(self): + self._mock_ssh.stop() + + def test_MoongenTestPMD_setup(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + def test_MoongenTestPMD_teardown(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + p.teardown() + self.assertFalse(p.setup_done) + + def test_MoongenTestPMD_l2fwd_is_forward_setup_no(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + result = p._is_forward_setup() + self.assertFalse(result) + + def test_MoongenTestPMD_l2fwd_is_forward_setup_yes(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + + result = p._is_forward_setup() + self.assertTrue(result) + + def test_MoongenTestPMD_testpmd_is_forward_setup_no(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + + result = p._is_forward_setup() + self.assertFalse(result) + + def test_MoongenTestPMD_testpmd_is_forward_setup_yes(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + result = p._is_forward_setup() + self.assertTrue(result) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_testpmd_forward_setup_first(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + + p.forward_setup() + self.assertFalse(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_testpmd_dpdk_setup_next(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + p.forward_setup() + self.assertTrue(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_l2fwd_forward_setup_first(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + p.forward_setup() + self.assertFalse(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_l2fwd_dpdk_setup_next(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + p.forward_setup() + self.assertTrue(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + def test_moongen_testpmd_generate_config_file(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.generate_config_file(frame_size=1, multistream=1, + runBidirec="True", tg_port1_vlan=1, + tg_port2_vlan=2, SearchRuntime=1, + Package_Loss=0) + self.assertTrue(p.CONFIG_FILE) + + def test_moongen_testpmd_result_to_data_match(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + mock_subprocess.call().execute.return_value = None + result = ("[REPORT]Device 1->0: Tx frames: 420161490 Rx Frames: 420161490" + " frame loss: 0, 0.000000% Rx Mpps: 7.002708\n[REPORT] " + "total: Tx frames: 840321216 Rx Frames: 840321216 frame loss: " + "0, 0.000000% Tx Mpps: 14.005388 Rx Mpps: 14.005388\n'") + p.result_to_data(result=result) + self.assertTrue(p.TO_DATA) + + def test_moongen_testpmd_result_to_data_not_match(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + mock_subprocess.call().execute.return_value = None + result = ("") + p.result_to_data(result=result) + self.assertTrue(p.TO_DATA) + + @mock.patch('time.sleep') + def test_moongen_testpmd_run_ok(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + p.setup_done = True + p.forward_setup_done = True + p.setup() + + # run() specific mocks + p.server = self.mock_ssh.SSH.from_node() + mock_subprocess.call().execute.return_value = None + mock_subprocess.call().execute.return_value = None + result = ("[REPORT]Device 1->0: Tx frames: 420161490 Rx Frames: 420161490" + " frame loss: 0, 0.000000% Rx Mpps: 7.002708\n[REPORT] " + "total: Tx frames: 840321216 Rx Frames: 840321216 frame loss: " + "0, 0.000000% Tx Mpps: 14.005388 Rx Mpps: 14.005388\n'") + self.mock_ssh.SSH.from_node().execute.return_value = ( + 0, result, '') + + test_result = {} + p.run(test_result) + + self.assertEqual(test_result['rx_mpps'], 14.005388) + + def test_moongen_testpmd_run_falied_vsperf_execution(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # run() specific mocks + mock_subprocess.call().execute.return_value = None + mock_subprocess.call().execute.return_value = None + self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + + result = {} + self.assertRaises(RuntimeError, p.run, result) + + def test_moongen_testpmd_run_falied_csv_report(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # run() specific mocks + mock_subprocess.call().execute.return_value = None + mock_subprocess.call().execute.return_value = None + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + + result = {} + self.assertRaises(RuntimeError, p.run, result) + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py b/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py index f47d1ca29..f149cee69 100644 --- a/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py +++ b/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py @@ -61,6 +61,22 @@ class FioTestCase(unittest.TestCase): } args = {'options': options} p = fio.Fio(args, self.ctx) + mock_ssh.SSH.from_node().execute.return_value = (0, '/dev/vdb', '') + p.setup() + + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + def test_fio_job_file_no_disk__setup(self, mock_ssh): + + options = { + 'job_file': 'job_file.ini', + 'directory': '/FIO_Test' + } + args = {'options': options} + p = fio.Fio(args, self.ctx) + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') p.setup() mock_ssh.SSH.from_node().execute.return_value = (0, '', '') diff --git a/yardstick/tests/unit/common/test_ansible_common.py b/yardstick/tests/unit/common/test_ansible_common.py index b01195fcc..48d8a60c8 100644 --- a/yardstick/tests/unit/common/test_ansible_common.py +++ b/yardstick/tests/unit/common/test_ansible_common.py @@ -17,6 +17,7 @@ from __future__ import absolute_import import os import tempfile +import shutil from collections import defaultdict import mock @@ -246,3 +247,18 @@ class AnsibleCommonTestCase(unittest.TestCase): a.execute_ansible('', d, ansible_check=True, verbose=True) finally: os.rmdir(d) + + def test_get_sut_info(self): + d = tempfile.mkdtemp() + a = ansible_common.AnsibleCommon({}) + try: + a.get_sut_info(d) + finally: + shutil.rmtree(d) + + def test_get_sut_info_not_exist(self): + a = ansible_common.AnsibleCommon({}) + try: + a.get_sut_info('/hello/world') + except OSError: + pass diff --git a/yardstick/tests/unit/common/test_openstack_utils.py b/yardstick/tests/unit/common/test_openstack_utils.py index 4863f05c0..c6b0f46b2 100644 --- a/yardstick/tests/unit/common/test_openstack_utils.py +++ b/yardstick/tests/unit/common/test_openstack_utils.py @@ -83,3 +83,81 @@ class DeleteNeutronNetTestCase(unittest.TestCase): 'network_id') self.assertFalse(output) mock_logger.error.assert_called_once() + + +class CreateNeutronNetTestCase(unittest.TestCase): + + def setUp(self): + self.mock_shade_client = mock.Mock() + self.network_name = 'name' + self.mock_shade_client.create_network = mock.Mock() + + def test_create_neutron_net(self): + _uuid = uuidutils.generate_uuid() + self.mock_shade_client.create_network.return_value = {'id': _uuid} + output = openstack_utils.create_neutron_net(self.mock_shade_client, + self.network_name) + self.assertEqual(_uuid, output) + + @mock.patch.object(openstack_utils, 'log') + def test_create_neutron_net_exception(self, mock_logger): + self.mock_shade_client.create_network.side_effect = ( + exc.OpenStackCloudException('error message')) + + output = openstack_utils.create_neutron_net(self.mock_shade_client, + self.network_name) + mock_logger.error.assert_called_once() + self.assertIsNone(output) + + +class CreateNeutronSubnetTestCase(unittest.TestCase): + + def setUp(self): + self.mock_shade_client = mock.Mock() + self.network_name_or_id = 'name_or_id' + self.mock_shade_client.create_subnet = mock.Mock() + + def test_create_neutron_subnet(self): + _uuid = uuidutils.generate_uuid() + self.mock_shade_client.create_subnet.return_value = {'id': _uuid} + output = openstack_utils.create_neutron_subnet( + self.mock_shade_client, self.network_name_or_id) + self.assertEqual(_uuid, output) + + @mock.patch.object(openstack_utils, 'log') + def test_create_neutron_subnet_exception(self, mock_logger): + self.mock_shade_client.create_subnet.side_effect = ( + exc.OpenStackCloudException('error message')) + + output = openstack_utils.create_neutron_subnet( + self.mock_shade_client, self.network_name_or_id) + mock_logger.error.assert_called_once() + self.assertIsNone(output) + + +class DeleteNeutronRouterTestCase(unittest.TestCase): + + def setUp(self): + self.mock_shade_client = mock.Mock() + self.mock_shade_client.delete_router = mock.Mock() + + def test_delete_neutron_router(self): + self.mock_shade_client.delete_router.return_value = True + output = openstack_utils.delete_neutron_router(self.mock_shade_client, + 'router_id') + self.assertTrue(output) + + def test_delete_neutron_router_fail(self): + self.mock_shade_client.delete_router.return_value = False + output = openstack_utils.delete_neutron_router(self.mock_shade_client, + 'router_id') + self.assertFalse(output) + + @mock.patch.object(openstack_utils, 'log') + def test_delete_neutron_router_exception(self, mock_logger): + self.mock_shade_client.delete_router.side_effect = ( + exc.OpenStackCloudException('error message')) + output = openstack_utils.delete_neutron_router(self.mock_shade_client, + 'router_id') + mock_logger.error.assert_called_once() + self.assertFalse(output) diff --git a/yardstick/tests/unit/orchestrator/test_heat.py b/yardstick/tests/unit/orchestrator/test_heat.py index 9ab8740e3..aae2487aa 100644 --- a/yardstick/tests/unit/orchestrator/test_heat.py +++ b/yardstick/tests/unit/orchestrator/test_heat.py @@ -272,10 +272,18 @@ class HeatTemplateTestCase(unittest.TestCase): heat_template.add_subnet("subnet2", "network2", "cidr2") heat_template.add_router("router1", "gw1", "subnet1") heat_template.add_router_interface("router_if1", "router1", "subnet1") - heat_template.add_port("port1", "network1", "subnet1", "normal") - heat_template.add_port("port2", "network2", "subnet2", "normal", + network1 = mock.MagicMock() + network1.stack_name = "network1" + network1.subnet_stack_name = "subnet1" + network1.vnic_type = "normal" + network2 = mock.MagicMock() + network2.stack_name = "network2" + network2.subnet_stack_name = "subnet2" + network2.vnic_type = "normal" + heat_template.add_port("port1", network1) + heat_template.add_port("port2", network2, sec_group_id="sec_group1", provider="not-sriov") - heat_template.add_port("port3", "network2", "subnet2", "normal", + heat_template.add_port("port3", network2, sec_group_id="sec_group1", provider="sriov") heat_template.add_floating_ip("floating_ip1", "network1", "port1", "router_if1") diff --git a/yardstick/tests/unit/service/__init__.py b/yardstick/tests/unit/service/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/unit/service/__init__.py diff --git a/yardstick/tests/unit/service/test_environment.py b/yardstick/tests/unit/service/test_environment.py new file mode 100644 index 000000000..4af9a3958 --- /dev/null +++ b/yardstick/tests/unit/service/test_environment.py @@ -0,0 +1,49 @@ +############################################################################## +# Copyright (c) 2016 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 unittest + +import mock + +from yardstick.service.environment import Environment +from yardstick.service.environment import AnsibleCommon +from yardstick.common.exceptions import UnsupportedPodFormatError + + +class EnvironmentTestCase(unittest.TestCase): + + def test_get_sut_info(self): + pod_info = { + 'nodes': [ + { + 'name': 'node1', + 'host_name': 'host1', + 'role': 'Controller', + 'ip': '10.1.0.50', + 'user': 'root', + 'passward': 'root' + } + ] + } + + AnsibleCommon.gen_inventory_ini_dict = mock.MagicMock() + AnsibleCommon.get_sut_info = mock.MagicMock(return_value={'node1': {}}) + + env = Environment(pod=pod_info) + env.get_sut_info() + + def test_get_sut_info_pod_str(self): + pod_info = 'nodes' + + env = Environment(pod=pod_info) + with self.assertRaises(UnsupportedPodFormatError): + env.get_sut_info() + + +if __name__ == '__main__': + unittest.main() diff --git a/yardstick/tests/unit/test_cmd/commands/test_env.py b/yardstick/tests/unit/test_cmd/commands/test_env.py index 1156b6642..57dacbcd3 100644 --- a/yardstick/tests/unit/test_cmd/commands/test_env.py +++ b/yardstick/tests/unit/test_cmd/commands/test_env.py @@ -21,30 +21,30 @@ class EnvCommandTestCase(unittest.TestCase): def test_do_influxdb(self, check_status_mock, start_async_task_mock): env = EnvCommand() env.do_influxdb({}) - self.assertTrue(start_async_task_mock.called) - self.assertTrue(check_status_mock.called) + start_async_task_mock.assert_called_once() + check_status_mock.assert_called_once() @mock.patch('yardstick.cmd.commands.env.EnvCommand._start_async_task') @mock.patch('yardstick.cmd.commands.env.EnvCommand._check_status') def test_do_grafana(self, check_status_mock, start_async_task_mock): env = EnvCommand() env.do_grafana({}) - self.assertTrue(start_async_task_mock.called) - self.assertTrue(check_status_mock.called) + start_async_task_mock.assert_called_once() + check_status_mock.assert_called_once() @mock.patch('yardstick.cmd.commands.env.EnvCommand._start_async_task') @mock.patch('yardstick.cmd.commands.env.EnvCommand._check_status') def test_do_prepare(self, check_status_mock, start_async_task_mock): env = EnvCommand() env.do_prepare({}) - self.assertTrue(start_async_task_mock.called) - self.assertTrue(check_status_mock.called) + start_async_task_mock.assert_called_once() + check_status_mock.assert_called_once() @mock.patch('yardstick.cmd.commands.env.HttpClient.post') def test_start_async_task(self, post_mock): data = {'action': 'create_grafana'} EnvCommand()._start_async_task(data) - self.assertTrue(post_mock.called) + post_mock.assert_called_once() @mock.patch('yardstick.cmd.commands.env.HttpClient.get') @mock.patch('yardstick.cmd.commands.env.EnvCommand._print_status') diff --git a/yardstick/tests/unit/test_cmd/commands/test_testcase.py b/yardstick/tests/unit/test_cmd/commands/test_testcase.py index f6f842e20..922167614 100644 --- a/yardstick/tests/unit/test_cmd/commands/test_testcase.py +++ b/yardstick/tests/unit/test_cmd/commands/test_testcase.py @@ -18,4 +18,4 @@ class TestcaseCommandsUT(unittest.TestCase): def test_do_list(self, mock_client, mock_print): mock_client.get.return_value = {'result': []} TestcaseCommands().do_list({}) - self.assertTrue(mock_print.called) + mock_print.assert_called_once() |